1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999, 2000, 2001
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Contributed by Morten Welinder */
23 /* New display, keyboard, and mouse control by Kim F. Storm */
25 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
34 #include <sys/param.h>
38 #include <string.h> /* for bzero and string functions */
39 #include <sys/stat.h> /* for _fixpath */
40 #include <unistd.h> /* for chdir, dup, dup2, etc. */
43 #include <io.h> /* for setmode */
44 #include <dpmi.h> /* for __dpmi_xxx stuff */
45 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
46 #include <libc/dosio.h> /* for _USE_LFN */
47 #include <conio.h> /* for cputs */
52 #include "termhooks.h"
54 #include "dispextern.h"
64 #include "blockinput.h"
69 /* #include <process.h> */
70 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
78 #define _dos_ds _go32_info_block.selector_for_linear_memory
84 #include "syssignal.h"
90 /* If other `malloc' than ours is used, force our `sbrk' behave like
91 Unix programs expect (resize memory blocks to keep them contiguous).
92 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
93 because that's what `gmalloc' expects to get. */
97 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
98 #else /* not REL_ALLOC */
99 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
100 #endif /* not REL_ALLOC */
101 #endif /* GNU_MALLOC */
103 #endif /* not SYSTEM_MALLOC */
104 #endif /* __DJGPP__ > 1 */
123 /* ------------------------ Mouse control ---------------------------
125 * Coordinates are in screen positions and zero based.
126 * Mouse buttons are numbered from left to right and also zero based.
129 /* This used to be in termhooks.h, but mainstream Emacs code no longer
130 uses it, and it was removed... */
131 #define NUM_MOUSE_BUTTONS (5)
133 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
134 static int mouse_visible
;
136 static int mouse_last_x
;
137 static int mouse_last_y
;
139 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
140 static int mouse_button_count
;
147 if (have_mouse
> 0 && !mouse_visible
)
150 fprintf (termscript
, "<M_ON>");
152 int86 (0x33, ®s
, ®s
);
162 if (have_mouse
> 0 && mouse_visible
)
165 fprintf (termscript
, "<M_OFF>");
167 int86 (0x33, ®s
, ®s
);
173 mouse_setup_buttons (int n_buttons
)
177 mouse_button_count
= 3;
178 mouse_button_translate
[0] = 0; /* Left */
179 mouse_button_translate
[1] = 2; /* Middle */
180 mouse_button_translate
[2] = 1; /* Right */
182 else /* two, what else? */
184 mouse_button_count
= 2;
185 mouse_button_translate
[0] = 0;
186 mouse_button_translate
[1] = 1;
190 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
191 1, 1, "NSet number of mouse buttons to: ",
192 "Set the number of mouse buttons to use by Emacs.\n\
193 This is useful with mice that report the number of buttons inconsistently,\n\
194 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of\n\
195 them. This happens with wheeled mice on Windows 9X, for example.")
197 Lisp_Object nbuttons
;
201 CHECK_NUMBER (nbuttons
);
204 Fsignal (Qargs_out_of_range
,
205 Fcons (build_string ("only 2 or 3 mouse buttons are supported"),
206 Fcons (nbuttons
, Qnil
)));
207 mouse_setup_buttons (n
);
212 mouse_get_xy (int *x
, int *y
)
217 int86 (0x33, ®s
, ®s
);
229 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
231 mouse_last_x
= regs
.x
.cx
= x
* 8;
232 mouse_last_y
= regs
.x
.dx
= y
* 8;
233 int86 (0x33, ®s
, ®s
);
237 mouse_pressed (b
, xp
, yp
)
242 if (b
>= mouse_button_count
)
245 regs
.x
.bx
= mouse_button_translate
[b
];
246 int86 (0x33, ®s
, ®s
);
248 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
249 return (regs
.x
.bx
!= 0);
253 mouse_released (b
, xp
, yp
)
258 if (b
>= mouse_button_count
)
261 regs
.x
.bx
= mouse_button_translate
[b
];
262 int86 (0x33, ®s
, ®s
);
264 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
265 return (regs
.x
.bx
!= 0);
269 mouse_button_depressed (b
, xp
, yp
)
274 if (b
>= mouse_button_count
)
277 int86 (0x33, ®s
, ®s
);
278 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
288 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
291 Lisp_Object
*bar_window
, *x
, *y
;
292 enum scroll_bar_part
*part
;
296 Lisp_Object frame
, tail
;
298 /* Clear the mouse-moved flag for every frame on this display. */
299 FOR_EACH_FRAME (tail
, frame
)
300 XFRAME (frame
)->mouse_moved
= 0;
302 *f
= SELECTED_FRAME();
304 mouse_get_xy (&ix
, &iy
);
305 *time
= event_timestamp ();
306 *x
= make_number (mouse_last_x
= ix
);
307 *y
= make_number (mouse_last_y
= iy
);
315 mouse_get_xy (&x
, &y
);
316 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
321 /* Force the mouse driver to ``forget'' about any button clicks until
324 mouse_clear_clicks (void)
328 for (b
= 0; b
< mouse_button_count
; b
++)
330 int dummy_x
, dummy_y
;
332 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
333 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
343 fprintf (termscript
, "<M_INIT>");
346 int86 (0x33, ®s
, ®s
);
348 /* Reset the mouse last press/release info. It seems that Windows
349 doesn't do that automatically when function 21h is called, which
350 causes Emacs to ``remember'' the click that switched focus to the
351 window just before Emacs was started from that window. */
352 mouse_clear_clicks ();
356 regs
.x
.dx
= 8 * (ScreenCols () - 1);
357 int86 (0x33, ®s
, ®s
);
361 regs
.x
.dx
= 8 * (ScreenRows () - 1);
362 int86 (0x33, ®s
, ®s
);
368 /* ------------------------- Screen control ----------------------
372 static int internal_terminal
= 0;
374 #ifndef HAVE_X_WINDOWS
375 extern unsigned char ScreenAttrib
;
376 static int screen_face
;
378 static int screen_size_X
;
379 static int screen_size_Y
;
380 static int screen_size
;
382 static int current_pos_X
;
383 static int current_pos_Y
;
384 static int new_pos_X
;
385 static int new_pos_Y
;
387 static void *startup_screen_buffer
;
388 static int startup_screen_size_X
;
389 static int startup_screen_size_Y
;
390 static int startup_pos_X
;
391 static int startup_pos_Y
;
392 static unsigned char startup_screen_attrib
;
394 static clock_t startup_time
;
396 static int term_setup_done
;
398 static unsigned short outside_cursor
;
400 /* Similar to the_only_frame. */
401 struct x_output the_only_x_display
;
403 /* Support for DOS/V (allows Japanese characters to be displayed on
404 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
406 /* Holds the address of the text-mode screen buffer. */
407 static unsigned long screen_old_address
= 0;
408 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
409 static unsigned short screen_virtual_segment
= 0;
410 static unsigned short screen_virtual_offset
= 0;
411 /* A flag to control how to display unibyte 8-bit characters. */
412 extern int unibyte_display_via_language_environment
;
416 /* The screen colors of the curent frame, which serve as the default
417 colors for newly-created frames. */
418 static int initial_screen_colors
[2];
421 /* Update the screen from a part of relocated DOS/V screen buffer which
422 begins at OFFSET and includes COUNT characters. */
424 dosv_refresh_virtual_screen (int offset
, int count
)
428 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
431 regs
.h
.ah
= 0xff; /* update relocated screen */
432 regs
.x
.es
= screen_virtual_segment
;
433 regs
.x
.di
= screen_virtual_offset
+ offset
;
435 __dpmi_int (0x10, ®s
);
440 dos_direct_output (y
, x
, buf
, len
)
446 int t0
= 2 * (x
+ y
* screen_size_X
);
447 int t
= t0
+ (int) ScreenPrimary
;
452 dosmemput (buf
++, 1, t
);
456 /* This is faster. */
457 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
458 _farnspokeb (t
, *buf
);
460 if (screen_virtual_segment
)
461 dosv_refresh_virtual_screen (t0
, l0
);
466 /* Flash the screen as a substitute for BEEPs. */
470 do_visible_bell (xorattr
)
471 unsigned char xorattr
;
476 movl _ScreenPrimary,%%eax \n\
483 xorb %%al,%%gs:(%%ebx) \n\
486 jne visible_bell_1 \n\
488 jne visible_bell_3 \n\
490 movzwl %%ax,%%eax \n\
491 movzwl %%ax,%%eax \n\
492 movzwl %%ax,%%eax \n\
493 movzwl %%ax,%%eax \n\
495 jne visible_bell_2 \n\
496 jmp visible_bell_0 \n\
499 : "m" (xorattr
), "g" (screen_size
)
500 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
504 ScreenVisualBell (void)
506 /* This creates an xor-mask that will swap the default fore- and
507 background colors. */
508 do_visible_bell (((the_only_x_display
.foreground_pixel
509 ^ the_only_x_display
.background_pixel
)
514 #ifndef HAVE_X_WINDOWS
516 static int blink_bit
= -1; /* the state of the blink bit at startup */
518 /* Enable bright background colors. */
524 /* Remember the original state of the blink/bright-background bit.
525 It is stored at 0040:0065h in the BIOS data area. */
527 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
531 int86 (0x10, ®s
, ®s
);
534 /* Disable bright background colors (and enable blinking) if we found
535 the video system in that state at startup. */
537 maybe_enable_blinking (void)
545 int86 (0x10, ®s
, ®s
);
549 /* Return non-zero if the system has a VGA adapter. */
556 int86 (0x10, ®s
, ®s
);
557 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
562 /* Set the screen dimensions so that it can show no less than
563 ROWS x COLS frame. */
566 dos_set_window_size (rows
, cols
)
570 Lisp_Object video_mode
;
571 int video_mode_value
;
574 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
576 if (*rows
== current_rows
&& *cols
== current_cols
)
580 have_vga
= vga_installed ();
582 /* If the user specified a special video mode for these dimensions,
584 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
585 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
588 if (INTEGERP (video_mode
)
589 && (video_mode_value
= XINT (video_mode
)) > 0)
591 regs
.x
.ax
= video_mode_value
;
592 int86 (0x10, ®s
, ®s
);
596 /* Must hardware-reset the mouse, or else it won't update
597 its notion of screen dimensions for some non-standard
598 video modes. This is *painfully* slow... */
600 int86 (0x33, ®s
, ®s
);
604 /* Find one of the dimensions supported by standard EGA/VGA
605 which gives us at least the required dimensions. */
614 } std_dimension
[] = {
624 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
626 if (std_dimension
[i
].need_vga
<= have_vga
627 && std_dimension
[i
].rows
>= *rows
)
629 if (std_dimension
[i
].rows
!= current_rows
630 || *cols
!= current_cols
)
631 _set_screen_lines (std_dimension
[i
].rows
);
638 #else /* not __DJGPP__ > 1 */
640 else if (*rows
<= 25)
642 if (current_rows
!= 25 || current_cols
!= 80)
645 int86 (0x10, ®s
, ®s
);
648 int86 (0x10, ®s
, ®s
);
651 int86 (0x10, ®s
, ®s
);
653 int86 (0x10, ®s
, ®s
);
656 else if (*rows
<= 50)
657 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
658 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
661 int86 (0x10, ®s
, ®s
);
664 int86 (0x10, ®s
, ®s
);
667 int86 (0x10, ®s
, ®s
);
670 int86 (0x10, ®s
, ®s
);
672 #endif /* not __DJGPP__ > 1 */
680 /* Tell the caller what dimensions have been REALLY set. */
681 *rows
= ScreenRows ();
682 *cols
= ScreenCols ();
684 /* Update Emacs' notion of screen dimensions. */
685 screen_size_X
= *cols
;
686 screen_size_Y
= *rows
;
687 screen_size
= *cols
* *rows
;
690 /* If the dimensions changed, the mouse highlight info is invalid. */
691 if (current_rows
!= *rows
|| current_cols
!= *cols
)
693 struct frame
*f
= SELECTED_FRAME();
694 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
695 Lisp_Object window
= dpyinfo
->mouse_face_window
;
697 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
699 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
700 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
701 dpyinfo
->mouse_face_window
= Qnil
;
706 /* Enable bright background colors. */
709 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
710 be defensive anyway. */
711 if (screen_virtual_segment
)
712 dosv_refresh_virtual_screen (0, *cols
* *rows
);
715 /* If we write a character in the position where the mouse is,
716 the mouse cursor may need to be refreshed. */
726 mouse_get_xy (&x
, &y
);
727 if (y
!= new_pos_Y
|| x
< new_pos_X
)
733 #define DEFAULT_CURSOR_START (-1)
734 #define DEFAULT_CURSOR_WIDTH (-1)
735 #define BOX_CURSOR_WIDTH (-32)
737 /* Set cursor to begin at scan line START_LINE in the character cell
738 and extend for WIDTH scan lines. Scan lines are counted from top
739 of the character cell, starting from zero. */
741 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
744 unsigned desired_cursor
;
746 int max_line
, top_line
, bot_line
;
748 /* Avoid the costly BIOS call if F isn't the currently selected
749 frame. Allow for NULL as unconditionally meaning the selected
751 if (f
&& f
!= SELECTED_FRAME())
754 /* The character cell size in scan lines is stored at 40:85 in the
756 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
759 default: /* this relies on CGA cursor emulation being ON! */
776 if (width
== BOX_CURSOR_WIDTH
)
781 else if (start_line
!= DEFAULT_CURSOR_START
)
783 top_line
= start_line
;
784 bot_line
= top_line
- width
- 1;
786 else if (width
!= DEFAULT_CURSOR_WIDTH
)
789 bot_line
= -1 - width
;
792 top_line
= bot_line
+ 1;
796 /* [31, 0] seems to DTRT for all screen sizes. */
800 else /* WIDTH is positive */
802 if (start_line
!= DEFAULT_CURSOR_START
)
803 bot_line
= start_line
;
804 top_line
= bot_line
- (width
- 1);
807 /* If the current cursor shape is already what they want, we are
809 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
810 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
814 regs
.x
.cx
= desired_cursor
;
815 __dpmi_int (0x10, ®s
);
816 #endif /* __DJGPP__ > 1 */
820 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
822 if (EQ (cursor_type
, Qbar
))
824 /* Just BAR means the normal EGA/VGA cursor. */
825 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
827 else if (CONSP (cursor_type
) && EQ (XCAR (cursor_type
), Qbar
))
829 Lisp_Object bar_parms
= XCDR (cursor_type
);
832 if (INTEGERP (bar_parms
))
834 /* Feature: negative WIDTH means cursor at the top
835 of the character cell, zero means invisible cursor. */
836 width
= XINT (bar_parms
);
837 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
840 else if (CONSP (bar_parms
)
841 && INTEGERP (XCAR (bar_parms
))
842 && INTEGERP (XCDR (bar_parms
)))
844 int start_line
= XINT (XCDR (bar_parms
));
846 width
= XINT (XCAR (bar_parms
));
847 msdos_set_cursor_shape (f
, start_line
, width
);
851 /* Treat anything unknown as "box cursor". This includes nil, so
852 that a frame which doesn't specify a cursor type gets a box,
853 which is the default in Emacs. */
854 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
867 union REGS inregs
, outregs
;
870 intdos (&inregs
, &outregs
);
874 /* Given a face id FACE, extract the face parameters to be used for
875 display until the face changes. The face parameters (actually, its
876 color) are used to construct the video attribute byte for each
877 glyph during the construction of the buffer that is then blitted to
880 IT_set_face (int face
)
882 struct frame
*sf
= SELECTED_FRAME();
883 struct face
*fp
= FACE_FROM_ID (sf
, face
);
884 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
885 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
890 /* The default face for the frame should always be realized and
898 dflt_fg
= dfp
->foreground
;
899 dflt_bg
= dfp
->background
;
901 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
902 mean use the colors of the default face. Note that we assume all
903 16 colors to be available for the background, since Emacs switches
904 on this mode (and loses the blinking attribute) at startup. */
905 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
906 fg
= FRAME_FOREGROUND_PIXEL (sf
);
907 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
908 fg
= FRAME_BACKGROUND_PIXEL (sf
);
909 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
910 bg
= FRAME_BACKGROUND_PIXEL (sf
);
911 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
912 bg
= FRAME_FOREGROUND_PIXEL (sf
);
914 /* Make sure highlighted lines really stand out, come what may. */
915 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
917 unsigned long tem
= fg
;
922 /* If the user requested inverse video, obey. */
925 unsigned long tem2
= fg
;
931 fprintf (termscript
, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face
,
932 fp
->foreground
, fp
->background
, fg
, bg
);
933 if (fg
>= 0 && fg
< 16)
935 ScreenAttrib
&= 0xf0;
938 if (bg
>= 0 && bg
< 16)
940 ScreenAttrib
&= 0x0f;
941 ScreenAttrib
|= ((bg
& 0x0f) << 4);
945 Lisp_Object Vdos_unsupported_char_glyph
;
948 IT_write_glyphs (struct glyph
*str
, int str_len
)
950 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
951 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
952 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
953 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
954 register int sl
= str_len
;
955 register int tlen
= GLYPH_TABLE_LENGTH
;
956 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
958 /* If terminal_coding does any conversion, use it, otherwise use
959 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
960 because it always returns 1 if terminal_coding.src_multibyte is 1. */
961 struct coding_system
*coding
=
962 (terminal_coding
.common_flags
& CODING_REQUIRE_ENCODING_MASK
964 : &safe_terminal_coding
);
967 /* Do we need to consider conversion of unibyte characters to
969 int convert_unibyte_characters
970 = (NILP (current_buffer
->enable_multibyte_characters
)
971 && unibyte_display_via_language_environment
);
973 unsigned char conversion_buffer
[256];
974 int conversion_buffer_size
= sizeof conversion_buffer
;
976 if (str_len
<= 0) return;
978 screen_buf
= screen_bp
= alloca (str_len
* 2);
979 screen_buf_end
= screen_buf
+ str_len
* 2;
980 sf
= SELECTED_FRAME();
982 /* Since faces get cached and uncached behind our back, we can't
983 rely on their indices in the cache being consistent across
984 invocations. So always reset the screen face to the default
985 face of the frame, before writing glyphs, and let the glyphs
986 set the right face if it's different from the default. */
987 IT_set_face (DEFAULT_FACE_ID
);
989 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
991 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
994 int cf
, chlen
, enclen
;
995 unsigned char workbuf
[MAX_MULTIBYTE_LENGTH
], *buf
;
998 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
999 only for the redisplay code to know how many columns does
1000 this character occupy on the screen. Skip padding glyphs. */
1001 if (CHAR_GLYPH_PADDING_P (*str
))
1008 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
1009 int glyph_not_in_table
= 0;
1011 /* If g is negative, it means we have a multibyte character
1012 in *str. That's what GLYPH_FROM_CHAR_GLYPH returns for
1013 multibyte characters. */
1014 if (g
< 0 || g
>= tlen
)
1016 /* This glyph doesn't have an entry in Vglyph_table. */
1018 glyph_not_in_table
= 1;
1022 /* This glyph has an entry in Vglyph_table, so process
1023 any aliases before testing for simpleness. */
1024 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
1025 ch
= FAST_GLYPH_CHAR (g
);
1028 /* Convert the character code to multibyte, if they
1029 requested display via language environment. We only want
1030 to convert unibyte characters to multibyte in unibyte
1031 buffers! Otherwise, the 8-bit value in CH came from the
1032 display table set up to display foreign characters. */
1033 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
1035 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
1036 ch
= unibyte_char_to_multibyte (ch
);
1038 /* Invalid characters are displayed with a special glyph. */
1039 if (! CHAR_VALID_P (ch
, 0))
1041 g
= !NILP (Vdos_unsupported_char_glyph
)
1042 ? Vdos_unsupported_char_glyph
1043 : MAKE_GLYPH (sf
, '\177', GLYPH_FACE (sf
, g
));
1044 ch
= FAST_GLYPH_CHAR (g
);
1047 /* If the face of this glyph is different from the current
1048 screen face, update the screen attribute byte. */
1050 if (cf
!= screen_face
)
1051 IT_set_face (cf
); /* handles invalid faces gracefully */
1053 if (glyph_not_in_table
|| GLYPH_SIMPLE_P (tbase
, tlen
, g
))
1055 /* We generate the multi-byte form of CH in WORKBUF. */
1056 chlen
= CHAR_STRING (ch
, workbuf
);
1061 /* We have a string in Vglyph_table. */
1062 chlen
= GLYPH_LENGTH (tbase
, g
);
1063 buf
= GLYPH_STRING (tbase
, g
);
1066 /* If the character is not multibyte, don't bother converting it. */
1069 *conversion_buffer
= (unsigned char)ch
;
1075 coding
->src_multibyte
= 1;
1076 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
1077 conversion_buffer_size
);
1078 chlen
-= coding
->consumed
;
1079 enclen
= coding
->produced
;
1081 /* Replace glyph codes that cannot be converted by
1082 terminal_coding with Vdos_unsupported_char_glyph. */
1083 if (*conversion_buffer
== '?')
1085 unsigned char *cbp
= conversion_buffer
;
1087 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
1088 *cbp
++ = unsupported_char
;
1089 if (unsupported_face
!= screen_face
)
1090 IT_set_face (unsupported_face
);
1094 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
1096 /* The allocated buffer for screen writes is too small.
1097 Flush it and loop again without incrementing STR, so
1098 that the next loop will begin with the same glyph. */
1099 int nbytes
= screen_bp
- screen_buf
;
1102 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
1103 if (screen_virtual_segment
)
1104 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
1105 new_pos_X
+= nbytes
/ 2;
1108 /* Prepare to reuse the same buffer again. */
1109 screen_bp
= screen_buf
;
1113 /* There's enough place in the allocated buffer to add
1114 the encoding of this glyph. */
1116 /* First, copy the encoded bytes. */
1117 for (bp
= conversion_buffer
; enclen
--; bp
++)
1119 *screen_bp
++ = (unsigned char)*bp
;
1120 *screen_bp
++ = ScreenAttrib
;
1122 fputc (*bp
, termscript
);
1125 /* Now copy the bytes not consumed by the encoding. */
1128 buf
+= coding
->consumed
;
1132 fputc (*buf
, termscript
);
1133 *screen_bp
++ = (unsigned char)*buf
++;
1134 *screen_bp
++ = ScreenAttrib
;
1138 /* Update STR and its remaining length. */
1145 /* Dump whatever is left in the screen buffer. */
1147 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1148 if (screen_virtual_segment
)
1149 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1150 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1152 /* We may have to output some codes to terminate the writing. */
1153 if (CODING_REQUIRE_FLUSHING (coding
))
1155 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1156 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
1157 if (coding
->produced
> 0)
1159 screen_buf
= alloca (coding
->produced
* 2);
1160 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
1161 coding
->produced
--; bp
++)
1163 *screen_bp
++ = (unsigned char)*bp
;
1164 *screen_bp
++ = ScreenAttrib
;
1166 fputc (*bp
, termscript
);
1168 offset
+= screen_bp
- screen_buf
;
1170 dosmemput (screen_buf
, screen_bp
- screen_buf
,
1171 (int)ScreenPrimary
+ offset
);
1172 if (screen_virtual_segment
)
1173 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1174 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1179 /************************************************************************
1180 Mouse Highlight (and friends..)
1181 ************************************************************************/
1183 /* This is used for debugging, to turn off note_mouse_highlight. */
1184 int disable_mouse_highlight
;
1186 /* If non-nil, dos_rawgetc generates an event to display that string.
1187 (The display is done in keyboard.c:read_char, by calling
1189 static Lisp_Object help_echo
;
1190 static Lisp_Object previous_help_echo
; /* a helper temporary variable */
1192 /* These record the window, the object and the position where the help
1193 echo string was generated. */
1194 static Lisp_Object help_echo_window
;
1195 static Lisp_Object help_echo_object
;
1196 static int help_echo_pos
;
1198 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1200 /* Set the mouse pointer shape according to whether it is in the
1201 area where the mouse highlight is in effect. */
1203 IT_set_mouse_pointer (int mode
)
1205 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1206 many possibilities to change its shape, and the available
1207 functionality pretty much sucks (e.g., almost every reasonable
1208 shape will conceal the character it is on). Since the color of
1209 the pointer changes in the highlighted area, it is not clear to
1210 me whether anything else is required, anyway. */
1213 /* Display the active region described by mouse_face_*
1214 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1216 show_mouse_face (struct display_info
*dpyinfo
, int hl
)
1218 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1219 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1224 /* If window is in the process of being destroyed, don't bother
1226 if (w
->current_matrix
== NULL
)
1227 goto set_cursor_shape
;
1229 /* Recognize when we are called to operate on rows that don't exist
1230 anymore. This can happen when a window is split. */
1231 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1232 goto set_cursor_shape
;
1234 /* There's no sense to do anything if the mouse face isn't realized. */
1237 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1239 goto set_cursor_shape
;
1242 /* Note that mouse_face_beg_row etc. are window relative. */
1243 for (i
= dpyinfo
->mouse_face_beg_row
;
1244 i
<= dpyinfo
->mouse_face_end_row
;
1247 int start_hpos
, end_hpos
;
1248 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1250 /* Don't do anything if row doesn't have valid contents. */
1251 if (!row
->enabled_p
)
1254 /* For all but the first row, the highlight starts at column 0. */
1255 if (i
== dpyinfo
->mouse_face_beg_row
)
1256 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1260 if (i
== dpyinfo
->mouse_face_end_row
)
1261 end_hpos
= dpyinfo
->mouse_face_end_col
;
1263 end_hpos
= row
->used
[TEXT_AREA
];
1265 if (end_hpos
<= start_hpos
)
1267 /* Record that some glyphs of this row are displayed in
1269 row
->mouse_face_p
= hl
> 0;
1272 int vpos
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1273 int kstart
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1274 int nglyphs
= end_hpos
- start_hpos
;
1275 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1276 int start_offset
= offset
;
1279 fprintf (termscript
, "\n<MH+ %d-%d:%d>",
1280 kstart
, kstart
+ nglyphs
- 1, vpos
);
1283 IT_set_face (dpyinfo
->mouse_face_face_id
);
1284 /* Since we are going to change only the _colors_ of the
1285 displayed text, there's no need to go through all the
1286 pain of generating and encoding the text from the glyphs.
1287 Instead, we simply poke the attribute byte of each
1288 affected position in video memory with the colors
1289 computed by IT_set_face! */
1290 _farsetsel (_dos_ds
);
1293 _farnspokeb (offset
, ScreenAttrib
);
1296 if (screen_virtual_segment
)
1297 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1302 /* We are removing a previously-drawn mouse highlight. The
1303 safest way to do so is to redraw the glyphs anew, since
1304 all kinds of faces and display tables could have changed
1306 int nglyphs
= end_hpos
- start_hpos
;
1307 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1309 if (end_hpos
>= row
->used
[TEXT_AREA
])
1310 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1312 /* IT_write_glyphs writes at cursor position, so we need to
1313 temporarily move cursor coordinates to the beginning of
1314 the highlight region. */
1315 new_pos_X
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1316 new_pos_Y
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1319 fprintf (termscript
, "<MH- %d-%d:%d>",
1320 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1321 IT_write_glyphs (row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1323 fputs ("\n", termscript
);
1331 /* Change the mouse pointer shape. */
1332 IT_set_mouse_pointer (hl
);
1335 /* Clear out the mouse-highlighted active region.
1336 Redraw it un-highlighted first. */
1338 clear_mouse_face (struct display_info
*dpyinfo
)
1340 if (! NILP (dpyinfo
->mouse_face_window
))
1341 show_mouse_face (dpyinfo
, 0);
1343 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1344 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1345 dpyinfo
->mouse_face_window
= Qnil
;
1348 /* Find the glyph matrix position of buffer position POS in window W.
1349 *HPOS and *VPOS are set to the positions found. W's current glyphs
1350 must be up to date. If POS is above window start return (0, 0).
1351 If POS is after end of W, return end of last line in W. */
1353 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1357 int maybe_next_line_p
= 0;
1358 int line_start_position
;
1359 int yb
= window_text_bottom_y (w
);
1360 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0);
1361 struct glyph_row
*best_row
= row
;
1365 if (row
->used
[TEXT_AREA
])
1366 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1368 line_start_position
= 0;
1370 if (line_start_position
> pos
)
1372 /* If the position sought is the end of the buffer,
1373 don't include the blank lines at the bottom of the window. */
1374 else if (line_start_position
== pos
1375 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1377 maybe_next_line_p
= 1;
1380 else if (line_start_position
> 0)
1383 /* Don't overstep the last matrix row, lest we get into the
1384 never-never land... */
1385 if (row
->y
+ 1 >= yb
)
1391 /* Find the right column within BEST_ROW. */
1394 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1396 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1399 charpos
= glyph
->charpos
;
1406 else if (charpos
> pos
)
1408 else if (charpos
> 0)
1412 /* If we're looking for the end of the buffer,
1413 and we didn't find it in the line we scanned,
1414 use the start of the following line. */
1415 if (maybe_next_line_p
)
1422 *hpos
= lastcol
+ 1;
1426 /* Take proper action when mouse has moved to the mode or top line of
1427 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1428 mode line. X is relative to the start of the text display area of
1429 W, so the width of fringes and scroll bars must be subtracted
1430 to get a position relative to the start of the mode line. */
1432 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1434 struct frame
*f
= XFRAME (w
->frame
);
1435 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1436 struct glyph_row
*row
;
1439 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1441 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1445 extern Lisp_Object Qhelp_echo
;
1446 struct glyph
*glyph
, *end
;
1447 Lisp_Object help
, map
;
1449 /* Find the glyph under X. */
1450 glyph
= row
->glyphs
[TEXT_AREA
]
1451 + x
- FRAME_LEFT_SCROLL_BAR_WIDTH (f
) * CANON_X_UNIT (f
);
1452 end
= glyph
+ row
->used
[TEXT_AREA
];
1454 && STRINGP (glyph
->object
)
1455 && XSTRING (glyph
->object
)->intervals
1456 && glyph
->charpos
>= 0
1457 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1459 /* If we're on a string with `help-echo' text property,
1460 arrange for the help to be displayed. This is done by
1461 setting the global variable help_echo to the help string. */
1462 help
= Fget_text_property (make_number (glyph
->charpos
),
1463 Qhelp_echo
, glyph
->object
);
1467 XSETWINDOW (help_echo_window
, w
);
1468 help_echo_object
= glyph
->object
;
1469 help_echo_pos
= glyph
->charpos
;
1475 /* Take proper action when the mouse has moved to position X, Y on
1476 frame F as regards highlighting characters that have mouse-face
1477 properties. Also de-highlighting chars where the mouse was before.
1478 X and Y can be negative or out of range. */
1480 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1482 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1487 /* When a menu is active, don't highlight because this looks odd. */
1488 if (mouse_preempted
)
1491 if (disable_mouse_highlight
1492 || !f
->glyphs_initialized_p
)
1495 dpyinfo
->mouse_face_mouse_x
= x
;
1496 dpyinfo
->mouse_face_mouse_y
= y
;
1497 dpyinfo
->mouse_face_mouse_frame
= f
;
1499 if (dpyinfo
->mouse_face_defer
)
1504 dpyinfo
->mouse_face_deferred_gc
= 1;
1508 /* Which window is that in? */
1509 window
= window_from_coordinates (f
, x
, y
, &portion
, 0);
1511 /* If we were displaying active text in another window, clear that. */
1512 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1513 clear_mouse_face (dpyinfo
);
1515 /* Not on a window -> return. */
1516 if (!WINDOWP (window
))
1519 /* Convert to window-relative coordinates. */
1520 w
= XWINDOW (window
);
1521 x
-= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1522 y
-= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1524 if (portion
== 1 || portion
== 3)
1526 /* Mouse is on the mode or top line. */
1527 IT_note_mode_line_highlight (w
, x
, portion
== 1);
1531 IT_set_mouse_pointer (0);
1533 /* Are we in a window whose display is up to date?
1534 And verify the buffer's text has not changed. */
1535 if (/* Within text portion of the window. */
1537 && EQ (w
->window_end_valid
, w
->buffer
)
1538 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1539 && (XFASTINT (w
->last_overlay_modified
)
1540 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1543 struct glyph_row
*row
;
1544 struct glyph
*glyph
;
1545 int nrows
= w
->current_matrix
->nrows
;
1547 /* Find the glyph under X/Y. */
1549 if (y
>= 0 && y
< nrows
)
1551 row
= MATRIX_ROW (w
->current_matrix
, y
);
1552 /* Give up if some row before the one we are looking for is
1554 for (i
= 0; i
<= y
; i
++)
1555 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1557 if (i
> y
/* all rows upto and including the one at Y are enabled */
1558 && row
->displays_text_p
1559 && x
< window_box_width (w
, TEXT_AREA
))
1561 glyph
= row
->glyphs
[TEXT_AREA
];
1562 if (x
>= row
->used
[TEXT_AREA
])
1567 if (!BUFFERP (glyph
->object
))
1573 /* Clear mouse face if X/Y not over text. */
1576 clear_mouse_face (dpyinfo
);
1580 if (!BUFFERP (glyph
->object
))
1582 pos
= glyph
->charpos
;
1584 /* Check for mouse-face and help-echo. */
1586 extern Lisp_Object Qmouse_face
;
1587 Lisp_Object mouse_face
, overlay
, position
;
1588 Lisp_Object
*overlay_vec
;
1590 struct buffer
*obuf
;
1593 /* If we get an out-of-range value, return now; avoid an error. */
1594 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1597 /* Make the window's buffer temporarily current for
1598 overlays_at and compute_char_face. */
1599 obuf
= current_buffer
;
1600 current_buffer
= XBUFFER (w
->buffer
);
1606 /* Is this char mouse-active or does it have help-echo? */
1607 XSETINT (position
, pos
);
1609 /* Put all the overlays we want in a vector in overlay_vec.
1610 Store the length in len. If there are more than 10, make
1611 enough space for all, and try again. */
1613 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1614 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
, 0);
1615 if (noverlays
> len
)
1618 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1619 noverlays
= overlays_at (pos
,
1620 0, &overlay_vec
, &len
, NULL
, NULL
, 0);
1623 /* Sort overlays into increasing priority order. */
1624 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1626 /* Check mouse-face highlighting. */
1627 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1628 && y
>= dpyinfo
->mouse_face_beg_row
1629 && y
<= dpyinfo
->mouse_face_end_row
1630 && (y
> dpyinfo
->mouse_face_beg_row
1631 || x
>= dpyinfo
->mouse_face_beg_col
)
1632 && (y
< dpyinfo
->mouse_face_end_row
1633 || x
< dpyinfo
->mouse_face_end_col
1634 || dpyinfo
->mouse_face_past_end
)))
1636 /* Clear the display of the old active region, if any. */
1637 clear_mouse_face (dpyinfo
);
1639 /* Find highest priority overlay that has a mouse-face prop. */
1641 for (i
= noverlays
- 1; i
>= 0; --i
)
1643 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1644 if (!NILP (mouse_face
))
1646 overlay
= overlay_vec
[i
];
1651 /* If no overlay applies, get a text property. */
1653 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1656 /* Handle the overlay case. */
1657 if (! NILP (overlay
))
1659 /* Find the range of text around this char that
1660 should be active. */
1661 Lisp_Object before
, after
;
1664 before
= Foverlay_start (overlay
);
1665 after
= Foverlay_end (overlay
);
1666 /* Record this as the current active region. */
1667 fast_find_position (w
, XFASTINT (before
),
1668 &dpyinfo
->mouse_face_beg_col
,
1669 &dpyinfo
->mouse_face_beg_row
);
1670 dpyinfo
->mouse_face_past_end
1671 = !fast_find_position (w
, XFASTINT (after
),
1672 &dpyinfo
->mouse_face_end_col
,
1673 &dpyinfo
->mouse_face_end_row
);
1674 dpyinfo
->mouse_face_window
= window
;
1675 dpyinfo
->mouse_face_face_id
1676 = face_at_buffer_position (w
, pos
, 0, 0,
1677 &ignore
, pos
+ 1, 1);
1679 /* Display it as active. */
1680 show_mouse_face (dpyinfo
, 1);
1682 /* Handle the text property case. */
1683 else if (! NILP (mouse_face
))
1685 /* Find the range of text around this char that
1686 should be active. */
1687 Lisp_Object before
, after
, beginning
, end
;
1690 beginning
= Fmarker_position (w
->start
);
1691 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1692 - XFASTINT (w
->window_end_pos
)));
1694 = Fprevious_single_property_change (make_number (pos
+ 1),
1696 w
->buffer
, beginning
);
1698 = Fnext_single_property_change (position
, Qmouse_face
,
1700 /* Record this as the current active region. */
1701 fast_find_position (w
, XFASTINT (before
),
1702 &dpyinfo
->mouse_face_beg_col
,
1703 &dpyinfo
->mouse_face_beg_row
);
1704 dpyinfo
->mouse_face_past_end
1705 = !fast_find_position (w
, XFASTINT (after
),
1706 &dpyinfo
->mouse_face_end_col
,
1707 &dpyinfo
->mouse_face_end_row
);
1708 dpyinfo
->mouse_face_window
= window
;
1709 dpyinfo
->mouse_face_face_id
1710 = face_at_buffer_position (w
, pos
, 0, 0,
1711 &ignore
, pos
+ 1, 1);
1713 /* Display it as active. */
1714 show_mouse_face (dpyinfo
, 1);
1718 /* Look for a `help-echo' property. */
1721 extern Lisp_Object Qhelp_echo
;
1723 /* Check overlays first. */
1725 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1727 overlay
= overlay_vec
[i
];
1728 help
= Foverlay_get (overlay
, Qhelp_echo
);
1734 help_echo_window
= window
;
1735 help_echo_object
= overlay
;
1736 help_echo_pos
= pos
;
1738 /* Try text properties. */
1739 else if (NILP (help
)
1740 && ((STRINGP (glyph
->object
)
1741 && glyph
->charpos
>= 0
1742 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1743 || (BUFFERP (glyph
->object
)
1744 && glyph
->charpos
>= BEGV
1745 && glyph
->charpos
< ZV
)))
1747 help
= Fget_text_property (make_number (glyph
->charpos
),
1748 Qhelp_echo
, glyph
->object
);
1752 help_echo_window
= window
;
1753 help_echo_object
= glyph
->object
;
1754 help_echo_pos
= glyph
->charpos
;
1761 current_buffer
= obuf
;
1767 IT_clear_end_of_line (int first_unused
)
1771 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1772 extern int fatal_error_in_progress
;
1774 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1778 i
= (j
= first_unused
- new_pos_X
) * 2;
1780 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1781 spaces
= sp
= alloca (i
);
1786 *sp
++ = ScreenAttrib
;
1790 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1791 if (screen_virtual_segment
)
1792 dosv_refresh_virtual_screen (offset
, i
/ 2);
1794 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1795 Let's follow their lead, in case someone relies on this. */
1796 new_pos_X
= first_unused
;
1800 IT_clear_screen (void)
1803 fprintf (termscript
, "<CLR:SCR>");
1804 /* We are sometimes called (from clear_garbaged_frames) when a new
1805 frame is being created, but its faces are not yet realized. In
1806 such a case we cannot call IT_set_face, since it will fail to find
1807 any valid faces and will abort. Instead, use the initial screen
1808 colors; that should mimic what a Unix tty does, which simply clears
1809 the screen with whatever default colors are in use. */
1810 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1811 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1816 if (screen_virtual_segment
)
1817 dosv_refresh_virtual_screen (0, screen_size
);
1818 new_pos_X
= new_pos_Y
= 0;
1822 IT_clear_to_end (void)
1825 fprintf (termscript
, "<CLR:EOS>");
1827 while (new_pos_Y
< screen_size_Y
) {
1829 IT_clear_end_of_line (screen_size_X
);
1835 IT_cursor_to (int y
, int x
)
1838 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1843 static int cursor_cleared
;
1846 IT_display_cursor (int on
)
1848 if (on
&& cursor_cleared
)
1850 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1853 else if (!on
&& !cursor_cleared
)
1855 ScreenSetCursor (-1, -1);
1860 /* Emacs calls cursor-movement functions a lot when it updates the
1861 display (probably a legacy of old terminals where you cannot
1862 update a screen line without first moving the cursor there).
1863 However, cursor movement is expensive on MSDOS (it calls a slow
1864 BIOS function and requires 2 mode switches), while actual screen
1865 updates access the video memory directly and don't depend on
1866 cursor position. To avoid slowing down the redisplay, we cheat:
1867 all functions that move the cursor only set internal variables
1868 which record the cursor position, whereas the cursor is only
1869 moved to its final position whenever screen update is complete.
1871 `IT_cmgoto' is called from the keyboard reading loop and when the
1872 frame update is complete. This means that we are ready for user
1873 input, so we update the cursor position to show where the point is,
1874 and also make the mouse pointer visible.
1876 Special treatment is required when the cursor is in the echo area,
1877 to put the cursor at the end of the text displayed there. */
1880 IT_cmgoto (FRAME_PTR f
)
1882 /* Only set the cursor to where it should be if the display is
1883 already in sync with the window contents. */
1884 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1886 /* FIXME: This needs to be rewritten for the new redisplay, or
1889 static int previous_pos_X
= -1;
1891 update_cursor_pos
= 1; /* temporary!!! */
1893 /* If the display is in sync, forget any previous knowledge about
1894 cursor position. This is primarily for unexpected events like
1895 C-g in the minibuffer. */
1896 if (update_cursor_pos
&& previous_pos_X
>= 0)
1897 previous_pos_X
= -1;
1898 /* If we are in the echo area, put the cursor at the
1899 end of the echo area message. */
1900 if (!update_cursor_pos
1901 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1903 int tem_X
= current_pos_X
, dummy
;
1905 if (echo_area_glyphs
)
1907 tem_X
= echo_area_glyphs_length
;
1908 /* Save current cursor position, to be restored after the
1909 echo area message is erased. Only remember one level
1910 of previous cursor position. */
1911 if (previous_pos_X
== -1)
1912 ScreenGetCursor (&dummy
, &previous_pos_X
);
1914 else if (previous_pos_X
>= 0)
1916 /* We wind up here after the echo area message is erased.
1917 Restore the cursor position we remembered above. */
1918 tem_X
= previous_pos_X
;
1919 previous_pos_X
= -1;
1922 if (current_pos_X
!= tem_X
)
1925 update_cursor_pos
= 1;
1930 if (update_cursor_pos
1931 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1933 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1935 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1938 /* Maybe cursor is invisible, so make it visible. */
1939 IT_display_cursor (1);
1941 /* Mouse pointer should be always visible if we are waiting for
1948 IT_update_begin (struct frame
*f
)
1950 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1951 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1955 if (f
&& f
== mouse_face_frame
)
1957 /* Don't do highlighting for mouse motion during the update. */
1958 display_info
->mouse_face_defer
= 1;
1960 /* If F needs to be redrawn, simply forget about any prior mouse
1962 if (FRAME_GARBAGED_P (f
))
1963 display_info
->mouse_face_window
= Qnil
;
1965 /* Can we tell that this update does not affect the window
1966 where the mouse highlight is? If so, no need to turn off.
1967 Likewise, don't do anything if none of the enabled rows
1968 contains glyphs highlighted in mouse face. */
1969 if (!NILP (display_info
->mouse_face_window
)
1970 && WINDOWP (display_info
->mouse_face_window
))
1972 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1975 /* If the mouse highlight is in the window that was deleted
1976 (e.g., if it was popped by completion), clear highlight
1978 if (NILP (w
->buffer
))
1979 display_info
->mouse_face_window
= Qnil
;
1982 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1983 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1984 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1988 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1989 clear_mouse_face (display_info
);
1992 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1994 /* If the frame with mouse highlight was deleted, invalidate the
1996 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1997 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1998 display_info
->mouse_face_window
= Qnil
;
1999 display_info
->mouse_face_deferred_gc
= 0;
2000 display_info
->mouse_face_mouse_frame
= NULL
;
2007 IT_update_end (struct frame
*f
)
2009 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
2012 Lisp_Object Qcursor_type
;
2015 IT_frame_up_to_date (struct frame
*f
)
2017 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
2018 Lisp_Object new_cursor
, frame_desired_cursor
;
2021 if (dpyinfo
->mouse_face_deferred_gc
2022 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
2025 if (dpyinfo
->mouse_face_mouse_frame
)
2026 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
2027 dpyinfo
->mouse_face_mouse_x
,
2028 dpyinfo
->mouse_face_mouse_y
);
2029 dpyinfo
->mouse_face_deferred_gc
= 0;
2033 /* Set the cursor type to whatever they wanted. In a minibuffer
2034 window, we want the cursor to appear only if we are reading input
2035 from this window, and we want the cursor to be taken from the
2036 frame parameters. For the selected window, we use either its
2037 buffer-local value or the value from the frame parameters if the
2038 buffer doesn't define its local value for the cursor type. */
2039 sw
= XWINDOW (f
->selected_window
);
2040 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
2041 if (cursor_in_echo_area
2042 && FRAME_HAS_MINIBUF_P (f
)
2043 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
2044 && sw
== XWINDOW (echo_area_window
))
2045 new_cursor
= frame_desired_cursor
;
2048 struct buffer
*b
= XBUFFER (sw
->buffer
);
2050 if (EQ (b
->cursor_type
, Qt
))
2051 new_cursor
= frame_desired_cursor
;
2052 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
2053 new_cursor
= Fcons (Qbar
, make_number (0));
2055 new_cursor
= b
->cursor_type
;
2058 IT_set_cursor_type (f
, new_cursor
);
2060 IT_cmgoto (f
); /* position cursor when update is done */
2063 /* Copy LEN glyphs displayed on a single line whose vertical position
2064 is YPOS, beginning at horizontal position XFROM to horizontal
2065 position XTO, by moving blocks in the video memory. Used by
2066 functions that insert and delete glyphs. */
2068 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
2070 /* The offsets of source and destination relative to the
2071 conventional memorty selector. */
2072 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
2073 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
2075 if (from
== to
|| len
<= 0)
2078 _farsetsel (_dos_ds
);
2080 /* The source and destination might overlap, so we need to move
2081 glyphs non-destructively. */
2084 for ( ; len
; from
+= 2, to
+= 2, len
--)
2085 _farnspokew (to
, _farnspeekw (from
));
2089 from
+= (len
- 1) * 2;
2090 to
+= (len
- 1) * 2;
2091 for ( ; len
; from
-= 2, to
-= 2, len
--)
2092 _farnspokew (to
, _farnspeekw (from
));
2094 if (screen_virtual_segment
)
2095 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
2098 /* Insert and delete glyphs. */
2100 IT_insert_glyphs (start
, len
)
2101 register struct glyph
*start
;
2104 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
2106 /* Shift right the glyphs from the nominal cursor position to the
2107 end of this line. */
2108 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2110 /* Now write the glyphs to be inserted. */
2111 IT_write_glyphs (start
, len
);
2115 IT_delete_glyphs (n
)
2121 /* set-window-configuration on window.c needs this. */
2123 x_set_menu_bar_lines (f
, value
, oldval
)
2125 Lisp_Object value
, oldval
;
2127 set_menu_bar_lines (f
, value
, oldval
);
2130 /* This was copied from xfaces.c */
2132 extern Lisp_Object Qbackground_color
;
2133 extern Lisp_Object Qforeground_color
;
2134 Lisp_Object Qreverse
;
2135 extern Lisp_Object Qtitle
;
2137 /* IT_set_terminal_modes is called when emacs is started,
2138 resumed, and whenever the screen is redrawn! */
2141 IT_set_terminal_modes (void)
2144 fprintf (termscript
, "\n<SET_TERM>");
2146 screen_size_X
= ScreenCols ();
2147 screen_size_Y
= ScreenRows ();
2148 screen_size
= screen_size_X
* screen_size_Y
;
2150 new_pos_X
= new_pos_Y
= 0;
2151 current_pos_X
= current_pos_Y
= -1;
2153 if (term_setup_done
)
2155 term_setup_done
= 1;
2157 startup_screen_size_X
= screen_size_X
;
2158 startup_screen_size_Y
= screen_size_Y
;
2159 startup_screen_attrib
= ScreenAttrib
;
2162 /* Is DOS/V (or any other RSIS software which relocates
2163 the screen) installed? */
2165 unsigned short es_value
;
2168 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2169 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2170 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2171 else if (screen_old_address
) /* already switched to Japanese mode once */
2172 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2174 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2176 es_value
= regs
.x
.es
;
2177 __dpmi_int (0x10, ®s
);
2179 if (regs
.x
.es
!= es_value
)
2181 /* screen_old_address is only set if ScreenPrimary does NOT
2182 already point to the relocated buffer address returned by
2183 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2184 ScreenPrimary to that address at startup under DOS/V. */
2185 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2186 screen_old_address
= ScreenPrimary
;
2187 screen_virtual_segment
= regs
.x
.es
;
2188 screen_virtual_offset
= regs
.x
.di
;
2189 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2192 #endif /* __DJGPP__ > 1 */
2194 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2195 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2198 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2199 screen_size_X
, screen_size_Y
);
2204 /* IT_reset_terminal_modes is called when emacs is
2205 suspended or killed. */
2208 IT_reset_terminal_modes (void)
2210 int display_row_start
= (int) ScreenPrimary
;
2211 int saved_row_len
= startup_screen_size_X
* 2;
2212 int update_row_len
= ScreenCols () * 2;
2213 int current_rows
= ScreenRows ();
2214 int to_next_row
= update_row_len
;
2215 unsigned char *saved_row
= startup_screen_buffer
;
2216 int cursor_pos_X
= ScreenCols () - 1;
2217 int cursor_pos_Y
= ScreenRows () - 1;
2220 fprintf (termscript
, "\n<RESET_TERM>");
2222 if (!term_setup_done
)
2227 /* Leave the video system in the same state as we found it,
2228 as far as the blink/bright-background bit is concerned. */
2229 maybe_enable_blinking ();
2231 /* We have a situation here.
2232 We cannot just do ScreenUpdate(startup_screen_buffer) because
2233 the luser could have changed screen dimensions inside Emacs
2234 and failed (or didn't want) to restore them before killing
2235 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2236 thus will happily use memory outside what was allocated for
2237 `startup_screen_buffer'.
2238 Thus we only restore as much as the current screen dimensions
2239 can hold, and clear the rest (if the saved screen is smaller than
2240 the current) with the color attribute saved at startup. The cursor
2241 is also restored within the visible dimensions. */
2243 ScreenAttrib
= startup_screen_attrib
;
2245 /* Don't restore the screen if we are exiting less than 2 seconds
2246 after startup: we might be crashing, and the screen might show
2247 some vital clues to what's wrong. */
2248 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2251 if (screen_virtual_segment
)
2252 dosv_refresh_virtual_screen (0, screen_size
);
2254 if (update_row_len
> saved_row_len
)
2255 update_row_len
= saved_row_len
;
2256 if (current_rows
> startup_screen_size_Y
)
2257 current_rows
= startup_screen_size_Y
;
2260 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2261 update_row_len
/ 2, current_rows
);
2263 while (current_rows
--)
2265 dosmemput (saved_row
, update_row_len
, display_row_start
);
2266 if (screen_virtual_segment
)
2267 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2268 update_row_len
/ 2);
2269 saved_row
+= saved_row_len
;
2270 display_row_start
+= to_next_row
;
2273 if (startup_pos_X
< cursor_pos_X
)
2274 cursor_pos_X
= startup_pos_X
;
2275 if (startup_pos_Y
< cursor_pos_Y
)
2276 cursor_pos_Y
= startup_pos_Y
;
2278 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2279 xfree (startup_screen_buffer
);
2281 term_setup_done
= 0;
2285 IT_set_terminal_window (int foo
)
2289 /* Remember the screen colors of the curent frame, to serve as the
2290 default colors for newly-created frames. */
2291 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2292 Smsdos_remember_default_colors
, 1, 1, 0,
2293 "Remember the screen colors of the current frame.")
2299 CHECK_FRAME (frame
);
2302 /* This function is called after applying default-frame-alist to the
2303 initial frame. At that time, if reverse-colors option was
2304 specified in default-frame-alist, it was already applied, and
2305 frame colors are reversed. We need to account for that. */
2306 if (EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
))
2308 initial_screen_colors
[0] = FRAME_BACKGROUND_PIXEL (f
);
2309 initial_screen_colors
[1] = FRAME_FOREGROUND_PIXEL (f
);
2313 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2314 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2319 IT_set_frame_parameters (f
, alist
)
2324 int length
= XINT (Flength (alist
));
2327 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2329 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2330 /* Do we have to reverse the foreground and background colors? */
2331 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2332 int was_reverse
= reverse
;
2333 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2334 int need_to_reverse
;
2335 unsigned long orig_fg
;
2336 unsigned long orig_bg
;
2337 Lisp_Object frame_bg
, frame_fg
;
2338 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2340 /* If we are creating a new frame, begin with the original screen colors
2341 used for the initial frame. */
2342 if (alist
== Vdefault_frame_alist
2343 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2345 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2346 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2348 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2349 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2350 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2351 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2352 /* frame_fg and frame_bg could be nil if, for example,
2353 f->param_alist is nil, e.g. if we are called from
2354 Fmake_terminal_frame. */
2355 if (NILP (frame_fg
))
2356 frame_fg
= build_string (unspecified_fg
);
2357 if (NILP (frame_bg
))
2358 frame_bg
= build_string (unspecified_bg
);
2360 /* Extract parm names and values into those vectors. */
2362 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2367 parms
[i
] = Fcar (elt
);
2368 CHECK_SYMBOL (parms
[i
]);
2369 values
[i
] = Fcdr (elt
);
2375 for (i
= 0; i
< j
; i
++)
2377 Lisp_Object prop
, val
;
2382 if (EQ (prop
, Qreverse
))
2383 reverse
= EQ (val
, Qt
);
2386 need_to_reverse
= reverse
&& !was_reverse
;
2387 if (termscript
&& need_to_reverse
)
2388 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2390 /* Now process the alist elements in reverse of specified order. */
2391 for (i
--; i
>= 0; i
--)
2393 Lisp_Object prop
, val
;
2399 if (EQ (prop
, Qforeground_color
))
2401 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2402 ? LFACE_BACKGROUND_INDEX
2403 : LFACE_FOREGROUND_INDEX
);
2404 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2405 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2406 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2408 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2409 /* Make sure the foreground of the default face for this
2410 frame is changed as well. */
2411 XSETFRAME (frame
, f
);
2412 if (need_to_reverse
)
2414 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2416 prop
= Qbackground_color
;
2421 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2427 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2430 else if (EQ (prop
, Qbackground_color
))
2432 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2433 ? LFACE_FOREGROUND_INDEX
2434 : LFACE_BACKGROUND_INDEX
);
2435 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2436 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2437 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2439 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2440 /* Make sure the background of the default face for this
2441 frame is changed as well. */
2442 XSETFRAME (frame
, f
);
2443 if (need_to_reverse
)
2445 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2447 prop
= Qforeground_color
;
2452 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2458 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2461 else if (EQ (prop
, Qtitle
))
2463 x_set_title (f
, val
);
2465 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
2467 else if (EQ (prop
, Qcursor_type
))
2469 IT_set_cursor_type (f
, val
);
2471 fprintf (termscript
, "<CTYPE: %s>\n",
2472 EQ (val
, Qbar
) || CONSP (val
) && EQ (XCAR (val
), Qbar
)
2475 store_frame_param (f
, prop
, val
);
2478 /* If they specified "reverse", but not the colors, we need to swap
2479 the current frame colors. */
2480 if (need_to_reverse
)
2486 XSETFRAME (frame
, f
);
2487 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2488 tty_color_name (f
, orig_bg
),
2494 XSETFRAME (frame
, f
);
2495 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2496 tty_color_name (f
, orig_fg
),
2504 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2505 if (f
== SELECTED_FRAME())
2510 extern void init_frame_faces (FRAME_PTR
);
2512 #endif /* !HAVE_X_WINDOWS */
2515 /* Do we need the internal terminal? */
2518 internal_terminal_init ()
2520 char *term
= getenv ("TERM");
2522 struct frame
*sf
= SELECTED_FRAME();
2524 #ifdef HAVE_X_WINDOWS
2525 if (!inhibit_window_system
)
2530 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2532 if (getenv ("EMACSTEST"))
2533 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2535 #ifndef HAVE_X_WINDOWS
2536 if (!internal_terminal
|| inhibit_window_system
)
2538 sf
->output_method
= output_termcap
;
2542 Vwindow_system
= intern ("pc");
2543 Vwindow_system_version
= make_number (1);
2544 sf
->output_method
= output_msdos_raw
;
2546 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2547 screen_old_address
= 0;
2549 /* Forget the stale screen colors as well. */
2550 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2552 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2553 the_only_x_display
.background_pixel
= 7; /* White */
2554 the_only_x_display
.foreground_pixel
= 0; /* Black */
2556 colors
= getenv ("EMACSCOLORS");
2557 if (colors
&& strlen (colors
) >= 2)
2559 /* The colors use 4 bits each (we enable bright background). */
2560 if (isdigit (colors
[0]))
2562 else if (isxdigit (colors
[0]))
2563 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2564 if (colors
[0] >= 0 && colors
[0] < 16)
2565 the_only_x_display
.foreground_pixel
= colors
[0];
2566 if (isdigit (colors
[1]))
2568 else if (isxdigit (colors
[1]))
2569 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2570 if (colors
[1] >= 0 && colors
[1] < 16)
2571 the_only_x_display
.background_pixel
= colors
[1];
2573 the_only_x_display
.line_height
= 1;
2574 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2575 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2576 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2577 the_only_x_display
.display_info
.mouse_face_beg_row
=
2578 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2579 the_only_x_display
.display_info
.mouse_face_end_row
=
2580 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2581 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2582 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2583 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2584 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2585 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2587 init_frame_faces (sf
);
2589 ring_bell_hook
= IT_ring_bell
;
2590 insert_glyphs_hook
= IT_insert_glyphs
;
2591 delete_glyphs_hook
= IT_delete_glyphs
;
2592 write_glyphs_hook
= IT_write_glyphs
;
2593 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2594 clear_to_end_hook
= IT_clear_to_end
;
2595 clear_end_of_line_hook
= IT_clear_end_of_line
;
2596 clear_frame_hook
= IT_clear_screen
;
2597 update_begin_hook
= IT_update_begin
;
2598 update_end_hook
= IT_update_end
;
2599 frame_up_to_date_hook
= IT_frame_up_to_date
;
2601 /* These hooks are called by term.c without being checked. */
2602 set_terminal_modes_hook
= IT_set_terminal_modes
;
2603 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2604 set_terminal_window_hook
= IT_set_terminal_window
;
2605 char_ins_del_ok
= 0;
2609 dos_get_saved_screen (screen
, rows
, cols
)
2614 #ifndef HAVE_X_WINDOWS
2615 *screen
= startup_screen_buffer
;
2616 *cols
= startup_screen_size_X
;
2617 *rows
= startup_screen_size_Y
;
2618 return *screen
!= (char *)0;
2624 #ifndef HAVE_X_WINDOWS
2626 /* We are not X, but we can emulate it well enough for our needs... */
2630 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2631 error ("Not running under a window system");
2637 /* ----------------------- Keyboard control ----------------------
2639 * Keymaps reflect the following keyboard layout:
2641 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2642 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2643 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2644 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2648 #define Ignore 0x0000
2649 #define Normal 0x0000 /* normal key - alt changes scan-code */
2650 #define FctKey 0x1000 /* func key if c == 0, else c */
2651 #define Special 0x2000 /* func key even if c != 0 */
2652 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2653 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2654 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2655 #define Grey 0x6000 /* Grey keypad key */
2657 #define Alt 0x0100 /* alt scan-code */
2658 #define Ctrl 0x0200 /* ctrl scan-code */
2659 #define Shift 0x0400 /* shift scan-code */
2661 static int extended_kbd
; /* 101 (102) keyboard present. */
2663 struct kbd_translate
{
2666 unsigned short code
;
2669 struct dos_keyboard_map
2674 struct kbd_translate
*translate_table
;
2678 static struct dos_keyboard_map us_keyboard
= {
2680 /* 01234567890123456789012345678901234567890 12345678901234 */
2681 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2682 /* 0123456789012345678901234567890123456789 012345678901234 */
2683 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2684 0, /* no Alt-Gr key */
2685 0 /* no translate table */
2688 static struct dos_keyboard_map fr_keyboard
= {
2690 /* 012 3456789012345678901234567890123456789012345678901234 */
2691 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2692 /* 0123456789012345678901234567890123456789012345678901234 */
2693 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2694 /* 01234567 89012345678901234567890123456789012345678901234 */
2696 0 /* no translate table */
2700 * Italian keyboard support, country code 39.
2703 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2704 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2707 static struct kbd_translate it_kbd_translate_table
[] = {
2708 { 0x56, 0x3c, Normal
| 13 },
2709 { 0x56, 0x3e, Normal
| 27 },
2712 static struct dos_keyboard_map it_keyboard
= {
2714 /* 0 123456789012345678901234567890123456789012345678901234 */
2715 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2716 /* 01 23456789012345678901234567890123456789012345678901234 */
2717 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2718 /* 0123456789012345678901234567890123456789012345678901234 */
2720 it_kbd_translate_table
2723 static struct dos_keyboard_map dk_keyboard
= {
2725 /* 0123456789012345678901234567890123456789012345678901234 */
2726 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2727 /* 01 23456789012345678901234567890123456789012345678901234 */
2728 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2729 /* 0123456789012345678901234567890123456789012345678901234 */
2731 0 /* no translate table */
2734 static struct kbd_translate jp_kbd_translate_table
[] = {
2735 { 0x73, 0x5c, Normal
| 0 },
2736 { 0x73, 0x5f, Normal
| 0 },
2737 { 0x73, 0x1c, Map
| 0 },
2738 { 0x7d, 0x5c, Normal
| 13 },
2739 { 0x7d, 0x7c, Normal
| 13 },
2740 { 0x7d, 0x1c, Map
| 13 },
2743 static struct dos_keyboard_map jp_keyboard
= {
2745 /* 0123456789012 345678901234567890123456789012345678901234 */
2746 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2747 /* 01 23456789012345678901234567890123456789012345678901234 */
2748 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2749 0, /* no Alt-Gr key */
2750 jp_kbd_translate_table
2753 static struct keyboard_layout_list
2756 struct dos_keyboard_map
*keyboard_map
;
2757 } keyboard_layout_list
[] =
2766 static struct dos_keyboard_map
*keyboard
;
2767 static int keyboard_map_all
;
2768 static int international_keyboard
;
2771 dos_set_keyboard (code
, always
)
2776 _go32_dpmi_registers regs
;
2778 /* See if Keyb.Com is installed (for international keyboard support).
2779 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2780 of Windows 9X! So don't do that! */
2782 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2783 _go32_dpmi_simulate_int (0x2f, ®s
);
2784 if (regs
.h
.al
== 0xff)
2785 international_keyboard
= 1;
2787 /* Initialize to US settings, for countries that don't have their own. */
2788 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2789 keyboard_map_all
= always
;
2790 dos_keyboard_layout
= 1;
2792 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2793 if (code
== keyboard_layout_list
[i
].country_code
)
2795 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2796 keyboard_map_all
= always
;
2797 dos_keyboard_layout
= code
;
2805 unsigned char char_code
; /* normal code */
2806 unsigned char meta_code
; /* M- code */
2807 unsigned char keypad_code
; /* keypad code */
2808 unsigned char editkey_code
; /* edit key */
2809 } keypad_translate_map
[] = {
2810 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2811 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2812 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2813 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2814 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2815 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2816 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2817 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2818 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2819 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2820 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2825 unsigned char char_code
; /* normal code */
2826 unsigned char keypad_code
; /* keypad code */
2827 } grey_key_translate_map
[] = {
2828 '/', 0xaf, /* kp-decimal */
2829 '*', 0xaa, /* kp-multiply */
2830 '-', 0xad, /* kp-subtract */
2831 '+', 0xab, /* kp-add */
2832 '\r', 0x8d /* kp-enter */
2835 static unsigned short
2836 ibmpc_translate_map
[] =
2838 /* --------------- 00 to 0f --------------- */
2839 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2840 Alt
| ModFct
| 0x1b, /* Escape */
2841 Normal
| 1, /* '1' */
2842 Normal
| 2, /* '2' */
2843 Normal
| 3, /* '3' */
2844 Normal
| 4, /* '4' */
2845 Normal
| 5, /* '5' */
2846 Normal
| 6, /* '6' */
2847 Normal
| 7, /* '7' */
2848 Normal
| 8, /* '8' */
2849 Normal
| 9, /* '9' */
2850 Normal
| 10, /* '0' */
2851 Normal
| 11, /* '-' */
2852 Normal
| 12, /* '=' */
2853 Special
| 0x08, /* Backspace */
2854 ModFct
| 0x74, /* Tab/Backtab */
2856 /* --------------- 10 to 1f --------------- */
2869 ModFct
| 0x0d, /* Return */
2874 /* --------------- 20 to 2f --------------- */
2883 Map
| 40, /* '\'' */
2885 Ignore
, /* Left shift */
2886 Map
| 41, /* '\\' */
2892 /* --------------- 30 to 3f --------------- */
2899 Ignore
, /* Right shift */
2900 Grey
| 1, /* Grey * */
2902 Normal
| 55, /* ' ' */
2903 Ignore
, /* Caps Lock */
2904 FctKey
| 0xbe, /* F1 */
2905 FctKey
| 0xbf, /* F2 */
2906 FctKey
| 0xc0, /* F3 */
2907 FctKey
| 0xc1, /* F4 */
2908 FctKey
| 0xc2, /* F5 */
2910 /* --------------- 40 to 4f --------------- */
2911 FctKey
| 0xc3, /* F6 */
2912 FctKey
| 0xc4, /* F7 */
2913 FctKey
| 0xc5, /* F8 */
2914 FctKey
| 0xc6, /* F9 */
2915 FctKey
| 0xc7, /* F10 */
2916 Ignore
, /* Num Lock */
2917 Ignore
, /* Scroll Lock */
2918 KeyPad
| 7, /* Home */
2919 KeyPad
| 8, /* Up */
2920 KeyPad
| 9, /* Page Up */
2921 Grey
| 2, /* Grey - */
2922 KeyPad
| 4, /* Left */
2923 KeyPad
| 5, /* Keypad 5 */
2924 KeyPad
| 6, /* Right */
2925 Grey
| 3, /* Grey + */
2926 KeyPad
| 1, /* End */
2928 /* --------------- 50 to 5f --------------- */
2929 KeyPad
| 2, /* Down */
2930 KeyPad
| 3, /* Page Down */
2931 KeyPad
| 0, /* Insert */
2932 KeyPad
| 10, /* Delete */
2933 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2934 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2935 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2936 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2937 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2938 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2939 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2940 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2941 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2942 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2943 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2944 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2946 /* --------------- 60 to 6f --------------- */
2947 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2948 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2949 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2950 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2951 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2952 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2953 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2954 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2955 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2956 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2957 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2958 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2959 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2960 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2961 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2962 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2964 /* --------------- 70 to 7f --------------- */
2965 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2966 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2967 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2968 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2969 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2970 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2971 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2972 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2973 Alt
| Map
| 1, /* '1' */
2974 Alt
| Map
| 2, /* '2' */
2975 Alt
| Map
| 3, /* '3' */
2976 Alt
| Map
| 4, /* '4' */
2977 Alt
| Map
| 5, /* '5' */
2978 Alt
| Map
| 6, /* '6' */
2979 Alt
| Map
| 7, /* '7' */
2980 Alt
| Map
| 8, /* '8' */
2982 /* --------------- 80 to 8f --------------- */
2983 Alt
| Map
| 9, /* '9' */
2984 Alt
| Map
| 10, /* '0' */
2985 Alt
| Map
| 11, /* '-' */
2986 Alt
| Map
| 12, /* '=' */
2987 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2988 FctKey
| 0xc8, /* F11 */
2989 FctKey
| 0xc9, /* F12 */
2990 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2991 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2992 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2993 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2994 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2995 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2996 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2997 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2998 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
3000 /* --------------- 90 to 9f --------------- */
3001 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
3002 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
3003 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
3004 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
3005 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
3006 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
3007 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
3008 Alt
| FctKey
| 0x50, /* (Alt) Home */
3009 Alt
| FctKey
| 0x52, /* (Alt) Up */
3010 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
3011 Ignore
, /* NO KEY */
3012 Alt
| FctKey
| 0x51, /* (Alt) Left */
3013 Ignore
, /* NO KEY */
3014 Alt
| FctKey
| 0x53, /* (Alt) Right */
3015 Ignore
, /* NO KEY */
3016 Alt
| FctKey
| 0x57, /* (Alt) End */
3018 /* --------------- a0 to af --------------- */
3019 Alt
| KeyPad
| 2, /* (Alt) Down */
3020 Alt
| KeyPad
| 3, /* (Alt) Page Down */
3021 Alt
| KeyPad
| 0, /* (Alt) Insert */
3022 Alt
| KeyPad
| 10, /* (Alt) Delete */
3023 Alt
| Grey
| 0, /* (Alt) Grey / */
3024 Alt
| FctKey
| 0x09, /* (Alt) Tab */
3025 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
3028 /* These bit-positions corresponds to values returned by BIOS */
3029 #define SHIFT_P 0x0003 /* two bits! */
3030 #define CTRL_P 0x0004
3031 #define ALT_P 0x0008
3032 #define SCRLOCK_P 0x0010
3033 #define NUMLOCK_P 0x0020
3034 #define CAPSLOCK_P 0x0040
3035 #define ALT_GR_P 0x0800
3036 #define SUPER_P 0x4000 /* pseudo */
3037 #define HYPER_P 0x8000 /* pseudo */
3040 dos_get_modifiers (keymask
)
3047 /* Calculate modifier bits */
3048 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
3049 int86 (0x16, ®s
, ®s
);
3053 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
3054 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3058 mask
= regs
.h
.al
& (SHIFT_P
|
3059 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3061 /* Do not break international keyboard support. */
3062 /* When Keyb.Com is loaded, the right Alt key is */
3063 /* used for accessing characters like { and } */
3064 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
3067 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
3070 if (dos_hyper_key
== 1)
3073 modifiers
|= hyper_modifier
;
3075 else if (dos_super_key
== 1)
3078 modifiers
|= super_modifier
;
3080 else if (!international_keyboard
)
3082 /* If Keyb.Com is NOT installed, let Right Alt behave
3083 like the Left Alt. */
3089 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
3092 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
3094 if (dos_hyper_key
== 2)
3097 modifiers
|= hyper_modifier
;
3099 else if (dos_super_key
== 2)
3102 modifiers
|= super_modifier
;
3110 modifiers
|= shift_modifier
;
3112 modifiers
|= ctrl_modifier
;
3114 modifiers
|= meta_modifier
;
3121 #define NUM_RECENT_DOSKEYS (100)
3122 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
3123 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3124 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3126 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3127 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
3128 Each input key receives two values in this vector: first the ASCII code,\n\
3129 and then the scan code.")
3132 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
3135 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3136 return Fvector (total_doskeys
, keys
);
3139 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3140 bcopy (keys
+ recent_doskeys_index
,
3141 XVECTOR (val
)->contents
,
3142 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3144 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3145 recent_doskeys_index
* sizeof (Lisp_Object
));
3150 /* Get a char from keyboard. Function keys are put into the event queue. */
3154 struct input_event event
;
3157 #ifndef HAVE_X_WINDOWS
3158 /* Maybe put the cursor where it should be. */
3159 IT_cmgoto (SELECTED_FRAME());
3162 /* The following condition is equivalent to `kbhit ()', except that
3163 it uses the bios to do its job. This pleases DESQview/X. */
3164 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3165 int86 (0x16, ®s
, ®s
),
3166 (regs
.x
.flags
& 0x40) == 0)
3169 register unsigned char c
;
3170 int sc
, code
= -1, mask
, kp_mode
;
3173 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3174 int86 (0x16, ®s
, ®s
);
3179 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3181 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3182 recent_doskeys_index
= 0;
3183 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3185 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3186 recent_doskeys_index
= 0;
3188 modifiers
= dos_get_modifiers (&mask
);
3190 #ifndef HAVE_X_WINDOWS
3191 if (!NILP (Vdos_display_scancodes
))
3194 sprintf (buf
, "%02x:%02x*%04x",
3195 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3196 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3204 case 10: /* Ctrl Grey Enter */
3205 code
= Ctrl
| Grey
| 4;
3207 case 13: /* Grey Enter */
3210 case '/': /* Grey / */
3220 /* Try the keyboard-private translation table first. */
3221 if (keyboard
->translate_table
)
3223 struct kbd_translate
*p
= keyboard
->translate_table
;
3227 if (p
->sc
== sc
&& p
->ch
== c
)
3235 /* If the private table didn't translate it, use the general
3239 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3241 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3248 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3249 Emacs is ready to read a key. Therefore, if they press
3250 `Alt-x' when Emacs is busy, by the time we get to
3251 `dos_get_modifiers', they might have already released the
3252 Alt key, and Emacs gets just `x', which is BAD.
3253 However, for keys with the `Map' property set, the ASCII
3254 code returns zero iff Alt is pressed. So, when we DON'T
3255 have to support international_keyboard, we don't have to
3256 distinguish between the left and right Alt keys, and we
3257 can set the META modifier for any keys with the `Map'
3258 property if they return zero ASCII code (c = 0). */
3260 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3261 modifiers
|= meta_modifier
;
3263 modifiers
|= ctrl_modifier
;
3265 modifiers
|= shift_modifier
;
3268 switch (code
& 0xf000)
3271 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3273 c
= 0; /* Special */
3286 if (c
== 0) /* ctrl-break */
3288 return c
; /* ALT-nnn */
3290 if (!keyboard_map_all
)
3299 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3300 if (!keyboard_map_all
)
3304 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3305 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3309 code
= keyboard
->shifted
[code
];
3311 modifiers
&= ~shift_modifier
;
3314 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3315 code
= keyboard
->alt_gr
[code
];
3317 code
= keyboard
->unshifted
[code
];
3322 if (c
== 0xe0) /* edit key */
3325 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3326 kp_mode
= dos_keypad_mode
& 0x03;
3328 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3333 if (code
== 10 && dos_decimal_point
)
3334 return dos_decimal_point
;
3335 return keypad_translate_map
[code
].char_code
;
3338 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3342 code
= keypad_translate_map
[code
].meta_code
;
3343 modifiers
= meta_modifier
;
3347 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3354 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3355 if (dos_keypad_mode
& kp_mode
)
3356 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3358 code
= grey_key_translate_map
[code
].char_code
;
3367 event
.kind
= non_ascii_keystroke
;
3369 event
.kind
= ascii_keystroke
;
3371 event
.modifiers
= modifiers
;
3372 event
.frame_or_window
= selected_frame
;
3374 event
.timestamp
= event_timestamp ();
3375 kbd_buffer_store_event (&event
);
3378 if (have_mouse
> 0 && !mouse_preempted
)
3380 int but
, press
, x
, y
, ok
;
3381 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3383 /* Check for mouse movement *before* buttons. */
3384 mouse_check_moved ();
3386 /* If the mouse moved from the spot of its last sighting, we
3387 might need to update mouse highlight. */
3388 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3390 previous_help_echo
= help_echo
;
3391 help_echo
= help_echo_object
= help_echo_window
= Qnil
;
3393 IT_note_mouse_highlight (SELECTED_FRAME(),
3394 mouse_last_x
, mouse_last_y
);
3395 /* If the contents of the global variable help_echo has
3396 changed, generate a HELP_EVENT. */
3397 if (!NILP (help_echo
) || !NILP (previous_help_echo
))
3399 /* HELP_EVENT takes 2 events in the event loop. */
3400 event
.kind
= HELP_EVENT
;
3401 event
.frame_or_window
= selected_frame
;
3402 event
.arg
= help_echo_object
;
3403 event
.x
= make_number (help_echo_pos
);
3404 event
.timestamp
= event_timestamp ();
3406 kbd_buffer_store_event (&event
);
3407 if (WINDOWP (help_echo_window
))
3408 event
.frame_or_window
= help_echo_window
;
3409 event
.arg
= help_echo
;
3411 kbd_buffer_store_event (&event
);
3415 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3416 for (press
= 0; press
< 2; press
++)
3418 int button_num
= but
;
3421 ok
= mouse_pressed (but
, &x
, &y
);
3423 ok
= mouse_released (but
, &x
, &y
);
3426 /* Allow a simultaneous press/release of Mouse-1 and
3427 Mouse-2 to simulate Mouse-3 on two-button mice. */
3428 if (mouse_button_count
== 2 && but
< 2)
3430 int x2
, y2
; /* don't clobber original coordinates */
3432 /* If only one button is pressed, wait 100 msec and
3433 check again. This way, Speedy Gonzales isn't
3434 punished, while the slow get their chance. */
3435 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3436 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3441 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3442 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3447 event
.kind
= mouse_click
;
3448 event
.code
= button_num
;
3449 event
.modifiers
= dos_get_modifiers (0)
3450 | (press
? down_modifier
: up_modifier
);
3453 event
.frame_or_window
= selected_frame
;
3455 event
.timestamp
= event_timestamp ();
3456 kbd_buffer_store_event (&event
);
3464 static int prev_get_char
= -1;
3466 /* Return 1 if a key is ready to be read without suspending execution. */
3470 if (prev_get_char
!= -1)
3473 return ((prev_get_char
= dos_rawgetc ()) != -1);
3476 /* Read a key. Return -1 if no key is ready. */
3480 if (prev_get_char
!= -1)
3482 int c
= prev_get_char
;
3487 return dos_rawgetc ();
3490 #ifndef HAVE_X_WINDOWS
3491 /* See xterm.c for more info. */
3493 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
3495 register int pix_x
, pix_y
;
3496 register int *x
, *y
;
3500 if (bounds
) abort ();
3502 /* Ignore clipping. */
3509 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
3512 register int *pix_x
, *pix_y
;
3518 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3521 Actually, I don't know the meaning of all the parameters of the functions
3522 here -- I only know how they are called by xmenu.c. I could of course
3523 grab the nearest Xlib manual (down the hall, second-to-last door on the
3524 left), but I don't think it's worth the effort. */
3526 /* These hold text of the current and the previous menu help messages. */
3527 static char *menu_help_message
, *prev_menu_help_message
;
3528 /* Pane number and item number of the menu item which generated the
3529 last menu help message. */
3530 static int menu_help_paneno
, menu_help_itemno
;
3537 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3538 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3542 /* Allocate some (more) memory for MENU ensuring that there is room for one
3546 IT_menu_make_room (XMenu
*menu
)
3548 if (menu
->allocated
== 0)
3550 int count
= menu
->allocated
= 10;
3551 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3552 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3553 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3554 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3556 else if (menu
->allocated
== menu
->count
)
3558 int count
= menu
->allocated
= menu
->allocated
+ 10;
3560 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3562 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3564 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3566 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3570 /* Search the given menu structure for a given pane number. */
3573 IT_menu_search_pane (XMenu
*menu
, int pane
)
3578 for (i
= 0; i
< menu
->count
; i
++)
3579 if (menu
->submenu
[i
])
3581 if (pane
== menu
->panenumber
[i
])
3582 return menu
->submenu
[i
];
3583 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3589 /* Determine how much screen space a given menu needs. */
3592 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3594 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3597 maxheight
= menu
->count
;
3598 for (i
= 0; i
< menu
->count
; i
++)
3600 if (menu
->submenu
[i
])
3602 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3603 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3604 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3607 *width
= menu
->width
+ maxsubwidth
;
3608 *height
= maxheight
;
3611 /* Display MENU at (X,Y) using FACES. */
3614 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3616 int i
, j
, face
, width
;
3617 struct glyph
*text
, *p
;
3620 int enabled
, mousehere
;
3622 struct frame
*sf
= SELECTED_FRAME();
3624 menu_help_message
= NULL
;
3626 width
= menu
->width
;
3627 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3628 ScreenGetCursor (&row
, &col
);
3629 mouse_get_xy (&mx
, &my
);
3630 IT_update_begin (sf
);
3631 for (i
= 0; i
< menu
->count
; i
++)
3633 int max_width
= width
+ 2;
3635 IT_cursor_to (y
+ i
, x
);
3637 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3638 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3639 face
= faces
[enabled
+ mousehere
* 2];
3640 /* The following if clause means that we display the menu help
3641 strings even if the menu item is currently disabled. */
3642 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3644 menu_help_message
= menu
->help_text
[i
];
3645 menu_help_paneno
= pn
- 1;
3646 menu_help_itemno
= i
;
3649 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3651 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3655 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3658 else /* make '^x' */
3660 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3663 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3667 /* Don't let the menu text overflow into the next screen row. */
3668 if (x
+ max_width
> screen_size_X
)
3670 max_width
= screen_size_X
- x
;
3671 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3673 for (; j
< max_width
- 2; j
++, p
++)
3674 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3676 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3678 IT_write_glyphs (text
, max_width
);
3681 IT_cursor_to (row
, col
);
3685 /* --------------------------- X Menu emulation ---------------------- */
3687 /* Report availability of menus. */
3695 /* Create a brand new menu structure. */
3698 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3700 return IT_menu_create ();
3703 /* Create a new pane and place it on the outer-most level. It is not
3704 clear that it should be placed out there, but I don't know what else
3708 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3716 IT_menu_make_room (menu
);
3717 menu
->submenu
[menu
->count
] = IT_menu_create ();
3718 menu
->text
[menu
->count
] = txt
;
3719 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3720 menu
->help_text
[menu
->count
] = NULL
;
3723 /* Adjust length for possible control characters (which will
3724 be written as ^x). */
3725 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3729 if (len
> menu
->width
)
3732 return menu
->panecount
;
3735 /* Create a new item in a menu pane. */
3738 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3739 int foo
, char *txt
, int enable
, char *help_text
)
3745 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3747 IT_menu_make_room (menu
);
3748 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3749 menu
->text
[menu
->count
] = txt
;
3750 menu
->panenumber
[menu
->count
] = enable
;
3751 menu
->help_text
[menu
->count
] = help_text
;
3754 /* Adjust length for possible control characters (which will
3755 be written as ^x). */
3756 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3760 if (len
> menu
->width
)
3766 /* Decide where the menu would be placed if requested at (X,Y). */
3769 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3770 int *ulx
, int *uly
, int *width
, int *height
)
3772 IT_menu_calc_size (menu
, width
, height
);
3778 struct IT_menu_state
3780 void *screen_behind
;
3787 /* Display menu, wait for user's response, and return that response. */
3790 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3791 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3792 void (*help_callback
)(char *, int, int))
3794 struct IT_menu_state
*state
;
3799 Lisp_Object selectface
;
3800 int leave
, result
, onepane
;
3801 int title_faces
[4]; /* face to display the menu title */
3802 int buffers_num_deleted
= 0;
3803 struct frame
*sf
= SELECTED_FRAME();
3804 Lisp_Object saved_echo_area_message
;
3806 /* Just in case we got here without a mouse present... */
3807 if (have_mouse
<= 0)
3808 return XM_IA_SELECT
;
3809 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3810 around the display. */
3816 /* We will process all the mouse events directly, so we had
3817 better prevent dos_rawgetc from stealing them from us. */
3820 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3821 screensize
= screen_size
* 2;
3823 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3824 0, DEFAULT_FACE_ID
);
3826 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3827 0, DEFAULT_FACE_ID
);
3828 selectface
= intern ("msdos-menu-select-face");
3829 faces
[2] = lookup_derived_face (sf
, selectface
,
3831 faces
[3] = lookup_derived_face (sf
, selectface
,
3834 /* Make sure the menu title is always displayed with
3835 `msdos-menu-active-face', no matter where the mouse pointer is. */
3836 for (i
= 0; i
< 4; i
++)
3837 title_faces
[i
] = faces
[3];
3841 /* Don't let the title for the "Buffers" popup menu include a
3842 digit (which is ugly).
3844 This is a terrible kludge, but I think the "Buffers" case is
3845 the only one where the title includes a number, so it doesn't
3846 seem to be necessary to make this more general. */
3847 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3849 menu
->text
[0][7] = '\0';
3850 buffers_num_deleted
= 1;
3853 /* We need to save the current echo area message, so that we could
3854 restore it below, before we exit. See the commentary below,
3855 before the call to message_with_string. */
3856 saved_echo_area_message
= Fcurrent_message ();
3857 state
[0].menu
= menu
;
3859 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3861 /* Turn off the cursor. Otherwise it shows through the menu
3862 panes, which is ugly. */
3863 IT_display_cursor (0);
3865 /* Display the menu title. */
3866 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3867 if (buffers_num_deleted
)
3868 menu
->text
[0][7] = ' ';
3869 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3871 menu
->width
= menu
->submenu
[0]->width
;
3872 state
[0].menu
= menu
->submenu
[0];
3876 state
[0].menu
= menu
;
3878 state
[0].x
= x0
- 1;
3880 state
[0].pane
= onepane
;
3882 mouse_last_x
= -1; /* A hack that forces display. */
3886 if (!mouse_visible
) mouse_on ();
3887 mouse_check_moved ();
3888 if (sf
->mouse_moved
)
3890 sf
->mouse_moved
= 0;
3891 result
= XM_IA_SELECT
;
3892 mouse_get_xy (&x
, &y
);
3893 for (i
= 0; i
< statecount
; i
++)
3894 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3896 int dy
= y
- state
[i
].y
;
3897 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3899 if (!state
[i
].menu
->submenu
[dy
])
3900 if (state
[i
].menu
->panenumber
[dy
])
3901 result
= XM_SUCCESS
;
3903 result
= XM_IA_SELECT
;
3904 *pane
= state
[i
].pane
- 1;
3906 /* We hit some part of a menu, so drop extra menus that
3907 have been opened. That does not include an open and
3909 if (i
!= statecount
- 2
3910 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3911 while (i
!= statecount
- 1)
3915 ScreenUpdate (state
[statecount
].screen_behind
);
3916 if (screen_virtual_segment
)
3917 dosv_refresh_virtual_screen (0, screen_size
);
3918 xfree (state
[statecount
].screen_behind
);
3920 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3922 IT_menu_display (state
[i
].menu
,
3927 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3928 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3930 ScreenRetrieve (state
[statecount
].screen_behind
3931 = xmalloc (screensize
));
3933 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3934 state
[statecount
].y
= y
;
3939 IT_menu_display (state
[statecount
- 1].menu
,
3940 state
[statecount
- 1].y
,
3941 state
[statecount
- 1].x
,
3942 state
[statecount
- 1].pane
,
3947 if ((menu_help_message
|| prev_menu_help_message
)
3948 && menu_help_message
!= prev_menu_help_message
)
3950 help_callback (menu_help_message
,
3951 menu_help_paneno
, menu_help_itemno
);
3952 IT_display_cursor (0);
3953 prev_menu_help_message
= menu_help_message
;
3955 /* We are busy-waiting for the mouse to move, so let's be nice
3956 to other Windows applications by releasing our time slice. */
3959 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3961 /* Only leave if user both pressed and released the mouse, and in
3962 that order. This avoids popping down the menu pane unless
3963 the user is really done with it. */
3964 if (mouse_pressed (b
, &x
, &y
))
3966 while (mouse_button_depressed (b
, &x
, &y
))
3970 (void) mouse_released (b
, &x
, &y
);
3975 ScreenUpdate (state
[0].screen_behind
);
3976 if (screen_virtual_segment
)
3977 dosv_refresh_virtual_screen (0, screen_size
);
3979 /* We have a situation here. ScreenUpdate has just restored the
3980 screen contents as it was before we started drawing this menu.
3981 That includes any echo area message that could have been
3982 displayed back then. (In reality, that echo area message will
3983 almost always be the ``keystroke echo'' that echoes the sequence
3984 of menu items chosen by the user.) However, if the menu had some
3985 help messages, then displaying those messages caused Emacs to
3986 forget about the original echo area message. So when
3987 ScreenUpdate restored it, it created a discrepancy between the
3988 actual screen contents and what Emacs internal data structures
3991 To avoid this conflict, we force Emacs to restore the original
3992 echo area message as we found it when we entered this function.
3993 The irony of this is that we then erase the restored message
3994 right away, so the only purpose of restoring it is so that
3995 erasing it works correctly... */
3996 if (! NILP (saved_echo_area_message
))
3997 message_with_string ("%s", saved_echo_area_message
, 0);
3999 while (statecount
--)
4000 xfree (state
[statecount
].screen_behind
);
4001 IT_display_cursor (1); /* turn cursor back on */
4002 /* Clean up any mouse events that are waiting inside Emacs event queue.
4003 These events are likely to be generated before the menu was even
4004 displayed, probably because the user pressed and released the button
4005 (which invoked the menu) too quickly. If we don't remove these events,
4006 Emacs will process them after we return and surprise the user. */
4007 discard_mouse_events ();
4008 mouse_clear_clicks ();
4009 if (!kbd_buffer_events_waiting (1))
4010 clear_input_pending ();
4011 /* Allow mouse events generation by dos_rawgetc. */
4016 /* Dispose of a menu. */
4019 XMenuDestroy (Display
*foo
, XMenu
*menu
)
4022 if (menu
->allocated
)
4024 for (i
= 0; i
< menu
->count
; i
++)
4025 if (menu
->submenu
[i
])
4026 XMenuDestroy (foo
, menu
->submenu
[i
]);
4028 xfree (menu
->submenu
);
4029 xfree (menu
->panenumber
);
4030 xfree (menu
->help_text
);
4033 menu_help_message
= prev_menu_help_message
= NULL
;
4037 x_pixel_width (struct frame
*f
)
4039 return FRAME_WIDTH (f
);
4043 x_pixel_height (struct frame
*f
)
4045 return FRAME_HEIGHT (f
);
4047 #endif /* !HAVE_X_WINDOWS */
4049 /* ----------------------- DOS / UNIX conversion --------------------- */
4051 void msdos_downcase_filename (unsigned char *);
4053 /* Destructively turn backslashes into slashes. */
4056 dostounix_filename (p
)
4059 msdos_downcase_filename (p
);
4069 /* Destructively turn slashes into backslashes. */
4072 unixtodos_filename (p
)
4075 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4089 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4092 getdefdir (drive
, dst
)
4096 char in_path
[4], *p
= in_path
;
4099 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4102 *p
++ = drive
+ 'A' - 1;
4109 _fixpath (in_path
, dst
);
4110 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4111 it queries the LFN support, so ignore that error. */
4112 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
4115 msdos_downcase_filename (dst
);
4121 /* Remove all CR's that are followed by a LF. */
4126 register unsigned char *buf
;
4128 unsigned char *np
= buf
;
4129 unsigned char *startp
= buf
;
4130 unsigned char *endp
= buf
+ n
;
4134 while (buf
< endp
- 1)
4138 if (*(++buf
) != 0x0a)
4149 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4151 /* In DJGPP v2.0, library `write' can call `malloc', which might
4152 cause relocation of the buffer whose address we get in ADDR.
4153 Here is a version of `write' that avoids calling `malloc',
4154 to serve us until such time as the library is fixed.
4155 Actually, what we define here is called `__write', because
4156 `write' is a stub that just jmp's to `__write' (to be
4157 POSIXLY-correct with respect to the global name-space). */
4159 #include <io.h> /* for _write */
4160 #include <libc/dosio.h> /* for __file_handle_modes[] */
4162 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4164 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4167 __write (int handle
, const void *buffer
, size_t count
)
4172 if(__file_handle_modes
[handle
] & O_BINARY
)
4173 return _write (handle
, buffer
, count
);
4177 const char *bp
= buffer
;
4178 int total_written
= 0;
4179 int nmoved
= 0, ncr
= 0;
4183 /* The next test makes sure there's space for at least 2 more
4184 characters in xbuf[], so both CR and LF can be put there. */
4196 if (xbp
>= XBUF_END
|| !count
)
4198 size_t to_write
= nmoved
+ ncr
;
4199 int written
= _write (handle
, xbuf
, to_write
);
4204 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4206 /* If some, but not all were written (disk full?), return
4207 an estimate of the total written bytes not counting CRs. */
4208 if (written
< to_write
)
4209 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4216 return total_written
;
4220 /* A low-level file-renaming function which works around Windows 95 bug.
4221 This is pulled directly out of DJGPP v2.01 library sources, and only
4222 used when you compile with DJGPP v2.0. */
4226 int _rename(const char *old
, const char *new)
4229 int olen
= strlen(old
) + 1;
4231 int use_lfn
= _USE_LFN
;
4232 char tempfile
[FILENAME_MAX
];
4233 const char *orig
= old
;
4236 r
.x
.dx
= __tb_offset
;
4237 r
.x
.di
= __tb_offset
+ olen
;
4238 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4242 /* Windows 95 bug: for some filenames, when you rename
4243 file -> file~ (as in Emacs, to leave a backup), the
4244 short 8+3 alias doesn't change, which effectively
4245 makes OLD and NEW the same file. We must rename
4246 through a temporary file to work around this. */
4248 char *pbase
= 0, *p
;
4249 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4250 int idx
= sizeof(try_char
) - 1;
4252 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4253 might point to another drive, which will fail the DOS call. */
4254 strcpy(tempfile
, old
);
4255 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4256 if (*p
== '/' || *p
== '\\' || *p
== ':')
4262 strcpy(pbase
, "X$$djren$$.$$temp$$");
4268 *pbase
= try_char
[--idx
];
4269 } while (_chmod(tempfile
, 0) != -1);
4272 _put_path2(tempfile
, olen
);
4274 __dpmi_int(0x21, &r
);
4277 errno
= __doserr_to_errno(r
.x
.ax
);
4281 /* Now create a file with the original name. This will
4282 ensure that NEW will always have a 8+3 alias
4283 different from that of OLD. (Seems to be required
4284 when NameNumericTail in the Registry is set to 0.) */
4285 lfn_fd
= _creat(old
, 0);
4287 olen
= strlen(tempfile
) + 1;
4289 r
.x
.di
= __tb_offset
+ olen
;
4298 _put_path2(new, olen
);
4300 __dpmi_int(0x21, &r
);
4303 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4304 remove(new); /* and try again */
4307 errno
= __doserr_to_errno(r
.x
.ax
);
4309 /* Restore to original name if we renamed it to temporary. */
4317 _put_path2(orig
, olen
);
4318 _put_path(tempfile
);
4320 __dpmi_int(0x21, &r
);
4329 /* Success. Delete the file possibly created to work
4330 around the Windows 95 bug. */
4332 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4336 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4338 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4340 "Return non-nil if long file names are supported on MSDOS.")
4343 return (_USE_LFN
? Qt
: Qnil
);
4346 /* Convert alphabetic characters in a filename to lower-case. */
4349 msdos_downcase_filename (p
)
4350 register unsigned char *p
;
4352 /* Always lower-case drive letters a-z, even if the filesystem
4353 preserves case in filenames.
4354 This is so MSDOS filenames could be compared by string comparison
4355 functions that are case-sensitive. Even case-preserving filesystems
4356 do not distinguish case in drive letters. */
4357 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4363 /* Under LFN we expect to get pathnames in their true case. */
4364 if (NILP (Fmsdos_long_file_names ()))
4366 if (*p
>= 'A' && *p
<= 'Z')
4370 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4372 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4373 When long filenames are supported, doesn't change FILENAME.\n\
4374 If FILENAME is not a string, returns nil.\n\
4375 The argument object is never altered--the value is a copy.")
4377 Lisp_Object filename
;
4381 if (! STRINGP (filename
))
4384 tem
= Fcopy_sequence (filename
);
4385 msdos_downcase_filename (XSTRING (tem
)->data
);
4389 /* The Emacs root directory as determined by init_environment. */
4391 static char emacsroot
[MAXPATHLEN
];
4394 rootrelativepath (rel
)
4397 static char result
[MAXPATHLEN
+ 10];
4399 strcpy (result
, emacsroot
);
4400 strcat (result
, "/");
4401 strcat (result
, rel
);
4405 /* Define a lot of environment variables if not already defined. Don't
4406 remove anything unless you know what you're doing -- lots of code will
4407 break if one or more of these are missing. */
4410 init_environment (argc
, argv
, skip_args
)
4417 static const char * const tempdirs
[] = {
4418 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4421 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4423 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4424 temporary files and assume "/tmp" if $TMPDIR is unset, which
4425 will break on DOS/Windows. Refuse to work if we cannot find
4426 a directory, not even "c:/", usable for that purpose. */
4427 for (i
= 0; i
< imax
; i
++)
4429 const char *tmp
= tempdirs
[i
];
4432 tmp
= getenv (tmp
+ 1);
4433 /* Note that `access' can lie to us if the directory resides on a
4434 read-only filesystem, like CD-ROM or a write-protected floppy.
4435 The only way to be really sure is to actually create a file and
4436 see if it succeeds. But I think that's too much to ask. */
4437 if (tmp
&& access (tmp
, D_OK
) == 0)
4439 setenv ("TMPDIR", tmp
, 1);
4446 Fcons (build_string ("no usable temporary directories found!!"),
4448 "While setting TMPDIR: ");
4450 /* Note the startup time, so we know not to clear the screen if we
4451 exit immediately; see IT_reset_terminal_modes.
4452 (Yes, I know `clock' returns zero the first time it's called, but
4453 I do this anyway, in case some wiseguy changes that at some point.) */
4454 startup_time
= clock ();
4456 /* Find our root from argv[0]. Assuming argv[0] is, say,
4457 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4458 root
= alloca (MAXPATHLEN
+ 20);
4459 _fixpath (argv
[0], root
);
4460 msdos_downcase_filename (root
);
4461 len
= strlen (root
);
4462 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4466 && (strcmp (root
+ len
- 4, "/bin") == 0
4467 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4468 root
[len
- 4] = '\0';
4470 strcpy (root
, "c:/emacs"); /* let's be defensive */
4471 len
= strlen (root
);
4472 strcpy (emacsroot
, root
);
4474 /* We default HOME to our root. */
4475 setenv ("HOME", root
, 0);
4477 /* We default EMACSPATH to root + "/bin". */
4478 strcpy (root
+ len
, "/bin");
4479 setenv ("EMACSPATH", root
, 0);
4481 /* I don't expect anybody to ever use other terminals so the internal
4482 terminal is the default. */
4483 setenv ("TERM", "internal", 0);
4485 #ifdef HAVE_X_WINDOWS
4486 /* Emacs expects DISPLAY to be set. */
4487 setenv ("DISPLAY", "unix:0.0", 0);
4490 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4491 downcase it and mirror the backslashes. */
4492 s
= getenv ("COMSPEC");
4493 if (!s
) s
= "c:/command.com";
4494 t
= alloca (strlen (s
) + 1);
4496 dostounix_filename (t
);
4497 setenv ("SHELL", t
, 0);
4499 /* PATH is also downcased and backslashes mirrored. */
4500 s
= getenv ("PATH");
4502 t
= alloca (strlen (s
) + 3);
4503 /* Current directory is always considered part of MsDos's path but it is
4504 not normally mentioned. Now it is. */
4505 strcat (strcpy (t
, ".;"), s
);
4506 dostounix_filename (t
); /* Not a single file name, but this should work. */
4507 setenv ("PATH", t
, 1);
4509 /* In some sense all dos users have root privileges, so... */
4510 setenv ("USER", "root", 0);
4511 setenv ("NAME", getenv ("USER"), 0);
4513 /* Time zone determined from country code. To make this possible, the
4514 country code may not span more than one time zone. In other words,
4515 in the USA, you lose. */
4517 switch (dos_country_code
)
4519 case 31: /* Belgium */
4520 case 32: /* The Netherlands */
4521 case 33: /* France */
4522 case 34: /* Spain */
4523 case 36: /* Hungary */
4524 case 38: /* Yugoslavia (or what's left of it?) */
4525 case 39: /* Italy */
4526 case 41: /* Switzerland */
4527 case 42: /* Tjekia */
4528 case 45: /* Denmark */
4529 case 46: /* Sweden */
4530 case 47: /* Norway */
4531 case 48: /* Poland */
4532 case 49: /* Germany */
4533 /* Daylight saving from last Sunday in March to last Sunday in
4534 September, both at 2AM. */
4535 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4537 case 44: /* United Kingdom */
4538 case 351: /* Portugal */
4539 case 354: /* Iceland */
4540 setenv ("TZ", "GMT+00", 0);
4542 case 81: /* Japan */
4543 case 82: /* Korea */
4544 setenv ("TZ", "JST-09", 0);
4546 case 90: /* Turkey */
4547 case 358: /* Finland */
4548 setenv ("TZ", "EET-02", 0);
4550 case 972: /* Israel */
4551 /* This is an approximation. (For exact rules, use the
4552 `zoneinfo/israel' file which comes with DJGPP, but you need
4553 to install it in `/usr/share/zoneinfo/' directory first.) */
4554 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4562 static int break_stat
; /* BREAK check mode status. */
4563 static int stdin_stat
; /* stdin IOCTL status. */
4567 /* These must be global. */
4568 static _go32_dpmi_seginfo ctrl_break_vector
;
4569 static _go32_dpmi_registers ctrl_break_regs
;
4570 static int ctrlbreakinstalled
= 0;
4572 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4575 ctrl_break_func (regs
)
4576 _go32_dpmi_registers
*regs
;
4582 install_ctrl_break_check ()
4584 if (!ctrlbreakinstalled
)
4586 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4587 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4588 ctrlbreakinstalled
= 1;
4589 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4590 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4592 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4596 #endif /* __DJGPP__ < 2 */
4598 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4599 control chars by DOS. Determine the keyboard type. */
4604 union REGS inregs
, outregs
;
4605 static int first_time
= 1;
4607 break_stat
= getcbrk ();
4610 install_ctrl_break_check ();
4616 int86 (0x15, &inregs
, &outregs
);
4617 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4621 if (internal_terminal
4622 #ifdef HAVE_X_WINDOWS
4623 && inhibit_window_system
4627 inregs
.x
.ax
= 0x0021;
4628 int86 (0x33, &inregs
, &outregs
);
4629 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4632 /* Reportedly, the above doesn't work for some mouse drivers. There
4633 is an additional detection method that should work, but might be
4634 a little slower. Use that as an alternative. */
4635 inregs
.x
.ax
= 0x0000;
4636 int86 (0x33, &inregs
, &outregs
);
4637 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4642 have_mouse
= 1; /* enable mouse */
4644 mouse_setup_buttons (outregs
.x
.bx
);
4645 mouse_position_hook
= &mouse_get_pos
;
4649 #ifndef HAVE_X_WINDOWS
4651 /* Save the cursor shape used outside Emacs. */
4652 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4661 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4662 return (stdin_stat
!= -1);
4665 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4667 #else /* __DJGPP__ < 2 */
4671 /* I think it is wrong to overwrite `stdin_stat' every time
4672 but the first one this function is called, but I don't
4673 want to change the way it used to work in v1.x.--EZ */
4675 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4676 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4677 intdos (&inregs
, &outregs
);
4678 stdin_stat
= outregs
.h
.dl
;
4680 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4681 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4682 intdos (&inregs
, &outregs
);
4683 return !outregs
.x
.cflag
;
4685 #endif /* __DJGPP__ < 2 */
4688 /* Restore status of standard input and Ctrl-C checking. */
4693 union REGS inregs
, outregs
;
4695 setcbrk (break_stat
);
4700 #ifndef HAVE_X_WINDOWS
4701 /* Restore the cursor shape we found on startup. */
4705 inregs
.x
.cx
= outside_cursor
;
4706 int86 (0x10, &inregs
, &outregs
);
4710 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4712 #else /* not __DJGPP__ >= 2 */
4714 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4715 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4716 inregs
.x
.dx
= stdin_stat
;
4717 intdos (&inregs
, &outregs
);
4718 return !outregs
.x
.cflag
;
4720 #endif /* not __DJGPP__ >= 2 */
4724 /* Run command as specified by ARGV in directory DIR.
4725 The command is run with input from TEMPIN, output to
4726 file TEMPOUT and stderr to TEMPERR. */
4729 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4730 unsigned char **argv
;
4731 const char *working_dir
;
4732 int tempin
, tempout
, temperr
;
4735 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4736 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4737 int msshell
, result
= -1;
4738 int inbak
, outbak
, errbak
;
4742 /* Get current directory as MSDOS cwd is not per-process. */
4745 /* If argv[0] is the shell, it might come in any lettercase.
4746 Since `Fmember' is case-sensitive, we need to downcase
4747 argv[0], even if we are on case-preserving filesystems. */
4748 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4749 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4752 if (*pl
>= 'A' && *pl
<= 'Z')
4757 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4758 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4759 && !strcmp ("-c", argv
[1]);
4762 saveargv1
= argv
[1];
4763 saveargv2
= argv
[2];
4765 /* We only need to mirror slashes if a DOS shell will be invoked
4766 not via `system' (which does the mirroring itself). Yes, that
4767 means DJGPP v1.x will lose here. */
4768 if (argv
[2] && argv
[3])
4770 char *p
= alloca (strlen (argv
[2]) + 1);
4772 strcpy (argv
[2] = p
, saveargv2
);
4773 while (*p
&& isspace (*p
))
4785 chdir (working_dir
);
4789 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4790 goto done
; /* Allocation might fail due to lack of descriptors. */
4793 mouse_get_xy (&x
, &y
);
4795 dos_ttcooked (); /* do it here while 0 = stdin */
4803 if (msshell
&& !argv
[3])
4805 /* MS-DOS native shells are too restrictive. For starters, they
4806 cannot grok commands longer than 126 characters. In DJGPP v2
4807 and later, `system' is much smarter, so we'll call it instead. */
4811 /* A shell gets a single argument--its full command
4812 line--whose original was saved in `saveargv2'. */
4814 /* Don't let them pass empty command lines to `system', since
4815 with some shells it will try to invoke an interactive shell,
4816 which will hang Emacs. */
4817 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4821 extern char **environ
;
4822 char **save_env
= environ
;
4823 int save_system_flags
= __system_flags
;
4825 /* Request the most powerful version of `system'. We need
4826 all the help we can get to avoid calling stock DOS shells. */
4827 __system_flags
= (__system_redirect
4828 | __system_use_shell
4829 | __system_allow_multiple_cmds
4830 | __system_allow_long_cmds
4831 | __system_handle_null_commands
4832 | __system_emulate_chdir
);
4835 result
= system (cmnd
);
4836 __system_flags
= save_system_flags
;
4840 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4844 #endif /* __DJGPP__ > 1 */
4846 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4851 emacs_close (inbak
);
4852 emacs_close (outbak
);
4853 emacs_close (errbak
);
4859 mouse_moveto (x
, y
);
4862 /* Some programs might change the meaning of the highest bit of the
4863 text attribute byte, so we get blinking characters instead of the
4864 bright background colors. Restore that. */
4871 argv
[1] = saveargv1
;
4872 argv
[2] = saveargv2
;
4880 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4887 /* ------------------------- Compatibility functions -------------------
4892 /* Hostnames for a pc are not really funny,
4893 but they are used in change log so we emulate the best we can. */
4895 gethostname (p
, size
)
4899 char *q
= egetenv ("HOSTNAME");
4906 /* When time zones are set from Ms-Dos too many C-libraries are playing
4907 tricks with time values. We solve this by defining our own version
4908 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4909 once and after each call to `tzset' with TZ changed. That is
4910 accomplished by aliasing tzset to init_gettimeofday. */
4912 static struct tm time_rec
;
4915 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4923 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4927 time_rec
.tm_year
= d
.da_year
- 1900;
4928 time_rec
.tm_mon
= d
.da_mon
- 1;
4929 time_rec
.tm_mday
= d
.da_day
;
4932 time_rec
.tm_hour
= t
.ti_hour
;
4933 time_rec
.tm_min
= t
.ti_min
;
4934 time_rec
.tm_sec
= t
.ti_sec
;
4937 tm
.tm_gmtoff
= dos_timezone_offset
;
4939 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4940 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4942 /* Ignore tzp; it's obsolescent. */
4946 #endif /* __DJGPP__ < 2 */
4949 * A list of unimplemented functions that we silently ignore.
4953 unsigned alarm (s
) unsigned s
; {}
4954 fork () { return 0; }
4955 int kill (x
, y
) int x
, y
; { return -1; }
4957 void volatile pause () {}
4958 sigsetmask (x
) int x
; { return 0; }
4959 sigblock (mask
) int mask
; { return 0; }
4962 void request_sigio (void) {}
4963 setpgrp () {return 0; }
4964 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4965 void unrequest_sigio (void) {}
4969 #ifdef POSIX_SIGNALS
4971 /* Augment DJGPP library POSIX signal functions. This is needed
4972 as of DJGPP v2.01, but might be in the library in later releases. */
4974 #include <libc/bss.h>
4976 /* A counter to know when to re-initialize the static sets. */
4977 static int sigprocmask_count
= -1;
4979 /* Which signals are currently blocked (initially none). */
4980 static sigset_t current_mask
;
4982 /* Which signals are pending (initially none). */
4983 static sigset_t pending_signals
;
4985 /* Previous handlers to restore when the blocked signals are unblocked. */
4986 typedef void (*sighandler_t
)(int);
4987 static sighandler_t prev_handlers
[320];
4989 /* A signal handler which just records that a signal occured
4990 (it will be raised later, if and when the signal is unblocked). */
4992 sig_suspender (signo
)
4995 sigaddset (&pending_signals
, signo
);
4999 sigprocmask (how
, new_set
, old_set
)
5001 const sigset_t
*new_set
;
5007 /* If called for the first time, initialize. */
5008 if (sigprocmask_count
!= __bss_count
)
5010 sigprocmask_count
= __bss_count
;
5011 sigemptyset (&pending_signals
);
5012 sigemptyset (¤t_mask
);
5013 for (signo
= 0; signo
< 320; signo
++)
5014 prev_handlers
[signo
] = SIG_ERR
;
5018 *old_set
= current_mask
;
5023 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
5029 sigemptyset (&new_mask
);
5031 /* DJGPP supports upto 320 signals. */
5032 for (signo
= 0; signo
< 320; signo
++)
5034 if (sigismember (¤t_mask
, signo
))
5035 sigaddset (&new_mask
, signo
);
5036 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
5038 sigaddset (&new_mask
, signo
);
5040 /* SIGKILL is silently ignored, as on other platforms. */
5041 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
5042 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
5044 if (( how
== SIG_UNBLOCK
5045 && sigismember (&new_mask
, signo
)
5046 && sigismember (new_set
, signo
))
5047 || (how
== SIG_SETMASK
5048 && sigismember (&new_mask
, signo
)
5049 && !sigismember (new_set
, signo
)))
5051 sigdelset (&new_mask
, signo
);
5052 if (prev_handlers
[signo
] != SIG_ERR
)
5054 signal (signo
, prev_handlers
[signo
]);
5055 prev_handlers
[signo
] = SIG_ERR
;
5057 if (sigismember (&pending_signals
, signo
))
5059 sigdelset (&pending_signals
, signo
);
5064 current_mask
= new_mask
;
5068 #else /* not POSIX_SIGNALS */
5070 sigsetmask (x
) int x
; { return 0; }
5071 sigblock (mask
) int mask
; { return 0; }
5073 #endif /* not POSIX_SIGNALS */
5074 #endif /* __DJGPP__ > 1 */
5077 #include "sysselect.h"
5079 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5080 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5081 ((long)(time).tv_sec < 0 \
5082 || ((time).tv_sec == 0 \
5083 && (long)(time).tv_usec <= 0))
5086 /* This yields the rest of the current time slice to the task manager.
5087 It should be called by any code which knows that it has nothing
5088 useful to do except idle.
5090 I don't use __dpmi_yield here, since versions of library before 2.02
5091 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5092 on some versions of Windows 9X. */
5095 dos_yield_time_slice (void)
5097 _go32_dpmi_registers r
;
5100 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
5101 _go32_dpmi_simulate_int (0x2f, &r
);
5106 /* Only event queue is checked. */
5107 /* We don't have to call timer_check here
5108 because wait_reading_process_input takes care of that. */
5110 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5112 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5113 EMACS_TIME
*timeout
;
5121 check_input
= FD_ISSET (0, rfds
);
5132 /* If we are looking only for the terminal, with no timeout,
5133 just read it and wait -- that's more efficient. */
5136 while (!detect_input_pending ())
5138 dos_yield_time_slice ();
5143 EMACS_TIME clnow
, cllast
, cldiff
;
5146 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5148 while (!check_input
|| !detect_input_pending ())
5151 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5152 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5154 /* When seconds wrap around, we assume that no more than
5155 1 minute passed since last `gettime'. */
5156 if (EMACS_TIME_NEG_P (cldiff
))
5157 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5158 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5160 /* Stop when timeout value crosses zero. */
5161 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5164 dos_yield_time_slice ();
5174 * Define overlaid functions:
5176 * chdir -> sys_chdir
5177 * tzset -> init_gettimeofday
5178 * abort -> dos_abort
5183 extern int chdir ();
5189 int len
= strlen (path
);
5190 char *tmp
= (char *)path
;
5192 if (*tmp
&& tmp
[1] == ':')
5194 if (getdisk () != tolower (tmp
[0]) - 'a')
5195 setdisk (tolower (tmp
[0]) - 'a');
5196 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5200 if (len
> 1 && (tmp
[len
- 1] == '/'))
5202 char *tmp1
= (char *) alloca (len
+ 1);
5213 extern void tzset (void);
5216 init_gettimeofday ()
5222 ltm
= gtm
= time (NULL
);
5223 ltm
= mktime (lstm
= localtime (<m
));
5224 gtm
= mktime (gmtime (>m
));
5225 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5226 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5227 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5234 dos_abort (file
, line
)
5238 char buffer1
[200], buffer2
[400];
5241 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5242 for (i
= j
= 0; buffer1
[i
]; i
++) {
5243 buffer2
[j
++] = buffer1
[i
];
5244 buffer2
[j
++] = 0x70;
5246 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5247 ScreenSetCursor (2, 0);
5255 ScreenSetCursor (10, 0);
5256 cputs ("\r\n\nEmacs aborted!\r\n");
5258 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5259 if (screen_virtual_segment
)
5260 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5261 /* Generate traceback, so we could tell whodunit. */
5262 signal (SIGINT
, SIG_DFL
);
5263 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5264 #else /* __DJGPP_MINOR__ >= 2 */
5266 #endif /* __DJGPP_MINOR__ >= 2 */
5272 /* The following variables are required so that cus-start.el won't
5273 complain about unbound variables. */
5274 #ifndef HAVE_X_WINDOWS
5275 /* Search path for bitmap files (xfns.c). */
5276 Lisp_Object Vx_bitmap_file_path
;
5277 int x_stretch_cursor_p
;
5279 #ifndef subprocesses
5280 /* Nonzero means delete a process right away if it exits (process.c). */
5281 static int delete_exited_processes
;
5286 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5287 staticpro (&recent_doskeys
);
5288 #ifndef HAVE_X_WINDOWS
5290 staticpro (&help_echo
);
5291 help_echo_object
= Qnil
;
5292 staticpro (&help_echo_object
);
5293 help_echo_window
= Qnil
;
5294 staticpro (&help_echo_window
);
5295 previous_help_echo
= Qnil
;
5296 staticpro (&previous_help_echo
);
5299 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
5300 "List of directories to search for bitmap files for X.");
5301 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
5303 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p
,
5304 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5305 For example, if a block cursor is over a tab, it will be drawn as\n\
5306 wide as that tab on the display. (No effect on MS-DOS.)");
5307 x_stretch_cursor_p
= 0;
5309 /* The following two are from xfns.c: */
5310 Qbar
= intern ("bar");
5312 Qcursor_type
= intern ("cursor-type");
5313 staticpro (&Qcursor_type
);
5314 Qreverse
= intern ("reverse");
5315 staticpro (&Qreverse
);
5317 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5318 "*Glyph to display instead of chars not supported by current codepage.\n\
5320 This variable is used only by MSDOS terminals.");
5321 Vdos_unsupported_char_glyph
= '\177';
5323 #ifndef subprocesses
5324 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5325 "*Non-nil means delete processes immediately when they exit.\n\
5326 nil means don't delete them until `list-processes' is run.");
5327 delete_exited_processes
= 0;
5330 defsubr (&Srecent_doskeys
);
5331 defsubr (&Smsdos_long_file_names
);
5332 defsubr (&Smsdos_downcase_filename
);
5333 defsubr (&Smsdos_remember_default_colors
);
5334 defsubr (&Smsdos_set_mouse_buttons
);