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 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
961 width of a DOS display in any known text mode. We multiply by 2 to
962 accomodate the screen attribute byte. */
963 #define MAX_SCREEN_BUF 160*2
965 Lisp_Object Vdos_unsupported_char_glyph
;
966 extern unsigned char *encode_terminal_code (struct glyph
*, int,
967 struct coding_system
*);
969 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
971 unsigned char screen_buf
[MAX_SCREEN_BUF
], *screen_bp
, *bp
;
972 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
973 register int sl
= str_len
;
974 struct tty_display_info
*tty
= FRAME_TTY (f
);
976 unsigned char *conversion_buffer
;
978 /* Do we need to consider conversion of unibyte characters to
980 int convert_unibyte_characters
981 = (NILP (current_buffer
->enable_multibyte_characters
)
982 && unibyte_display_via_language_environment
);
984 /* If terminal_coding does any conversion, use it, otherwise use
985 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
986 because it always returns 1 if terminal_coding.src_multibyte is 1. */
987 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
989 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
990 coding
= &safe_terminal_coding
;
992 if (str_len
<= 0) return;
994 sf
= SELECTED_FRAME();
996 /* Since faces get cached and uncached behind our back, we can't
997 rely on their indices in the cache being consistent across
998 invocations. So always reset the screen face to the default
999 face of the frame, before writing glyphs, and let the glyphs
1000 set the right face if it's different from the default. */
1001 IT_set_face (DEFAULT_FACE_ID
);
1003 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1005 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
1006 screen_bp
= &screen_buf
[0];
1012 /* If the face of this glyph is different from the current
1013 screen face, update the screen attribute byte. */
1015 if (cf
!= screen_face
)
1016 IT_set_face (cf
); /* handles invalid faces gracefully */
1018 /* Identify a run of glyphs with the same face. */
1019 for (n
= 1; n
< sl
; ++n
)
1020 if (str
[n
].face_id
!= cf
)
1024 /* This is the last glyph. */
1025 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1027 conversion_buffer
= encode_terminal_code (str
, n
, coding
);
1028 if (coding
->produced
> 0)
1030 /* Copy the encoded bytes to the screen buffer. */
1031 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
1033 /* Paranoia: discard bytes that would overrun the end of
1034 the screen buffer. */
1035 if (screen_bp
- screen_buf
<= MAX_SCREEN_BUF
- 2)
1037 *screen_bp
++ = (unsigned char)*bp
;
1038 *screen_bp
++ = ScreenAttrib
;
1040 if (tty
->termscript
)
1041 fputc (*bp
, tty
->termscript
);
1044 /* Update STR and its remaining length. */
1049 /* Dump whatever we have in the screen buffer. */
1051 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1052 if (screen_virtual_segment
)
1053 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1054 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1057 /************************************************************************
1058 Mouse Highlight (and friends..)
1059 ************************************************************************/
1061 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1062 static Lisp_Object last_mouse_window
;
1064 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1066 /* Set the mouse pointer shape according to whether it is in the
1067 area where the mouse highlight is in effect. */
1069 IT_set_mouse_pointer (int mode
)
1071 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1072 many possibilities to change its shape, and the available
1073 functionality pretty much sucks (e.g., almost every reasonable
1074 shape will conceal the character it is on). Since the color of
1075 the pointer changes in the highlighted area, it is not clear to
1076 me whether anything else is required, anyway. */
1079 /* Display the active region described by mouse_face_*
1080 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1082 show_mouse_face (struct tty_display_info
*dpyinfo
, int hl
)
1084 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1085 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1088 struct tty_display_info
*tty
= FRAME_TTY (f
);
1091 /* If window is in the process of being destroyed, don't bother
1093 if (w
->current_matrix
== NULL
)
1094 goto set_cursor_shape
;
1096 /* Recognize when we are called to operate on rows that don't exist
1097 anymore. This can happen when a window is split. */
1098 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1099 goto set_cursor_shape
;
1101 /* There's no sense to do anything if the mouse face isn't realized. */
1104 if (dpyinfo
->mouse_face_hidden
)
1105 goto set_cursor_shape
;
1107 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1109 goto set_cursor_shape
;
1112 /* Note that mouse_face_beg_row etc. are window relative. */
1113 for (i
= dpyinfo
->mouse_face_beg_row
;
1114 i
<= dpyinfo
->mouse_face_end_row
;
1117 int start_hpos
, end_hpos
;
1118 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1120 /* Don't do anything if row doesn't have valid contents. */
1121 if (!row
->enabled_p
)
1124 /* For all but the first row, the highlight starts at column 0. */
1125 if (i
== dpyinfo
->mouse_face_beg_row
)
1126 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1130 if (i
== dpyinfo
->mouse_face_end_row
)
1131 end_hpos
= dpyinfo
->mouse_face_end_col
;
1133 end_hpos
= row
->used
[TEXT_AREA
];
1135 if (end_hpos
<= start_hpos
)
1137 /* Record that some glyphs of this row are displayed in
1139 row
->mouse_face_p
= hl
> 0;
1142 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1143 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1144 int nglyphs
= end_hpos
- start_hpos
;
1145 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1146 int start_offset
= offset
;
1148 if (tty
->termscript
)
1149 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
1150 kstart
, kstart
+ nglyphs
- 1, vpos
);
1153 IT_set_face (dpyinfo
->mouse_face_face_id
);
1154 /* Since we are going to change only the _colors_ of the
1155 displayed text, there's no need to go through all the
1156 pain of generating and encoding the text from the glyphs.
1157 Instead, we simply poke the attribute byte of each
1158 affected position in video memory with the colors
1159 computed by IT_set_face! */
1160 _farsetsel (_dos_ds
);
1163 _farnspokeb (offset
, ScreenAttrib
);
1166 if (screen_virtual_segment
)
1167 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1172 /* We are removing a previously-drawn mouse highlight. The
1173 safest way to do so is to redraw the glyphs anew, since
1174 all kinds of faces and display tables could have changed
1176 int nglyphs
= end_hpos
- start_hpos
;
1177 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1179 if (end_hpos
>= row
->used
[TEXT_AREA
])
1180 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1182 /* IT_write_glyphs writes at cursor position, so we need to
1183 temporarily move cursor coordinates to the beginning of
1184 the highlight region. */
1185 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1186 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1188 if (tty
->termscript
)
1189 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1190 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1191 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1192 if (tty
->termscript
)
1193 fputs ("\n", tty
->termscript
);
1200 /* Change the mouse pointer shape. */
1201 IT_set_mouse_pointer (hl
);
1204 /* Clear out the mouse-highlighted active region.
1205 Redraw it un-highlighted first. */
1207 clear_mouse_face (struct tty_display_info
*dpyinfo
)
1209 if (!dpyinfo
->mouse_face_hidden
&& ! NILP (dpyinfo
->mouse_face_window
))
1210 show_mouse_face (dpyinfo
, 0);
1212 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1213 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1214 dpyinfo
->mouse_face_window
= Qnil
;
1217 /* Find the glyph matrix position of buffer position POS in window W.
1218 *HPOS and *VPOS are set to the positions found. W's current glyphs
1219 must be up to date. If POS is above window start return (0, 0).
1220 If POS is after end of W, return end of last line in W. */
1222 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1224 int i
, lastcol
, line_start_position
, maybe_next_line_p
= 0;
1225 int yb
= window_text_bottom_y (w
);
1226 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0), *best_row
= row
;
1230 if (row
->used
[TEXT_AREA
])
1231 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1233 line_start_position
= 0;
1235 if (line_start_position
> pos
)
1237 /* If the position sought is the end of the buffer,
1238 don't include the blank lines at the bottom of the window. */
1239 else if (line_start_position
== pos
1240 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1242 maybe_next_line_p
= 1;
1245 else if (line_start_position
> 0)
1248 /* Don't overstep the last matrix row, lest we get into the
1249 never-never land... */
1250 if (row
->y
+ 1 >= yb
)
1256 /* Find the right column within BEST_ROW. */
1259 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1261 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1264 charpos
= glyph
->charpos
;
1271 else if (charpos
> pos
)
1273 else if (charpos
> 0)
1277 /* If we're looking for the end of the buffer,
1278 and we didn't find it in the line we scanned,
1279 use the start of the following line. */
1280 if (maybe_next_line_p
)
1287 *hpos
= lastcol
+ 1;
1291 /* Take proper action when mouse has moved to the mode or top line of
1292 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1293 mode line. X is relative to the start of the text display area of
1294 W, so the width of fringes and scroll bars must be subtracted
1295 to get a position relative to the start of the mode line. */
1297 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1299 struct frame
*f
= XFRAME (w
->frame
);
1300 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1301 struct glyph_row
*row
;
1304 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1306 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1310 extern Lisp_Object Qhelp_echo
;
1311 struct glyph
*glyph
, *end
;
1312 Lisp_Object help
, map
;
1314 /* Find the glyph under X. */
1315 glyph
= (row
->glyphs
[TEXT_AREA
]
1317 /* in case someone implements scroll bars some day... */
1318 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w
));
1319 end
= glyph
+ row
->used
[TEXT_AREA
];
1321 && STRINGP (glyph
->object
)
1322 && STRING_INTERVALS (glyph
->object
)
1323 && glyph
->charpos
>= 0
1324 && glyph
->charpos
< SCHARS (glyph
->object
))
1326 /* If we're on a string with `help-echo' text property,
1327 arrange for the help to be displayed. This is done by
1328 setting the global variable help_echo to the help string. */
1329 help
= Fget_text_property (make_number (glyph
->charpos
),
1330 Qhelp_echo
, glyph
->object
);
1333 help_echo_string
= help
;
1334 XSETWINDOW (help_echo_window
, w
);
1335 help_echo_object
= glyph
->object
;
1336 help_echo_pos
= glyph
->charpos
;
1342 /* Take proper action when the mouse has moved to position X, Y on
1343 frame F as regards highlighting characters that have mouse-face
1344 properties. Also de-highlighting chars where the mouse was before.
1345 X and Y can be negative or out of range. */
1347 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1349 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1350 enum window_part part
= ON_NOTHING
;
1354 /* When a menu is active, don't highlight because this looks odd. */
1355 if (mouse_preempted
)
1358 if (NILP (Vmouse_highlight
)
1359 || !f
->glyphs_initialized_p
)
1362 dpyinfo
->mouse_face_mouse_x
= x
;
1363 dpyinfo
->mouse_face_mouse_y
= y
;
1364 dpyinfo
->mouse_face_mouse_frame
= f
;
1366 if (dpyinfo
->mouse_face_defer
)
1371 dpyinfo
->mouse_face_deferred_gc
= 1;
1375 /* Which window is that in? */
1376 window
= window_from_coordinates (f
, x
, y
, &part
, &x
, &y
, 0);
1378 /* If we were displaying active text in another window, clear that. */
1379 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1380 clear_mouse_face (dpyinfo
);
1382 /* Not on a window -> return. */
1383 if (!WINDOWP (window
))
1386 /* Convert to window-relative coordinates. */
1387 w
= XWINDOW (window
);
1389 if (part
== ON_MODE_LINE
|| part
== ON_HEADER_LINE
)
1391 /* Mouse is on the mode or top line. */
1392 IT_note_mode_line_highlight (w
, x
, part
== ON_MODE_LINE
);
1396 IT_set_mouse_pointer (0);
1398 /* Are we in a window whose display is up to date?
1399 And verify the buffer's text has not changed. */
1401 && EQ (w
->window_end_valid
, w
->buffer
)
1402 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1403 && (XFASTINT (w
->last_overlay_modified
)
1404 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1406 int pos
, i
, nrows
= w
->current_matrix
->nrows
;
1407 struct glyph_row
*row
;
1408 struct glyph
*glyph
;
1410 /* Find the glyph under X/Y. */
1412 if (y
>= 0 && y
< nrows
)
1414 row
= MATRIX_ROW (w
->current_matrix
, y
);
1415 /* Give up if some row before the one we are looking for is
1417 for (i
= 0; i
<= y
; i
++)
1418 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1420 if (i
> y
/* all rows upto and including the one at Y are enabled */
1421 && row
->displays_text_p
1422 && x
< window_box_width (w
, TEXT_AREA
))
1424 glyph
= row
->glyphs
[TEXT_AREA
];
1425 if (x
>= row
->used
[TEXT_AREA
])
1430 if (!BUFFERP (glyph
->object
))
1436 /* Clear mouse face if X/Y not over text. */
1439 clear_mouse_face (dpyinfo
);
1443 if (!BUFFERP (glyph
->object
))
1445 pos
= glyph
->charpos
;
1447 /* Check for mouse-face and help-echo. */
1449 extern Lisp_Object Qmouse_face
;
1450 Lisp_Object mouse_face
, overlay
, position
, *overlay_vec
;
1451 int noverlays
, obegv
, ozv
;
1452 struct buffer
*obuf
;
1454 /* If we get an out-of-range value, return now; avoid an error. */
1455 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1458 /* Make the window's buffer temporarily current for
1459 overlays_at and compute_char_face. */
1460 obuf
= current_buffer
;
1461 current_buffer
= XBUFFER (w
->buffer
);
1467 /* Is this char mouse-active or does it have help-echo? */
1468 XSETINT (position
, pos
);
1470 /* Put all the overlays we want in a vector in overlay_vec. */
1471 GET_OVERLAYS_AT (pos
, overlay_vec
, noverlays
, NULL
, 0);
1472 /* Sort overlays into increasing priority order. */
1473 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1475 /* Check mouse-face highlighting. */
1476 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1477 && y
>= dpyinfo
->mouse_face_beg_row
1478 && y
<= dpyinfo
->mouse_face_end_row
1479 && (y
> dpyinfo
->mouse_face_beg_row
1480 || x
>= dpyinfo
->mouse_face_beg_col
)
1481 && (y
< dpyinfo
->mouse_face_end_row
1482 || x
< dpyinfo
->mouse_face_end_col
1483 || dpyinfo
->mouse_face_past_end
)))
1485 /* Clear the display of the old active region, if any. */
1486 clear_mouse_face (dpyinfo
);
1488 /* Find highest priority overlay that has a mouse-face prop. */
1490 for (i
= noverlays
- 1; i
>= 0; --i
)
1492 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1493 if (!NILP (mouse_face
))
1495 overlay
= overlay_vec
[i
];
1500 /* If no overlay applies, get a text property. */
1502 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1505 /* Handle the overlay case. */
1506 if (! NILP (overlay
))
1508 /* Find the range of text around this char that
1509 should be active. */
1510 Lisp_Object before
, after
;
1513 before
= Foverlay_start (overlay
);
1514 after
= Foverlay_end (overlay
);
1515 /* Record this as the current active region. */
1516 fast_find_position (w
, XFASTINT (before
),
1517 &dpyinfo
->mouse_face_beg_col
,
1518 &dpyinfo
->mouse_face_beg_row
);
1519 dpyinfo
->mouse_face_past_end
1520 = !fast_find_position (w
, XFASTINT (after
),
1521 &dpyinfo
->mouse_face_end_col
,
1522 &dpyinfo
->mouse_face_end_row
);
1523 dpyinfo
->mouse_face_window
= window
;
1524 dpyinfo
->mouse_face_face_id
1525 = face_at_buffer_position (w
, pos
, 0, 0,
1527 !dpyinfo
->mouse_face_hidden
);
1529 /* Display it as active. */
1530 show_mouse_face (dpyinfo
, 1);
1532 /* Handle the text property case. */
1533 else if (! NILP (mouse_face
))
1535 /* Find the range of text around this char that
1536 should be active. */
1537 Lisp_Object before
, after
, beginning
, end
;
1540 beginning
= Fmarker_position (w
->start
);
1541 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1542 - XFASTINT (w
->window_end_pos
)));
1544 = Fprevious_single_property_change (make_number (pos
+ 1),
1546 w
->buffer
, beginning
);
1548 = Fnext_single_property_change (position
, Qmouse_face
,
1550 /* Record this as the current active region. */
1551 fast_find_position (w
, XFASTINT (before
),
1552 &dpyinfo
->mouse_face_beg_col
,
1553 &dpyinfo
->mouse_face_beg_row
);
1554 dpyinfo
->mouse_face_past_end
1555 = !fast_find_position (w
, XFASTINT (after
),
1556 &dpyinfo
->mouse_face_end_col
,
1557 &dpyinfo
->mouse_face_end_row
);
1558 dpyinfo
->mouse_face_window
= window
;
1559 dpyinfo
->mouse_face_face_id
1560 = face_at_buffer_position (w
, pos
, 0, 0,
1562 !dpyinfo
->mouse_face_hidden
);
1564 /* Display it as active. */
1565 show_mouse_face (dpyinfo
, 1);
1569 /* Look for a `help-echo' property. */
1572 extern Lisp_Object Qhelp_echo
;
1574 /* Check overlays first. */
1576 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1578 overlay
= overlay_vec
[i
];
1579 help
= Foverlay_get (overlay
, Qhelp_echo
);
1584 help_echo_string
= help
;
1585 help_echo_window
= window
;
1586 help_echo_object
= overlay
;
1587 help_echo_pos
= pos
;
1589 /* Try text properties. */
1590 else if (NILP (help
)
1591 && ((STRINGP (glyph
->object
)
1592 && glyph
->charpos
>= 0
1593 && glyph
->charpos
< SCHARS (glyph
->object
))
1594 || (BUFFERP (glyph
->object
)
1595 && glyph
->charpos
>= BEGV
1596 && glyph
->charpos
< ZV
)))
1598 help
= Fget_text_property (make_number (glyph
->charpos
),
1599 Qhelp_echo
, glyph
->object
);
1602 help_echo_string
= help
;
1603 help_echo_window
= window
;
1604 help_echo_object
= glyph
->object
;
1605 help_echo_pos
= glyph
->charpos
;
1612 current_buffer
= obuf
;
1618 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1621 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1622 extern int fatal_error_in_progress
;
1623 struct tty_display_info
*tty
= FRAME_TTY (f
);
1625 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1629 i
= (j
= first_unused
- new_pos_X
) * 2;
1630 if (tty
->termscript
)
1631 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1632 spaces
= sp
= alloca (i
);
1637 *sp
++ = ScreenAttrib
;
1641 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1642 if (screen_virtual_segment
)
1643 dosv_refresh_virtual_screen (offset
, i
/ 2);
1645 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1646 Let's follow their lead, in case someone relies on this. */
1647 new_pos_X
= first_unused
;
1651 IT_clear_screen (struct frame
*f
)
1653 struct tty_display_info
*tty
= FRAME_TTY (f
);
1655 if (tty
->termscript
)
1656 fprintf (tty
->termscript
, "<CLR:SCR>");
1657 /* We are sometimes called (from clear_garbaged_frames) when a new
1658 frame is being created, but its faces are not yet realized. In
1659 such a case we cannot call IT_set_face, since it will fail to find
1660 any valid faces and will abort. Instead, use the initial screen
1661 colors; that should mimic what a Unix tty does, which simply clears
1662 the screen with whatever default colors are in use. */
1663 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1664 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1669 if (screen_virtual_segment
)
1670 dosv_refresh_virtual_screen (0, screen_size
);
1671 new_pos_X
= new_pos_Y
= 0;
1675 IT_clear_to_end (struct frame
*f
)
1677 struct tty_display_info
*tty
= FRAME_TTY (f
);
1679 if (tty
->termscript
)
1680 fprintf (tty
->termscript
, "<CLR:EOS>");
1682 while (new_pos_Y
< screen_size_Y
) {
1684 IT_clear_end_of_line (f
, screen_size_X
);
1690 IT_cursor_to (struct frame
*f
, int y
, int x
)
1692 struct tty_display_info
*tty
= FRAME_TTY (f
);
1694 if (tty
->termscript
)
1695 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1700 static int cursor_cleared
;
1703 IT_display_cursor (int on
)
1705 struct tty_display_info
*tty
= CURTTY ();
1707 if (on
&& cursor_cleared
)
1709 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1711 if (tty
->termscript
)
1712 fprintf (tty
->termscript
, "\nCURSOR ON");
1714 else if (!on
&& !cursor_cleared
)
1716 ScreenSetCursor (-1, -1);
1718 if (tty
->termscript
)
1719 fprintf (tty
->termscript
, "\nCURSOR OFF");
1723 /* Emacs calls cursor-movement functions a lot when it updates the
1724 display (probably a legacy of old terminals where you cannot
1725 update a screen line without first moving the cursor there).
1726 However, cursor movement is expensive on MSDOS (it calls a slow
1727 BIOS function and requires 2 mode switches), while actual screen
1728 updates access the video memory directly and don't depend on
1729 cursor position. To avoid slowing down the redisplay, we cheat:
1730 all functions that move the cursor only set internal variables
1731 which record the cursor position, whereas the cursor is only
1732 moved to its final position whenever screen update is complete.
1734 `IT_cmgoto' is called from the keyboard reading loop and when the
1735 frame update is complete. This means that we are ready for user
1736 input, so we update the cursor position to show where the point is,
1737 and also make the mouse pointer visible.
1739 Special treatment is required when the cursor is in the echo area,
1740 to put the cursor at the end of the text displayed there. */
1743 IT_cmgoto (FRAME_PTR f
)
1745 /* Only set the cursor to where it should be if the display is
1746 already in sync with the window contents. */
1747 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1748 struct tty_display_info
*tty
= FRAME_TTY (f
);
1750 /* FIXME: This needs to be rewritten for the new redisplay, or
1753 static int previous_pos_X
= -1;
1755 update_cursor_pos
= 1; /* temporary!!! */
1757 /* If the display is in sync, forget any previous knowledge about
1758 cursor position. This is primarily for unexpected events like
1759 C-g in the minibuffer. */
1760 if (update_cursor_pos
&& previous_pos_X
>= 0)
1761 previous_pos_X
= -1;
1762 /* If we are in the echo area, put the cursor at the
1763 end of the echo area message. */
1764 if (!update_cursor_pos
1765 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1767 int tem_X
= current_pos_X
, dummy
;
1769 if (echo_area_glyphs
)
1771 tem_X
= echo_area_glyphs_length
;
1772 /* Save current cursor position, to be restored after the
1773 echo area message is erased. Only remember one level
1774 of previous cursor position. */
1775 if (previous_pos_X
== -1)
1776 ScreenGetCursor (&dummy
, &previous_pos_X
);
1778 else if (previous_pos_X
>= 0)
1780 /* We wind up here after the echo area message is erased.
1781 Restore the cursor position we remembered above. */
1782 tem_X
= previous_pos_X
;
1783 previous_pos_X
= -1;
1786 if (current_pos_X
!= tem_X
)
1789 update_cursor_pos
= 1;
1794 if (update_cursor_pos
1795 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1797 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1798 if (tty
->termscript
)
1799 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1802 /* Maybe cursor is invisible, so make it visible. */
1803 IT_display_cursor (1);
1805 /* Mouse pointer should be always visible if we are waiting for
1812 IT_update_begin (struct frame
*f
)
1814 struct tty_display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1815 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1817 if (display_info
->termscript
)
1818 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1822 if (f
&& f
== mouse_face_frame
)
1824 /* Don't do highlighting for mouse motion during the update. */
1825 display_info
->mouse_face_defer
= 1;
1827 /* If F needs to be redrawn, simply forget about any prior mouse
1829 if (FRAME_GARBAGED_P (f
))
1830 display_info
->mouse_face_window
= Qnil
;
1832 /* Can we tell that this update does not affect the window
1833 where the mouse highlight is? If so, no need to turn off.
1834 Likewise, don't do anything if none of the enabled rows
1835 contains glyphs highlighted in mouse face. */
1836 if (!NILP (display_info
->mouse_face_window
)
1837 && WINDOWP (display_info
->mouse_face_window
))
1839 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1842 /* If the mouse highlight is in the window that was deleted
1843 (e.g., if it was popped by completion), clear highlight
1845 if (NILP (w
->buffer
))
1846 display_info
->mouse_face_window
= Qnil
;
1849 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1850 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1851 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1855 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1856 clear_mouse_face (display_info
);
1859 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1861 /* If the frame with mouse highlight was deleted, invalidate the
1863 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1864 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1865 display_info
->mouse_face_window
= Qnil
;
1866 display_info
->mouse_face_deferred_gc
= 0;
1867 display_info
->mouse_face_mouse_frame
= NULL
;
1874 IT_update_end (struct frame
*f
)
1876 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1878 if (dpyinfo
->termscript
)
1879 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1880 dpyinfo
->mouse_face_defer
= 0;
1884 IT_frame_up_to_date (struct frame
*f
)
1886 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1887 Lisp_Object new_cursor
, frame_desired_cursor
;
1890 if (dpyinfo
->mouse_face_deferred_gc
1891 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
1894 if (dpyinfo
->mouse_face_mouse_frame
)
1895 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1896 dpyinfo
->mouse_face_mouse_x
,
1897 dpyinfo
->mouse_face_mouse_y
);
1898 dpyinfo
->mouse_face_deferred_gc
= 0;
1902 /* Set the cursor type to whatever they wanted. In a minibuffer
1903 window, we want the cursor to appear only if we are reading input
1904 from this window, and we want the cursor to be taken from the
1905 frame parameters. For the selected window, we use either its
1906 buffer-local value or the value from the frame parameters if the
1907 buffer doesn't define its local value for the cursor type. */
1908 sw
= XWINDOW (f
->selected_window
);
1909 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1910 if (cursor_in_echo_area
1911 && FRAME_HAS_MINIBUF_P (f
)
1912 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1913 && sw
== XWINDOW (echo_area_window
))
1914 new_cursor
= frame_desired_cursor
;
1917 struct buffer
*b
= XBUFFER (sw
->buffer
);
1919 if (EQ (b
->cursor_type
, Qt
))
1920 new_cursor
= frame_desired_cursor
;
1921 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1922 new_cursor
= Fcons (Qbar
, make_number (0));
1924 new_cursor
= b
->cursor_type
;
1927 IT_set_cursor_type (f
, new_cursor
);
1929 IT_cmgoto (f
); /* position cursor when update is done */
1932 /* Copy LEN glyphs displayed on a single line whose vertical position
1933 is YPOS, beginning at horizontal position XFROM to horizontal
1934 position XTO, by moving blocks in the video memory. Used by
1935 functions that insert and delete glyphs. */
1937 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1939 /* The offsets of source and destination relative to the
1940 conventional memorty selector. */
1941 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1942 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1944 if (from
== to
|| len
<= 0)
1947 _farsetsel (_dos_ds
);
1949 /* The source and destination might overlap, so we need to move
1950 glyphs non-destructively. */
1953 for ( ; len
; from
+= 2, to
+= 2, len
--)
1954 _farnspokew (to
, _farnspeekw (from
));
1958 from
+= (len
- 1) * 2;
1959 to
+= (len
- 1) * 2;
1960 for ( ; len
; from
-= 2, to
-= 2, len
--)
1961 _farnspokew (to
, _farnspeekw (from
));
1963 if (screen_virtual_segment
)
1964 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1967 /* Insert and delete glyphs. */
1969 IT_insert_glyphs (f
, start
, len
)
1971 register struct glyph
*start
;
1974 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1976 /* Shift right the glyphs from the nominal cursor position to the
1977 end of this line. */
1978 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1980 /* Now write the glyphs to be inserted. */
1981 IT_write_glyphs (f
, start
, len
);
1985 IT_delete_glyphs (f
, n
)
1992 /* set-window-configuration on window.c needs this. */
1994 x_set_menu_bar_lines (f
, value
, oldval
)
1996 Lisp_Object value
, oldval
;
1998 set_menu_bar_lines (f
, value
, oldval
);
2001 /* This was copied from xfaces.c */
2003 extern Lisp_Object Qbackground_color
;
2004 extern Lisp_Object Qforeground_color
;
2005 Lisp_Object Qreverse
;
2006 extern Lisp_Object Qtitle
;
2008 /* IT_set_terminal_modes is called when emacs is started,
2009 resumed, and whenever the screen is redrawn! */
2012 IT_set_terminal_modes (struct terminal
*term
)
2014 struct tty_display_info
*tty
;
2016 /* If called with initial terminal, it's too early to do anything
2018 if (term
->type
== output_initial
)
2021 tty
= term
->display_info
.tty
;
2023 if (tty
->termscript
)
2024 fprintf (tty
->termscript
, "\n<SET_TERM>");
2026 screen_size_X
= ScreenCols ();
2027 screen_size_Y
= ScreenRows ();
2028 screen_size
= screen_size_X
* screen_size_Y
;
2030 new_pos_X
= new_pos_Y
= 0;
2031 current_pos_X
= current_pos_Y
= -1;
2033 if (term_setup_done
)
2035 term_setup_done
= 1;
2037 startup_screen_size_X
= screen_size_X
;
2038 startup_screen_size_Y
= screen_size_Y
;
2039 startup_screen_attrib
= ScreenAttrib
;
2042 /* Is DOS/V (or any other RSIS software which relocates
2043 the screen) installed? */
2045 unsigned short es_value
;
2048 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2049 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2050 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2051 else if (screen_old_address
) /* already switched to Japanese mode once */
2052 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2054 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2056 es_value
= regs
.x
.es
;
2057 __dpmi_int (0x10, ®s
);
2059 if (regs
.x
.es
!= es_value
)
2061 /* screen_old_address is only set if ScreenPrimary does NOT
2062 already point to the relocated buffer address returned by
2063 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2064 ScreenPrimary to that address at startup under DOS/V. */
2065 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2066 screen_old_address
= ScreenPrimary
;
2067 screen_virtual_segment
= regs
.x
.es
;
2068 screen_virtual_offset
= regs
.x
.di
;
2069 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2072 #endif /* __DJGPP__ > 1 */
2074 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2075 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2080 /* IT_reset_terminal_modes is called when emacs is
2081 suspended or killed. */
2084 IT_reset_terminal_modes (struct terminal
*term
)
2086 int display_row_start
= (int) ScreenPrimary
;
2087 int saved_row_len
= startup_screen_size_X
* 2;
2088 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
2089 int to_next_row
= update_row_len
;
2090 unsigned char *saved_row
= startup_screen_buffer
;
2091 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
2092 struct tty_display_info
*tty
= term
->display_info
.tty
;
2094 if (tty
->termscript
)
2095 fprintf (tty
->termscript
, "\n<RESET_TERM>");
2097 if (!term_setup_done
)
2102 /* Leave the video system in the same state as we found it,
2103 as far as the blink/bright-background bit is concerned. */
2104 maybe_enable_blinking ();
2106 /* We have a situation here.
2107 We cannot just do ScreenUpdate(startup_screen_buffer) because
2108 the luser could have changed screen dimensions inside Emacs
2109 and failed (or didn't want) to restore them before killing
2110 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2111 thus will happily use memory outside what was allocated for
2112 `startup_screen_buffer'.
2113 Thus we only restore as much as the current screen dimensions
2114 can hold, and clear the rest (if the saved screen is smaller than
2115 the current) with the color attribute saved at startup. The cursor
2116 is also restored within the visible dimensions. */
2118 ScreenAttrib
= startup_screen_attrib
;
2120 /* Don't restore the screen if we are exiting less than 2 seconds
2121 after startup: we might be crashing, and the screen might show
2122 some vital clues to what's wrong. */
2123 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2126 if (screen_virtual_segment
)
2127 dosv_refresh_virtual_screen (0, screen_size
);
2129 if (update_row_len
> saved_row_len
)
2130 update_row_len
= saved_row_len
;
2131 if (current_rows
> startup_screen_size_Y
)
2132 current_rows
= startup_screen_size_Y
;
2134 if (tty
->termscript
)
2135 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2136 update_row_len
/ 2, current_rows
);
2138 while (current_rows
--)
2140 dosmemput (saved_row
, update_row_len
, display_row_start
);
2141 if (screen_virtual_segment
)
2142 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2143 update_row_len
/ 2);
2144 saved_row
+= saved_row_len
;
2145 display_row_start
+= to_next_row
;
2148 if (startup_pos_X
< cursor_pos_X
)
2149 cursor_pos_X
= startup_pos_X
;
2150 if (startup_pos_Y
< cursor_pos_Y
)
2151 cursor_pos_Y
= startup_pos_Y
;
2153 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2154 xfree (startup_screen_buffer
);
2155 startup_screen_buffer
= NULL
;
2157 term_setup_done
= 0;
2161 IT_set_terminal_window (struct frame
*f
, int foo
)
2165 /* Remember the screen colors of the curent frame, to serve as the
2166 default colors for newly-created frames. */
2167 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2168 Smsdos_remember_default_colors
, 1, 1, 0,
2169 doc
: /* Remember the screen colors of the current frame. */)
2175 CHECK_FRAME (frame
);
2178 /* This function is called after applying default-frame-alist to the
2179 initial frame. At that time, if reverse-colors option was
2180 specified in default-frame-alist, it was already applied, and
2181 frame colors are reversed. */
2182 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2183 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2187 IT_set_frame_parameters (f
, alist
)
2192 int i
, j
, length
= XINT (Flength (alist
));
2194 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2196 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2197 /* Do we have to reverse the foreground and background colors? */
2198 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2199 int need_to_reverse
, was_reverse
= reverse
;
2200 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2201 unsigned long orig_fg
, orig_bg
;
2202 Lisp_Object frame_bg
, frame_fg
;
2203 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2204 struct tty_display_info
*tty
= FRAME_TTY (f
);
2206 /* If we are creating a new frame, begin with the original screen colors
2207 used for the initial frame. */
2208 if (EQ (alist
, Vdefault_frame_alist
)
2209 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2211 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2212 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2213 init_frame_faces (f
);
2215 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2216 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2217 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2218 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2219 /* frame_fg and frame_bg could be nil if, for example,
2220 f->param_alist is nil, e.g. if we are called from
2221 Fmake_terminal_frame. */
2222 if (NILP (frame_fg
))
2223 frame_fg
= build_string (unspecified_fg
);
2224 if (NILP (frame_bg
))
2225 frame_bg
= build_string (unspecified_bg
);
2227 /* Extract parm names and values into those vectors. */
2229 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2234 parms
[i
] = Fcar (elt
);
2235 CHECK_SYMBOL (parms
[i
]);
2236 values
[i
] = Fcdr (elt
);
2242 for (i
= 0; i
< j
; i
++)
2244 Lisp_Object prop
, val
;
2249 if (EQ (prop
, Qreverse
))
2250 reverse
= EQ (val
, Qt
);
2253 need_to_reverse
= reverse
&& !was_reverse
;
2254 if (tty
->termscript
&& need_to_reverse
)
2255 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
2257 /* Now process the alist elements in reverse of specified order. */
2258 for (i
--; i
>= 0; i
--)
2260 Lisp_Object prop
, val
, frame
;
2265 if (EQ (prop
, Qforeground_color
))
2267 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2268 ? LFACE_BACKGROUND_INDEX
2269 : LFACE_FOREGROUND_INDEX
);
2270 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2271 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2272 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2274 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2275 /* Make sure the foreground of the default face for this
2276 frame is changed as well. */
2277 XSETFRAME (frame
, f
);
2278 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2282 if (tty
->termscript
)
2283 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
2286 else if (EQ (prop
, Qbackground_color
))
2288 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2289 ? LFACE_FOREGROUND_INDEX
2290 : LFACE_BACKGROUND_INDEX
);
2291 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2292 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2293 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2295 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2296 /* Make sure the background of the default face for this
2297 frame is changed as well. */
2298 XSETFRAME (frame
, f
);
2299 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2303 if (tty
->termscript
)
2304 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
2307 else if (EQ (prop
, Qtitle
))
2309 x_set_title (f
, val
);
2310 if (tty
->termscript
)
2311 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
2313 else if (EQ (prop
, Qcursor_type
))
2315 IT_set_cursor_type (f
, val
);
2316 if (tty
->termscript
)
2317 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
2318 EQ (val
, Qbar
) || EQ (val
, Qhbar
)
2319 || CONSP (val
) && (EQ (XCAR (val
), Qbar
)
2320 || EQ (XCAR (val
), Qhbar
))
2323 else if (EQ (prop
, Qtty_type
))
2325 internal_terminal_init ();
2326 if (tty
->termscript
)
2327 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2328 SBYTES (val
), SDATA (val
));
2330 store_frame_param (f
, prop
, val
);
2333 /* If they specified "reverse", but not the colors, we need to swap
2334 the current frame colors. */
2335 if (need_to_reverse
)
2341 XSETFRAME (frame
, f
);
2342 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2343 tty_color_name (f
, orig_bg
),
2349 XSETFRAME (frame
, f
);
2350 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2351 tty_color_name (f
, orig_fg
),
2359 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2360 if (f
== SELECTED_FRAME())
2365 extern void init_frame_faces (FRAME_PTR
);
2367 #endif /* !HAVE_X_WINDOWS */
2370 /* Do we need the internal terminal? */
2373 internal_terminal_init ()
2375 static int init_needed
= 1;
2376 char *term
= getenv ("TERM"), *colors
;
2377 struct frame
*sf
= SELECTED_FRAME();
2378 struct tty_display_info
*tty
;
2380 #ifdef HAVE_X_WINDOWS
2381 if (!inhibit_window_system
)
2385 /* If this is the initial terminal, we are done here. */
2386 if (sf
->output_method
== output_initial
)
2390 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2392 #ifndef HAVE_X_WINDOWS
2393 if (!internal_terminal
|| inhibit_window_system
)
2395 sf
->output_method
= output_termcap
;
2399 tty
= FRAME_TTY (sf
);
2400 current_kboard
->Vwindow_system
= Qpc
;
2401 sf
->output_method
= output_msdos_raw
;
2404 if (!tty
->termscript
&& getenv ("EMACSTEST"))
2405 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
2406 if (tty
->termscript
)
2408 time_t now
= time (NULL
);
2409 struct tm
*tnow
= localtime (&now
);
2412 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
2413 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
2414 fprintf (tty
->termscript
, "=====================\n\n");
2417 Vinitial_window_system
= Qpc
;
2418 Vwindow_system_version
= make_number (23); /* RE Emacs version */
2419 tty
->terminal
->type
= output_msdos_raw
;
2421 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2423 screen_old_address
= 0;
2425 /* Forget the stale screen colors as well. */
2426 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2428 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2429 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2431 colors
= getenv ("EMACSCOLORS");
2432 if (colors
&& strlen (colors
) >= 2)
2434 /* The colors use 4 bits each (we enable bright background). */
2435 if (isdigit (colors
[0]))
2437 else if (isxdigit (colors
[0]))
2438 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2439 if (colors
[0] >= 0 && colors
[0] < 16)
2440 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
2441 if (isdigit (colors
[1]))
2443 else if (isxdigit (colors
[1]))
2444 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2445 if (colors
[1] >= 0 && colors
[1] < 16)
2446 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
2448 the_only_display_info
.mouse_face_mouse_frame
= NULL
;
2449 the_only_display_info
.mouse_face_deferred_gc
= 0;
2450 the_only_display_info
.mouse_face_beg_row
=
2451 the_only_display_info
.mouse_face_beg_col
= -1;
2452 the_only_display_info
.mouse_face_end_row
=
2453 the_only_display_info
.mouse_face_end_col
= -1;
2454 the_only_display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2455 the_only_display_info
.mouse_face_window
= Qnil
;
2456 the_only_display_info
.mouse_face_mouse_x
=
2457 the_only_display_info
.mouse_face_mouse_y
= 0;
2458 the_only_display_info
.mouse_face_defer
= 0;
2459 the_only_display_info
.mouse_face_hidden
= 0;
2461 if (have_mouse
) /* detected in dos_ttraw, which see */
2463 have_mouse
= 1; /* enable mouse */
2465 mouse_setup_buttons (mouse_button_count
);
2466 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
2470 if (tty
->termscript
&& screen_size
)
2471 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2472 screen_size_X
, screen_size_Y
);
2474 init_frame_faces (sf
);
2481 initialize_msdos_display (struct terminal
*term
)
2483 term
->rif
= 0; /* we don't support window-based display */
2484 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
2485 term
->clear_to_end_hook
= IT_clear_to_end
;
2486 term
->clear_frame_hook
= IT_clear_screen
;
2487 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
2488 term
->ins_del_lines_hook
= 0;
2489 term
->insert_glyphs_hook
= IT_insert_glyphs
;
2490 term
->write_glyphs_hook
= IT_write_glyphs
;
2491 term
->delete_glyphs_hook
= IT_delete_glyphs
;
2492 term
->ring_bell_hook
= IT_ring_bell
;
2493 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2494 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
2495 term
->set_terminal_window_hook
= IT_set_terminal_window
;
2496 term
->update_begin_hook
= IT_update_begin
;
2497 term
->update_end_hook
= IT_update_end
;
2498 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
2499 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
2500 term
->frame_rehighlight_hook
= 0;
2501 term
->frame_raise_lower_hook
= 0;
2502 term
->set_vertical_scroll_bar_hook
= 0;
2503 term
->condemn_scroll_bars_hook
= 0;
2504 term
->redeem_scroll_bar_hook
= 0;
2505 term
->judge_scroll_bars_hook
= 0;
2506 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
2509 dos_get_saved_screen (screen
, rows
, cols
)
2514 #ifndef HAVE_X_WINDOWS
2515 *screen
= startup_screen_buffer
;
2516 *cols
= startup_screen_size_X
;
2517 *rows
= startup_screen_size_Y
;
2518 return *screen
!= (char *)0;
2524 #ifndef HAVE_X_WINDOWS
2526 /* We are not X, but we can emulate it well enough for our needs... */
2530 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2531 error ("Not running under a window system");
2537 /* ----------------------- Keyboard control ----------------------
2539 * Keymaps reflect the following keyboard layout:
2541 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2542 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2543 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2544 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2548 #define Ignore 0x0000
2549 #define Normal 0x0000 /* normal key - alt changes scan-code */
2550 #define FctKey 0x1000 /* func key if c == 0, else c */
2551 #define Special 0x2000 /* func key even if c != 0 */
2552 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2553 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2554 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2555 #define Grey 0x6000 /* Grey keypad key */
2557 #define Alt 0x0100 /* alt scan-code */
2558 #define Ctrl 0x0200 /* ctrl scan-code */
2559 #define Shift 0x0400 /* shift scan-code */
2561 static int extended_kbd
; /* 101 (102) keyboard present. */
2563 struct kbd_translate
{
2566 unsigned short code
;
2569 struct dos_keyboard_map
2574 struct kbd_translate
*translate_table
;
2578 static struct dos_keyboard_map us_keyboard
= {
2580 /* 01234567890123456789012345678901234567890 12345678901234 */
2581 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2582 /* 0123456789012345678901234567890123456789 012345678901234 */
2583 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2584 0, /* no Alt-Gr key */
2585 0 /* no translate table */
2588 static struct dos_keyboard_map fr_keyboard
= {
2590 /* 012 3456789012345678901234567890123456789012345678901234 */
2591 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2592 /* 0123456789012345678901234567890123456789012345678901234 */
2593 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2594 /* 01234567 89012345678901234567890123456789012345678901234 */
2596 0 /* no translate table */
2600 * Italian keyboard support, country code 39.
2603 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2604 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2607 static struct kbd_translate it_kbd_translate_table
[] = {
2608 { 0x56, 0x3c, Normal
| 13 },
2609 { 0x56, 0x3e, Normal
| 27 },
2612 static struct dos_keyboard_map it_keyboard
= {
2614 /* 0 123456789012345678901234567890123456789012345678901234 */
2615 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2616 /* 01 23456789012345678901234567890123456789012345678901234 */
2617 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2618 /* 0123456789012345678901234567890123456789012345678901234 */
2620 it_kbd_translate_table
2623 static struct dos_keyboard_map dk_keyboard
= {
2625 /* 0123456789012345678901234567890123456789012345678901234 */
2626 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2627 /* 01 23456789012345678901234567890123456789012345678901234 */
2628 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2629 /* 0123456789012345678901234567890123456789012345678901234 */
2631 0 /* no translate table */
2634 static struct kbd_translate jp_kbd_translate_table
[] = {
2635 { 0x73, 0x5c, Normal
| 0 },
2636 { 0x73, 0x5f, Normal
| 0 },
2637 { 0x73, 0x1c, Map
| 0 },
2638 { 0x7d, 0x5c, Normal
| 13 },
2639 { 0x7d, 0x7c, Normal
| 13 },
2640 { 0x7d, 0x1c, Map
| 13 },
2643 static struct dos_keyboard_map jp_keyboard
= {
2645 /* 0123456789012 345678901234567890123456789012345678901234 */
2646 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2647 /* 01 23456789012345678901234567890123456789012345678901234 */
2648 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2649 0, /* no Alt-Gr key */
2650 jp_kbd_translate_table
2653 static struct keyboard_layout_list
2656 struct dos_keyboard_map
*keyboard_map
;
2657 } keyboard_layout_list
[] =
2666 static struct dos_keyboard_map
*keyboard
;
2667 static int keyboard_map_all
;
2668 static int international_keyboard
;
2671 dos_set_keyboard (code
, always
)
2676 _go32_dpmi_registers regs
;
2678 /* See if Keyb.Com is installed (for international keyboard support).
2679 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2680 of Windows 9X! So don't do that! */
2682 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2683 _go32_dpmi_simulate_int (0x2f, ®s
);
2684 if (regs
.h
.al
== 0xff)
2685 international_keyboard
= 1;
2687 /* Initialize to US settings, for countries that don't have their own. */
2688 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2689 keyboard_map_all
= always
;
2690 dos_keyboard_layout
= 1;
2692 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2693 if (code
== keyboard_layout_list
[i
].country_code
)
2695 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2696 keyboard_map_all
= always
;
2697 dos_keyboard_layout
= code
;
2705 unsigned char char_code
; /* normal code */
2706 unsigned char meta_code
; /* M- code */
2707 unsigned char keypad_code
; /* keypad code */
2708 unsigned char editkey_code
; /* edit key */
2709 } keypad_translate_map
[] = {
2710 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2711 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2712 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2713 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2714 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2715 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2716 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2717 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2718 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2719 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2720 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2725 unsigned char char_code
; /* normal code */
2726 unsigned char keypad_code
; /* keypad code */
2727 } grey_key_translate_map
[] = {
2728 '/', 0xaf, /* kp-decimal */
2729 '*', 0xaa, /* kp-multiply */
2730 '-', 0xad, /* kp-subtract */
2731 '+', 0xab, /* kp-add */
2732 '\r', 0x8d /* kp-enter */
2735 static unsigned short
2736 ibmpc_translate_map
[] =
2738 /* --------------- 00 to 0f --------------- */
2739 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2740 Alt
| ModFct
| 0x1b, /* Escape */
2741 Normal
| 1, /* '1' */
2742 Normal
| 2, /* '2' */
2743 Normal
| 3, /* '3' */
2744 Normal
| 4, /* '4' */
2745 Normal
| 5, /* '5' */
2746 Normal
| 6, /* '6' */
2747 Normal
| 7, /* '7' */
2748 Normal
| 8, /* '8' */
2749 Normal
| 9, /* '9' */
2750 Normal
| 10, /* '0' */
2751 Normal
| 11, /* '-' */
2752 Normal
| 12, /* '=' */
2753 Special
| 0x08, /* Backspace */
2754 ModFct
| 0x74, /* Tab/Backtab */
2756 /* --------------- 10 to 1f --------------- */
2769 ModFct
| 0x0d, /* Return */
2774 /* --------------- 20 to 2f --------------- */
2783 Map
| 40, /* '\'' */
2785 Ignore
, /* Left shift */
2786 Map
| 41, /* '\\' */
2792 /* --------------- 30 to 3f --------------- */
2799 Ignore
, /* Right shift */
2800 Grey
| 1, /* Grey * */
2802 Normal
| 55, /* ' ' */
2803 Ignore
, /* Caps Lock */
2804 FctKey
| 0xbe, /* F1 */
2805 FctKey
| 0xbf, /* F2 */
2806 FctKey
| 0xc0, /* F3 */
2807 FctKey
| 0xc1, /* F4 */
2808 FctKey
| 0xc2, /* F5 */
2810 /* --------------- 40 to 4f --------------- */
2811 FctKey
| 0xc3, /* F6 */
2812 FctKey
| 0xc4, /* F7 */
2813 FctKey
| 0xc5, /* F8 */
2814 FctKey
| 0xc6, /* F9 */
2815 FctKey
| 0xc7, /* F10 */
2816 Ignore
, /* Num Lock */
2817 Ignore
, /* Scroll Lock */
2818 KeyPad
| 7, /* Home */
2819 KeyPad
| 8, /* Up */
2820 KeyPad
| 9, /* Page Up */
2821 Grey
| 2, /* Grey - */
2822 KeyPad
| 4, /* Left */
2823 KeyPad
| 5, /* Keypad 5 */
2824 KeyPad
| 6, /* Right */
2825 Grey
| 3, /* Grey + */
2826 KeyPad
| 1, /* End */
2828 /* --------------- 50 to 5f --------------- */
2829 KeyPad
| 2, /* Down */
2830 KeyPad
| 3, /* Page Down */
2831 KeyPad
| 0, /* Insert */
2832 KeyPad
| 10, /* Delete */
2833 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2834 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2835 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2836 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2837 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2838 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2839 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2840 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2841 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2842 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2843 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2844 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2846 /* --------------- 60 to 6f --------------- */
2847 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2848 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2849 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2850 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2851 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2852 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2853 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2854 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2855 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2856 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2857 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2858 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2859 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2860 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2861 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2862 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2864 /* --------------- 70 to 7f --------------- */
2865 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2866 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2867 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2868 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2869 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2870 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2871 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2872 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2873 Alt
| Map
| 1, /* '1' */
2874 Alt
| Map
| 2, /* '2' */
2875 Alt
| Map
| 3, /* '3' */
2876 Alt
| Map
| 4, /* '4' */
2877 Alt
| Map
| 5, /* '5' */
2878 Alt
| Map
| 6, /* '6' */
2879 Alt
| Map
| 7, /* '7' */
2880 Alt
| Map
| 8, /* '8' */
2882 /* --------------- 80 to 8f --------------- */
2883 Alt
| Map
| 9, /* '9' */
2884 Alt
| Map
| 10, /* '0' */
2885 Alt
| Map
| 11, /* '-' */
2886 Alt
| Map
| 12, /* '=' */
2887 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2888 FctKey
| 0xc8, /* F11 */
2889 FctKey
| 0xc9, /* F12 */
2890 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2891 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2892 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2893 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2894 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2895 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2896 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2897 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2898 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2900 /* --------------- 90 to 9f --------------- */
2901 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2902 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2903 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2904 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2905 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2906 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2907 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2908 Alt
| FctKey
| 0x50, /* (Alt) Home */
2909 Alt
| FctKey
| 0x52, /* (Alt) Up */
2910 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2911 Ignore
, /* NO KEY */
2912 Alt
| FctKey
| 0x51, /* (Alt) Left */
2913 Ignore
, /* NO KEY */
2914 Alt
| FctKey
| 0x53, /* (Alt) Right */
2915 Ignore
, /* NO KEY */
2916 Alt
| FctKey
| 0x57, /* (Alt) End */
2918 /* --------------- a0 to af --------------- */
2919 Alt
| KeyPad
| 2, /* (Alt) Down */
2920 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2921 Alt
| KeyPad
| 0, /* (Alt) Insert */
2922 Alt
| KeyPad
| 10, /* (Alt) Delete */
2923 Alt
| Grey
| 0, /* (Alt) Grey / */
2924 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2925 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2928 /* These bit-positions corresponds to values returned by BIOS */
2929 #define SHIFT_P 0x0003 /* two bits! */
2930 #define CTRL_P 0x0004
2931 #define ALT_P 0x0008
2932 #define SCRLOCK_P 0x0010
2933 #define NUMLOCK_P 0x0020
2934 #define CAPSLOCK_P 0x0040
2935 #define ALT_GR_P 0x0800
2936 #define SUPER_P 0x4000 /* pseudo */
2937 #define HYPER_P 0x8000 /* pseudo */
2940 dos_get_modifiers (keymask
)
2944 int mask
, modifiers
= 0;
2946 /* Calculate modifier bits */
2947 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2948 int86 (0x16, ®s
, ®s
);
2952 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2953 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2957 mask
= regs
.h
.al
& (SHIFT_P
|
2958 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2960 /* Do not break international keyboard support. */
2961 /* When Keyb.Com is loaded, the right Alt key is */
2962 /* used for accessing characters like { and } */
2963 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2966 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2969 if (dos_hyper_key
== 1)
2972 modifiers
|= hyper_modifier
;
2974 else if (dos_super_key
== 1)
2977 modifiers
|= super_modifier
;
2979 else if (!international_keyboard
)
2981 /* If Keyb.Com is NOT installed, let Right Alt behave
2982 like the Left Alt. */
2988 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2991 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2993 if (dos_hyper_key
== 2)
2996 modifiers
|= hyper_modifier
;
2998 else if (dos_super_key
== 2)
3001 modifiers
|= super_modifier
;
3009 modifiers
|= shift_modifier
;
3011 modifiers
|= ctrl_modifier
;
3013 modifiers
|= meta_modifier
;
3020 #define NUM_RECENT_DOSKEYS (100)
3021 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
3022 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3023 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3025 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3026 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3027 Each input key receives two values in this vector: first the ASCII code,
3028 and then the scan code. */)
3031 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
3033 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3034 return Fvector (total_doskeys
, keys
);
3037 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3038 bcopy (keys
+ recent_doskeys_index
,
3039 XVECTOR (val
)->contents
,
3040 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3042 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3043 recent_doskeys_index
* sizeof (Lisp_Object
));
3048 /* Get a char from keyboard. Function keys are put into the event queue. */
3052 struct input_event event
;
3054 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3057 #ifndef HAVE_X_WINDOWS
3058 /* Maybe put the cursor where it should be. */
3059 IT_cmgoto (SELECTED_FRAME());
3062 /* The following condition is equivalent to `kbhit ()', except that
3063 it uses the bios to do its job. This pleases DESQview/X. */
3064 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3065 int86 (0x16, ®s
, ®s
),
3066 (regs
.x
.flags
& 0x40) == 0)
3069 register unsigned char c
;
3070 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
3072 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3073 int86 (0x16, ®s
, ®s
);
3078 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3080 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3081 recent_doskeys_index
= 0;
3082 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3084 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3085 recent_doskeys_index
= 0;
3087 modifiers
= dos_get_modifiers (&mask
);
3089 #ifndef HAVE_X_WINDOWS
3090 if (!NILP (Vdos_display_scancodes
))
3093 sprintf (buf
, "%02x:%02x*%04x",
3094 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3095 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3103 case 10: /* Ctrl Grey Enter */
3104 code
= Ctrl
| Grey
| 4;
3106 case 13: /* Grey Enter */
3109 case '/': /* Grey / */
3119 /* Try the keyboard-private translation table first. */
3120 if (keyboard
->translate_table
)
3122 struct kbd_translate
*p
= keyboard
->translate_table
;
3126 if (p
->sc
== sc
&& p
->ch
== c
)
3134 /* If the private table didn't translate it, use the general
3138 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3140 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3147 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3148 Emacs is ready to read a key. Therefore, if they press
3149 `Alt-x' when Emacs is busy, by the time we get to
3150 `dos_get_modifiers', they might have already released the
3151 Alt key, and Emacs gets just `x', which is BAD.
3152 However, for keys with the `Map' property set, the ASCII
3153 code returns zero only if Alt is pressed. So, when we DON'T
3154 have to support international_keyboard, we don't have to
3155 distinguish between the left and right Alt keys, and we
3156 can set the META modifier for any keys with the `Map'
3157 property if they return zero ASCII code (c = 0). */
3159 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3160 modifiers
|= meta_modifier
;
3162 modifiers
|= ctrl_modifier
;
3164 modifiers
|= shift_modifier
;
3167 switch (code
& 0xf000)
3170 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3172 c
= 0; /* Special */
3185 if (c
== 0) /* ctrl-break */
3187 return c
; /* ALT-nnn */
3189 if (!keyboard_map_all
)
3198 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3199 if (!keyboard_map_all
)
3203 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3204 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3208 code
= keyboard
->shifted
[code
];
3210 modifiers
&= ~shift_modifier
;
3213 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3214 code
= keyboard
->alt_gr
[code
];
3216 code
= keyboard
->unshifted
[code
];
3221 if (c
== 0xe0) /* edit key */
3224 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3225 kp_mode
= dos_keypad_mode
& 0x03;
3227 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3232 if (code
== 10 && dos_decimal_point
)
3233 return dos_decimal_point
;
3234 return keypad_translate_map
[code
].char_code
;
3237 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3241 code
= keypad_translate_map
[code
].meta_code
;
3242 modifiers
= meta_modifier
;
3246 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3253 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3254 if (dos_keypad_mode
& kp_mode
)
3255 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3257 code
= grey_key_translate_map
[code
].char_code
;
3265 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
3267 clear_mouse_face (dpyinfo
);
3268 dpyinfo
->mouse_face_hidden
= 1;
3272 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
3274 event
.kind
= ASCII_KEYSTROKE_EVENT
;
3276 event
.modifiers
= modifiers
;
3277 event
.frame_or_window
= selected_frame
;
3279 event
.timestamp
= event_timestamp ();
3280 kbd_buffer_store_event (&event
);
3283 if (have_mouse
> 0 && !mouse_preempted
)
3285 int but
, press
, x
, y
, ok
;
3286 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3287 Lisp_Object mouse_window
= Qnil
;
3289 /* Check for mouse movement *before* buttons. */
3290 mouse_check_moved ();
3292 /* If the mouse moved from the spot of its last sighting, we
3293 might need to update mouse highlight. */
3294 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3296 if (dpyinfo
->mouse_face_hidden
)
3298 dpyinfo
->mouse_face_hidden
= 0;
3299 clear_mouse_face (dpyinfo
);
3302 /* Generate SELECT_WINDOW_EVENTs when needed. */
3303 if (!NILP (Vmouse_autoselect_window
))
3305 mouse_window
= window_from_coordinates (SELECTED_FRAME(),
3309 /* A window will be selected only when it is not
3310 selected now, and the last mouse movement event was
3311 not in it. A minibuffer window will be selected iff
3313 if (WINDOWP (mouse_window
)
3314 && !EQ (mouse_window
, last_mouse_window
)
3315 && !EQ (mouse_window
, selected_window
))
3317 event
.kind
= SELECT_WINDOW_EVENT
;
3318 event
.frame_or_window
= mouse_window
;
3320 event
.timestamp
= event_timestamp ();
3321 kbd_buffer_store_event (&event
);
3323 last_mouse_window
= mouse_window
;
3326 last_mouse_window
= Qnil
;
3328 previous_help_echo_string
= help_echo_string
;
3329 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
3331 IT_note_mouse_highlight (SELECTED_FRAME(),
3332 mouse_last_x
, mouse_last_y
);
3333 /* If the contents of the global variable help_echo has
3334 changed, generate a HELP_EVENT. */
3335 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
3337 event
.kind
= HELP_EVENT
;
3338 event
.frame_or_window
= selected_frame
;
3339 event
.arg
= help_echo_object
;
3340 event
.x
= WINDOWP (help_echo_window
)
3341 ? help_echo_window
: selected_frame
;
3342 event
.y
= help_echo_string
;
3343 event
.timestamp
= event_timestamp ();
3344 event
.code
= help_echo_pos
;
3345 kbd_buffer_store_event (&event
);
3349 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3350 for (press
= 0; press
< 2; press
++)
3352 int button_num
= but
;
3355 ok
= mouse_pressed (but
, &x
, &y
);
3357 ok
= mouse_released (but
, &x
, &y
);
3360 /* Allow a simultaneous press/release of Mouse-1 and
3361 Mouse-2 to simulate Mouse-3 on two-button mice. */
3362 if (mouse_button_count
== 2 && but
< 2)
3364 int x2
, y2
; /* don't clobber original coordinates */
3366 /* If only one button is pressed, wait 100 msec and
3367 check again. This way, Speedy Gonzales isn't
3368 punished, while the slow get their chance. */
3369 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3370 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3375 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3376 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3381 event
.kind
= MOUSE_CLICK_EVENT
;
3382 event
.code
= button_num
;
3383 event
.modifiers
= dos_get_modifiers (0)
3384 | (press
? down_modifier
: up_modifier
);
3385 event
.x
= make_number (x
);
3386 event
.y
= make_number (y
);
3387 event
.frame_or_window
= selected_frame
;
3389 event
.timestamp
= event_timestamp ();
3390 kbd_buffer_store_event (&event
);
3398 static int prev_get_char
= -1;
3400 /* Return 1 if a key is ready to be read without suspending execution. */
3404 if (prev_get_char
!= -1)
3407 return ((prev_get_char
= dos_rawgetc ()) != -1);
3410 /* Read a key. Return -1 if no key is ready. */
3414 if (prev_get_char
!= -1)
3416 int c
= prev_get_char
;
3421 return dos_rawgetc ();
3424 #ifndef HAVE_X_WINDOWS
3426 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3429 Actually, I don't know the meaning of all the parameters of the functions
3430 here -- I only know how they are called by xmenu.c. I could of course
3431 grab the nearest Xlib manual (down the hall, second-to-last door on the
3432 left), but I don't think it's worth the effort. */
3434 /* These hold text of the current and the previous menu help messages. */
3435 static char *menu_help_message
, *prev_menu_help_message
;
3436 /* Pane number and item number of the menu item which generated the
3437 last menu help message. */
3438 static int menu_help_paneno
, menu_help_itemno
;
3445 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3446 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3450 /* Allocate some (more) memory for MENU ensuring that there is room for one
3454 IT_menu_make_room (XMenu
*menu
)
3456 if (menu
->allocated
== 0)
3458 int count
= menu
->allocated
= 10;
3459 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3460 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3461 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3462 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3464 else if (menu
->allocated
== menu
->count
)
3466 int count
= menu
->allocated
= menu
->allocated
+ 10;
3468 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3470 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3472 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3474 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3478 /* Search the given menu structure for a given pane number. */
3481 IT_menu_search_pane (XMenu
*menu
, int pane
)
3486 for (i
= 0; i
< menu
->count
; i
++)
3487 if (menu
->submenu
[i
])
3489 if (pane
== menu
->panenumber
[i
])
3490 return menu
->submenu
[i
];
3491 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3497 /* Determine how much screen space a given menu needs. */
3500 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3502 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3505 maxheight
= menu
->count
;
3506 for (i
= 0; i
< menu
->count
; i
++)
3508 if (menu
->submenu
[i
])
3510 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3511 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3512 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3515 *width
= menu
->width
+ maxsubwidth
;
3516 *height
= maxheight
;
3519 /* Display MENU at (X,Y) using FACES. */
3521 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3524 (GLYPH).type = CHAR_GLYPH; \
3525 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3526 (GLYPH).charpos = -1; \
3531 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3533 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
3534 struct glyph
*text
, *p
;
3535 const unsigned char *q
;
3536 struct frame
*sf
= SELECTED_FRAME();
3538 menu_help_message
= NULL
;
3540 width
= menu
->width
;
3541 /* We multiply width by 2 to account for possible control characters.
3542 FIXME: cater to non-ASCII characters in menus. */
3543 text
= (struct glyph
*) xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
3544 ScreenGetCursor (&row
, &col
);
3545 mouse_get_xy (&mx
, &my
);
3546 IT_update_begin (sf
);
3547 for (i
= 0; i
< menu
->count
; i
++)
3549 int max_width
= width
+ 2;
3551 IT_cursor_to (sf
, y
+ i
, x
);
3553 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3554 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
3555 face
= faces
[enabled
+ mousehere
* 2];
3556 /* The following if clause means that we display the menu help
3557 strings even if the menu item is currently disabled. */
3558 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3560 menu_help_message
= menu
->help_text
[i
];
3561 menu_help_paneno
= pn
- 1;
3562 menu_help_itemno
= i
;
3565 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3567 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3569 unsigned c
= STRING_CHAR_ADVANCE (q
);
3573 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
3576 else /* make '^x' */
3578 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
3581 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
3585 /* Don't let the menu text overflow into the next screen row. */
3586 if (x
+ max_width
> screen_size_X
)
3588 max_width
= screen_size_X
- x
;
3589 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3591 for (; j
< max_width
- 2; j
++, p
++)
3592 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3594 /* 16 is the character code of a character that on DOS terminal
3595 produces a nice-looking right-pointing arrow glyph. */
3596 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3598 IT_write_glyphs (sf
, text
, max_width
);
3601 IT_cursor_to (sf
, row
, col
);
3605 /* --------------------------- X Menu emulation ---------------------- */
3607 /* Report availability of menus. */
3610 have_menus_p () { return 1; }
3612 /* Create a brand new menu structure. */
3615 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3617 return IT_menu_create ();
3620 /* Create a new pane and place it on the outer-most level. It is not
3621 clear that it should be placed out there, but I don't know what else
3625 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3633 IT_menu_make_room (menu
);
3634 menu
->submenu
[menu
->count
] = IT_menu_create ();
3635 menu
->text
[menu
->count
] = txt
;
3636 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3637 menu
->help_text
[menu
->count
] = NULL
;
3640 /* Adjust length for possible control characters (which will
3641 be written as ^x). */
3642 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3646 if (len
> menu
->width
)
3649 return menu
->panecount
;
3652 /* Create a new item in a menu pane. */
3655 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3656 int foo
, char *txt
, int enable
, char *help_text
)
3662 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3664 IT_menu_make_room (menu
);
3665 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3666 menu
->text
[menu
->count
] = txt
;
3667 menu
->panenumber
[menu
->count
] = enable
;
3668 menu
->help_text
[menu
->count
] = help_text
;
3671 /* Adjust length for possible control characters (which will
3672 be written as ^x). */
3673 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3677 if (len
> menu
->width
)
3683 /* Decide where the menu would be placed if requested at (X,Y). */
3686 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3687 int *ulx
, int *uly
, int *width
, int *height
)
3689 IT_menu_calc_size (menu
, width
, height
);
3695 struct IT_menu_state
3697 void *screen_behind
;
3704 /* Display menu, wait for user's response, and return that response. */
3707 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3708 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3709 void (*help_callback
)(char *, int, int))
3711 struct IT_menu_state
*state
;
3712 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3713 int title_faces
[4]; /* face to display the menu title */
3714 int faces
[4], buffers_num_deleted
= 0;
3715 struct frame
*sf
= SELECTED_FRAME();
3716 Lisp_Object saved_echo_area_message
, selectface
;
3718 /* Just in case we got here without a mouse present... */
3719 if (have_mouse
<= 0)
3720 return XM_IA_SELECT
;
3721 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3722 around the display. */
3728 /* We will process all the mouse events directly, so we had
3729 better prevent dos_rawgetc from stealing them from us. */
3732 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3733 screensize
= screen_size
* 2;
3735 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3736 DEFAULT_FACE_ID
, 1);
3738 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3739 DEFAULT_FACE_ID
, 1);
3740 selectface
= intern ("msdos-menu-select-face");
3741 faces
[2] = lookup_derived_face (sf
, selectface
,
3743 faces
[3] = lookup_derived_face (sf
, selectface
,
3746 /* Make sure the menu title is always displayed with
3747 `msdos-menu-active-face', no matter where the mouse pointer is. */
3748 for (i
= 0; i
< 4; i
++)
3749 title_faces
[i
] = faces
[3];
3753 /* Don't let the title for the "Buffers" popup menu include a
3754 digit (which is ugly).
3756 This is a terrible kludge, but I think the "Buffers" case is
3757 the only one where the title includes a number, so it doesn't
3758 seem to be necessary to make this more general. */
3759 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3761 menu
->text
[0][7] = '\0';
3762 buffers_num_deleted
= 1;
3765 /* We need to save the current echo area message, so that we could
3766 restore it below, before we exit. See the commentary below,
3767 before the call to message_with_string. */
3768 saved_echo_area_message
= Fcurrent_message ();
3769 state
[0].menu
= menu
;
3771 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3773 /* Turn off the cursor. Otherwise it shows through the menu
3774 panes, which is ugly. */
3775 IT_display_cursor (0);
3777 /* Display the menu title. */
3778 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3779 if (buffers_num_deleted
)
3780 menu
->text
[0][7] = ' ';
3781 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3783 menu
->width
= menu
->submenu
[0]->width
;
3784 state
[0].menu
= menu
->submenu
[0];
3788 state
[0].menu
= menu
;
3790 state
[0].x
= x0
- 1;
3792 state
[0].pane
= onepane
;
3794 mouse_last_x
= -1; /* A hack that forces display. */
3798 if (!mouse_visible
) mouse_on ();
3799 mouse_check_moved ();
3800 if (sf
->mouse_moved
)
3802 sf
->mouse_moved
= 0;
3803 result
= XM_IA_SELECT
;
3804 mouse_get_xy (&x
, &y
);
3805 for (i
= 0; i
< statecount
; i
++)
3806 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3808 int dy
= y
- state
[i
].y
;
3809 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3811 if (!state
[i
].menu
->submenu
[dy
])
3812 if (state
[i
].menu
->panenumber
[dy
])
3813 result
= XM_SUCCESS
;
3815 result
= XM_IA_SELECT
;
3816 *pane
= state
[i
].pane
- 1;
3818 /* We hit some part of a menu, so drop extra menus that
3819 have been opened. That does not include an open and
3821 if (i
!= statecount
- 2
3822 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3823 while (i
!= statecount
- 1)
3827 ScreenUpdate (state
[statecount
].screen_behind
);
3828 if (screen_virtual_segment
)
3829 dosv_refresh_virtual_screen (0, screen_size
);
3830 xfree (state
[statecount
].screen_behind
);
3832 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3834 IT_menu_display (state
[i
].menu
,
3839 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3840 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3842 ScreenRetrieve (state
[statecount
].screen_behind
3843 = xmalloc (screensize
));
3845 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3846 state
[statecount
].y
= y
;
3851 IT_menu_display (state
[statecount
- 1].menu
,
3852 state
[statecount
- 1].y
,
3853 state
[statecount
- 1].x
,
3854 state
[statecount
- 1].pane
,
3859 if ((menu_help_message
|| prev_menu_help_message
)
3860 && menu_help_message
!= prev_menu_help_message
)
3862 help_callback (menu_help_message
,
3863 menu_help_paneno
, menu_help_itemno
);
3864 IT_display_cursor (0);
3865 prev_menu_help_message
= menu_help_message
;
3867 /* We are busy-waiting for the mouse to move, so let's be nice
3868 to other Windows applications by releasing our time slice. */
3871 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3873 /* Only leave if user both pressed and released the mouse, and in
3874 that order. This avoids popping down the menu pane unless
3875 the user is really done with it. */
3876 if (mouse_pressed (b
, &x
, &y
))
3878 while (mouse_button_depressed (b
, &x
, &y
))
3882 (void) mouse_released (b
, &x
, &y
);
3887 ScreenUpdate (state
[0].screen_behind
);
3888 if (screen_virtual_segment
)
3889 dosv_refresh_virtual_screen (0, screen_size
);
3891 /* We have a situation here. ScreenUpdate has just restored the
3892 screen contents as it was before we started drawing this menu.
3893 That includes any echo area message that could have been
3894 displayed back then. (In reality, that echo area message will
3895 almost always be the ``keystroke echo'' that echoes the sequence
3896 of menu items chosen by the user.) However, if the menu had some
3897 help messages, then displaying those messages caused Emacs to
3898 forget about the original echo area message. So when
3899 ScreenUpdate restored it, it created a discrepancy between the
3900 actual screen contents and what Emacs internal data structures
3903 To avoid this conflict, we force Emacs to restore the original
3904 echo area message as we found it when we entered this function.
3905 The irony of this is that we then erase the restored message
3906 right away, so the only purpose of restoring it is so that
3907 erasing it works correctly... */
3908 if (! NILP (saved_echo_area_message
))
3909 message_with_string ("%s", saved_echo_area_message
, 0);
3911 while (statecount
--)
3912 xfree (state
[statecount
].screen_behind
);
3913 IT_display_cursor (1); /* turn cursor back on */
3914 /* Clean up any mouse events that are waiting inside Emacs event queue.
3915 These events are likely to be generated before the menu was even
3916 displayed, probably because the user pressed and released the button
3917 (which invoked the menu) too quickly. If we don't remove these events,
3918 Emacs will process them after we return and surprise the user. */
3919 discard_mouse_events ();
3920 mouse_clear_clicks ();
3921 if (!kbd_buffer_events_waiting (1))
3922 clear_input_pending ();
3923 /* Allow mouse events generation by dos_rawgetc. */
3928 /* Dispose of a menu. */
3931 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3934 if (menu
->allocated
)
3936 for (i
= 0; i
< menu
->count
; i
++)
3937 if (menu
->submenu
[i
])
3938 XMenuDestroy (foo
, menu
->submenu
[i
]);
3940 xfree (menu
->submenu
);
3941 xfree (menu
->panenumber
);
3942 xfree (menu
->help_text
);
3945 menu_help_message
= prev_menu_help_message
= NULL
;
3949 x_pixel_width (struct frame
*f
)
3951 return FRAME_COLS (f
);
3955 x_pixel_height (struct frame
*f
)
3957 return FRAME_LINES (f
);
3959 #endif /* !HAVE_X_WINDOWS */
3961 /* ----------------------- DOS / UNIX conversion --------------------- */
3963 void msdos_downcase_filename (unsigned char *);
3965 /* Destructively turn backslashes into slashes. */
3968 dostounix_filename (p
)
3971 msdos_downcase_filename (p
);
3981 /* Destructively turn slashes into backslashes. */
3984 unixtodos_filename (p
)
3987 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4001 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4004 getdefdir (drive
, dst
)
4008 char in_path
[4], *p
= in_path
, e
= errno
;
4010 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4013 *p
++ = drive
+ 'A' - 1;
4020 _fixpath (in_path
, dst
);
4021 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4022 it queries the LFN support, so ignore that error. */
4023 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
4026 msdos_downcase_filename (dst
);
4033 emacs_root_dir (void)
4035 static char root_dir
[4];
4037 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
4038 root_dir
[0] = tolower (root_dir
[0]);
4042 /* Remove all CR's that are followed by a LF. */
4047 register unsigned char *buf
;
4049 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
4053 while (buf
< endp
- 1)
4057 if (*(++buf
) != 0x0a)
4068 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4070 /* In DJGPP v2.0, library `write' can call `malloc', which might
4071 cause relocation of the buffer whose address we get in ADDR.
4072 Here is a version of `write' that avoids calling `malloc',
4073 to serve us until such time as the library is fixed.
4074 Actually, what we define here is called `__write', because
4075 `write' is a stub that just jmp's to `__write' (to be
4076 POSIXLY-correct with respect to the global name-space). */
4078 #include <io.h> /* for _write */
4079 #include <libc/dosio.h> /* for __file_handle_modes[] */
4081 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4083 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4086 __write (int handle
, const void *buffer
, size_t count
)
4091 if(__file_handle_modes
[handle
] & O_BINARY
)
4092 return _write (handle
, buffer
, count
);
4096 const char *bp
= buffer
;
4097 int total_written
= 0;
4098 int nmoved
= 0, ncr
= 0;
4102 /* The next test makes sure there's space for at least 2 more
4103 characters in xbuf[], so both CR and LF can be put there. */
4115 if (xbp
>= XBUF_END
|| !count
)
4117 size_t to_write
= nmoved
+ ncr
;
4118 int written
= _write (handle
, xbuf
, to_write
);
4123 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4125 /* If some, but not all were written (disk full?), return
4126 an estimate of the total written bytes not counting CRs. */
4127 if (written
< to_write
)
4128 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4135 return total_written
;
4139 /* A low-level file-renaming function which works around Windows 95 bug.
4140 This is pulled directly out of DJGPP v2.01 library sources, and only
4141 used when you compile with DJGPP v2.0. */
4145 int _rename(const char *old
, const char *new)
4148 int olen
= strlen(old
) + 1;
4150 int use_lfn
= _USE_LFN
;
4151 char tempfile
[FILENAME_MAX
];
4152 const char *orig
= old
;
4155 r
.x
.dx
= __tb_offset
;
4156 r
.x
.di
= __tb_offset
+ olen
;
4157 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4161 /* Windows 95 bug: for some filenames, when you rename
4162 file -> file~ (as in Emacs, to leave a backup), the
4163 short 8+3 alias doesn't change, which effectively
4164 makes OLD and NEW the same file. We must rename
4165 through a temporary file to work around this. */
4167 char *pbase
= 0, *p
;
4168 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4169 int idx
= sizeof(try_char
) - 1;
4171 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4172 might point to another drive, which will fail the DOS call. */
4173 strcpy(tempfile
, old
);
4174 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4175 if (*p
== '/' || *p
== '\\' || *p
== ':')
4181 strcpy(pbase
, "X$$djren$$.$$temp$$");
4187 *pbase
= try_char
[--idx
];
4188 } while (_chmod(tempfile
, 0) != -1);
4191 _put_path2(tempfile
, olen
);
4193 __dpmi_int(0x21, &r
);
4196 errno
= __doserr_to_errno(r
.x
.ax
);
4200 /* Now create a file with the original name. This will
4201 ensure that NEW will always have a 8+3 alias
4202 different from that of OLD. (Seems to be required
4203 when NameNumericTail in the Registry is set to 0.) */
4204 lfn_fd
= _creat(old
, 0);
4206 olen
= strlen(tempfile
) + 1;
4208 r
.x
.di
= __tb_offset
+ olen
;
4217 _put_path2(new, olen
);
4219 __dpmi_int(0x21, &r
);
4222 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4223 remove(new); /* and try again */
4226 errno
= __doserr_to_errno(r
.x
.ax
);
4228 /* Restore to original name if we renamed it to temporary. */
4236 _put_path2(orig
, olen
);
4237 _put_path(tempfile
);
4239 __dpmi_int(0x21, &r
);
4248 /* Success. Delete the file possibly created to work
4249 around the Windows 95 bug. */
4251 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4255 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4257 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4259 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
4262 return (_USE_LFN
? Qt
: Qnil
);
4265 /* Convert alphabetic characters in a filename to lower-case. */
4268 msdos_downcase_filename (p
)
4269 register unsigned char *p
;
4271 /* Always lower-case drive letters a-z, even if the filesystem
4272 preserves case in filenames.
4273 This is so MSDOS filenames could be compared by string comparison
4274 functions that are case-sensitive. Even case-preserving filesystems
4275 do not distinguish case in drive letters. */
4276 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4282 /* Under LFN we expect to get pathnames in their true case. */
4283 if (NILP (Fmsdos_long_file_names ()))
4285 if (*p
>= 'A' && *p
<= 'Z')
4289 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4291 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
4292 When long filenames are supported, doesn't change FILENAME.
4293 If FILENAME is not a string, returns nil.
4294 The argument object is never altered--the value is a copy. */)
4296 Lisp_Object filename
;
4300 if (! STRINGP (filename
))
4303 tem
= Fcopy_sequence (filename
);
4304 msdos_downcase_filename (SDATA (tem
));
4308 /* The Emacs root directory as determined by init_environment. */
4310 static char emacsroot
[MAXPATHLEN
];
4313 rootrelativepath (rel
)
4316 static char result
[MAXPATHLEN
+ 10];
4318 strcpy (result
, emacsroot
);
4319 strcat (result
, "/");
4320 strcat (result
, rel
);
4324 /* Define a lot of environment variables if not already defined. Don't
4325 remove anything unless you know what you're doing -- lots of code will
4326 break if one or more of these are missing. */
4329 init_environment (argc
, argv
, skip_args
)
4336 static const char * const tempdirs
[] = {
4337 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4339 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4341 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4342 temporary files and assume "/tmp" if $TMPDIR is unset, which
4343 will break on DOS/Windows. Refuse to work if we cannot find
4344 a directory, not even "c:/", usable for that purpose. */
4345 for (i
= 0; i
< imax
; i
++)
4347 const char *tmp
= tempdirs
[i
];
4348 char buf
[FILENAME_MAX
];
4354 tmp
= getenv (tmp
+ 1);
4358 /* Some lusers set TMPDIR=e:, probably because some losing
4359 programs cannot handle multiple slashes if they use e:/.
4360 e: fails in `access' below, so we interpret e: as e:/. */
4361 tmp_len
= strlen(tmp
);
4362 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
4365 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
4370 /* Note that `access' can lie to us if the directory resides on a
4371 read-only filesystem, like CD-ROM or a write-protected floppy.
4372 The only way to be really sure is to actually create a file and
4373 see if it succeeds. But I think that's too much to ask. */
4374 if (tmp
&& access (tmp
, D_OK
) == 0)
4376 setenv ("TMPDIR", tmp
, 1);
4383 Fcons (build_string ("no usable temporary directories found!!"),
4385 "While setting TMPDIR: ");
4387 /* Note the startup time, so we know not to clear the screen if we
4388 exit immediately; see IT_reset_terminal_modes.
4389 (Yes, I know `clock' returns zero the first time it's called, but
4390 I do this anyway, in case some wiseguy changes that at some point.) */
4391 startup_time
= clock ();
4393 /* Find our root from argv[0]. Assuming argv[0] is, say,
4394 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4395 root
= alloca (MAXPATHLEN
+ 20);
4396 _fixpath (argv
[0], root
);
4397 msdos_downcase_filename (root
);
4398 len
= strlen (root
);
4399 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4403 && (strcmp (root
+ len
- 4, "/bin") == 0
4404 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4405 root
[len
- 4] = '\0';
4407 strcpy (root
, "c:/emacs"); /* let's be defensive */
4408 len
= strlen (root
);
4409 strcpy (emacsroot
, root
);
4411 /* We default HOME to our root. */
4412 setenv ("HOME", root
, 0);
4414 /* We default EMACSPATH to root + "/bin". */
4415 strcpy (root
+ len
, "/bin");
4416 setenv ("EMACSPATH", root
, 0);
4418 /* I don't expect anybody to ever use other terminals so the internal
4419 terminal is the default. */
4420 setenv ("TERM", "internal", 0);
4422 #ifdef HAVE_X_WINDOWS
4423 /* Emacs expects DISPLAY to be set. */
4424 setenv ("DISPLAY", "unix:0.0", 0);
4427 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4428 downcase it and mirror the backslashes. */
4429 s
= getenv ("COMSPEC");
4430 if (!s
) s
= "c:/command.com";
4431 t
= alloca (strlen (s
) + 1);
4433 dostounix_filename (t
);
4434 setenv ("SHELL", t
, 0);
4436 /* PATH is also downcased and backslashes mirrored. */
4437 s
= getenv ("PATH");
4439 t
= alloca (strlen (s
) + 3);
4440 /* Current directory is always considered part of MsDos's path but it is
4441 not normally mentioned. Now it is. */
4442 strcat (strcpy (t
, ".;"), s
);
4443 dostounix_filename (t
); /* Not a single file name, but this should work. */
4444 setenv ("PATH", t
, 1);
4446 /* In some sense all dos users have root privileges, so... */
4447 setenv ("USER", "root", 0);
4448 setenv ("NAME", getenv ("USER"), 0);
4450 /* Time zone determined from country code. To make this possible, the
4451 country code may not span more than one time zone. In other words,
4452 in the USA, you lose. */
4454 switch (dos_country_code
)
4456 case 31: /* Belgium */
4457 case 32: /* The Netherlands */
4458 case 33: /* France */
4459 case 34: /* Spain */
4460 case 36: /* Hungary */
4461 case 38: /* Yugoslavia (or what's left of it?) */
4462 case 39: /* Italy */
4463 case 41: /* Switzerland */
4464 case 42: /* Tjekia */
4465 case 45: /* Denmark */
4466 case 46: /* Sweden */
4467 case 47: /* Norway */
4468 case 48: /* Poland */
4469 case 49: /* Germany */
4470 /* Daylight saving from last Sunday in March to last Sunday in
4471 September, both at 2AM. */
4472 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4474 case 44: /* United Kingdom */
4475 case 351: /* Portugal */
4476 case 354: /* Iceland */
4477 setenv ("TZ", "GMT+00", 0);
4479 case 81: /* Japan */
4480 case 82: /* Korea */
4481 setenv ("TZ", "JST-09", 0);
4483 case 90: /* Turkey */
4484 case 358: /* Finland */
4485 setenv ("TZ", "EET-02", 0);
4487 case 972: /* Israel */
4488 /* This is an approximation. (For exact rules, use the
4489 `zoneinfo/israel' file which comes with DJGPP, but you need
4490 to install it in `/usr/share/zoneinfo/' directory first.) */
4491 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4499 static int break_stat
; /* BREAK check mode status. */
4500 static int stdin_stat
; /* stdin IOCTL status. */
4504 /* These must be global. */
4505 static _go32_dpmi_seginfo ctrl_break_vector
;
4506 static _go32_dpmi_registers ctrl_break_regs
;
4507 static int ctrlbreakinstalled
= 0;
4509 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4512 ctrl_break_func (regs
)
4513 _go32_dpmi_registers
*regs
;
4519 install_ctrl_break_check ()
4521 if (!ctrlbreakinstalled
)
4523 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4524 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4525 ctrlbreakinstalled
= 1;
4526 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4527 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4529 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4533 #endif /* __DJGPP__ < 2 */
4535 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4536 control chars by DOS. Determine the keyboard type. */
4539 dos_ttraw (struct tty_display_info
*tty
)
4541 union REGS inregs
, outregs
;
4542 static int first_time
= 1;
4544 /* If we are called for the initial terminal, it's too early to do
4545 anything, and termscript isn't set up. */
4546 if (tty
->terminal
->type
== output_initial
)
4549 break_stat
= getcbrk ();
4552 install_ctrl_break_check ();
4558 int86 (0x15, &inregs
, &outregs
);
4559 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4564 #ifdef HAVE_X_WINDOWS
4565 && inhibit_window_system
4569 inregs
.x
.ax
= 0x0021;
4570 int86 (0x33, &inregs
, &outregs
);
4571 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4574 /* Reportedly, the above doesn't work for some mouse drivers. There
4575 is an additional detection method that should work, but might be
4576 a little slower. Use that as an alternative. */
4577 inregs
.x
.ax
= 0x0000;
4578 int86 (0x33, &inregs
, &outregs
);
4579 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4582 mouse_button_count
= outregs
.x
.bx
;
4584 #ifndef HAVE_X_WINDOWS
4586 /* Save the cursor shape used outside Emacs. */
4587 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4596 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4597 return (stdin_stat
!= -1);
4600 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4602 #else /* __DJGPP__ < 2 */
4606 /* I think it is wrong to overwrite `stdin_stat' every time
4607 but the first one this function is called, but I don't
4608 want to change the way it used to work in v1.x.--EZ */
4610 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4611 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4612 intdos (&inregs
, &outregs
);
4613 stdin_stat
= outregs
.h
.dl
;
4615 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4616 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4617 intdos (&inregs
, &outregs
);
4618 return !outregs
.x
.cflag
;
4620 #endif /* __DJGPP__ < 2 */
4623 /* Restore status of standard input and Ctrl-C checking. */
4628 union REGS inregs
, outregs
;
4630 setcbrk (break_stat
);
4635 #ifndef HAVE_X_WINDOWS
4636 /* Restore the cursor shape we found on startup. */
4640 inregs
.x
.cx
= outside_cursor
;
4641 int86 (0x10, &inregs
, &outregs
);
4645 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4647 #else /* not __DJGPP__ >= 2 */
4649 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4650 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4651 inregs
.x
.dx
= stdin_stat
;
4652 intdos (&inregs
, &outregs
);
4653 return !outregs
.x
.cflag
;
4655 #endif /* not __DJGPP__ >= 2 */
4659 /* Run command as specified by ARGV in directory DIR.
4660 The command is run with input from TEMPIN, output to
4661 file TEMPOUT and stderr to TEMPERR. */
4664 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4665 unsigned char **argv
;
4666 const char *working_dir
;
4667 int tempin
, tempout
, temperr
;
4670 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4671 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4672 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
4675 /* Get current directory as MSDOS cwd is not per-process. */
4678 /* If argv[0] is the shell, it might come in any lettercase.
4679 Since `Fmember' is case-sensitive, we need to downcase
4680 argv[0], even if we are on case-preserving filesystems. */
4681 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4682 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4685 if (*pl
>= 'A' && *pl
<= 'Z')
4690 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4691 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4692 && !strcmp ("-c", argv
[1]);
4695 saveargv1
= argv
[1];
4696 saveargv2
= argv
[2];
4698 /* We only need to mirror slashes if a DOS shell will be invoked
4699 not via `system' (which does the mirroring itself). Yes, that
4700 means DJGPP v1.x will lose here. */
4701 if (argv
[2] && argv
[3])
4703 char *p
= alloca (strlen (argv
[2]) + 1);
4705 strcpy (argv
[2] = p
, saveargv2
);
4706 while (*p
&& isspace (*p
))
4718 chdir (working_dir
);
4722 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4723 goto done
; /* Allocation might fail due to lack of descriptors. */
4726 mouse_get_xy (&x
, &y
);
4728 if (!noninteractive
)
4729 dos_ttcooked (); /* do it here while 0 = stdin */
4737 if (msshell
&& !argv
[3])
4739 /* MS-DOS native shells are too restrictive. For starters, they
4740 cannot grok commands longer than 126 characters. In DJGPP v2
4741 and later, `system' is much smarter, so we'll call it instead. */
4745 /* A shell gets a single argument--its full command
4746 line--whose original was saved in `saveargv2'. */
4748 /* Don't let them pass empty command lines to `system', since
4749 with some shells it will try to invoke an interactive shell,
4750 which will hang Emacs. */
4751 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4755 extern char **environ
;
4756 char **save_env
= environ
;
4757 int save_system_flags
= __system_flags
;
4759 /* Request the most powerful version of `system'. We need
4760 all the help we can get to avoid calling stock DOS shells. */
4761 __system_flags
= (__system_redirect
4762 | __system_use_shell
4763 | __system_allow_multiple_cmds
4764 | __system_allow_long_cmds
4765 | __system_handle_null_commands
4766 | __system_emulate_chdir
);
4769 result
= system (cmnd
);
4770 __system_flags
= save_system_flags
;
4774 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4778 #endif /* __DJGPP__ > 1 */
4780 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4785 emacs_close (inbak
);
4786 emacs_close (outbak
);
4787 emacs_close (errbak
);
4789 if (!noninteractive
)
4790 dos_ttraw (CURTTY ());
4794 mouse_moveto (x
, y
);
4797 /* Some programs might change the meaning of the highest bit of the
4798 text attribute byte, so we get blinking characters instead of the
4799 bright background colors. Restore that. */
4800 if (!noninteractive
)
4807 argv
[1] = saveargv1
;
4808 argv
[2] = saveargv2
;
4817 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4818 reset_all_sys_modes ();
4824 /* ------------------------- Compatibility functions -------------------
4829 /* Hostnames for a pc are not really funny,
4830 but they are used in change log so we emulate the best we can. */
4832 gethostname (p
, size
)
4836 char *q
= egetenv ("HOSTNAME");
4843 /* When time zones are set from Ms-Dos too many C-libraries are playing
4844 tricks with time values. We solve this by defining our own version
4845 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4846 once and after each call to `tzset' with TZ changed. That is
4847 accomplished by aliasing tzset to init_gettimeofday. */
4849 static struct tm time_rec
;
4852 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4860 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4864 time_rec
.tm_year
= d
.da_year
- 1900;
4865 time_rec
.tm_mon
= d
.da_mon
- 1;
4866 time_rec
.tm_mday
= d
.da_day
;
4869 time_rec
.tm_hour
= t
.ti_hour
;
4870 time_rec
.tm_min
= t
.ti_min
;
4871 time_rec
.tm_sec
= t
.ti_sec
;
4874 tm
.tm_gmtoff
= dos_timezone_offset
;
4876 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4877 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4879 /* Ignore tzp; it's obsolescent. */
4883 #endif /* __DJGPP__ < 2 */
4886 * A list of unimplemented functions that we silently ignore.
4890 unsigned alarm (s
) unsigned s
; {}
4891 fork () { return 0; }
4892 int kill (x
, y
) int x
, y
; { return -1; }
4894 void volatile pause () {}
4895 sigsetmask (x
) int x
; { return 0; }
4896 sigblock (mask
) int mask
; { return 0; }
4899 setpgrp () {return 0; }
4900 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4903 #if __DJGPP_MINOR__ < 2
4905 #ifdef POSIX_SIGNALS
4907 /* Augment DJGPP library POSIX signal functions. This is needed
4908 as of DJGPP v2.01, but might be in the library in later releases. */
4910 #include <libc/bss.h>
4912 /* A counter to know when to re-initialize the static sets. */
4913 static int sigprocmask_count
= -1;
4915 /* Which signals are currently blocked (initially none). */
4916 static sigset_t current_mask
;
4918 /* Which signals are pending (initially none). */
4919 static sigset_t msdos_pending_signals
;
4921 /* Previous handlers to restore when the blocked signals are unblocked. */
4922 typedef void (*sighandler_t
)(int);
4923 static sighandler_t prev_handlers
[320];
4925 /* A signal handler which just records that a signal occurred
4926 (it will be raised later, if and when the signal is unblocked). */
4928 sig_suspender (signo
)
4931 sigaddset (&msdos_pending_signals
, signo
);
4935 sigprocmask (how
, new_set
, old_set
)
4937 const sigset_t
*new_set
;
4943 /* If called for the first time, initialize. */
4944 if (sigprocmask_count
!= __bss_count
)
4946 sigprocmask_count
= __bss_count
;
4947 sigemptyset (&msdos_pending_signals
);
4948 sigemptyset (¤t_mask
);
4949 for (signo
= 0; signo
< 320; signo
++)
4950 prev_handlers
[signo
] = SIG_ERR
;
4954 *old_set
= current_mask
;
4959 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4965 sigemptyset (&new_mask
);
4967 /* DJGPP supports upto 320 signals. */
4968 for (signo
= 0; signo
< 320; signo
++)
4970 if (sigismember (¤t_mask
, signo
))
4971 sigaddset (&new_mask
, signo
);
4972 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4974 sigaddset (&new_mask
, signo
);
4976 /* SIGKILL is silently ignored, as on other platforms. */
4977 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4978 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4980 if (( how
== SIG_UNBLOCK
4981 && sigismember (&new_mask
, signo
)
4982 && sigismember (new_set
, signo
))
4983 || (how
== SIG_SETMASK
4984 && sigismember (&new_mask
, signo
)
4985 && !sigismember (new_set
, signo
)))
4987 sigdelset (&new_mask
, signo
);
4988 if (prev_handlers
[signo
] != SIG_ERR
)
4990 signal (signo
, prev_handlers
[signo
]);
4991 prev_handlers
[signo
] = SIG_ERR
;
4993 if (sigismember (&msdos_pending_signals
, signo
))
4995 sigdelset (&msdos_pending_signals
, signo
);
5000 current_mask
= new_mask
;
5004 #else /* not POSIX_SIGNALS */
5006 sigsetmask (x
) int x
; { return 0; }
5007 sigblock (mask
) int mask
; { return 0; }
5009 #endif /* not POSIX_SIGNALS */
5010 #endif /* not __DJGPP_MINOR__ < 2 */
5011 #endif /* __DJGPP__ > 1 */
5014 #include "sysselect.h"
5016 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5017 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5018 ((long)(time).tv_sec < 0 \
5019 || ((time).tv_sec == 0 \
5020 && (long)(time).tv_usec <= 0))
5023 /* This yields the rest of the current time slice to the task manager.
5024 It should be called by any code which knows that it has nothing
5025 useful to do except idle.
5027 I don't use __dpmi_yield here, since versions of library before 2.02
5028 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5029 on some versions of Windows 9X. */
5032 dos_yield_time_slice (void)
5034 _go32_dpmi_registers r
;
5037 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
5038 _go32_dpmi_simulate_int (0x2f, &r
);
5043 /* Only event queue is checked. */
5044 /* We don't have to call timer_check here
5045 because wait_reading_process_output takes care of that. */
5047 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5049 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5050 EMACS_TIME
*timeout
;
5058 check_input
= FD_ISSET (0, rfds
);
5069 /* If we are looking only for the terminal, with no timeout,
5070 just read it and wait -- that's more efficient. */
5073 while (!detect_input_pending ())
5075 dos_yield_time_slice ();
5080 EMACS_TIME clnow
, cllast
, cldiff
;
5083 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5085 while (!check_input
|| !detect_input_pending ())
5088 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5089 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5091 /* When seconds wrap around, we assume that no more than
5092 1 minute passed since last `gettime'. */
5093 if (EMACS_TIME_NEG_P (cldiff
))
5094 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5095 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5097 /* Stop when timeout value crosses zero. */
5098 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5101 dos_yield_time_slice ();
5111 * Define overlaid functions:
5113 * chdir -> sys_chdir
5114 * tzset -> init_gettimeofday
5115 * abort -> dos_abort
5120 extern int chdir ();
5126 int len
= strlen (path
);
5127 char *tmp
= (char *)path
;
5129 if (*tmp
&& tmp
[1] == ':')
5131 if (getdisk () != tolower (tmp
[0]) - 'a')
5132 setdisk (tolower (tmp
[0]) - 'a');
5133 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5137 if (len
> 1 && (tmp
[len
- 1] == '/'))
5139 char *tmp1
= (char *) alloca (len
+ 1);
5150 extern void tzset (void);
5153 init_gettimeofday ()
5159 ltm
= gtm
= time (NULL
);
5160 ltm
= mktime (lstm
= localtime (<m
));
5161 gtm
= mktime (gmtime (>m
));
5162 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5163 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5164 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5171 dos_abort (file
, line
)
5175 char buffer1
[200], buffer2
[400];
5178 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5179 for (i
= j
= 0; buffer1
[i
]; i
++) {
5180 buffer2
[j
++] = buffer1
[i
];
5181 buffer2
[j
++] = 0x70;
5183 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5184 ScreenSetCursor (2, 0);
5192 ScreenSetCursor (10, 0);
5193 cputs ("\r\n\nEmacs aborted!\r\n");
5195 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5196 if (screen_virtual_segment
)
5197 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5198 /* Generate traceback, so we could tell whodunit. */
5199 signal (SIGINT
, SIG_DFL
);
5200 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5201 #else /* __DJGPP_MINOR__ >= 2 */
5203 #endif /* __DJGPP_MINOR__ >= 2 */
5209 /* The following variables are required so that cus-start.el won't
5210 complain about unbound variables. */
5211 #ifndef subprocesses
5212 /* Nonzero means delete a process right away if it exits (process.c). */
5213 static int delete_exited_processes
;
5218 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5219 staticpro (&recent_doskeys
);
5221 #ifndef HAVE_X_WINDOWS
5223 /* The following two are from xfns.c: */
5224 Qreverse
= intern ("reverse");
5225 staticpro (&Qreverse
);
5227 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5228 doc
: /* *Glyph to display instead of chars not supported by current codepage.
5229 This variable is used only by MS-DOS terminals. */);
5230 Vdos_unsupported_char_glyph
= make_number ('\177');
5233 #ifndef subprocesses
5234 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5235 doc
: /* *Non-nil means delete processes immediately when they exit.
5236 A value of nil means don't delete them until `list-processes' is run. */);
5237 delete_exited_processes
= 0;
5240 defsubr (&Srecent_doskeys
);
5241 defsubr (&Smsdos_long_file_names
);
5242 defsubr (&Smsdos_downcase_filename
);
5243 defsubr (&Smsdos_remember_default_colors
);
5244 defsubr (&Smsdos_set_mouse_buttons
);
5249 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5250 (do not change this comment) */