1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
33 #include <sys/param.h>
37 #include <string.h> /* for bzero and string functions */
38 #include <sys/stat.h> /* for _fixpath */
39 #include <unistd.h> /* for chdir, dup, dup2, etc. */
40 #include <dir.h> /* for getdisk */
42 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
44 #include <io.h> /* for setmode */
45 #include <dpmi.h> /* for __dpmi_xxx stuff */
46 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
47 #include <libc/dosio.h> /* for _USE_LFN */
48 #include <conio.h> /* for cputs */
54 #include "termhooks.h"
56 #include "dispextern.h"
59 #include "character.h"
65 #include "blockinput.h"
67 #include "intervals.h"
71 /* #include <process.h> */
72 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
80 #define _dos_ds _go32_info_block.selector_for_linear_memory
86 #include "syssignal.h"
92 /* If other `malloc' than ours is used, force our `sbrk' behave like
93 Unix programs expect (resize memory blocks to keep them contiguous).
94 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
95 because that's what `gmalloc' expects to get. */
99 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
100 #else /* not REL_ALLOC */
101 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
102 #endif /* not REL_ALLOC */
103 #endif /* GNU_MALLOC */
105 #endif /* not SYSTEM_MALLOC */
106 #endif /* __DJGPP__ > 1 */
125 /* ------------------------ Mouse control ---------------------------
127 * Coordinates are in screen positions and zero based.
128 * Mouse buttons are numbered from left to right and also zero based.
131 /* This used to be in termhooks.h, but mainstream Emacs code no longer
132 uses it, and it was removed... */
133 #define NUM_MOUSE_BUTTONS (5)
135 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
136 static int mouse_visible
;
138 static int mouse_last_x
;
139 static int mouse_last_y
;
141 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
142 static int mouse_button_count
;
149 if (have_mouse
> 0 && !mouse_visible
)
151 struct tty_display_info
*tty
= CURTTY ();
154 fprintf (tty
->termscript
, "<M_ON>");
156 int86 (0x33, ®s
, ®s
);
166 if (have_mouse
> 0 && mouse_visible
)
168 struct tty_display_info
*tty
= CURTTY ();
171 fprintf (tty
->termscript
, "<M_OFF>");
173 int86 (0x33, ®s
, ®s
);
179 mouse_setup_buttons (int n_buttons
)
183 mouse_button_count
= 3;
184 mouse_button_translate
[0] = 0; /* Left */
185 mouse_button_translate
[1] = 2; /* Middle */
186 mouse_button_translate
[2] = 1; /* Right */
188 else /* two, what else? */
190 mouse_button_count
= 2;
191 mouse_button_translate
[0] = 0;
192 mouse_button_translate
[1] = 1;
196 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
197 1, 1, "NSet number of mouse buttons to: ",
198 doc
: /* Set the number of mouse buttons to use by Emacs.
199 This is useful with mice that report the number of buttons inconsistently,
200 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
201 them. This happens with wheeled mice on Windows 9X, for example. */)
203 Lisp_Object nbuttons
;
207 CHECK_NUMBER (nbuttons
);
210 xsignal2 (Qargs_out_of_range
,
211 build_string ("only 2 or 3 mouse buttons are supported"),
213 mouse_setup_buttons (n
);
218 mouse_get_xy (int *x
, int *y
)
223 int86 (0x33, ®s
, ®s
);
233 struct tty_display_info
*tty
= CURTTY ();
236 fprintf (tty
->termscript
, "<M_XY=%dx%d>", x
, y
);
238 mouse_last_x
= regs
.x
.cx
= x
* 8;
239 mouse_last_y
= regs
.x
.dx
= y
* 8;
240 int86 (0x33, ®s
, ®s
);
244 mouse_pressed (b
, xp
, yp
)
249 if (b
>= mouse_button_count
)
252 regs
.x
.bx
= mouse_button_translate
[b
];
253 int86 (0x33, ®s
, ®s
);
255 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
256 return (regs
.x
.bx
!= 0);
260 mouse_released (b
, xp
, yp
)
265 if (b
>= mouse_button_count
)
268 regs
.x
.bx
= mouse_button_translate
[b
];
269 int86 (0x33, ®s
, ®s
);
271 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
272 return (regs
.x
.bx
!= 0);
276 mouse_button_depressed (b
, xp
, yp
)
281 if (b
>= mouse_button_count
)
284 int86 (0x33, ®s
, ®s
);
285 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
295 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
298 Lisp_Object
*bar_window
, *x
, *y
;
299 enum scroll_bar_part
*part
;
303 Lisp_Object frame
, tail
;
305 /* Clear the mouse-moved flag for every frame on this display. */
306 FOR_EACH_FRAME (tail
, frame
)
307 XFRAME (frame
)->mouse_moved
= 0;
309 *f
= SELECTED_FRAME();
311 mouse_get_xy (&ix
, &iy
);
312 *time
= event_timestamp ();
313 *x
= make_number (mouse_last_x
= ix
);
314 *y
= make_number (mouse_last_y
= iy
);
322 mouse_get_xy (&x
, &y
);
323 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
328 /* Force the mouse driver to ``forget'' about any button clicks until
331 mouse_clear_clicks (void)
335 for (b
= 0; b
< mouse_button_count
; b
++)
337 int dummy_x
, dummy_y
;
339 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
340 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
348 struct tty_display_info
*tty
= CURTTY ();
351 fprintf (tty
->termscript
, "<M_INIT>");
354 int86 (0x33, ®s
, ®s
);
356 /* Reset the mouse last press/release info. It seems that Windows
357 doesn't do that automatically when function 21h is called, which
358 causes Emacs to ``remember'' the click that switched focus to the
359 window just before Emacs was started from that window. */
360 mouse_clear_clicks ();
364 regs
.x
.dx
= 8 * (ScreenCols () - 1);
365 int86 (0x33, ®s
, ®s
);
369 regs
.x
.dx
= 8 * (ScreenRows () - 1);
370 int86 (0x33, ®s
, ®s
);
376 /* ------------------------- Screen control ----------------------
380 static int internal_terminal
= 0;
382 #ifndef HAVE_X_WINDOWS
383 extern unsigned char ScreenAttrib
;
384 static int screen_face
;
386 static int screen_size_X
;
387 static int screen_size_Y
;
388 static int screen_size
;
390 static int current_pos_X
;
391 static int current_pos_Y
;
392 static int new_pos_X
;
393 static int new_pos_Y
;
395 static void *startup_screen_buffer
;
396 static int startup_screen_size_X
;
397 static int startup_screen_size_Y
;
398 static int startup_pos_X
;
399 static int startup_pos_Y
;
400 static unsigned char startup_screen_attrib
;
402 static clock_t startup_time
;
404 static int term_setup_done
;
406 static unsigned short outside_cursor
;
408 /* Similar to the_only_frame. */
409 struct tty_display_info the_only_display_info
;
411 /* Support for DOS/V (allows Japanese characters to be displayed on
412 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
414 /* Holds the address of the text-mode screen buffer. */
415 static unsigned long screen_old_address
= 0;
416 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
417 static unsigned short screen_virtual_segment
= 0;
418 static unsigned short screen_virtual_offset
= 0;
419 /* A flag to control how to display unibyte 8-bit characters. */
420 extern int unibyte_display_via_language_environment
;
422 extern Lisp_Object Qcursor_type
;
423 extern Lisp_Object Qbar
, Qhbar
;
425 /* The screen colors of the current frame, which serve as the default
426 colors for newly-created frames. */
427 static int initial_screen_colors
[2];
430 /* Update the screen from a part of relocated DOS/V screen buffer which
431 begins at OFFSET and includes COUNT characters. */
433 dosv_refresh_virtual_screen (int offset
, int count
)
437 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
440 regs
.h
.ah
= 0xff; /* update relocated screen */
441 regs
.x
.es
= screen_virtual_segment
;
442 regs
.x
.di
= screen_virtual_offset
+ offset
;
444 __dpmi_int (0x10, ®s
);
449 dos_direct_output (y
, x
, buf
, len
)
454 int t0
= 2 * (x
+ y
* screen_size_X
);
455 int t
= t0
+ (int) ScreenPrimary
;
460 dosmemput (buf
++, 1, t
);
464 /* This is faster. */
465 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
466 _farnspokeb (t
, *buf
);
468 if (screen_virtual_segment
)
469 dosv_refresh_virtual_screen (t0
, l0
);
474 /* Flash the screen as a substitute for BEEPs. */
478 do_visible_bell (xorattr
)
479 unsigned char xorattr
;
484 movl _ScreenPrimary,%%eax \n\
491 xorb %%al,%%gs:(%%ebx) \n\
494 jne visible_bell_1 \n\
496 jne visible_bell_3 \n\
498 movzwl %%ax,%%eax \n\
499 movzwl %%ax,%%eax \n\
500 movzwl %%ax,%%eax \n\
501 movzwl %%ax,%%eax \n\
503 jne visible_bell_2 \n\
504 jmp visible_bell_0 \n\
507 : "m" (xorattr
), "g" (screen_size
)
508 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
512 ScreenVisualBell (void)
514 /* This creates an xor-mask that will swap the default fore- and
515 background colors. */
516 do_visible_bell (((FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ())
517 ^ FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()))
522 #ifndef HAVE_X_WINDOWS
524 static int blink_bit
= -1; /* the state of the blink bit at startup */
526 /* Enable bright background colors. */
532 /* Remember the original state of the blink/bright-background bit.
533 It is stored at 0040:0065h in the BIOS data area. */
535 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
539 int86 (0x10, ®s
, ®s
);
542 /* Disable bright background colors (and enable blinking) if we found
543 the video system in that state at startup. */
545 maybe_enable_blinking (void)
553 int86 (0x10, ®s
, ®s
);
557 /* Return non-zero if the system has a VGA adapter. */
564 int86 (0x10, ®s
, ®s
);
565 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
570 /* Set the screen dimensions so that it can show no less than
571 ROWS x COLS frame. */
574 dos_set_window_size (rows
, cols
)
579 Lisp_Object video_mode
;
580 int video_mode_value
, have_vga
= 0;
581 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
583 if (*rows
== current_rows
&& *cols
== current_cols
)
587 have_vga
= vga_installed ();
589 /* If the user specified a special video mode for these dimensions,
591 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
592 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
595 if (INTEGERP (video_mode
)
596 && (video_mode_value
= XINT (video_mode
)) > 0)
598 regs
.x
.ax
= video_mode_value
;
599 int86 (0x10, ®s
, ®s
);
603 /* Must hardware-reset the mouse, or else it won't update
604 its notion of screen dimensions for some non-standard
605 video modes. This is *painfully* slow... */
607 int86 (0x33, ®s
, ®s
);
611 /* Find one of the dimensions supported by standard EGA/VGA
612 which gives us at least the required dimensions. */
620 } std_dimension
[] = {
630 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
632 if (std_dimension
[i
].need_vga
<= have_vga
633 && std_dimension
[i
].rows
>= *rows
)
635 if (std_dimension
[i
].rows
!= current_rows
636 || *cols
!= current_cols
)
637 _set_screen_lines (std_dimension
[i
].rows
);
644 #else /* not __DJGPP__ > 1 */
646 else if (*rows
<= 25)
648 if (current_rows
!= 25 || current_cols
!= 80)
651 int86 (0x10, ®s
, ®s
);
654 int86 (0x10, ®s
, ®s
);
657 int86 (0x10, ®s
, ®s
);
659 int86 (0x10, ®s
, ®s
);
662 else if (*rows
<= 50)
663 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
664 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
667 int86 (0x10, ®s
, ®s
);
670 int86 (0x10, ®s
, ®s
);
673 int86 (0x10, ®s
, ®s
);
676 int86 (0x10, ®s
, ®s
);
678 #endif /* not __DJGPP__ > 1 */
686 /* Tell the caller what dimensions have been REALLY set. */
687 *rows
= ScreenRows ();
688 *cols
= ScreenCols ();
690 /* Update Emacs' notion of screen dimensions. */
691 screen_size_X
= *cols
;
692 screen_size_Y
= *rows
;
693 screen_size
= *cols
* *rows
;
696 /* If the dimensions changed, the mouse highlight info is invalid. */
697 if (current_rows
!= *rows
|| current_cols
!= *cols
)
699 struct frame
*f
= SELECTED_FRAME();
700 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
701 Lisp_Object window
= dpyinfo
->mouse_face_window
;
703 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
705 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
706 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
707 dpyinfo
->mouse_face_window
= Qnil
;
712 /* Enable bright background colors. */
715 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
716 be defensive anyway. */
717 if (screen_virtual_segment
)
718 dosv_refresh_virtual_screen (0, *cols
* *rows
);
721 /* If we write a character in the position where the mouse is,
722 the mouse cursor may need to be refreshed. */
732 mouse_get_xy (&x
, &y
);
733 if (y
!= new_pos_Y
|| x
< new_pos_X
)
739 #define DEFAULT_CURSOR_START (-1)
740 #define DEFAULT_CURSOR_WIDTH (-1)
741 #define BOX_CURSOR_WIDTH (-32)
743 /* Set cursor to begin at scan line START_LINE in the character cell
744 and extend for WIDTH scan lines. Scan lines are counted from top
745 of the character cell, starting from zero. */
747 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
750 unsigned desired_cursor
;
752 int max_line
, top_line
, bot_line
;
753 struct tty_display_info
*tty
= FRAME_TTY (f
);
755 /* Avoid the costly BIOS call if F isn't the currently selected
756 frame. Allow for NULL as unconditionally meaning the selected
758 if (f
&& f
!= SELECTED_FRAME())
762 fprintf (tty
->termscript
, "\nCURSOR SHAPE=(%d,%d)", start_line
, width
);
764 /* The character cell size in scan lines is stored at 40:85 in the
766 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
769 default: /* this relies on CGA cursor emulation being ON! */
786 if (width
== BOX_CURSOR_WIDTH
)
791 else if (start_line
!= DEFAULT_CURSOR_START
)
793 top_line
= start_line
;
794 bot_line
= top_line
- width
- 1;
796 else if (width
!= DEFAULT_CURSOR_WIDTH
)
799 bot_line
= -1 - width
;
802 top_line
= bot_line
+ 1;
806 /* [31, 0] seems to DTRT for all screen sizes. */
810 else /* WIDTH is positive */
812 if (start_line
!= DEFAULT_CURSOR_START
)
813 bot_line
= start_line
;
814 top_line
= bot_line
- (width
- 1);
817 /* If the current cursor shape is already what they want, we are
819 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
820 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
824 regs
.x
.cx
= desired_cursor
;
825 __dpmi_int (0x10, ®s
);
826 #endif /* __DJGPP__ > 1 */
830 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
832 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
834 /* Just BAR means the normal EGA/VGA cursor. */
835 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
837 else if (CONSP (cursor_type
)
838 && (EQ (XCAR (cursor_type
), Qbar
)
839 || EQ (XCAR (cursor_type
), Qhbar
)))
841 Lisp_Object bar_parms
= XCDR (cursor_type
);
844 if (INTEGERP (bar_parms
))
846 /* Feature: negative WIDTH means cursor at the top
847 of the character cell, zero means invisible cursor. */
848 width
= XINT (bar_parms
);
849 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
852 else if (CONSP (bar_parms
)
853 && INTEGERP (XCAR (bar_parms
))
854 && INTEGERP (XCDR (bar_parms
)))
856 int start_line
= XINT (XCDR (bar_parms
));
858 width
= XINT (XCAR (bar_parms
));
859 msdos_set_cursor_shape (f
, start_line
, width
);
864 /* Treat anything unknown as "box cursor". This includes nil, so
865 that a frame which doesn't specify a cursor type gets a box,
866 which is the default in Emacs. */
867 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
872 IT_ring_bell (struct frame
*f
)
881 union REGS inregs
, outregs
;
884 intdos (&inregs
, &outregs
);
888 /* Given a face id FACE, extract the face parameters to be used for
889 display until the face changes. The face parameters (actually, its
890 color) are used to construct the video attribute byte for each
891 glyph during the construction of the buffer that is then blitted to
894 IT_set_face (int face
)
896 struct frame
*sf
= SELECTED_FRAME();
897 struct face
*fp
= FACE_FROM_ID (sf
, face
);
898 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
899 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
900 struct tty_display_info
*tty
= FRAME_TTY (sf
);
905 /* The default face for the frame should always be realized and
913 dflt_fg
= dfp
->foreground
;
914 dflt_bg
= dfp
->background
;
916 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
917 mean use the colors of the default face. Note that we assume all
918 16 colors to be available for the background, since Emacs switches
919 on this mode (and loses the blinking attribute) at startup. */
920 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
921 fg
= FRAME_FOREGROUND_PIXEL (sf
);
922 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
923 fg
= FRAME_BACKGROUND_PIXEL (sf
);
924 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
925 bg
= FRAME_BACKGROUND_PIXEL (sf
);
926 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
927 bg
= FRAME_FOREGROUND_PIXEL (sf
);
929 /* Make sure highlighted lines really stand out, come what may. */
930 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
932 unsigned long tem
= fg
;
937 /* If the user requested inverse video, obey. */
940 unsigned long tem2
= fg
;
946 fprintf (tty
->termscript
, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face
,
947 fp
->foreground
, fp
->background
, fg
, bg
);
948 if (fg
>= 0 && fg
< 16)
950 ScreenAttrib
&= 0xf0;
953 if (bg
>= 0 && bg
< 16)
955 ScreenAttrib
&= 0x0f;
956 ScreenAttrib
|= ((bg
& 0x0f) << 4);
960 Lisp_Object Vdos_unsupported_char_glyph
;
961 extern unsigned char *encode_terminal_code (struct glyph
*, int,
962 struct coding_system
*);
964 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
966 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
967 int unsupported_face
= 0;
968 unsigned unsupported_char
= '\177';
969 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
970 register int sl
= str_len
;
971 register int tlen
= GLYPH_TABLE_LENGTH
;
972 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
973 struct tty_display_info
*tty
= FRAME_TTY (f
);
975 unsigned char *conversion_buffer
;
977 /* Do we need to consider conversion of unibyte characters to
979 int convert_unibyte_characters
980 = (NILP (current_buffer
->enable_multibyte_characters
)
981 && unibyte_display_via_language_environment
);
983 /* If terminal_coding does any conversion, use it, otherwise use
984 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
985 because it always returns 1 if terminal_coding.src_multibyte is 1. */
986 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
988 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
989 coding
= &safe_terminal_coding
;
991 if (str_len
<= 0) return;
993 screen_buf
= screen_bp
= alloca (str_len
* 2);
994 screen_buf_end
= screen_buf
+ str_len
* 2;
995 sf
= SELECTED_FRAME();
997 /* Since faces get cached and uncached behind our back, we can't
998 rely on their indices in the cache being consistent across
999 invocations. So always reset the screen face to the default
1000 face of the frame, before writing glyphs, and let the glyphs
1001 set the right face if it's different from the default. */
1002 IT_set_face (DEFAULT_FACE_ID
);
1004 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1006 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
1011 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
1012 only for the redisplay code to know how many columns does
1013 this character occupy on the screen. Skip padding glyphs. */
1014 if (CHAR_GLYPH_PADDING_P (*str
))
1021 /* If the face of this glyph is different from the current
1022 screen face, update the screen attribute byte. */
1024 if (cf
!= screen_face
)
1025 IT_set_face (cf
); /* handles invalid faces gracefully */
1028 /* This is the last glyph. */
1029 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1031 conversion_buffer
= encode_terminal_code (str
, 1, coding
);
1032 if (coding
->produced
> 0)
1034 if (2*coding
->produced
> screen_buf_end
- screen_bp
)
1036 /* The allocated buffer for screen writes is too small.
1037 Flush it and loop again without incrementing STR, so
1038 that the next loop will begin with the same glyph. */
1039 int nbytes
= screen_bp
- screen_buf
;
1042 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
1043 if (screen_virtual_segment
)
1044 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
1045 new_pos_X
+= nbytes
/ 2;
1048 /* Prepare to reuse the same buffer again. */
1049 screen_bp
= screen_buf
;
1054 /* There's enough place in the allocated buffer to add
1055 the encoding of this glyph. */
1057 /* Copy the encoded bytes to the allocated buffer. */
1058 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
1060 *screen_bp
++ = (unsigned char)*bp
;
1061 *screen_bp
++ = ScreenAttrib
;
1062 if (tty
->termscript
)
1063 fputc (*bp
, tty
->termscript
);
1067 /* Update STR and its remaining length. */
1073 /* Dump whatever is left in the screen buffer. */
1075 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1076 if (screen_virtual_segment
)
1077 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1078 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1081 /************************************************************************
1082 Mouse Highlight (and friends..)
1083 ************************************************************************/
1085 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1086 static Lisp_Object last_mouse_window
;
1088 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1090 /* Set the mouse pointer shape according to whether it is in the
1091 area where the mouse highlight is in effect. */
1093 IT_set_mouse_pointer (int mode
)
1095 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1096 many possibilities to change its shape, and the available
1097 functionality pretty much sucks (e.g., almost every reasonable
1098 shape will conceal the character it is on). Since the color of
1099 the pointer changes in the highlighted area, it is not clear to
1100 me whether anything else is required, anyway. */
1103 /* Display the active region described by mouse_face_*
1104 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1106 show_mouse_face (struct tty_display_info
*dpyinfo
, int hl
)
1108 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1109 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1112 struct tty_display_info
*tty
= FRAME_TTY (f
);
1115 /* If window is in the process of being destroyed, don't bother
1117 if (w
->current_matrix
== NULL
)
1118 goto set_cursor_shape
;
1120 /* Recognize when we are called to operate on rows that don't exist
1121 anymore. This can happen when a window is split. */
1122 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1123 goto set_cursor_shape
;
1125 /* There's no sense to do anything if the mouse face isn't realized. */
1128 if (dpyinfo
->mouse_face_hidden
)
1129 goto set_cursor_shape
;
1131 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1133 goto set_cursor_shape
;
1136 /* Note that mouse_face_beg_row etc. are window relative. */
1137 for (i
= dpyinfo
->mouse_face_beg_row
;
1138 i
<= dpyinfo
->mouse_face_end_row
;
1141 int start_hpos
, end_hpos
;
1142 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1144 /* Don't do anything if row doesn't have valid contents. */
1145 if (!row
->enabled_p
)
1148 /* For all but the first row, the highlight starts at column 0. */
1149 if (i
== dpyinfo
->mouse_face_beg_row
)
1150 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1154 if (i
== dpyinfo
->mouse_face_end_row
)
1155 end_hpos
= dpyinfo
->mouse_face_end_col
;
1157 end_hpos
= row
->used
[TEXT_AREA
];
1159 if (end_hpos
<= start_hpos
)
1161 /* Record that some glyphs of this row are displayed in
1163 row
->mouse_face_p
= hl
> 0;
1166 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1167 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1168 int nglyphs
= end_hpos
- start_hpos
;
1169 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1170 int start_offset
= offset
;
1172 if (tty
->termscript
)
1173 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
1174 kstart
, kstart
+ nglyphs
- 1, vpos
);
1177 IT_set_face (dpyinfo
->mouse_face_face_id
);
1178 /* Since we are going to change only the _colors_ of the
1179 displayed text, there's no need to go through all the
1180 pain of generating and encoding the text from the glyphs.
1181 Instead, we simply poke the attribute byte of each
1182 affected position in video memory with the colors
1183 computed by IT_set_face! */
1184 _farsetsel (_dos_ds
);
1187 _farnspokeb (offset
, ScreenAttrib
);
1190 if (screen_virtual_segment
)
1191 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1196 /* We are removing a previously-drawn mouse highlight. The
1197 safest way to do so is to redraw the glyphs anew, since
1198 all kinds of faces and display tables could have changed
1200 int nglyphs
= end_hpos
- start_hpos
;
1201 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1203 if (end_hpos
>= row
->used
[TEXT_AREA
])
1204 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1206 /* IT_write_glyphs writes at cursor position, so we need to
1207 temporarily move cursor coordinates to the beginning of
1208 the highlight region. */
1209 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1210 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1212 if (tty
->termscript
)
1213 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1214 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1215 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1216 if (tty
->termscript
)
1217 fputs ("\n", tty
->termscript
);
1224 /* Change the mouse pointer shape. */
1225 IT_set_mouse_pointer (hl
);
1228 /* Clear out the mouse-highlighted active region.
1229 Redraw it un-highlighted first. */
1231 clear_mouse_face (struct tty_display_info
*dpyinfo
)
1233 if (!dpyinfo
->mouse_face_hidden
&& ! NILP (dpyinfo
->mouse_face_window
))
1234 show_mouse_face (dpyinfo
, 0);
1236 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1237 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1238 dpyinfo
->mouse_face_window
= Qnil
;
1241 /* Find the glyph matrix position of buffer position POS in window W.
1242 *HPOS and *VPOS are set to the positions found. W's current glyphs
1243 must be up to date. If POS is above window start return (0, 0).
1244 If POS is after end of W, return end of last line in W. */
1246 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1248 int i
, lastcol
, line_start_position
, maybe_next_line_p
= 0;
1249 int yb
= window_text_bottom_y (w
);
1250 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0), *best_row
= row
;
1254 if (row
->used
[TEXT_AREA
])
1255 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1257 line_start_position
= 0;
1259 if (line_start_position
> pos
)
1261 /* If the position sought is the end of the buffer,
1262 don't include the blank lines at the bottom of the window. */
1263 else if (line_start_position
== pos
1264 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1266 maybe_next_line_p
= 1;
1269 else if (line_start_position
> 0)
1272 /* Don't overstep the last matrix row, lest we get into the
1273 never-never land... */
1274 if (row
->y
+ 1 >= yb
)
1280 /* Find the right column within BEST_ROW. */
1283 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1285 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1288 charpos
= glyph
->charpos
;
1295 else if (charpos
> pos
)
1297 else if (charpos
> 0)
1301 /* If we're looking for the end of the buffer,
1302 and we didn't find it in the line we scanned,
1303 use the start of the following line. */
1304 if (maybe_next_line_p
)
1311 *hpos
= lastcol
+ 1;
1315 /* Take proper action when mouse has moved to the mode or top line of
1316 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1317 mode line. X is relative to the start of the text display area of
1318 W, so the width of fringes and scroll bars must be subtracted
1319 to get a position relative to the start of the mode line. */
1321 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1323 struct frame
*f
= XFRAME (w
->frame
);
1324 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1325 struct glyph_row
*row
;
1328 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1330 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1334 extern Lisp_Object Qhelp_echo
;
1335 struct glyph
*glyph
, *end
;
1336 Lisp_Object help
, map
;
1338 /* Find the glyph under X. */
1339 glyph
= (row
->glyphs
[TEXT_AREA
]
1341 /* in case someone implements scroll bars some day... */
1342 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w
));
1343 end
= glyph
+ row
->used
[TEXT_AREA
];
1345 && STRINGP (glyph
->object
)
1346 && STRING_INTERVALS (glyph
->object
)
1347 && glyph
->charpos
>= 0
1348 && glyph
->charpos
< SCHARS (glyph
->object
))
1350 /* If we're on a string with `help-echo' text property,
1351 arrange for the help to be displayed. This is done by
1352 setting the global variable help_echo to the help string. */
1353 help
= Fget_text_property (make_number (glyph
->charpos
),
1354 Qhelp_echo
, glyph
->object
);
1357 help_echo_string
= help
;
1358 XSETWINDOW (help_echo_window
, w
);
1359 help_echo_object
= glyph
->object
;
1360 help_echo_pos
= glyph
->charpos
;
1366 /* Take proper action when the mouse has moved to position X, Y on
1367 frame F as regards highlighting characters that have mouse-face
1368 properties. Also de-highlighting chars where the mouse was before.
1369 X and Y can be negative or out of range. */
1371 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1373 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1374 enum window_part part
= ON_NOTHING
;
1378 /* When a menu is active, don't highlight because this looks odd. */
1379 if (mouse_preempted
)
1382 if (NILP (Vmouse_highlight
)
1383 || !f
->glyphs_initialized_p
)
1386 dpyinfo
->mouse_face_mouse_x
= x
;
1387 dpyinfo
->mouse_face_mouse_y
= y
;
1388 dpyinfo
->mouse_face_mouse_frame
= f
;
1390 if (dpyinfo
->mouse_face_defer
)
1395 dpyinfo
->mouse_face_deferred_gc
= 1;
1399 /* Which window is that in? */
1400 window
= window_from_coordinates (f
, x
, y
, &part
, &x
, &y
, 0);
1402 /* If we were displaying active text in another window, clear that. */
1403 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1404 clear_mouse_face (dpyinfo
);
1406 /* Not on a window -> return. */
1407 if (!WINDOWP (window
))
1410 /* Convert to window-relative coordinates. */
1411 w
= XWINDOW (window
);
1413 if (part
== ON_MODE_LINE
|| part
== ON_HEADER_LINE
)
1415 /* Mouse is on the mode or top line. */
1416 IT_note_mode_line_highlight (w
, x
, part
== ON_MODE_LINE
);
1420 IT_set_mouse_pointer (0);
1422 /* Are we in a window whose display is up to date?
1423 And verify the buffer's text has not changed. */
1425 && EQ (w
->window_end_valid
, w
->buffer
)
1426 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1427 && (XFASTINT (w
->last_overlay_modified
)
1428 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1430 int pos
, i
, nrows
= w
->current_matrix
->nrows
;
1431 struct glyph_row
*row
;
1432 struct glyph
*glyph
;
1434 /* Find the glyph under X/Y. */
1436 if (y
>= 0 && y
< nrows
)
1438 row
= MATRIX_ROW (w
->current_matrix
, y
);
1439 /* Give up if some row before the one we are looking for is
1441 for (i
= 0; i
<= y
; i
++)
1442 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1444 if (i
> y
/* all rows upto and including the one at Y are enabled */
1445 && row
->displays_text_p
1446 && x
< window_box_width (w
, TEXT_AREA
))
1448 glyph
= row
->glyphs
[TEXT_AREA
];
1449 if (x
>= row
->used
[TEXT_AREA
])
1454 if (!BUFFERP (glyph
->object
))
1460 /* Clear mouse face if X/Y not over text. */
1463 clear_mouse_face (dpyinfo
);
1467 if (!BUFFERP (glyph
->object
))
1469 pos
= glyph
->charpos
;
1471 /* Check for mouse-face and help-echo. */
1473 extern Lisp_Object Qmouse_face
;
1474 Lisp_Object mouse_face
, overlay
, position
, *overlay_vec
;
1475 int noverlays
, obegv
, ozv
;
1476 struct buffer
*obuf
;
1478 /* If we get an out-of-range value, return now; avoid an error. */
1479 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1482 /* Make the window's buffer temporarily current for
1483 overlays_at and compute_char_face. */
1484 obuf
= current_buffer
;
1485 current_buffer
= XBUFFER (w
->buffer
);
1491 /* Is this char mouse-active or does it have help-echo? */
1492 XSETINT (position
, pos
);
1494 /* Put all the overlays we want in a vector in overlay_vec. */
1495 GET_OVERLAYS_AT (pos
, overlay_vec
, noverlays
, NULL
, 0);
1496 /* Sort overlays into increasing priority order. */
1497 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1499 /* Check mouse-face highlighting. */
1500 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1501 && y
>= dpyinfo
->mouse_face_beg_row
1502 && y
<= dpyinfo
->mouse_face_end_row
1503 && (y
> dpyinfo
->mouse_face_beg_row
1504 || x
>= dpyinfo
->mouse_face_beg_col
)
1505 && (y
< dpyinfo
->mouse_face_end_row
1506 || x
< dpyinfo
->mouse_face_end_col
1507 || dpyinfo
->mouse_face_past_end
)))
1509 /* Clear the display of the old active region, if any. */
1510 clear_mouse_face (dpyinfo
);
1512 /* Find highest priority overlay that has a mouse-face prop. */
1514 for (i
= noverlays
- 1; i
>= 0; --i
)
1516 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1517 if (!NILP (mouse_face
))
1519 overlay
= overlay_vec
[i
];
1524 /* If no overlay applies, get a text property. */
1526 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1529 /* Handle the overlay case. */
1530 if (! NILP (overlay
))
1532 /* Find the range of text around this char that
1533 should be active. */
1534 Lisp_Object before
, after
;
1537 before
= Foverlay_start (overlay
);
1538 after
= Foverlay_end (overlay
);
1539 /* Record this as the current active region. */
1540 fast_find_position (w
, XFASTINT (before
),
1541 &dpyinfo
->mouse_face_beg_col
,
1542 &dpyinfo
->mouse_face_beg_row
);
1543 dpyinfo
->mouse_face_past_end
1544 = !fast_find_position (w
, XFASTINT (after
),
1545 &dpyinfo
->mouse_face_end_col
,
1546 &dpyinfo
->mouse_face_end_row
);
1547 dpyinfo
->mouse_face_window
= window
;
1548 dpyinfo
->mouse_face_face_id
1549 = face_at_buffer_position (w
, pos
, 0, 0,
1551 !dpyinfo
->mouse_face_hidden
);
1553 /* Display it as active. */
1554 show_mouse_face (dpyinfo
, 1);
1556 /* Handle the text property case. */
1557 else if (! NILP (mouse_face
))
1559 /* Find the range of text around this char that
1560 should be active. */
1561 Lisp_Object before
, after
, beginning
, end
;
1564 beginning
= Fmarker_position (w
->start
);
1565 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1566 - XFASTINT (w
->window_end_pos
)));
1568 = Fprevious_single_property_change (make_number (pos
+ 1),
1570 w
->buffer
, beginning
);
1572 = Fnext_single_property_change (position
, Qmouse_face
,
1574 /* Record this as the current active region. */
1575 fast_find_position (w
, XFASTINT (before
),
1576 &dpyinfo
->mouse_face_beg_col
,
1577 &dpyinfo
->mouse_face_beg_row
);
1578 dpyinfo
->mouse_face_past_end
1579 = !fast_find_position (w
, XFASTINT (after
),
1580 &dpyinfo
->mouse_face_end_col
,
1581 &dpyinfo
->mouse_face_end_row
);
1582 dpyinfo
->mouse_face_window
= window
;
1583 dpyinfo
->mouse_face_face_id
1584 = face_at_buffer_position (w
, pos
, 0, 0,
1586 !dpyinfo
->mouse_face_hidden
);
1588 /* Display it as active. */
1589 show_mouse_face (dpyinfo
, 1);
1593 /* Look for a `help-echo' property. */
1596 extern Lisp_Object Qhelp_echo
;
1598 /* Check overlays first. */
1600 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1602 overlay
= overlay_vec
[i
];
1603 help
= Foverlay_get (overlay
, Qhelp_echo
);
1608 help_echo_string
= help
;
1609 help_echo_window
= window
;
1610 help_echo_object
= overlay
;
1611 help_echo_pos
= pos
;
1613 /* Try text properties. */
1614 else if (NILP (help
)
1615 && ((STRINGP (glyph
->object
)
1616 && glyph
->charpos
>= 0
1617 && glyph
->charpos
< SCHARS (glyph
->object
))
1618 || (BUFFERP (glyph
->object
)
1619 && glyph
->charpos
>= BEGV
1620 && glyph
->charpos
< ZV
)))
1622 help
= Fget_text_property (make_number (glyph
->charpos
),
1623 Qhelp_echo
, glyph
->object
);
1626 help_echo_string
= help
;
1627 help_echo_window
= window
;
1628 help_echo_object
= glyph
->object
;
1629 help_echo_pos
= glyph
->charpos
;
1636 current_buffer
= obuf
;
1642 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1645 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1646 extern int fatal_error_in_progress
;
1647 struct tty_display_info
*tty
= FRAME_TTY (f
);
1649 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1653 i
= (j
= first_unused
- new_pos_X
) * 2;
1654 if (tty
->termscript
)
1655 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1656 spaces
= sp
= alloca (i
);
1661 *sp
++ = ScreenAttrib
;
1665 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1666 if (screen_virtual_segment
)
1667 dosv_refresh_virtual_screen (offset
, i
/ 2);
1669 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1670 Let's follow their lead, in case someone relies on this. */
1671 new_pos_X
= first_unused
;
1675 IT_clear_screen (struct frame
*f
)
1677 struct tty_display_info
*tty
= FRAME_TTY (f
);
1679 if (tty
->termscript
)
1680 fprintf (tty
->termscript
, "<CLR:SCR>");
1681 /* We are sometimes called (from clear_garbaged_frames) when a new
1682 frame is being created, but its faces are not yet realized. In
1683 such a case we cannot call IT_set_face, since it will fail to find
1684 any valid faces and will abort. Instead, use the initial screen
1685 colors; that should mimic what a Unix tty does, which simply clears
1686 the screen with whatever default colors are in use. */
1687 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1688 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1693 if (screen_virtual_segment
)
1694 dosv_refresh_virtual_screen (0, screen_size
);
1695 new_pos_X
= new_pos_Y
= 0;
1699 IT_clear_to_end (struct frame
*f
)
1701 struct tty_display_info
*tty
= FRAME_TTY (f
);
1703 if (tty
->termscript
)
1704 fprintf (tty
->termscript
, "<CLR:EOS>");
1706 while (new_pos_Y
< screen_size_Y
) {
1708 IT_clear_end_of_line (f
, screen_size_X
);
1714 IT_cursor_to (struct frame
*f
, int y
, int x
)
1716 struct tty_display_info
*tty
= FRAME_TTY (f
);
1718 if (tty
->termscript
)
1719 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1724 static int cursor_cleared
;
1727 IT_display_cursor (int on
)
1729 struct tty_display_info
*tty
= CURTTY ();
1731 if (on
&& cursor_cleared
)
1733 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1735 if (tty
->termscript
)
1736 fprintf (tty
->termscript
, "\nCURSOR ON");
1738 else if (!on
&& !cursor_cleared
)
1740 ScreenSetCursor (-1, -1);
1742 if (tty
->termscript
)
1743 fprintf (tty
->termscript
, "\nCURSOR OFF");
1747 /* Emacs calls cursor-movement functions a lot when it updates the
1748 display (probably a legacy of old terminals where you cannot
1749 update a screen line without first moving the cursor there).
1750 However, cursor movement is expensive on MSDOS (it calls a slow
1751 BIOS function and requires 2 mode switches), while actual screen
1752 updates access the video memory directly and don't depend on
1753 cursor position. To avoid slowing down the redisplay, we cheat:
1754 all functions that move the cursor only set internal variables
1755 which record the cursor position, whereas the cursor is only
1756 moved to its final position whenever screen update is complete.
1758 `IT_cmgoto' is called from the keyboard reading loop and when the
1759 frame update is complete. This means that we are ready for user
1760 input, so we update the cursor position to show where the point is,
1761 and also make the mouse pointer visible.
1763 Special treatment is required when the cursor is in the echo area,
1764 to put the cursor at the end of the text displayed there. */
1767 IT_cmgoto (FRAME_PTR f
)
1769 /* Only set the cursor to where it should be if the display is
1770 already in sync with the window contents. */
1771 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1772 struct tty_display_info
*tty
= FRAME_TTY (f
);
1774 /* FIXME: This needs to be rewritten for the new redisplay, or
1777 static int previous_pos_X
= -1;
1779 update_cursor_pos
= 1; /* temporary!!! */
1781 /* If the display is in sync, forget any previous knowledge about
1782 cursor position. This is primarily for unexpected events like
1783 C-g in the minibuffer. */
1784 if (update_cursor_pos
&& previous_pos_X
>= 0)
1785 previous_pos_X
= -1;
1786 /* If we are in the echo area, put the cursor at the
1787 end of the echo area message. */
1788 if (!update_cursor_pos
1789 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1791 int tem_X
= current_pos_X
, dummy
;
1793 if (echo_area_glyphs
)
1795 tem_X
= echo_area_glyphs_length
;
1796 /* Save current cursor position, to be restored after the
1797 echo area message is erased. Only remember one level
1798 of previous cursor position. */
1799 if (previous_pos_X
== -1)
1800 ScreenGetCursor (&dummy
, &previous_pos_X
);
1802 else if (previous_pos_X
>= 0)
1804 /* We wind up here after the echo area message is erased.
1805 Restore the cursor position we remembered above. */
1806 tem_X
= previous_pos_X
;
1807 previous_pos_X
= -1;
1810 if (current_pos_X
!= tem_X
)
1813 update_cursor_pos
= 1;
1818 if (update_cursor_pos
1819 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1821 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1822 if (tty
->termscript
)
1823 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1826 /* Maybe cursor is invisible, so make it visible. */
1827 IT_display_cursor (1);
1829 /* Mouse pointer should be always visible if we are waiting for
1836 IT_update_begin (struct frame
*f
)
1838 struct tty_display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1839 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1841 if (display_info
->termscript
)
1842 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1846 if (f
&& f
== mouse_face_frame
)
1848 /* Don't do highlighting for mouse motion during the update. */
1849 display_info
->mouse_face_defer
= 1;
1851 /* If F needs to be redrawn, simply forget about any prior mouse
1853 if (FRAME_GARBAGED_P (f
))
1854 display_info
->mouse_face_window
= Qnil
;
1856 /* Can we tell that this update does not affect the window
1857 where the mouse highlight is? If so, no need to turn off.
1858 Likewise, don't do anything if none of the enabled rows
1859 contains glyphs highlighted in mouse face. */
1860 if (!NILP (display_info
->mouse_face_window
)
1861 && WINDOWP (display_info
->mouse_face_window
))
1863 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1866 /* If the mouse highlight is in the window that was deleted
1867 (e.g., if it was popped by completion), clear highlight
1869 if (NILP (w
->buffer
))
1870 display_info
->mouse_face_window
= Qnil
;
1873 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1874 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1875 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1879 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1880 clear_mouse_face (display_info
);
1883 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1885 /* If the frame with mouse highlight was deleted, invalidate the
1887 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1888 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1889 display_info
->mouse_face_window
= Qnil
;
1890 display_info
->mouse_face_deferred_gc
= 0;
1891 display_info
->mouse_face_mouse_frame
= NULL
;
1898 IT_update_end (struct frame
*f
)
1900 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1902 if (dpyinfo
->termscript
)
1903 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1904 dpyinfo
->mouse_face_defer
= 0;
1908 IT_frame_up_to_date (struct frame
*f
)
1910 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1911 Lisp_Object new_cursor
, frame_desired_cursor
;
1914 if (dpyinfo
->mouse_face_deferred_gc
1915 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
1918 if (dpyinfo
->mouse_face_mouse_frame
)
1919 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1920 dpyinfo
->mouse_face_mouse_x
,
1921 dpyinfo
->mouse_face_mouse_y
);
1922 dpyinfo
->mouse_face_deferred_gc
= 0;
1926 /* Set the cursor type to whatever they wanted. In a minibuffer
1927 window, we want the cursor to appear only if we are reading input
1928 from this window, and we want the cursor to be taken from the
1929 frame parameters. For the selected window, we use either its
1930 buffer-local value or the value from the frame parameters if the
1931 buffer doesn't define its local value for the cursor type. */
1932 sw
= XWINDOW (f
->selected_window
);
1933 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1934 if (cursor_in_echo_area
1935 && FRAME_HAS_MINIBUF_P (f
)
1936 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1937 && sw
== XWINDOW (echo_area_window
))
1938 new_cursor
= frame_desired_cursor
;
1941 struct buffer
*b
= XBUFFER (sw
->buffer
);
1943 if (EQ (b
->cursor_type
, Qt
))
1944 new_cursor
= frame_desired_cursor
;
1945 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1946 new_cursor
= Fcons (Qbar
, make_number (0));
1948 new_cursor
= b
->cursor_type
;
1951 IT_set_cursor_type (f
, new_cursor
);
1953 IT_cmgoto (f
); /* position cursor when update is done */
1956 /* Copy LEN glyphs displayed on a single line whose vertical position
1957 is YPOS, beginning at horizontal position XFROM to horizontal
1958 position XTO, by moving blocks in the video memory. Used by
1959 functions that insert and delete glyphs. */
1961 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1963 /* The offsets of source and destination relative to the
1964 conventional memorty selector. */
1965 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1966 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1968 if (from
== to
|| len
<= 0)
1971 _farsetsel (_dos_ds
);
1973 /* The source and destination might overlap, so we need to move
1974 glyphs non-destructively. */
1977 for ( ; len
; from
+= 2, to
+= 2, len
--)
1978 _farnspokew (to
, _farnspeekw (from
));
1982 from
+= (len
- 1) * 2;
1983 to
+= (len
- 1) * 2;
1984 for ( ; len
; from
-= 2, to
-= 2, len
--)
1985 _farnspokew (to
, _farnspeekw (from
));
1987 if (screen_virtual_segment
)
1988 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1991 /* Insert and delete glyphs. */
1993 IT_insert_glyphs (f
, start
, len
)
1995 register struct glyph
*start
;
1998 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
2000 /* Shift right the glyphs from the nominal cursor position to the
2001 end of this line. */
2002 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2004 /* Now write the glyphs to be inserted. */
2005 IT_write_glyphs (f
, start
, len
);
2009 IT_delete_glyphs (f
, n
)
2016 /* set-window-configuration on window.c needs this. */
2018 x_set_menu_bar_lines (f
, value
, oldval
)
2020 Lisp_Object value
, oldval
;
2022 set_menu_bar_lines (f
, value
, oldval
);
2025 /* This was copied from xfaces.c */
2027 extern Lisp_Object Qbackground_color
;
2028 extern Lisp_Object Qforeground_color
;
2029 Lisp_Object Qreverse
;
2030 extern Lisp_Object Qtitle
;
2032 /* IT_set_terminal_modes is called when emacs is started,
2033 resumed, and whenever the screen is redrawn! */
2036 IT_set_terminal_modes (struct terminal
*term
)
2038 struct tty_display_info
*tty
;
2040 /* If called with initial terminal, it's too early to do anything
2042 if (term
->type
== output_initial
)
2045 tty
= term
->display_info
.tty
;
2047 if (tty
->termscript
)
2048 fprintf (tty
->termscript
, "\n<SET_TERM>");
2050 screen_size_X
= ScreenCols ();
2051 screen_size_Y
= ScreenRows ();
2052 screen_size
= screen_size_X
* screen_size_Y
;
2054 new_pos_X
= new_pos_Y
= 0;
2055 current_pos_X
= current_pos_Y
= -1;
2057 if (term_setup_done
)
2059 term_setup_done
= 1;
2061 startup_screen_size_X
= screen_size_X
;
2062 startup_screen_size_Y
= screen_size_Y
;
2063 startup_screen_attrib
= ScreenAttrib
;
2066 /* Is DOS/V (or any other RSIS software which relocates
2067 the screen) installed? */
2069 unsigned short es_value
;
2072 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2073 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2074 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2075 else if (screen_old_address
) /* already switched to Japanese mode once */
2076 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2078 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2080 es_value
= regs
.x
.es
;
2081 __dpmi_int (0x10, ®s
);
2083 if (regs
.x
.es
!= es_value
)
2085 /* screen_old_address is only set if ScreenPrimary does NOT
2086 already point to the relocated buffer address returned by
2087 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2088 ScreenPrimary to that address at startup under DOS/V. */
2089 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2090 screen_old_address
= ScreenPrimary
;
2091 screen_virtual_segment
= regs
.x
.es
;
2092 screen_virtual_offset
= regs
.x
.di
;
2093 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2096 #endif /* __DJGPP__ > 1 */
2098 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2099 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2104 /* IT_reset_terminal_modes is called when emacs is
2105 suspended or killed. */
2108 IT_reset_terminal_modes (struct terminal
*term
)
2110 int display_row_start
= (int) ScreenPrimary
;
2111 int saved_row_len
= startup_screen_size_X
* 2;
2112 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
2113 int to_next_row
= update_row_len
;
2114 unsigned char *saved_row
= startup_screen_buffer
;
2115 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
2116 struct tty_display_info
*tty
= term
->display_info
.tty
;
2118 if (tty
->termscript
)
2119 fprintf (tty
->termscript
, "\n<RESET_TERM>");
2121 if (!term_setup_done
)
2126 /* Leave the video system in the same state as we found it,
2127 as far as the blink/bright-background bit is concerned. */
2128 maybe_enable_blinking ();
2130 /* We have a situation here.
2131 We cannot just do ScreenUpdate(startup_screen_buffer) because
2132 the luser could have changed screen dimensions inside Emacs
2133 and failed (or didn't want) to restore them before killing
2134 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2135 thus will happily use memory outside what was allocated for
2136 `startup_screen_buffer'.
2137 Thus we only restore as much as the current screen dimensions
2138 can hold, and clear the rest (if the saved screen is smaller than
2139 the current) with the color attribute saved at startup. The cursor
2140 is also restored within the visible dimensions. */
2142 ScreenAttrib
= startup_screen_attrib
;
2144 /* Don't restore the screen if we are exiting less than 2 seconds
2145 after startup: we might be crashing, and the screen might show
2146 some vital clues to what's wrong. */
2147 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2150 if (screen_virtual_segment
)
2151 dosv_refresh_virtual_screen (0, screen_size
);
2153 if (update_row_len
> saved_row_len
)
2154 update_row_len
= saved_row_len
;
2155 if (current_rows
> startup_screen_size_Y
)
2156 current_rows
= startup_screen_size_Y
;
2158 if (tty
->termscript
)
2159 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2160 update_row_len
/ 2, current_rows
);
2162 while (current_rows
--)
2164 dosmemput (saved_row
, update_row_len
, display_row_start
);
2165 if (screen_virtual_segment
)
2166 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2167 update_row_len
/ 2);
2168 saved_row
+= saved_row_len
;
2169 display_row_start
+= to_next_row
;
2172 if (startup_pos_X
< cursor_pos_X
)
2173 cursor_pos_X
= startup_pos_X
;
2174 if (startup_pos_Y
< cursor_pos_Y
)
2175 cursor_pos_Y
= startup_pos_Y
;
2177 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2178 xfree (startup_screen_buffer
);
2179 startup_screen_buffer
= NULL
;
2181 term_setup_done
= 0;
2185 IT_set_terminal_window (struct frame
*f
, int foo
)
2189 /* Remember the screen colors of the curent frame, to serve as the
2190 default colors for newly-created frames. */
2191 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2192 Smsdos_remember_default_colors
, 1, 1, 0,
2193 doc
: /* Remember the screen colors of the current frame. */)
2199 CHECK_FRAME (frame
);
2202 /* This function is called after applying default-frame-alist to the
2203 initial frame. At that time, if reverse-colors option was
2204 specified in default-frame-alist, it was already applied, and
2205 frame colors are reversed. */
2206 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2207 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2211 IT_set_frame_parameters (f
, alist
)
2216 int i
, j
, length
= XINT (Flength (alist
));
2218 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2220 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2221 /* Do we have to reverse the foreground and background colors? */
2222 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2223 int need_to_reverse
, was_reverse
= reverse
;
2224 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2225 unsigned long orig_fg
, orig_bg
;
2226 Lisp_Object frame_bg
, frame_fg
;
2227 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2228 struct tty_display_info
*tty
= FRAME_TTY (f
);
2230 /* If we are creating a new frame, begin with the original screen colors
2231 used for the initial frame. */
2232 if (EQ (alist
, Vdefault_frame_alist
)
2233 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2235 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2236 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2237 init_frame_faces (f
);
2239 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2240 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2241 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2242 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2243 /* frame_fg and frame_bg could be nil if, for example,
2244 f->param_alist is nil, e.g. if we are called from
2245 Fmake_terminal_frame. */
2246 if (NILP (frame_fg
))
2247 frame_fg
= build_string (unspecified_fg
);
2248 if (NILP (frame_bg
))
2249 frame_bg
= build_string (unspecified_bg
);
2251 /* Extract parm names and values into those vectors. */
2253 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2258 parms
[i
] = Fcar (elt
);
2259 CHECK_SYMBOL (parms
[i
]);
2260 values
[i
] = Fcdr (elt
);
2266 for (i
= 0; i
< j
; i
++)
2268 Lisp_Object prop
, val
;
2273 if (EQ (prop
, Qreverse
))
2274 reverse
= EQ (val
, Qt
);
2277 need_to_reverse
= reverse
&& !was_reverse
;
2278 if (tty
->termscript
&& need_to_reverse
)
2279 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
2281 /* Now process the alist elements in reverse of specified order. */
2282 for (i
--; i
>= 0; i
--)
2284 Lisp_Object prop
, val
, frame
;
2289 if (EQ (prop
, Qforeground_color
))
2291 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2292 ? LFACE_BACKGROUND_INDEX
2293 : LFACE_FOREGROUND_INDEX
);
2294 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2295 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2296 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2298 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2299 /* Make sure the foreground of the default face for this
2300 frame is changed as well. */
2301 XSETFRAME (frame
, f
);
2302 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2306 if (tty
->termscript
)
2307 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
2310 else if (EQ (prop
, Qbackground_color
))
2312 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2313 ? LFACE_FOREGROUND_INDEX
2314 : LFACE_BACKGROUND_INDEX
);
2315 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2316 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2317 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2319 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2320 /* Make sure the background of the default face for this
2321 frame is changed as well. */
2322 XSETFRAME (frame
, f
);
2323 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2327 if (tty
->termscript
)
2328 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
2331 else if (EQ (prop
, Qtitle
))
2333 x_set_title (f
, val
);
2334 if (tty
->termscript
)
2335 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
2337 else if (EQ (prop
, Qcursor_type
))
2339 IT_set_cursor_type (f
, val
);
2340 if (tty
->termscript
)
2341 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
2342 EQ (val
, Qbar
) || EQ (val
, Qhbar
)
2343 || CONSP (val
) && (EQ (XCAR (val
), Qbar
)
2344 || EQ (XCAR (val
), Qhbar
))
2347 else if (EQ (prop
, Qtty_type
))
2349 internal_terminal_init ();
2350 if (tty
->termscript
)
2351 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2352 SBYTES (val
), SDATA (val
));
2354 store_frame_param (f
, prop
, val
);
2357 /* If they specified "reverse", but not the colors, we need to swap
2358 the current frame colors. */
2359 if (need_to_reverse
)
2365 XSETFRAME (frame
, f
);
2366 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2367 tty_color_name (f
, orig_bg
),
2373 XSETFRAME (frame
, f
);
2374 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2375 tty_color_name (f
, orig_fg
),
2383 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2384 if (f
== SELECTED_FRAME())
2389 extern void init_frame_faces (FRAME_PTR
);
2391 #endif /* !HAVE_X_WINDOWS */
2394 /* Do we need the internal terminal? */
2397 internal_terminal_init ()
2399 static int init_needed
= 1;
2400 char *term
= getenv ("TERM"), *colors
;
2401 struct frame
*sf
= SELECTED_FRAME();
2402 struct tty_display_info
*tty
;
2404 #ifdef HAVE_X_WINDOWS
2405 if (!inhibit_window_system
)
2409 /* If this is the initial terminal, we are done here. */
2410 if (sf
->output_method
== output_initial
)
2414 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2416 #ifndef HAVE_X_WINDOWS
2417 if (!internal_terminal
|| inhibit_window_system
)
2419 sf
->output_method
= output_termcap
;
2423 tty
= FRAME_TTY (sf
);
2424 current_kboard
->Vwindow_system
= Qpc
;
2425 sf
->output_method
= output_msdos_raw
;
2428 if (!tty
->termscript
&& getenv ("EMACSTEST"))
2429 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
2430 if (tty
->termscript
)
2432 time_t now
= time (NULL
);
2433 struct tm
*tnow
= localtime (&now
);
2436 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
2437 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
2438 fprintf (tty
->termscript
, "=====================\n\n");
2441 Vinitial_window_system
= Qpc
;
2442 Vwindow_system_version
= make_number (23); /* RE Emacs version */
2443 tty
->terminal
->type
= output_msdos_raw
;
2445 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2447 screen_old_address
= 0;
2449 /* Forget the stale screen colors as well. */
2450 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2452 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2453 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2455 colors
= getenv ("EMACSCOLORS");
2456 if (colors
&& strlen (colors
) >= 2)
2458 /* The colors use 4 bits each (we enable bright background). */
2459 if (isdigit (colors
[0]))
2461 else if (isxdigit (colors
[0]))
2462 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2463 if (colors
[0] >= 0 && colors
[0] < 16)
2464 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
2465 if (isdigit (colors
[1]))
2467 else if (isxdigit (colors
[1]))
2468 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2469 if (colors
[1] >= 0 && colors
[1] < 16)
2470 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
2472 the_only_display_info
.mouse_face_mouse_frame
= NULL
;
2473 the_only_display_info
.mouse_face_deferred_gc
= 0;
2474 the_only_display_info
.mouse_face_beg_row
=
2475 the_only_display_info
.mouse_face_beg_col
= -1;
2476 the_only_display_info
.mouse_face_end_row
=
2477 the_only_display_info
.mouse_face_end_col
= -1;
2478 the_only_display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2479 the_only_display_info
.mouse_face_window
= Qnil
;
2480 the_only_display_info
.mouse_face_mouse_x
=
2481 the_only_display_info
.mouse_face_mouse_y
= 0;
2482 the_only_display_info
.mouse_face_defer
= 0;
2483 the_only_display_info
.mouse_face_hidden
= 0;
2485 if (have_mouse
) /* detected in dos_ttraw, which see */
2487 have_mouse
= 1; /* enable mouse */
2489 mouse_setup_buttons (mouse_button_count
);
2490 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
2494 if (tty
->termscript
&& screen_size
)
2495 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2496 screen_size_X
, screen_size_Y
);
2498 init_frame_faces (sf
);
2505 initialize_msdos_display (struct terminal
*term
)
2507 term
->rif
= 0; /* we don't support window-based display */
2508 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
2509 term
->clear_to_end_hook
= IT_clear_to_end
;
2510 term
->clear_frame_hook
= IT_clear_screen
;
2511 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
2512 term
->ins_del_lines_hook
= 0;
2513 term
->insert_glyphs_hook
= IT_insert_glyphs
;
2514 term
->write_glyphs_hook
= IT_write_glyphs
;
2515 term
->delete_glyphs_hook
= IT_delete_glyphs
;
2516 term
->ring_bell_hook
= IT_ring_bell
;
2517 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2518 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
2519 term
->set_terminal_window_hook
= IT_set_terminal_window
;
2520 term
->update_begin_hook
= IT_update_begin
;
2521 term
->update_end_hook
= IT_update_end
;
2522 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
2523 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
2524 term
->frame_rehighlight_hook
= 0;
2525 term
->frame_raise_lower_hook
= 0;
2526 term
->set_vertical_scroll_bar_hook
= 0;
2527 term
->condemn_scroll_bars_hook
= 0;
2528 term
->redeem_scroll_bar_hook
= 0;
2529 term
->judge_scroll_bars_hook
= 0;
2530 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
2533 dos_get_saved_screen (screen
, rows
, cols
)
2538 #ifndef HAVE_X_WINDOWS
2539 *screen
= startup_screen_buffer
;
2540 *cols
= startup_screen_size_X
;
2541 *rows
= startup_screen_size_Y
;
2542 return *screen
!= (char *)0;
2548 #ifndef HAVE_X_WINDOWS
2550 /* We are not X, but we can emulate it well enough for our needs... */
2554 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2555 error ("Not running under a window system");
2561 /* ----------------------- Keyboard control ----------------------
2563 * Keymaps reflect the following keyboard layout:
2565 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2566 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2567 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2568 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2572 #define Ignore 0x0000
2573 #define Normal 0x0000 /* normal key - alt changes scan-code */
2574 #define FctKey 0x1000 /* func key if c == 0, else c */
2575 #define Special 0x2000 /* func key even if c != 0 */
2576 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2577 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2578 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2579 #define Grey 0x6000 /* Grey keypad key */
2581 #define Alt 0x0100 /* alt scan-code */
2582 #define Ctrl 0x0200 /* ctrl scan-code */
2583 #define Shift 0x0400 /* shift scan-code */
2585 static int extended_kbd
; /* 101 (102) keyboard present. */
2587 struct kbd_translate
{
2590 unsigned short code
;
2593 struct dos_keyboard_map
2598 struct kbd_translate
*translate_table
;
2602 static struct dos_keyboard_map us_keyboard
= {
2604 /* 01234567890123456789012345678901234567890 12345678901234 */
2605 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2606 /* 0123456789012345678901234567890123456789 012345678901234 */
2607 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2608 0, /* no Alt-Gr key */
2609 0 /* no translate table */
2612 static struct dos_keyboard_map fr_keyboard
= {
2614 /* 012 3456789012345678901234567890123456789012345678901234 */
2615 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2616 /* 0123456789012345678901234567890123456789012345678901234 */
2617 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2618 /* 01234567 89012345678901234567890123456789012345678901234 */
2620 0 /* no translate table */
2624 * Italian keyboard support, country code 39.
2627 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2628 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2631 static struct kbd_translate it_kbd_translate_table
[] = {
2632 { 0x56, 0x3c, Normal
| 13 },
2633 { 0x56, 0x3e, Normal
| 27 },
2636 static struct dos_keyboard_map it_keyboard
= {
2638 /* 0 123456789012345678901234567890123456789012345678901234 */
2639 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2640 /* 01 23456789012345678901234567890123456789012345678901234 */
2641 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2642 /* 0123456789012345678901234567890123456789012345678901234 */
2644 it_kbd_translate_table
2647 static struct dos_keyboard_map dk_keyboard
= {
2649 /* 0123456789012345678901234567890123456789012345678901234 */
2650 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2651 /* 01 23456789012345678901234567890123456789012345678901234 */
2652 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2653 /* 0123456789012345678901234567890123456789012345678901234 */
2655 0 /* no translate table */
2658 static struct kbd_translate jp_kbd_translate_table
[] = {
2659 { 0x73, 0x5c, Normal
| 0 },
2660 { 0x73, 0x5f, Normal
| 0 },
2661 { 0x73, 0x1c, Map
| 0 },
2662 { 0x7d, 0x5c, Normal
| 13 },
2663 { 0x7d, 0x7c, Normal
| 13 },
2664 { 0x7d, 0x1c, Map
| 13 },
2667 static struct dos_keyboard_map jp_keyboard
= {
2669 /* 0123456789012 345678901234567890123456789012345678901234 */
2670 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2671 /* 01 23456789012345678901234567890123456789012345678901234 */
2672 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2673 0, /* no Alt-Gr key */
2674 jp_kbd_translate_table
2677 static struct keyboard_layout_list
2680 struct dos_keyboard_map
*keyboard_map
;
2681 } keyboard_layout_list
[] =
2690 static struct dos_keyboard_map
*keyboard
;
2691 static int keyboard_map_all
;
2692 static int international_keyboard
;
2695 dos_set_keyboard (code
, always
)
2700 _go32_dpmi_registers regs
;
2702 /* See if Keyb.Com is installed (for international keyboard support).
2703 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2704 of Windows 9X! So don't do that! */
2706 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2707 _go32_dpmi_simulate_int (0x2f, ®s
);
2708 if (regs
.h
.al
== 0xff)
2709 international_keyboard
= 1;
2711 /* Initialize to US settings, for countries that don't have their own. */
2712 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2713 keyboard_map_all
= always
;
2714 dos_keyboard_layout
= 1;
2716 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2717 if (code
== keyboard_layout_list
[i
].country_code
)
2719 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2720 keyboard_map_all
= always
;
2721 dos_keyboard_layout
= code
;
2729 unsigned char char_code
; /* normal code */
2730 unsigned char meta_code
; /* M- code */
2731 unsigned char keypad_code
; /* keypad code */
2732 unsigned char editkey_code
; /* edit key */
2733 } keypad_translate_map
[] = {
2734 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2735 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2736 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2737 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2738 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2739 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2740 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2741 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2742 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2743 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2744 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2749 unsigned char char_code
; /* normal code */
2750 unsigned char keypad_code
; /* keypad code */
2751 } grey_key_translate_map
[] = {
2752 '/', 0xaf, /* kp-decimal */
2753 '*', 0xaa, /* kp-multiply */
2754 '-', 0xad, /* kp-subtract */
2755 '+', 0xab, /* kp-add */
2756 '\r', 0x8d /* kp-enter */
2759 static unsigned short
2760 ibmpc_translate_map
[] =
2762 /* --------------- 00 to 0f --------------- */
2763 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2764 Alt
| ModFct
| 0x1b, /* Escape */
2765 Normal
| 1, /* '1' */
2766 Normal
| 2, /* '2' */
2767 Normal
| 3, /* '3' */
2768 Normal
| 4, /* '4' */
2769 Normal
| 5, /* '5' */
2770 Normal
| 6, /* '6' */
2771 Normal
| 7, /* '7' */
2772 Normal
| 8, /* '8' */
2773 Normal
| 9, /* '9' */
2774 Normal
| 10, /* '0' */
2775 Normal
| 11, /* '-' */
2776 Normal
| 12, /* '=' */
2777 Special
| 0x08, /* Backspace */
2778 ModFct
| 0x74, /* Tab/Backtab */
2780 /* --------------- 10 to 1f --------------- */
2793 ModFct
| 0x0d, /* Return */
2798 /* --------------- 20 to 2f --------------- */
2807 Map
| 40, /* '\'' */
2809 Ignore
, /* Left shift */
2810 Map
| 41, /* '\\' */
2816 /* --------------- 30 to 3f --------------- */
2823 Ignore
, /* Right shift */
2824 Grey
| 1, /* Grey * */
2826 Normal
| 55, /* ' ' */
2827 Ignore
, /* Caps Lock */
2828 FctKey
| 0xbe, /* F1 */
2829 FctKey
| 0xbf, /* F2 */
2830 FctKey
| 0xc0, /* F3 */
2831 FctKey
| 0xc1, /* F4 */
2832 FctKey
| 0xc2, /* F5 */
2834 /* --------------- 40 to 4f --------------- */
2835 FctKey
| 0xc3, /* F6 */
2836 FctKey
| 0xc4, /* F7 */
2837 FctKey
| 0xc5, /* F8 */
2838 FctKey
| 0xc6, /* F9 */
2839 FctKey
| 0xc7, /* F10 */
2840 Ignore
, /* Num Lock */
2841 Ignore
, /* Scroll Lock */
2842 KeyPad
| 7, /* Home */
2843 KeyPad
| 8, /* Up */
2844 KeyPad
| 9, /* Page Up */
2845 Grey
| 2, /* Grey - */
2846 KeyPad
| 4, /* Left */
2847 KeyPad
| 5, /* Keypad 5 */
2848 KeyPad
| 6, /* Right */
2849 Grey
| 3, /* Grey + */
2850 KeyPad
| 1, /* End */
2852 /* --------------- 50 to 5f --------------- */
2853 KeyPad
| 2, /* Down */
2854 KeyPad
| 3, /* Page Down */
2855 KeyPad
| 0, /* Insert */
2856 KeyPad
| 10, /* Delete */
2857 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2858 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2859 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2860 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2861 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2862 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2863 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2864 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2865 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2866 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2867 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2868 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2870 /* --------------- 60 to 6f --------------- */
2871 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2872 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2873 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2874 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2875 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2876 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2877 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2878 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2879 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2880 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2881 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2882 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2883 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2884 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2885 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2886 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2888 /* --------------- 70 to 7f --------------- */
2889 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2890 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2891 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2892 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2893 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2894 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2895 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2896 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2897 Alt
| Map
| 1, /* '1' */
2898 Alt
| Map
| 2, /* '2' */
2899 Alt
| Map
| 3, /* '3' */
2900 Alt
| Map
| 4, /* '4' */
2901 Alt
| Map
| 5, /* '5' */
2902 Alt
| Map
| 6, /* '6' */
2903 Alt
| Map
| 7, /* '7' */
2904 Alt
| Map
| 8, /* '8' */
2906 /* --------------- 80 to 8f --------------- */
2907 Alt
| Map
| 9, /* '9' */
2908 Alt
| Map
| 10, /* '0' */
2909 Alt
| Map
| 11, /* '-' */
2910 Alt
| Map
| 12, /* '=' */
2911 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2912 FctKey
| 0xc8, /* F11 */
2913 FctKey
| 0xc9, /* F12 */
2914 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2915 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2916 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2917 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2918 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2919 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2920 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2921 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2922 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2924 /* --------------- 90 to 9f --------------- */
2925 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2926 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2927 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2928 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2929 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2930 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2931 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2932 Alt
| FctKey
| 0x50, /* (Alt) Home */
2933 Alt
| FctKey
| 0x52, /* (Alt) Up */
2934 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2935 Ignore
, /* NO KEY */
2936 Alt
| FctKey
| 0x51, /* (Alt) Left */
2937 Ignore
, /* NO KEY */
2938 Alt
| FctKey
| 0x53, /* (Alt) Right */
2939 Ignore
, /* NO KEY */
2940 Alt
| FctKey
| 0x57, /* (Alt) End */
2942 /* --------------- a0 to af --------------- */
2943 Alt
| KeyPad
| 2, /* (Alt) Down */
2944 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2945 Alt
| KeyPad
| 0, /* (Alt) Insert */
2946 Alt
| KeyPad
| 10, /* (Alt) Delete */
2947 Alt
| Grey
| 0, /* (Alt) Grey / */
2948 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2949 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2952 /* These bit-positions corresponds to values returned by BIOS */
2953 #define SHIFT_P 0x0003 /* two bits! */
2954 #define CTRL_P 0x0004
2955 #define ALT_P 0x0008
2956 #define SCRLOCK_P 0x0010
2957 #define NUMLOCK_P 0x0020
2958 #define CAPSLOCK_P 0x0040
2959 #define ALT_GR_P 0x0800
2960 #define SUPER_P 0x4000 /* pseudo */
2961 #define HYPER_P 0x8000 /* pseudo */
2964 dos_get_modifiers (keymask
)
2968 int mask
, modifiers
= 0;
2970 /* Calculate modifier bits */
2971 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2972 int86 (0x16, ®s
, ®s
);
2976 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2977 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2981 mask
= regs
.h
.al
& (SHIFT_P
|
2982 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2984 /* Do not break international keyboard support. */
2985 /* When Keyb.Com is loaded, the right Alt key is */
2986 /* used for accessing characters like { and } */
2987 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2990 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2993 if (dos_hyper_key
== 1)
2996 modifiers
|= hyper_modifier
;
2998 else if (dos_super_key
== 1)
3001 modifiers
|= super_modifier
;
3003 else if (!international_keyboard
)
3005 /* If Keyb.Com is NOT installed, let Right Alt behave
3006 like the Left Alt. */
3012 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
3015 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
3017 if (dos_hyper_key
== 2)
3020 modifiers
|= hyper_modifier
;
3022 else if (dos_super_key
== 2)
3025 modifiers
|= super_modifier
;
3033 modifiers
|= shift_modifier
;
3035 modifiers
|= ctrl_modifier
;
3037 modifiers
|= meta_modifier
;
3044 #define NUM_RECENT_DOSKEYS (100)
3045 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
3046 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3047 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3049 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3050 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3051 Each input key receives two values in this vector: first the ASCII code,
3052 and then the scan code. */)
3055 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
3057 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3058 return Fvector (total_doskeys
, keys
);
3061 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3062 bcopy (keys
+ recent_doskeys_index
,
3063 XVECTOR (val
)->contents
,
3064 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3066 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3067 recent_doskeys_index
* sizeof (Lisp_Object
));
3072 /* Get a char from keyboard. Function keys are put into the event queue. */
3076 struct input_event event
;
3078 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3081 #ifndef HAVE_X_WINDOWS
3082 /* Maybe put the cursor where it should be. */
3083 IT_cmgoto (SELECTED_FRAME());
3086 /* The following condition is equivalent to `kbhit ()', except that
3087 it uses the bios to do its job. This pleases DESQview/X. */
3088 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3089 int86 (0x16, ®s
, ®s
),
3090 (regs
.x
.flags
& 0x40) == 0)
3093 register unsigned char c
;
3094 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
3096 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3097 int86 (0x16, ®s
, ®s
);
3102 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3104 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3105 recent_doskeys_index
= 0;
3106 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3108 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3109 recent_doskeys_index
= 0;
3111 modifiers
= dos_get_modifiers (&mask
);
3113 #ifndef HAVE_X_WINDOWS
3114 if (!NILP (Vdos_display_scancodes
))
3117 sprintf (buf
, "%02x:%02x*%04x",
3118 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3119 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3127 case 10: /* Ctrl Grey Enter */
3128 code
= Ctrl
| Grey
| 4;
3130 case 13: /* Grey Enter */
3133 case '/': /* Grey / */
3143 /* Try the keyboard-private translation table first. */
3144 if (keyboard
->translate_table
)
3146 struct kbd_translate
*p
= keyboard
->translate_table
;
3150 if (p
->sc
== sc
&& p
->ch
== c
)
3158 /* If the private table didn't translate it, use the general
3162 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3164 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3171 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3172 Emacs is ready to read a key. Therefore, if they press
3173 `Alt-x' when Emacs is busy, by the time we get to
3174 `dos_get_modifiers', they might have already released the
3175 Alt key, and Emacs gets just `x', which is BAD.
3176 However, for keys with the `Map' property set, the ASCII
3177 code returns zero only if Alt is pressed. So, when we DON'T
3178 have to support international_keyboard, we don't have to
3179 distinguish between the left and right Alt keys, and we
3180 can set the META modifier for any keys with the `Map'
3181 property if they return zero ASCII code (c = 0). */
3183 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3184 modifiers
|= meta_modifier
;
3186 modifiers
|= ctrl_modifier
;
3188 modifiers
|= shift_modifier
;
3191 switch (code
& 0xf000)
3194 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3196 c
= 0; /* Special */
3209 if (c
== 0) /* ctrl-break */
3211 return c
; /* ALT-nnn */
3213 if (!keyboard_map_all
)
3222 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3223 if (!keyboard_map_all
)
3227 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3228 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3232 code
= keyboard
->shifted
[code
];
3234 modifiers
&= ~shift_modifier
;
3237 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3238 code
= keyboard
->alt_gr
[code
];
3240 code
= keyboard
->unshifted
[code
];
3245 if (c
== 0xe0) /* edit key */
3248 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3249 kp_mode
= dos_keypad_mode
& 0x03;
3251 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3256 if (code
== 10 && dos_decimal_point
)
3257 return dos_decimal_point
;
3258 return keypad_translate_map
[code
].char_code
;
3261 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3265 code
= keypad_translate_map
[code
].meta_code
;
3266 modifiers
= meta_modifier
;
3270 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3277 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3278 if (dos_keypad_mode
& kp_mode
)
3279 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3281 code
= grey_key_translate_map
[code
].char_code
;
3289 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
3291 clear_mouse_face (dpyinfo
);
3292 dpyinfo
->mouse_face_hidden
= 1;
3296 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
3298 event
.kind
= ASCII_KEYSTROKE_EVENT
;
3300 event
.modifiers
= modifiers
;
3301 event
.frame_or_window
= selected_frame
;
3303 event
.timestamp
= event_timestamp ();
3304 kbd_buffer_store_event (&event
);
3307 if (have_mouse
> 0 && !mouse_preempted
)
3309 int but
, press
, x
, y
, ok
;
3310 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3311 Lisp_Object mouse_window
= Qnil
;
3313 /* Check for mouse movement *before* buttons. */
3314 mouse_check_moved ();
3316 /* If the mouse moved from the spot of its last sighting, we
3317 might need to update mouse highlight. */
3318 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3320 if (dpyinfo
->mouse_face_hidden
)
3322 dpyinfo
->mouse_face_hidden
= 0;
3323 clear_mouse_face (dpyinfo
);
3326 /* Generate SELECT_WINDOW_EVENTs when needed. */
3327 if (!NILP (Vmouse_autoselect_window
))
3329 mouse_window
= window_from_coordinates (SELECTED_FRAME(),
3333 /* A window will be selected only when it is not
3334 selected now, and the last mouse movement event was
3335 not in it. A minibuffer window will be selected iff
3337 if (WINDOWP (mouse_window
)
3338 && !EQ (mouse_window
, last_mouse_window
)
3339 && !EQ (mouse_window
, selected_window
))
3341 event
.kind
= SELECT_WINDOW_EVENT
;
3342 event
.frame_or_window
= mouse_window
;
3344 event
.timestamp
= event_timestamp ();
3345 kbd_buffer_store_event (&event
);
3347 last_mouse_window
= mouse_window
;
3350 last_mouse_window
= Qnil
;
3352 previous_help_echo_string
= help_echo_string
;
3353 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
3355 IT_note_mouse_highlight (SELECTED_FRAME(),
3356 mouse_last_x
, mouse_last_y
);
3357 /* If the contents of the global variable help_echo has
3358 changed, generate a HELP_EVENT. */
3359 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
3361 event
.kind
= HELP_EVENT
;
3362 event
.frame_or_window
= selected_frame
;
3363 event
.arg
= help_echo_object
;
3364 event
.x
= WINDOWP (help_echo_window
)
3365 ? help_echo_window
: selected_frame
;
3366 event
.y
= help_echo_string
;
3367 event
.timestamp
= event_timestamp ();
3368 event
.code
= help_echo_pos
;
3369 kbd_buffer_store_event (&event
);
3373 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3374 for (press
= 0; press
< 2; press
++)
3376 int button_num
= but
;
3379 ok
= mouse_pressed (but
, &x
, &y
);
3381 ok
= mouse_released (but
, &x
, &y
);
3384 /* Allow a simultaneous press/release of Mouse-1 and
3385 Mouse-2 to simulate Mouse-3 on two-button mice. */
3386 if (mouse_button_count
== 2 && but
< 2)
3388 int x2
, y2
; /* don't clobber original coordinates */
3390 /* If only one button is pressed, wait 100 msec and
3391 check again. This way, Speedy Gonzales isn't
3392 punished, while the slow get their chance. */
3393 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3394 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3399 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3400 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3405 event
.kind
= MOUSE_CLICK_EVENT
;
3406 event
.code
= button_num
;
3407 event
.modifiers
= dos_get_modifiers (0)
3408 | (press
? down_modifier
: up_modifier
);
3409 event
.x
= make_number (x
);
3410 event
.y
= make_number (y
);
3411 event
.frame_or_window
= selected_frame
;
3413 event
.timestamp
= event_timestamp ();
3414 kbd_buffer_store_event (&event
);
3422 static int prev_get_char
= -1;
3424 /* Return 1 if a key is ready to be read without suspending execution. */
3428 if (prev_get_char
!= -1)
3431 return ((prev_get_char
= dos_rawgetc ()) != -1);
3434 /* Read a key. Return -1 if no key is ready. */
3438 if (prev_get_char
!= -1)
3440 int c
= prev_get_char
;
3445 return dos_rawgetc ();
3448 #ifndef HAVE_X_WINDOWS
3450 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3453 Actually, I don't know the meaning of all the parameters of the functions
3454 here -- I only know how they are called by xmenu.c. I could of course
3455 grab the nearest Xlib manual (down the hall, second-to-last door on the
3456 left), but I don't think it's worth the effort. */
3458 /* These hold text of the current and the previous menu help messages. */
3459 static char *menu_help_message
, *prev_menu_help_message
;
3460 /* Pane number and item number of the menu item which generated the
3461 last menu help message. */
3462 static int menu_help_paneno
, menu_help_itemno
;
3469 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3470 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3474 /* Allocate some (more) memory for MENU ensuring that there is room for one
3478 IT_menu_make_room (XMenu
*menu
)
3480 if (menu
->allocated
== 0)
3482 int count
= menu
->allocated
= 10;
3483 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3484 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3485 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3486 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3488 else if (menu
->allocated
== menu
->count
)
3490 int count
= menu
->allocated
= menu
->allocated
+ 10;
3492 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3494 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3496 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3498 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3502 /* Search the given menu structure for a given pane number. */
3505 IT_menu_search_pane (XMenu
*menu
, int pane
)
3510 for (i
= 0; i
< menu
->count
; i
++)
3511 if (menu
->submenu
[i
])
3513 if (pane
== menu
->panenumber
[i
])
3514 return menu
->submenu
[i
];
3515 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3521 /* Determine how much screen space a given menu needs. */
3524 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3526 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3529 maxheight
= menu
->count
;
3530 for (i
= 0; i
< menu
->count
; i
++)
3532 if (menu
->submenu
[i
])
3534 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3535 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3536 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3539 *width
= menu
->width
+ maxsubwidth
;
3540 *height
= maxheight
;
3543 /* Display MENU at (X,Y) using FACES. */
3545 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3548 (GLYPH).type = CHAR_GLYPH; \
3549 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3550 (GLYPH).charpos = -1; \
3555 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3557 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
3558 struct glyph
*text
, *p
;
3559 const unsigned char *q
;
3560 struct frame
*sf
= SELECTED_FRAME();
3562 menu_help_message
= NULL
;
3564 width
= menu
->width
;
3565 /* We multiply width by 2 to account for possible control characters.
3566 FIXME: cater to non-ASCII characters in menus. */
3567 text
= (struct glyph
*) xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
3568 ScreenGetCursor (&row
, &col
);
3569 mouse_get_xy (&mx
, &my
);
3570 IT_update_begin (sf
);
3571 for (i
= 0; i
< menu
->count
; i
++)
3573 int max_width
= width
+ 2;
3575 IT_cursor_to (sf
, y
+ i
, x
);
3577 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3578 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
3579 face
= faces
[enabled
+ mousehere
* 2];
3580 /* The following if clause means that we display the menu help
3581 strings even if the menu item is currently disabled. */
3582 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3584 menu_help_message
= menu
->help_text
[i
];
3585 menu_help_paneno
= pn
- 1;
3586 menu_help_itemno
= i
;
3589 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3591 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3593 unsigned c
= STRING_CHAR_ADVANCE (q
);
3597 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
3600 else /* make '^x' */
3602 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
3605 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
3609 /* Don't let the menu text overflow into the next screen row. */
3610 if (x
+ max_width
> screen_size_X
)
3612 max_width
= screen_size_X
- x
;
3613 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3615 for (; j
< max_width
- 2; j
++, p
++)
3616 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3618 /* 16 is the character code of a character that on DOS terminal
3619 produces a nice-looking right-pointing arrow glyph. */
3620 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3622 IT_write_glyphs (sf
, text
, max_width
);
3625 IT_cursor_to (sf
, row
, col
);
3629 /* --------------------------- X Menu emulation ---------------------- */
3631 /* Report availability of menus. */
3634 have_menus_p () { return 1; }
3636 /* Create a brand new menu structure. */
3639 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3641 return IT_menu_create ();
3644 /* Create a new pane and place it on the outer-most level. It is not
3645 clear that it should be placed out there, but I don't know what else
3649 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3657 IT_menu_make_room (menu
);
3658 menu
->submenu
[menu
->count
] = IT_menu_create ();
3659 menu
->text
[menu
->count
] = txt
;
3660 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3661 menu
->help_text
[menu
->count
] = NULL
;
3664 /* Adjust length for possible control characters (which will
3665 be written as ^x). */
3666 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3670 if (len
> menu
->width
)
3673 return menu
->panecount
;
3676 /* Create a new item in a menu pane. */
3679 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3680 int foo
, char *txt
, int enable
, char *help_text
)
3686 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3688 IT_menu_make_room (menu
);
3689 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3690 menu
->text
[menu
->count
] = txt
;
3691 menu
->panenumber
[menu
->count
] = enable
;
3692 menu
->help_text
[menu
->count
] = help_text
;
3695 /* Adjust length for possible control characters (which will
3696 be written as ^x). */
3697 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3701 if (len
> menu
->width
)
3707 /* Decide where the menu would be placed if requested at (X,Y). */
3710 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3711 int *ulx
, int *uly
, int *width
, int *height
)
3713 IT_menu_calc_size (menu
, width
, height
);
3719 struct IT_menu_state
3721 void *screen_behind
;
3728 /* Display menu, wait for user's response, and return that response. */
3731 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3732 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3733 void (*help_callback
)(char *, int, int))
3735 struct IT_menu_state
*state
;
3736 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3737 int title_faces
[4]; /* face to display the menu title */
3738 int faces
[4], buffers_num_deleted
= 0;
3739 struct frame
*sf
= SELECTED_FRAME();
3740 Lisp_Object saved_echo_area_message
, selectface
;
3742 /* Just in case we got here without a mouse present... */
3743 if (have_mouse
<= 0)
3744 return XM_IA_SELECT
;
3745 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3746 around the display. */
3752 /* We will process all the mouse events directly, so we had
3753 better prevent dos_rawgetc from stealing them from us. */
3756 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3757 screensize
= screen_size
* 2;
3759 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3760 DEFAULT_FACE_ID
, 1);
3762 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3763 DEFAULT_FACE_ID
, 1);
3764 selectface
= intern ("msdos-menu-select-face");
3765 faces
[2] = lookup_derived_face (sf
, selectface
,
3767 faces
[3] = lookup_derived_face (sf
, selectface
,
3770 /* Make sure the menu title is always displayed with
3771 `msdos-menu-active-face', no matter where the mouse pointer is. */
3772 for (i
= 0; i
< 4; i
++)
3773 title_faces
[i
] = faces
[3];
3777 /* Don't let the title for the "Buffers" popup menu include a
3778 digit (which is ugly).
3780 This is a terrible kludge, but I think the "Buffers" case is
3781 the only one where the title includes a number, so it doesn't
3782 seem to be necessary to make this more general. */
3783 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3785 menu
->text
[0][7] = '\0';
3786 buffers_num_deleted
= 1;
3789 /* We need to save the current echo area message, so that we could
3790 restore it below, before we exit. See the commentary below,
3791 before the call to message_with_string. */
3792 saved_echo_area_message
= Fcurrent_message ();
3793 state
[0].menu
= menu
;
3795 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3797 /* Turn off the cursor. Otherwise it shows through the menu
3798 panes, which is ugly. */
3799 IT_display_cursor (0);
3801 /* Display the menu title. */
3802 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3803 if (buffers_num_deleted
)
3804 menu
->text
[0][7] = ' ';
3805 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3807 menu
->width
= menu
->submenu
[0]->width
;
3808 state
[0].menu
= menu
->submenu
[0];
3812 state
[0].menu
= menu
;
3814 state
[0].x
= x0
- 1;
3816 state
[0].pane
= onepane
;
3818 mouse_last_x
= -1; /* A hack that forces display. */
3822 if (!mouse_visible
) mouse_on ();
3823 mouse_check_moved ();
3824 if (sf
->mouse_moved
)
3826 sf
->mouse_moved
= 0;
3827 result
= XM_IA_SELECT
;
3828 mouse_get_xy (&x
, &y
);
3829 for (i
= 0; i
< statecount
; i
++)
3830 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3832 int dy
= y
- state
[i
].y
;
3833 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3835 if (!state
[i
].menu
->submenu
[dy
])
3836 if (state
[i
].menu
->panenumber
[dy
])
3837 result
= XM_SUCCESS
;
3839 result
= XM_IA_SELECT
;
3840 *pane
= state
[i
].pane
- 1;
3842 /* We hit some part of a menu, so drop extra menus that
3843 have been opened. That does not include an open and
3845 if (i
!= statecount
- 2
3846 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3847 while (i
!= statecount
- 1)
3851 ScreenUpdate (state
[statecount
].screen_behind
);
3852 if (screen_virtual_segment
)
3853 dosv_refresh_virtual_screen (0, screen_size
);
3854 xfree (state
[statecount
].screen_behind
);
3856 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3858 IT_menu_display (state
[i
].menu
,
3863 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3864 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3866 ScreenRetrieve (state
[statecount
].screen_behind
3867 = xmalloc (screensize
));
3869 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3870 state
[statecount
].y
= y
;
3875 IT_menu_display (state
[statecount
- 1].menu
,
3876 state
[statecount
- 1].y
,
3877 state
[statecount
- 1].x
,
3878 state
[statecount
- 1].pane
,
3883 if ((menu_help_message
|| prev_menu_help_message
)
3884 && menu_help_message
!= prev_menu_help_message
)
3886 help_callback (menu_help_message
,
3887 menu_help_paneno
, menu_help_itemno
);
3888 IT_display_cursor (0);
3889 prev_menu_help_message
= menu_help_message
;
3891 /* We are busy-waiting for the mouse to move, so let's be nice
3892 to other Windows applications by releasing our time slice. */
3895 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3897 /* Only leave if user both pressed and released the mouse, and in
3898 that order. This avoids popping down the menu pane unless
3899 the user is really done with it. */
3900 if (mouse_pressed (b
, &x
, &y
))
3902 while (mouse_button_depressed (b
, &x
, &y
))
3906 (void) mouse_released (b
, &x
, &y
);
3911 ScreenUpdate (state
[0].screen_behind
);
3912 if (screen_virtual_segment
)
3913 dosv_refresh_virtual_screen (0, screen_size
);
3915 /* We have a situation here. ScreenUpdate has just restored the
3916 screen contents as it was before we started drawing this menu.
3917 That includes any echo area message that could have been
3918 displayed back then. (In reality, that echo area message will
3919 almost always be the ``keystroke echo'' that echoes the sequence
3920 of menu items chosen by the user.) However, if the menu had some
3921 help messages, then displaying those messages caused Emacs to
3922 forget about the original echo area message. So when
3923 ScreenUpdate restored it, it created a discrepancy between the
3924 actual screen contents and what Emacs internal data structures
3927 To avoid this conflict, we force Emacs to restore the original
3928 echo area message as we found it when we entered this function.
3929 The irony of this is that we then erase the restored message
3930 right away, so the only purpose of restoring it is so that
3931 erasing it works correctly... */
3932 if (! NILP (saved_echo_area_message
))
3933 message_with_string ("%s", saved_echo_area_message
, 0);
3935 while (statecount
--)
3936 xfree (state
[statecount
].screen_behind
);
3937 IT_display_cursor (1); /* turn cursor back on */
3938 /* Clean up any mouse events that are waiting inside Emacs event queue.
3939 These events are likely to be generated before the menu was even
3940 displayed, probably because the user pressed and released the button
3941 (which invoked the menu) too quickly. If we don't remove these events,
3942 Emacs will process them after we return and surprise the user. */
3943 discard_mouse_events ();
3944 mouse_clear_clicks ();
3945 if (!kbd_buffer_events_waiting (1))
3946 clear_input_pending ();
3947 /* Allow mouse events generation by dos_rawgetc. */
3952 /* Dispose of a menu. */
3955 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3958 if (menu
->allocated
)
3960 for (i
= 0; i
< menu
->count
; i
++)
3961 if (menu
->submenu
[i
])
3962 XMenuDestroy (foo
, menu
->submenu
[i
]);
3964 xfree (menu
->submenu
);
3965 xfree (menu
->panenumber
);
3966 xfree (menu
->help_text
);
3969 menu_help_message
= prev_menu_help_message
= NULL
;
3973 x_pixel_width (struct frame
*f
)
3975 return FRAME_COLS (f
);
3979 x_pixel_height (struct frame
*f
)
3981 return FRAME_LINES (f
);
3983 #endif /* !HAVE_X_WINDOWS */
3985 /* ----------------------- DOS / UNIX conversion --------------------- */
3987 void msdos_downcase_filename (unsigned char *);
3989 /* Destructively turn backslashes into slashes. */
3992 dostounix_filename (p
)
3995 msdos_downcase_filename (p
);
4005 /* Destructively turn slashes into backslashes. */
4008 unixtodos_filename (p
)
4011 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4025 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4028 getdefdir (drive
, dst
)
4032 char in_path
[4], *p
= in_path
, e
= errno
;
4034 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4037 *p
++ = drive
+ 'A' - 1;
4044 _fixpath (in_path
, dst
);
4045 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4046 it queries the LFN support, so ignore that error. */
4047 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
4050 msdos_downcase_filename (dst
);
4057 emacs_root_dir (void)
4059 static char root_dir
[4];
4061 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
4062 root_dir
[0] = tolower (root_dir
[0]);
4066 /* Remove all CR's that are followed by a LF. */
4071 register unsigned char *buf
;
4073 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
4077 while (buf
< endp
- 1)
4081 if (*(++buf
) != 0x0a)
4092 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4094 /* In DJGPP v2.0, library `write' can call `malloc', which might
4095 cause relocation of the buffer whose address we get in ADDR.
4096 Here is a version of `write' that avoids calling `malloc',
4097 to serve us until such time as the library is fixed.
4098 Actually, what we define here is called `__write', because
4099 `write' is a stub that just jmp's to `__write' (to be
4100 POSIXLY-correct with respect to the global name-space). */
4102 #include <io.h> /* for _write */
4103 #include <libc/dosio.h> /* for __file_handle_modes[] */
4105 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4107 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4110 __write (int handle
, const void *buffer
, size_t count
)
4115 if(__file_handle_modes
[handle
] & O_BINARY
)
4116 return _write (handle
, buffer
, count
);
4120 const char *bp
= buffer
;
4121 int total_written
= 0;
4122 int nmoved
= 0, ncr
= 0;
4126 /* The next test makes sure there's space for at least 2 more
4127 characters in xbuf[], so both CR and LF can be put there. */
4139 if (xbp
>= XBUF_END
|| !count
)
4141 size_t to_write
= nmoved
+ ncr
;
4142 int written
= _write (handle
, xbuf
, to_write
);
4147 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4149 /* If some, but not all were written (disk full?), return
4150 an estimate of the total written bytes not counting CRs. */
4151 if (written
< to_write
)
4152 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4159 return total_written
;
4163 /* A low-level file-renaming function which works around Windows 95 bug.
4164 This is pulled directly out of DJGPP v2.01 library sources, and only
4165 used when you compile with DJGPP v2.0. */
4169 int _rename(const char *old
, const char *new)
4172 int olen
= strlen(old
) + 1;
4174 int use_lfn
= _USE_LFN
;
4175 char tempfile
[FILENAME_MAX
];
4176 const char *orig
= old
;
4179 r
.x
.dx
= __tb_offset
;
4180 r
.x
.di
= __tb_offset
+ olen
;
4181 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4185 /* Windows 95 bug: for some filenames, when you rename
4186 file -> file~ (as in Emacs, to leave a backup), the
4187 short 8+3 alias doesn't change, which effectively
4188 makes OLD and NEW the same file. We must rename
4189 through a temporary file to work around this. */
4191 char *pbase
= 0, *p
;
4192 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4193 int idx
= sizeof(try_char
) - 1;
4195 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4196 might point to another drive, which will fail the DOS call. */
4197 strcpy(tempfile
, old
);
4198 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4199 if (*p
== '/' || *p
== '\\' || *p
== ':')
4205 strcpy(pbase
, "X$$djren$$.$$temp$$");
4211 *pbase
= try_char
[--idx
];
4212 } while (_chmod(tempfile
, 0) != -1);
4215 _put_path2(tempfile
, olen
);
4217 __dpmi_int(0x21, &r
);
4220 errno
= __doserr_to_errno(r
.x
.ax
);
4224 /* Now create a file with the original name. This will
4225 ensure that NEW will always have a 8+3 alias
4226 different from that of OLD. (Seems to be required
4227 when NameNumericTail in the Registry is set to 0.) */
4228 lfn_fd
= _creat(old
, 0);
4230 olen
= strlen(tempfile
) + 1;
4232 r
.x
.di
= __tb_offset
+ olen
;
4241 _put_path2(new, olen
);
4243 __dpmi_int(0x21, &r
);
4246 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4247 remove(new); /* and try again */
4250 errno
= __doserr_to_errno(r
.x
.ax
);
4252 /* Restore to original name if we renamed it to temporary. */
4260 _put_path2(orig
, olen
);
4261 _put_path(tempfile
);
4263 __dpmi_int(0x21, &r
);
4272 /* Success. Delete the file possibly created to work
4273 around the Windows 95 bug. */
4275 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4279 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4281 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4283 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
4286 return (_USE_LFN
? Qt
: Qnil
);
4289 /* Convert alphabetic characters in a filename to lower-case. */
4292 msdos_downcase_filename (p
)
4293 register unsigned char *p
;
4295 /* Always lower-case drive letters a-z, even if the filesystem
4296 preserves case in filenames.
4297 This is so MSDOS filenames could be compared by string comparison
4298 functions that are case-sensitive. Even case-preserving filesystems
4299 do not distinguish case in drive letters. */
4300 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4306 /* Under LFN we expect to get pathnames in their true case. */
4307 if (NILP (Fmsdos_long_file_names ()))
4309 if (*p
>= 'A' && *p
<= 'Z')
4313 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4315 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
4316 When long filenames are supported, doesn't change FILENAME.
4317 If FILENAME is not a string, returns nil.
4318 The argument object is never altered--the value is a copy. */)
4320 Lisp_Object filename
;
4324 if (! STRINGP (filename
))
4327 tem
= Fcopy_sequence (filename
);
4328 msdos_downcase_filename (SDATA (tem
));
4332 /* The Emacs root directory as determined by init_environment. */
4334 static char emacsroot
[MAXPATHLEN
];
4337 rootrelativepath (rel
)
4340 static char result
[MAXPATHLEN
+ 10];
4342 strcpy (result
, emacsroot
);
4343 strcat (result
, "/");
4344 strcat (result
, rel
);
4348 /* Define a lot of environment variables if not already defined. Don't
4349 remove anything unless you know what you're doing -- lots of code will
4350 break if one or more of these are missing. */
4353 init_environment (argc
, argv
, skip_args
)
4360 static const char * const tempdirs
[] = {
4361 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4363 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4365 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4366 temporary files and assume "/tmp" if $TMPDIR is unset, which
4367 will break on DOS/Windows. Refuse to work if we cannot find
4368 a directory, not even "c:/", usable for that purpose. */
4369 for (i
= 0; i
< imax
; i
++)
4371 const char *tmp
= tempdirs
[i
];
4372 char buf
[FILENAME_MAX
];
4378 tmp
= getenv (tmp
+ 1);
4382 /* Some lusers set TMPDIR=e:, probably because some losing
4383 programs cannot handle multiple slashes if they use e:/.
4384 e: fails in `access' below, so we interpret e: as e:/. */
4385 tmp_len
= strlen(tmp
);
4386 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
4389 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
4394 /* Note that `access' can lie to us if the directory resides on a
4395 read-only filesystem, like CD-ROM or a write-protected floppy.
4396 The only way to be really sure is to actually create a file and
4397 see if it succeeds. But I think that's too much to ask. */
4398 if (tmp
&& access (tmp
, D_OK
) == 0)
4400 setenv ("TMPDIR", tmp
, 1);
4407 Fcons (build_string ("no usable temporary directories found!!"),
4409 "While setting TMPDIR: ");
4411 /* Note the startup time, so we know not to clear the screen if we
4412 exit immediately; see IT_reset_terminal_modes.
4413 (Yes, I know `clock' returns zero the first time it's called, but
4414 I do this anyway, in case some wiseguy changes that at some point.) */
4415 startup_time
= clock ();
4417 /* Find our root from argv[0]. Assuming argv[0] is, say,
4418 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4419 root
= alloca (MAXPATHLEN
+ 20);
4420 _fixpath (argv
[0], root
);
4421 msdos_downcase_filename (root
);
4422 len
= strlen (root
);
4423 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4427 && (strcmp (root
+ len
- 4, "/bin") == 0
4428 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4429 root
[len
- 4] = '\0';
4431 strcpy (root
, "c:/emacs"); /* let's be defensive */
4432 len
= strlen (root
);
4433 strcpy (emacsroot
, root
);
4435 /* We default HOME to our root. */
4436 setenv ("HOME", root
, 0);
4438 /* We default EMACSPATH to root + "/bin". */
4439 strcpy (root
+ len
, "/bin");
4440 setenv ("EMACSPATH", root
, 0);
4442 /* I don't expect anybody to ever use other terminals so the internal
4443 terminal is the default. */
4444 setenv ("TERM", "internal", 0);
4446 #ifdef HAVE_X_WINDOWS
4447 /* Emacs expects DISPLAY to be set. */
4448 setenv ("DISPLAY", "unix:0.0", 0);
4451 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4452 downcase it and mirror the backslashes. */
4453 s
= getenv ("COMSPEC");
4454 if (!s
) s
= "c:/command.com";
4455 t
= alloca (strlen (s
) + 1);
4457 dostounix_filename (t
);
4458 setenv ("SHELL", t
, 0);
4460 /* PATH is also downcased and backslashes mirrored. */
4461 s
= getenv ("PATH");
4463 t
= alloca (strlen (s
) + 3);
4464 /* Current directory is always considered part of MsDos's path but it is
4465 not normally mentioned. Now it is. */
4466 strcat (strcpy (t
, ".;"), s
);
4467 dostounix_filename (t
); /* Not a single file name, but this should work. */
4468 setenv ("PATH", t
, 1);
4470 /* In some sense all dos users have root privileges, so... */
4471 setenv ("USER", "root", 0);
4472 setenv ("NAME", getenv ("USER"), 0);
4474 /* Time zone determined from country code. To make this possible, the
4475 country code may not span more than one time zone. In other words,
4476 in the USA, you lose. */
4478 switch (dos_country_code
)
4480 case 31: /* Belgium */
4481 case 32: /* The Netherlands */
4482 case 33: /* France */
4483 case 34: /* Spain */
4484 case 36: /* Hungary */
4485 case 38: /* Yugoslavia (or what's left of it?) */
4486 case 39: /* Italy */
4487 case 41: /* Switzerland */
4488 case 42: /* Tjekia */
4489 case 45: /* Denmark */
4490 case 46: /* Sweden */
4491 case 47: /* Norway */
4492 case 48: /* Poland */
4493 case 49: /* Germany */
4494 /* Daylight saving from last Sunday in March to last Sunday in
4495 September, both at 2AM. */
4496 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4498 case 44: /* United Kingdom */
4499 case 351: /* Portugal */
4500 case 354: /* Iceland */
4501 setenv ("TZ", "GMT+00", 0);
4503 case 81: /* Japan */
4504 case 82: /* Korea */
4505 setenv ("TZ", "JST-09", 0);
4507 case 90: /* Turkey */
4508 case 358: /* Finland */
4509 setenv ("TZ", "EET-02", 0);
4511 case 972: /* Israel */
4512 /* This is an approximation. (For exact rules, use the
4513 `zoneinfo/israel' file which comes with DJGPP, but you need
4514 to install it in `/usr/share/zoneinfo/' directory first.) */
4515 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4523 static int break_stat
; /* BREAK check mode status. */
4524 static int stdin_stat
; /* stdin IOCTL status. */
4528 /* These must be global. */
4529 static _go32_dpmi_seginfo ctrl_break_vector
;
4530 static _go32_dpmi_registers ctrl_break_regs
;
4531 static int ctrlbreakinstalled
= 0;
4533 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4536 ctrl_break_func (regs
)
4537 _go32_dpmi_registers
*regs
;
4543 install_ctrl_break_check ()
4545 if (!ctrlbreakinstalled
)
4547 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4548 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4549 ctrlbreakinstalled
= 1;
4550 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4551 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4553 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4557 #endif /* __DJGPP__ < 2 */
4559 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4560 control chars by DOS. Determine the keyboard type. */
4563 dos_ttraw (struct tty_display_info
*tty
)
4565 union REGS inregs
, outregs
;
4566 static int first_time
= 1;
4568 /* If we are called for the initial terminal, it's too early to do
4569 anything, and termscript isn't set up. */
4570 if (tty
->terminal
->type
== output_initial
)
4573 break_stat
= getcbrk ();
4576 install_ctrl_break_check ();
4582 int86 (0x15, &inregs
, &outregs
);
4583 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4588 #ifdef HAVE_X_WINDOWS
4589 && inhibit_window_system
4593 inregs
.x
.ax
= 0x0021;
4594 int86 (0x33, &inregs
, &outregs
);
4595 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4598 /* Reportedly, the above doesn't work for some mouse drivers. There
4599 is an additional detection method that should work, but might be
4600 a little slower. Use that as an alternative. */
4601 inregs
.x
.ax
= 0x0000;
4602 int86 (0x33, &inregs
, &outregs
);
4603 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4606 mouse_button_count
= outregs
.x
.bx
;
4608 #ifndef HAVE_X_WINDOWS
4610 /* Save the cursor shape used outside Emacs. */
4611 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4620 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4621 return (stdin_stat
!= -1);
4624 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4626 #else /* __DJGPP__ < 2 */
4630 /* I think it is wrong to overwrite `stdin_stat' every time
4631 but the first one this function is called, but I don't
4632 want to change the way it used to work in v1.x.--EZ */
4634 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4635 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4636 intdos (&inregs
, &outregs
);
4637 stdin_stat
= outregs
.h
.dl
;
4639 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4640 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4641 intdos (&inregs
, &outregs
);
4642 return !outregs
.x
.cflag
;
4644 #endif /* __DJGPP__ < 2 */
4647 /* Restore status of standard input and Ctrl-C checking. */
4652 union REGS inregs
, outregs
;
4654 setcbrk (break_stat
);
4659 #ifndef HAVE_X_WINDOWS
4660 /* Restore the cursor shape we found on startup. */
4664 inregs
.x
.cx
= outside_cursor
;
4665 int86 (0x10, &inregs
, &outregs
);
4669 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4671 #else /* not __DJGPP__ >= 2 */
4673 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4674 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4675 inregs
.x
.dx
= stdin_stat
;
4676 intdos (&inregs
, &outregs
);
4677 return !outregs
.x
.cflag
;
4679 #endif /* not __DJGPP__ >= 2 */
4683 /* Run command as specified by ARGV in directory DIR.
4684 The command is run with input from TEMPIN, output to
4685 file TEMPOUT and stderr to TEMPERR. */
4688 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4689 unsigned char **argv
;
4690 const char *working_dir
;
4691 int tempin
, tempout
, temperr
;
4694 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4695 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4696 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
4699 /* Get current directory as MSDOS cwd is not per-process. */
4702 /* If argv[0] is the shell, it might come in any lettercase.
4703 Since `Fmember' is case-sensitive, we need to downcase
4704 argv[0], even if we are on case-preserving filesystems. */
4705 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4706 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4709 if (*pl
>= 'A' && *pl
<= 'Z')
4714 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4715 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4716 && !strcmp ("-c", argv
[1]);
4719 saveargv1
= argv
[1];
4720 saveargv2
= argv
[2];
4722 /* We only need to mirror slashes if a DOS shell will be invoked
4723 not via `system' (which does the mirroring itself). Yes, that
4724 means DJGPP v1.x will lose here. */
4725 if (argv
[2] && argv
[3])
4727 char *p
= alloca (strlen (argv
[2]) + 1);
4729 strcpy (argv
[2] = p
, saveargv2
);
4730 while (*p
&& isspace (*p
))
4742 chdir (working_dir
);
4746 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4747 goto done
; /* Allocation might fail due to lack of descriptors. */
4750 mouse_get_xy (&x
, &y
);
4752 if (!noninteractive
)
4753 dos_ttcooked (); /* do it here while 0 = stdin */
4761 if (msshell
&& !argv
[3])
4763 /* MS-DOS native shells are too restrictive. For starters, they
4764 cannot grok commands longer than 126 characters. In DJGPP v2
4765 and later, `system' is much smarter, so we'll call it instead. */
4769 /* A shell gets a single argument--its full command
4770 line--whose original was saved in `saveargv2'. */
4772 /* Don't let them pass empty command lines to `system', since
4773 with some shells it will try to invoke an interactive shell,
4774 which will hang Emacs. */
4775 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4779 extern char **environ
;
4780 char **save_env
= environ
;
4781 int save_system_flags
= __system_flags
;
4783 /* Request the most powerful version of `system'. We need
4784 all the help we can get to avoid calling stock DOS shells. */
4785 __system_flags
= (__system_redirect
4786 | __system_use_shell
4787 | __system_allow_multiple_cmds
4788 | __system_allow_long_cmds
4789 | __system_handle_null_commands
4790 | __system_emulate_chdir
);
4793 result
= system (cmnd
);
4794 __system_flags
= save_system_flags
;
4798 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4802 #endif /* __DJGPP__ > 1 */
4804 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4809 emacs_close (inbak
);
4810 emacs_close (outbak
);
4811 emacs_close (errbak
);
4813 if (!noninteractive
)
4814 dos_ttraw (CURTTY ());
4818 mouse_moveto (x
, y
);
4821 /* Some programs might change the meaning of the highest bit of the
4822 text attribute byte, so we get blinking characters instead of the
4823 bright background colors. Restore that. */
4824 if (!noninteractive
)
4831 argv
[1] = saveargv1
;
4832 argv
[2] = saveargv2
;
4841 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4842 reset_all_sys_modes ();
4848 /* ------------------------- Compatibility functions -------------------
4853 /* Hostnames for a pc are not really funny,
4854 but they are used in change log so we emulate the best we can. */
4856 gethostname (p
, size
)
4860 char *q
= egetenv ("HOSTNAME");
4867 /* When time zones are set from Ms-Dos too many C-libraries are playing
4868 tricks with time values. We solve this by defining our own version
4869 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4870 once and after each call to `tzset' with TZ changed. That is
4871 accomplished by aliasing tzset to init_gettimeofday. */
4873 static struct tm time_rec
;
4876 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4884 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4888 time_rec
.tm_year
= d
.da_year
- 1900;
4889 time_rec
.tm_mon
= d
.da_mon
- 1;
4890 time_rec
.tm_mday
= d
.da_day
;
4893 time_rec
.tm_hour
= t
.ti_hour
;
4894 time_rec
.tm_min
= t
.ti_min
;
4895 time_rec
.tm_sec
= t
.ti_sec
;
4898 tm
.tm_gmtoff
= dos_timezone_offset
;
4900 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4901 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4903 /* Ignore tzp; it's obsolescent. */
4907 #endif /* __DJGPP__ < 2 */
4910 * A list of unimplemented functions that we silently ignore.
4914 unsigned alarm (s
) unsigned s
; {}
4915 fork () { return 0; }
4916 int kill (x
, y
) int x
, y
; { return -1; }
4918 void volatile pause () {}
4919 sigsetmask (x
) int x
; { return 0; }
4920 sigblock (mask
) int mask
; { return 0; }
4923 setpgrp () {return 0; }
4924 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4927 #if __DJGPP_MINOR__ < 2
4929 #ifdef POSIX_SIGNALS
4931 /* Augment DJGPP library POSIX signal functions. This is needed
4932 as of DJGPP v2.01, but might be in the library in later releases. */
4934 #include <libc/bss.h>
4936 /* A counter to know when to re-initialize the static sets. */
4937 static int sigprocmask_count
= -1;
4939 /* Which signals are currently blocked (initially none). */
4940 static sigset_t current_mask
;
4942 /* Which signals are pending (initially none). */
4943 static sigset_t pending_signals
;
4945 /* Previous handlers to restore when the blocked signals are unblocked. */
4946 typedef void (*sighandler_t
)(int);
4947 static sighandler_t prev_handlers
[320];
4949 /* A signal handler which just records that a signal occurred
4950 (it will be raised later, if and when the signal is unblocked). */
4952 sig_suspender (signo
)
4955 sigaddset (&pending_signals
, signo
);
4959 sigprocmask (how
, new_set
, old_set
)
4961 const sigset_t
*new_set
;
4967 /* If called for the first time, initialize. */
4968 if (sigprocmask_count
!= __bss_count
)
4970 sigprocmask_count
= __bss_count
;
4971 sigemptyset (&pending_signals
);
4972 sigemptyset (¤t_mask
);
4973 for (signo
= 0; signo
< 320; signo
++)
4974 prev_handlers
[signo
] = SIG_ERR
;
4978 *old_set
= current_mask
;
4983 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4989 sigemptyset (&new_mask
);
4991 /* DJGPP supports upto 320 signals. */
4992 for (signo
= 0; signo
< 320; signo
++)
4994 if (sigismember (¤t_mask
, signo
))
4995 sigaddset (&new_mask
, signo
);
4996 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4998 sigaddset (&new_mask
, signo
);
5000 /* SIGKILL is silently ignored, as on other platforms. */
5001 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
5002 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
5004 if (( how
== SIG_UNBLOCK
5005 && sigismember (&new_mask
, signo
)
5006 && sigismember (new_set
, signo
))
5007 || (how
== SIG_SETMASK
5008 && sigismember (&new_mask
, signo
)
5009 && !sigismember (new_set
, signo
)))
5011 sigdelset (&new_mask
, signo
);
5012 if (prev_handlers
[signo
] != SIG_ERR
)
5014 signal (signo
, prev_handlers
[signo
]);
5015 prev_handlers
[signo
] = SIG_ERR
;
5017 if (sigismember (&pending_signals
, signo
))
5019 sigdelset (&pending_signals
, signo
);
5024 current_mask
= new_mask
;
5028 #else /* not POSIX_SIGNALS */
5030 sigsetmask (x
) int x
; { return 0; }
5031 sigblock (mask
) int mask
; { return 0; }
5033 #endif /* not POSIX_SIGNALS */
5034 #endif /* not __DJGPP_MINOR__ < 2 */
5035 #endif /* __DJGPP__ > 1 */
5038 #include "sysselect.h"
5040 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5041 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5042 ((long)(time).tv_sec < 0 \
5043 || ((time).tv_sec == 0 \
5044 && (long)(time).tv_usec <= 0))
5047 /* This yields the rest of the current time slice to the task manager.
5048 It should be called by any code which knows that it has nothing
5049 useful to do except idle.
5051 I don't use __dpmi_yield here, since versions of library before 2.02
5052 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5053 on some versions of Windows 9X. */
5056 dos_yield_time_slice (void)
5058 _go32_dpmi_registers r
;
5061 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
5062 _go32_dpmi_simulate_int (0x2f, &r
);
5067 /* Only event queue is checked. */
5068 /* We don't have to call timer_check here
5069 because wait_reading_process_output takes care of that. */
5071 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5073 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5074 EMACS_TIME
*timeout
;
5082 check_input
= FD_ISSET (0, rfds
);
5093 /* If we are looking only for the terminal, with no timeout,
5094 just read it and wait -- that's more efficient. */
5097 while (!detect_input_pending ())
5099 dos_yield_time_slice ();
5104 EMACS_TIME clnow
, cllast
, cldiff
;
5107 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5109 while (!check_input
|| !detect_input_pending ())
5112 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5113 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5115 /* When seconds wrap around, we assume that no more than
5116 1 minute passed since last `gettime'. */
5117 if (EMACS_TIME_NEG_P (cldiff
))
5118 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5119 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5121 /* Stop when timeout value crosses zero. */
5122 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5125 dos_yield_time_slice ();
5135 * Define overlaid functions:
5137 * chdir -> sys_chdir
5138 * tzset -> init_gettimeofday
5139 * abort -> dos_abort
5144 extern int chdir ();
5150 int len
= strlen (path
);
5151 char *tmp
= (char *)path
;
5153 if (*tmp
&& tmp
[1] == ':')
5155 if (getdisk () != tolower (tmp
[0]) - 'a')
5156 setdisk (tolower (tmp
[0]) - 'a');
5157 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5161 if (len
> 1 && (tmp
[len
- 1] == '/'))
5163 char *tmp1
= (char *) alloca (len
+ 1);
5174 extern void tzset (void);
5177 init_gettimeofday ()
5183 ltm
= gtm
= time (NULL
);
5184 ltm
= mktime (lstm
= localtime (<m
));
5185 gtm
= mktime (gmtime (>m
));
5186 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5187 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5188 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5195 dos_abort (file
, line
)
5199 char buffer1
[200], buffer2
[400];
5202 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5203 for (i
= j
= 0; buffer1
[i
]; i
++) {
5204 buffer2
[j
++] = buffer1
[i
];
5205 buffer2
[j
++] = 0x70;
5207 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5208 ScreenSetCursor (2, 0);
5216 ScreenSetCursor (10, 0);
5217 cputs ("\r\n\nEmacs aborted!\r\n");
5219 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5220 if (screen_virtual_segment
)
5221 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5222 /* Generate traceback, so we could tell whodunit. */
5223 signal (SIGINT
, SIG_DFL
);
5224 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5225 #else /* __DJGPP_MINOR__ >= 2 */
5227 #endif /* __DJGPP_MINOR__ >= 2 */
5233 /* The following variables are required so that cus-start.el won't
5234 complain about unbound variables. */
5235 #ifndef subprocesses
5236 /* Nonzero means delete a process right away if it exits (process.c). */
5237 static int delete_exited_processes
;
5242 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5243 staticpro (&recent_doskeys
);
5245 #ifndef HAVE_X_WINDOWS
5247 /* The following two are from xfns.c: */
5248 Qreverse
= intern ("reverse");
5249 staticpro (&Qreverse
);
5251 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5252 doc
: /* *Glyph to display instead of chars not supported by current codepage.
5253 This variable is used only by MS-DOS terminals. */);
5254 Vdos_unsupported_char_glyph
= make_number ('\177');
5257 #ifndef subprocesses
5258 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5259 doc
: /* *Non-nil means delete processes immediately when they exit.
5260 A value of nil means don't delete them until `list-processes' is run. */);
5261 delete_exited_processes
= 0;
5264 defsubr (&Srecent_doskeys
);
5265 defsubr (&Smsdos_long_file_names
);
5266 defsubr (&Smsdos_downcase_filename
);
5267 defsubr (&Smsdos_remember_default_colors
);
5268 defsubr (&Smsdos_set_mouse_buttons
);
5273 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5274 (do not change this comment) */