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 */
51 #include "termhooks.h"
53 #include "dispextern.h"
66 /* #include <process.h> */
67 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
75 #define _dos_ds _go32_info_block.selector_for_linear_memory
81 #include "syssignal.h"
87 /* If other `malloc' than ours is used, force our `sbrk' behave like
88 Unix programs expect (resize memory blocks to keep them contiguous).
89 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
90 because that's what `gmalloc' expects to get. */
94 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
95 #else /* not REL_ALLOC */
96 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
97 #endif /* not REL_ALLOC */
98 #endif /* GNU_MALLOC */
100 #endif /* not SYSTEM_MALLOC */
101 #endif /* __DJGPP__ > 1 */
120 /* ------------------------ Mouse control ---------------------------
122 * Coordinates are in screen positions and zero based.
123 * Mouse buttons are numbered from left to right and also zero based.
126 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
127 static int mouse_visible
;
129 static int mouse_last_x
;
130 static int mouse_last_y
;
132 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
133 static int mouse_button_count
;
140 if (have_mouse
> 0 && !mouse_visible
)
143 fprintf (termscript
, "<M_ON>");
145 int86 (0x33, ®s
, ®s
);
155 if (have_mouse
> 0 && mouse_visible
)
158 fprintf (termscript
, "<M_OFF>");
160 int86 (0x33, ®s
, ®s
);
166 mouse_get_xy (int *x
, int *y
)
171 int86 (0x33, ®s
, ®s
);
183 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
185 mouse_last_x
= regs
.x
.cx
= x
* 8;
186 mouse_last_y
= regs
.x
.dx
= y
* 8;
187 int86 (0x33, ®s
, ®s
);
191 mouse_pressed (b
, xp
, yp
)
196 if (b
>= mouse_button_count
)
199 regs
.x
.bx
= mouse_button_translate
[b
];
200 int86 (0x33, ®s
, ®s
);
202 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
203 return (regs
.x
.bx
!= 0);
207 mouse_released (b
, xp
, yp
)
212 if (b
>= mouse_button_count
)
215 regs
.x
.bx
= mouse_button_translate
[b
];
216 int86 (0x33, ®s
, ®s
);
218 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
219 return (regs
.x
.bx
!= 0);
223 mouse_button_depressed (b
, xp
, yp
)
228 if (b
>= mouse_button_count
)
231 int86 (0x33, ®s
, ®s
);
232 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
242 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
245 Lisp_Object
*bar_window
, *x
, *y
;
246 enum scroll_bar_part
*part
;
250 Lisp_Object frame
, tail
;
252 /* Clear the mouse-moved flag for every frame on this display. */
253 FOR_EACH_FRAME (tail
, frame
)
254 XFRAME (frame
)->mouse_moved
= 0;
258 mouse_get_xy (&ix
, &iy
);
259 *time
= event_timestamp ();
260 *x
= make_number (mouse_last_x
= ix
);
261 *y
= make_number (mouse_last_y
= iy
);
269 mouse_get_xy (&x
, &y
);
270 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
282 fprintf (termscript
, "<M_INIT>");
285 int86 (0x33, ®s
, ®s
);
287 /* Reset the mouse last press/release info. It seems that Windows
288 doesn't do that automatically when function 21h is called, which
289 causes Emacs to ``remember'' the click that switched focus to the
290 window just before Emacs was started from that window. */
291 for (b
= 0; b
< mouse_button_count
; b
++)
293 int dummy_x
, dummy_y
;
295 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
296 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
301 regs
.x
.dx
= 8 * (ScreenCols () - 1);
302 int86 (0x33, ®s
, ®s
);
306 regs
.x
.dx
= 8 * (ScreenRows () - 1);
307 int86 (0x33, ®s
, ®s
);
313 /* ------------------------- Screen control ----------------------
317 static int internal_terminal
= 0;
319 #ifndef HAVE_X_WINDOWS
320 extern unsigned char ScreenAttrib
;
321 static int screen_face
;
322 static int highlight
;
324 static int screen_size_X
;
325 static int screen_size_Y
;
326 static int screen_size
;
328 static int current_pos_X
;
329 static int current_pos_Y
;
330 static int new_pos_X
;
331 static int new_pos_Y
;
333 static void *startup_screen_buffer
;
334 static int startup_screen_size_X
;
335 static int startup_screen_size_Y
;
336 static int startup_pos_X
;
337 static int startup_pos_Y
;
338 static unsigned char startup_screen_attrib
;
340 static clock_t startup_time
;
342 static int term_setup_done
;
344 /* Similar to the_only_frame. */
345 struct x_output the_only_x_display
;
347 /* This is never dereferenced. */
348 Display
*x_current_display
;
350 /* Support for DOS/V (allows Japanese characters to be displayed on
351 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
353 /* Holds the address of the text-mode screen buffer. */
354 static unsigned long screen_old_address
= 0;
355 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
356 static unsigned short screen_virtual_segment
= 0;
357 static unsigned short screen_virtual_offset
= 0;
358 /* A flag to control how to display unibyte 8-bit characters. */
359 extern int unibyte_display_via_language_environment
;
362 /* Update the screen from a part of relocated DOS/V screen buffer which
363 begins at OFFSET and includes COUNT characters. */
365 dosv_refresh_virtual_screen (int offset
, int count
)
369 if (offset
< 0 || count
< 0) /* paranoia; illegal values crash DOS/V */
372 regs
.h
.ah
= 0xff; /* update relocated screen */
373 regs
.x
.es
= screen_virtual_segment
;
374 regs
.x
.di
= screen_virtual_offset
+ offset
;
376 __dpmi_int (0x10, ®s
);
381 dos_direct_output (y
, x
, buf
, len
)
387 int t0
= 2 * (x
+ y
* screen_size_X
);
388 int t
= t0
+ (int) ScreenPrimary
;
393 dosmemput (buf
++, 1, t
);
397 /* This is faster. */
398 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
399 _farnspokeb (t
, *buf
);
401 if (screen_virtual_segment
)
402 dosv_refresh_virtual_screen (t0
, l0
);
407 /* Flash the screen as a substitute for BEEPs. */
411 do_visible_bell (xorattr
)
412 unsigned char xorattr
;
417 movl _ScreenPrimary,%%eax
424 xorb %%al,%%gs:(%%ebx)
440 : "m" (xorattr
), "g" (screen_size
)
441 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
445 ScreenVisualBell (void)
447 /* This creates an xor-mask that will swap the default fore- and
448 background colors. */
449 do_visible_bell (((the_only_x_display
.foreground_pixel
450 ^ the_only_x_display
.background_pixel
)
455 #ifndef HAVE_X_WINDOWS
457 static int blink_bit
= -1; /* the state of the blink bit at startup */
459 /* Enable bright background colors. */
465 /* Remember the original state of the blink/bright-background bit.
466 It is stored at 0040:0065h in the BIOS data area. */
468 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
472 int86 (0x10, ®s
, ®s
);
475 /* Disable bright background colors (and enable blinking) if we found
476 the video system in that state at startup. */
478 maybe_enable_blinking (void)
486 int86 (0x10, ®s
, ®s
);
490 /* Set the screen dimensions so that it can show no less than
491 ROWS x COLS frame. */
494 dos_set_window_size (rows
, cols
)
498 Lisp_Object video_mode
;
499 int video_mode_value
;
502 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
504 if (*rows
== current_rows
&& *cols
== current_cols
)
507 /* Do we have a VGA? */
509 int86 (0x10, ®s
, ®s
);
510 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
515 /* If the user specified a special video mode for these dimensions,
517 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
518 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
521 if (INTEGERP (video_mode
)
522 && (video_mode_value
= XINT (video_mode
)) > 0)
524 regs
.x
.ax
= video_mode_value
;
525 int86 (0x10, ®s
, ®s
);
529 /* Must hardware-reset the mouse, or else it won't update
530 its notion of screen dimensions for some non-standard
531 video modes. This is *painfully* slow... */
533 int86 (0x33, ®s
, ®s
);
537 /* Find one of the dimensions supported by standard EGA/VGA
538 which gives us at least the required dimensions. */
547 } std_dimension
[] = {
557 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
559 if (std_dimension
[i
].need_vga
<= have_vga
560 && std_dimension
[i
].rows
>= *rows
)
562 if (std_dimension
[i
].rows
!= current_rows
563 || *cols
!= current_cols
)
564 _set_screen_lines (std_dimension
[i
].rows
);
571 #else /* not __DJGPP__ > 1 */
573 else if (*rows
<= 25)
575 if (current_rows
!= 25 || current_cols
!= 80)
578 int86 (0x10, ®s
, ®s
);
581 int86 (0x10, ®s
, ®s
);
584 int86 (0x10, ®s
, ®s
);
586 int86 (0x10, ®s
, ®s
);
589 else if (*rows
<= 50)
590 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
591 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
594 int86 (0x10, ®s
, ®s
);
597 int86 (0x10, ®s
, ®s
);
600 int86 (0x10, ®s
, ®s
);
603 int86 (0x10, ®s
, ®s
);
605 #endif /* not __DJGPP__ > 1 */
613 /* Tell the caller what dimensions have been REALLY set. */
614 *rows
= ScreenRows ();
615 *cols
= ScreenCols ();
617 /* Enable bright background colors. */
620 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
621 be defensive anyway. */
622 if (screen_virtual_segment
)
623 dosv_refresh_virtual_screen (0, *cols
* *rows
);
626 /* If we write a character in the position where the mouse is,
627 the mouse cursor may need to be refreshed. */
637 mouse_get_xy (&x
, &y
);
638 if (y
!= new_pos_Y
|| x
< new_pos_X
)
654 union REGS inregs
, outregs
;
657 intdos (&inregs
, &outregs
);
661 /* Given a face id FACE, extract the face parameters to be used for
662 display until the face changes. The face parameters (actually, its
663 color) are used to construct the video attribute byte for each
664 glyph during the construction of the buffer that is then blitted to
667 IT_set_face (int face
)
669 struct face
*fp
= FACE_FROM_ID (selected_frame
, face
);
670 unsigned long fg
, bg
;
673 fp
= FACE_FROM_ID (selected_frame
, DEFAULT_FACE_ID
);
678 /* Don't use invalid colors. In particular, a color of -1 means use
679 the colors of the default face, except that if highlight is on,
680 invert the foreground and the background. Note that we assume
681 all 16 colors to be available for the background, since Emacs
682 switches on this mode (and loses the blinking attribute) at
684 if (fg
== (unsigned long)-1)
685 fg
= highlight
? FRAME_BACKGROUND_PIXEL (selected_frame
)
686 : FRAME_FOREGROUND_PIXEL (selected_frame
);
687 if (bg
== (unsigned long)-1)
688 bg
= highlight
? FRAME_FOREGROUND_PIXEL (selected_frame
)
689 : FRAME_BACKGROUND_PIXEL (selected_frame
);
691 fprintf (termscript
, "<FACE %d%s: %d/%d>",
692 face
, highlight
? "H" : "", fp
->foreground
, fp
->background
);
693 if (fg
>= 0 && fg
< 16)
695 ScreenAttrib
&= 0xf0;
698 if (bg
>= 0 && bg
< 16)
700 ScreenAttrib
&= 0x0f;
701 ScreenAttrib
|= ((bg
& 0x0f) << 4);
705 Lisp_Object Vdos_unsupported_char_glyph
;
708 IT_write_glyphs (struct glyph
*str
, int str_len
)
710 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
711 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
712 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
713 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
714 register int sl
= str_len
;
715 register int tlen
= GLYPH_TABLE_LENGTH
;
716 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
718 struct coding_system
*coding
= (CODING_REQUIRE_ENCODING (&terminal_coding
)
720 : &safe_terminal_coding
);
722 /* Do we need to consider conversion of unibyte characters to
724 int convert_unibyte_characters
725 = (NILP (current_buffer
->enable_multibyte_characters
)
726 && unibyte_display_via_language_environment
);
728 if (str_len
== 0) return;
730 screen_buf
= screen_bp
= alloca (str_len
* 2);
731 screen_buf_end
= screen_buf
+ str_len
* 2;
733 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
735 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
738 int cf
, chlen
, enclen
;
739 unsigned char workbuf
[4], *buf
;
741 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
743 /* Find the actual glyph to display by traversing the entire
744 aliases chain for this glyph. */
745 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
747 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
748 only for the redisplay code to know how many columns does
749 this character occupy on the screen. Skip padding glyphs. */
750 if (CHAR_GLYPH_PADDING_P (*str
))
757 /* Convert the character code to multibyte, if they
758 requested display via language environment. */
759 ch
= FAST_GLYPH_CHAR (g
);
760 /* We only want to convert unibyte characters to multibyte
761 in unibyte buffers! Otherwise, the 8-bit code might come
762 from the display table set up to display foreign characters. */
763 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
765 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
766 ch
= unibyte_char_to_multibyte (ch
);
768 /* Invalid characters are displayed with a special glyph. */
769 if (! GLYPH_CHAR_VALID_P (ch
))
771 g
= !NILP (Vdos_unsupported_char_glyph
)
772 ? Vdos_unsupported_char_glyph
773 : MAKE_GLYPH (selected_frame
, '\177',
774 GLYPH_FACE (selected_frame
, g
));
775 ch
= FAST_GLYPH_CHAR (g
);
777 if (COMPOSITE_CHAR_P (ch
))
779 /* If CH is a composite character, we can display
780 only the first component. */
781 g
= cmpchar_table
[COMPOSITE_CHAR_ID (ch
)]->glyph
[0],
782 ch
= GLYPH_CHAR (selected_frame
, g
);
783 cf
= FAST_GLYPH_FACE (g
);
786 /* If the face of this glyph is different from the current
787 screen face, update the screen attribute byte. */
788 cf
= FAST_GLYPH_FACE (g
);
789 if (cf
!= screen_face
)
790 IT_set_face (cf
); /* handles invalid faces gracefully */
792 if (GLYPH_SIMPLE_P (tbase
, tlen
, g
))
793 /* We generate the multi-byte form of CH in BUF. */
794 chlen
= CHAR_STRING (ch
, workbuf
, buf
);
797 /* We have a string in Vglyph_table. */
798 chlen
= GLYPH_LENGTH (tbase
, g
);
799 buf
= GLYPH_STRING (tbase
, g
);
802 /* If the character is not multibyte, don't bother converting it. */
805 *conversion_buffer
= (unsigned char)ch
;
811 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
812 conversion_buffer_size
);
813 chlen
-= coding
->consumed
;
814 enclen
= coding
->produced
;
816 /* Replace glyph codes that cannot be converted by
817 terminal_coding with Vdos_unsupported_char_glyph. */
818 if (*conversion_buffer
== '?')
820 char *cbp
= conversion_buffer
;
822 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
823 *cbp
++ = unsupported_char
;
824 if (unsupported_face
!= screen_face
)
825 IT_set_face (unsupported_face
);
829 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
831 /* The allocated buffer for screen writes is too small.
832 Flush it and loop again without incrementing STR, so
833 that the next loop will begin with the same glyph. */
834 int nbytes
= screen_bp
- screen_buf
;
837 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
838 if (screen_virtual_segment
)
839 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
840 new_pos_X
+= nbytes
/ 2;
843 /* Prepare to reuse the same buffer again. */
844 screen_bp
= screen_buf
;
848 /* There's enough place in the allocated buffer to add
849 the encoding of this glyph. */
851 /* First, copy the encoded bytes. */
852 for (bp
= conversion_buffer
; enclen
--; bp
++)
854 *screen_bp
++ = (unsigned char)*bp
;
855 *screen_bp
++ = ScreenAttrib
;
857 fputc (*bp
, termscript
);
860 /* Now copy the bytes not consumed by the encoding. */
863 buf
+= coding
->consumed
;
867 fputc (*buf
, termscript
);
868 *screen_bp
++ = (unsigned char)*buf
++;
869 *screen_bp
++ = ScreenAttrib
;
873 /* Update STR and its remaining length. */
880 /* Dump whatever is left in the screen buffer. */
882 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
883 if (screen_virtual_segment
)
884 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
885 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
887 /* We may have to output some codes to terminate the writing. */
888 if (CODING_REQUIRE_FLUSHING (coding
))
890 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
891 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
892 if (coding
->produced
> 0)
894 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
895 coding
->produced
--; bp
++)
897 *screen_bp
++ = (unsigned char)*bp
;
898 *screen_bp
++ = ScreenAttrib
;
900 fputc (*bp
, termscript
);
902 offset
+= screen_bp
- screen_buf
;
904 dosmemput (screen_buf
, screen_bp
- screen_buf
,
905 (int)ScreenPrimary
+ offset
);
906 if (screen_virtual_segment
)
907 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
908 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
914 IT_clear_end_of_line (int first_unused
)
918 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
919 extern int fatal_error_in_progress
;
921 if (fatal_error_in_progress
)
926 fprintf (termscript
, "<CLR:EOL>");
927 i
= (j
= screen_size_X
- new_pos_X
) * 2;
928 spaces
= sp
= alloca (i
);
933 *sp
++ = ScreenAttrib
;
937 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
938 if (screen_virtual_segment
)
939 dosv_refresh_virtual_screen (offset
, i
/ 2);
943 IT_clear_screen (void)
946 fprintf (termscript
, "<CLR:SCR>");
950 if (screen_virtual_segment
)
951 dosv_refresh_virtual_screen (0, screen_size
);
952 new_pos_X
= new_pos_Y
= 0;
956 IT_clear_to_end (void)
959 fprintf (termscript
, "<CLR:EOS>");
961 while (new_pos_Y
< screen_size_Y
) {
963 IT_clear_end_of_line (0);
969 IT_cursor_to (int y
, int x
)
972 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
977 static int cursor_cleared
;
980 IT_display_cursor (int on
)
982 if (on
&& cursor_cleared
)
984 ScreenSetCursor (current_pos_Y
, current_pos_X
);
987 else if (!on
&& !cursor_cleared
)
989 ScreenSetCursor (-1, -1);
994 /* Emacs calls cursor-movement functions a lot when it updates the
995 display (probably a legacy of old terminals where you cannot
996 update a screen line without first moving the cursor there).
997 However, cursor movement is expensive on MSDOS (it calls a slow
998 BIOS function and requires 2 mode switches), while actual screen
999 updates access the video memory directly and don't depend on
1000 cursor position. To avoid slowing down the redisplay, we cheat:
1001 all functions that move the cursor only set internal variables
1002 which record the cursor position, whereas the cursor is only
1003 moved to its final position whenever screen update is complete.
1005 `IT_cmgoto' is called from the keyboard reading loop and when the
1006 frame update is complete. This means that we are ready for user
1007 input, so we update the cursor position to show where the point is,
1008 and also make the mouse pointer visible.
1010 Special treatment is required when the cursor is in the echo area,
1011 to put the cursor at the end of the text displayed there. */
1014 IT_cmgoto (FRAME_PTR f
)
1016 /* Only set the cursor to where it should be if the display is
1017 already in sync with the window contents. */
1018 int update_cursor_pos
= MODIFF
== unchanged_modified
;
1019 static int previous_pos_X
= -1;
1021 /* If the display is in sync, forget any previous knowledge about
1022 cursor position. This is primarily for unexpected events like
1023 C-g in the minibuffer. */
1024 if (update_cursor_pos
&& previous_pos_X
>= 0)
1025 previous_pos_X
= -1;
1026 /* If we are in the echo area, put the cursor at the
1027 end of the echo area message. */
1028 if (!update_cursor_pos
1029 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1031 int tem_X
= current_pos_X
, dummy
;
1033 if (echo_area_glyphs
)
1035 tem_X
= echo_area_glyphs_length
;
1036 /* Save current cursor position, to be restored after the
1037 echo area message is erased. Only remember one level
1038 of previous cursor position. */
1039 if (previous_pos_X
== -1)
1040 ScreenGetCursor (&dummy
, &previous_pos_X
);
1042 else if (previous_pos_X
>= 0)
1044 /* We wind up here after the echo area message is erased.
1045 Restore the cursor position we remembered above. */
1046 tem_X
= previous_pos_X
;
1047 previous_pos_X
= -1;
1050 if (current_pos_X
!= tem_X
)
1053 update_cursor_pos
= 1;
1057 if (update_cursor_pos
1058 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1060 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1062 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1065 /* Maybe cursor is invisible, so make it visible. */
1066 IT_display_cursor (1);
1068 /* Mouse pointer should be always visible if we are waiting for
1075 IT_reassert_line_highlight (int new, int vpos
)
1078 IT_set_face (0); /* To possibly clear the highlighting. */
1082 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1084 highlight
= new_highlight
;
1085 IT_set_face (0); /* To possibly clear the highlighting. */
1086 IT_cursor_to (vpos
, 0);
1087 IT_clear_end_of_line (first_unused_hpos
);
1091 IT_update_begin (struct frame
*foo
)
1094 IT_set_face (0); /* To possibly clear the highlighting. */
1099 IT_update_end (struct frame
*foo
)
1103 /* Copy LEN glyphs displayed on a single line whose vertical position
1104 is YPOS, beginning at horizontal position XFROM to horizontal
1105 position XTO, by moving blocks in the video memory. Used by
1106 functions that insert and delete glyphs. */
1108 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1110 /* The offsets of source and destination relative to the
1111 conventional memorty selector. */
1112 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1113 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1115 if (from
== to
|| len
<= 0)
1118 _farsetsel (_dos_ds
);
1120 /* The source and destination might overlap, so we need to move
1121 glyphs non-destructively. */
1124 for ( ; len
; from
+= 2, to
+= 2, len
--)
1125 _farnspokew (to
, _farnspeekw (from
));
1129 from
+= (len
- 1) * 2;
1130 to
+= (len
- 1) * 2;
1131 for ( ; len
; from
-= 2, to
-= 2, len
--)
1132 _farnspokew (to
, _farnspeekw (from
));
1134 if (screen_virtual_segment
)
1135 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1138 /* Insert and delete glyphs. */
1140 IT_insert_glyphs (start
, len
)
1141 register struct glyph
*start
;
1144 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1146 /* Shift right the glyphs from the nominal cursor position to the
1147 end of this line. */
1148 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1150 /* Now write the glyphs to be inserted. */
1151 IT_write_glyphs (start
, len
);
1155 IT_delete_glyphs (n
)
1161 /* set-window-configuration on window.c needs this. */
1163 x_set_menu_bar_lines (f
, value
, oldval
)
1165 Lisp_Object value
, oldval
;
1167 set_menu_bar_lines (f
, value
, oldval
);
1170 /* This was copied from xfns.c */
1172 Lisp_Object Qbackground_color
;
1173 Lisp_Object Qforeground_color
;
1174 extern Lisp_Object Qtitle
;
1176 /* IT_set_terminal_modes is called when emacs is started,
1177 resumed, and whenever the screen is redrawn! */
1180 IT_set_terminal_modes (void)
1183 fprintf (termscript
, "\n<SET_TERM>");
1186 screen_size_X
= ScreenCols ();
1187 screen_size_Y
= ScreenRows ();
1188 screen_size
= screen_size_X
* screen_size_Y
;
1190 new_pos_X
= new_pos_Y
= 0;
1191 current_pos_X
= current_pos_Y
= -1;
1193 if (term_setup_done
)
1195 term_setup_done
= 1;
1197 startup_screen_size_X
= screen_size_X
;
1198 startup_screen_size_Y
= screen_size_Y
;
1199 startup_screen_attrib
= ScreenAttrib
;
1202 /* Is DOS/V (or any other RSIS software which relocates
1203 the screen) installed? */
1205 unsigned short es_value
;
1208 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1209 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1210 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1211 else if (screen_old_address
) /* already switched to Japanese mode once */
1212 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1214 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1216 es_value
= regs
.x
.es
;
1217 __dpmi_int (0x10, ®s
);
1219 if (regs
.x
.es
!= es_value
)
1221 /* screen_old_address is only set if ScreenPrimary does NOT
1222 already point to the relocated buffer address returned by
1223 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1224 ScreenPrimary to that address at startup under DOS/V. */
1225 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
1226 screen_old_address
= ScreenPrimary
;
1227 screen_virtual_segment
= regs
.x
.es
;
1228 screen_virtual_offset
= regs
.x
.di
;
1229 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1232 #endif /* __DJGPP__ > 1 */
1234 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1235 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1238 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1239 screen_size_X
, screen_size_Y
);
1244 /* IT_reset_terminal_modes is called when emacs is
1245 suspended or killed. */
1248 IT_reset_terminal_modes (void)
1250 int display_row_start
= (int) ScreenPrimary
;
1251 int saved_row_len
= startup_screen_size_X
* 2;
1252 int update_row_len
= ScreenCols () * 2;
1253 int current_rows
= ScreenRows ();
1254 int to_next_row
= update_row_len
;
1255 unsigned char *saved_row
= startup_screen_buffer
;
1256 int cursor_pos_X
= ScreenCols () - 1;
1257 int cursor_pos_Y
= ScreenRows () - 1;
1260 fprintf (termscript
, "\n<RESET_TERM>");
1264 if (!term_setup_done
)
1269 /* Leave the video system in the same state as we found it,
1270 as far as the blink/bright-background bit is concerned. */
1271 maybe_enable_blinking ();
1273 /* We have a situation here.
1274 We cannot just do ScreenUpdate(startup_screen_buffer) because
1275 the luser could have changed screen dimensions inside Emacs
1276 and failed (or didn't want) to restore them before killing
1277 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1278 thus will happily use memory outside what was allocated for
1279 `startup_screen_buffer'.
1280 Thus we only restore as much as the current screen dimensions
1281 can hold, and clear the rest (if the saved screen is smaller than
1282 the current) with the color attribute saved at startup. The cursor
1283 is also restored within the visible dimensions. */
1285 ScreenAttrib
= startup_screen_attrib
;
1287 /* Don't restore the screen if we are exiting less than 2 seconds
1288 after startup: we might be crashing, and the screen might show
1289 some vital clues to what's wrong. */
1290 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1293 if (screen_virtual_segment
)
1294 dosv_refresh_virtual_screen (0, screen_size
);
1296 if (update_row_len
> saved_row_len
)
1297 update_row_len
= saved_row_len
;
1298 if (current_rows
> startup_screen_size_Y
)
1299 current_rows
= startup_screen_size_Y
;
1302 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1303 update_row_len
/ 2, current_rows
);
1305 while (current_rows
--)
1307 dosmemput (saved_row
, update_row_len
, display_row_start
);
1308 if (screen_virtual_segment
)
1309 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
1310 update_row_len
/ 2);
1311 saved_row
+= saved_row_len
;
1312 display_row_start
+= to_next_row
;
1315 if (startup_pos_X
< cursor_pos_X
)
1316 cursor_pos_X
= startup_pos_X
;
1317 if (startup_pos_Y
< cursor_pos_Y
)
1318 cursor_pos_Y
= startup_pos_Y
;
1320 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
1321 xfree (startup_screen_buffer
);
1323 term_setup_done
= 0;
1327 IT_set_terminal_window (int foo
)
1332 IT_set_frame_parameters (f
, alist
)
1337 int length
= XINT (Flength (alist
));
1340 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1342 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1344 struct face
*dflt
= NULL
;
1346 if (FRAME_FACE_CACHE (f
))
1347 dflt
= FACE_FROM_ID (f
, DEFAULT_FACE_ID
);
1351 /* Extract parm names and values into those vectors. */
1353 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1358 parms
[i
] = Fcar (elt
);
1359 CHECK_SYMBOL (parms
[i
], 1);
1360 values
[i
] = Fcdr (elt
);
1365 /* Now process them in reverse of specified order. */
1366 for (i
--; i
>= 0; i
--)
1368 Lisp_Object prop
= parms
[i
];
1369 Lisp_Object val
= values
[i
];
1371 if (EQ (prop
, Qforeground_color
))
1373 unsigned long new_color
= load_color (f
, NULL
, val
,
1374 LFACE_FOREGROUND_INDEX
);
1375 if (new_color
!= ~0)
1379 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1380 dflt
->foreground
= new_color
;
1383 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
1386 else if (EQ (prop
, Qbackground_color
))
1388 unsigned long new_color
= load_color (f
, NULL
, val
,
1389 LFACE_BACKGROUND_INDEX
);
1390 if (new_color
!= ~0)
1394 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1395 dflt
->background
= new_color
;
1398 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
1401 else if (EQ (prop
, Qtitle
))
1403 x_set_title (f
, val
);
1405 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
1407 else if (EQ (prop
, intern ("reverse")) && EQ (val
, Qt
))
1409 unsigned long fg
= FRAME_FOREGROUND_PIXEL (f
);
1413 FRAME_FOREGROUND_PIXEL (f
) = FRAME_BACKGROUND_PIXEL (f
); /* FIXME! */
1414 FRAME_BACKGROUND_PIXEL (f
) = fg
;
1415 dflt
->foreground
= FRAME_FOREGROUND_PIXEL (f
);
1416 dflt
->foreground
= fg
;
1418 fprintf (termscript
, "<INVERSE-VIDEO>\n");
1420 store_frame_param (f
, prop
, val
);
1426 recompute_basic_faces (f
);
1427 if (f
== selected_frame
)
1432 extern void init_frame_faces (FRAME_PTR
);
1434 #endif /* !HAVE_X_WINDOWS */
1437 /* Do we need the internal terminal? */
1440 internal_terminal_init ()
1442 char *term
= getenv ("TERM");
1445 #ifdef HAVE_X_WINDOWS
1446 if (!inhibit_window_system
)
1451 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1453 if (getenv ("EMACSTEST"))
1454 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1456 #ifndef HAVE_X_WINDOWS
1457 if (!internal_terminal
|| inhibit_window_system
)
1459 selected_frame
->output_method
= output_termcap
;
1463 Vwindow_system
= intern ("pc");
1464 Vwindow_system_version
= make_number (1);
1466 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1467 screen_old_address
= 0;
1469 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1470 the_only_x_display
.background_pixel
= 7; /* White */
1471 the_only_x_display
.foreground_pixel
= 0; /* Black */
1473 colors
= getenv ("EMACSCOLORS");
1474 if (colors
&& strlen (colors
) >= 2)
1476 /* The colors use 4 bits each (we enable bright background). */
1477 if (isdigit (colors
[0]))
1479 else if (isxdigit (colors
[0]))
1480 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1481 if (colors
[0] >= 0 && colors
[0] < 16)
1482 the_only_x_display
.foreground_pixel
= colors
[0];
1483 if (isdigit (colors
[1]))
1485 else if (isxdigit (colors
[1]))
1486 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1487 if (colors
[1] >= 0 && colors
[1] < 16)
1488 the_only_x_display
.background_pixel
= colors
[1];
1490 the_only_x_display
.line_height
= 1;
1491 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1493 init_frame_faces (selected_frame
);
1495 ring_bell_hook
= IT_ring_bell
;
1496 insert_glyphs_hook
= IT_insert_glyphs
;
1497 delete_glyphs_hook
= IT_delete_glyphs
;
1498 write_glyphs_hook
= IT_write_glyphs
;
1499 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1500 clear_to_end_hook
= IT_clear_to_end
;
1501 clear_end_of_line_hook
= IT_clear_end_of_line
;
1502 clear_frame_hook
= IT_clear_screen
;
1503 change_line_highlight_hook
= IT_change_line_highlight
;
1504 update_begin_hook
= IT_update_begin
;
1505 update_end_hook
= IT_update_end
;
1506 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1507 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1509 /* These hooks are called by term.c without being checked. */
1510 set_terminal_modes_hook
= IT_set_terminal_modes
;
1511 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1512 set_terminal_window_hook
= IT_set_terminal_window
;
1513 char_ins_del_ok
= 0;
1517 dos_get_saved_screen (screen
, rows
, cols
)
1522 #ifndef HAVE_X_WINDOWS
1523 *screen
= startup_screen_buffer
;
1524 *cols
= startup_screen_size_X
;
1525 *rows
= startup_screen_size_Y
;
1526 return *screen
!= (char *)0;
1532 #ifndef HAVE_X_WINDOWS
1534 /* We are not X, but we can emulate it well enough for our needs... */
1538 if (! FRAME_MSDOS_P (selected_frame
))
1539 error ("Not running under a windows system");
1545 /* ----------------------- Keyboard control ----------------------
1547 * Keymaps reflect the following keyboard layout:
1549 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1550 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1551 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1552 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1556 #define Ignore 0x0000
1557 #define Normal 0x0000 /* normal key - alt changes scan-code */
1558 #define FctKey 0x1000 /* func key if c == 0, else c */
1559 #define Special 0x2000 /* func key even if c != 0 */
1560 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1561 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1562 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1563 #define Grey 0x6000 /* Grey keypad key */
1565 #define Alt 0x0100 /* alt scan-code */
1566 #define Ctrl 0x0200 /* ctrl scan-code */
1567 #define Shift 0x0400 /* shift scan-code */
1569 static int extended_kbd
; /* 101 (102) keyboard present. */
1571 struct kbd_translate
{
1574 unsigned short code
;
1577 struct dos_keyboard_map
1582 struct kbd_translate
*translate_table
;
1586 static struct dos_keyboard_map us_keyboard
= {
1588 /* 01234567890123456789012345678901234567890 12345678901234 */
1589 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1590 /* 0123456789012345678901234567890123456789 012345678901234 */
1591 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1592 0, /* no Alt-Gr key */
1593 0 /* no translate table */
1596 static struct dos_keyboard_map fr_keyboard
= {
1598 /* 012 3456789012345678901234567890123456789012345678901234 */
1599 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1600 /* 0123456789012345678901234567890123456789012345678901234 */
1601 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1602 /* 01234567 89012345678901234567890123456789012345678901234 */
1604 0 /* no translate table */
1608 * Italian keyboard support, country code 39.
1611 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1612 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1615 static struct kbd_translate it_kbd_translate_table
[] = {
1616 { 0x56, 0x3c, Normal
| 13 },
1617 { 0x56, 0x3e, Normal
| 27 },
1620 static struct dos_keyboard_map it_keyboard
= {
1622 /* 0 123456789012345678901234567890123456789012345678901234 */
1623 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
1624 /* 01 23456789012345678901234567890123456789012345678901234 */
1625 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
1626 /* 0123456789012345678901234567890123456789012345678901234 */
1628 it_kbd_translate_table
1631 static struct dos_keyboard_map dk_keyboard
= {
1633 /* 0123456789012345678901234567890123456789012345678901234 */
1634 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1635 /* 01 23456789012345678901234567890123456789012345678901234 */
1636 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1637 /* 0123456789012345678901234567890123456789012345678901234 */
1639 0 /* no translate table */
1642 static struct kbd_translate jp_kbd_translate_table
[] = {
1643 { 0x73, 0x5c, Normal
| 0 },
1644 { 0x73, 0x5f, Normal
| 0 },
1645 { 0x73, 0x1c, Map
| 0 },
1646 { 0x7d, 0x5c, Normal
| 13 },
1647 { 0x7d, 0x7c, Normal
| 13 },
1648 { 0x7d, 0x1c, Map
| 13 },
1651 static struct dos_keyboard_map jp_keyboard
= {
1653 /* 0123456789012 345678901234567890123456789012345678901234 */
1654 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1655 /* 01 23456789012345678901234567890123456789012345678901234 */
1656 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
1657 0, /* no Alt-Gr key */
1658 jp_kbd_translate_table
1661 static struct keyboard_layout_list
1664 struct dos_keyboard_map
*keyboard_map
;
1665 } keyboard_layout_list
[] =
1674 static struct dos_keyboard_map
*keyboard
;
1675 static int keyboard_map_all
;
1676 static int international_keyboard
;
1679 dos_set_keyboard (code
, always
)
1684 _go32_dpmi_registers regs
;
1686 /* See if Keyb.Com is installed (for international keyboard support).
1687 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1688 of Windows 9X! So don't do that! */
1690 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
1691 _go32_dpmi_simulate_int (0x2f, ®s
);
1692 if (regs
.h
.al
== 0xff)
1693 international_keyboard
= 1;
1695 /* Initialize to US settings, for countries that don't have their own. */
1696 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1697 keyboard_map_all
= always
;
1698 dos_keyboard_layout
= 1;
1700 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1701 if (code
== keyboard_layout_list
[i
].country_code
)
1703 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1704 keyboard_map_all
= always
;
1705 dos_keyboard_layout
= code
;
1713 unsigned char char_code
; /* normal code */
1714 unsigned char meta_code
; /* M- code */
1715 unsigned char keypad_code
; /* keypad code */
1716 unsigned char editkey_code
; /* edit key */
1717 } keypad_translate_map
[] = {
1718 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1719 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1720 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1721 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1722 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1723 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1724 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1725 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1726 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1727 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1728 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1733 unsigned char char_code
; /* normal code */
1734 unsigned char keypad_code
; /* keypad code */
1735 } grey_key_translate_map
[] = {
1736 '/', 0xaf, /* kp-decimal */
1737 '*', 0xaa, /* kp-multiply */
1738 '-', 0xad, /* kp-subtract */
1739 '+', 0xab, /* kp-add */
1740 '\r', 0x8d /* kp-enter */
1743 static unsigned short
1744 ibmpc_translate_map
[] =
1746 /* --------------- 00 to 0f --------------- */
1747 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1748 Alt
| ModFct
| 0x1b, /* Escape */
1749 Normal
| 1, /* '1' */
1750 Normal
| 2, /* '2' */
1751 Normal
| 3, /* '3' */
1752 Normal
| 4, /* '4' */
1753 Normal
| 5, /* '5' */
1754 Normal
| 6, /* '6' */
1755 Normal
| 7, /* '7' */
1756 Normal
| 8, /* '8' */
1757 Normal
| 9, /* '9' */
1758 Normal
| 10, /* '0' */
1759 Normal
| 11, /* '-' */
1760 Normal
| 12, /* '=' */
1761 Special
| 0x08, /* Backspace */
1762 ModFct
| 0x74, /* Tab/Backtab */
1764 /* --------------- 10 to 1f --------------- */
1777 ModFct
| 0x0d, /* Return */
1782 /* --------------- 20 to 2f --------------- */
1791 Map
| 40, /* '\'' */
1793 Ignore
, /* Left shift */
1794 Map
| 41, /* '\\' */
1800 /* --------------- 30 to 3f --------------- */
1807 Ignore
, /* Right shift */
1808 Grey
| 1, /* Grey * */
1810 Normal
| 55, /* ' ' */
1811 Ignore
, /* Caps Lock */
1812 FctKey
| 0xbe, /* F1 */
1813 FctKey
| 0xbf, /* F2 */
1814 FctKey
| 0xc0, /* F3 */
1815 FctKey
| 0xc1, /* F4 */
1816 FctKey
| 0xc2, /* F5 */
1818 /* --------------- 40 to 4f --------------- */
1819 FctKey
| 0xc3, /* F6 */
1820 FctKey
| 0xc4, /* F7 */
1821 FctKey
| 0xc5, /* F8 */
1822 FctKey
| 0xc6, /* F9 */
1823 FctKey
| 0xc7, /* F10 */
1824 Ignore
, /* Num Lock */
1825 Ignore
, /* Scroll Lock */
1826 KeyPad
| 7, /* Home */
1827 KeyPad
| 8, /* Up */
1828 KeyPad
| 9, /* Page Up */
1829 Grey
| 2, /* Grey - */
1830 KeyPad
| 4, /* Left */
1831 KeyPad
| 5, /* Keypad 5 */
1832 KeyPad
| 6, /* Right */
1833 Grey
| 3, /* Grey + */
1834 KeyPad
| 1, /* End */
1836 /* --------------- 50 to 5f --------------- */
1837 KeyPad
| 2, /* Down */
1838 KeyPad
| 3, /* Page Down */
1839 KeyPad
| 0, /* Insert */
1840 KeyPad
| 10, /* Delete */
1841 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1842 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1843 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1844 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1845 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1846 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1847 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1848 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1849 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1850 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1851 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1852 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1854 /* --------------- 60 to 6f --------------- */
1855 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1856 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1857 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1858 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1859 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1860 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1861 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1862 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1863 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1864 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1865 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1866 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1867 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1868 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1869 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1870 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1872 /* --------------- 70 to 7f --------------- */
1873 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1874 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1875 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1876 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1877 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1878 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1879 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1880 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1881 Alt
| Map
| 1, /* '1' */
1882 Alt
| Map
| 2, /* '2' */
1883 Alt
| Map
| 3, /* '3' */
1884 Alt
| Map
| 4, /* '4' */
1885 Alt
| Map
| 5, /* '5' */
1886 Alt
| Map
| 6, /* '6' */
1887 Alt
| Map
| 7, /* '7' */
1888 Alt
| Map
| 8, /* '8' */
1890 /* --------------- 80 to 8f --------------- */
1891 Alt
| Map
| 9, /* '9' */
1892 Alt
| Map
| 10, /* '0' */
1893 Alt
| Map
| 11, /* '-' */
1894 Alt
| Map
| 12, /* '=' */
1895 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1896 FctKey
| 0xc8, /* F11 */
1897 FctKey
| 0xc9, /* F12 */
1898 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1899 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1900 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1901 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1902 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1903 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1904 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1905 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1906 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1908 /* --------------- 90 to 9f --------------- */
1909 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1910 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1911 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1912 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1913 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1914 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1915 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1916 Alt
| FctKey
| 0x50, /* (Alt) Home */
1917 Alt
| FctKey
| 0x52, /* (Alt) Up */
1918 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1919 Ignore
, /* NO KEY */
1920 Alt
| FctKey
| 0x51, /* (Alt) Left */
1921 Ignore
, /* NO KEY */
1922 Alt
| FctKey
| 0x53, /* (Alt) Right */
1923 Ignore
, /* NO KEY */
1924 Alt
| FctKey
| 0x57, /* (Alt) End */
1926 /* --------------- a0 to af --------------- */
1927 Alt
| KeyPad
| 2, /* (Alt) Down */
1928 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1929 Alt
| KeyPad
| 0, /* (Alt) Insert */
1930 Alt
| KeyPad
| 10, /* (Alt) Delete */
1931 Alt
| Grey
| 0, /* (Alt) Grey / */
1932 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1933 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1936 /* These bit-positions corresponds to values returned by BIOS */
1937 #define SHIFT_P 0x0003 /* two bits! */
1938 #define CTRL_P 0x0004
1939 #define ALT_P 0x0008
1940 #define SCRLOCK_P 0x0010
1941 #define NUMLOCK_P 0x0020
1942 #define CAPSLOCK_P 0x0040
1943 #define ALT_GR_P 0x0800
1944 #define SUPER_P 0x4000 /* pseudo */
1945 #define HYPER_P 0x8000 /* pseudo */
1948 dos_get_modifiers (keymask
)
1955 /* Calculate modifier bits */
1956 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1957 int86 (0x16, ®s
, ®s
);
1961 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1962 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1966 mask
= regs
.h
.al
& (SHIFT_P
|
1967 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1969 /* Do not break international keyboard support. */
1970 /* When Keyb.Com is loaded, the right Alt key is */
1971 /* used for accessing characters like { and } */
1972 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1975 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1978 if (dos_hyper_key
== 1)
1981 modifiers
|= hyper_modifier
;
1983 else if (dos_super_key
== 1)
1986 modifiers
|= super_modifier
;
1988 else if (!international_keyboard
)
1990 /* If Keyb.Com is NOT installed, let Right Alt behave
1991 like the Left Alt. */
1997 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2000 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2002 if (dos_hyper_key
== 2)
2005 modifiers
|= hyper_modifier
;
2007 else if (dos_super_key
== 2)
2010 modifiers
|= super_modifier
;
2018 modifiers
|= shift_modifier
;
2020 modifiers
|= ctrl_modifier
;
2022 modifiers
|= meta_modifier
;
2029 #define NUM_RECENT_DOSKEYS (100)
2030 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2031 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2032 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2034 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2035 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2036 Each input key receives two values in this vector: first the ASCII code,\n\
2037 and then the scan code.")
2040 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
2043 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2044 return Fvector (total_doskeys
, keys
);
2047 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2048 bcopy (keys
+ recent_doskeys_index
,
2049 XVECTOR (val
)->contents
,
2050 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
2052 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2053 recent_doskeys_index
* sizeof (Lisp_Object
));
2058 /* Get a char from keyboard. Function keys are put into the event queue. */
2060 extern void kbd_buffer_store_event (struct input_event
*);
2061 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
2066 struct input_event event
;
2069 #ifndef HAVE_X_WINDOWS
2070 /* Maybe put the cursor where it should be. */
2071 IT_cmgoto (selected_frame
);
2074 /* The following condition is equivalent to `kbhit ()', except that
2075 it uses the bios to do its job. This pleases DESQview/X. */
2076 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2077 int86 (0x16, ®s
, ®s
),
2078 (regs
.x
.flags
& 0x40) == 0)
2081 register unsigned char c
;
2082 int sc
, code
= -1, mask
, kp_mode
;
2085 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2086 int86 (0x16, ®s
, ®s
);
2091 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2093 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2094 recent_doskeys_index
= 0;
2095 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2097 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2098 recent_doskeys_index
= 0;
2100 modifiers
= dos_get_modifiers (&mask
);
2102 #ifndef HAVE_X_WINDOWS
2103 if (!NILP (Vdos_display_scancodes
))
2106 sprintf (buf
, "%02x:%02x*%04x",
2107 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2108 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2116 case 10: /* Ctrl Grey Enter */
2117 code
= Ctrl
| Grey
| 4;
2119 case 13: /* Grey Enter */
2122 case '/': /* Grey / */
2132 /* Try the keyboard-private translation table first. */
2133 if (keyboard
->translate_table
)
2135 struct kbd_translate
*p
= keyboard
->translate_table
;
2139 if (p
->sc
== sc
&& p
->ch
== c
)
2147 /* If the private table didn't translate it, use the general
2151 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
2153 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
2160 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2161 Emacs is ready to read a key. Therefore, if they press
2162 `Alt-x' when Emacs is busy, by the time we get to
2163 `dos_get_modifiers', they might have already released the
2164 Alt key, and Emacs gets just `x', which is BAD.
2165 However, for keys with the `Map' property set, the ASCII
2166 code returns zero iff Alt is pressed. So, when we DON'T
2167 have to support international_keyboard, we don't have to
2168 distinguish between the left and right Alt keys, and we
2169 can set the META modifier for any keys with the `Map'
2170 property if they return zero ASCII code (c = 0). */
2172 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
2173 modifiers
|= meta_modifier
;
2175 modifiers
|= ctrl_modifier
;
2177 modifiers
|= shift_modifier
;
2180 switch (code
& 0xf000)
2183 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
2185 c
= 0; /* Special */
2198 if (c
== 0) /* ctrl-break */
2200 return c
; /* ALT-nnn */
2202 if (!keyboard_map_all
)
2211 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
2212 if (!keyboard_map_all
)
2216 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
2217 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
2221 code
= keyboard
->shifted
[code
];
2223 modifiers
&= ~shift_modifier
;
2226 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
2227 code
= keyboard
->alt_gr
[code
];
2229 code
= keyboard
->unshifted
[code
];
2234 if (c
== 0xe0) /* edit key */
2237 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
2238 kp_mode
= dos_keypad_mode
& 0x03;
2240 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
2245 if (code
== 10 && dos_decimal_point
)
2246 return dos_decimal_point
;
2247 return keypad_translate_map
[code
].char_code
;
2250 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
2254 code
= keypad_translate_map
[code
].meta_code
;
2255 modifiers
= meta_modifier
;
2259 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
2266 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
2267 if (dos_keypad_mode
& kp_mode
)
2268 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
2270 code
= grey_key_translate_map
[code
].char_code
;
2279 event
.kind
= non_ascii_keystroke
;
2281 event
.kind
= ascii_keystroke
;
2283 event
.modifiers
= modifiers
;
2284 XSETFRAME (event
.frame_or_window
, selected_frame
);
2285 event
.timestamp
= event_timestamp ();
2286 kbd_buffer_store_event (&event
);
2289 if (have_mouse
> 0 && !mouse_preempted
)
2291 int but
, press
, x
, y
, ok
;
2293 /* Check for mouse movement *before* buttons. */
2294 mouse_check_moved ();
2296 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
2297 for (press
= 0; press
< 2; press
++)
2299 int button_num
= but
;
2302 ok
= mouse_pressed (but
, &x
, &y
);
2304 ok
= mouse_released (but
, &x
, &y
);
2307 /* Allow a simultaneous press/release of Mouse-1 and
2308 Mouse-2 to simulate Mouse-3 on two-button mice. */
2309 if (mouse_button_count
== 2 && but
< 2)
2311 int x2
, y2
; /* don't clobber original coordinates */
2313 /* If only one button is pressed, wait 100 msec and
2314 check again. This way, Speedy Gonzales isn't
2315 punished, while the slow get their chance. */
2316 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2317 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2322 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2323 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2328 event
.kind
= mouse_click
;
2329 event
.code
= button_num
;
2330 event
.modifiers
= dos_get_modifiers (0)
2331 | (press
? down_modifier
: up_modifier
);
2334 XSETFRAME (event
.frame_or_window
, selected_frame
);
2335 event
.timestamp
= event_timestamp ();
2336 kbd_buffer_store_event (&event
);
2344 static int prev_get_char
= -1;
2346 /* Return 1 if a key is ready to be read without suspending execution. */
2350 if (prev_get_char
!= -1)
2353 return ((prev_get_char
= dos_rawgetc ()) != -1);
2356 /* Read a key. Return -1 if no key is ready. */
2360 if (prev_get_char
!= -1)
2362 int c
= prev_get_char
;
2367 return dos_rawgetc ();
2370 #ifndef HAVE_X_WINDOWS
2371 /* See xterm.c for more info. */
2373 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
2375 register int pix_x
, pix_y
;
2376 register int *x
, *y
;
2380 if (bounds
) abort ();
2382 /* Ignore clipping. */
2389 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
2392 register int *pix_x
, *pix_y
;
2398 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2401 Actually, I don't know the meaning of all the parameters of the functions
2402 here -- I only know how they are called by xmenu.c. I could of course
2403 grab the nearest Xlib manual (down the hall, second-to-last door on the
2404 left), but I don't think it's worth the effort. */
2411 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
2412 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
2416 /* Allocate some (more) memory for MENU ensuring that there is room for one
2420 IT_menu_make_room (XMenu
*menu
)
2422 if (menu
->allocated
== 0)
2424 int count
= menu
->allocated
= 10;
2425 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
2426 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
2427 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
2429 else if (menu
->allocated
== menu
->count
)
2431 int count
= menu
->allocated
= menu
->allocated
+ 10;
2433 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2435 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2437 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2441 /* Search the given menu structure for a given pane number. */
2444 IT_menu_search_pane (XMenu
*menu
, int pane
)
2449 for (i
= 0; i
< menu
->count
; i
++)
2450 if (menu
->submenu
[i
])
2452 if (pane
== menu
->panenumber
[i
])
2453 return menu
->submenu
[i
];
2454 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2460 /* Determine how much screen space a given menu needs. */
2463 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2465 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2468 maxheight
= menu
->count
;
2469 for (i
= 0; i
< menu
->count
; i
++)
2471 if (menu
->submenu
[i
])
2473 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2474 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2475 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2478 *width
= menu
->width
+ maxsubwidth
;
2479 *height
= maxheight
;
2482 /* Display MENU at (X,Y) using FACES. */
2485 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
2487 int i
, j
, face
, width
;
2488 struct glyph
*text
, *p
;
2491 int enabled
, mousehere
;
2494 width
= menu
->width
;
2495 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
2496 ScreenGetCursor (&row
, &col
);
2497 mouse_get_xy (&mx
, &my
);
2498 IT_update_begin (selected_frame
);
2499 for (i
= 0; i
< menu
->count
; i
++)
2501 IT_cursor_to (y
+ i
, x
);
2503 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2504 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
2505 face
= faces
[enabled
+ mousehere
* 2];
2507 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
2509 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2513 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
2516 else /* make '^x' */
2518 SET_CHAR_GLYPH (*p
, '^', face
, 0);
2521 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
2526 for (; j
< width
; j
++, p
++)
2527 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
2529 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
2531 IT_write_glyphs (text
, width
+ 2);
2533 IT_update_end (selected_frame
);
2534 IT_cursor_to (row
, col
);
2538 /* --------------------------- X Menu emulation ---------------------- */
2540 /* Report availability of menus. */
2548 /* Create a brand new menu structure. */
2551 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2553 return IT_menu_create ();
2556 /* Create a new pane and place it on the outer-most level. It is not
2557 clear that it should be placed out there, but I don't know what else
2561 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2569 IT_menu_make_room (menu
);
2570 menu
->submenu
[menu
->count
] = IT_menu_create ();
2571 menu
->text
[menu
->count
] = txt
;
2572 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2575 /* Adjust length for possible control characters (which will
2576 be written as ^x). */
2577 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2581 if (len
> menu
->width
)
2584 return menu
->panecount
;
2587 /* Create a new item in a menu pane. */
2590 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2591 int foo
, char *txt
, int enable
)
2597 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2599 IT_menu_make_room (menu
);
2600 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2601 menu
->text
[menu
->count
] = txt
;
2602 menu
->panenumber
[menu
->count
] = enable
;
2605 /* Adjust length for possible control characters (which will
2606 be written as ^x). */
2607 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2611 if (len
> menu
->width
)
2617 /* Decide where the menu would be placed if requested at (X,Y). */
2620 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2621 int *ulx
, int *uly
, int *width
, int *height
)
2623 IT_menu_calc_size (menu
, width
, height
);
2629 struct IT_menu_state
2631 void *screen_behind
;
2638 /* Display menu, wait for user's response, and return that response. */
2641 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2642 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2644 struct IT_menu_state
*state
;
2649 Lisp_Object selectface
;
2650 int leave
, result
, onepane
;
2651 int title_faces
[4]; /* face to display the menu title */
2652 int buffers_num_deleted
= 0;
2654 /* Just in case we got here without a mouse present... */
2655 if (have_mouse
<= 0)
2656 return XM_IA_SELECT
;
2657 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2658 around the display. */
2664 /* We will process all the mouse events directly, so we had
2665 better prevented dos_rawgetc from stealing them from us. */
2668 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2669 screensize
= screen_size
* 2;
2671 = lookup_derived_face (selected_frame
, intern ("msdos-menu-passive-face"),
2672 CHARSET_ASCII
, DEFAULT_FACE_ID
);
2674 = lookup_derived_face (selected_frame
, intern ("msdos-menu-active-face"),
2675 CHARSET_ASCII
, DEFAULT_FACE_ID
);
2676 selectface
= intern ("msdos-menu-select-face");
2677 faces
[2] = lookup_derived_face (selected_frame
, selectface
,
2678 CHARSET_ASCII
, faces
[0]);
2679 faces
[3] = lookup_derived_face (selected_frame
, selectface
,
2680 CHARSET_ASCII
, faces
[1]);
2682 /* Make sure the menu title is always displayed with
2683 `msdos-menu-active-face', no matter where the mouse pointer is. */
2684 for (i
= 0; i
< 4; i
++)
2685 title_faces
[i
] = faces
[3];
2689 /* Don't let the title for the "Buffers" popup menu include a
2690 digit (which is ugly).
2692 This is a terrible kludge, but I think the "Buffers" case is
2693 the only one where the title includes a number, so it doesn't
2694 seem to be necessary to make this more general. */
2695 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2697 menu
->text
[0][7] = '\0';
2698 buffers_num_deleted
= 1;
2700 state
[0].menu
= menu
;
2702 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2704 /* Turn off the cursor. Otherwise it shows through the menu
2705 panes, which is ugly. */
2706 IT_display_cursor (0);
2708 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2709 if (buffers_num_deleted
)
2710 menu
->text
[0][7] = ' ';
2711 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2713 menu
->width
= menu
->submenu
[0]->width
;
2714 state
[0].menu
= menu
->submenu
[0];
2718 state
[0].menu
= menu
;
2720 state
[0].x
= x0
- 1;
2722 state
[0].pane
= onepane
;
2724 mouse_last_x
= -1; /* A hack that forces display. */
2728 if (!mouse_visible
) mouse_on ();
2729 mouse_check_moved ();
2730 if (selected_frame
->mouse_moved
)
2732 selected_frame
->mouse_moved
= 0;
2733 result
= XM_IA_SELECT
;
2734 mouse_get_xy (&x
, &y
);
2735 for (i
= 0; i
< statecount
; i
++)
2736 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2738 int dy
= y
- state
[i
].y
;
2739 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2741 if (!state
[i
].menu
->submenu
[dy
])
2742 if (state
[i
].menu
->panenumber
[dy
])
2743 result
= XM_SUCCESS
;
2745 result
= XM_IA_SELECT
;
2746 *pane
= state
[i
].pane
- 1;
2748 /* We hit some part of a menu, so drop extra menus that
2749 have been opened. That does not include an open and
2751 if (i
!= statecount
- 2
2752 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2753 while (i
!= statecount
- 1)
2757 ScreenUpdate (state
[statecount
].screen_behind
);
2758 if (screen_virtual_segment
)
2759 dosv_refresh_virtual_screen (0, screen_size
);
2760 xfree (state
[statecount
].screen_behind
);
2762 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2764 IT_menu_display (state
[i
].menu
,
2768 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2769 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2771 ScreenRetrieve (state
[statecount
].screen_behind
2772 = xmalloc (screensize
));
2774 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2775 state
[statecount
].y
= y
;
2780 IT_menu_display (state
[statecount
- 1].menu
,
2781 state
[statecount
- 1].y
,
2782 state
[statecount
- 1].x
,
2786 /* We are busy-waiting for the mouse to move, so let's be nice
2787 to other Windows applications by releasing our time slice. */
2789 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
2791 /* Only leave if user both pressed and released the mouse, and in
2792 that order. This avoids popping down the menu pane unless
2793 the user is really done with it. */
2794 if (mouse_pressed (b
, &x
, &y
))
2796 while (mouse_button_depressed (b
, &x
, &y
))
2800 (void) mouse_released (b
, &x
, &y
);
2805 ScreenUpdate (state
[0].screen_behind
);
2806 if (screen_virtual_segment
)
2807 dosv_refresh_virtual_screen (0, screen_size
);
2808 while (statecount
--)
2809 xfree (state
[statecount
].screen_behind
);
2810 IT_display_cursor (1); /* turn cursor back on */
2811 /* Clean up any mouse events that are waiting inside Emacs event queue.
2812 These events are likely to be generated before the menu was even
2813 displayed, probably because the user pressed and released the button
2814 (which invoked the menu) too quickly. If we don't remove these events,
2815 Emacs will process them after we return and surprise the user. */
2816 discard_mouse_events ();
2817 /* Allow mouse events generation by dos_rawgetc. */
2822 /* Dispose of a menu. */
2825 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2828 if (menu
->allocated
)
2830 for (i
= 0; i
< menu
->count
; i
++)
2831 if (menu
->submenu
[i
])
2832 XMenuDestroy (foo
, menu
->submenu
[i
]);
2834 xfree (menu
->submenu
);
2835 xfree (menu
->panenumber
);
2841 x_pixel_width (struct frame
*f
)
2843 return FRAME_WIDTH (f
);
2847 x_pixel_height (struct frame
*f
)
2849 return FRAME_HEIGHT (f
);
2851 #endif /* !HAVE_X_WINDOWS */
2853 /* ----------------------- DOS / UNIX conversion --------------------- */
2855 void msdos_downcase_filename (unsigned char *);
2857 /* Destructively turn backslashes into slashes. */
2860 dostounix_filename (p
)
2863 msdos_downcase_filename (p
);
2873 /* Destructively turn slashes into backslashes. */
2876 unixtodos_filename (p
)
2879 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2893 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2896 getdefdir (drive
, dst
)
2900 char in_path
[4], *p
= in_path
;
2903 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2906 *p
++ = drive
+ 'A' - 1;
2913 _fixpath (in_path
, dst
);
2914 /* _fixpath can set errno to ENOSYS on non-LFN systems because
2915 it queries the LFN support, so ignore that error. */
2916 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
2919 msdos_downcase_filename (dst
);
2925 /* Remove all CR's that are followed by a LF. */
2930 register unsigned char *buf
;
2932 unsigned char *np
= buf
;
2933 unsigned char *startp
= buf
;
2934 unsigned char *endp
= buf
+ n
;
2938 while (buf
< endp
- 1)
2942 if (*(++buf
) != 0x0a)
2953 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2955 /* In DJGPP v2.0, library `write' can call `malloc', which might
2956 cause relocation of the buffer whose address we get in ADDR.
2957 Here is a version of `write' that avoids calling `malloc',
2958 to serve us until such time as the library is fixed.
2959 Actually, what we define here is called `__write', because
2960 `write' is a stub that just jmp's to `__write' (to be
2961 POSIXLY-correct with respect to the global name-space). */
2963 #include <io.h> /* for _write */
2964 #include <libc/dosio.h> /* for __file_handle_modes[] */
2966 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2968 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2971 __write (int handle
, const void *buffer
, size_t count
)
2976 if(__file_handle_modes
[handle
] & O_BINARY
)
2977 return _write (handle
, buffer
, count
);
2981 const char *bp
= buffer
;
2982 int total_written
= 0;
2983 int nmoved
= 0, ncr
= 0;
2987 /* The next test makes sure there's space for at least 2 more
2988 characters in xbuf[], so both CR and LF can be put there. */
3000 if (xbp
>= XBUF_END
|| !count
)
3002 size_t to_write
= nmoved
+ ncr
;
3003 int written
= _write (handle
, xbuf
, to_write
);
3008 total_written
+= nmoved
; /* CRs aren't counted in ret value */
3010 /* If some, but not all were written (disk full?), return
3011 an estimate of the total written bytes not counting CRs. */
3012 if (written
< to_write
)
3013 return total_written
- (to_write
- written
) * nmoved
/to_write
;
3020 return total_written
;
3024 /* A low-level file-renaming function which works around Windows 95 bug.
3025 This is pulled directly out of DJGPP v2.01 library sources, and only
3026 used when you compile with DJGPP v2.0. */
3030 int _rename(const char *old
, const char *new)
3033 int olen
= strlen(old
) + 1;
3035 int use_lfn
= _USE_LFN
;
3036 char tempfile
[FILENAME_MAX
];
3037 const char *orig
= old
;
3040 r
.x
.dx
= __tb_offset
;
3041 r
.x
.di
= __tb_offset
+ olen
;
3042 r
.x
.ds
= r
.x
.es
= __tb_segment
;
3046 /* Windows 95 bug: for some filenames, when you rename
3047 file -> file~ (as in Emacs, to leave a backup), the
3048 short 8+3 alias doesn't change, which effectively
3049 makes OLD and NEW the same file. We must rename
3050 through a temporary file to work around this. */
3052 char *pbase
= 0, *p
;
3053 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
3054 int idx
= sizeof(try_char
) - 1;
3056 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
3057 might point to another drive, which will fail the DOS call. */
3058 strcpy(tempfile
, old
);
3059 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
3060 if (*p
== '/' || *p
== '\\' || *p
== ':')
3066 strcpy(pbase
, "X$$djren$$.$$temp$$");
3072 *pbase
= try_char
[--idx
];
3073 } while (_chmod(tempfile
, 0) != -1);
3076 _put_path2(tempfile
, olen
);
3078 __dpmi_int(0x21, &r
);
3081 errno
= __doserr_to_errno(r
.x
.ax
);
3085 /* Now create a file with the original name. This will
3086 ensure that NEW will always have a 8+3 alias
3087 different from that of OLD. (Seems to be required
3088 when NameNumericTail in the Registry is set to 0.) */
3089 lfn_fd
= _creat(old
, 0);
3091 olen
= strlen(tempfile
) + 1;
3093 r
.x
.di
= __tb_offset
+ olen
;
3102 _put_path2(new, olen
);
3104 __dpmi_int(0x21, &r
);
3107 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
3108 remove(new); /* and try again */
3111 errno
= __doserr_to_errno(r
.x
.ax
);
3113 /* Restore to original name if we renamed it to temporary. */
3121 _put_path2(orig
, olen
);
3122 _put_path(tempfile
);
3124 __dpmi_int(0x21, &r
);
3133 /* Success. Delete the file possibly created to work
3134 around the Windows 95 bug. */
3136 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
3140 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
3142 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3144 "Return non-nil if long file names are supported on MSDOS.")
3147 return (_USE_LFN
? Qt
: Qnil
);
3150 /* Convert alphabetic characters in a filename to lower-case. */
3153 msdos_downcase_filename (p
)
3154 register unsigned char *p
;
3156 /* Always lower-case drive letters a-z, even if the filesystem
3157 preserves case in filenames.
3158 This is so MSDOS filenames could be compared by string comparison
3159 functions that are case-sensitive. Even case-preserving filesystems
3160 do not distinguish case in drive letters. */
3161 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3167 /* Under LFN we expect to get pathnames in their true case. */
3168 if (NILP (Fmsdos_long_file_names ()))
3170 if (*p
>= 'A' && *p
<= 'Z')
3174 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3176 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
3177 When long filenames are supported, doesn't change FILENAME.\n\
3178 If FILENAME is not a string, returns nil.\n\
3179 The argument object is never altered--the value is a copy.")
3181 Lisp_Object filename
;
3185 if (! STRINGP (filename
))
3188 tem
= Fcopy_sequence (filename
);
3189 msdos_downcase_filename (XSTRING (tem
)->data
);
3193 /* The Emacs root directory as determined by init_environment. */
3195 static char emacsroot
[MAXPATHLEN
];
3198 rootrelativepath (rel
)
3201 static char result
[MAXPATHLEN
+ 10];
3203 strcpy (result
, emacsroot
);
3204 strcat (result
, "/");
3205 strcat (result
, rel
);
3209 /* Define a lot of environment variables if not already defined. Don't
3210 remove anything unless you know what you're doing -- lots of code will
3211 break if one or more of these are missing. */
3214 init_environment (argc
, argv
, skip_args
)
3221 static const char * const tempdirs
[] = {
3222 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3225 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
3227 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3228 temporary files and assume "/tmp" if $TMPDIR is unset, which
3229 will break on DOS/Windows. Refuse to work if we cannot find
3230 a directory, not even "c:/", usable for that purpose. */
3231 for (i
= 0; i
< imax
; i
++)
3233 const char *tmp
= tempdirs
[i
];
3236 tmp
= getenv (tmp
+ 1);
3237 /* Note that `access' can lie to us if the directory resides on a
3238 read-only filesystem, like CD-ROM or a write-protected floppy.
3239 The only way to be really sure is to actually create a file and
3240 see if it succeeds. But I think that's too much to ask. */
3241 if (tmp
&& access (tmp
, D_OK
) == 0)
3243 setenv ("TMPDIR", tmp
, 1);
3250 Fcons (build_string ("no usable temporary directories found!!"),
3252 "While setting TMPDIR: ");
3254 /* Note the startup time, so we know not to clear the screen if we
3255 exit immediately; see IT_reset_terminal_modes.
3256 (Yes, I know `clock' returns zero the first time it's called, but
3257 I do this anyway, in case some wiseguy changes that at some point.) */
3258 startup_time
= clock ();
3260 /* Find our root from argv[0]. Assuming argv[0] is, say,
3261 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3262 root
= alloca (MAXPATHLEN
+ 20);
3263 _fixpath (argv
[0], root
);
3264 msdos_downcase_filename (root
);
3265 len
= strlen (root
);
3266 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
3270 && (strcmp (root
+ len
- 4, "/bin") == 0
3271 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
3272 root
[len
- 4] = '\0';
3274 strcpy (root
, "c:/emacs"); /* let's be defensive */
3275 len
= strlen (root
);
3276 strcpy (emacsroot
, root
);
3278 /* We default HOME to our root. */
3279 setenv ("HOME", root
, 0);
3281 /* We default EMACSPATH to root + "/bin". */
3282 strcpy (root
+ len
, "/bin");
3283 setenv ("EMACSPATH", root
, 0);
3285 /* I don't expect anybody to ever use other terminals so the internal
3286 terminal is the default. */
3287 setenv ("TERM", "internal", 0);
3289 #ifdef HAVE_X_WINDOWS
3290 /* Emacs expects DISPLAY to be set. */
3291 setenv ("DISPLAY", "unix:0.0", 0);
3294 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3295 downcase it and mirror the backslashes. */
3296 s
= getenv ("COMSPEC");
3297 if (!s
) s
= "c:/command.com";
3298 t
= alloca (strlen (s
) + 1);
3300 dostounix_filename (t
);
3301 setenv ("SHELL", t
, 0);
3303 /* PATH is also downcased and backslashes mirrored. */
3304 s
= getenv ("PATH");
3306 t
= alloca (strlen (s
) + 3);
3307 /* Current directory is always considered part of MsDos's path but it is
3308 not normally mentioned. Now it is. */
3309 strcat (strcpy (t
, ".;"), s
);
3310 dostounix_filename (t
); /* Not a single file name, but this should work. */
3311 setenv ("PATH", t
, 1);
3313 /* In some sense all dos users have root privileges, so... */
3314 setenv ("USER", "root", 0);
3315 setenv ("NAME", getenv ("USER"), 0);
3317 /* Time zone determined from country code. To make this possible, the
3318 country code may not span more than one time zone. In other words,
3319 in the USA, you lose. */
3321 switch (dos_country_code
)
3323 case 31: /* Belgium */
3324 case 32: /* The Netherlands */
3325 case 33: /* France */
3326 case 34: /* Spain */
3327 case 36: /* Hungary */
3328 case 38: /* Yugoslavia (or what's left of it?) */
3329 case 39: /* Italy */
3330 case 41: /* Switzerland */
3331 case 42: /* Tjekia */
3332 case 45: /* Denmark */
3333 case 46: /* Sweden */
3334 case 47: /* Norway */
3335 case 48: /* Poland */
3336 case 49: /* Germany */
3337 /* Daylight saving from last Sunday in March to last Sunday in
3338 September, both at 2AM. */
3339 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3341 case 44: /* United Kingdom */
3342 case 351: /* Portugal */
3343 case 354: /* Iceland */
3344 setenv ("TZ", "GMT+00", 0);
3346 case 81: /* Japan */
3347 case 82: /* Korea */
3348 setenv ("TZ", "JST-09", 0);
3350 case 90: /* Turkey */
3351 case 358: /* Finland */
3352 setenv ("TZ", "EET-02", 0);
3354 case 972: /* Israel */
3355 /* This is an approximation. (For exact rules, use the
3356 `zoneinfo/israel' file which comes with DJGPP, but you need
3357 to install it in `/usr/share/zoneinfo/' directory first.) */
3358 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3366 static int break_stat
; /* BREAK check mode status. */
3367 static int stdin_stat
; /* stdin IOCTL status. */
3371 /* These must be global. */
3372 static _go32_dpmi_seginfo ctrl_break_vector
;
3373 static _go32_dpmi_registers ctrl_break_regs
;
3374 static int ctrlbreakinstalled
= 0;
3376 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3379 ctrl_break_func (regs
)
3380 _go32_dpmi_registers
*regs
;
3386 install_ctrl_break_check ()
3388 if (!ctrlbreakinstalled
)
3390 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3391 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3392 ctrlbreakinstalled
= 1;
3393 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
3394 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
3396 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
3400 #endif /* __DJGPP__ < 2 */
3402 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3403 control chars by DOS. Determine the keyboard type. */
3408 union REGS inregs
, outregs
;
3409 static int first_time
= 1;
3411 break_stat
= getcbrk ();
3414 install_ctrl_break_check ();
3420 int86 (0x15, &inregs
, &outregs
);
3421 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
3425 if (internal_terminal
3426 #ifdef HAVE_X_WINDOWS
3427 && inhibit_window_system
3431 inregs
.x
.ax
= 0x0021;
3432 int86 (0x33, &inregs
, &outregs
);
3433 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3436 /* Reportedly, the above doesn't work for some mouse drivers. There
3437 is an additional detection method that should work, but might be
3438 a little slower. Use that as an alternative. */
3439 inregs
.x
.ax
= 0x0000;
3440 int86 (0x33, &inregs
, &outregs
);
3441 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3446 have_mouse
= 1; /* enable mouse */
3449 if (outregs
.x
.bx
== 3)
3451 mouse_button_count
= 3;
3452 mouse_button_translate
[0] = 0; /* Left */
3453 mouse_button_translate
[1] = 2; /* Middle */
3454 mouse_button_translate
[2] = 1; /* Right */
3458 mouse_button_count
= 2;
3459 mouse_button_translate
[0] = 0;
3460 mouse_button_translate
[1] = 1;
3462 mouse_position_hook
= &mouse_get_pos
;
3471 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
3472 return (stdin_stat
!= -1);
3475 return (setmode (fileno (stdin
), O_BINARY
) != -1);
3477 #else /* __DJGPP__ < 2 */
3481 /* I think it is wrong to overwrite `stdin_stat' every time
3482 but the first one this function is called, but I don't
3483 want to change the way it used to work in v1.x.--EZ */
3485 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
3486 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3487 intdos (&inregs
, &outregs
);
3488 stdin_stat
= outregs
.h
.dl
;
3490 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
3491 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
3492 intdos (&inregs
, &outregs
);
3493 return !outregs
.x
.cflag
;
3495 #endif /* __DJGPP__ < 2 */
3498 /* Restore status of standard input and Ctrl-C checking. */
3503 union REGS inregs
, outregs
;
3505 setcbrk (break_stat
);
3510 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3512 #else /* not __DJGPP__ >= 2 */
3514 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
3515 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3516 inregs
.x
.dx
= stdin_stat
;
3517 intdos (&inregs
, &outregs
);
3518 return !outregs
.x
.cflag
;
3520 #endif /* not __DJGPP__ >= 2 */
3524 /* Run command as specified by ARGV in directory DIR.
3525 The command is run with input from TEMPIN, output to
3526 file TEMPOUT and stderr to TEMPERR. */
3529 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
3530 unsigned char **argv
;
3531 const char *working_dir
;
3532 int tempin
, tempout
, temperr
;
3535 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3536 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3537 int msshell
, result
= -1;
3538 int inbak
, outbak
, errbak
;
3542 /* Get current directory as MSDOS cwd is not per-process. */
3545 /* If argv[0] is the shell, it might come in any lettercase.
3546 Since `Fmember' is case-sensitive, we need to downcase
3547 argv[0], even if we are on case-preserving filesystems. */
3548 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3549 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3552 if (*pl
>= 'A' && *pl
<= 'Z')
3557 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3558 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3559 && !strcmp ("-c", argv
[1]);
3562 saveargv1
= argv
[1];
3563 saveargv2
= argv
[2];
3567 char *p
= alloca (strlen (argv
[2]) + 1);
3569 strcpy (argv
[2] = p
, saveargv2
);
3570 while (*p
&& isspace (*p
))
3572 while (*p
&& !isspace (*p
))
3580 chdir (working_dir
);
3584 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3585 goto done
; /* Allocation might fail due to lack of descriptors. */
3588 mouse_get_xy (&x
, &y
);
3590 dos_ttcooked (); /* do it here while 0 = stdin */
3598 if (msshell
&& !argv
[3])
3600 /* MS-DOS native shells are too restrictive. For starters, they
3601 cannot grok commands longer than 126 characters. In DJGPP v2
3602 and later, `system' is much smarter, so we'll call it instead. */
3606 /* A shell gets a single argument--its full command
3607 line--whose original was saved in `saveargv2'. */
3609 /* Don't let them pass empty command lines to `system', since
3610 with some shells it will try to invoke an interactive shell,
3611 which will hang Emacs. */
3612 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3616 extern char **environ
;
3617 int save_system_flags
= __system_flags
;
3619 /* Request the most powerful version of `system'. We need
3620 all the help we can get to avoid calling stock DOS shells. */
3621 __system_flags
= (__system_redirect
3622 | __system_use_shell
3623 | __system_allow_multiple_cmds
3624 | __system_allow_long_cmds
3625 | __system_handle_null_commands
3626 | __system_emulate_chdir
);
3629 result
= system (cmnd
);
3630 __system_flags
= save_system_flags
;
3633 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3637 #endif /* __DJGPP__ > 1 */
3639 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3652 mouse_moveto (x
, y
);
3655 /* Some programs might change the meaning of the highest bit of the
3656 text attribute byte, so we get blinking characters instead of the
3657 bright background colors. Restore that. */
3664 argv
[1] = saveargv1
;
3665 argv
[2] = saveargv2
;
3673 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3680 /* ------------------------- Compatibility functions -------------------
3685 /* Hostnames for a pc are not really funny,
3686 but they are used in change log so we emulate the best we can. */
3688 gethostname (p
, size
)
3692 char *q
= egetenv ("HOSTNAME");
3699 /* When time zones are set from Ms-Dos too many C-libraries are playing
3700 tricks with time values. We solve this by defining our own version
3701 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3702 once and after each call to `tzset' with TZ changed. That is
3703 accomplished by aliasing tzset to init_gettimeofday. */
3705 static struct tm time_rec
;
3708 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3716 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3720 time_rec
.tm_year
= d
.da_year
- 1900;
3721 time_rec
.tm_mon
= d
.da_mon
- 1;
3722 time_rec
.tm_mday
= d
.da_day
;
3725 time_rec
.tm_hour
= t
.ti_hour
;
3726 time_rec
.tm_min
= t
.ti_min
;
3727 time_rec
.tm_sec
= t
.ti_sec
;
3730 tm
.tm_gmtoff
= dos_timezone_offset
;
3732 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3733 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3735 /* Ignore tzp; it's obsolescent. */
3739 #endif /* __DJGPP__ < 2 */
3742 * A list of unimplemented functions that we silently ignore.
3746 unsigned alarm (s
) unsigned s
; {}
3747 fork () { return 0; }
3748 int kill (x
, y
) int x
, y
; { return -1; }
3750 void volatile pause () {}
3751 sigsetmask (x
) int x
; { return 0; }
3752 sigblock (mask
) int mask
; { return 0; }
3755 void request_sigio (void) {}
3756 setpgrp () {return 0; }
3757 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3758 void unrequest_sigio (void) {}
3762 #ifdef POSIX_SIGNALS
3764 /* Augment DJGPP library POSIX signal functions. This is needed
3765 as of DJGPP v2.01, but might be in the library in later releases. */
3767 #include <libc/bss.h>
3769 /* A counter to know when to re-initialize the static sets. */
3770 static int sigprocmask_count
= -1;
3772 /* Which signals are currently blocked (initially none). */
3773 static sigset_t current_mask
;
3775 /* Which signals are pending (initially none). */
3776 static sigset_t pending_signals
;
3778 /* Previous handlers to restore when the blocked signals are unblocked. */
3779 typedef void (*sighandler_t
)(int);
3780 static sighandler_t prev_handlers
[320];
3782 /* A signal handler which just records that a signal occured
3783 (it will be raised later, if and when the signal is unblocked). */
3785 sig_suspender (signo
)
3788 sigaddset (&pending_signals
, signo
);
3792 sigprocmask (how
, new_set
, old_set
)
3794 const sigset_t
*new_set
;
3800 /* If called for the first time, initialize. */
3801 if (sigprocmask_count
!= __bss_count
)
3803 sigprocmask_count
= __bss_count
;
3804 sigemptyset (&pending_signals
);
3805 sigemptyset (¤t_mask
);
3806 for (signo
= 0; signo
< 320; signo
++)
3807 prev_handlers
[signo
] = SIG_ERR
;
3811 *old_set
= current_mask
;
3816 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3822 sigemptyset (&new_mask
);
3824 /* DJGPP supports upto 320 signals. */
3825 for (signo
= 0; signo
< 320; signo
++)
3827 if (sigismember (¤t_mask
, signo
))
3828 sigaddset (&new_mask
, signo
);
3829 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3831 sigaddset (&new_mask
, signo
);
3833 /* SIGKILL is silently ignored, as on other platforms. */
3834 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3835 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3837 if (( how
== SIG_UNBLOCK
3838 && sigismember (&new_mask
, signo
)
3839 && sigismember (new_set
, signo
))
3840 || (how
== SIG_SETMASK
3841 && sigismember (&new_mask
, signo
)
3842 && !sigismember (new_set
, signo
)))
3844 sigdelset (&new_mask
, signo
);
3845 if (prev_handlers
[signo
] != SIG_ERR
)
3847 signal (signo
, prev_handlers
[signo
]);
3848 prev_handlers
[signo
] = SIG_ERR
;
3850 if (sigismember (&pending_signals
, signo
))
3852 sigdelset (&pending_signals
, signo
);
3857 current_mask
= new_mask
;
3861 #else /* not POSIX_SIGNALS */
3863 sigsetmask (x
) int x
; { return 0; }
3864 sigblock (mask
) int mask
; { return 0; }
3866 #endif /* not POSIX_SIGNALS */
3867 #endif /* __DJGPP__ > 1 */
3870 #include "sysselect.h"
3872 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3873 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3874 ((long)(time).tv_sec < 0 \
3875 || ((time).tv_sec == 0 \
3876 && (long)(time).tv_usec <= 0))
3879 /* This yields the rest of the current time slice to the task manager.
3880 It should be called by any code which knows that it has nothing
3881 useful to do except idle.
3883 I don't use __dpmi_yield here, since versions of library before 2.02
3884 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3885 on some versions of Windows 9X. */
3888 dos_yield_time_slice (void)
3890 _go32_dpmi_registers r
;
3893 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
3894 _go32_dpmi_simulate_int (0x2f, &r
);
3899 /* Only event queue is checked. */
3900 /* We don't have to call timer_check here
3901 because wait_reading_process_input takes care of that. */
3903 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3905 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3906 EMACS_TIME
*timeout
;
3914 check_input
= FD_ISSET (0, rfds
);
3925 /* If we are looking only for the terminal, with no timeout,
3926 just read it and wait -- that's more efficient. */
3929 while (!detect_input_pending ())
3931 dos_yield_time_slice ();
3936 EMACS_TIME clnow
, cllast
, cldiff
;
3939 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3941 while (!check_input
|| !detect_input_pending ())
3944 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3945 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3947 /* When seconds wrap around, we assume that no more than
3948 1 minute passed since last `gettime'. */
3949 if (EMACS_TIME_NEG_P (cldiff
))
3950 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3951 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3953 /* Stop when timeout value crosses zero. */
3954 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3957 dos_yield_time_slice ();
3967 * Define overlaid functions:
3969 * chdir -> sys_chdir
3970 * tzset -> init_gettimeofday
3971 * abort -> dos_abort
3976 extern int chdir ();
3982 int len
= strlen (path
);
3983 char *tmp
= (char *)path
;
3985 if (*tmp
&& tmp
[1] == ':')
3987 if (getdisk () != tolower (tmp
[0]) - 'a')
3988 setdisk (tolower (tmp
[0]) - 'a');
3989 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3993 if (len
> 1 && (tmp
[len
- 1] == '/'))
3995 char *tmp1
= (char *) alloca (len
+ 1);
4006 extern void tzset (void);
4009 init_gettimeofday ()
4015 ltm
= gtm
= time (NULL
);
4016 ltm
= mktime (lstm
= localtime (<m
));
4017 gtm
= mktime (gmtime (>m
));
4018 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4019 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4020 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4027 dos_abort (file
, line
)
4031 char buffer1
[200], buffer2
[400];
4034 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
4035 for (i
= j
= 0; buffer1
[i
]; i
++) {
4036 buffer2
[j
++] = buffer1
[i
];
4037 buffer2
[j
++] = 0x70;
4039 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
4040 ScreenSetCursor (2, 0);
4048 ScreenSetCursor (10, 0);
4049 cputs ("\r\n\nEmacs aborted!\r\n");
4051 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4052 if (screen_virtual_segment
)
4053 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
4054 /* Generate traceback, so we could tell whodunit. */
4055 signal (SIGINT
, SIG_DFL
);
4056 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4057 #else /* __DJGPP_MINOR__ >= 2 */
4059 #endif /* __DJGPP_MINOR__ >= 2 */
4065 /* The following two are required so that customization feature
4066 won't complain about unbound variables. */
4067 #ifndef HAVE_X_WINDOWS
4068 /* Search path for bitmap files (xfns.c). */
4069 Lisp_Object Vx_bitmap_file_path
;
4071 #ifndef subprocesses
4072 /* Nonzero means delete a process right away if it exits (process.c). */
4073 static int delete_exited_processes
;
4078 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
4079 staticpro (&recent_doskeys
);
4080 #ifndef HAVE_X_WINDOWS
4081 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
4082 "List of directories to search for bitmap files for X.");
4083 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
4085 /* The following three are from xfns.c: */
4086 Qbackground_color
= intern ("background-color");
4087 staticpro (&Qbackground_color
);
4088 Qforeground_color
= intern ("foreground-color");
4089 staticpro (&Qforeground_color
);
4091 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
4092 "*Glyph to display instead of chars not supported by current codepage.\n\
4094 This variable is used only by MSDOS terminals.");
4095 Vdos_unsupported_char_glyph
= '\177';
4097 #ifndef subprocesses
4098 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
4099 "*Non-nil means delete processes immediately when they exit.\n\
4100 nil means don't delete them until `list-processes' is run.");
4101 delete_exited_processes
= 0;
4104 defsubr (&Srecent_doskeys
);
4105 defsubr (&Smsdos_long_file_names
);
4106 defsubr (&Smsdos_downcase_filename
);