1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999, 2000, 01, 2003
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Contributed by Morten Welinder */
23 /* New display, keyboard, and mouse control by Kim F. Storm */
25 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
34 #include <sys/param.h>
38 #include <string.h> /* for bzero and string functions */
39 #include <sys/stat.h> /* for _fixpath */
40 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #include <dir.h> /* for getdisk */
43 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
45 #include <io.h> /* for setmode */
46 #include <dpmi.h> /* for __dpmi_xxx stuff */
47 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
48 #include <libc/dosio.h> /* for _USE_LFN */
49 #include <conio.h> /* for cputs */
54 #include "termhooks.h"
56 #include "dispextern.h"
66 #include "blockinput.h"
68 #include "intervals.h"
72 /* #include <process.h> */
73 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
81 #define _dos_ds _go32_info_block.selector_for_linear_memory
87 #include "syssignal.h"
93 /* If other `malloc' than ours is used, force our `sbrk' behave like
94 Unix programs expect (resize memory blocks to keep them contiguous).
95 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
96 because that's what `gmalloc' expects to get. */
100 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
101 #else /* not REL_ALLOC */
102 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
103 #endif /* not REL_ALLOC */
104 #endif /* GNU_MALLOC */
106 #endif /* not SYSTEM_MALLOC */
107 #endif /* __DJGPP__ > 1 */
126 /* ------------------------ Mouse control ---------------------------
128 * Coordinates are in screen positions and zero based.
129 * Mouse buttons are numbered from left to right and also zero based.
132 /* This used to be in termhooks.h, but mainstream Emacs code no longer
133 uses it, and it was removed... */
134 #define NUM_MOUSE_BUTTONS (5)
136 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
137 static int mouse_visible
;
139 static int mouse_last_x
;
140 static int mouse_last_y
;
142 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
143 static int mouse_button_count
;
150 if (have_mouse
> 0 && !mouse_visible
)
153 fprintf (termscript
, "<M_ON>");
155 int86 (0x33, ®s
, ®s
);
165 if (have_mouse
> 0 && mouse_visible
)
168 fprintf (termscript
, "<M_OFF>");
170 int86 (0x33, ®s
, ®s
);
176 mouse_setup_buttons (int n_buttons
)
180 mouse_button_count
= 3;
181 mouse_button_translate
[0] = 0; /* Left */
182 mouse_button_translate
[1] = 2; /* Middle */
183 mouse_button_translate
[2] = 1; /* Right */
185 else /* two, what else? */
187 mouse_button_count
= 2;
188 mouse_button_translate
[0] = 0;
189 mouse_button_translate
[1] = 1;
193 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
194 1, 1, "NSet number of mouse buttons to: ",
195 doc
: /* Set the number of mouse buttons to use by Emacs.
196 This is useful with mice that report the number of buttons inconsistently,
197 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
198 them. This happens with wheeled mice on Windows 9X, for example. */)
200 Lisp_Object nbuttons
;
204 CHECK_NUMBER (nbuttons
);
207 Fsignal (Qargs_out_of_range
,
208 Fcons (build_string ("only 2 or 3 mouse buttons are supported"),
209 Fcons (nbuttons
, Qnil
)));
210 mouse_setup_buttons (n
);
215 mouse_get_xy (int *x
, int *y
)
220 int86 (0x33, ®s
, ®s
);
232 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
234 mouse_last_x
= regs
.x
.cx
= x
* 8;
235 mouse_last_y
= regs
.x
.dx
= y
* 8;
236 int86 (0x33, ®s
, ®s
);
240 mouse_pressed (b
, xp
, yp
)
245 if (b
>= mouse_button_count
)
248 regs
.x
.bx
= mouse_button_translate
[b
];
249 int86 (0x33, ®s
, ®s
);
251 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
252 return (regs
.x
.bx
!= 0);
256 mouse_released (b
, xp
, yp
)
261 if (b
>= mouse_button_count
)
264 regs
.x
.bx
= mouse_button_translate
[b
];
265 int86 (0x33, ®s
, ®s
);
267 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
268 return (regs
.x
.bx
!= 0);
272 mouse_button_depressed (b
, xp
, yp
)
277 if (b
>= mouse_button_count
)
280 int86 (0x33, ®s
, ®s
);
281 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
291 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
294 Lisp_Object
*bar_window
, *x
, *y
;
295 enum scroll_bar_part
*part
;
299 Lisp_Object frame
, tail
;
301 /* Clear the mouse-moved flag for every frame on this display. */
302 FOR_EACH_FRAME (tail
, frame
)
303 XFRAME (frame
)->mouse_moved
= 0;
305 *f
= SELECTED_FRAME();
307 mouse_get_xy (&ix
, &iy
);
308 *time
= event_timestamp ();
309 *x
= make_number (mouse_last_x
= ix
);
310 *y
= make_number (mouse_last_y
= iy
);
318 mouse_get_xy (&x
, &y
);
319 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
324 /* Force the mouse driver to ``forget'' about any button clicks until
327 mouse_clear_clicks (void)
331 for (b
= 0; b
< mouse_button_count
; b
++)
333 int dummy_x
, dummy_y
;
335 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
336 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
346 fprintf (termscript
, "<M_INIT>");
349 int86 (0x33, ®s
, ®s
);
351 /* Reset the mouse last press/release info. It seems that Windows
352 doesn't do that automatically when function 21h is called, which
353 causes Emacs to ``remember'' the click that switched focus to the
354 window just before Emacs was started from that window. */
355 mouse_clear_clicks ();
359 regs
.x
.dx
= 8 * (ScreenCols () - 1);
360 int86 (0x33, ®s
, ®s
);
364 regs
.x
.dx
= 8 * (ScreenRows () - 1);
365 int86 (0x33, ®s
, ®s
);
371 /* ------------------------- Screen control ----------------------
375 static int internal_terminal
= 0;
377 #ifndef HAVE_X_WINDOWS
378 extern unsigned char ScreenAttrib
;
379 static int screen_face
;
381 static int screen_size_X
;
382 static int screen_size_Y
;
383 static int screen_size
;
385 static int current_pos_X
;
386 static int current_pos_Y
;
387 static int new_pos_X
;
388 static int new_pos_Y
;
390 static void *startup_screen_buffer
;
391 static int startup_screen_size_X
;
392 static int startup_screen_size_Y
;
393 static int startup_pos_X
;
394 static int startup_pos_Y
;
395 static unsigned char startup_screen_attrib
;
397 static clock_t startup_time
;
399 static int term_setup_done
;
401 static unsigned short outside_cursor
;
403 /* Similar to the_only_frame. */
404 struct x_output the_only_x_display
;
406 /* Support for DOS/V (allows Japanese characters to be displayed on
407 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
409 /* Holds the address of the text-mode screen buffer. */
410 static unsigned long screen_old_address
= 0;
411 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
412 static unsigned short screen_virtual_segment
= 0;
413 static unsigned short screen_virtual_offset
= 0;
414 /* A flag to control how to display unibyte 8-bit characters. */
415 extern int unibyte_display_via_language_environment
;
417 extern Lisp_Object Qcursor_type
;
418 extern Lisp_Object Qbar
, Qhbar
;
420 /* The screen colors of the current frame, which serve as the default
421 colors for newly-created frames. */
422 static int initial_screen_colors
[2];
425 /* Update the screen from a part of relocated DOS/V screen buffer which
426 begins at OFFSET and includes COUNT characters. */
428 dosv_refresh_virtual_screen (int offset
, int count
)
432 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
435 regs
.h
.ah
= 0xff; /* update relocated screen */
436 regs
.x
.es
= screen_virtual_segment
;
437 regs
.x
.di
= screen_virtual_offset
+ offset
;
439 __dpmi_int (0x10, ®s
);
444 dos_direct_output (y
, x
, buf
, len
)
449 int t0
= 2 * (x
+ y
* screen_size_X
);
450 int t
= t0
+ (int) ScreenPrimary
;
455 dosmemput (buf
++, 1, t
);
459 /* This is faster. */
460 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
461 _farnspokeb (t
, *buf
);
463 if (screen_virtual_segment
)
464 dosv_refresh_virtual_screen (t0
, l0
);
469 /* Flash the screen as a substitute for BEEPs. */
473 do_visible_bell (xorattr
)
474 unsigned char xorattr
;
479 movl _ScreenPrimary,%%eax \n\
486 xorb %%al,%%gs:(%%ebx) \n\
489 jne visible_bell_1 \n\
491 jne visible_bell_3 \n\
493 movzwl %%ax,%%eax \n\
494 movzwl %%ax,%%eax \n\
495 movzwl %%ax,%%eax \n\
496 movzwl %%ax,%%eax \n\
498 jne visible_bell_2 \n\
499 jmp visible_bell_0 \n\
502 : "m" (xorattr
), "g" (screen_size
)
503 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
507 ScreenVisualBell (void)
509 /* This creates an xor-mask that will swap the default fore- and
510 background colors. */
511 do_visible_bell (((the_only_x_display
.foreground_pixel
512 ^ the_only_x_display
.background_pixel
)
517 #ifndef HAVE_X_WINDOWS
519 static int blink_bit
= -1; /* the state of the blink bit at startup */
521 /* Enable bright background colors. */
527 /* Remember the original state of the blink/bright-background bit.
528 It is stored at 0040:0065h in the BIOS data area. */
530 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
534 int86 (0x10, ®s
, ®s
);
537 /* Disable bright background colors (and enable blinking) if we found
538 the video system in that state at startup. */
540 maybe_enable_blinking (void)
548 int86 (0x10, ®s
, ®s
);
552 /* Return non-zero if the system has a VGA adapter. */
559 int86 (0x10, ®s
, ®s
);
560 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
565 /* Set the screen dimensions so that it can show no less than
566 ROWS x COLS frame. */
569 dos_set_window_size (rows
, cols
)
574 Lisp_Object video_mode
;
575 int video_mode_value
, have_vga
= 0;
576 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
578 if (*rows
== current_rows
&& *cols
== current_cols
)
582 have_vga
= vga_installed ();
584 /* If the user specified a special video mode for these dimensions,
586 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
587 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
590 if (INTEGERP (video_mode
)
591 && (video_mode_value
= XINT (video_mode
)) > 0)
593 regs
.x
.ax
= video_mode_value
;
594 int86 (0x10, ®s
, ®s
);
598 /* Must hardware-reset the mouse, or else it won't update
599 its notion of screen dimensions for some non-standard
600 video modes. This is *painfully* slow... */
602 int86 (0x33, ®s
, ®s
);
606 /* Find one of the dimensions supported by standard EGA/VGA
607 which gives us at least the required dimensions. */
615 } std_dimension
[] = {
625 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
627 if (std_dimension
[i
].need_vga
<= have_vga
628 && std_dimension
[i
].rows
>= *rows
)
630 if (std_dimension
[i
].rows
!= current_rows
631 || *cols
!= current_cols
)
632 _set_screen_lines (std_dimension
[i
].rows
);
639 #else /* not __DJGPP__ > 1 */
641 else if (*rows
<= 25)
643 if (current_rows
!= 25 || current_cols
!= 80)
646 int86 (0x10, ®s
, ®s
);
649 int86 (0x10, ®s
, ®s
);
652 int86 (0x10, ®s
, ®s
);
654 int86 (0x10, ®s
, ®s
);
657 else if (*rows
<= 50)
658 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
659 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
662 int86 (0x10, ®s
, ®s
);
665 int86 (0x10, ®s
, ®s
);
668 int86 (0x10, ®s
, ®s
);
671 int86 (0x10, ®s
, ®s
);
673 #endif /* not __DJGPP__ > 1 */
681 /* Tell the caller what dimensions have been REALLY set. */
682 *rows
= ScreenRows ();
683 *cols
= ScreenCols ();
685 /* Update Emacs' notion of screen dimensions. */
686 screen_size_X
= *cols
;
687 screen_size_Y
= *rows
;
688 screen_size
= *cols
* *rows
;
691 /* If the dimensions changed, the mouse highlight info is invalid. */
692 if (current_rows
!= *rows
|| current_cols
!= *cols
)
694 struct frame
*f
= SELECTED_FRAME();
695 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
696 Lisp_Object window
= dpyinfo
->mouse_face_window
;
698 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
700 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
701 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
702 dpyinfo
->mouse_face_window
= Qnil
;
707 /* Enable bright background colors. */
710 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
711 be defensive anyway. */
712 if (screen_virtual_segment
)
713 dosv_refresh_virtual_screen (0, *cols
* *rows
);
716 /* If we write a character in the position where the mouse is,
717 the mouse cursor may need to be refreshed. */
727 mouse_get_xy (&x
, &y
);
728 if (y
!= new_pos_Y
|| x
< new_pos_X
)
734 #define DEFAULT_CURSOR_START (-1)
735 #define DEFAULT_CURSOR_WIDTH (-1)
736 #define BOX_CURSOR_WIDTH (-32)
738 /* Set cursor to begin at scan line START_LINE in the character cell
739 and extend for WIDTH scan lines. Scan lines are counted from top
740 of the character cell, starting from zero. */
742 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
745 unsigned desired_cursor
;
747 int max_line
, top_line
, bot_line
;
749 /* Avoid the costly BIOS call if F isn't the currently selected
750 frame. Allow for NULL as unconditionally meaning the selected
752 if (f
&& f
!= SELECTED_FRAME())
755 /* The character cell size in scan lines is stored at 40:85 in the
757 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
760 default: /* this relies on CGA cursor emulation being ON! */
777 if (width
== BOX_CURSOR_WIDTH
)
782 else if (start_line
!= DEFAULT_CURSOR_START
)
784 top_line
= start_line
;
785 bot_line
= top_line
- width
- 1;
787 else if (width
!= DEFAULT_CURSOR_WIDTH
)
790 bot_line
= -1 - width
;
793 top_line
= bot_line
+ 1;
797 /* [31, 0] seems to DTRT for all screen sizes. */
801 else /* WIDTH is positive */
803 if (start_line
!= DEFAULT_CURSOR_START
)
804 bot_line
= start_line
;
805 top_line
= bot_line
- (width
- 1);
808 /* If the current cursor shape is already what they want, we are
810 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
811 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
815 regs
.x
.cx
= desired_cursor
;
816 __dpmi_int (0x10, ®s
);
817 #endif /* __DJGPP__ > 1 */
821 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
823 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
825 /* Just BAR means the normal EGA/VGA cursor. */
826 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
828 else if (CONSP (cursor_type
)
829 && (EQ (XCAR (cursor_type
), Qbar
)
830 || EQ (XCAR (cursor_type
), Qhbar
)))
832 Lisp_Object bar_parms
= XCDR (cursor_type
);
835 if (INTEGERP (bar_parms
))
837 /* Feature: negative WIDTH means cursor at the top
838 of the character cell, zero means invisible cursor. */
839 width
= XINT (bar_parms
);
840 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
843 else if (CONSP (bar_parms
)
844 && INTEGERP (XCAR (bar_parms
))
845 && INTEGERP (XCDR (bar_parms
)))
847 int start_line
= XINT (XCDR (bar_parms
));
849 width
= XINT (XCAR (bar_parms
));
850 msdos_set_cursor_shape (f
, start_line
, width
);
854 /* Treat anything unknown as "box cursor". This includes nil, so
855 that a frame which doesn't specify a cursor type gets a box,
856 which is the default in Emacs. */
857 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
870 union REGS inregs
, outregs
;
873 intdos (&inregs
, &outregs
);
877 /* Given a face id FACE, extract the face parameters to be used for
878 display until the face changes. The face parameters (actually, its
879 color) are used to construct the video attribute byte for each
880 glyph during the construction of the buffer that is then blitted to
883 IT_set_face (int face
)
885 struct frame
*sf
= SELECTED_FRAME();
886 struct face
*fp
= FACE_FROM_ID (sf
, face
);
887 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
888 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
893 /* The default face for the frame should always be realized and
901 dflt_fg
= dfp
->foreground
;
902 dflt_bg
= dfp
->background
;
904 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
905 mean use the colors of the default face. Note that we assume all
906 16 colors to be available for the background, since Emacs switches
907 on this mode (and loses the blinking attribute) at startup. */
908 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
909 fg
= FRAME_FOREGROUND_PIXEL (sf
);
910 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
911 fg
= FRAME_BACKGROUND_PIXEL (sf
);
912 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
913 bg
= FRAME_BACKGROUND_PIXEL (sf
);
914 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
915 bg
= FRAME_FOREGROUND_PIXEL (sf
);
917 /* Make sure highlighted lines really stand out, come what may. */
918 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
920 unsigned long tem
= fg
;
925 /* If the user requested inverse video, obey. */
928 unsigned long tem2
= fg
;
934 fprintf (termscript
, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face
,
935 fp
->foreground
, fp
->background
, fg
, bg
);
936 if (fg
>= 0 && fg
< 16)
938 ScreenAttrib
&= 0xf0;
941 if (bg
>= 0 && bg
< 16)
943 ScreenAttrib
&= 0x0f;
944 ScreenAttrib
|= ((bg
& 0x0f) << 4);
948 Lisp_Object Vdos_unsupported_char_glyph
;
951 IT_write_glyphs (struct glyph
*str
, int str_len
)
953 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
954 int unsupported_face
= 0;
955 unsigned unsupported_char
= '\177';
956 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
957 register int sl
= str_len
;
958 register int tlen
= GLYPH_TABLE_LENGTH
;
959 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
961 /* If terminal_coding does any conversion, use it, otherwise use
962 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
963 because it always returns 1 if terminal_coding.src_multibyte is 1. */
964 struct coding_system
*coding
=
965 (terminal_coding
.common_flags
& CODING_REQUIRE_ENCODING_MASK
967 : &safe_terminal_coding
);
970 /* Do we need to consider conversion of unibyte characters to
972 int convert_unibyte_characters
973 = (NILP (current_buffer
->enable_multibyte_characters
)
974 && unibyte_display_via_language_environment
);
976 unsigned char conversion_buffer
[256];
977 int conversion_buffer_size
= sizeof conversion_buffer
;
979 if (str_len
<= 0) return;
981 /* Set up the unsupported character glyph */
982 if (!NILP (Vdos_unsupported_char_glyph
))
984 unsupported_char
= FAST_GLYPH_CHAR (XINT (Vdos_unsupported_char_glyph
));
985 unsupported_face
= FAST_GLYPH_FACE (XINT (Vdos_unsupported_char_glyph
));
988 screen_buf
= screen_bp
= alloca (str_len
* 2);
989 screen_buf_end
= screen_buf
+ str_len
* 2;
990 sf
= SELECTED_FRAME();
992 /* Since faces get cached and uncached behind our back, we can't
993 rely on their indices in the cache being consistent across
994 invocations. So always reset the screen face to the default
995 face of the frame, before writing glyphs, and let the glyphs
996 set the right face if it's different from the default. */
997 IT_set_face (DEFAULT_FACE_ID
);
999 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1001 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
1004 int cf
, chlen
, enclen
;
1005 unsigned char workbuf
[MAX_MULTIBYTE_LENGTH
], *buf
;
1008 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
1009 only for the redisplay code to know how many columns does
1010 this character occupy on the screen. Skip padding glyphs. */
1011 if (CHAR_GLYPH_PADDING_P (*str
))
1018 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
1019 int glyph_not_in_table
= 0;
1021 /* If g is negative, it means we have a multibyte character
1022 in *str. That's what GLYPH_FROM_CHAR_GLYPH returns for
1023 multibyte characters. */
1024 if (g
< 0 || g
>= tlen
)
1026 /* This glyph doesn't have an entry in Vglyph_table. */
1028 glyph_not_in_table
= 1;
1032 /* This glyph has an entry in Vglyph_table, so process
1033 any aliases before testing for simpleness. */
1034 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
1035 ch
= FAST_GLYPH_CHAR (g
);
1038 /* Convert the character code to multibyte, if they
1039 requested display via language environment. We only want
1040 to convert unibyte characters to multibyte in unibyte
1041 buffers! Otherwise, the 8-bit value in CH came from the
1042 display table set up to display foreign characters. */
1043 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
1045 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
1046 ch
= unibyte_char_to_multibyte (ch
);
1048 /* Invalid characters are displayed with a special glyph. */
1049 if (! CHAR_VALID_P (ch
, 0))
1051 g
= !NILP (Vdos_unsupported_char_glyph
)
1052 ? XINT (Vdos_unsupported_char_glyph
)
1053 : MAKE_GLYPH (sf
, '\177', GLYPH_FACE (sf
, g
));
1054 ch
= FAST_GLYPH_CHAR (g
);
1057 /* If the face of this glyph is different from the current
1058 screen face, update the screen attribute byte. */
1060 if (cf
!= screen_face
)
1061 IT_set_face (cf
); /* handles invalid faces gracefully */
1063 if (glyph_not_in_table
|| GLYPH_SIMPLE_P (tbase
, tlen
, g
))
1065 /* We generate the multi-byte form of CH in WORKBUF. */
1066 chlen
= CHAR_STRING (ch
, workbuf
);
1071 /* We have a string in Vglyph_table. */
1072 chlen
= GLYPH_LENGTH (tbase
, g
);
1073 buf
= GLYPH_STRING (tbase
, g
);
1076 /* If the character is not multibyte, don't bother converting it. */
1079 *conversion_buffer
= (unsigned char)ch
;
1085 coding
->src_multibyte
= 1;
1086 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
1087 conversion_buffer_size
);
1088 chlen
-= coding
->consumed
;
1089 enclen
= coding
->produced
;
1091 /* Replace glyph codes that cannot be converted by
1092 terminal_coding with Vdos_unsupported_char_glyph. */
1093 if (*conversion_buffer
== '?')
1095 unsigned char *cbp
= conversion_buffer
;
1097 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
1098 *cbp
++ = unsupported_char
;
1099 if (unsupported_face
!= screen_face
)
1100 IT_set_face (unsupported_face
);
1104 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
1106 /* The allocated buffer for screen writes is too small.
1107 Flush it and loop again without incrementing STR, so
1108 that the next loop will begin with the same glyph. */
1109 int nbytes
= screen_bp
- screen_buf
;
1112 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
1113 if (screen_virtual_segment
)
1114 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
1115 new_pos_X
+= nbytes
/ 2;
1118 /* Prepare to reuse the same buffer again. */
1119 screen_bp
= screen_buf
;
1123 /* There's enough place in the allocated buffer to add
1124 the encoding of this glyph. */
1126 /* First, copy the encoded bytes. */
1127 for (bp
= conversion_buffer
; enclen
--; bp
++)
1129 *screen_bp
++ = (unsigned char)*bp
;
1130 *screen_bp
++ = ScreenAttrib
;
1132 fputc (*bp
, termscript
);
1135 /* Now copy the bytes not consumed by the encoding. */
1138 buf
+= coding
->consumed
;
1142 fputc (*buf
, termscript
);
1143 *screen_bp
++ = (unsigned char)*buf
++;
1144 *screen_bp
++ = ScreenAttrib
;
1148 /* Update STR and its remaining length. */
1155 /* Dump whatever is left in the screen buffer. */
1157 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1158 if (screen_virtual_segment
)
1159 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1160 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1162 /* We may have to output some codes to terminate the writing. */
1163 if (CODING_REQUIRE_FLUSHING (coding
))
1165 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1166 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
1167 if (coding
->produced
> 0)
1169 screen_buf
= alloca (coding
->produced
* 2);
1170 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
1171 coding
->produced
--; bp
++)
1173 *screen_bp
++ = (unsigned char)*bp
;
1174 *screen_bp
++ = ScreenAttrib
;
1176 fputc (*bp
, termscript
);
1178 offset
+= screen_bp
- screen_buf
;
1180 dosmemput (screen_buf
, screen_bp
- screen_buf
,
1181 (int)ScreenPrimary
+ offset
);
1182 if (screen_virtual_segment
)
1183 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1184 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1189 /************************************************************************
1190 Mouse Highlight (and friends..)
1191 ************************************************************************/
1193 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1194 static Lisp_Object last_mouse_window
;
1196 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1198 /* Set the mouse pointer shape according to whether it is in the
1199 area where the mouse highlight is in effect. */
1201 IT_set_mouse_pointer (int mode
)
1203 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1204 many possibilities to change its shape, and the available
1205 functionality pretty much sucks (e.g., almost every reasonable
1206 shape will conceal the character it is on). Since the color of
1207 the pointer changes in the highlighted area, it is not clear to
1208 me whether anything else is required, anyway. */
1211 /* Display the active region described by mouse_face_*
1212 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1214 show_mouse_face (struct display_info
*dpyinfo
, int hl
)
1216 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1217 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1222 /* If window is in the process of being destroyed, don't bother
1224 if (w
->current_matrix
== NULL
)
1225 goto set_cursor_shape
;
1227 /* Recognize when we are called to operate on rows that don't exist
1228 anymore. This can happen when a window is split. */
1229 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1230 goto set_cursor_shape
;
1232 /* There's no sense to do anything if the mouse face isn't realized. */
1235 if (dpyinfo
->mouse_face_hidden
)
1236 goto set_cursor_shape
;
1238 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1240 goto set_cursor_shape
;
1243 /* Note that mouse_face_beg_row etc. are window relative. */
1244 for (i
= dpyinfo
->mouse_face_beg_row
;
1245 i
<= dpyinfo
->mouse_face_end_row
;
1248 int start_hpos
, end_hpos
;
1249 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1251 /* Don't do anything if row doesn't have valid contents. */
1252 if (!row
->enabled_p
)
1255 /* For all but the first row, the highlight starts at column 0. */
1256 if (i
== dpyinfo
->mouse_face_beg_row
)
1257 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1261 if (i
== dpyinfo
->mouse_face_end_row
)
1262 end_hpos
= dpyinfo
->mouse_face_end_col
;
1264 end_hpos
= row
->used
[TEXT_AREA
];
1266 if (end_hpos
<= start_hpos
)
1268 /* Record that some glyphs of this row are displayed in
1270 row
->mouse_face_p
= hl
> 0;
1273 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1274 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1275 int nglyphs
= end_hpos
- start_hpos
;
1276 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1277 int start_offset
= offset
;
1280 fprintf (termscript
, "\n<MH+ %d-%d:%d>",
1281 kstart
, kstart
+ nglyphs
- 1, vpos
);
1284 IT_set_face (dpyinfo
->mouse_face_face_id
);
1285 /* Since we are going to change only the _colors_ of the
1286 displayed text, there's no need to go through all the
1287 pain of generating and encoding the text from the glyphs.
1288 Instead, we simply poke the attribute byte of each
1289 affected position in video memory with the colors
1290 computed by IT_set_face! */
1291 _farsetsel (_dos_ds
);
1294 _farnspokeb (offset
, ScreenAttrib
);
1297 if (screen_virtual_segment
)
1298 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1303 /* We are removing a previously-drawn mouse highlight. The
1304 safest way to do so is to redraw the glyphs anew, since
1305 all kinds of faces and display tables could have changed
1307 int nglyphs
= end_hpos
- start_hpos
;
1308 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1310 if (end_hpos
>= row
->used
[TEXT_AREA
])
1311 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1313 /* IT_write_glyphs writes at cursor position, so we need to
1314 temporarily move cursor coordinates to the beginning of
1315 the highlight region. */
1316 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1317 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1320 fprintf (termscript
, "<MH- %d-%d:%d>",
1321 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1322 IT_write_glyphs (row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1324 fputs ("\n", termscript
);
1331 /* Change the mouse pointer shape. */
1332 IT_set_mouse_pointer (hl
);
1335 /* Clear out the mouse-highlighted active region.
1336 Redraw it un-highlighted first. */
1338 clear_mouse_face (struct display_info
*dpyinfo
)
1340 if (!dpyinfo
->mouse_face_hidden
&& ! NILP (dpyinfo
->mouse_face_window
))
1341 show_mouse_face (dpyinfo
, 0);
1343 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1344 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1345 dpyinfo
->mouse_face_window
= Qnil
;
1348 /* Find the glyph matrix position of buffer position POS in window W.
1349 *HPOS and *VPOS are set to the positions found. W's current glyphs
1350 must be up to date. If POS is above window start return (0, 0).
1351 If POS is after end of W, return end of last line in W. */
1353 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1355 int i
, lastcol
, line_start_position
, maybe_next_line_p
= 0;
1356 int yb
= window_text_bottom_y (w
);
1357 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0), *best_row
= row
;
1361 if (row
->used
[TEXT_AREA
])
1362 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1364 line_start_position
= 0;
1366 if (line_start_position
> pos
)
1368 /* If the position sought is the end of the buffer,
1369 don't include the blank lines at the bottom of the window. */
1370 else if (line_start_position
== pos
1371 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1373 maybe_next_line_p
= 1;
1376 else if (line_start_position
> 0)
1379 /* Don't overstep the last matrix row, lest we get into the
1380 never-never land... */
1381 if (row
->y
+ 1 >= yb
)
1387 /* Find the right column within BEST_ROW. */
1390 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1392 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1395 charpos
= glyph
->charpos
;
1402 else if (charpos
> pos
)
1404 else if (charpos
> 0)
1408 /* If we're looking for the end of the buffer,
1409 and we didn't find it in the line we scanned,
1410 use the start of the following line. */
1411 if (maybe_next_line_p
)
1418 *hpos
= lastcol
+ 1;
1422 /* Take proper action when mouse has moved to the mode or top line of
1423 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1424 mode line. X is relative to the start of the text display area of
1425 W, so the width of fringes and scroll bars must be subtracted
1426 to get a position relative to the start of the mode line. */
1428 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1430 struct frame
*f
= XFRAME (w
->frame
);
1431 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1432 struct glyph_row
*row
;
1435 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1437 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1441 extern Lisp_Object Qhelp_echo
;
1442 struct glyph
*glyph
, *end
;
1443 Lisp_Object help
, map
;
1445 /* Find the glyph under X. */
1446 glyph
= (row
->glyphs
[TEXT_AREA
]
1448 /* in case someone implements scroll bars some day... */
1449 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w
));
1450 end
= glyph
+ row
->used
[TEXT_AREA
];
1452 && STRINGP (glyph
->object
)
1453 && STRING_INTERVALS (glyph
->object
)
1454 && glyph
->charpos
>= 0
1455 && glyph
->charpos
< SCHARS (glyph
->object
))
1457 /* If we're on a string with `help-echo' text property,
1458 arrange for the help to be displayed. This is done by
1459 setting the global variable help_echo to the help string. */
1460 help
= Fget_text_property (make_number (glyph
->charpos
),
1461 Qhelp_echo
, glyph
->object
);
1464 help_echo_string
= help
;
1465 XSETWINDOW (help_echo_window
, w
);
1466 help_echo_object
= glyph
->object
;
1467 help_echo_pos
= glyph
->charpos
;
1473 /* Take proper action when the mouse has moved to position X, Y on
1474 frame F as regards highlighting characters that have mouse-face
1475 properties. Also de-highlighting chars where the mouse was before.
1476 X and Y can be negative or out of range. */
1478 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1480 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1481 enum window_part part
= ON_NOTHING
;
1485 /* When a menu is active, don't highlight because this looks odd. */
1486 if (mouse_preempted
)
1489 if (NILP (Vmouse_highlight
)
1490 || !f
->glyphs_initialized_p
)
1493 dpyinfo
->mouse_face_mouse_x
= x
;
1494 dpyinfo
->mouse_face_mouse_y
= y
;
1495 dpyinfo
->mouse_face_mouse_frame
= f
;
1497 if (dpyinfo
->mouse_face_defer
)
1502 dpyinfo
->mouse_face_deferred_gc
= 1;
1506 /* Which window is that in? */
1507 window
= window_from_coordinates (f
, x
, y
, &part
, &x
, &y
, 0);
1509 /* If we were displaying active text in another window, clear that. */
1510 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1511 clear_mouse_face (dpyinfo
);
1513 /* Not on a window -> return. */
1514 if (!WINDOWP (window
))
1517 /* Convert to window-relative coordinates. */
1518 w
= XWINDOW (window
);
1520 if (part
== ON_MODE_LINE
|| part
== ON_HEADER_LINE
)
1522 /* Mouse is on the mode or top line. */
1523 IT_note_mode_line_highlight (w
, x
, part
== ON_MODE_LINE
);
1527 IT_set_mouse_pointer (0);
1529 /* Are we in a window whose display is up to date?
1530 And verify the buffer's text has not changed. */
1532 && EQ (w
->window_end_valid
, w
->buffer
)
1533 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1534 && (XFASTINT (w
->last_overlay_modified
)
1535 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1537 int pos
, i
, nrows
= w
->current_matrix
->nrows
;
1538 struct glyph_row
*row
;
1539 struct glyph
*glyph
;
1541 /* Find the glyph under X/Y. */
1543 if (y
>= 0 && y
< nrows
)
1545 row
= MATRIX_ROW (w
->current_matrix
, y
);
1546 /* Give up if some row before the one we are looking for is
1548 for (i
= 0; i
<= y
; i
++)
1549 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1551 if (i
> y
/* all rows upto and including the one at Y are enabled */
1552 && row
->displays_text_p
1553 && x
< window_box_width (w
, TEXT_AREA
))
1555 glyph
= row
->glyphs
[TEXT_AREA
];
1556 if (x
>= row
->used
[TEXT_AREA
])
1561 if (!BUFFERP (glyph
->object
))
1567 /* Clear mouse face if X/Y not over text. */
1570 clear_mouse_face (dpyinfo
);
1574 if (!BUFFERP (glyph
->object
))
1576 pos
= glyph
->charpos
;
1578 /* Check for mouse-face and help-echo. */
1580 extern Lisp_Object Qmouse_face
;
1581 Lisp_Object mouse_face
, overlay
, position
, *overlay_vec
;
1582 int noverlays
, obegv
, ozv
;;
1583 struct buffer
*obuf
;
1585 /* If we get an out-of-range value, return now; avoid an error. */
1586 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1589 /* Make the window's buffer temporarily current for
1590 overlays_at and compute_char_face. */
1591 obuf
= current_buffer
;
1592 current_buffer
= XBUFFER (w
->buffer
);
1598 /* Is this char mouse-active or does it have help-echo? */
1599 XSETINT (position
, pos
);
1601 /* Put all the overlays we want in a vector in overlay_vec. */
1602 GET_OVERLAYS_AT (pos
, overlay_vec
, noverlays
, NULL
, 0);
1603 /* Sort overlays into increasing priority order. */
1604 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1606 /* Check mouse-face highlighting. */
1607 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1608 && y
>= dpyinfo
->mouse_face_beg_row
1609 && y
<= dpyinfo
->mouse_face_end_row
1610 && (y
> dpyinfo
->mouse_face_beg_row
1611 || x
>= dpyinfo
->mouse_face_beg_col
)
1612 && (y
< dpyinfo
->mouse_face_end_row
1613 || x
< dpyinfo
->mouse_face_end_col
1614 || dpyinfo
->mouse_face_past_end
)))
1616 /* Clear the display of the old active region, if any. */
1617 clear_mouse_face (dpyinfo
);
1619 /* Find highest priority overlay that has a mouse-face prop. */
1621 for (i
= noverlays
- 1; i
>= 0; --i
)
1623 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1624 if (!NILP (mouse_face
))
1626 overlay
= overlay_vec
[i
];
1631 /* If no overlay applies, get a text property. */
1633 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1636 /* Handle the overlay case. */
1637 if (! NILP (overlay
))
1639 /* Find the range of text around this char that
1640 should be active. */
1641 Lisp_Object before
, after
;
1644 before
= Foverlay_start (overlay
);
1645 after
= Foverlay_end (overlay
);
1646 /* Record this as the current active region. */
1647 fast_find_position (w
, XFASTINT (before
),
1648 &dpyinfo
->mouse_face_beg_col
,
1649 &dpyinfo
->mouse_face_beg_row
);
1650 dpyinfo
->mouse_face_past_end
1651 = !fast_find_position (w
, XFASTINT (after
),
1652 &dpyinfo
->mouse_face_end_col
,
1653 &dpyinfo
->mouse_face_end_row
);
1654 dpyinfo
->mouse_face_window
= window
;
1655 dpyinfo
->mouse_face_face_id
1656 = face_at_buffer_position (w
, pos
, 0, 0,
1658 !dpyinfo
->mouse_face_hidden
);
1660 /* Display it as active. */
1661 show_mouse_face (dpyinfo
, 1);
1663 /* Handle the text property case. */
1664 else if (! NILP (mouse_face
))
1666 /* Find the range of text around this char that
1667 should be active. */
1668 Lisp_Object before
, after
, beginning
, end
;
1671 beginning
= Fmarker_position (w
->start
);
1672 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1673 - XFASTINT (w
->window_end_pos
)));
1675 = Fprevious_single_property_change (make_number (pos
+ 1),
1677 w
->buffer
, beginning
);
1679 = Fnext_single_property_change (position
, Qmouse_face
,
1681 /* Record this as the current active region. */
1682 fast_find_position (w
, XFASTINT (before
),
1683 &dpyinfo
->mouse_face_beg_col
,
1684 &dpyinfo
->mouse_face_beg_row
);
1685 dpyinfo
->mouse_face_past_end
1686 = !fast_find_position (w
, XFASTINT (after
),
1687 &dpyinfo
->mouse_face_end_col
,
1688 &dpyinfo
->mouse_face_end_row
);
1689 dpyinfo
->mouse_face_window
= window
;
1690 dpyinfo
->mouse_face_face_id
1691 = face_at_buffer_position (w
, pos
, 0, 0,
1693 !dpyinfo
->mouse_face_hidden
);
1695 /* Display it as active. */
1696 show_mouse_face (dpyinfo
, 1);
1700 /* Look for a `help-echo' property. */
1703 extern Lisp_Object Qhelp_echo
;
1705 /* Check overlays first. */
1707 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1709 overlay
= overlay_vec
[i
];
1710 help
= Foverlay_get (overlay
, Qhelp_echo
);
1715 help_echo_string
= help
;
1716 help_echo_window
= window
;
1717 help_echo_object
= overlay
;
1718 help_echo_pos
= pos
;
1720 /* Try text properties. */
1721 else if (NILP (help
)
1722 && ((STRINGP (glyph
->object
)
1723 && glyph
->charpos
>= 0
1724 && glyph
->charpos
< SCHARS (glyph
->object
))
1725 || (BUFFERP (glyph
->object
)
1726 && glyph
->charpos
>= BEGV
1727 && glyph
->charpos
< ZV
)))
1729 help
= Fget_text_property (make_number (glyph
->charpos
),
1730 Qhelp_echo
, glyph
->object
);
1733 help_echo_string
= help
;
1734 help_echo_window
= window
;
1735 help_echo_object
= glyph
->object
;
1736 help_echo_pos
= glyph
->charpos
;
1743 current_buffer
= obuf
;
1749 IT_clear_end_of_line (int first_unused
)
1752 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1753 extern int fatal_error_in_progress
;
1755 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1759 i
= (j
= first_unused
- new_pos_X
) * 2;
1761 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1762 spaces
= sp
= alloca (i
);
1767 *sp
++ = ScreenAttrib
;
1771 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1772 if (screen_virtual_segment
)
1773 dosv_refresh_virtual_screen (offset
, i
/ 2);
1775 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1776 Let's follow their lead, in case someone relies on this. */
1777 new_pos_X
= first_unused
;
1781 IT_clear_screen (void)
1784 fprintf (termscript
, "<CLR:SCR>");
1785 /* We are sometimes called (from clear_garbaged_frames) when a new
1786 frame is being created, but its faces are not yet realized. In
1787 such a case we cannot call IT_set_face, since it will fail to find
1788 any valid faces and will abort. Instead, use the initial screen
1789 colors; that should mimic what a Unix tty does, which simply clears
1790 the screen with whatever default colors are in use. */
1791 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1792 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1797 if (screen_virtual_segment
)
1798 dosv_refresh_virtual_screen (0, screen_size
);
1799 new_pos_X
= new_pos_Y
= 0;
1803 IT_clear_to_end (void)
1806 fprintf (termscript
, "<CLR:EOS>");
1808 while (new_pos_Y
< screen_size_Y
) {
1810 IT_clear_end_of_line (screen_size_X
);
1816 IT_cursor_to (int y
, int x
)
1819 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1824 static int cursor_cleared
;
1827 IT_display_cursor (int on
)
1829 if (on
&& cursor_cleared
)
1831 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1834 else if (!on
&& !cursor_cleared
)
1836 ScreenSetCursor (-1, -1);
1841 /* Emacs calls cursor-movement functions a lot when it updates the
1842 display (probably a legacy of old terminals where you cannot
1843 update a screen line without first moving the cursor there).
1844 However, cursor movement is expensive on MSDOS (it calls a slow
1845 BIOS function and requires 2 mode switches), while actual screen
1846 updates access the video memory directly and don't depend on
1847 cursor position. To avoid slowing down the redisplay, we cheat:
1848 all functions that move the cursor only set internal variables
1849 which record the cursor position, whereas the cursor is only
1850 moved to its final position whenever screen update is complete.
1852 `IT_cmgoto' is called from the keyboard reading loop and when the
1853 frame update is complete. This means that we are ready for user
1854 input, so we update the cursor position to show where the point is,
1855 and also make the mouse pointer visible.
1857 Special treatment is required when the cursor is in the echo area,
1858 to put the cursor at the end of the text displayed there. */
1861 IT_cmgoto (FRAME_PTR f
)
1863 /* Only set the cursor to where it should be if the display is
1864 already in sync with the window contents. */
1865 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1867 /* FIXME: This needs to be rewritten for the new redisplay, or
1870 static int previous_pos_X
= -1;
1872 update_cursor_pos
= 1; /* temporary!!! */
1874 /* If the display is in sync, forget any previous knowledge about
1875 cursor position. This is primarily for unexpected events like
1876 C-g in the minibuffer. */
1877 if (update_cursor_pos
&& previous_pos_X
>= 0)
1878 previous_pos_X
= -1;
1879 /* If we are in the echo area, put the cursor at the
1880 end of the echo area message. */
1881 if (!update_cursor_pos
1882 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1884 int tem_X
= current_pos_X
, dummy
;
1886 if (echo_area_glyphs
)
1888 tem_X
= echo_area_glyphs_length
;
1889 /* Save current cursor position, to be restored after the
1890 echo area message is erased. Only remember one level
1891 of previous cursor position. */
1892 if (previous_pos_X
== -1)
1893 ScreenGetCursor (&dummy
, &previous_pos_X
);
1895 else if (previous_pos_X
>= 0)
1897 /* We wind up here after the echo area message is erased.
1898 Restore the cursor position we remembered above. */
1899 tem_X
= previous_pos_X
;
1900 previous_pos_X
= -1;
1903 if (current_pos_X
!= tem_X
)
1906 update_cursor_pos
= 1;
1911 if (update_cursor_pos
1912 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1914 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1916 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1919 /* Maybe cursor is invisible, so make it visible. */
1920 IT_display_cursor (1);
1922 /* Mouse pointer should be always visible if we are waiting for
1929 IT_update_begin (struct frame
*f
)
1931 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1932 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1936 if (f
&& f
== mouse_face_frame
)
1938 /* Don't do highlighting for mouse motion during the update. */
1939 display_info
->mouse_face_defer
= 1;
1941 /* If F needs to be redrawn, simply forget about any prior mouse
1943 if (FRAME_GARBAGED_P (f
))
1944 display_info
->mouse_face_window
= Qnil
;
1946 /* Can we tell that this update does not affect the window
1947 where the mouse highlight is? If so, no need to turn off.
1948 Likewise, don't do anything if none of the enabled rows
1949 contains glyphs highlighted in mouse face. */
1950 if (!NILP (display_info
->mouse_face_window
)
1951 && WINDOWP (display_info
->mouse_face_window
))
1953 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1956 /* If the mouse highlight is in the window that was deleted
1957 (e.g., if it was popped by completion), clear highlight
1959 if (NILP (w
->buffer
))
1960 display_info
->mouse_face_window
= Qnil
;
1963 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1964 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1965 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1969 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1970 clear_mouse_face (display_info
);
1973 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1975 /* If the frame with mouse highlight was deleted, invalidate the
1977 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1978 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1979 display_info
->mouse_face_window
= Qnil
;
1980 display_info
->mouse_face_deferred_gc
= 0;
1981 display_info
->mouse_face_mouse_frame
= NULL
;
1988 IT_update_end (struct frame
*f
)
1990 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
1994 IT_frame_up_to_date (struct frame
*f
)
1996 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1997 Lisp_Object new_cursor
, frame_desired_cursor
;
2000 if (dpyinfo
->mouse_face_deferred_gc
2001 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
2004 if (dpyinfo
->mouse_face_mouse_frame
)
2005 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
2006 dpyinfo
->mouse_face_mouse_x
,
2007 dpyinfo
->mouse_face_mouse_y
);
2008 dpyinfo
->mouse_face_deferred_gc
= 0;
2012 /* Set the cursor type to whatever they wanted. In a minibuffer
2013 window, we want the cursor to appear only if we are reading input
2014 from this window, and we want the cursor to be taken from the
2015 frame parameters. For the selected window, we use either its
2016 buffer-local value or the value from the frame parameters if the
2017 buffer doesn't define its local value for the cursor type. */
2018 sw
= XWINDOW (f
->selected_window
);
2019 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
2020 if (cursor_in_echo_area
2021 && FRAME_HAS_MINIBUF_P (f
)
2022 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
2023 && sw
== XWINDOW (echo_area_window
))
2024 new_cursor
= frame_desired_cursor
;
2027 struct buffer
*b
= XBUFFER (sw
->buffer
);
2029 if (EQ (b
->cursor_type
, Qt
))
2030 new_cursor
= frame_desired_cursor
;
2031 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
2032 new_cursor
= Fcons (Qbar
, make_number (0));
2034 new_cursor
= b
->cursor_type
;
2037 IT_set_cursor_type (f
, new_cursor
);
2039 IT_cmgoto (f
); /* position cursor when update is done */
2042 /* Copy LEN glyphs displayed on a single line whose vertical position
2043 is YPOS, beginning at horizontal position XFROM to horizontal
2044 position XTO, by moving blocks in the video memory. Used by
2045 functions that insert and delete glyphs. */
2047 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
2049 /* The offsets of source and destination relative to the
2050 conventional memorty selector. */
2051 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
2052 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
2054 if (from
== to
|| len
<= 0)
2057 _farsetsel (_dos_ds
);
2059 /* The source and destination might overlap, so we need to move
2060 glyphs non-destructively. */
2063 for ( ; len
; from
+= 2, to
+= 2, len
--)
2064 _farnspokew (to
, _farnspeekw (from
));
2068 from
+= (len
- 1) * 2;
2069 to
+= (len
- 1) * 2;
2070 for ( ; len
; from
-= 2, to
-= 2, len
--)
2071 _farnspokew (to
, _farnspeekw (from
));
2073 if (screen_virtual_segment
)
2074 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
2077 /* Insert and delete glyphs. */
2079 IT_insert_glyphs (start
, len
)
2080 register struct glyph
*start
;
2083 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
2085 /* Shift right the glyphs from the nominal cursor position to the
2086 end of this line. */
2087 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2089 /* Now write the glyphs to be inserted. */
2090 IT_write_glyphs (start
, len
);
2094 IT_delete_glyphs (n
)
2100 /* set-window-configuration on window.c needs this. */
2102 x_set_menu_bar_lines (f
, value
, oldval
)
2104 Lisp_Object value
, oldval
;
2106 set_menu_bar_lines (f
, value
, oldval
);
2109 /* This was copied from xfaces.c */
2111 extern Lisp_Object Qbackground_color
;
2112 extern Lisp_Object Qforeground_color
;
2113 Lisp_Object Qreverse
;
2114 extern Lisp_Object Qtitle
;
2116 /* IT_set_terminal_modes is called when emacs is started,
2117 resumed, and whenever the screen is redrawn! */
2120 IT_set_terminal_modes (void)
2123 fprintf (termscript
, "\n<SET_TERM>");
2125 screen_size_X
= ScreenCols ();
2126 screen_size_Y
= ScreenRows ();
2127 screen_size
= screen_size_X
* screen_size_Y
;
2129 new_pos_X
= new_pos_Y
= 0;
2130 current_pos_X
= current_pos_Y
= -1;
2132 if (term_setup_done
)
2134 term_setup_done
= 1;
2136 startup_screen_size_X
= screen_size_X
;
2137 startup_screen_size_Y
= screen_size_Y
;
2138 startup_screen_attrib
= ScreenAttrib
;
2141 /* Is DOS/V (or any other RSIS software which relocates
2142 the screen) installed? */
2144 unsigned short es_value
;
2147 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2148 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2149 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2150 else if (screen_old_address
) /* already switched to Japanese mode once */
2151 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2153 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2155 es_value
= regs
.x
.es
;
2156 __dpmi_int (0x10, ®s
);
2158 if (regs
.x
.es
!= es_value
)
2160 /* screen_old_address is only set if ScreenPrimary does NOT
2161 already point to the relocated buffer address returned by
2162 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2163 ScreenPrimary to that address at startup under DOS/V. */
2164 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2165 screen_old_address
= ScreenPrimary
;
2166 screen_virtual_segment
= regs
.x
.es
;
2167 screen_virtual_offset
= regs
.x
.di
;
2168 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2171 #endif /* __DJGPP__ > 1 */
2173 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2174 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2177 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2178 screen_size_X
, screen_size_Y
);
2183 /* IT_reset_terminal_modes is called when emacs is
2184 suspended or killed. */
2187 IT_reset_terminal_modes (void)
2189 int display_row_start
= (int) ScreenPrimary
;
2190 int saved_row_len
= startup_screen_size_X
* 2;
2191 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
2192 int to_next_row
= update_row_len
;
2193 unsigned char *saved_row
= startup_screen_buffer
;
2194 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
2197 fprintf (termscript
, "\n<RESET_TERM>");
2199 if (!term_setup_done
)
2204 /* Leave the video system in the same state as we found it,
2205 as far as the blink/bright-background bit is concerned. */
2206 maybe_enable_blinking ();
2208 /* We have a situation here.
2209 We cannot just do ScreenUpdate(startup_screen_buffer) because
2210 the luser could have changed screen dimensions inside Emacs
2211 and failed (or didn't want) to restore them before killing
2212 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2213 thus will happily use memory outside what was allocated for
2214 `startup_screen_buffer'.
2215 Thus we only restore as much as the current screen dimensions
2216 can hold, and clear the rest (if the saved screen is smaller than
2217 the current) with the color attribute saved at startup. The cursor
2218 is also restored within the visible dimensions. */
2220 ScreenAttrib
= startup_screen_attrib
;
2222 /* Don't restore the screen if we are exiting less than 2 seconds
2223 after startup: we might be crashing, and the screen might show
2224 some vital clues to what's wrong. */
2225 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2228 if (screen_virtual_segment
)
2229 dosv_refresh_virtual_screen (0, screen_size
);
2231 if (update_row_len
> saved_row_len
)
2232 update_row_len
= saved_row_len
;
2233 if (current_rows
> startup_screen_size_Y
)
2234 current_rows
= startup_screen_size_Y
;
2237 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2238 update_row_len
/ 2, current_rows
);
2240 while (current_rows
--)
2242 dosmemput (saved_row
, update_row_len
, display_row_start
);
2243 if (screen_virtual_segment
)
2244 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2245 update_row_len
/ 2);
2246 saved_row
+= saved_row_len
;
2247 display_row_start
+= to_next_row
;
2250 if (startup_pos_X
< cursor_pos_X
)
2251 cursor_pos_X
= startup_pos_X
;
2252 if (startup_pos_Y
< cursor_pos_Y
)
2253 cursor_pos_Y
= startup_pos_Y
;
2255 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2256 xfree (startup_screen_buffer
);
2258 term_setup_done
= 0;
2262 IT_set_terminal_window (int foo
)
2266 /* Remember the screen colors of the curent frame, to serve as the
2267 default colors for newly-created frames. */
2268 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2269 Smsdos_remember_default_colors
, 1, 1, 0,
2270 doc
: /* Remember the screen colors of the current frame. */)
2276 CHECK_FRAME (frame
);
2279 /* This function is called after applying default-frame-alist to the
2280 initial frame. At that time, if reverse-colors option was
2281 specified in default-frame-alist, it was already applied, and
2282 frame colors are reversed. We need to account for that. */
2283 if (EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
))
2285 initial_screen_colors
[0] = FRAME_BACKGROUND_PIXEL (f
);
2286 initial_screen_colors
[1] = FRAME_FOREGROUND_PIXEL (f
);
2290 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2291 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2296 IT_set_frame_parameters (f
, alist
)
2301 int i
, j
, length
= XINT (Flength (alist
));
2303 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2305 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2306 /* Do we have to reverse the foreground and background colors? */
2307 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2308 int need_to_reverse
, was_reverse
= reverse
;
2309 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2310 unsigned long orig_fg
, orig_bg
;
2311 Lisp_Object frame_bg
, frame_fg
;
2312 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2314 /* If we are creating a new frame, begin with the original screen colors
2315 used for the initial frame. */
2316 if (alist
== Vdefault_frame_alist
2317 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2319 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2320 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2322 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2323 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2324 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2325 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2326 /* frame_fg and frame_bg could be nil if, for example,
2327 f->param_alist is nil, e.g. if we are called from
2328 Fmake_terminal_frame. */
2329 if (NILP (frame_fg
))
2330 frame_fg
= build_string (unspecified_fg
);
2331 if (NILP (frame_bg
))
2332 frame_bg
= build_string (unspecified_bg
);
2334 /* Extract parm names and values into those vectors. */
2336 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2341 parms
[i
] = Fcar (elt
);
2342 CHECK_SYMBOL (parms
[i
]);
2343 values
[i
] = Fcdr (elt
);
2349 for (i
= 0; i
< j
; i
++)
2351 Lisp_Object prop
, val
;
2356 if (EQ (prop
, Qreverse
))
2357 reverse
= EQ (val
, Qt
);
2360 need_to_reverse
= reverse
&& !was_reverse
;
2361 if (termscript
&& need_to_reverse
)
2362 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2364 /* Now process the alist elements in reverse of specified order. */
2365 for (i
--; i
>= 0; i
--)
2367 Lisp_Object prop
, val
, frame
;
2372 if (EQ (prop
, Qforeground_color
))
2374 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2375 ? LFACE_BACKGROUND_INDEX
2376 : LFACE_FOREGROUND_INDEX
);
2377 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2378 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2379 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2381 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2382 /* Make sure the foreground of the default face for this
2383 frame is changed as well. */
2384 XSETFRAME (frame
, f
);
2385 if (need_to_reverse
)
2387 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2389 prop
= Qbackground_color
;
2394 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2400 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2403 else if (EQ (prop
, Qbackground_color
))
2405 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2406 ? LFACE_FOREGROUND_INDEX
2407 : LFACE_BACKGROUND_INDEX
);
2408 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2409 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2410 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2412 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2413 /* Make sure the background of the default face for this
2414 frame is changed as well. */
2415 XSETFRAME (frame
, f
);
2416 if (need_to_reverse
)
2418 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2420 prop
= Qforeground_color
;
2425 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2431 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2434 else if (EQ (prop
, Qtitle
))
2436 x_set_title (f
, val
);
2438 fprintf (termscript
, "<TITLE: %s>\n", SDATA (val
));
2440 else if (EQ (prop
, Qcursor_type
))
2442 IT_set_cursor_type (f
, val
);
2444 fprintf (termscript
, "<CTYPE: %s>\n",
2445 EQ (val
, Qbar
) || EQ (val
, Qhbar
)
2446 || CONSP (val
) && (EQ (XCAR (val
), Qbar
)
2447 || EQ (XCAR (val
), Qhbar
))
2450 store_frame_param (f
, prop
, val
);
2453 /* If they specified "reverse", but not the colors, we need to swap
2454 the current frame colors. */
2455 if (need_to_reverse
)
2461 XSETFRAME (frame
, f
);
2462 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2463 tty_color_name (f
, orig_bg
),
2469 XSETFRAME (frame
, f
);
2470 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2471 tty_color_name (f
, orig_fg
),
2479 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2480 if (f
== SELECTED_FRAME())
2485 extern void init_frame_faces (FRAME_PTR
);
2487 #endif /* !HAVE_X_WINDOWS */
2490 /* Do we need the internal terminal? */
2493 internal_terminal_init ()
2495 char *term
= getenv ("TERM"), *colors
;
2496 struct frame
*sf
= SELECTED_FRAME();
2498 #ifdef HAVE_X_WINDOWS
2499 if (!inhibit_window_system
)
2504 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2506 if (getenv ("EMACSTEST"))
2507 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2509 #ifndef HAVE_X_WINDOWS
2510 if (!internal_terminal
|| inhibit_window_system
)
2512 sf
->output_method
= output_termcap
;
2516 Vwindow_system
= intern ("pc");
2517 Vwindow_system_version
= make_number (1);
2518 sf
->output_method
= output_msdos_raw
;
2520 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2521 screen_old_address
= 0;
2523 /* Forget the stale screen colors as well. */
2524 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2526 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2527 the_only_x_display
.background_pixel
= 7; /* White */
2528 the_only_x_display
.foreground_pixel
= 0; /* Black */
2530 colors
= getenv ("EMACSCOLORS");
2531 if (colors
&& strlen (colors
) >= 2)
2533 /* The colors use 4 bits each (we enable bright background). */
2534 if (isdigit (colors
[0]))
2536 else if (isxdigit (colors
[0]))
2537 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2538 if (colors
[0] >= 0 && colors
[0] < 16)
2539 the_only_x_display
.foreground_pixel
= colors
[0];
2540 if (isdigit (colors
[1]))
2542 else if (isxdigit (colors
[1]))
2543 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2544 if (colors
[1] >= 0 && colors
[1] < 16)
2545 the_only_x_display
.background_pixel
= colors
[1];
2547 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2548 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2549 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2550 the_only_x_display
.display_info
.mouse_face_beg_row
=
2551 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2552 the_only_x_display
.display_info
.mouse_face_end_row
=
2553 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2554 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2555 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2556 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2557 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2558 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2559 the_only_x_display
.display_info
.mouse_face_hidden
= 0;
2561 init_frame_faces (sf
);
2563 ring_bell_hook
= IT_ring_bell
;
2564 insert_glyphs_hook
= IT_insert_glyphs
;
2565 delete_glyphs_hook
= IT_delete_glyphs
;
2566 write_glyphs_hook
= IT_write_glyphs
;
2567 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2568 clear_to_end_hook
= IT_clear_to_end
;
2569 clear_end_of_line_hook
= IT_clear_end_of_line
;
2570 clear_frame_hook
= IT_clear_screen
;
2571 update_begin_hook
= IT_update_begin
;
2572 update_end_hook
= IT_update_end
;
2573 frame_up_to_date_hook
= IT_frame_up_to_date
;
2575 /* These hooks are called by term.c without being checked. */
2576 set_terminal_modes_hook
= IT_set_terminal_modes
;
2577 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2578 set_terminal_window_hook
= IT_set_terminal_window
;
2579 char_ins_del_ok
= 0;
2583 dos_get_saved_screen (screen
, rows
, cols
)
2588 #ifndef HAVE_X_WINDOWS
2589 *screen
= startup_screen_buffer
;
2590 *cols
= startup_screen_size_X
;
2591 *rows
= startup_screen_size_Y
;
2592 return *screen
!= (char *)0;
2598 #ifndef HAVE_X_WINDOWS
2600 /* We are not X, but we can emulate it well enough for our needs... */
2604 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2605 error ("Not running under a window system");
2611 /* ----------------------- Keyboard control ----------------------
2613 * Keymaps reflect the following keyboard layout:
2615 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2616 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2617 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2618 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2622 #define Ignore 0x0000
2623 #define Normal 0x0000 /* normal key - alt changes scan-code */
2624 #define FctKey 0x1000 /* func key if c == 0, else c */
2625 #define Special 0x2000 /* func key even if c != 0 */
2626 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2627 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2628 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2629 #define Grey 0x6000 /* Grey keypad key */
2631 #define Alt 0x0100 /* alt scan-code */
2632 #define Ctrl 0x0200 /* ctrl scan-code */
2633 #define Shift 0x0400 /* shift scan-code */
2635 static int extended_kbd
; /* 101 (102) keyboard present. */
2637 struct kbd_translate
{
2640 unsigned short code
;
2643 struct dos_keyboard_map
2648 struct kbd_translate
*translate_table
;
2652 static struct dos_keyboard_map us_keyboard
= {
2654 /* 01234567890123456789012345678901234567890 12345678901234 */
2655 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2656 /* 0123456789012345678901234567890123456789 012345678901234 */
2657 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2658 0, /* no Alt-Gr key */
2659 0 /* no translate table */
2662 static struct dos_keyboard_map fr_keyboard
= {
2664 /* 012 3456789012345678901234567890123456789012345678901234 */
2665 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2666 /* 0123456789012345678901234567890123456789012345678901234 */
2667 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2668 /* 01234567 89012345678901234567890123456789012345678901234 */
2670 0 /* no translate table */
2674 * Italian keyboard support, country code 39.
2677 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2678 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2681 static struct kbd_translate it_kbd_translate_table
[] = {
2682 { 0x56, 0x3c, Normal
| 13 },
2683 { 0x56, 0x3e, Normal
| 27 },
2686 static struct dos_keyboard_map it_keyboard
= {
2688 /* 0 123456789012345678901234567890123456789012345678901234 */
2689 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2690 /* 01 23456789012345678901234567890123456789012345678901234 */
2691 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2692 /* 0123456789012345678901234567890123456789012345678901234 */
2694 it_kbd_translate_table
2697 static struct dos_keyboard_map dk_keyboard
= {
2699 /* 0123456789012345678901234567890123456789012345678901234 */
2700 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2701 /* 01 23456789012345678901234567890123456789012345678901234 */
2702 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2703 /* 0123456789012345678901234567890123456789012345678901234 */
2705 0 /* no translate table */
2708 static struct kbd_translate jp_kbd_translate_table
[] = {
2709 { 0x73, 0x5c, Normal
| 0 },
2710 { 0x73, 0x5f, Normal
| 0 },
2711 { 0x73, 0x1c, Map
| 0 },
2712 { 0x7d, 0x5c, Normal
| 13 },
2713 { 0x7d, 0x7c, Normal
| 13 },
2714 { 0x7d, 0x1c, Map
| 13 },
2717 static struct dos_keyboard_map jp_keyboard
= {
2719 /* 0123456789012 345678901234567890123456789012345678901234 */
2720 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2721 /* 01 23456789012345678901234567890123456789012345678901234 */
2722 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2723 0, /* no Alt-Gr key */
2724 jp_kbd_translate_table
2727 static struct keyboard_layout_list
2730 struct dos_keyboard_map
*keyboard_map
;
2731 } keyboard_layout_list
[] =
2740 static struct dos_keyboard_map
*keyboard
;
2741 static int keyboard_map_all
;
2742 static int international_keyboard
;
2745 dos_set_keyboard (code
, always
)
2750 _go32_dpmi_registers regs
;
2752 /* See if Keyb.Com is installed (for international keyboard support).
2753 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2754 of Windows 9X! So don't do that! */
2756 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2757 _go32_dpmi_simulate_int (0x2f, ®s
);
2758 if (regs
.h
.al
== 0xff)
2759 international_keyboard
= 1;
2761 /* Initialize to US settings, for countries that don't have their own. */
2762 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2763 keyboard_map_all
= always
;
2764 dos_keyboard_layout
= 1;
2766 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2767 if (code
== keyboard_layout_list
[i
].country_code
)
2769 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2770 keyboard_map_all
= always
;
2771 dos_keyboard_layout
= code
;
2779 unsigned char char_code
; /* normal code */
2780 unsigned char meta_code
; /* M- code */
2781 unsigned char keypad_code
; /* keypad code */
2782 unsigned char editkey_code
; /* edit key */
2783 } keypad_translate_map
[] = {
2784 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2785 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2786 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2787 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2788 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2789 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2790 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2791 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2792 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2793 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2794 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2799 unsigned char char_code
; /* normal code */
2800 unsigned char keypad_code
; /* keypad code */
2801 } grey_key_translate_map
[] = {
2802 '/', 0xaf, /* kp-decimal */
2803 '*', 0xaa, /* kp-multiply */
2804 '-', 0xad, /* kp-subtract */
2805 '+', 0xab, /* kp-add */
2806 '\r', 0x8d /* kp-enter */
2809 static unsigned short
2810 ibmpc_translate_map
[] =
2812 /* --------------- 00 to 0f --------------- */
2813 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2814 Alt
| ModFct
| 0x1b, /* Escape */
2815 Normal
| 1, /* '1' */
2816 Normal
| 2, /* '2' */
2817 Normal
| 3, /* '3' */
2818 Normal
| 4, /* '4' */
2819 Normal
| 5, /* '5' */
2820 Normal
| 6, /* '6' */
2821 Normal
| 7, /* '7' */
2822 Normal
| 8, /* '8' */
2823 Normal
| 9, /* '9' */
2824 Normal
| 10, /* '0' */
2825 Normal
| 11, /* '-' */
2826 Normal
| 12, /* '=' */
2827 Special
| 0x08, /* Backspace */
2828 ModFct
| 0x74, /* Tab/Backtab */
2830 /* --------------- 10 to 1f --------------- */
2843 ModFct
| 0x0d, /* Return */
2848 /* --------------- 20 to 2f --------------- */
2857 Map
| 40, /* '\'' */
2859 Ignore
, /* Left shift */
2860 Map
| 41, /* '\\' */
2866 /* --------------- 30 to 3f --------------- */
2873 Ignore
, /* Right shift */
2874 Grey
| 1, /* Grey * */
2876 Normal
| 55, /* ' ' */
2877 Ignore
, /* Caps Lock */
2878 FctKey
| 0xbe, /* F1 */
2879 FctKey
| 0xbf, /* F2 */
2880 FctKey
| 0xc0, /* F3 */
2881 FctKey
| 0xc1, /* F4 */
2882 FctKey
| 0xc2, /* F5 */
2884 /* --------------- 40 to 4f --------------- */
2885 FctKey
| 0xc3, /* F6 */
2886 FctKey
| 0xc4, /* F7 */
2887 FctKey
| 0xc5, /* F8 */
2888 FctKey
| 0xc6, /* F9 */
2889 FctKey
| 0xc7, /* F10 */
2890 Ignore
, /* Num Lock */
2891 Ignore
, /* Scroll Lock */
2892 KeyPad
| 7, /* Home */
2893 KeyPad
| 8, /* Up */
2894 KeyPad
| 9, /* Page Up */
2895 Grey
| 2, /* Grey - */
2896 KeyPad
| 4, /* Left */
2897 KeyPad
| 5, /* Keypad 5 */
2898 KeyPad
| 6, /* Right */
2899 Grey
| 3, /* Grey + */
2900 KeyPad
| 1, /* End */
2902 /* --------------- 50 to 5f --------------- */
2903 KeyPad
| 2, /* Down */
2904 KeyPad
| 3, /* Page Down */
2905 KeyPad
| 0, /* Insert */
2906 KeyPad
| 10, /* Delete */
2907 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2908 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2909 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2910 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2911 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2912 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2913 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2914 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2915 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2916 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2917 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2918 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2920 /* --------------- 60 to 6f --------------- */
2921 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2922 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2923 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2924 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2925 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2926 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2927 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2928 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2929 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2930 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2931 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2932 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2933 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2934 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2935 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2936 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2938 /* --------------- 70 to 7f --------------- */
2939 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2940 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2941 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2942 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2943 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2944 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2945 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2946 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2947 Alt
| Map
| 1, /* '1' */
2948 Alt
| Map
| 2, /* '2' */
2949 Alt
| Map
| 3, /* '3' */
2950 Alt
| Map
| 4, /* '4' */
2951 Alt
| Map
| 5, /* '5' */
2952 Alt
| Map
| 6, /* '6' */
2953 Alt
| Map
| 7, /* '7' */
2954 Alt
| Map
| 8, /* '8' */
2956 /* --------------- 80 to 8f --------------- */
2957 Alt
| Map
| 9, /* '9' */
2958 Alt
| Map
| 10, /* '0' */
2959 Alt
| Map
| 11, /* '-' */
2960 Alt
| Map
| 12, /* '=' */
2961 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2962 FctKey
| 0xc8, /* F11 */
2963 FctKey
| 0xc9, /* F12 */
2964 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2965 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2966 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2967 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2968 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2969 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2970 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2971 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2972 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2974 /* --------------- 90 to 9f --------------- */
2975 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2976 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2977 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2978 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2979 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2980 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2981 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2982 Alt
| FctKey
| 0x50, /* (Alt) Home */
2983 Alt
| FctKey
| 0x52, /* (Alt) Up */
2984 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2985 Ignore
, /* NO KEY */
2986 Alt
| FctKey
| 0x51, /* (Alt) Left */
2987 Ignore
, /* NO KEY */
2988 Alt
| FctKey
| 0x53, /* (Alt) Right */
2989 Ignore
, /* NO KEY */
2990 Alt
| FctKey
| 0x57, /* (Alt) End */
2992 /* --------------- a0 to af --------------- */
2993 Alt
| KeyPad
| 2, /* (Alt) Down */
2994 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2995 Alt
| KeyPad
| 0, /* (Alt) Insert */
2996 Alt
| KeyPad
| 10, /* (Alt) Delete */
2997 Alt
| Grey
| 0, /* (Alt) Grey / */
2998 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2999 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
3002 /* These bit-positions corresponds to values returned by BIOS */
3003 #define SHIFT_P 0x0003 /* two bits! */
3004 #define CTRL_P 0x0004
3005 #define ALT_P 0x0008
3006 #define SCRLOCK_P 0x0010
3007 #define NUMLOCK_P 0x0020
3008 #define CAPSLOCK_P 0x0040
3009 #define ALT_GR_P 0x0800
3010 #define SUPER_P 0x4000 /* pseudo */
3011 #define HYPER_P 0x8000 /* pseudo */
3014 dos_get_modifiers (keymask
)
3018 int mask
, modifiers
= 0;
3020 /* Calculate modifier bits */
3021 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
3022 int86 (0x16, ®s
, ®s
);
3026 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
3027 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3031 mask
= regs
.h
.al
& (SHIFT_P
|
3032 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3034 /* Do not break international keyboard support. */
3035 /* When Keyb.Com is loaded, the right Alt key is */
3036 /* used for accessing characters like { and } */
3037 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
3040 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
3043 if (dos_hyper_key
== 1)
3046 modifiers
|= hyper_modifier
;
3048 else if (dos_super_key
== 1)
3051 modifiers
|= super_modifier
;
3053 else if (!international_keyboard
)
3055 /* If Keyb.Com is NOT installed, let Right Alt behave
3056 like the Left Alt. */
3062 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
3065 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
3067 if (dos_hyper_key
== 2)
3070 modifiers
|= hyper_modifier
;
3072 else if (dos_super_key
== 2)
3075 modifiers
|= super_modifier
;
3083 modifiers
|= shift_modifier
;
3085 modifiers
|= ctrl_modifier
;
3087 modifiers
|= meta_modifier
;
3094 #define NUM_RECENT_DOSKEYS (100)
3095 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
3096 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3097 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3099 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3100 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3101 Each input key receives two values in this vector: first the ASCII code,
3102 and then the scan code. */)
3105 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
3107 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3108 return Fvector (total_doskeys
, keys
);
3111 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3112 bcopy (keys
+ recent_doskeys_index
,
3113 XVECTOR (val
)->contents
,
3114 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3116 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3117 recent_doskeys_index
* sizeof (Lisp_Object
));
3122 /* Get a char from keyboard. Function keys are put into the event queue. */
3126 struct input_event event
;
3128 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3131 #ifndef HAVE_X_WINDOWS
3132 /* Maybe put the cursor where it should be. */
3133 IT_cmgoto (SELECTED_FRAME());
3136 /* The following condition is equivalent to `kbhit ()', except that
3137 it uses the bios to do its job. This pleases DESQview/X. */
3138 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3139 int86 (0x16, ®s
, ®s
),
3140 (regs
.x
.flags
& 0x40) == 0)
3143 register unsigned char c
;
3144 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
3146 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3147 int86 (0x16, ®s
, ®s
);
3152 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3154 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3155 recent_doskeys_index
= 0;
3156 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3158 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3159 recent_doskeys_index
= 0;
3161 modifiers
= dos_get_modifiers (&mask
);
3163 #ifndef HAVE_X_WINDOWS
3164 if (!NILP (Vdos_display_scancodes
))
3167 sprintf (buf
, "%02x:%02x*%04x",
3168 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3169 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3177 case 10: /* Ctrl Grey Enter */
3178 code
= Ctrl
| Grey
| 4;
3180 case 13: /* Grey Enter */
3183 case '/': /* Grey / */
3193 /* Try the keyboard-private translation table first. */
3194 if (keyboard
->translate_table
)
3196 struct kbd_translate
*p
= keyboard
->translate_table
;
3200 if (p
->sc
== sc
&& p
->ch
== c
)
3208 /* If the private table didn't translate it, use the general
3212 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3214 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3221 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3222 Emacs is ready to read a key. Therefore, if they press
3223 `Alt-x' when Emacs is busy, by the time we get to
3224 `dos_get_modifiers', they might have already released the
3225 Alt key, and Emacs gets just `x', which is BAD.
3226 However, for keys with the `Map' property set, the ASCII
3227 code returns zero iff Alt is pressed. So, when we DON'T
3228 have to support international_keyboard, we don't have to
3229 distinguish between the left and right Alt keys, and we
3230 can set the META modifier for any keys with the `Map'
3231 property if they return zero ASCII code (c = 0). */
3233 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3234 modifiers
|= meta_modifier
;
3236 modifiers
|= ctrl_modifier
;
3238 modifiers
|= shift_modifier
;
3241 switch (code
& 0xf000)
3244 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3246 c
= 0; /* Special */
3259 if (c
== 0) /* ctrl-break */
3261 return c
; /* ALT-nnn */
3263 if (!keyboard_map_all
)
3272 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3273 if (!keyboard_map_all
)
3277 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3278 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3282 code
= keyboard
->shifted
[code
];
3284 modifiers
&= ~shift_modifier
;
3287 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3288 code
= keyboard
->alt_gr
[code
];
3290 code
= keyboard
->unshifted
[code
];
3295 if (c
== 0xe0) /* edit key */
3298 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3299 kp_mode
= dos_keypad_mode
& 0x03;
3301 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3306 if (code
== 10 && dos_decimal_point
)
3307 return dos_decimal_point
;
3308 return keypad_translate_map
[code
].char_code
;
3311 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3315 code
= keypad_translate_map
[code
].meta_code
;
3316 modifiers
= meta_modifier
;
3320 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3327 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3328 if (dos_keypad_mode
& kp_mode
)
3329 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3331 code
= grey_key_translate_map
[code
].char_code
;
3339 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
3341 clear_mouse_face (dpyinfo
);
3342 dpyinfo
->mouse_face_hidden
= 1;
3346 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
3348 event
.kind
= ASCII_KEYSTROKE_EVENT
;
3350 event
.modifiers
= modifiers
;
3351 event
.frame_or_window
= selected_frame
;
3353 event
.timestamp
= event_timestamp ();
3354 kbd_buffer_store_event (&event
);
3357 if (have_mouse
> 0 && !mouse_preempted
)
3359 int but
, press
, x
, y
, ok
;
3360 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3361 Lisp_Object mouse_window
= Qnil
;
3363 /* Check for mouse movement *before* buttons. */
3364 mouse_check_moved ();
3366 /* If the mouse moved from the spot of its last sighting, we
3367 might need to update mouse highlight. */
3368 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3370 if (dpyinfo
->mouse_face_hidden
)
3372 dpyinfo
->mouse_face_hidden
= 0;
3373 clear_mouse_face (dpyinfo
);
3376 /* Generate SELECT_WINDOW_EVENTs when needed. */
3377 if (mouse_autoselect_window
)
3379 mouse_window
= window_from_coordinates (SELECTED_FRAME(),
3383 /* A window will be selected only when it is not
3384 selected now, and the last mouse movement event was
3385 not in it. A minibuffer window will be selected iff
3387 if (WINDOWP (mouse_window
)
3388 && !EQ (mouse_window
, last_mouse_window
)
3389 && !EQ (mouse_window
, selected_window
))
3391 event
.kind
= SELECT_WINDOW_EVENT
;
3392 event
.frame_or_window
= mouse_window
;
3394 event
.timestamp
= event_timestamp ();
3395 kbd_buffer_store_event (&event
);
3397 last_mouse_window
= mouse_window
;
3400 last_mouse_window
= Qnil
;
3402 previous_help_echo_string
= help_echo_string
;
3403 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
3405 IT_note_mouse_highlight (SELECTED_FRAME(),
3406 mouse_last_x
, mouse_last_y
);
3407 /* If the contents of the global variable help_echo has
3408 changed, generate a HELP_EVENT. */
3409 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
3411 event
.kind
= HELP_EVENT
;
3412 event
.frame_or_window
= selected_frame
;
3413 event
.arg
= help_echo_object
;
3414 event
.x
= WINDOWP (help_echo_window
)
3415 ? help_echo_window
: selected_frame
;
3416 event
.y
= help_echo_string
;
3417 event
.timestamp
= event_timestamp ();
3418 event
.code
= help_echo_pos
;
3419 kbd_buffer_store_event (&event
);
3423 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3424 for (press
= 0; press
< 2; press
++)
3426 int button_num
= but
;
3429 ok
= mouse_pressed (but
, &x
, &y
);
3431 ok
= mouse_released (but
, &x
, &y
);
3434 /* Allow a simultaneous press/release of Mouse-1 and
3435 Mouse-2 to simulate Mouse-3 on two-button mice. */
3436 if (mouse_button_count
== 2 && but
< 2)
3438 int x2
, y2
; /* don't clobber original coordinates */
3440 /* If only one button is pressed, wait 100 msec and
3441 check again. This way, Speedy Gonzales isn't
3442 punished, while the slow get their chance. */
3443 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3444 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3449 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3450 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3455 event
.kind
= MOUSE_CLICK_EVENT
;
3456 event
.code
= button_num
;
3457 event
.modifiers
= dos_get_modifiers (0)
3458 | (press
? down_modifier
: up_modifier
);
3459 event
.x
= make_number (x
);
3460 event
.y
= make_number (y
);
3461 event
.frame_or_window
= selected_frame
;
3463 event
.timestamp
= event_timestamp ();
3464 kbd_buffer_store_event (&event
);
3472 static int prev_get_char
= -1;
3474 /* Return 1 if a key is ready to be read without suspending execution. */
3478 if (prev_get_char
!= -1)
3481 return ((prev_get_char
= dos_rawgetc ()) != -1);
3484 /* Read a key. Return -1 if no key is ready. */
3488 if (prev_get_char
!= -1)
3490 int c
= prev_get_char
;
3495 return dos_rawgetc ();
3498 #ifndef HAVE_X_WINDOWS
3500 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3503 Actually, I don't know the meaning of all the parameters of the functions
3504 here -- I only know how they are called by xmenu.c. I could of course
3505 grab the nearest Xlib manual (down the hall, second-to-last door on the
3506 left), but I don't think it's worth the effort. */
3508 /* These hold text of the current and the previous menu help messages. */
3509 static char *menu_help_message
, *prev_menu_help_message
;
3510 /* Pane number and item number of the menu item which generated the
3511 last menu help message. */
3512 static int menu_help_paneno
, menu_help_itemno
;
3519 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3520 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3524 /* Allocate some (more) memory for MENU ensuring that there is room for one
3528 IT_menu_make_room (XMenu
*menu
)
3530 if (menu
->allocated
== 0)
3532 int count
= menu
->allocated
= 10;
3533 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3534 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3535 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3536 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3538 else if (menu
->allocated
== menu
->count
)
3540 int count
= menu
->allocated
= menu
->allocated
+ 10;
3542 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3544 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3546 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3548 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3552 /* Search the given menu structure for a given pane number. */
3555 IT_menu_search_pane (XMenu
*menu
, int pane
)
3560 for (i
= 0; i
< menu
->count
; i
++)
3561 if (menu
->submenu
[i
])
3563 if (pane
== menu
->panenumber
[i
])
3564 return menu
->submenu
[i
];
3565 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3571 /* Determine how much screen space a given menu needs. */
3574 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3576 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3579 maxheight
= menu
->count
;
3580 for (i
= 0; i
< menu
->count
; i
++)
3582 if (menu
->submenu
[i
])
3584 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3585 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3586 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3589 *width
= menu
->width
+ maxsubwidth
;
3590 *height
= maxheight
;
3593 /* Display MENU at (X,Y) using FACES. */
3596 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3598 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
3599 struct glyph
*text
, *p
;
3601 struct frame
*sf
= SELECTED_FRAME();
3603 menu_help_message
= NULL
;
3605 width
= menu
->width
;
3606 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3607 ScreenGetCursor (&row
, &col
);
3608 mouse_get_xy (&mx
, &my
);
3609 IT_update_begin (sf
);
3610 for (i
= 0; i
< menu
->count
; i
++)
3612 int max_width
= width
+ 2;
3614 IT_cursor_to (y
+ i
, x
);
3616 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3617 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3618 face
= faces
[enabled
+ mousehere
* 2];
3619 /* The following if clause means that we display the menu help
3620 strings even if the menu item is currently disabled. */
3621 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3623 menu_help_message
= menu
->help_text
[i
];
3624 menu_help_paneno
= pn
- 1;
3625 menu_help_itemno
= i
;
3628 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3630 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3634 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3637 else /* make '^x' */
3639 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3642 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3646 /* Don't let the menu text overflow into the next screen row. */
3647 if (x
+ max_width
> screen_size_X
)
3649 max_width
= screen_size_X
- x
;
3650 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3652 for (; j
< max_width
- 2; j
++, p
++)
3653 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3655 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3657 IT_write_glyphs (text
, max_width
);
3660 IT_cursor_to (row
, col
);
3664 /* --------------------------- X Menu emulation ---------------------- */
3666 /* Report availability of menus. */
3669 have_menus_p () { return 1; }
3671 /* Create a brand new menu structure. */
3674 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3676 return IT_menu_create ();
3679 /* Create a new pane and place it on the outer-most level. It is not
3680 clear that it should be placed out there, but I don't know what else
3684 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3692 IT_menu_make_room (menu
);
3693 menu
->submenu
[menu
->count
] = IT_menu_create ();
3694 menu
->text
[menu
->count
] = txt
;
3695 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3696 menu
->help_text
[menu
->count
] = NULL
;
3699 /* Adjust length for possible control characters (which will
3700 be written as ^x). */
3701 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3705 if (len
> menu
->width
)
3708 return menu
->panecount
;
3711 /* Create a new item in a menu pane. */
3714 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3715 int foo
, char *txt
, int enable
, char *help_text
)
3721 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3723 IT_menu_make_room (menu
);
3724 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3725 menu
->text
[menu
->count
] = txt
;
3726 menu
->panenumber
[menu
->count
] = enable
;
3727 menu
->help_text
[menu
->count
] = help_text
;
3730 /* Adjust length for possible control characters (which will
3731 be written as ^x). */
3732 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3736 if (len
> menu
->width
)
3742 /* Decide where the menu would be placed if requested at (X,Y). */
3745 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3746 int *ulx
, int *uly
, int *width
, int *height
)
3748 IT_menu_calc_size (menu
, width
, height
);
3754 struct IT_menu_state
3756 void *screen_behind
;
3763 /* Display menu, wait for user's response, and return that response. */
3766 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3767 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3768 void (*help_callback
)(char *, int, int))
3770 struct IT_menu_state
*state
;
3771 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3772 int title_faces
[4]; /* face to display the menu title */
3773 int faces
[4], buffers_num_deleted
= 0;
3774 struct frame
*sf
= SELECTED_FRAME();
3775 Lisp_Object saved_echo_area_message
, selectface
;
3777 /* Just in case we got here without a mouse present... */
3778 if (have_mouse
<= 0)
3779 return XM_IA_SELECT
;
3780 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3781 around the display. */
3787 /* We will process all the mouse events directly, so we had
3788 better prevent dos_rawgetc from stealing them from us. */
3791 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3792 screensize
= screen_size
* 2;
3794 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3795 0, DEFAULT_FACE_ID
);
3797 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3798 0, DEFAULT_FACE_ID
);
3799 selectface
= intern ("msdos-menu-select-face");
3800 faces
[2] = lookup_derived_face (sf
, selectface
,
3802 faces
[3] = lookup_derived_face (sf
, selectface
,
3805 /* Make sure the menu title is always displayed with
3806 `msdos-menu-active-face', no matter where the mouse pointer is. */
3807 for (i
= 0; i
< 4; i
++)
3808 title_faces
[i
] = faces
[3];
3812 /* Don't let the title for the "Buffers" popup menu include a
3813 digit (which is ugly).
3815 This is a terrible kludge, but I think the "Buffers" case is
3816 the only one where the title includes a number, so it doesn't
3817 seem to be necessary to make this more general. */
3818 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3820 menu
->text
[0][7] = '\0';
3821 buffers_num_deleted
= 1;
3824 /* We need to save the current echo area message, so that we could
3825 restore it below, before we exit. See the commentary below,
3826 before the call to message_with_string. */
3827 saved_echo_area_message
= Fcurrent_message ();
3828 state
[0].menu
= menu
;
3830 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3832 /* Turn off the cursor. Otherwise it shows through the menu
3833 panes, which is ugly. */
3834 IT_display_cursor (0);
3836 /* Display the menu title. */
3837 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3838 if (buffers_num_deleted
)
3839 menu
->text
[0][7] = ' ';
3840 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3842 menu
->width
= menu
->submenu
[0]->width
;
3843 state
[0].menu
= menu
->submenu
[0];
3847 state
[0].menu
= menu
;
3849 state
[0].x
= x0
- 1;
3851 state
[0].pane
= onepane
;
3853 mouse_last_x
= -1; /* A hack that forces display. */
3857 if (!mouse_visible
) mouse_on ();
3858 mouse_check_moved ();
3859 if (sf
->mouse_moved
)
3861 sf
->mouse_moved
= 0;
3862 result
= XM_IA_SELECT
;
3863 mouse_get_xy (&x
, &y
);
3864 for (i
= 0; i
< statecount
; i
++)
3865 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3867 int dy
= y
- state
[i
].y
;
3868 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3870 if (!state
[i
].menu
->submenu
[dy
])
3871 if (state
[i
].menu
->panenumber
[dy
])
3872 result
= XM_SUCCESS
;
3874 result
= XM_IA_SELECT
;
3875 *pane
= state
[i
].pane
- 1;
3877 /* We hit some part of a menu, so drop extra menus that
3878 have been opened. That does not include an open and
3880 if (i
!= statecount
- 2
3881 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3882 while (i
!= statecount
- 1)
3886 ScreenUpdate (state
[statecount
].screen_behind
);
3887 if (screen_virtual_segment
)
3888 dosv_refresh_virtual_screen (0, screen_size
);
3889 xfree (state
[statecount
].screen_behind
);
3891 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3893 IT_menu_display (state
[i
].menu
,
3898 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3899 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3901 ScreenRetrieve (state
[statecount
].screen_behind
3902 = xmalloc (screensize
));
3904 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3905 state
[statecount
].y
= y
;
3910 IT_menu_display (state
[statecount
- 1].menu
,
3911 state
[statecount
- 1].y
,
3912 state
[statecount
- 1].x
,
3913 state
[statecount
- 1].pane
,
3918 if ((menu_help_message
|| prev_menu_help_message
)
3919 && menu_help_message
!= prev_menu_help_message
)
3921 help_callback (menu_help_message
,
3922 menu_help_paneno
, menu_help_itemno
);
3923 IT_display_cursor (0);
3924 prev_menu_help_message
= menu_help_message
;
3926 /* We are busy-waiting for the mouse to move, so let's be nice
3927 to other Windows applications by releasing our time slice. */
3930 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3932 /* Only leave if user both pressed and released the mouse, and in
3933 that order. This avoids popping down the menu pane unless
3934 the user is really done with it. */
3935 if (mouse_pressed (b
, &x
, &y
))
3937 while (mouse_button_depressed (b
, &x
, &y
))
3941 (void) mouse_released (b
, &x
, &y
);
3946 ScreenUpdate (state
[0].screen_behind
);
3947 if (screen_virtual_segment
)
3948 dosv_refresh_virtual_screen (0, screen_size
);
3950 /* We have a situation here. ScreenUpdate has just restored the
3951 screen contents as it was before we started drawing this menu.
3952 That includes any echo area message that could have been
3953 displayed back then. (In reality, that echo area message will
3954 almost always be the ``keystroke echo'' that echoes the sequence
3955 of menu items chosen by the user.) However, if the menu had some
3956 help messages, then displaying those messages caused Emacs to
3957 forget about the original echo area message. So when
3958 ScreenUpdate restored it, it created a discrepancy between the
3959 actual screen contents and what Emacs internal data structures
3962 To avoid this conflict, we force Emacs to restore the original
3963 echo area message as we found it when we entered this function.
3964 The irony of this is that we then erase the restored message
3965 right away, so the only purpose of restoring it is so that
3966 erasing it works correctly... */
3967 if (! NILP (saved_echo_area_message
))
3968 message_with_string ("%s", saved_echo_area_message
, 0);
3970 while (statecount
--)
3971 xfree (state
[statecount
].screen_behind
);
3972 IT_display_cursor (1); /* turn cursor back on */
3973 /* Clean up any mouse events that are waiting inside Emacs event queue.
3974 These events are likely to be generated before the menu was even
3975 displayed, probably because the user pressed and released the button
3976 (which invoked the menu) too quickly. If we don't remove these events,
3977 Emacs will process them after we return and surprise the user. */
3978 discard_mouse_events ();
3979 mouse_clear_clicks ();
3980 if (!kbd_buffer_events_waiting (1))
3981 clear_input_pending ();
3982 /* Allow mouse events generation by dos_rawgetc. */
3987 /* Dispose of a menu. */
3990 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3993 if (menu
->allocated
)
3995 for (i
= 0; i
< menu
->count
; i
++)
3996 if (menu
->submenu
[i
])
3997 XMenuDestroy (foo
, menu
->submenu
[i
]);
3999 xfree (menu
->submenu
);
4000 xfree (menu
->panenumber
);
4001 xfree (menu
->help_text
);
4004 menu_help_message
= prev_menu_help_message
= NULL
;
4008 x_pixel_width (struct frame
*f
)
4010 return FRAME_COLS (f
);
4014 x_pixel_height (struct frame
*f
)
4016 return FRAME_LINES (f
);
4018 #endif /* !HAVE_X_WINDOWS */
4020 /* ----------------------- DOS / UNIX conversion --------------------- */
4022 void msdos_downcase_filename (unsigned char *);
4024 /* Destructively turn backslashes into slashes. */
4027 dostounix_filename (p
)
4030 msdos_downcase_filename (p
);
4040 /* Destructively turn slashes into backslashes. */
4043 unixtodos_filename (p
)
4046 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4060 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4063 getdefdir (drive
, dst
)
4067 char in_path
[4], *p
= in_path
, e
= errno
;;
4069 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4072 *p
++ = drive
+ 'A' - 1;
4079 _fixpath (in_path
, dst
);
4080 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4081 it queries the LFN support, so ignore that error. */
4082 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
4085 msdos_downcase_filename (dst
);
4092 emacs_root_dir (void)
4094 static char root_dir
[4];
4096 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
4097 root_dir
[0] = tolower (root_dir
[0]);
4101 /* Remove all CR's that are followed by a LF. */
4106 register unsigned char *buf
;
4108 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
4112 while (buf
< endp
- 1)
4116 if (*(++buf
) != 0x0a)
4127 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4129 /* In DJGPP v2.0, library `write' can call `malloc', which might
4130 cause relocation of the buffer whose address we get in ADDR.
4131 Here is a version of `write' that avoids calling `malloc',
4132 to serve us until such time as the library is fixed.
4133 Actually, what we define here is called `__write', because
4134 `write' is a stub that just jmp's to `__write' (to be
4135 POSIXLY-correct with respect to the global name-space). */
4137 #include <io.h> /* for _write */
4138 #include <libc/dosio.h> /* for __file_handle_modes[] */
4140 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4142 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4145 __write (int handle
, const void *buffer
, size_t count
)
4150 if(__file_handle_modes
[handle
] & O_BINARY
)
4151 return _write (handle
, buffer
, count
);
4155 const char *bp
= buffer
;
4156 int total_written
= 0;
4157 int nmoved
= 0, ncr
= 0;
4161 /* The next test makes sure there's space for at least 2 more
4162 characters in xbuf[], so both CR and LF can be put there. */
4174 if (xbp
>= XBUF_END
|| !count
)
4176 size_t to_write
= nmoved
+ ncr
;
4177 int written
= _write (handle
, xbuf
, to_write
);
4182 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4184 /* If some, but not all were written (disk full?), return
4185 an estimate of the total written bytes not counting CRs. */
4186 if (written
< to_write
)
4187 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4194 return total_written
;
4198 /* A low-level file-renaming function which works around Windows 95 bug.
4199 This is pulled directly out of DJGPP v2.01 library sources, and only
4200 used when you compile with DJGPP v2.0. */
4204 int _rename(const char *old
, const char *new)
4207 int olen
= strlen(old
) + 1;
4209 int use_lfn
= _USE_LFN
;
4210 char tempfile
[FILENAME_MAX
];
4211 const char *orig
= old
;
4214 r
.x
.dx
= __tb_offset
;
4215 r
.x
.di
= __tb_offset
+ olen
;
4216 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4220 /* Windows 95 bug: for some filenames, when you rename
4221 file -> file~ (as in Emacs, to leave a backup), the
4222 short 8+3 alias doesn't change, which effectively
4223 makes OLD and NEW the same file. We must rename
4224 through a temporary file to work around this. */
4226 char *pbase
= 0, *p
;
4227 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4228 int idx
= sizeof(try_char
) - 1;
4230 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4231 might point to another drive, which will fail the DOS call. */
4232 strcpy(tempfile
, old
);
4233 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4234 if (*p
== '/' || *p
== '\\' || *p
== ':')
4240 strcpy(pbase
, "X$$djren$$.$$temp$$");
4246 *pbase
= try_char
[--idx
];
4247 } while (_chmod(tempfile
, 0) != -1);
4250 _put_path2(tempfile
, olen
);
4252 __dpmi_int(0x21, &r
);
4255 errno
= __doserr_to_errno(r
.x
.ax
);
4259 /* Now create a file with the original name. This will
4260 ensure that NEW will always have a 8+3 alias
4261 different from that of OLD. (Seems to be required
4262 when NameNumericTail in the Registry is set to 0.) */
4263 lfn_fd
= _creat(old
, 0);
4265 olen
= strlen(tempfile
) + 1;
4267 r
.x
.di
= __tb_offset
+ olen
;
4276 _put_path2(new, olen
);
4278 __dpmi_int(0x21, &r
);
4281 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4282 remove(new); /* and try again */
4285 errno
= __doserr_to_errno(r
.x
.ax
);
4287 /* Restore to original name if we renamed it to temporary. */
4295 _put_path2(orig
, olen
);
4296 _put_path(tempfile
);
4298 __dpmi_int(0x21, &r
);
4307 /* Success. Delete the file possibly created to work
4308 around the Windows 95 bug. */
4310 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4314 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4316 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4318 doc
: /* Return non-nil if long file names are supported on MSDOS. */)
4321 return (_USE_LFN
? Qt
: Qnil
);
4324 /* Convert alphabetic characters in a filename to lower-case. */
4327 msdos_downcase_filename (p
)
4328 register unsigned char *p
;
4330 /* Always lower-case drive letters a-z, even if the filesystem
4331 preserves case in filenames.
4332 This is so MSDOS filenames could be compared by string comparison
4333 functions that are case-sensitive. Even case-preserving filesystems
4334 do not distinguish case in drive letters. */
4335 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4341 /* Under LFN we expect to get pathnames in their true case. */
4342 if (NILP (Fmsdos_long_file_names ()))
4344 if (*p
>= 'A' && *p
<= 'Z')
4348 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4350 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
4351 When long filenames are supported, doesn't change FILENAME.
4352 If FILENAME is not a string, returns nil.
4353 The argument object is never altered--the value is a copy. */)
4355 Lisp_Object filename
;
4359 if (! STRINGP (filename
))
4362 tem
= Fcopy_sequence (filename
);
4363 msdos_downcase_filename (SDATA (tem
));
4367 /* The Emacs root directory as determined by init_environment. */
4369 static char emacsroot
[MAXPATHLEN
];
4372 rootrelativepath (rel
)
4375 static char result
[MAXPATHLEN
+ 10];
4377 strcpy (result
, emacsroot
);
4378 strcat (result
, "/");
4379 strcat (result
, rel
);
4383 /* Define a lot of environment variables if not already defined. Don't
4384 remove anything unless you know what you're doing -- lots of code will
4385 break if one or more of these are missing. */
4388 init_environment (argc
, argv
, skip_args
)
4395 static const char * const tempdirs
[] = {
4396 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4398 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4400 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4401 temporary files and assume "/tmp" if $TMPDIR is unset, which
4402 will break on DOS/Windows. Refuse to work if we cannot find
4403 a directory, not even "c:/", usable for that purpose. */
4404 for (i
= 0; i
< imax
; i
++)
4406 const char *tmp
= tempdirs
[i
];
4407 char buf
[FILENAME_MAX
];
4413 tmp
= getenv (tmp
+ 1);
4417 /* Some lusers set TMPDIR=e:, probably because some losing
4418 programs cannot handle multiple slashes if they use e:/.
4419 e: fails in `access' below, so we interpret e: as e:/. */
4420 tmp_len
= strlen(tmp
);
4421 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
4424 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
4429 /* Note that `access' can lie to us if the directory resides on a
4430 read-only filesystem, like CD-ROM or a write-protected floppy.
4431 The only way to be really sure is to actually create a file and
4432 see if it succeeds. But I think that's too much to ask. */
4433 if (tmp
&& access (tmp
, D_OK
) == 0)
4435 setenv ("TMPDIR", tmp
, 1);
4442 Fcons (build_string ("no usable temporary directories found!!"),
4444 "While setting TMPDIR: ");
4446 /* Note the startup time, so we know not to clear the screen if we
4447 exit immediately; see IT_reset_terminal_modes.
4448 (Yes, I know `clock' returns zero the first time it's called, but
4449 I do this anyway, in case some wiseguy changes that at some point.) */
4450 startup_time
= clock ();
4452 /* Find our root from argv[0]. Assuming argv[0] is, say,
4453 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4454 root
= alloca (MAXPATHLEN
+ 20);
4455 _fixpath (argv
[0], root
);
4456 msdos_downcase_filename (root
);
4457 len
= strlen (root
);
4458 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4462 && (strcmp (root
+ len
- 4, "/bin") == 0
4463 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4464 root
[len
- 4] = '\0';
4466 strcpy (root
, "c:/emacs"); /* let's be defensive */
4467 len
= strlen (root
);
4468 strcpy (emacsroot
, root
);
4470 /* We default HOME to our root. */
4471 setenv ("HOME", root
, 0);
4473 /* We default EMACSPATH to root + "/bin". */
4474 strcpy (root
+ len
, "/bin");
4475 setenv ("EMACSPATH", root
, 0);
4477 /* I don't expect anybody to ever use other terminals so the internal
4478 terminal is the default. */
4479 setenv ("TERM", "internal", 0);
4481 #ifdef HAVE_X_WINDOWS
4482 /* Emacs expects DISPLAY to be set. */
4483 setenv ("DISPLAY", "unix:0.0", 0);
4486 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4487 downcase it and mirror the backslashes. */
4488 s
= getenv ("COMSPEC");
4489 if (!s
) s
= "c:/command.com";
4490 t
= alloca (strlen (s
) + 1);
4492 dostounix_filename (t
);
4493 setenv ("SHELL", t
, 0);
4495 /* PATH is also downcased and backslashes mirrored. */
4496 s
= getenv ("PATH");
4498 t
= alloca (strlen (s
) + 3);
4499 /* Current directory is always considered part of MsDos's path but it is
4500 not normally mentioned. Now it is. */
4501 strcat (strcpy (t
, ".;"), s
);
4502 dostounix_filename (t
); /* Not a single file name, but this should work. */
4503 setenv ("PATH", t
, 1);
4505 /* In some sense all dos users have root privileges, so... */
4506 setenv ("USER", "root", 0);
4507 setenv ("NAME", getenv ("USER"), 0);
4509 /* Time zone determined from country code. To make this possible, the
4510 country code may not span more than one time zone. In other words,
4511 in the USA, you lose. */
4513 switch (dos_country_code
)
4515 case 31: /* Belgium */
4516 case 32: /* The Netherlands */
4517 case 33: /* France */
4518 case 34: /* Spain */
4519 case 36: /* Hungary */
4520 case 38: /* Yugoslavia (or what's left of it?) */
4521 case 39: /* Italy */
4522 case 41: /* Switzerland */
4523 case 42: /* Tjekia */
4524 case 45: /* Denmark */
4525 case 46: /* Sweden */
4526 case 47: /* Norway */
4527 case 48: /* Poland */
4528 case 49: /* Germany */
4529 /* Daylight saving from last Sunday in March to last Sunday in
4530 September, both at 2AM. */
4531 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4533 case 44: /* United Kingdom */
4534 case 351: /* Portugal */
4535 case 354: /* Iceland */
4536 setenv ("TZ", "GMT+00", 0);
4538 case 81: /* Japan */
4539 case 82: /* Korea */
4540 setenv ("TZ", "JST-09", 0);
4542 case 90: /* Turkey */
4543 case 358: /* Finland */
4544 setenv ("TZ", "EET-02", 0);
4546 case 972: /* Israel */
4547 /* This is an approximation. (For exact rules, use the
4548 `zoneinfo/israel' file which comes with DJGPP, but you need
4549 to install it in `/usr/share/zoneinfo/' directory first.) */
4550 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4558 static int break_stat
; /* BREAK check mode status. */
4559 static int stdin_stat
; /* stdin IOCTL status. */
4563 /* These must be global. */
4564 static _go32_dpmi_seginfo ctrl_break_vector
;
4565 static _go32_dpmi_registers ctrl_break_regs
;
4566 static int ctrlbreakinstalled
= 0;
4568 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4571 ctrl_break_func (regs
)
4572 _go32_dpmi_registers
*regs
;
4578 install_ctrl_break_check ()
4580 if (!ctrlbreakinstalled
)
4582 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4583 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4584 ctrlbreakinstalled
= 1;
4585 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4586 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4588 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4592 #endif /* __DJGPP__ < 2 */
4594 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4595 control chars by DOS. Determine the keyboard type. */
4600 union REGS inregs
, outregs
;
4601 static int first_time
= 1;
4603 break_stat
= getcbrk ();
4606 install_ctrl_break_check ();
4612 int86 (0x15, &inregs
, &outregs
);
4613 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4617 if (internal_terminal
4618 #ifdef HAVE_X_WINDOWS
4619 && inhibit_window_system
4623 inregs
.x
.ax
= 0x0021;
4624 int86 (0x33, &inregs
, &outregs
);
4625 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4628 /* Reportedly, the above doesn't work for some mouse drivers. There
4629 is an additional detection method that should work, but might be
4630 a little slower. Use that as an alternative. */
4631 inregs
.x
.ax
= 0x0000;
4632 int86 (0x33, &inregs
, &outregs
);
4633 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4638 have_mouse
= 1; /* enable mouse */
4640 mouse_setup_buttons (outregs
.x
.bx
);
4641 mouse_position_hook
= &mouse_get_pos
;
4645 #ifndef HAVE_X_WINDOWS
4647 /* Save the cursor shape used outside Emacs. */
4648 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4657 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4658 return (stdin_stat
!= -1);
4661 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4663 #else /* __DJGPP__ < 2 */
4667 /* I think it is wrong to overwrite `stdin_stat' every time
4668 but the first one this function is called, but I don't
4669 want to change the way it used to work in v1.x.--EZ */
4671 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4672 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4673 intdos (&inregs
, &outregs
);
4674 stdin_stat
= outregs
.h
.dl
;
4676 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4677 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4678 intdos (&inregs
, &outregs
);
4679 return !outregs
.x
.cflag
;
4681 #endif /* __DJGPP__ < 2 */
4684 /* Restore status of standard input and Ctrl-C checking. */
4689 union REGS inregs
, outregs
;
4691 setcbrk (break_stat
);
4696 #ifndef HAVE_X_WINDOWS
4697 /* Restore the cursor shape we found on startup. */
4701 inregs
.x
.cx
= outside_cursor
;
4702 int86 (0x10, &inregs
, &outregs
);
4706 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4708 #else /* not __DJGPP__ >= 2 */
4710 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4711 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4712 inregs
.x
.dx
= stdin_stat
;
4713 intdos (&inregs
, &outregs
);
4714 return !outregs
.x
.cflag
;
4716 #endif /* not __DJGPP__ >= 2 */
4720 /* Run command as specified by ARGV in directory DIR.
4721 The command is run with input from TEMPIN, output to
4722 file TEMPOUT and stderr to TEMPERR. */
4725 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4726 unsigned char **argv
;
4727 const char *working_dir
;
4728 int tempin
, tempout
, temperr
;
4731 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4732 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4733 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
4736 /* Get current directory as MSDOS cwd is not per-process. */
4739 /* If argv[0] is the shell, it might come in any lettercase.
4740 Since `Fmember' is case-sensitive, we need to downcase
4741 argv[0], even if we are on case-preserving filesystems. */
4742 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4743 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4746 if (*pl
>= 'A' && *pl
<= 'Z')
4751 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4752 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4753 && !strcmp ("-c", argv
[1]);
4756 saveargv1
= argv
[1];
4757 saveargv2
= argv
[2];
4759 /* We only need to mirror slashes if a DOS shell will be invoked
4760 not via `system' (which does the mirroring itself). Yes, that
4761 means DJGPP v1.x will lose here. */
4762 if (argv
[2] && argv
[3])
4764 char *p
= alloca (strlen (argv
[2]) + 1);
4766 strcpy (argv
[2] = p
, saveargv2
);
4767 while (*p
&& isspace (*p
))
4779 chdir (working_dir
);
4783 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4784 goto done
; /* Allocation might fail due to lack of descriptors. */
4787 mouse_get_xy (&x
, &y
);
4789 dos_ttcooked (); /* do it here while 0 = stdin */
4797 if (msshell
&& !argv
[3])
4799 /* MS-DOS native shells are too restrictive. For starters, they
4800 cannot grok commands longer than 126 characters. In DJGPP v2
4801 and later, `system' is much smarter, so we'll call it instead. */
4805 /* A shell gets a single argument--its full command
4806 line--whose original was saved in `saveargv2'. */
4808 /* Don't let them pass empty command lines to `system', since
4809 with some shells it will try to invoke an interactive shell,
4810 which will hang Emacs. */
4811 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4815 extern char **environ
;
4816 char **save_env
= environ
;
4817 int save_system_flags
= __system_flags
;
4819 /* Request the most powerful version of `system'. We need
4820 all the help we can get to avoid calling stock DOS shells. */
4821 __system_flags
= (__system_redirect
4822 | __system_use_shell
4823 | __system_allow_multiple_cmds
4824 | __system_allow_long_cmds
4825 | __system_handle_null_commands
4826 | __system_emulate_chdir
);
4829 result
= system (cmnd
);
4830 __system_flags
= save_system_flags
;
4834 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4838 #endif /* __DJGPP__ > 1 */
4840 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4845 emacs_close (inbak
);
4846 emacs_close (outbak
);
4847 emacs_close (errbak
);
4853 mouse_moveto (x
, y
);
4856 /* Some programs might change the meaning of the highest bit of the
4857 text attribute byte, so we get blinking characters instead of the
4858 bright background colors. Restore that. */
4865 argv
[1] = saveargv1
;
4866 argv
[2] = saveargv2
;
4875 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4882 /* ------------------------- Compatibility functions -------------------
4887 /* Hostnames for a pc are not really funny,
4888 but they are used in change log so we emulate the best we can. */
4890 gethostname (p
, size
)
4894 char *q
= egetenv ("HOSTNAME");
4901 /* When time zones are set from Ms-Dos too many C-libraries are playing
4902 tricks with time values. We solve this by defining our own version
4903 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4904 once and after each call to `tzset' with TZ changed. That is
4905 accomplished by aliasing tzset to init_gettimeofday. */
4907 static struct tm time_rec
;
4910 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4918 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4922 time_rec
.tm_year
= d
.da_year
- 1900;
4923 time_rec
.tm_mon
= d
.da_mon
- 1;
4924 time_rec
.tm_mday
= d
.da_day
;
4927 time_rec
.tm_hour
= t
.ti_hour
;
4928 time_rec
.tm_min
= t
.ti_min
;
4929 time_rec
.tm_sec
= t
.ti_sec
;
4932 tm
.tm_gmtoff
= dos_timezone_offset
;
4934 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4935 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4937 /* Ignore tzp; it's obsolescent. */
4941 #endif /* __DJGPP__ < 2 */
4944 * A list of unimplemented functions that we silently ignore.
4948 unsigned alarm (s
) unsigned s
; {}
4949 fork () { return 0; }
4950 int kill (x
, y
) int x
, y
; { return -1; }
4952 void volatile pause () {}
4953 sigsetmask (x
) int x
; { return 0; }
4954 sigblock (mask
) int mask
; { return 0; }
4957 void request_sigio (void) {}
4958 setpgrp () {return 0; }
4959 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4960 void unrequest_sigio (void) {}
4963 #if __DJGPP_MINOR__ < 2
4965 #ifdef POSIX_SIGNALS
4967 /* Augment DJGPP library POSIX signal functions. This is needed
4968 as of DJGPP v2.01, but might be in the library in later releases. */
4970 #include <libc/bss.h>
4972 /* A counter to know when to re-initialize the static sets. */
4973 static int sigprocmask_count
= -1;
4975 /* Which signals are currently blocked (initially none). */
4976 static sigset_t current_mask
;
4978 /* Which signals are pending (initially none). */
4979 static sigset_t pending_signals
;
4981 /* Previous handlers to restore when the blocked signals are unblocked. */
4982 typedef void (*sighandler_t
)(int);
4983 static sighandler_t prev_handlers
[320];
4985 /* A signal handler which just records that a signal occurred
4986 (it will be raised later, if and when the signal is unblocked). */
4988 sig_suspender (signo
)
4991 sigaddset (&pending_signals
, signo
);
4995 sigprocmask (how
, new_set
, old_set
)
4997 const sigset_t
*new_set
;
5003 /* If called for the first time, initialize. */
5004 if (sigprocmask_count
!= __bss_count
)
5006 sigprocmask_count
= __bss_count
;
5007 sigemptyset (&pending_signals
);
5008 sigemptyset (¤t_mask
);
5009 for (signo
= 0; signo
< 320; signo
++)
5010 prev_handlers
[signo
] = SIG_ERR
;
5014 *old_set
= current_mask
;
5019 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
5025 sigemptyset (&new_mask
);
5027 /* DJGPP supports upto 320 signals. */
5028 for (signo
= 0; signo
< 320; signo
++)
5030 if (sigismember (¤t_mask
, signo
))
5031 sigaddset (&new_mask
, signo
);
5032 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
5034 sigaddset (&new_mask
, signo
);
5036 /* SIGKILL is silently ignored, as on other platforms. */
5037 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
5038 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
5040 if (( how
== SIG_UNBLOCK
5041 && sigismember (&new_mask
, signo
)
5042 && sigismember (new_set
, signo
))
5043 || (how
== SIG_SETMASK
5044 && sigismember (&new_mask
, signo
)
5045 && !sigismember (new_set
, signo
)))
5047 sigdelset (&new_mask
, signo
);
5048 if (prev_handlers
[signo
] != SIG_ERR
)
5050 signal (signo
, prev_handlers
[signo
]);
5051 prev_handlers
[signo
] = SIG_ERR
;
5053 if (sigismember (&pending_signals
, signo
))
5055 sigdelset (&pending_signals
, signo
);
5060 current_mask
= new_mask
;
5064 #else /* not POSIX_SIGNALS */
5066 sigsetmask (x
) int x
; { return 0; }
5067 sigblock (mask
) int mask
; { return 0; }
5069 #endif /* not POSIX_SIGNALS */
5070 #endif /* not __DJGPP_MINOR__ < 2 */
5071 #endif /* __DJGPP__ > 1 */
5074 #include "sysselect.h"
5076 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5077 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5078 ((long)(time).tv_sec < 0 \
5079 || ((time).tv_sec == 0 \
5080 && (long)(time).tv_usec <= 0))
5083 /* This yields the rest of the current time slice to the task manager.
5084 It should be called by any code which knows that it has nothing
5085 useful to do except idle.
5087 I don't use __dpmi_yield here, since versions of library before 2.02
5088 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5089 on some versions of Windows 9X. */
5092 dos_yield_time_slice (void)
5094 _go32_dpmi_registers r
;
5097 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
5098 _go32_dpmi_simulate_int (0x2f, &r
);
5103 /* Only event queue is checked. */
5104 /* We don't have to call timer_check here
5105 because wait_reading_process_input takes care of that. */
5107 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5109 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5110 EMACS_TIME
*timeout
;
5118 check_input
= FD_ISSET (0, rfds
);
5129 /* If we are looking only for the terminal, with no timeout,
5130 just read it and wait -- that's more efficient. */
5133 while (!detect_input_pending ())
5135 dos_yield_time_slice ();
5140 EMACS_TIME clnow
, cllast
, cldiff
;
5143 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5145 while (!check_input
|| !detect_input_pending ())
5148 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5149 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5151 /* When seconds wrap around, we assume that no more than
5152 1 minute passed since last `gettime'. */
5153 if (EMACS_TIME_NEG_P (cldiff
))
5154 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5155 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5157 /* Stop when timeout value crosses zero. */
5158 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5161 dos_yield_time_slice ();
5171 * Define overlaid functions:
5173 * chdir -> sys_chdir
5174 * tzset -> init_gettimeofday
5175 * abort -> dos_abort
5180 extern int chdir ();
5186 int len
= strlen (path
);
5187 char *tmp
= (char *)path
;
5189 if (*tmp
&& tmp
[1] == ':')
5191 if (getdisk () != tolower (tmp
[0]) - 'a')
5192 setdisk (tolower (tmp
[0]) - 'a');
5193 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5197 if (len
> 1 && (tmp
[len
- 1] == '/'))
5199 char *tmp1
= (char *) alloca (len
+ 1);
5210 extern void tzset (void);
5213 init_gettimeofday ()
5219 ltm
= gtm
= time (NULL
);
5220 ltm
= mktime (lstm
= localtime (<m
));
5221 gtm
= mktime (gmtime (>m
));
5222 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5223 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5224 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5231 dos_abort (file
, line
)
5235 char buffer1
[200], buffer2
[400];
5238 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5239 for (i
= j
= 0; buffer1
[i
]; i
++) {
5240 buffer2
[j
++] = buffer1
[i
];
5241 buffer2
[j
++] = 0x70;
5243 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5244 ScreenSetCursor (2, 0);
5252 ScreenSetCursor (10, 0);
5253 cputs ("\r\n\nEmacs aborted!\r\n");
5255 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5256 if (screen_virtual_segment
)
5257 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5258 /* Generate traceback, so we could tell whodunit. */
5259 signal (SIGINT
, SIG_DFL
);
5260 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5261 #else /* __DJGPP_MINOR__ >= 2 */
5263 #endif /* __DJGPP_MINOR__ >= 2 */
5269 /* The following variables are required so that cus-start.el won't
5270 complain about unbound variables. */
5271 #ifndef subprocesses
5272 /* Nonzero means delete a process right away if it exits (process.c). */
5273 static int delete_exited_processes
;
5278 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5279 staticpro (&recent_doskeys
);
5281 #ifndef HAVE_X_WINDOWS
5283 /* The following two are from xfns.c: */
5284 Qreverse
= intern ("reverse");
5285 staticpro (&Qreverse
);
5287 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5288 doc
: /* *Glyph to display instead of chars not supported by current codepage.
5289 This variable is used only by MSDOS terminals. */);
5290 Vdos_unsupported_char_glyph
= make_number ('\177');
5293 #ifndef subprocesses
5294 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5295 doc
: /* *Non-nil means delete processes immediately when they exit.
5296 nil means don't delete them until `list-processes' is run. */);
5297 delete_exited_processes
= 0;
5300 defsubr (&Srecent_doskeys
);
5301 defsubr (&Smsdos_long_file_names
);
5302 defsubr (&Smsdos_downcase_filename
);
5303 defsubr (&Smsdos_remember_default_colors
);
5304 defsubr (&Smsdos_set_mouse_buttons
);
5309 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5310 (do not change this comment) */