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;
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
);
662 IT_set_face (int face
)
665 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
667 if (face
== 1 || (face
== 0 && highlight
))
668 fp
= FRAME_MODE_LINE_FACE (foo
);
669 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
670 fp
= FRAME_DEFAULT_FACE (foo
);
672 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
674 fprintf (termscript
, "<FACE %d: %d/%d>",
675 face
, FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
677 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
680 Lisp_Object Vdos_unsupported_char_glyph
;
683 IT_write_glyphs (GLYPH
*str
, int str_len
)
685 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
686 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
687 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
688 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
689 register int sl
= str_len
;
690 register int tlen
= GLYPH_TABLE_LENGTH
;
691 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
693 struct coding_system
*coding
= (CODING_REQUIRE_ENCODING (&terminal_coding
)
695 : &safe_terminal_coding
);
697 /* Do we need to consider conversion of unibyte characters to
699 int convert_unibyte_characters
700 = (NILP (current_buffer
->enable_multibyte_characters
)
701 && unibyte_display_via_language_environment
);
703 if (str_len
== 0) return;
705 screen_buf
= screen_bp
= alloca (str_len
* 2);
706 screen_buf_end
= screen_buf
+ str_len
* 2;
708 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
710 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
713 int cf
, ch
, chlen
, enclen
;
714 unsigned char workbuf
[4], *buf
;
715 register GLYPH g
= *str
;
717 /* Find the actual glyph to display by traversing the entire
718 aliases chain for this glyph. */
719 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
721 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
722 only for the redisplay code to know how many columns does
723 this character occupy on the screen. Skip padding glyphs. */
724 if ((g
& GLYPH_MASK_PADDING
))
731 /* Convert the character code to multibyte, if they
732 requested display via language environment. */
733 ch
= FAST_GLYPH_CHAR (g
);
734 /* We only want to convert unibyte characters to multibyte
735 in unibyte buffers! Otherwise, the 8-bit code might come
736 from the display table set up to display foreign characters. */
737 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
739 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
740 ch
= unibyte_char_to_multibyte (ch
);
742 /* Invalid characters are displayed with a special glyph. */
745 g
= !NILP (Vdos_unsupported_char_glyph
)
746 ? Vdos_unsupported_char_glyph
747 : MAKE_GLYPH (selected_frame
, '\177',
748 GLYPH_FACE (selected_frame
, g
));
749 ch
= FAST_GLYPH_CHAR (g
);
751 if (COMPOSITE_CHAR_P (ch
))
753 /* If CH is a composite character, we can display
754 only the first component. */
755 g
= cmpchar_table
[COMPOSITE_CHAR_ID (ch
)]->glyph
[0],
756 ch
= GLYPH_CHAR (selected_frame
, g
);
757 cf
= FAST_GLYPH_FACE (g
);
760 /* If the face of this glyph is different from the current
761 screen face, update the screen attribute byte. */
762 cf
= FAST_GLYPH_FACE (g
);
763 if (cf
!= screen_face
)
764 IT_set_face (cf
); /* handles invalid faces gracefully */
766 if (GLYPH_SIMPLE_P (tbase
, tlen
, g
))
767 /* We generate the multi-byte form of CH in BUF. */
768 chlen
= CHAR_STRING (ch
, workbuf
, buf
);
771 /* We have a string in Vglyph_table. */
772 chlen
= GLYPH_LENGTH (tbase
, g
);
773 buf
= GLYPH_STRING (tbase
, g
);
776 /* If the character is not multibyte, don't bother converting it.
777 FIXME: what about "emacs --unibyte" */
780 *conversion_buffer
= (unsigned char)ch
;
786 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
787 conversion_buffer_size
);
788 chlen
-= coding
->consumed
;
789 enclen
= coding
->produced
;
791 /* Replace glyph codes that cannot be converted by
792 terminal_coding with Vdos_unsupported_char_glyph. */
793 if (*conversion_buffer
== '?')
795 char *cbp
= conversion_buffer
;
797 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
798 *cbp
++ = unsupported_char
;
799 if (unsupported_face
!= screen_face
)
800 IT_set_face (unsupported_face
);
804 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
806 /* The allocated buffer for screen writes is too small.
807 Flush it and loop again without incrementing STR, so
808 that the next loop will begin with the same glyph. */
809 int nbytes
= screen_bp
- screen_buf
;
812 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
813 if (screen_virtual_segment
)
814 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
815 new_pos_X
+= nbytes
/ 2;
818 /* Prepare to reuse the same buffer again. */
819 screen_bp
= screen_buf
;
823 /* There's enough place in the allocated buffer to add
824 the encoding of this glyph. */
826 /* First, copy the encoded bytes. */
827 for (bp
= conversion_buffer
; enclen
--; bp
++)
829 *screen_bp
++ = (unsigned char)*bp
;
830 *screen_bp
++ = ScreenAttrib
;
832 fputc (*bp
, termscript
);
835 /* Now copy the bytes not consumed by the encoding. */
838 buf
+= coding
->consumed
;
842 fputc (*buf
, termscript
);
843 *screen_bp
++ = (unsigned char)*buf
++;
844 *screen_bp
++ = ScreenAttrib
;
848 /* Update STR and its remaining length. */
855 /* Dump whatever is left in the screen buffer. */
857 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
858 if (screen_virtual_segment
)
859 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
860 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
862 /* We may have to output some codes to terminate the writing. */
863 if (CODING_REQUIRE_FLUSHING (coding
))
865 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
866 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
867 if (coding
->produced
> 0)
869 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
870 coding
->produced
--; bp
++)
872 *screen_bp
++ = (unsigned char)*bp
;
873 *screen_bp
++ = ScreenAttrib
;
875 fputc (*bp
, termscript
);
877 offset
+= screen_bp
- screen_buf
;
879 dosmemput (screen_buf
, screen_bp
- screen_buf
,
880 (int)ScreenPrimary
+ offset
);
881 if (screen_virtual_segment
)
882 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
883 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
889 IT_clear_end_of_line (int first_unused
)
893 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
894 extern int fatal_error_in_progress
;
896 if (fatal_error_in_progress
)
901 fprintf (termscript
, "<CLR:EOL>");
902 i
= (j
= screen_size_X
- new_pos_X
) * 2;
903 spaces
= sp
= alloca (i
);
908 *sp
++ = ScreenAttrib
;
912 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
913 if (screen_virtual_segment
)
914 dosv_refresh_virtual_screen (offset
, i
/ 2);
918 IT_clear_screen (void)
921 fprintf (termscript
, "<CLR:SCR>");
925 if (screen_virtual_segment
)
926 dosv_refresh_virtual_screen (0, screen_size
);
927 new_pos_X
= new_pos_Y
= 0;
931 IT_clear_to_end (void)
934 fprintf (termscript
, "<CLR:EOS>");
936 while (new_pos_Y
< screen_size_Y
) {
938 IT_clear_end_of_line (0);
944 IT_cursor_to (int y
, int x
)
947 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
952 static int cursor_cleared
;
955 IT_display_cursor (int on
)
957 if (on
&& cursor_cleared
)
959 ScreenSetCursor (current_pos_Y
, current_pos_X
);
962 else if (!on
&& !cursor_cleared
)
964 ScreenSetCursor (-1, -1);
969 /* Emacs calls cursor-movement functions a lot when it updates the
970 display (probably a legacy of old terminals where you cannot
971 update a screen line without first moving the cursor there).
972 However, cursor movement is expensive on MSDOS (it calls a slow
973 BIOS function and requires 2 mode switches), while actual screen
974 updates access the video memory directly and don't depend on
975 cursor position. To avoid slowing down the redisplay, we cheat:
976 all functions that move the cursor only set internal variables
977 which record the cursor position, whereas the cursor is only
978 moved to its final position whenever screen update is complete.
980 `IT_cmgoto' is called from the keyboard reading loop and when the
981 frame update is complete. This means that we are ready for user
982 input, so we update the cursor position to show where the point is,
983 and also make the mouse pointer visible.
985 Special treatment is required when the cursor is in the echo area,
986 to put the cursor at the end of the text displayed there. */
989 IT_cmgoto (FRAME_PTR f
)
991 /* Only set the cursor to where it should be if the display is
992 already in sync with the window contents. */
993 int update_cursor_pos
= MODIFF
== unchanged_modified
;
994 static int previous_pos_X
= -1;
996 /* If the display is in sync, forget any previous knowledge about
997 cursor position. This is primarily for unexpected events like
998 C-g in the minibuffer. */
999 if (update_cursor_pos
&& previous_pos_X
>= 0)
1000 previous_pos_X
= -1;
1001 /* If we are in the echo area, put the cursor at the
1002 end of the echo area message. */
1003 if (!update_cursor_pos
1004 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1006 int tem_X
= current_pos_X
, dummy
;
1008 if (echo_area_glyphs
)
1010 tem_X
= echo_area_glyphs_length
;
1011 /* Save current cursor position, to be restored after the
1012 echo area message is erased. Only remember one level
1013 of previous cursor position. */
1014 if (previous_pos_X
== -1)
1015 ScreenGetCursor (&dummy
, &previous_pos_X
);
1017 else if (previous_pos_X
>= 0)
1019 /* We wind up here after the echo area message is erased.
1020 Restore the cursor position we remembered above. */
1021 tem_X
= previous_pos_X
;
1022 previous_pos_X
= -1;
1025 if (current_pos_X
!= tem_X
)
1028 update_cursor_pos
= 1;
1032 if (update_cursor_pos
1033 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1035 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1037 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1040 /* Maybe cursor is invisible, so make it visible. */
1041 IT_display_cursor (1);
1043 /* Mouse pointer should be always visible if we are waiting for
1050 IT_reassert_line_highlight (int new, int vpos
)
1053 IT_set_face (0); /* To possibly clear the highlighting. */
1057 IT_change_line_highlight (int new_highlight
, int vpos
, int first_unused_hpos
)
1059 highlight
= new_highlight
;
1060 IT_set_face (0); /* To possibly clear the highlighting. */
1061 IT_cursor_to (vpos
, 0);
1062 IT_clear_end_of_line (first_unused_hpos
);
1066 IT_update_begin (struct frame
*foo
)
1069 IT_set_face (0); /* To possibly clear the highlighting. */
1074 IT_update_end (struct frame
*foo
)
1078 /* Insert and delete characters. These are not supposed to be used
1079 because we are supposed to turn off the feature of using them by
1080 setting char_ins_del_ok to zero (see internal_terminal_init). */
1082 IT_insert_glyphs (start
, len
)
1083 register char *start
;
1090 IT_delete_glyphs (n
)
1096 /* set-window-configuration on window.c needs this. */
1098 x_set_menu_bar_lines (f
, value
, oldval
)
1100 Lisp_Object value
, oldval
;
1102 set_menu_bar_lines (f
, value
, oldval
);
1105 /* This was copied from xfns.c */
1107 Lisp_Object Qbackground_color
;
1108 Lisp_Object Qforeground_color
;
1109 extern Lisp_Object Qtitle
;
1111 /* IT_set_terminal_modes is called when emacs is started,
1112 resumed, and whenever the screen is redrawn! */
1115 IT_set_terminal_modes (void)
1118 fprintf (termscript
, "\n<SET_TERM>");
1121 screen_size_X
= ScreenCols ();
1122 screen_size_Y
= ScreenRows ();
1123 screen_size
= screen_size_X
* screen_size_Y
;
1125 new_pos_X
= new_pos_Y
= 0;
1126 current_pos_X
= current_pos_Y
= -1;
1128 if (term_setup_done
)
1130 term_setup_done
= 1;
1132 startup_screen_size_X
= screen_size_X
;
1133 startup_screen_size_Y
= screen_size_Y
;
1134 startup_screen_attrib
= ScreenAttrib
;
1137 /* Is DOS/V (or any other RSIS software which relocates
1138 the screen) installed? */
1140 unsigned short es_value
;
1143 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1144 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1145 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1146 else if (screen_old_address
) /* already switched to Japanese mode once */
1147 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1149 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1151 es_value
= regs
.x
.es
;
1152 __dpmi_int (0x10, ®s
);
1154 if (regs
.x
.es
!= es_value
)
1156 /* screen_old_address is only set if ScreenPrimary does NOT
1157 already point to the relocated buffer address returned by
1158 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1159 ScreenPrimary to that address at startup under DOS/V. */
1160 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
1161 screen_old_address
= ScreenPrimary
;
1162 screen_virtual_segment
= regs
.x
.es
;
1163 screen_virtual_offset
= regs
.x
.di
;
1164 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1167 #endif /* __DJGPP__ > 1 */
1169 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1170 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1173 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1174 screen_size_X
, screen_size_Y
);
1179 /* IT_reset_terminal_modes is called when emacs is
1180 suspended or killed. */
1183 IT_reset_terminal_modes (void)
1185 int display_row_start
= (int) ScreenPrimary
;
1186 int saved_row_len
= startup_screen_size_X
* 2;
1187 int update_row_len
= ScreenCols () * 2;
1188 int current_rows
= ScreenRows ();
1189 int to_next_row
= update_row_len
;
1190 unsigned char *saved_row
= startup_screen_buffer
;
1191 int cursor_pos_X
= ScreenCols () - 1;
1192 int cursor_pos_Y
= ScreenRows () - 1;
1195 fprintf (termscript
, "\n<RESET_TERM>");
1199 if (!term_setup_done
)
1204 /* Leave the video system in the same state as we found it,
1205 as far as the blink/bright-background bit is concerned. */
1206 maybe_enable_blinking ();
1208 /* We have a situation here.
1209 We cannot just do ScreenUpdate(startup_screen_buffer) because
1210 the luser could have changed screen dimensions inside Emacs
1211 and failed (or didn't want) to restore them before killing
1212 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1213 thus will happily use memory outside what was allocated for
1214 `startup_screen_buffer'.
1215 Thus we only restore as much as the current screen dimensions
1216 can hold, and clear the rest (if the saved screen is smaller than
1217 the current) with the color attribute saved at startup. The cursor
1218 is also restored within the visible dimensions. */
1220 ScreenAttrib
= startup_screen_attrib
;
1222 /* Don't restore the screen if we are exiting less than 2 seconds
1223 after startup: we might be crashing, and the screen might show
1224 some vital clues to what's wrong. */
1225 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1228 if (screen_virtual_segment
)
1229 dosv_refresh_virtual_screen (0, screen_size
);
1231 if (update_row_len
> saved_row_len
)
1232 update_row_len
= saved_row_len
;
1233 if (current_rows
> startup_screen_size_Y
)
1234 current_rows
= startup_screen_size_Y
;
1237 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1238 update_row_len
/ 2, current_rows
);
1240 while (current_rows
--)
1242 dosmemput (saved_row
, update_row_len
, display_row_start
);
1243 if (screen_virtual_segment
)
1244 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
1245 update_row_len
/ 2);
1246 saved_row
+= saved_row_len
;
1247 display_row_start
+= to_next_row
;
1250 if (startup_pos_X
< cursor_pos_X
)
1251 cursor_pos_X
= startup_pos_X
;
1252 if (startup_pos_Y
< cursor_pos_Y
)
1253 cursor_pos_Y
= startup_pos_Y
;
1255 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
1256 xfree (startup_screen_buffer
);
1258 term_setup_done
= 0;
1262 IT_set_terminal_window (int foo
)
1267 IT_set_frame_parameters (f
, alist
)
1272 int length
= XINT (Flength (alist
));
1275 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1277 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1279 extern unsigned long load_color ();
1283 /* Extract parm names and values into those vectors. */
1285 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1290 parms
[i
] = Fcar (elt
);
1291 CHECK_SYMBOL (parms
[i
], 1);
1292 values
[i
] = Fcdr (elt
);
1297 /* Now process them in reverse of specified order. */
1298 for (i
--; i
>= 0; i
--)
1300 Lisp_Object prop
= parms
[i
];
1301 Lisp_Object val
= values
[i
];
1303 if (EQ (prop
, Qforeground_color
))
1305 unsigned long new_color
= load_color (f
, val
);
1306 if (new_color
!= ~0)
1308 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1311 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
1314 else if (EQ (prop
, Qbackground_color
))
1316 unsigned long new_color
= load_color (f
, val
);
1317 if (new_color
!= ~0)
1319 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1322 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
1325 else if (EQ (prop
, Qtitle
))
1327 x_set_title (f
, val
);
1329 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
1331 else if (EQ (prop
, intern ("reverse")) && EQ (val
, Qt
))
1333 unsigned long fg
= FRAME_FOREGROUND_PIXEL (f
);
1335 FRAME_FOREGROUND_PIXEL (f
) = FRAME_BACKGROUND_PIXEL (f
);
1336 FRAME_BACKGROUND_PIXEL (f
) = fg
;
1338 fprintf (termscript
, "<INVERSE-VIDEO>\n");
1340 store_frame_param (f
, prop
, val
);
1346 extern void recompute_basic_faces (FRAME_PTR
);
1347 extern void redraw_frame (FRAME_PTR
);
1349 recompute_basic_faces (f
);
1350 if (f
== selected_frame
)
1355 extern void init_frame_faces (FRAME_PTR
);
1357 #endif /* !HAVE_X_WINDOWS */
1360 /* Do we need the internal terminal? */
1363 internal_terminal_init ()
1365 char *term
= getenv ("TERM");
1368 #ifdef HAVE_X_WINDOWS
1369 if (!inhibit_window_system
)
1374 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1376 if (getenv ("EMACSTEST"))
1377 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1379 #ifndef HAVE_X_WINDOWS
1380 if (!internal_terminal
|| inhibit_window_system
)
1382 selected_frame
->output_method
= output_termcap
;
1386 Vwindow_system
= intern ("pc");
1387 Vwindow_system_version
= make_number (1);
1389 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1390 screen_old_address
= 0;
1392 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1393 the_only_x_display
.background_pixel
= 7; /* White */
1394 the_only_x_display
.foreground_pixel
= 0; /* Black */
1396 colors
= getenv ("EMACSCOLORS");
1397 if (colors
&& strlen (colors
) >= 2)
1399 /* The colors use 4 bits each (we enable bright background). */
1400 if (isdigit (colors
[0]))
1402 else if (isxdigit (colors
[0]))
1403 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1404 if (colors
[0] >= 0 && colors
[0] < 16)
1405 the_only_x_display
.foreground_pixel
= colors
[0];
1406 if (isdigit (colors
[1]))
1408 else if (isxdigit (colors
[1]))
1409 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1410 if (colors
[1] >= 0 && colors
[1] < 16)
1411 the_only_x_display
.background_pixel
= colors
[1];
1413 the_only_x_display
.line_height
= 1;
1414 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1416 init_frame_faces (selected_frame
);
1418 ring_bell_hook
= IT_ring_bell
;
1419 insert_glyphs_hook
= IT_insert_glyphs
;
1420 delete_glyphs_hook
= IT_delete_glyphs
;
1421 write_glyphs_hook
= IT_write_glyphs
;
1422 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1423 clear_to_end_hook
= IT_clear_to_end
;
1424 clear_end_of_line_hook
= IT_clear_end_of_line
;
1425 clear_frame_hook
= IT_clear_screen
;
1426 change_line_highlight_hook
= IT_change_line_highlight
;
1427 update_begin_hook
= IT_update_begin
;
1428 update_end_hook
= IT_update_end
;
1429 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1430 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1432 /* These hooks are called by term.c without being checked. */
1433 set_terminal_modes_hook
= IT_set_terminal_modes
;
1434 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1435 set_terminal_window_hook
= IT_set_terminal_window
;
1437 char_ins_del_ok
= 0; /* just as fast to write the line */
1441 dos_get_saved_screen (screen
, rows
, cols
)
1446 #ifndef HAVE_X_WINDOWS
1447 *screen
= startup_screen_buffer
;
1448 *cols
= startup_screen_size_X
;
1449 *rows
= startup_screen_size_Y
;
1450 return *screen
!= (char *)0;
1456 #ifndef HAVE_X_WINDOWS
1458 /* We are not X, but we can emulate it well enough for our needs... */
1462 if (! FRAME_MSDOS_P (selected_frame
))
1463 error ("Not running under a windows system");
1469 /* ----------------------- Keyboard control ----------------------
1471 * Keymaps reflect the following keyboard layout:
1473 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1474 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1475 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1476 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1480 #define Ignore 0x0000
1481 #define Normal 0x0000 /* normal key - alt changes scan-code */
1482 #define FctKey 0x1000 /* func key if c == 0, else c */
1483 #define Special 0x2000 /* func key even if c != 0 */
1484 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1485 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1486 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1487 #define Grey 0x6000 /* Grey keypad key */
1489 #define Alt 0x0100 /* alt scan-code */
1490 #define Ctrl 0x0200 /* ctrl scan-code */
1491 #define Shift 0x0400 /* shift scan-code */
1493 static int extended_kbd
; /* 101 (102) keyboard present. */
1495 struct kbd_translate
{
1498 unsigned short code
;
1501 struct dos_keyboard_map
1506 struct kbd_translate
*translate_table
;
1510 static struct dos_keyboard_map us_keyboard
= {
1512 /* 01234567890123456789012345678901234567890 12345678901234 */
1513 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1514 /* 0123456789012345678901234567890123456789 012345678901234 */
1515 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1516 0, /* no Alt-Gr key */
1517 0 /* no translate table */
1520 static struct dos_keyboard_map fr_keyboard
= {
1522 /* 012 3456789012345678901234567890123456789012345678901234 */
1523 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1524 /* 0123456789012345678901234567890123456789012345678901234 */
1525 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1526 /* 01234567 89012345678901234567890123456789012345678901234 */
1528 0 /* no translate table */
1532 * Italian keyboard support, country code 39.
1535 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1536 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1539 static struct kbd_translate it_kbd_translate_table
[] = {
1540 { 0x56, 0x3c, Normal
| 13 },
1541 { 0x56, 0x3e, Normal
| 27 },
1544 static struct dos_keyboard_map it_keyboard
= {
1546 /* 0 123456789012345678901234567890123456789012345678901234 */
1547 "\\1234567890'\8d< qwertyuiop\8a+> asdfghjkl\95\85\97 zxcvbnm,.- ",
1548 /* 01 23456789012345678901234567890123456789012345678901234 */
1549 "|!\"\9c$%&/()=?^> QWERTYUIOP\82* ASDFGHJKL\87øõ ZXCVBNM;:_ ",
1550 /* 0123456789012345678901234567890123456789012345678901234 */
1552 it_kbd_translate_table
1555 static struct dos_keyboard_map dk_keyboard
= {
1557 /* 0123456789012345678901234567890123456789012345678901234 */
1558 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1559 /* 01 23456789012345678901234567890123456789012345678901234 */
1560 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1561 /* 0123456789012345678901234567890123456789012345678901234 */
1563 0 /* no translate table */
1566 static struct kbd_translate jp_kbd_translate_table
[] = {
1567 { 0x73, 0x5c, Normal
| 0 },
1568 { 0x73, 0x5f, Normal
| 0 },
1569 { 0x73, 0x1c, Map
| 0 },
1570 { 0x7d, 0x5c, Normal
| 13 },
1571 { 0x7d, 0x7c, Normal
| 13 },
1572 { 0x7d, 0x1c, Map
| 13 },
1575 static struct dos_keyboard_map jp_keyboard
= {
1577 /* 0123456789012 345678901234567890123456789012345678901234 */
1578 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1579 /* 01 23456789012345678901234567890123456789012345678901234 */
1580 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
1581 0, /* no Alt-Gr key */
1582 jp_kbd_translate_table
1585 static struct keyboard_layout_list
1588 struct dos_keyboard_map
*keyboard_map
;
1589 } keyboard_layout_list
[] =
1598 static struct dos_keyboard_map
*keyboard
;
1599 static int keyboard_map_all
;
1600 static int international_keyboard
;
1603 dos_set_keyboard (code
, always
)
1608 _go32_dpmi_registers regs
;
1610 /* See if Keyb.Com is installed (for international keyboard support).
1611 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1612 of Windows 9X! So don't do that! */
1614 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
1615 _go32_dpmi_simulate_int (0x2f, ®s
);
1616 if (regs
.h
.al
== 0xff)
1617 international_keyboard
= 1;
1619 /* Initialize to US settings, for countries that don't have their own. */
1620 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1621 keyboard_map_all
= always
;
1622 dos_keyboard_layout
= 1;
1624 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1625 if (code
== keyboard_layout_list
[i
].country_code
)
1627 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1628 keyboard_map_all
= always
;
1629 dos_keyboard_layout
= code
;
1637 unsigned char char_code
; /* normal code */
1638 unsigned char meta_code
; /* M- code */
1639 unsigned char keypad_code
; /* keypad code */
1640 unsigned char editkey_code
; /* edit key */
1641 } keypad_translate_map
[] = {
1642 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1643 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1644 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1645 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1646 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1647 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1648 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1649 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1650 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1651 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1652 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1657 unsigned char char_code
; /* normal code */
1658 unsigned char keypad_code
; /* keypad code */
1659 } grey_key_translate_map
[] = {
1660 '/', 0xaf, /* kp-decimal */
1661 '*', 0xaa, /* kp-multiply */
1662 '-', 0xad, /* kp-subtract */
1663 '+', 0xab, /* kp-add */
1664 '\r', 0x8d /* kp-enter */
1667 static unsigned short
1668 ibmpc_translate_map
[] =
1670 /* --------------- 00 to 0f --------------- */
1671 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1672 Alt
| ModFct
| 0x1b, /* Escape */
1673 Normal
| 1, /* '1' */
1674 Normal
| 2, /* '2' */
1675 Normal
| 3, /* '3' */
1676 Normal
| 4, /* '4' */
1677 Normal
| 5, /* '5' */
1678 Normal
| 6, /* '6' */
1679 Normal
| 7, /* '7' */
1680 Normal
| 8, /* '8' */
1681 Normal
| 9, /* '9' */
1682 Normal
| 10, /* '0' */
1683 Normal
| 11, /* '-' */
1684 Normal
| 12, /* '=' */
1685 Special
| 0x08, /* Backspace */
1686 ModFct
| 0x74, /* Tab/Backtab */
1688 /* --------------- 10 to 1f --------------- */
1701 ModFct
| 0x0d, /* Return */
1706 /* --------------- 20 to 2f --------------- */
1715 Map
| 40, /* '\'' */
1717 Ignore
, /* Left shift */
1718 Map
| 41, /* '\\' */
1724 /* --------------- 30 to 3f --------------- */
1731 Ignore
, /* Right shift */
1732 Grey
| 1, /* Grey * */
1734 Normal
| 55, /* ' ' */
1735 Ignore
, /* Caps Lock */
1736 FctKey
| 0xbe, /* F1 */
1737 FctKey
| 0xbf, /* F2 */
1738 FctKey
| 0xc0, /* F3 */
1739 FctKey
| 0xc1, /* F4 */
1740 FctKey
| 0xc2, /* F5 */
1742 /* --------------- 40 to 4f --------------- */
1743 FctKey
| 0xc3, /* F6 */
1744 FctKey
| 0xc4, /* F7 */
1745 FctKey
| 0xc5, /* F8 */
1746 FctKey
| 0xc6, /* F9 */
1747 FctKey
| 0xc7, /* F10 */
1748 Ignore
, /* Num Lock */
1749 Ignore
, /* Scroll Lock */
1750 KeyPad
| 7, /* Home */
1751 KeyPad
| 8, /* Up */
1752 KeyPad
| 9, /* Page Up */
1753 Grey
| 2, /* Grey - */
1754 KeyPad
| 4, /* Left */
1755 KeyPad
| 5, /* Keypad 5 */
1756 KeyPad
| 6, /* Right */
1757 Grey
| 3, /* Grey + */
1758 KeyPad
| 1, /* End */
1760 /* --------------- 50 to 5f --------------- */
1761 KeyPad
| 2, /* Down */
1762 KeyPad
| 3, /* Page Down */
1763 KeyPad
| 0, /* Insert */
1764 KeyPad
| 10, /* Delete */
1765 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1766 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1767 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1768 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1769 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1770 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1771 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1772 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1773 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1774 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1775 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1776 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1778 /* --------------- 60 to 6f --------------- */
1779 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1780 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1781 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1782 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1783 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1784 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1785 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1786 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1787 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1788 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1789 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1790 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1791 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1792 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1793 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1794 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1796 /* --------------- 70 to 7f --------------- */
1797 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1798 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1799 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1800 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1801 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1802 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1803 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1804 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1805 Alt
| Map
| 1, /* '1' */
1806 Alt
| Map
| 2, /* '2' */
1807 Alt
| Map
| 3, /* '3' */
1808 Alt
| Map
| 4, /* '4' */
1809 Alt
| Map
| 5, /* '5' */
1810 Alt
| Map
| 6, /* '6' */
1811 Alt
| Map
| 7, /* '7' */
1812 Alt
| Map
| 8, /* '8' */
1814 /* --------------- 80 to 8f --------------- */
1815 Alt
| Map
| 9, /* '9' */
1816 Alt
| Map
| 10, /* '0' */
1817 Alt
| Map
| 11, /* '-' */
1818 Alt
| Map
| 12, /* '=' */
1819 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1820 FctKey
| 0xc8, /* F11 */
1821 FctKey
| 0xc9, /* F12 */
1822 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1823 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1824 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1825 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1826 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1827 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1828 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1829 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1830 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1832 /* --------------- 90 to 9f --------------- */
1833 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1834 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1835 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1836 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1837 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1838 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1839 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1840 Alt
| FctKey
| 0x50, /* (Alt) Home */
1841 Alt
| FctKey
| 0x52, /* (Alt) Up */
1842 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1843 Ignore
, /* NO KEY */
1844 Alt
| FctKey
| 0x51, /* (Alt) Left */
1845 Ignore
, /* NO KEY */
1846 Alt
| FctKey
| 0x53, /* (Alt) Right */
1847 Ignore
, /* NO KEY */
1848 Alt
| FctKey
| 0x57, /* (Alt) End */
1850 /* --------------- a0 to af --------------- */
1851 Alt
| KeyPad
| 2, /* (Alt) Down */
1852 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1853 Alt
| KeyPad
| 0, /* (Alt) Insert */
1854 Alt
| KeyPad
| 10, /* (Alt) Delete */
1855 Alt
| Grey
| 0, /* (Alt) Grey / */
1856 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1857 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1860 /* These bit-positions corresponds to values returned by BIOS */
1861 #define SHIFT_P 0x0003 /* two bits! */
1862 #define CTRL_P 0x0004
1863 #define ALT_P 0x0008
1864 #define SCRLOCK_P 0x0010
1865 #define NUMLOCK_P 0x0020
1866 #define CAPSLOCK_P 0x0040
1867 #define ALT_GR_P 0x0800
1868 #define SUPER_P 0x4000 /* pseudo */
1869 #define HYPER_P 0x8000 /* pseudo */
1872 dos_get_modifiers (keymask
)
1879 /* Calculate modifier bits */
1880 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1881 int86 (0x16, ®s
, ®s
);
1885 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1886 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1890 mask
= regs
.h
.al
& (SHIFT_P
|
1891 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1893 /* Do not break international keyboard support. */
1894 /* When Keyb.Com is loaded, the right Alt key is */
1895 /* used for accessing characters like { and } */
1896 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1899 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1902 if (dos_hyper_key
== 1)
1905 modifiers
|= hyper_modifier
;
1907 else if (dos_super_key
== 1)
1910 modifiers
|= super_modifier
;
1912 else if (!international_keyboard
)
1914 /* If Keyb.Com is NOT installed, let Right Alt behave
1915 like the Left Alt. */
1921 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1924 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1926 if (dos_hyper_key
== 2)
1929 modifiers
|= hyper_modifier
;
1931 else if (dos_super_key
== 2)
1934 modifiers
|= super_modifier
;
1942 modifiers
|= shift_modifier
;
1944 modifiers
|= ctrl_modifier
;
1946 modifiers
|= meta_modifier
;
1953 #define NUM_RECENT_DOSKEYS (100)
1954 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1955 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1956 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1958 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1959 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1960 Each input key receives two values in this vector: first the ASCII code,\n\
1961 and then the scan code.")
1964 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1967 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1968 return Fvector (total_doskeys
, keys
);
1971 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1972 bcopy (keys
+ recent_doskeys_index
,
1973 XVECTOR (val
)->contents
,
1974 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1976 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1977 recent_doskeys_index
* sizeof (Lisp_Object
));
1982 /* Get a char from keyboard. Function keys are put into the event queue. */
1984 extern void kbd_buffer_store_event (struct input_event
*);
1985 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1990 struct input_event event
;
1993 #ifndef HAVE_X_WINDOWS
1994 /* Maybe put the cursor where it should be. */
1995 IT_cmgoto (selected_frame
);
1998 /* The following condition is equivalent to `kbhit ()', except that
1999 it uses the bios to do its job. This pleases DESQview/X. */
2000 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2001 int86 (0x16, ®s
, ®s
),
2002 (regs
.x
.flags
& 0x40) == 0)
2005 register unsigned char c
;
2006 int sc
, code
= -1, mask
, kp_mode
;
2009 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2010 int86 (0x16, ®s
, ®s
);
2015 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2017 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2018 recent_doskeys_index
= 0;
2019 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2021 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2022 recent_doskeys_index
= 0;
2024 modifiers
= dos_get_modifiers (&mask
);
2026 #ifndef HAVE_X_WINDOWS
2027 if (!NILP (Vdos_display_scancodes
))
2030 sprintf (buf
, "%02x:%02x*%04x",
2031 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2032 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2040 case 10: /* Ctrl Grey Enter */
2041 code
= Ctrl
| Grey
| 4;
2043 case 13: /* Grey Enter */
2046 case '/': /* Grey / */
2056 /* Try the keyboard-private translation table first. */
2057 if (keyboard
->translate_table
)
2059 struct kbd_translate
*p
= keyboard
->translate_table
;
2063 if (p
->sc
== sc
&& p
->ch
== c
)
2071 /* If the private table didn't translate it, use the general
2075 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
2077 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
2084 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2085 Emacs is ready to read a key. Therefore, if they press
2086 `Alt-x' when Emacs is busy, by the time we get to
2087 `dos_get_modifiers', they might have already released the
2088 Alt key, and Emacs gets just `x', which is BAD.
2089 However, for keys with the `Map' property set, the ASCII
2090 code returns zero iff Alt is pressed. So, when we DON'T
2091 have to support international_keyboard, we don't have to
2092 distinguish between the left and right Alt keys, and we
2093 can set the META modifier for any keys with the `Map'
2094 property if they return zero ASCII code (c = 0). */
2096 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
2097 modifiers
|= meta_modifier
;
2099 modifiers
|= ctrl_modifier
;
2101 modifiers
|= shift_modifier
;
2104 switch (code
& 0xf000)
2107 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
2109 c
= 0; /* Special */
2122 if (c
== 0) /* ctrl-break */
2124 return c
; /* ALT-nnn */
2126 if (!keyboard_map_all
)
2135 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
2136 if (!keyboard_map_all
)
2140 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
2141 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
2145 code
= keyboard
->shifted
[code
];
2147 modifiers
&= ~shift_modifier
;
2150 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
2151 code
= keyboard
->alt_gr
[code
];
2153 code
= keyboard
->unshifted
[code
];
2158 if (c
== 0xe0) /* edit key */
2161 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
2162 kp_mode
= dos_keypad_mode
& 0x03;
2164 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
2169 if (code
== 10 && dos_decimal_point
)
2170 return dos_decimal_point
;
2171 return keypad_translate_map
[code
].char_code
;
2174 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
2178 code
= keypad_translate_map
[code
].meta_code
;
2179 modifiers
= meta_modifier
;
2183 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
2190 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
2191 if (dos_keypad_mode
& kp_mode
)
2192 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
2194 code
= grey_key_translate_map
[code
].char_code
;
2203 event
.kind
= non_ascii_keystroke
;
2205 event
.kind
= ascii_keystroke
;
2207 event
.modifiers
= modifiers
;
2208 XSETFRAME (event
.frame_or_window
, selected_frame
);
2209 event
.timestamp
= event_timestamp ();
2210 kbd_buffer_store_event (&event
);
2213 if (have_mouse
> 0 && !mouse_preempted
)
2215 int but
, press
, x
, y
, ok
;
2217 /* Check for mouse movement *before* buttons. */
2218 mouse_check_moved ();
2220 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
2221 for (press
= 0; press
< 2; press
++)
2223 int button_num
= but
;
2226 ok
= mouse_pressed (but
, &x
, &y
);
2228 ok
= mouse_released (but
, &x
, &y
);
2231 /* Allow a simultaneous press/release of Mouse-1 and
2232 Mouse-2 to simulate Mouse-3 on two-button mice. */
2233 if (mouse_button_count
== 2 && but
< 2)
2235 int x2
, y2
; /* don't clobber original coordinates */
2237 /* If only one button is pressed, wait 100 msec and
2238 check again. This way, Speedy Gonzales isn't
2239 punished, while the slow get their chance. */
2240 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2241 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2246 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2247 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2252 event
.kind
= mouse_click
;
2253 event
.code
= button_num
;
2254 event
.modifiers
= dos_get_modifiers (0)
2255 | (press
? down_modifier
: up_modifier
);
2258 XSETFRAME (event
.frame_or_window
, selected_frame
);
2259 event
.timestamp
= event_timestamp ();
2260 kbd_buffer_store_event (&event
);
2268 static int prev_get_char
= -1;
2270 /* Return 1 if a key is ready to be read without suspending execution. */
2274 if (prev_get_char
!= -1)
2277 return ((prev_get_char
= dos_rawgetc ()) != -1);
2280 /* Read a key. Return -1 if no key is ready. */
2284 if (prev_get_char
!= -1)
2286 int c
= prev_get_char
;
2291 return dos_rawgetc ();
2294 #ifndef HAVE_X_WINDOWS
2295 /* See xterm.c for more info. */
2297 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
2299 register int pix_x
, pix_y
;
2300 register int *x
, *y
;
2304 if (bounds
) abort ();
2306 /* Ignore clipping. */
2313 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
2316 register int *pix_x
, *pix_y
;
2322 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2325 Actually, I don't know the meaning of all the parameters of the functions
2326 here -- I only know how they are called by xmenu.c. I could of course
2327 grab the nearest Xlib manual (down the hall, second-to-last door on the
2328 left), but I don't think it's worth the effort. */
2335 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
2336 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
2340 /* Allocate some (more) memory for MENU ensuring that there is room for one
2344 IT_menu_make_room (XMenu
*menu
)
2346 if (menu
->allocated
== 0)
2348 int count
= menu
->allocated
= 10;
2349 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
2350 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
2351 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
2353 else if (menu
->allocated
== menu
->count
)
2355 int count
= menu
->allocated
= menu
->allocated
+ 10;
2357 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2359 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2361 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2365 /* Search the given menu structure for a given pane number. */
2368 IT_menu_search_pane (XMenu
*menu
, int pane
)
2373 for (i
= 0; i
< menu
->count
; i
++)
2374 if (menu
->submenu
[i
])
2376 if (pane
== menu
->panenumber
[i
])
2377 return menu
->submenu
[i
];
2378 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2384 /* Determine how much screen space a given menu needs. */
2387 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2389 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2392 maxheight
= menu
->count
;
2393 for (i
= 0; i
< menu
->count
; i
++)
2395 if (menu
->submenu
[i
])
2397 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2398 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2399 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2402 *width
= menu
->width
+ maxsubwidth
;
2403 *height
= maxheight
;
2406 /* Display MENU at (X,Y) using FACES. */
2409 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
2411 int i
, j
, face
, width
;
2415 int enabled
, mousehere
;
2418 width
= menu
->width
;
2419 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
2420 ScreenGetCursor (&row
, &col
);
2421 mouse_get_xy (&mx
, &my
);
2422 IT_update_begin (selected_frame
);
2423 for (i
= 0; i
< menu
->count
; i
++)
2425 IT_cursor_to (y
+ i
, x
);
2427 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2428 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
2429 face
= faces
[enabled
+ mousehere
* 2];
2431 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2432 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2435 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
2436 else /* make '^x' */
2438 *p
++ = FAST_MAKE_GLYPH ('^', face
);
2440 *p
++ = FAST_MAKE_GLYPH (*q
++ + 64, face
);
2444 for (; j
< width
; j
++)
2445 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2446 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
2447 IT_write_glyphs (text
, width
+ 2);
2449 IT_update_end (selected_frame
);
2450 IT_cursor_to (row
, col
);
2454 /* --------------------------- X Menu emulation ---------------------- */
2456 /* Report availability of menus. */
2464 /* Create a brand new menu structure. */
2467 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2469 return IT_menu_create ();
2472 /* Create a new pane and place it on the outer-most level. It is not
2473 clear that it should be placed out there, but I don't know what else
2477 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2485 IT_menu_make_room (menu
);
2486 menu
->submenu
[menu
->count
] = IT_menu_create ();
2487 menu
->text
[menu
->count
] = txt
;
2488 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2491 /* Adjust length for possible control characters (which will
2492 be written as ^x). */
2493 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2497 if (len
> menu
->width
)
2500 return menu
->panecount
;
2503 /* Create a new item in a menu pane. */
2506 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2507 int foo
, char *txt
, int enable
)
2513 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2515 IT_menu_make_room (menu
);
2516 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2517 menu
->text
[menu
->count
] = txt
;
2518 menu
->panenumber
[menu
->count
] = enable
;
2521 /* Adjust length for possible control characters (which will
2522 be written as ^x). */
2523 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2527 if (len
> menu
->width
)
2533 /* Decide where the menu would be placed if requested at (X,Y). */
2536 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2537 int *ulx
, int *uly
, int *width
, int *height
)
2539 IT_menu_calc_size (menu
, width
, height
);
2545 struct IT_menu_state
2547 void *screen_behind
;
2554 /* Display menu, wait for user's response, and return that response. */
2557 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2558 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2560 struct IT_menu_state
*state
;
2564 int faces
[4], selectface
;
2565 int leave
, result
, onepane
;
2566 int title_faces
[4]; /* face to display the menu title */
2567 int buffers_num_deleted
= 0;
2569 /* Just in case we got here without a mouse present... */
2570 if (have_mouse
<= 0)
2571 return XM_IA_SELECT
;
2572 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2573 around the display. */
2579 /* We will process all the mouse events directly, so we had
2580 better prevented dos_rawgetc from stealing them from us. */
2583 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2584 screensize
= screen_size
* 2;
2586 = compute_glyph_face (selected_frame
,
2589 intern ("msdos-menu-passive-face")),
2592 = compute_glyph_face (selected_frame
,
2595 intern ("msdos-menu-active-face")),
2598 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
2599 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
2600 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
2602 /* Make sure the menu title is always displayed with
2603 `msdos-menu-active-face', no matter where the mouse pointer is. */
2604 for (i
= 0; i
< 4; i
++)
2605 title_faces
[i
] = faces
[3];
2609 /* Don't let the title for the "Buffers" popup menu include a
2610 digit (which is ugly).
2612 This is a terrible kludge, but I think the "Buffers" case is
2613 the only one where the title includes a number, so it doesn't
2614 seem to be necessary to make this more general. */
2615 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2617 menu
->text
[0][7] = '\0';
2618 buffers_num_deleted
= 1;
2620 state
[0].menu
= menu
;
2622 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2624 /* Turn off the cursor. Otherwise it shows through the menu
2625 panes, which is ugly. */
2626 IT_display_cursor (0);
2628 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2629 if (buffers_num_deleted
)
2630 menu
->text
[0][7] = ' ';
2631 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2633 menu
->width
= menu
->submenu
[0]->width
;
2634 state
[0].menu
= menu
->submenu
[0];
2638 state
[0].menu
= menu
;
2640 state
[0].x
= x0
- 1;
2642 state
[0].pane
= onepane
;
2644 mouse_last_x
= -1; /* A hack that forces display. */
2648 if (!mouse_visible
) mouse_on ();
2649 mouse_check_moved ();
2650 if (selected_frame
->mouse_moved
)
2652 selected_frame
->mouse_moved
= 0;
2653 result
= XM_IA_SELECT
;
2654 mouse_get_xy (&x
, &y
);
2655 for (i
= 0; i
< statecount
; i
++)
2656 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2658 int dy
= y
- state
[i
].y
;
2659 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2661 if (!state
[i
].menu
->submenu
[dy
])
2662 if (state
[i
].menu
->panenumber
[dy
])
2663 result
= XM_SUCCESS
;
2665 result
= XM_IA_SELECT
;
2666 *pane
= state
[i
].pane
- 1;
2668 /* We hit some part of a menu, so drop extra menus that
2669 have been opened. That does not include an open and
2671 if (i
!= statecount
- 2
2672 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2673 while (i
!= statecount
- 1)
2677 ScreenUpdate (state
[statecount
].screen_behind
);
2678 if (screen_virtual_segment
)
2679 dosv_refresh_virtual_screen (0, screen_size
);
2680 xfree (state
[statecount
].screen_behind
);
2682 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2684 IT_menu_display (state
[i
].menu
,
2688 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2689 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2691 ScreenRetrieve (state
[statecount
].screen_behind
2692 = xmalloc (screensize
));
2694 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2695 state
[statecount
].y
= y
;
2700 IT_menu_display (state
[statecount
- 1].menu
,
2701 state
[statecount
- 1].y
,
2702 state
[statecount
- 1].x
,
2706 /* We are busy-waiting for the mouse to move, so let's be nice
2707 to other Windows applications by releasing our time slice. */
2709 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
2711 /* Only leave if user both pressed and released the mouse, and in
2712 that order. This avoids popping down the menu pane unless
2713 the user is really done with it. */
2714 if (mouse_pressed (b
, &x
, &y
))
2716 while (mouse_button_depressed (b
, &x
, &y
))
2720 (void) mouse_released (b
, &x
, &y
);
2725 ScreenUpdate (state
[0].screen_behind
);
2726 if (screen_virtual_segment
)
2727 dosv_refresh_virtual_screen (0, screen_size
);
2728 while (statecount
--)
2729 xfree (state
[statecount
].screen_behind
);
2730 IT_display_cursor (1); /* turn cursor back on */
2731 /* Clean up any mouse events that are waiting inside Emacs event queue.
2732 These events are likely to be generated before the menu was even
2733 displayed, probably because the user pressed and released the button
2734 (which invoked the menu) too quickly. If we don't remove these events,
2735 Emacs will process them after we return and surprise the user. */
2736 discard_mouse_events ();
2737 /* Allow mouse events generation by dos_rawgetc. */
2742 /* Dispose of a menu. */
2745 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2748 if (menu
->allocated
)
2750 for (i
= 0; i
< menu
->count
; i
++)
2751 if (menu
->submenu
[i
])
2752 XMenuDestroy (foo
, menu
->submenu
[i
]);
2754 xfree (menu
->submenu
);
2755 xfree (menu
->panenumber
);
2761 x_pixel_width (struct frame
*f
)
2763 return FRAME_WIDTH (f
);
2767 x_pixel_height (struct frame
*f
)
2769 return FRAME_HEIGHT (f
);
2771 #endif /* !HAVE_X_WINDOWS */
2773 /* ----------------------- DOS / UNIX conversion --------------------- */
2775 void msdos_downcase_filename (unsigned char *);
2777 /* Destructively turn backslashes into slashes. */
2780 dostounix_filename (p
)
2783 msdos_downcase_filename (p
);
2793 /* Destructively turn slashes into backslashes. */
2796 unixtodos_filename (p
)
2799 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2813 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2816 getdefdir (drive
, dst
)
2820 char in_path
[4], *p
= in_path
;
2823 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2826 *p
++ = drive
+ 'A' - 1;
2833 _fixpath (in_path
, dst
);
2837 msdos_downcase_filename (dst
);
2843 /* Remove all CR's that are followed by a LF. */
2848 register unsigned char *buf
;
2850 unsigned char *np
= buf
;
2851 unsigned char *startp
= buf
;
2852 unsigned char *endp
= buf
+ n
;
2856 while (buf
< endp
- 1)
2860 if (*(++buf
) != 0x0a)
2871 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2873 /* In DJGPP v2.0, library `write' can call `malloc', which might
2874 cause relocation of the buffer whose address we get in ADDR.
2875 Here is a version of `write' that avoids calling `malloc',
2876 to serve us until such time as the library is fixed.
2877 Actually, what we define here is called `__write', because
2878 `write' is a stub that just jmp's to `__write' (to be
2879 POSIXLY-correct with respect to the global name-space). */
2881 #include <io.h> /* for _write */
2882 #include <libc/dosio.h> /* for __file_handle_modes[] */
2884 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2886 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2889 __write (int handle
, const void *buffer
, size_t count
)
2894 if(__file_handle_modes
[handle
] & O_BINARY
)
2895 return _write (handle
, buffer
, count
);
2899 const char *bp
= buffer
;
2900 int total_written
= 0;
2901 int nmoved
= 0, ncr
= 0;
2905 /* The next test makes sure there's space for at least 2 more
2906 characters in xbuf[], so both CR and LF can be put there. */
2918 if (xbp
>= XBUF_END
|| !count
)
2920 size_t to_write
= nmoved
+ ncr
;
2921 int written
= _write (handle
, xbuf
, to_write
);
2926 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2928 /* If some, but not all were written (disk full?), return
2929 an estimate of the total written bytes not counting CRs. */
2930 if (written
< to_write
)
2931 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2938 return total_written
;
2942 /* A low-level file-renaming function which works around Windows 95 bug.
2943 This is pulled directly out of DJGPP v2.01 library sources, and only
2944 used when you compile with DJGPP v2.0. */
2948 int _rename(const char *old
, const char *new)
2951 int olen
= strlen(old
) + 1;
2953 int use_lfn
= _USE_LFN
;
2954 char tempfile
[FILENAME_MAX
];
2955 const char *orig
= old
;
2958 r
.x
.dx
= __tb_offset
;
2959 r
.x
.di
= __tb_offset
+ olen
;
2960 r
.x
.ds
= r
.x
.es
= __tb_segment
;
2964 /* Windows 95 bug: for some filenames, when you rename
2965 file -> file~ (as in Emacs, to leave a backup), the
2966 short 8+3 alias doesn't change, which effectively
2967 makes OLD and NEW the same file. We must rename
2968 through a temporary file to work around this. */
2970 char *pbase
= 0, *p
;
2971 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
2972 int idx
= sizeof(try_char
) - 1;
2974 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2975 might point to another drive, which will fail the DOS call. */
2976 strcpy(tempfile
, old
);
2977 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
2978 if (*p
== '/' || *p
== '\\' || *p
== ':')
2984 strcpy(pbase
, "X$$djren$$.$$temp$$");
2990 *pbase
= try_char
[--idx
];
2991 } while (_chmod(tempfile
, 0) != -1);
2994 _put_path2(tempfile
, olen
);
2996 __dpmi_int(0x21, &r
);
2999 errno
= __doserr_to_errno(r
.x
.ax
);
3003 /* Now create a file with the original name. This will
3004 ensure that NEW will always have a 8+3 alias
3005 different from that of OLD. (Seems to be required
3006 when NameNumericTail in the Registry is set to 0.) */
3007 lfn_fd
= _creat(old
, 0);
3009 olen
= strlen(tempfile
) + 1;
3011 r
.x
.di
= __tb_offset
+ olen
;
3020 _put_path2(new, olen
);
3022 __dpmi_int(0x21, &r
);
3025 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
3026 remove(new); /* and try again */
3029 errno
= __doserr_to_errno(r
.x
.ax
);
3031 /* Restore to original name if we renamed it to temporary. */
3039 _put_path2(orig
, olen
);
3040 _put_path(tempfile
);
3042 __dpmi_int(0x21, &r
);
3051 /* Success. Delete the file possibly created to work
3052 around the Windows 95 bug. */
3054 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
3058 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
3060 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3062 "Return non-nil if long file names are supported on MSDOS.")
3065 return (_USE_LFN
? Qt
: Qnil
);
3068 /* Convert alphabetic characters in a filename to lower-case. */
3071 msdos_downcase_filename (p
)
3072 register unsigned char *p
;
3074 /* Always lower-case drive letters a-z, even if the filesystem
3075 preserves case in filenames.
3076 This is so MSDOS filenames could be compared by string comparison
3077 functions that are case-sensitive. Even case-preserving filesystems
3078 do not distinguish case in drive letters. */
3079 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3085 /* Under LFN we expect to get pathnames in their true case. */
3086 if (NILP (Fmsdos_long_file_names ()))
3088 if (*p
>= 'A' && *p
<= 'Z')
3092 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3094 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
3095 When long filenames are supported, doesn't change FILENAME.\n\
3096 If FILENAME is not a string, returns nil.\n\
3097 The argument object is never altered--the value is a copy.")
3099 Lisp_Object filename
;
3103 if (! STRINGP (filename
))
3106 tem
= Fcopy_sequence (filename
);
3107 msdos_downcase_filename (XSTRING (tem
)->data
);
3111 /* The Emacs root directory as determined by init_environment. */
3113 static char emacsroot
[MAXPATHLEN
];
3116 rootrelativepath (rel
)
3119 static char result
[MAXPATHLEN
+ 10];
3121 strcpy (result
, emacsroot
);
3122 strcat (result
, "/");
3123 strcat (result
, rel
);
3127 /* Define a lot of environment variables if not already defined. Don't
3128 remove anything unless you know what you're doing -- lots of code will
3129 break if one or more of these are missing. */
3132 init_environment (argc
, argv
, skip_args
)
3139 static const char * const tempdirs
[] = {
3140 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3143 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
3145 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3146 temporary files and assume "/tmp" if $TMPDIR is unset, which
3147 will break on DOS/Windows. Refuse to work if we cannot find
3148 a directory, not even "c:/", usable for that purpose. */
3149 for (i
= 0; i
< imax
; i
++)
3151 const char *tmp
= tempdirs
[i
];
3154 tmp
= getenv (tmp
+ 1);
3155 /* Note that `access' can lie to us if the directory resides on a
3156 read-only filesystem, like CD-ROM or a write-protected floppy.
3157 The only way to be really sure is to actually create a file and
3158 see if it succeeds. But I think that's too much to ask. */
3159 if (tmp
&& access (tmp
, D_OK
) == 0)
3161 setenv ("TMPDIR", tmp
, 1);
3168 Fcons (build_string ("no usable temporary directories found!!"),
3170 "While setting TMPDIR: ");
3172 /* Note the startup time, so we know not to clear the screen if we
3173 exit immediately; see IT_reset_terminal_modes.
3174 (Yes, I know `clock' returns zero the first time it's called, but
3175 I do this anyway, in case some wiseguy changes that at some point.) */
3176 startup_time
= clock ();
3178 /* Find our root from argv[0]. Assuming argv[0] is, say,
3179 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3180 root
= alloca (MAXPATHLEN
+ 20);
3181 _fixpath (argv
[0], root
);
3182 msdos_downcase_filename (root
);
3183 len
= strlen (root
);
3184 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
3188 && (strcmp (root
+ len
- 4, "/bin") == 0
3189 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
3190 root
[len
- 4] = '\0';
3192 strcpy (root
, "c:/emacs"); /* let's be defensive */
3193 len
= strlen (root
);
3194 strcpy (emacsroot
, root
);
3196 /* We default HOME to our root. */
3197 setenv ("HOME", root
, 0);
3199 /* We default EMACSPATH to root + "/bin". */
3200 strcpy (root
+ len
, "/bin");
3201 setenv ("EMACSPATH", root
, 0);
3203 /* I don't expect anybody to ever use other terminals so the internal
3204 terminal is the default. */
3205 setenv ("TERM", "internal", 0);
3207 #ifdef HAVE_X_WINDOWS
3208 /* Emacs expects DISPLAY to be set. */
3209 setenv ("DISPLAY", "unix:0.0", 0);
3212 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3213 downcase it and mirror the backslashes. */
3214 s
= getenv ("COMSPEC");
3215 if (!s
) s
= "c:/command.com";
3216 t
= alloca (strlen (s
) + 1);
3218 dostounix_filename (t
);
3219 setenv ("SHELL", t
, 0);
3221 /* PATH is also downcased and backslashes mirrored. */
3222 s
= getenv ("PATH");
3224 t
= alloca (strlen (s
) + 3);
3225 /* Current directory is always considered part of MsDos's path but it is
3226 not normally mentioned. Now it is. */
3227 strcat (strcpy (t
, ".;"), s
);
3228 dostounix_filename (t
); /* Not a single file name, but this should work. */
3229 setenv ("PATH", t
, 1);
3231 /* In some sense all dos users have root privileges, so... */
3232 setenv ("USER", "root", 0);
3233 setenv ("NAME", getenv ("USER"), 0);
3235 /* Time zone determined from country code. To make this possible, the
3236 country code may not span more than one time zone. In other words,
3237 in the USA, you lose. */
3239 switch (dos_country_code
)
3241 case 31: /* Belgium */
3242 case 32: /* The Netherlands */
3243 case 33: /* France */
3244 case 34: /* Spain */
3245 case 36: /* Hungary */
3246 case 38: /* Yugoslavia (or what's left of it?) */
3247 case 39: /* Italy */
3248 case 41: /* Switzerland */
3249 case 42: /* Tjekia */
3250 case 45: /* Denmark */
3251 case 46: /* Sweden */
3252 case 47: /* Norway */
3253 case 48: /* Poland */
3254 case 49: /* Germany */
3255 /* Daylight saving from last Sunday in March to last Sunday in
3256 September, both at 2AM. */
3257 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3259 case 44: /* United Kingdom */
3260 case 351: /* Portugal */
3261 case 354: /* Iceland */
3262 setenv ("TZ", "GMT+00", 0);
3264 case 81: /* Japan */
3265 case 82: /* Korea */
3266 setenv ("TZ", "JST-09", 0);
3268 case 90: /* Turkey */
3269 case 358: /* Finland */
3270 setenv ("TZ", "EET-02", 0);
3272 case 972: /* Israel */
3273 /* This is an approximation. (For exact rules, use the
3274 `zoneinfo/israel' file which comes with DJGPP, but you need
3275 to install it in `/usr/share/zoneinfo/' directory first.) */
3276 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3284 static int break_stat
; /* BREAK check mode status. */
3285 static int stdin_stat
; /* stdin IOCTL status. */
3289 /* These must be global. */
3290 static _go32_dpmi_seginfo ctrl_break_vector
;
3291 static _go32_dpmi_registers ctrl_break_regs
;
3292 static int ctrlbreakinstalled
= 0;
3294 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3297 ctrl_break_func (regs
)
3298 _go32_dpmi_registers
*regs
;
3304 install_ctrl_break_check ()
3306 if (!ctrlbreakinstalled
)
3308 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3309 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3310 ctrlbreakinstalled
= 1;
3311 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
3312 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
3314 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
3318 #endif /* __DJGPP__ < 2 */
3320 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3321 control chars by DOS. Determine the keyboard type. */
3326 union REGS inregs
, outregs
;
3327 static int first_time
= 1;
3329 break_stat
= getcbrk ();
3332 install_ctrl_break_check ();
3338 int86 (0x15, &inregs
, &outregs
);
3339 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
3343 if (internal_terminal
3344 #ifdef HAVE_X_WINDOWS
3345 && inhibit_window_system
3349 inregs
.x
.ax
= 0x0021;
3350 int86 (0x33, &inregs
, &outregs
);
3351 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3354 /* Reportedly, the above doesn't work for some mouse drivers. There
3355 is an additional detection method that should work, but might be
3356 a little slower. Use that as an alternative. */
3357 inregs
.x
.ax
= 0x0000;
3358 int86 (0x33, &inregs
, &outregs
);
3359 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3364 have_mouse
= 1; /* enable mouse */
3367 if (outregs
.x
.bx
== 3)
3369 mouse_button_count
= 3;
3370 mouse_button_translate
[0] = 0; /* Left */
3371 mouse_button_translate
[1] = 2; /* Middle */
3372 mouse_button_translate
[2] = 1; /* Right */
3376 mouse_button_count
= 2;
3377 mouse_button_translate
[0] = 0;
3378 mouse_button_translate
[1] = 1;
3380 mouse_position_hook
= &mouse_get_pos
;
3389 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
3390 return (stdin_stat
!= -1);
3393 return (setmode (fileno (stdin
), O_BINARY
) != -1);
3395 #else /* __DJGPP__ < 2 */
3399 /* I think it is wrong to overwrite `stdin_stat' every time
3400 but the first one this function is called, but I don't
3401 want to change the way it used to work in v1.x.--EZ */
3403 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
3404 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3405 intdos (&inregs
, &outregs
);
3406 stdin_stat
= outregs
.h
.dl
;
3408 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
3409 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
3410 intdos (&inregs
, &outregs
);
3411 return !outregs
.x
.cflag
;
3413 #endif /* __DJGPP__ < 2 */
3416 /* Restore status of standard input and Ctrl-C checking. */
3421 union REGS inregs
, outregs
;
3423 setcbrk (break_stat
);
3428 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3430 #else /* not __DJGPP__ >= 2 */
3432 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
3433 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3434 inregs
.x
.dx
= stdin_stat
;
3435 intdos (&inregs
, &outregs
);
3436 return !outregs
.x
.cflag
;
3438 #endif /* not __DJGPP__ >= 2 */
3442 /* Run command as specified by ARGV in directory DIR.
3443 The command is run with input from TEMPIN, output to
3444 file TEMPOUT and stderr to TEMPERR. */
3447 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
3448 unsigned char **argv
;
3449 const char *working_dir
;
3450 int tempin
, tempout
, temperr
;
3453 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3454 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3455 int msshell
, result
= -1;
3456 int inbak
, outbak
, errbak
;
3460 /* Get current directory as MSDOS cwd is not per-process. */
3463 /* If argv[0] is the shell, it might come in any lettercase.
3464 Since `Fmember' is case-sensitive, we need to downcase
3465 argv[0], even if we are on case-preserving filesystems. */
3466 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3467 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3470 if (*pl
>= 'A' && *pl
<= 'Z')
3475 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3476 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3477 && !strcmp ("-c", argv
[1]);
3480 saveargv1
= argv
[1];
3481 saveargv2
= argv
[2];
3485 char *p
= alloca (strlen (argv
[2]) + 1);
3487 strcpy (argv
[2] = p
, saveargv2
);
3488 while (*p
&& isspace (*p
))
3490 while (*p
&& !isspace (*p
))
3498 chdir (working_dir
);
3502 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3503 goto done
; /* Allocation might fail due to lack of descriptors. */
3506 mouse_get_xy (&x
, &y
);
3508 dos_ttcooked (); /* do it here while 0 = stdin */
3516 if (msshell
&& !argv
[3])
3518 /* MS-DOS native shells are too restrictive. For starters, they
3519 cannot grok commands longer than 126 characters. In DJGPP v2
3520 and later, `system' is much smarter, so we'll call it instead. */
3524 /* A shell gets a single argument--its full command
3525 line--whose original was saved in `saveargv2'. */
3527 /* Don't let them pass empty command lines to `system', since
3528 with some shells it will try to invoke an interactive shell,
3529 which will hang Emacs. */
3530 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3534 extern char **environ
;
3535 int save_system_flags
= __system_flags
;
3537 /* Request the most powerful version of `system'. We need
3538 all the help we can get to avoid calling stock DOS shells. */
3539 __system_flags
= (__system_redirect
3540 | __system_use_shell
3541 | __system_allow_multiple_cmds
3542 | __system_allow_long_cmds
3543 | __system_handle_null_commands
3544 | __system_emulate_chdir
);
3547 result
= system (cmnd
);
3548 __system_flags
= save_system_flags
;
3551 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3555 #endif /* __DJGPP__ > 1 */
3557 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3570 mouse_moveto (x
, y
);
3573 /* Some programs might change the meaning of the highest bit of the
3574 text attribute byte, so we get blinking characters instead of the
3575 bright background colors. Restore that. */
3582 argv
[1] = saveargv1
;
3583 argv
[2] = saveargv2
;
3591 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3598 /* ------------------------- Compatibility functions -------------------
3603 /* Hostnames for a pc are not really funny,
3604 but they are used in change log so we emulate the best we can. */
3606 gethostname (p
, size
)
3610 char *q
= egetenv ("HOSTNAME");
3617 /* When time zones are set from Ms-Dos too many C-libraries are playing
3618 tricks with time values. We solve this by defining our own version
3619 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3620 once and after each call to `tzset' with TZ changed. That is
3621 accomplished by aliasing tzset to init_gettimeofday. */
3623 static struct tm time_rec
;
3626 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3634 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3638 time_rec
.tm_year
= d
.da_year
- 1900;
3639 time_rec
.tm_mon
= d
.da_mon
- 1;
3640 time_rec
.tm_mday
= d
.da_day
;
3643 time_rec
.tm_hour
= t
.ti_hour
;
3644 time_rec
.tm_min
= t
.ti_min
;
3645 time_rec
.tm_sec
= t
.ti_sec
;
3648 tm
.tm_gmtoff
= dos_timezone_offset
;
3650 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3651 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3653 /* Ignore tzp; it's obsolescent. */
3657 #endif /* __DJGPP__ < 2 */
3660 * A list of unimplemented functions that we silently ignore.
3664 unsigned alarm (s
) unsigned s
; {}
3665 fork () { return 0; }
3666 int kill (x
, y
) int x
, y
; { return -1; }
3668 void volatile pause () {}
3669 sigsetmask (x
) int x
; { return 0; }
3670 sigblock (mask
) int mask
; { return 0; }
3673 void request_sigio (void) {}
3674 setpgrp () {return 0; }
3675 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3676 void unrequest_sigio (void) {}
3680 #ifdef POSIX_SIGNALS
3682 /* Augment DJGPP library POSIX signal functions. This is needed
3683 as of DJGPP v2.01, but might be in the library in later releases. */
3685 #include <libc/bss.h>
3687 /* A counter to know when to re-initialize the static sets. */
3688 static int sigprocmask_count
= -1;
3690 /* Which signals are currently blocked (initially none). */
3691 static sigset_t current_mask
;
3693 /* Which signals are pending (initially none). */
3694 static sigset_t pending_signals
;
3696 /* Previous handlers to restore when the blocked signals are unblocked. */
3697 typedef void (*sighandler_t
)(int);
3698 static sighandler_t prev_handlers
[320];
3700 /* A signal handler which just records that a signal occured
3701 (it will be raised later, if and when the signal is unblocked). */
3703 sig_suspender (signo
)
3706 sigaddset (&pending_signals
, signo
);
3710 sigprocmask (how
, new_set
, old_set
)
3712 const sigset_t
*new_set
;
3718 /* If called for the first time, initialize. */
3719 if (sigprocmask_count
!= __bss_count
)
3721 sigprocmask_count
= __bss_count
;
3722 sigemptyset (&pending_signals
);
3723 sigemptyset (¤t_mask
);
3724 for (signo
= 0; signo
< 320; signo
++)
3725 prev_handlers
[signo
] = SIG_ERR
;
3729 *old_set
= current_mask
;
3734 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3740 sigemptyset (&new_mask
);
3742 /* DJGPP supports upto 320 signals. */
3743 for (signo
= 0; signo
< 320; signo
++)
3745 if (sigismember (¤t_mask
, signo
))
3746 sigaddset (&new_mask
, signo
);
3747 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3749 sigaddset (&new_mask
, signo
);
3751 /* SIGKILL is silently ignored, as on other platforms. */
3752 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3753 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3755 if (( how
== SIG_UNBLOCK
3756 && sigismember (&new_mask
, signo
)
3757 && sigismember (new_set
, signo
))
3758 || (how
== SIG_SETMASK
3759 && sigismember (&new_mask
, signo
)
3760 && !sigismember (new_set
, signo
)))
3762 sigdelset (&new_mask
, signo
);
3763 if (prev_handlers
[signo
] != SIG_ERR
)
3765 signal (signo
, prev_handlers
[signo
]);
3766 prev_handlers
[signo
] = SIG_ERR
;
3768 if (sigismember (&pending_signals
, signo
))
3770 sigdelset (&pending_signals
, signo
);
3775 current_mask
= new_mask
;
3779 #else /* not POSIX_SIGNALS */
3781 sigsetmask (x
) int x
; { return 0; }
3782 sigblock (mask
) int mask
; { return 0; }
3784 #endif /* not POSIX_SIGNALS */
3785 #endif /* __DJGPP__ > 1 */
3788 #include "sysselect.h"
3790 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3791 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3792 ((long)(time).tv_sec < 0 \
3793 || ((time).tv_sec == 0 \
3794 && (long)(time).tv_usec <= 0))
3797 /* This yields the rest of the current time slice to the task manager.
3798 It should be called by any code which knows that it has nothing
3799 useful to do except idle.
3801 I don't use __dpmi_yield here, since versions of library before 2.02
3802 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3803 on some versions of Windows 9X. */
3806 dos_yield_time_slice (void)
3808 _go32_dpmi_registers r
;
3811 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
3812 _go32_dpmi_simulate_int (0x2f, &r
);
3817 /* Only event queue is checked. */
3818 /* We don't have to call timer_check here
3819 because wait_reading_process_input takes care of that. */
3821 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3823 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3824 EMACS_TIME
*timeout
;
3832 check_input
= FD_ISSET (0, rfds
);
3843 /* If we are looking only for the terminal, with no timeout,
3844 just read it and wait -- that's more efficient. */
3847 while (!detect_input_pending ())
3849 dos_yield_time_slice ();
3854 EMACS_TIME clnow
, cllast
, cldiff
;
3857 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3859 while (!check_input
|| !detect_input_pending ())
3862 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3863 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3865 /* When seconds wrap around, we assume that no more than
3866 1 minute passed since last `gettime'. */
3867 if (EMACS_TIME_NEG_P (cldiff
))
3868 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3869 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3871 /* Stop when timeout value crosses zero. */
3872 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3875 dos_yield_time_slice ();
3885 * Define overlaid functions:
3887 * chdir -> sys_chdir
3888 * tzset -> init_gettimeofday
3889 * abort -> dos_abort
3894 extern int chdir ();
3900 int len
= strlen (path
);
3901 char *tmp
= (char *)path
;
3903 if (*tmp
&& tmp
[1] == ':')
3905 if (getdisk () != tolower (tmp
[0]) - 'a')
3906 setdisk (tolower (tmp
[0]) - 'a');
3907 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3911 if (len
> 1 && (tmp
[len
- 1] == '/'))
3913 char *tmp1
= (char *) alloca (len
+ 1);
3924 extern void tzset (void);
3927 init_gettimeofday ()
3933 ltm
= gtm
= time (NULL
);
3934 ltm
= mktime (lstm
= localtime (<m
));
3935 gtm
= mktime (gmtime (>m
));
3936 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
3937 time_rec
.tm_isdst
= lstm
->tm_isdst
;
3938 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
3945 dos_abort (file
, line
)
3949 char buffer1
[200], buffer2
[400];
3952 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
3953 for (i
= j
= 0; buffer1
[i
]; i
++) {
3954 buffer2
[j
++] = buffer1
[i
];
3955 buffer2
[j
++] = 0x70;
3957 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3958 ScreenSetCursor (2, 0);
3966 ScreenSetCursor (10, 0);
3967 cputs ("\r\n\nEmacs aborted!\r\n");
3969 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3970 if (screen_virtual_segment
)
3971 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
3972 /* Generate traceback, so we could tell whodunit. */
3973 signal (SIGINT
, SIG_DFL
);
3974 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3975 #else /* __DJGPP_MINOR__ >= 2 */
3977 #endif /* __DJGPP_MINOR__ >= 2 */
3983 /* The following two are required so that customization feature
3984 won't complain about unbound variables. */
3985 #ifndef HAVE_X_WINDOWS
3986 /* Search path for bitmap files (xfns.c). */
3987 Lisp_Object Vx_bitmap_file_path
;
3989 #ifndef subprocesses
3990 /* Nonzero means delete a process right away if it exits (process.c). */
3991 static int delete_exited_processes
;
3996 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3997 staticpro (&recent_doskeys
);
3998 #ifndef HAVE_X_WINDOWS
3999 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
4000 "List of directories to search for bitmap files for X.");
4001 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
4003 /* The following three are from xfns.c: */
4004 Qbackground_color
= intern ("background-color");
4005 staticpro (&Qbackground_color
);
4006 Qforeground_color
= intern ("foreground-color");
4007 staticpro (&Qforeground_color
);
4009 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
4010 "*Glyph to display instead of chars not supported by current codepage.\n\
4012 This variable is used only by MSDOS terminals.");
4013 Vdos_unsupported_char_glyph
= '\177';
4015 #ifndef subprocesses
4016 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
4017 "*Non-nil means delete processes immediately when they exit.\n\
4018 nil means don't delete them until `list-processes' is run.");
4019 delete_exited_processes
= 0;
4022 defsubr (&Srecent_doskeys
);
4023 defsubr (&Smsdos_long_file_names
);
4024 defsubr (&Smsdos_downcase_filename
);