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
, 0);
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
;
377 static int highlight
;
379 static int screen_size_X
;
380 static int screen_size_Y
;
381 static int screen_size
;
383 static int current_pos_X
;
384 static int current_pos_Y
;
385 static int new_pos_X
;
386 static int new_pos_Y
;
388 static void *startup_screen_buffer
;
389 static int startup_screen_size_X
;
390 static int startup_screen_size_Y
;
391 static int startup_pos_X
;
392 static int startup_pos_Y
;
393 static unsigned char startup_screen_attrib
;
395 static clock_t startup_time
;
397 static int term_setup_done
;
399 static unsigned short outside_cursor
;
401 /* Similar to the_only_frame. */
402 struct x_output the_only_x_display
;
404 /* Support for DOS/V (allows Japanese characters to be displayed on
405 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
407 /* Holds the address of the text-mode screen buffer. */
408 static unsigned long screen_old_address
= 0;
409 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
410 static unsigned short screen_virtual_segment
= 0;
411 static unsigned short screen_virtual_offset
= 0;
412 /* A flag to control how to display unibyte 8-bit characters. */
413 extern int unibyte_display_via_language_environment
;
417 static int initial_screen_colors
[2];
420 /* Update the screen from a part of relocated DOS/V screen buffer which
421 begins at OFFSET and includes COUNT characters. */
423 dosv_refresh_virtual_screen (int offset
, int count
)
427 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
430 regs
.h
.ah
= 0xff; /* update relocated screen */
431 regs
.x
.es
= screen_virtual_segment
;
432 regs
.x
.di
= screen_virtual_offset
+ offset
;
434 __dpmi_int (0x10, ®s
);
439 dos_direct_output (y
, x
, buf
, len
)
445 int t0
= 2 * (x
+ y
* screen_size_X
);
446 int t
= t0
+ (int) ScreenPrimary
;
451 dosmemput (buf
++, 1, t
);
455 /* This is faster. */
456 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
457 _farnspokeb (t
, *buf
);
459 if (screen_virtual_segment
)
460 dosv_refresh_virtual_screen (t0
, l0
);
465 /* Flash the screen as a substitute for BEEPs. */
469 do_visible_bell (xorattr
)
470 unsigned char xorattr
;
475 movl _ScreenPrimary,%%eax \n\
482 xorb %%al,%%gs:(%%ebx) \n\
485 jne visible_bell_1 \n\
487 jne visible_bell_3 \n\
489 movzwl %%ax,%%eax \n\
490 movzwl %%ax,%%eax \n\
491 movzwl %%ax,%%eax \n\
492 movzwl %%ax,%%eax \n\
494 jne visible_bell_2 \n\
495 jmp visible_bell_0 \n\
498 : "m" (xorattr
), "g" (screen_size
)
499 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
503 ScreenVisualBell (void)
505 /* This creates an xor-mask that will swap the default fore- and
506 background colors. */
507 do_visible_bell (((the_only_x_display
.foreground_pixel
508 ^ the_only_x_display
.background_pixel
)
513 #ifndef HAVE_X_WINDOWS
515 static int blink_bit
= -1; /* the state of the blink bit at startup */
517 /* Enable bright background colors. */
523 /* Remember the original state of the blink/bright-background bit.
524 It is stored at 0040:0065h in the BIOS data area. */
526 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
530 int86 (0x10, ®s
, ®s
);
533 /* Disable bright background colors (and enable blinking) if we found
534 the video system in that state at startup. */
536 maybe_enable_blinking (void)
544 int86 (0x10, ®s
, ®s
);
548 /* Return non-zero if the system has a VGA adapter. */
555 int86 (0x10, ®s
, ®s
);
556 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
561 /* Set the screen dimensions so that it can show no less than
562 ROWS x COLS frame. */
565 dos_set_window_size (rows
, cols
)
569 Lisp_Object video_mode
;
570 int video_mode_value
;
573 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
575 if (*rows
== current_rows
&& *cols
== current_cols
)
579 have_vga
= vga_installed ();
581 /* If the user specified a special video mode for these dimensions,
583 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
584 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
587 if (INTEGERP (video_mode
)
588 && (video_mode_value
= XINT (video_mode
)) > 0)
590 regs
.x
.ax
= video_mode_value
;
591 int86 (0x10, ®s
, ®s
);
595 /* Must hardware-reset the mouse, or else it won't update
596 its notion of screen dimensions for some non-standard
597 video modes. This is *painfully* slow... */
599 int86 (0x33, ®s
, ®s
);
603 /* Find one of the dimensions supported by standard EGA/VGA
604 which gives us at least the required dimensions. */
613 } std_dimension
[] = {
623 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
625 if (std_dimension
[i
].need_vga
<= have_vga
626 && std_dimension
[i
].rows
>= *rows
)
628 if (std_dimension
[i
].rows
!= current_rows
629 || *cols
!= current_cols
)
630 _set_screen_lines (std_dimension
[i
].rows
);
637 #else /* not __DJGPP__ > 1 */
639 else if (*rows
<= 25)
641 if (current_rows
!= 25 || current_cols
!= 80)
644 int86 (0x10, ®s
, ®s
);
647 int86 (0x10, ®s
, ®s
);
650 int86 (0x10, ®s
, ®s
);
652 int86 (0x10, ®s
, ®s
);
655 else if (*rows
<= 50)
656 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
657 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
660 int86 (0x10, ®s
, ®s
);
663 int86 (0x10, ®s
, ®s
);
666 int86 (0x10, ®s
, ®s
);
669 int86 (0x10, ®s
, ®s
);
671 #endif /* not __DJGPP__ > 1 */
679 /* Tell the caller what dimensions have been REALLY set. */
680 *rows
= ScreenRows ();
681 *cols
= ScreenCols ();
683 /* Update Emacs' notion of screen dimensions. */
684 screen_size_X
= *cols
;
685 screen_size_Y
= *rows
;
686 screen_size
= *cols
* *rows
;
689 /* If the dimensions changed, the mouse highlight info is invalid. */
690 if (current_rows
!= *rows
|| current_cols
!= *cols
)
692 struct frame
*f
= SELECTED_FRAME();
693 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
694 Lisp_Object window
= dpyinfo
->mouse_face_window
;
696 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
698 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
699 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
700 dpyinfo
->mouse_face_window
= Qnil
;
705 /* Enable bright background colors. */
708 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
709 be defensive anyway. */
710 if (screen_virtual_segment
)
711 dosv_refresh_virtual_screen (0, *cols
* *rows
);
714 /* If we write a character in the position where the mouse is,
715 the mouse cursor may need to be refreshed. */
725 mouse_get_xy (&x
, &y
);
726 if (y
!= new_pos_Y
|| x
< new_pos_X
)
732 #define DEFAULT_CURSOR_START (-1)
733 #define DEFAULT_CURSOR_WIDTH (-1)
734 #define BOX_CURSOR_WIDTH (-32)
736 /* Set cursor to begin at scan line START_LINE in the character cell
737 and extend for WIDTH scan lines. Scan lines are counted from top
738 of the character cell, starting from zero. */
740 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
743 unsigned desired_cursor
;
745 int max_line
, top_line
, bot_line
;
747 /* Avoid the costly BIOS call if F isn't the currently selected
748 frame. Allow for NULL as unconditionally meaning the selected
750 if (f
&& f
!= SELECTED_FRAME())
753 /* The character cell size in scan lines is stored at 40:85 in the
755 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
758 default: /* this relies on CGA cursor emulation being ON! */
775 if (width
== BOX_CURSOR_WIDTH
)
780 else if (start_line
!= DEFAULT_CURSOR_START
)
782 top_line
= start_line
;
783 bot_line
= top_line
- width
- 1;
785 else if (width
!= DEFAULT_CURSOR_WIDTH
)
788 bot_line
= -1 - width
;
791 top_line
= bot_line
+ 1;
795 /* [31, 0] seems to DTRT for all screen sizes. */
799 else /* WIDTH is positive */
801 if (start_line
!= DEFAULT_CURSOR_START
)
802 bot_line
= start_line
;
803 top_line
= bot_line
- (width
- 1);
806 /* If the current cursor shape is already what they want, we are
808 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
809 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
813 regs
.x
.cx
= desired_cursor
;
814 __dpmi_int (0x10, ®s
);
815 #endif /* __DJGPP__ > 1 */
819 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
821 if (EQ (cursor_type
, Qbar
))
823 /* Just BAR means the normal EGA/VGA cursor. */
824 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
826 else if (CONSP (cursor_type
) && EQ (XCAR (cursor_type
), Qbar
))
828 Lisp_Object bar_parms
= XCDR (cursor_type
);
831 if (INTEGERP (bar_parms
))
833 /* Feature: negative WIDTH means cursor at the top
834 of the character cell, zero means invisible cursor. */
835 width
= XINT (bar_parms
);
836 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
839 else if (CONSP (bar_parms
)
840 && INTEGERP (XCAR (bar_parms
))
841 && INTEGERP (XCDR (bar_parms
)))
843 int start_line
= XINT (XCDR (bar_parms
));
845 width
= XINT (XCAR (bar_parms
));
846 msdos_set_cursor_shape (f
, start_line
, width
);
850 /* Treat anything unknown as "box cursor". This includes nil, so
851 that a frame which doesn't specify a cursor type gets a box,
852 which is the default in Emacs. */
853 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
866 union REGS inregs
, outregs
;
869 intdos (&inregs
, &outregs
);
873 /* Given a face id FACE, extract the face parameters to be used for
874 display until the face changes. The face parameters (actually, its
875 color) are used to construct the video attribute byte for each
876 glyph during the construction of the buffer that is then blitted to
879 IT_set_face (int face
)
881 struct frame
*sf
= SELECTED_FRAME();
882 struct face
*fp
= FACE_FROM_ID (sf
, face
);
883 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
884 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
889 /* The default face for the frame should always be realized and
897 dflt_fg
= dfp
->foreground
;
898 dflt_bg
= dfp
->background
;
900 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
901 colors mean use the colors of the default face, except that if
902 highlight is on, invert the foreground and the background. Note
903 that we assume all 16 colors to be available for the background,
904 since Emacs switches on this mode (and loses the blinking
905 attribute) at startup. */
906 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
907 fg
= FRAME_FOREGROUND_PIXEL (sf
);
908 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
909 fg
= FRAME_BACKGROUND_PIXEL (sf
);
910 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
911 bg
= FRAME_BACKGROUND_PIXEL (sf
);
912 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
913 bg
= FRAME_FOREGROUND_PIXEL (sf
);
915 /* Make sure highlighted lines really stand out, come what may. */
916 if ((highlight
|| fp
->tty_reverse_p
)
917 && (fg
== dflt_fg
&& bg
== dflt_bg
))
919 unsigned long tem
= fg
;
924 /* If the user requested inverse video, obey. */
927 unsigned long tem2
= fg
;
933 fprintf (termscript
, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face
,
934 highlight
? "H" : "", fp
->foreground
, fp
->background
, fg
, bg
);
935 if (fg
>= 0 && fg
< 16)
937 ScreenAttrib
&= 0xf0;
940 if (bg
>= 0 && bg
< 16)
942 ScreenAttrib
&= 0x0f;
943 ScreenAttrib
|= ((bg
& 0x0f) << 4);
947 Lisp_Object Vdos_unsupported_char_glyph
;
950 IT_write_glyphs (struct glyph
*str
, int str_len
)
952 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
953 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
954 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
955 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
956 register int sl
= str_len
;
957 register int tlen
= GLYPH_TABLE_LENGTH
;
958 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
960 /* If terminal_coding does any conversion, use it, otherwise use
961 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
962 because it always returns 1 if terminal_coding.src_multibyte is 1. */
963 struct coding_system
*coding
=
964 (terminal_coding
.common_flags
& CODING_REQUIRE_ENCODING_MASK
966 : &safe_terminal_coding
);
969 /* Do we need to consider conversion of unibyte characters to
971 int convert_unibyte_characters
972 = (NILP (current_buffer
->enable_multibyte_characters
)
973 && unibyte_display_via_language_environment
);
975 unsigned char conversion_buffer
[256];
976 int conversion_buffer_size
= sizeof conversion_buffer
;
978 if (str_len
<= 0) return;
980 screen_buf
= screen_bp
= alloca (str_len
* 2);
981 screen_buf_end
= screen_buf
+ str_len
* 2;
982 sf
= SELECTED_FRAME();
984 /* Since faces get cached and uncached behind our back, we can't
985 rely on their indices in the cache being consistent across
986 invocations. So always reset the screen face to the default
987 face of the frame, before writing glyphs, and let the glyphs
988 set the right face if it's different from the default. */
989 IT_set_face (DEFAULT_FACE_ID
);
991 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
993 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
996 int cf
, chlen
, enclen
;
997 unsigned char workbuf
[MAX_MULTIBYTE_LENGTH
], *buf
;
1000 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
1001 only for the redisplay code to know how many columns does
1002 this character occupy on the screen. Skip padding glyphs. */
1003 if (CHAR_GLYPH_PADDING_P (*str
))
1010 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
1011 int glyph_not_in_table
= 0;
1013 /* If g is negative, it means we have a multibyte character
1014 in *str. That's what GLYPH_FROM_CHAR_GLYPH returns for
1015 multibyte characters. */
1016 if (g
< 0 || g
>= tlen
)
1018 /* This glyph doesn't have an entry in Vglyph_table. */
1020 glyph_not_in_table
= 1;
1024 /* This glyph has an entry in Vglyph_table, so process
1025 any aliases before testing for simpleness. */
1026 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
1027 ch
= FAST_GLYPH_CHAR (g
);
1030 /* Convert the character code to multibyte, if they
1031 requested display via language environment. We only want
1032 to convert unibyte characters to multibyte in unibyte
1033 buffers! Otherwise, the 8-bit value in CH came from the
1034 display table set up to display foreign characters. */
1035 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
1037 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
1038 ch
= unibyte_char_to_multibyte (ch
);
1040 /* Invalid characters are displayed with a special glyph. */
1041 if (! CHAR_VALID_P (ch
, 0))
1043 g
= !NILP (Vdos_unsupported_char_glyph
)
1044 ? Vdos_unsupported_char_glyph
1045 : MAKE_GLYPH (sf
, '\177', GLYPH_FACE (sf
, g
));
1046 ch
= FAST_GLYPH_CHAR (g
);
1049 /* If the face of this glyph is different from the current
1050 screen face, update the screen attribute byte. */
1052 if (cf
!= screen_face
)
1053 IT_set_face (cf
); /* handles invalid faces gracefully */
1055 if (glyph_not_in_table
|| GLYPH_SIMPLE_P (tbase
, tlen
, g
))
1057 /* We generate the multi-byte form of CH in WORKBUF. */
1058 chlen
= CHAR_STRING (ch
, workbuf
);
1063 /* We have a string in Vglyph_table. */
1064 chlen
= GLYPH_LENGTH (tbase
, g
);
1065 buf
= GLYPH_STRING (tbase
, g
);
1068 /* If the character is not multibyte, don't bother converting it. */
1071 *conversion_buffer
= (unsigned char)ch
;
1077 coding
->src_multibyte
= 1;
1078 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
1079 conversion_buffer_size
);
1080 chlen
-= coding
->consumed
;
1081 enclen
= coding
->produced
;
1083 /* Replace glyph codes that cannot be converted by
1084 terminal_coding with Vdos_unsupported_char_glyph. */
1085 if (*conversion_buffer
== '?')
1087 unsigned char *cbp
= conversion_buffer
;
1089 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
1090 *cbp
++ = unsupported_char
;
1091 if (unsupported_face
!= screen_face
)
1092 IT_set_face (unsupported_face
);
1096 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
1098 /* The allocated buffer for screen writes is too small.
1099 Flush it and loop again without incrementing STR, so
1100 that the next loop will begin with the same glyph. */
1101 int nbytes
= screen_bp
- screen_buf
;
1104 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
1105 if (screen_virtual_segment
)
1106 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
1107 new_pos_X
+= nbytes
/ 2;
1110 /* Prepare to reuse the same buffer again. */
1111 screen_bp
= screen_buf
;
1115 /* There's enough place in the allocated buffer to add
1116 the encoding of this glyph. */
1118 /* First, copy the encoded bytes. */
1119 for (bp
= conversion_buffer
; enclen
--; bp
++)
1121 *screen_bp
++ = (unsigned char)*bp
;
1122 *screen_bp
++ = ScreenAttrib
;
1124 fputc (*bp
, termscript
);
1127 /* Now copy the bytes not consumed by the encoding. */
1130 buf
+= coding
->consumed
;
1134 fputc (*buf
, termscript
);
1135 *screen_bp
++ = (unsigned char)*buf
++;
1136 *screen_bp
++ = ScreenAttrib
;
1140 /* Update STR and its remaining length. */
1147 /* Dump whatever is left in the screen buffer. */
1149 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1150 if (screen_virtual_segment
)
1151 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1152 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1154 /* We may have to output some codes to terminate the writing. */
1155 if (CODING_REQUIRE_FLUSHING (coding
))
1157 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1158 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
1159 if (coding
->produced
> 0)
1161 screen_buf
= alloca (coding
->produced
* 2);
1162 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
1163 coding
->produced
--; bp
++)
1165 *screen_bp
++ = (unsigned char)*bp
;
1166 *screen_bp
++ = ScreenAttrib
;
1168 fputc (*bp
, termscript
);
1170 offset
+= screen_bp
- screen_buf
;
1172 dosmemput (screen_buf
, screen_bp
- screen_buf
,
1173 (int)ScreenPrimary
+ offset
);
1174 if (screen_virtual_segment
)
1175 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1176 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1181 /************************************************************************
1182 Mouse Highlight (and friends..)
1183 ************************************************************************/
1185 /* This is used for debugging, to turn off note_mouse_highlight. */
1186 int disable_mouse_highlight
;
1188 /* If non-nil, dos_rawgetc generates an event to display that string.
1189 (The display is done in keyboard.c:read_char, by calling
1191 static Lisp_Object help_echo
;
1192 static Lisp_Object previous_help_echo
; /* a helper temporary variable */
1194 /* These record the window, the object and the position where the help
1195 echo string was generated. */
1196 static Lisp_Object help_echo_window
;
1197 static Lisp_Object help_echo_object
;
1198 static int help_echo_pos
;
1200 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1202 /* Set the mouse pointer shape according to whether it is in the
1203 area where the mouse highlight is in effect. */
1205 IT_set_mouse_pointer (int mode
)
1207 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1208 many possibilities to change its shape, and the available
1209 functionality pretty much sucks (e.g., almost every reasonable
1210 shape will conceal the character it is on). Since the color of
1211 the pointer changes in the highlighted area, it is not clear to
1212 me whether anything else is required, anyway. */
1215 /* Display the active region described by mouse_face_*
1216 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1218 show_mouse_face (struct display_info
*dpyinfo
, int hl
)
1220 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1221 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1226 /* If window is in the process of being destroyed, don't bother
1228 if (w
->current_matrix
== NULL
)
1229 goto set_cursor_shape
;
1231 /* Recognize when we are called to operate on rows that don't exist
1232 anymore. This can happen when a window is split. */
1233 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1234 goto set_cursor_shape
;
1236 /* There's no sense to do anything if the mouse face isn't realized. */
1239 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1241 goto set_cursor_shape
;
1244 /* Note that mouse_face_beg_row etc. are window relative. */
1245 for (i
= dpyinfo
->mouse_face_beg_row
;
1246 i
<= dpyinfo
->mouse_face_end_row
;
1249 int start_hpos
, end_hpos
;
1250 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1252 /* Don't do anything if row doesn't have valid contents. */
1253 if (!row
->enabled_p
)
1256 /* For all but the first row, the highlight starts at column 0. */
1257 if (i
== dpyinfo
->mouse_face_beg_row
)
1258 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1262 if (i
== dpyinfo
->mouse_face_end_row
)
1263 end_hpos
= dpyinfo
->mouse_face_end_col
;
1265 end_hpos
= row
->used
[TEXT_AREA
];
1267 if (end_hpos
<= start_hpos
)
1269 /* Record that some glyphs of this row are displayed in
1271 row
->mouse_face_p
= hl
> 0;
1274 int vpos
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1275 int kstart
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1276 int nglyphs
= end_hpos
- start_hpos
;
1277 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1278 int start_offset
= offset
;
1281 fprintf (termscript
, "\n<MH+ %d-%d:%d>",
1282 kstart
, kstart
+ nglyphs
- 1, vpos
);
1285 IT_set_face (dpyinfo
->mouse_face_face_id
);
1286 /* Since we are going to change only the _colors_ of the
1287 displayed text, there's no need to go through all the
1288 pain of generating and encoding the text from the glyphs.
1289 Instead, we simply poke the attribute byte of each
1290 affected position in video memory with the colors
1291 computed by IT_set_face! */
1292 _farsetsel (_dos_ds
);
1295 _farnspokeb (offset
, ScreenAttrib
);
1298 if (screen_virtual_segment
)
1299 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1304 /* We are removing a previously-drawn mouse highlight. The
1305 safest way to do so is to redraw the glyphs anew, since
1306 all kinds of faces and display tables could have changed
1308 int nglyphs
= end_hpos
- start_hpos
;
1309 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1311 if (end_hpos
>= row
->used
[TEXT_AREA
])
1312 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1314 /* IT_write_glyphs writes at cursor position, so we need to
1315 temporarily move cursor coordinates to the beginning of
1316 the highlight region. */
1317 new_pos_X
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1318 new_pos_Y
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1321 fprintf (termscript
, "<MH- %d-%d:%d>",
1322 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1323 IT_write_glyphs (row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1325 fputs ("\n", termscript
);
1333 /* Change the mouse pointer shape. */
1334 IT_set_mouse_pointer (hl
);
1337 /* Clear out the mouse-highlighted active region.
1338 Redraw it un-highlighted first. */
1340 clear_mouse_face (struct display_info
*dpyinfo
)
1342 if (! NILP (dpyinfo
->mouse_face_window
))
1343 show_mouse_face (dpyinfo
, 0);
1345 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1346 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1347 dpyinfo
->mouse_face_window
= Qnil
;
1350 /* Find the glyph matrix position of buffer position POS in window W.
1351 *HPOS and *VPOS are set to the positions found. W's current glyphs
1352 must be up to date. If POS is above window start return (0, 0).
1353 If POS is after end of W, return end of last line in W. */
1355 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1359 int maybe_next_line_p
= 0;
1360 int line_start_position
;
1361 int yb
= window_text_bottom_y (w
);
1362 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0);
1363 struct glyph_row
*best_row
= row
;
1367 if (row
->used
[TEXT_AREA
])
1368 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1370 line_start_position
= 0;
1372 if (line_start_position
> pos
)
1374 /* If the position sought is the end of the buffer,
1375 don't include the blank lines at the bottom of the window. */
1376 else if (line_start_position
== pos
1377 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1379 maybe_next_line_p
= 1;
1382 else if (line_start_position
> 0)
1385 /* Don't overstep the last matrix row, lest we get into the
1386 never-never land... */
1387 if (row
->y
+ 1 >= yb
)
1393 /* Find the right column within BEST_ROW. */
1396 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1398 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1401 charpos
= glyph
->charpos
;
1408 else if (charpos
> pos
)
1410 else if (charpos
> 0)
1414 /* If we're looking for the end of the buffer,
1415 and we didn't find it in the line we scanned,
1416 use the start of the following line. */
1417 if (maybe_next_line_p
)
1424 *hpos
= lastcol
+ 1;
1428 /* Take proper action when mouse has moved to the mode or top line of
1429 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1430 mode line. X is relative to the start of the text display area of
1431 W, so the width of bitmap areas and scroll bars must be subtracted
1432 to get a position relative to the start of the mode line. */
1434 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1436 struct frame
*f
= XFRAME (w
->frame
);
1437 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1438 struct glyph_row
*row
;
1441 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1443 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1447 extern Lisp_Object Qhelp_echo
;
1448 struct glyph
*glyph
, *end
;
1449 Lisp_Object help
, map
;
1451 /* Find the glyph under X. */
1452 glyph
= row
->glyphs
[TEXT_AREA
]
1453 + x
- FRAME_LEFT_SCROLL_BAR_WIDTH (f
) * CANON_X_UNIT (f
);
1454 end
= glyph
+ row
->used
[TEXT_AREA
];
1456 && STRINGP (glyph
->object
)
1457 && XSTRING (glyph
->object
)->intervals
1458 && glyph
->charpos
>= 0
1459 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1461 /* If we're on a string with `help-echo' text property,
1462 arrange for the help to be displayed. This is done by
1463 setting the global variable help_echo to the help string. */
1464 help
= Fget_text_property (make_number (glyph
->charpos
),
1465 Qhelp_echo
, glyph
->object
);
1469 XSETWINDOW (help_echo_window
, w
);
1470 help_echo_object
= glyph
->object
;
1471 help_echo_pos
= glyph
->charpos
;
1477 /* Take proper action when the mouse has moved to position X, Y on
1478 frame F as regards highlighting characters that have mouse-face
1479 properties. Also de-highlighting chars where the mouse was before.
1480 X and Y can be negative or out of range. */
1482 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1484 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1489 /* When a menu is active, don't highlight because this looks odd. */
1490 if (mouse_preempted
)
1493 if (disable_mouse_highlight
1494 || !f
->glyphs_initialized_p
)
1497 dpyinfo
->mouse_face_mouse_x
= x
;
1498 dpyinfo
->mouse_face_mouse_y
= y
;
1499 dpyinfo
->mouse_face_mouse_frame
= f
;
1501 if (dpyinfo
->mouse_face_defer
)
1506 dpyinfo
->mouse_face_deferred_gc
= 1;
1510 /* Which window is that in? */
1511 window
= window_from_coordinates (f
, x
, y
, &portion
, 0);
1513 /* If we were displaying active text in another window, clear that. */
1514 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1515 clear_mouse_face (dpyinfo
);
1517 /* Not on a window -> return. */
1518 if (!WINDOWP (window
))
1521 /* Convert to window-relative coordinates. */
1522 w
= XWINDOW (window
);
1523 x
-= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1524 y
-= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1526 if (portion
== 1 || portion
== 3)
1528 /* Mouse is on the mode or top line. */
1529 IT_note_mode_line_highlight (w
, x
, portion
== 1);
1533 IT_set_mouse_pointer (0);
1535 /* Are we in a window whose display is up to date?
1536 And verify the buffer's text has not changed. */
1537 if (/* Within text portion of the window. */
1539 && EQ (w
->window_end_valid
, w
->buffer
)
1540 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1541 && (XFASTINT (w
->last_overlay_modified
)
1542 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1545 struct glyph_row
*row
;
1546 struct glyph
*glyph
;
1547 int nrows
= w
->current_matrix
->nrows
;
1549 /* Find the glyph under X/Y. */
1551 if (y
>= 0 && y
< nrows
)
1553 row
= MATRIX_ROW (w
->current_matrix
, y
);
1554 /* Give up if some row before the one we are looking for is
1556 for (i
= 0; i
<= y
; i
++)
1557 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1559 if (i
> y
/* all rows upto and including the one at Y are enabled */
1560 && row
->displays_text_p
1561 && x
< window_box_width (w
, TEXT_AREA
))
1563 glyph
= row
->glyphs
[TEXT_AREA
];
1564 if (x
>= row
->used
[TEXT_AREA
])
1569 if (!BUFFERP (glyph
->object
))
1575 /* Clear mouse face if X/Y not over text. */
1578 clear_mouse_face (dpyinfo
);
1582 if (!BUFFERP (glyph
->object
))
1584 pos
= glyph
->charpos
;
1586 /* Check for mouse-face and help-echo. */
1588 extern Lisp_Object Qmouse_face
;
1589 Lisp_Object mouse_face
, overlay
, position
;
1590 Lisp_Object
*overlay_vec
;
1592 struct buffer
*obuf
;
1595 /* If we get an out-of-range value, return now; avoid an error. */
1596 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1599 /* Make the window's buffer temporarily current for
1600 overlays_at and compute_char_face. */
1601 obuf
= current_buffer
;
1602 current_buffer
= XBUFFER (w
->buffer
);
1608 /* Is this char mouse-active or does it have help-echo? */
1609 XSETINT (position
, pos
);
1611 /* Put all the overlays we want in a vector in overlay_vec.
1612 Store the length in len. If there are more than 10, make
1613 enough space for all, and try again. */
1615 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1616 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
, 0);
1617 if (noverlays
> len
)
1620 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1621 noverlays
= overlays_at (pos
,
1622 0, &overlay_vec
, &len
, NULL
, NULL
, 0);
1625 /* Sort overlays into increasing priority order. */
1626 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1628 /* Check mouse-face highlighting. */
1629 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1630 && y
>= dpyinfo
->mouse_face_beg_row
1631 && y
<= dpyinfo
->mouse_face_end_row
1632 && (y
> dpyinfo
->mouse_face_beg_row
1633 || x
>= dpyinfo
->mouse_face_beg_col
)
1634 && (y
< dpyinfo
->mouse_face_end_row
1635 || x
< dpyinfo
->mouse_face_end_col
1636 || dpyinfo
->mouse_face_past_end
)))
1638 /* Clear the display of the old active region, if any. */
1639 clear_mouse_face (dpyinfo
);
1641 /* Find highest priority overlay that has a mouse-face prop. */
1643 for (i
= noverlays
- 1; i
>= 0; --i
)
1645 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1646 if (!NILP (mouse_face
))
1648 overlay
= overlay_vec
[i
];
1653 /* If no overlay applies, get a text property. */
1655 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1658 /* Handle the overlay case. */
1659 if (! NILP (overlay
))
1661 /* Find the range of text around this char that
1662 should be active. */
1663 Lisp_Object before
, after
;
1666 before
= Foverlay_start (overlay
);
1667 after
= Foverlay_end (overlay
);
1668 /* Record this as the current active region. */
1669 fast_find_position (w
, XFASTINT (before
),
1670 &dpyinfo
->mouse_face_beg_col
,
1671 &dpyinfo
->mouse_face_beg_row
);
1672 dpyinfo
->mouse_face_past_end
1673 = !fast_find_position (w
, XFASTINT (after
),
1674 &dpyinfo
->mouse_face_end_col
,
1675 &dpyinfo
->mouse_face_end_row
);
1676 dpyinfo
->mouse_face_window
= window
;
1677 dpyinfo
->mouse_face_face_id
1678 = face_at_buffer_position (w
, pos
, 0, 0,
1679 &ignore
, pos
+ 1, 1);
1681 /* Display it as active. */
1682 show_mouse_face (dpyinfo
, 1);
1684 /* Handle the text property case. */
1685 else if (! NILP (mouse_face
))
1687 /* Find the range of text around this char that
1688 should be active. */
1689 Lisp_Object before
, after
, beginning
, end
;
1692 beginning
= Fmarker_position (w
->start
);
1693 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1694 - XFASTINT (w
->window_end_pos
)));
1696 = Fprevious_single_property_change (make_number (pos
+ 1),
1698 w
->buffer
, beginning
);
1700 = Fnext_single_property_change (position
, Qmouse_face
,
1702 /* Record this as the current active region. */
1703 fast_find_position (w
, XFASTINT (before
),
1704 &dpyinfo
->mouse_face_beg_col
,
1705 &dpyinfo
->mouse_face_beg_row
);
1706 dpyinfo
->mouse_face_past_end
1707 = !fast_find_position (w
, XFASTINT (after
),
1708 &dpyinfo
->mouse_face_end_col
,
1709 &dpyinfo
->mouse_face_end_row
);
1710 dpyinfo
->mouse_face_window
= window
;
1711 dpyinfo
->mouse_face_face_id
1712 = face_at_buffer_position (w
, pos
, 0, 0,
1713 &ignore
, pos
+ 1, 1);
1715 /* Display it as active. */
1716 show_mouse_face (dpyinfo
, 1);
1720 /* Look for a `help-echo' property. */
1723 extern Lisp_Object Qhelp_echo
;
1725 /* Check overlays first. */
1727 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1729 overlay
= overlay_vec
[i
];
1730 help
= Foverlay_get (overlay
, Qhelp_echo
);
1736 help_echo_window
= window
;
1737 help_echo_object
= overlay
;
1738 help_echo_pos
= pos
;
1740 /* Try text properties. */
1741 else if (NILP (help
)
1742 && ((STRINGP (glyph
->object
)
1743 && glyph
->charpos
>= 0
1744 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1745 || (BUFFERP (glyph
->object
)
1746 && glyph
->charpos
>= BEGV
1747 && glyph
->charpos
< ZV
)))
1749 help
= Fget_text_property (make_number (glyph
->charpos
),
1750 Qhelp_echo
, glyph
->object
);
1754 help_echo_window
= window
;
1755 help_echo_object
= glyph
->object
;
1756 help_echo_pos
= glyph
->charpos
;
1763 current_buffer
= obuf
;
1769 IT_clear_end_of_line (int first_unused
)
1773 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1774 extern int fatal_error_in_progress
;
1776 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1780 i
= (j
= first_unused
- new_pos_X
) * 2;
1782 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1783 spaces
= sp
= alloca (i
);
1788 *sp
++ = ScreenAttrib
;
1792 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1793 if (screen_virtual_segment
)
1794 dosv_refresh_virtual_screen (offset
, i
/ 2);
1796 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1797 Let's follow their lead, in case someone relies on this. */
1798 new_pos_X
= first_unused
;
1802 IT_clear_screen (void)
1805 fprintf (termscript
, "<CLR:SCR>");
1806 /* We are sometimes called (from clear_garbaged_frames) when a new
1807 frame is being created, but its faces are not yet realized. In
1808 such a case we cannot call IT_set_face, since it will fail to find
1809 any valid faces and will abort. Instead, use the initial screen
1810 colors; that should mimic what a Unix tty does, which simply clears
1811 the screen with whatever default colors are in use. */
1812 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1813 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1818 if (screen_virtual_segment
)
1819 dosv_refresh_virtual_screen (0, screen_size
);
1820 new_pos_X
= new_pos_Y
= 0;
1824 IT_clear_to_end (void)
1827 fprintf (termscript
, "<CLR:EOS>");
1829 while (new_pos_Y
< screen_size_Y
) {
1831 IT_clear_end_of_line (screen_size_X
);
1837 IT_cursor_to (int y
, int x
)
1840 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1845 static int cursor_cleared
;
1848 IT_display_cursor (int on
)
1850 if (on
&& cursor_cleared
)
1852 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1855 else if (!on
&& !cursor_cleared
)
1857 ScreenSetCursor (-1, -1);
1862 /* Emacs calls cursor-movement functions a lot when it updates the
1863 display (probably a legacy of old terminals where you cannot
1864 update a screen line without first moving the cursor there).
1865 However, cursor movement is expensive on MSDOS (it calls a slow
1866 BIOS function and requires 2 mode switches), while actual screen
1867 updates access the video memory directly and don't depend on
1868 cursor position. To avoid slowing down the redisplay, we cheat:
1869 all functions that move the cursor only set internal variables
1870 which record the cursor position, whereas the cursor is only
1871 moved to its final position whenever screen update is complete.
1873 `IT_cmgoto' is called from the keyboard reading loop and when the
1874 frame update is complete. This means that we are ready for user
1875 input, so we update the cursor position to show where the point is,
1876 and also make the mouse pointer visible.
1878 Special treatment is required when the cursor is in the echo area,
1879 to put the cursor at the end of the text displayed there. */
1882 IT_cmgoto (FRAME_PTR f
)
1884 /* Only set the cursor to where it should be if the display is
1885 already in sync with the window contents. */
1886 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1888 /* FIXME: This needs to be rewritten for the new redisplay, or
1891 static int previous_pos_X
= -1;
1893 update_cursor_pos
= 1; /* temporary!!! */
1895 /* If the display is in sync, forget any previous knowledge about
1896 cursor position. This is primarily for unexpected events like
1897 C-g in the minibuffer. */
1898 if (update_cursor_pos
&& previous_pos_X
>= 0)
1899 previous_pos_X
= -1;
1900 /* If we are in the echo area, put the cursor at the
1901 end of the echo area message. */
1902 if (!update_cursor_pos
1903 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1905 int tem_X
= current_pos_X
, dummy
;
1907 if (echo_area_glyphs
)
1909 tem_X
= echo_area_glyphs_length
;
1910 /* Save current cursor position, to be restored after the
1911 echo area message is erased. Only remember one level
1912 of previous cursor position. */
1913 if (previous_pos_X
== -1)
1914 ScreenGetCursor (&dummy
, &previous_pos_X
);
1916 else if (previous_pos_X
>= 0)
1918 /* We wind up here after the echo area message is erased.
1919 Restore the cursor position we remembered above. */
1920 tem_X
= previous_pos_X
;
1921 previous_pos_X
= -1;
1924 if (current_pos_X
!= tem_X
)
1927 update_cursor_pos
= 1;
1932 if (update_cursor_pos
1933 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1935 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1937 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1940 /* Maybe cursor is invisible, so make it visible. */
1941 IT_display_cursor (1);
1943 /* Mouse pointer should be always visible if we are waiting for
1950 IT_reassert_line_highlight (int new, int vpos
)
1956 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1958 highlight
= new_highlight
;
1959 IT_cursor_to (vpos
, 0);
1960 IT_clear_end_of_line (first_unused_hpos
);
1964 IT_update_begin (struct frame
*f
)
1966 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1967 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1973 if (f
&& f
== mouse_face_frame
)
1975 /* Don't do highlighting for mouse motion during the update. */
1976 display_info
->mouse_face_defer
= 1;
1978 /* If F needs to be redrawn, simply forget about any prior mouse
1980 if (FRAME_GARBAGED_P (f
))
1981 display_info
->mouse_face_window
= Qnil
;
1983 /* Can we tell that this update does not affect the window
1984 where the mouse highlight is? If so, no need to turn off.
1985 Likewise, don't do anything if none of the enabled rows
1986 contains glyphs highlighted in mouse face. */
1987 if (!NILP (display_info
->mouse_face_window
)
1988 && WINDOWP (display_info
->mouse_face_window
))
1990 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1993 /* If the mouse highlight is in the window that was deleted
1994 (e.g., if it was popped by completion), clear highlight
1996 if (NILP (w
->buffer
))
1997 display_info
->mouse_face_window
= Qnil
;
2000 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
2001 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
2002 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
2006 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
2007 clear_mouse_face (display_info
);
2010 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
2012 /* If the frame with mouse highlight was deleted, invalidate the
2014 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
2015 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
2016 display_info
->mouse_face_window
= Qnil
;
2017 display_info
->mouse_face_deferred_gc
= 0;
2018 display_info
->mouse_face_mouse_frame
= NULL
;
2025 IT_update_end (struct frame
*f
)
2028 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
2031 Lisp_Object Qcursor_type
;
2034 IT_frame_up_to_date (struct frame
*f
)
2036 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
2037 Lisp_Object new_cursor
, frame_desired_cursor
;
2040 if (dpyinfo
->mouse_face_deferred_gc
2041 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
2044 if (dpyinfo
->mouse_face_mouse_frame
)
2045 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
2046 dpyinfo
->mouse_face_mouse_x
,
2047 dpyinfo
->mouse_face_mouse_y
);
2048 dpyinfo
->mouse_face_deferred_gc
= 0;
2052 /* Set the cursor type to whatever they wanted. In a minibuffer
2053 window, we want the cursor to appear only if we are reading input
2054 from this window, and we want the cursor to be taken from the
2055 frame parameters. For the selected window, we use either its
2056 buffer-local value or the value from the frame parameters if the
2057 buffer doesn't define its local value for the cursor type. */
2058 sw
= XWINDOW (f
->selected_window
);
2059 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
2060 if (cursor_in_echo_area
2061 && FRAME_HAS_MINIBUF_P (f
)
2062 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
2063 && sw
== XWINDOW (echo_area_window
))
2064 new_cursor
= frame_desired_cursor
;
2067 struct buffer
*b
= XBUFFER (sw
->buffer
);
2069 if (EQ (b
->cursor_type
, Qt
))
2070 new_cursor
= frame_desired_cursor
;
2071 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
2072 new_cursor
= Fcons (Qbar
, make_number (0));
2074 new_cursor
= b
->cursor_type
;
2077 IT_set_cursor_type (f
, new_cursor
);
2079 IT_cmgoto (f
); /* position cursor when update is done */
2082 /* Copy LEN glyphs displayed on a single line whose vertical position
2083 is YPOS, beginning at horizontal position XFROM to horizontal
2084 position XTO, by moving blocks in the video memory. Used by
2085 functions that insert and delete glyphs. */
2087 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
2089 /* The offsets of source and destination relative to the
2090 conventional memorty selector. */
2091 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
2092 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
2094 if (from
== to
|| len
<= 0)
2097 _farsetsel (_dos_ds
);
2099 /* The source and destination might overlap, so we need to move
2100 glyphs non-destructively. */
2103 for ( ; len
; from
+= 2, to
+= 2, len
--)
2104 _farnspokew (to
, _farnspeekw (from
));
2108 from
+= (len
- 1) * 2;
2109 to
+= (len
- 1) * 2;
2110 for ( ; len
; from
-= 2, to
-= 2, len
--)
2111 _farnspokew (to
, _farnspeekw (from
));
2113 if (screen_virtual_segment
)
2114 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
2117 /* Insert and delete glyphs. */
2119 IT_insert_glyphs (start
, len
)
2120 register struct glyph
*start
;
2123 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
2125 /* Shift right the glyphs from the nominal cursor position to the
2126 end of this line. */
2127 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2129 /* Now write the glyphs to be inserted. */
2130 IT_write_glyphs (start
, len
);
2134 IT_delete_glyphs (n
)
2140 /* set-window-configuration on window.c needs this. */
2142 x_set_menu_bar_lines (f
, value
, oldval
)
2144 Lisp_Object value
, oldval
;
2146 set_menu_bar_lines (f
, value
, oldval
);
2149 /* This was copied from xfaces.c */
2151 extern Lisp_Object Qbackground_color
;
2152 extern Lisp_Object Qforeground_color
;
2153 Lisp_Object Qreverse
;
2154 extern Lisp_Object Qtitle
;
2156 /* IT_set_terminal_modes is called when emacs is started,
2157 resumed, and whenever the screen is redrawn! */
2160 IT_set_terminal_modes (void)
2163 fprintf (termscript
, "\n<SET_TERM>");
2166 screen_size_X
= ScreenCols ();
2167 screen_size_Y
= ScreenRows ();
2168 screen_size
= screen_size_X
* screen_size_Y
;
2170 new_pos_X
= new_pos_Y
= 0;
2171 current_pos_X
= current_pos_Y
= -1;
2173 if (term_setup_done
)
2175 term_setup_done
= 1;
2177 startup_screen_size_X
= screen_size_X
;
2178 startup_screen_size_Y
= screen_size_Y
;
2179 startup_screen_attrib
= ScreenAttrib
;
2182 /* Is DOS/V (or any other RSIS software which relocates
2183 the screen) installed? */
2185 unsigned short es_value
;
2188 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2189 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2190 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2191 else if (screen_old_address
) /* already switched to Japanese mode once */
2192 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2194 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2196 es_value
= regs
.x
.es
;
2197 __dpmi_int (0x10, ®s
);
2199 if (regs
.x
.es
!= es_value
)
2201 /* screen_old_address is only set if ScreenPrimary does NOT
2202 already point to the relocated buffer address returned by
2203 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2204 ScreenPrimary to that address at startup under DOS/V. */
2205 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2206 screen_old_address
= ScreenPrimary
;
2207 screen_virtual_segment
= regs
.x
.es
;
2208 screen_virtual_offset
= regs
.x
.di
;
2209 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2212 #endif /* __DJGPP__ > 1 */
2214 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2215 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2218 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2219 screen_size_X
, screen_size_Y
);
2224 /* IT_reset_terminal_modes is called when emacs is
2225 suspended or killed. */
2228 IT_reset_terminal_modes (void)
2230 int display_row_start
= (int) ScreenPrimary
;
2231 int saved_row_len
= startup_screen_size_X
* 2;
2232 int update_row_len
= ScreenCols () * 2;
2233 int current_rows
= ScreenRows ();
2234 int to_next_row
= update_row_len
;
2235 unsigned char *saved_row
= startup_screen_buffer
;
2236 int cursor_pos_X
= ScreenCols () - 1;
2237 int cursor_pos_Y
= ScreenRows () - 1;
2240 fprintf (termscript
, "\n<RESET_TERM>");
2244 if (!term_setup_done
)
2249 /* Leave the video system in the same state as we found it,
2250 as far as the blink/bright-background bit is concerned. */
2251 maybe_enable_blinking ();
2253 /* We have a situation here.
2254 We cannot just do ScreenUpdate(startup_screen_buffer) because
2255 the luser could have changed screen dimensions inside Emacs
2256 and failed (or didn't want) to restore them before killing
2257 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2258 thus will happily use memory outside what was allocated for
2259 `startup_screen_buffer'.
2260 Thus we only restore as much as the current screen dimensions
2261 can hold, and clear the rest (if the saved screen is smaller than
2262 the current) with the color attribute saved at startup. The cursor
2263 is also restored within the visible dimensions. */
2265 ScreenAttrib
= startup_screen_attrib
;
2267 /* Don't restore the screen if we are exiting less than 2 seconds
2268 after startup: we might be crashing, and the screen might show
2269 some vital clues to what's wrong. */
2270 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2273 if (screen_virtual_segment
)
2274 dosv_refresh_virtual_screen (0, screen_size
);
2276 if (update_row_len
> saved_row_len
)
2277 update_row_len
= saved_row_len
;
2278 if (current_rows
> startup_screen_size_Y
)
2279 current_rows
= startup_screen_size_Y
;
2282 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2283 update_row_len
/ 2, current_rows
);
2285 while (current_rows
--)
2287 dosmemput (saved_row
, update_row_len
, display_row_start
);
2288 if (screen_virtual_segment
)
2289 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2290 update_row_len
/ 2);
2291 saved_row
+= saved_row_len
;
2292 display_row_start
+= to_next_row
;
2295 if (startup_pos_X
< cursor_pos_X
)
2296 cursor_pos_X
= startup_pos_X
;
2297 if (startup_pos_Y
< cursor_pos_Y
)
2298 cursor_pos_Y
= startup_pos_Y
;
2300 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2301 xfree (startup_screen_buffer
);
2303 term_setup_done
= 0;
2307 IT_set_terminal_window (int foo
)
2311 /* Remember the screen colors of the curent frame, to serve as the
2312 default colors for newly-created frames. */
2313 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2314 Smsdos_remember_default_colors
, 1, 1, 0,
2315 "Remember the screen colors of the current frame.")
2321 CHECK_FRAME (frame
, 0);
2324 /* This function is called after applying default-frame-alist to the
2325 initial frame. At that time, if reverse-colors option was
2326 specified in default-frame-alist, it was already applied, and
2327 frame colors are reversed. We need to account for that. */
2328 if (EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
))
2330 initial_screen_colors
[0] = FRAME_BACKGROUND_PIXEL (f
);
2331 initial_screen_colors
[1] = FRAME_FOREGROUND_PIXEL (f
);
2335 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2336 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2341 IT_set_frame_parameters (f
, alist
)
2346 int length
= XINT (Flength (alist
));
2349 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2351 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2352 /* Do we have to reverse the foreground and background colors? */
2353 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2354 int was_reverse
= reverse
;
2355 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2356 int need_to_reverse
;
2357 unsigned long orig_fg
;
2358 unsigned long orig_bg
;
2359 Lisp_Object frame_bg
, frame_fg
;
2360 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2362 /* If we are creating a new frame, begin with the original screen colors
2363 used for the initial frame. */
2364 if (alist
== Vdefault_frame_alist
2365 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2367 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2368 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2370 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2371 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2372 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2373 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2374 /* frame_fg and frame_bg could be nil if, for example,
2375 f->param_alist is nil, e.g. if we are called from
2376 Fmake_terminal_frame. */
2377 if (NILP (frame_fg
))
2378 frame_fg
= build_string (unspecified_fg
);
2379 if (NILP (frame_bg
))
2380 frame_bg
= build_string (unspecified_bg
);
2382 /* Extract parm names and values into those vectors. */
2384 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2389 parms
[i
] = Fcar (elt
);
2390 CHECK_SYMBOL (parms
[i
], 1);
2391 values
[i
] = Fcdr (elt
);
2397 for (i
= 0; i
< j
; i
++)
2399 Lisp_Object prop
, val
;
2404 if (EQ (prop
, Qreverse
))
2405 reverse
= EQ (val
, Qt
);
2408 need_to_reverse
= reverse
&& !was_reverse
;
2409 if (termscript
&& need_to_reverse
)
2410 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2412 /* Now process the alist elements in reverse of specified order. */
2413 for (i
--; i
>= 0; i
--)
2415 Lisp_Object prop
, val
;
2421 if (EQ (prop
, Qforeground_color
))
2423 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2424 ? LFACE_BACKGROUND_INDEX
2425 : LFACE_FOREGROUND_INDEX
);
2426 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2427 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2428 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2430 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2431 /* Make sure the foreground of the default face for this
2432 frame is changed as well. */
2433 XSETFRAME (frame
, f
);
2434 if (need_to_reverse
)
2436 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2438 prop
= Qbackground_color
;
2443 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2449 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2452 else if (EQ (prop
, Qbackground_color
))
2454 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2455 ? LFACE_FOREGROUND_INDEX
2456 : LFACE_BACKGROUND_INDEX
);
2457 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2458 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2459 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2461 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2462 /* Make sure the background of the default face for this
2463 frame is changed as well. */
2464 XSETFRAME (frame
, f
);
2465 if (need_to_reverse
)
2467 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2469 prop
= Qforeground_color
;
2474 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2480 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2483 else if (EQ (prop
, Qtitle
))
2485 x_set_title (f
, val
);
2487 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
2489 else if (EQ (prop
, Qcursor_type
))
2491 IT_set_cursor_type (f
, val
);
2493 fprintf (termscript
, "<CTYPE: %s>\n",
2494 EQ (val
, Qbar
) || CONSP (val
) && EQ (XCAR (val
), Qbar
)
2497 store_frame_param (f
, prop
, val
);
2500 /* If they specified "reverse", but not the colors, we need to swap
2501 the current frame colors. */
2502 if (need_to_reverse
)
2508 XSETFRAME (frame
, f
);
2509 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2510 tty_color_name (f
, orig_bg
),
2516 XSETFRAME (frame
, f
);
2517 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2518 tty_color_name (f
, orig_fg
),
2526 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2527 if (f
== SELECTED_FRAME())
2532 extern void init_frame_faces (FRAME_PTR
);
2534 #endif /* !HAVE_X_WINDOWS */
2537 /* Do we need the internal terminal? */
2540 internal_terminal_init ()
2542 char *term
= getenv ("TERM");
2544 struct frame
*sf
= SELECTED_FRAME();
2546 #ifdef HAVE_X_WINDOWS
2547 if (!inhibit_window_system
)
2552 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2554 if (getenv ("EMACSTEST"))
2555 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2557 #ifndef HAVE_X_WINDOWS
2558 if (!internal_terminal
|| inhibit_window_system
)
2560 sf
->output_method
= output_termcap
;
2564 Vwindow_system
= intern ("pc");
2565 Vwindow_system_version
= make_number (1);
2566 sf
->output_method
= output_msdos_raw
;
2568 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2569 screen_old_address
= 0;
2571 /* Forget the stale screen colors as well. */
2572 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2574 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2575 the_only_x_display
.background_pixel
= 7; /* White */
2576 the_only_x_display
.foreground_pixel
= 0; /* Black */
2578 colors
= getenv ("EMACSCOLORS");
2579 if (colors
&& strlen (colors
) >= 2)
2581 /* The colors use 4 bits each (we enable bright background). */
2582 if (isdigit (colors
[0]))
2584 else if (isxdigit (colors
[0]))
2585 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2586 if (colors
[0] >= 0 && colors
[0] < 16)
2587 the_only_x_display
.foreground_pixel
= colors
[0];
2588 if (isdigit (colors
[1]))
2590 else if (isxdigit (colors
[1]))
2591 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2592 if (colors
[1] >= 0 && colors
[1] < 16)
2593 the_only_x_display
.background_pixel
= colors
[1];
2595 the_only_x_display
.line_height
= 1;
2596 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2597 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2598 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2599 the_only_x_display
.display_info
.mouse_face_beg_row
=
2600 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2601 the_only_x_display
.display_info
.mouse_face_end_row
=
2602 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2603 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2604 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2605 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2606 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2607 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2609 init_frame_faces (sf
);
2611 ring_bell_hook
= IT_ring_bell
;
2612 insert_glyphs_hook
= IT_insert_glyphs
;
2613 delete_glyphs_hook
= IT_delete_glyphs
;
2614 write_glyphs_hook
= IT_write_glyphs
;
2615 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2616 clear_to_end_hook
= IT_clear_to_end
;
2617 clear_end_of_line_hook
= IT_clear_end_of_line
;
2618 clear_frame_hook
= IT_clear_screen
;
2619 change_line_highlight_hook
= IT_change_line_highlight
;
2620 update_begin_hook
= IT_update_begin
;
2621 update_end_hook
= IT_update_end
;
2622 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
2623 frame_up_to_date_hook
= IT_frame_up_to_date
;
2625 /* These hooks are called by term.c without being checked. */
2626 set_terminal_modes_hook
= IT_set_terminal_modes
;
2627 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2628 set_terminal_window_hook
= IT_set_terminal_window
;
2629 char_ins_del_ok
= 0;
2633 dos_get_saved_screen (screen
, rows
, cols
)
2638 #ifndef HAVE_X_WINDOWS
2639 *screen
= startup_screen_buffer
;
2640 *cols
= startup_screen_size_X
;
2641 *rows
= startup_screen_size_Y
;
2642 return *screen
!= (char *)0;
2648 #ifndef HAVE_X_WINDOWS
2650 /* We are not X, but we can emulate it well enough for our needs... */
2654 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2655 error ("Not running under a window system");
2661 /* ----------------------- Keyboard control ----------------------
2663 * Keymaps reflect the following keyboard layout:
2665 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2666 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2667 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2668 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2672 #define Ignore 0x0000
2673 #define Normal 0x0000 /* normal key - alt changes scan-code */
2674 #define FctKey 0x1000 /* func key if c == 0, else c */
2675 #define Special 0x2000 /* func key even if c != 0 */
2676 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2677 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2678 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2679 #define Grey 0x6000 /* Grey keypad key */
2681 #define Alt 0x0100 /* alt scan-code */
2682 #define Ctrl 0x0200 /* ctrl scan-code */
2683 #define Shift 0x0400 /* shift scan-code */
2685 static int extended_kbd
; /* 101 (102) keyboard present. */
2687 struct kbd_translate
{
2690 unsigned short code
;
2693 struct dos_keyboard_map
2698 struct kbd_translate
*translate_table
;
2702 static struct dos_keyboard_map us_keyboard
= {
2704 /* 01234567890123456789012345678901234567890 12345678901234 */
2705 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2706 /* 0123456789012345678901234567890123456789 012345678901234 */
2707 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2708 0, /* no Alt-Gr key */
2709 0 /* no translate table */
2712 static struct dos_keyboard_map fr_keyboard
= {
2714 /* 012 3456789012345678901234567890123456789012345678901234 */
2715 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2716 /* 0123456789012345678901234567890123456789012345678901234 */
2717 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2718 /* 01234567 89012345678901234567890123456789012345678901234 */
2720 0 /* no translate table */
2724 * Italian keyboard support, country code 39.
2727 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2728 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2731 static struct kbd_translate it_kbd_translate_table
[] = {
2732 { 0x56, 0x3c, Normal
| 13 },
2733 { 0x56, 0x3e, Normal
| 27 },
2736 static struct dos_keyboard_map it_keyboard
= {
2738 /* 0 123456789012345678901234567890123456789012345678901234 */
2739 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2740 /* 01 23456789012345678901234567890123456789012345678901234 */
2741 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2742 /* 0123456789012345678901234567890123456789012345678901234 */
2744 it_kbd_translate_table
2747 static struct dos_keyboard_map dk_keyboard
= {
2749 /* 0123456789012345678901234567890123456789012345678901234 */
2750 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2751 /* 01 23456789012345678901234567890123456789012345678901234 */
2752 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2753 /* 0123456789012345678901234567890123456789012345678901234 */
2755 0 /* no translate table */
2758 static struct kbd_translate jp_kbd_translate_table
[] = {
2759 { 0x73, 0x5c, Normal
| 0 },
2760 { 0x73, 0x5f, Normal
| 0 },
2761 { 0x73, 0x1c, Map
| 0 },
2762 { 0x7d, 0x5c, Normal
| 13 },
2763 { 0x7d, 0x7c, Normal
| 13 },
2764 { 0x7d, 0x1c, Map
| 13 },
2767 static struct dos_keyboard_map jp_keyboard
= {
2769 /* 0123456789012 345678901234567890123456789012345678901234 */
2770 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2771 /* 01 23456789012345678901234567890123456789012345678901234 */
2772 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2773 0, /* no Alt-Gr key */
2774 jp_kbd_translate_table
2777 static struct keyboard_layout_list
2780 struct dos_keyboard_map
*keyboard_map
;
2781 } keyboard_layout_list
[] =
2790 static struct dos_keyboard_map
*keyboard
;
2791 static int keyboard_map_all
;
2792 static int international_keyboard
;
2795 dos_set_keyboard (code
, always
)
2800 _go32_dpmi_registers regs
;
2802 /* See if Keyb.Com is installed (for international keyboard support).
2803 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2804 of Windows 9X! So don't do that! */
2806 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2807 _go32_dpmi_simulate_int (0x2f, ®s
);
2808 if (regs
.h
.al
== 0xff)
2809 international_keyboard
= 1;
2811 /* Initialize to US settings, for countries that don't have their own. */
2812 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2813 keyboard_map_all
= always
;
2814 dos_keyboard_layout
= 1;
2816 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2817 if (code
== keyboard_layout_list
[i
].country_code
)
2819 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2820 keyboard_map_all
= always
;
2821 dos_keyboard_layout
= code
;
2829 unsigned char char_code
; /* normal code */
2830 unsigned char meta_code
; /* M- code */
2831 unsigned char keypad_code
; /* keypad code */
2832 unsigned char editkey_code
; /* edit key */
2833 } keypad_translate_map
[] = {
2834 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2835 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2836 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2837 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2838 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2839 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2840 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2841 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2842 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2843 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2844 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2849 unsigned char char_code
; /* normal code */
2850 unsigned char keypad_code
; /* keypad code */
2851 } grey_key_translate_map
[] = {
2852 '/', 0xaf, /* kp-decimal */
2853 '*', 0xaa, /* kp-multiply */
2854 '-', 0xad, /* kp-subtract */
2855 '+', 0xab, /* kp-add */
2856 '\r', 0x8d /* kp-enter */
2859 static unsigned short
2860 ibmpc_translate_map
[] =
2862 /* --------------- 00 to 0f --------------- */
2863 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2864 Alt
| ModFct
| 0x1b, /* Escape */
2865 Normal
| 1, /* '1' */
2866 Normal
| 2, /* '2' */
2867 Normal
| 3, /* '3' */
2868 Normal
| 4, /* '4' */
2869 Normal
| 5, /* '5' */
2870 Normal
| 6, /* '6' */
2871 Normal
| 7, /* '7' */
2872 Normal
| 8, /* '8' */
2873 Normal
| 9, /* '9' */
2874 Normal
| 10, /* '0' */
2875 Normal
| 11, /* '-' */
2876 Normal
| 12, /* '=' */
2877 Special
| 0x08, /* Backspace */
2878 ModFct
| 0x74, /* Tab/Backtab */
2880 /* --------------- 10 to 1f --------------- */
2893 ModFct
| 0x0d, /* Return */
2898 /* --------------- 20 to 2f --------------- */
2907 Map
| 40, /* '\'' */
2909 Ignore
, /* Left shift */
2910 Map
| 41, /* '\\' */
2916 /* --------------- 30 to 3f --------------- */
2923 Ignore
, /* Right shift */
2924 Grey
| 1, /* Grey * */
2926 Normal
| 55, /* ' ' */
2927 Ignore
, /* Caps Lock */
2928 FctKey
| 0xbe, /* F1 */
2929 FctKey
| 0xbf, /* F2 */
2930 FctKey
| 0xc0, /* F3 */
2931 FctKey
| 0xc1, /* F4 */
2932 FctKey
| 0xc2, /* F5 */
2934 /* --------------- 40 to 4f --------------- */
2935 FctKey
| 0xc3, /* F6 */
2936 FctKey
| 0xc4, /* F7 */
2937 FctKey
| 0xc5, /* F8 */
2938 FctKey
| 0xc6, /* F9 */
2939 FctKey
| 0xc7, /* F10 */
2940 Ignore
, /* Num Lock */
2941 Ignore
, /* Scroll Lock */
2942 KeyPad
| 7, /* Home */
2943 KeyPad
| 8, /* Up */
2944 KeyPad
| 9, /* Page Up */
2945 Grey
| 2, /* Grey - */
2946 KeyPad
| 4, /* Left */
2947 KeyPad
| 5, /* Keypad 5 */
2948 KeyPad
| 6, /* Right */
2949 Grey
| 3, /* Grey + */
2950 KeyPad
| 1, /* End */
2952 /* --------------- 50 to 5f --------------- */
2953 KeyPad
| 2, /* Down */
2954 KeyPad
| 3, /* Page Down */
2955 KeyPad
| 0, /* Insert */
2956 KeyPad
| 10, /* Delete */
2957 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2958 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2959 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2960 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2961 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2962 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2963 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2964 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2965 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2966 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2967 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2968 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2970 /* --------------- 60 to 6f --------------- */
2971 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2972 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2973 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2974 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2975 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2976 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2977 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2978 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2979 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2980 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2981 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2982 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2983 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2984 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2985 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2986 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2988 /* --------------- 70 to 7f --------------- */
2989 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2990 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2991 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2992 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2993 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2994 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2995 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2996 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2997 Alt
| Map
| 1, /* '1' */
2998 Alt
| Map
| 2, /* '2' */
2999 Alt
| Map
| 3, /* '3' */
3000 Alt
| Map
| 4, /* '4' */
3001 Alt
| Map
| 5, /* '5' */
3002 Alt
| Map
| 6, /* '6' */
3003 Alt
| Map
| 7, /* '7' */
3004 Alt
| Map
| 8, /* '8' */
3006 /* --------------- 80 to 8f --------------- */
3007 Alt
| Map
| 9, /* '9' */
3008 Alt
| Map
| 10, /* '0' */
3009 Alt
| Map
| 11, /* '-' */
3010 Alt
| Map
| 12, /* '=' */
3011 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
3012 FctKey
| 0xc8, /* F11 */
3013 FctKey
| 0xc9, /* F12 */
3014 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
3015 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
3016 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
3017 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
3018 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
3019 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
3020 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
3021 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
3022 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
3024 /* --------------- 90 to 9f --------------- */
3025 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
3026 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
3027 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
3028 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
3029 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
3030 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
3031 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
3032 Alt
| FctKey
| 0x50, /* (Alt) Home */
3033 Alt
| FctKey
| 0x52, /* (Alt) Up */
3034 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
3035 Ignore
, /* NO KEY */
3036 Alt
| FctKey
| 0x51, /* (Alt) Left */
3037 Ignore
, /* NO KEY */
3038 Alt
| FctKey
| 0x53, /* (Alt) Right */
3039 Ignore
, /* NO KEY */
3040 Alt
| FctKey
| 0x57, /* (Alt) End */
3042 /* --------------- a0 to af --------------- */
3043 Alt
| KeyPad
| 2, /* (Alt) Down */
3044 Alt
| KeyPad
| 3, /* (Alt) Page Down */
3045 Alt
| KeyPad
| 0, /* (Alt) Insert */
3046 Alt
| KeyPad
| 10, /* (Alt) Delete */
3047 Alt
| Grey
| 0, /* (Alt) Grey / */
3048 Alt
| FctKey
| 0x09, /* (Alt) Tab */
3049 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
3052 /* These bit-positions corresponds to values returned by BIOS */
3053 #define SHIFT_P 0x0003 /* two bits! */
3054 #define CTRL_P 0x0004
3055 #define ALT_P 0x0008
3056 #define SCRLOCK_P 0x0010
3057 #define NUMLOCK_P 0x0020
3058 #define CAPSLOCK_P 0x0040
3059 #define ALT_GR_P 0x0800
3060 #define SUPER_P 0x4000 /* pseudo */
3061 #define HYPER_P 0x8000 /* pseudo */
3064 dos_get_modifiers (keymask
)
3071 /* Calculate modifier bits */
3072 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
3073 int86 (0x16, ®s
, ®s
);
3077 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
3078 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3082 mask
= regs
.h
.al
& (SHIFT_P
|
3083 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3085 /* Do not break international keyboard support. */
3086 /* When Keyb.Com is loaded, the right Alt key is */
3087 /* used for accessing characters like { and } */
3088 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
3091 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
3094 if (dos_hyper_key
== 1)
3097 modifiers
|= hyper_modifier
;
3099 else if (dos_super_key
== 1)
3102 modifiers
|= super_modifier
;
3104 else if (!international_keyboard
)
3106 /* If Keyb.Com is NOT installed, let Right Alt behave
3107 like the Left Alt. */
3113 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
3116 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
3118 if (dos_hyper_key
== 2)
3121 modifiers
|= hyper_modifier
;
3123 else if (dos_super_key
== 2)
3126 modifiers
|= super_modifier
;
3134 modifiers
|= shift_modifier
;
3136 modifiers
|= ctrl_modifier
;
3138 modifiers
|= meta_modifier
;
3145 #define NUM_RECENT_DOSKEYS (100)
3146 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
3147 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3148 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3150 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3151 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
3152 Each input key receives two values in this vector: first the ASCII code,\n\
3153 and then the scan code.")
3156 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
3159 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3160 return Fvector (total_doskeys
, keys
);
3163 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3164 bcopy (keys
+ recent_doskeys_index
,
3165 XVECTOR (val
)->contents
,
3166 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3168 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3169 recent_doskeys_index
* sizeof (Lisp_Object
));
3174 /* Get a char from keyboard. Function keys are put into the event queue. */
3178 struct input_event event
;
3181 #ifndef HAVE_X_WINDOWS
3182 /* Maybe put the cursor where it should be. */
3183 IT_cmgoto (SELECTED_FRAME());
3186 /* The following condition is equivalent to `kbhit ()', except that
3187 it uses the bios to do its job. This pleases DESQview/X. */
3188 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3189 int86 (0x16, ®s
, ®s
),
3190 (regs
.x
.flags
& 0x40) == 0)
3193 register unsigned char c
;
3194 int sc
, code
= -1, mask
, kp_mode
;
3197 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3198 int86 (0x16, ®s
, ®s
);
3203 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3205 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3206 recent_doskeys_index
= 0;
3207 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3209 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3210 recent_doskeys_index
= 0;
3212 modifiers
= dos_get_modifiers (&mask
);
3214 #ifndef HAVE_X_WINDOWS
3215 if (!NILP (Vdos_display_scancodes
))
3218 sprintf (buf
, "%02x:%02x*%04x",
3219 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3220 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3228 case 10: /* Ctrl Grey Enter */
3229 code
= Ctrl
| Grey
| 4;
3231 case 13: /* Grey Enter */
3234 case '/': /* Grey / */
3244 /* Try the keyboard-private translation table first. */
3245 if (keyboard
->translate_table
)
3247 struct kbd_translate
*p
= keyboard
->translate_table
;
3251 if (p
->sc
== sc
&& p
->ch
== c
)
3259 /* If the private table didn't translate it, use the general
3263 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3265 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3272 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3273 Emacs is ready to read a key. Therefore, if they press
3274 `Alt-x' when Emacs is busy, by the time we get to
3275 `dos_get_modifiers', they might have already released the
3276 Alt key, and Emacs gets just `x', which is BAD.
3277 However, for keys with the `Map' property set, the ASCII
3278 code returns zero iff Alt is pressed. So, when we DON'T
3279 have to support international_keyboard, we don't have to
3280 distinguish between the left and right Alt keys, and we
3281 can set the META modifier for any keys with the `Map'
3282 property if they return zero ASCII code (c = 0). */
3284 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3285 modifiers
|= meta_modifier
;
3287 modifiers
|= ctrl_modifier
;
3289 modifiers
|= shift_modifier
;
3292 switch (code
& 0xf000)
3295 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3297 c
= 0; /* Special */
3310 if (c
== 0) /* ctrl-break */
3312 return c
; /* ALT-nnn */
3314 if (!keyboard_map_all
)
3323 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3324 if (!keyboard_map_all
)
3328 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3329 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3333 code
= keyboard
->shifted
[code
];
3335 modifiers
&= ~shift_modifier
;
3338 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3339 code
= keyboard
->alt_gr
[code
];
3341 code
= keyboard
->unshifted
[code
];
3346 if (c
== 0xe0) /* edit key */
3349 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3350 kp_mode
= dos_keypad_mode
& 0x03;
3352 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3357 if (code
== 10 && dos_decimal_point
)
3358 return dos_decimal_point
;
3359 return keypad_translate_map
[code
].char_code
;
3362 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3366 code
= keypad_translate_map
[code
].meta_code
;
3367 modifiers
= meta_modifier
;
3371 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3378 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3379 if (dos_keypad_mode
& kp_mode
)
3380 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3382 code
= grey_key_translate_map
[code
].char_code
;
3391 event
.kind
= non_ascii_keystroke
;
3393 event
.kind
= ascii_keystroke
;
3395 event
.modifiers
= modifiers
;
3396 event
.frame_or_window
= selected_frame
;
3398 event
.timestamp
= event_timestamp ();
3399 kbd_buffer_store_event (&event
);
3402 if (have_mouse
> 0 && !mouse_preempted
)
3404 int but
, press
, x
, y
, ok
;
3405 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3407 /* Check for mouse movement *before* buttons. */
3408 mouse_check_moved ();
3410 /* If the mouse moved from the spot of its last sighting, we
3411 might need to update mouse highlight. */
3412 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3414 previous_help_echo
= help_echo
;
3415 help_echo
= help_echo_object
= help_echo_window
= Qnil
;
3417 IT_note_mouse_highlight (SELECTED_FRAME(),
3418 mouse_last_x
, mouse_last_y
);
3419 /* If the contents of the global variable help_echo has
3420 changed, generate a HELP_EVENT. */
3421 if (!NILP (help_echo
) || !NILP (previous_help_echo
))
3423 /* HELP_EVENT takes 2 events in the event loop. */
3424 event
.kind
= HELP_EVENT
;
3425 event
.frame_or_window
= selected_frame
;
3426 event
.arg
= help_echo_object
;
3427 event
.x
= make_number (help_echo_pos
);
3428 event
.timestamp
= event_timestamp ();
3430 kbd_buffer_store_event (&event
);
3431 if (WINDOWP (help_echo_window
))
3432 event
.frame_or_window
= help_echo_window
;
3433 event
.arg
= help_echo
;
3435 kbd_buffer_store_event (&event
);
3439 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3440 for (press
= 0; press
< 2; press
++)
3442 int button_num
= but
;
3445 ok
= mouse_pressed (but
, &x
, &y
);
3447 ok
= mouse_released (but
, &x
, &y
);
3450 /* Allow a simultaneous press/release of Mouse-1 and
3451 Mouse-2 to simulate Mouse-3 on two-button mice. */
3452 if (mouse_button_count
== 2 && but
< 2)
3454 int x2
, y2
; /* don't clobber original coordinates */
3456 /* If only one button is pressed, wait 100 msec and
3457 check again. This way, Speedy Gonzales isn't
3458 punished, while the slow get their chance. */
3459 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3460 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3465 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3466 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3471 event
.kind
= mouse_click
;
3472 event
.code
= button_num
;
3473 event
.modifiers
= dos_get_modifiers (0)
3474 | (press
? down_modifier
: up_modifier
);
3477 event
.frame_or_window
= selected_frame
;
3479 event
.timestamp
= event_timestamp ();
3480 kbd_buffer_store_event (&event
);
3488 static int prev_get_char
= -1;
3490 /* Return 1 if a key is ready to be read without suspending execution. */
3494 if (prev_get_char
!= -1)
3497 return ((prev_get_char
= dos_rawgetc ()) != -1);
3500 /* Read a key. Return -1 if no key is ready. */
3504 if (prev_get_char
!= -1)
3506 int c
= prev_get_char
;
3511 return dos_rawgetc ();
3514 #ifndef HAVE_X_WINDOWS
3515 /* See xterm.c for more info. */
3517 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
3519 register int pix_x
, pix_y
;
3520 register int *x
, *y
;
3524 if (bounds
) abort ();
3526 /* Ignore clipping. */
3533 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
3536 register int *pix_x
, *pix_y
;
3542 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3545 Actually, I don't know the meaning of all the parameters of the functions
3546 here -- I only know how they are called by xmenu.c. I could of course
3547 grab the nearest Xlib manual (down the hall, second-to-last door on the
3548 left), but I don't think it's worth the effort. */
3550 /* These hold text of the current and the previous menu help messages. */
3551 static char *menu_help_message
, *prev_menu_help_message
;
3552 /* Pane number and item number of the menu item which generated the
3553 last menu help message. */
3554 static int menu_help_paneno
, menu_help_itemno
;
3561 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3562 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3566 /* Allocate some (more) memory for MENU ensuring that there is room for one
3570 IT_menu_make_room (XMenu
*menu
)
3572 if (menu
->allocated
== 0)
3574 int count
= menu
->allocated
= 10;
3575 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3576 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3577 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3578 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3580 else if (menu
->allocated
== menu
->count
)
3582 int count
= menu
->allocated
= menu
->allocated
+ 10;
3584 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3586 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3588 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3590 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3594 /* Search the given menu structure for a given pane number. */
3597 IT_menu_search_pane (XMenu
*menu
, int pane
)
3602 for (i
= 0; i
< menu
->count
; i
++)
3603 if (menu
->submenu
[i
])
3605 if (pane
== menu
->panenumber
[i
])
3606 return menu
->submenu
[i
];
3607 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3613 /* Determine how much screen space a given menu needs. */
3616 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3618 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3621 maxheight
= menu
->count
;
3622 for (i
= 0; i
< menu
->count
; i
++)
3624 if (menu
->submenu
[i
])
3626 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3627 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3628 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3631 *width
= menu
->width
+ maxsubwidth
;
3632 *height
= maxheight
;
3635 /* Display MENU at (X,Y) using FACES. */
3638 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3640 int i
, j
, face
, width
;
3641 struct glyph
*text
, *p
;
3644 int enabled
, mousehere
;
3646 struct frame
*sf
= SELECTED_FRAME();
3648 menu_help_message
= NULL
;
3650 width
= menu
->width
;
3651 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3652 ScreenGetCursor (&row
, &col
);
3653 mouse_get_xy (&mx
, &my
);
3654 IT_update_begin (sf
);
3655 for (i
= 0; i
< menu
->count
; i
++)
3657 int max_width
= width
+ 2;
3659 IT_cursor_to (y
+ i
, x
);
3661 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3662 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3663 face
= faces
[enabled
+ mousehere
* 2];
3664 /* The following if clause means that we display the menu help
3665 strings even if the menu item is currently disabled. */
3666 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3668 menu_help_message
= menu
->help_text
[i
];
3669 menu_help_paneno
= pn
- 1;
3670 menu_help_itemno
= i
;
3673 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3675 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3679 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3682 else /* make '^x' */
3684 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3687 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3691 /* Don't let the menu text overflow into the next screen row. */
3692 if (x
+ max_width
> screen_size_X
)
3694 max_width
= screen_size_X
- x
;
3695 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3697 for (; j
< max_width
- 2; j
++, p
++)
3698 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3700 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3702 IT_write_glyphs (text
, max_width
);
3705 IT_cursor_to (row
, col
);
3709 /* --------------------------- X Menu emulation ---------------------- */
3711 /* Report availability of menus. */
3719 /* Create a brand new menu structure. */
3722 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3724 return IT_menu_create ();
3727 /* Create a new pane and place it on the outer-most level. It is not
3728 clear that it should be placed out there, but I don't know what else
3732 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3740 IT_menu_make_room (menu
);
3741 menu
->submenu
[menu
->count
] = IT_menu_create ();
3742 menu
->text
[menu
->count
] = txt
;
3743 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3744 menu
->help_text
[menu
->count
] = NULL
;
3747 /* Adjust length for possible control characters (which will
3748 be written as ^x). */
3749 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3753 if (len
> menu
->width
)
3756 return menu
->panecount
;
3759 /* Create a new item in a menu pane. */
3762 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3763 int foo
, char *txt
, int enable
, char *help_text
)
3769 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3771 IT_menu_make_room (menu
);
3772 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3773 menu
->text
[menu
->count
] = txt
;
3774 menu
->panenumber
[menu
->count
] = enable
;
3775 menu
->help_text
[menu
->count
] = help_text
;
3778 /* Adjust length for possible control characters (which will
3779 be written as ^x). */
3780 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3784 if (len
> menu
->width
)
3790 /* Decide where the menu would be placed if requested at (X,Y). */
3793 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3794 int *ulx
, int *uly
, int *width
, int *height
)
3796 IT_menu_calc_size (menu
, width
, height
);
3802 struct IT_menu_state
3804 void *screen_behind
;
3811 /* Display menu, wait for user's response, and return that response. */
3814 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3815 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3816 void (*help_callback
)(char *, int, int))
3818 struct IT_menu_state
*state
;
3823 Lisp_Object selectface
;
3824 int leave
, result
, onepane
;
3825 int title_faces
[4]; /* face to display the menu title */
3826 int buffers_num_deleted
= 0;
3827 struct frame
*sf
= SELECTED_FRAME();
3828 Lisp_Object saved_echo_area_message
;
3830 /* Just in case we got here without a mouse present... */
3831 if (have_mouse
<= 0)
3832 return XM_IA_SELECT
;
3833 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3834 around the display. */
3840 /* We will process all the mouse events directly, so we had
3841 better prevent dos_rawgetc from stealing them from us. */
3844 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3845 screensize
= screen_size
* 2;
3847 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3848 0, DEFAULT_FACE_ID
);
3850 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3851 0, DEFAULT_FACE_ID
);
3852 selectface
= intern ("msdos-menu-select-face");
3853 faces
[2] = lookup_derived_face (sf
, selectface
,
3855 faces
[3] = lookup_derived_face (sf
, selectface
,
3858 /* Make sure the menu title is always displayed with
3859 `msdos-menu-active-face', no matter where the mouse pointer is. */
3860 for (i
= 0; i
< 4; i
++)
3861 title_faces
[i
] = faces
[3];
3865 /* Don't let the title for the "Buffers" popup menu include a
3866 digit (which is ugly).
3868 This is a terrible kludge, but I think the "Buffers" case is
3869 the only one where the title includes a number, so it doesn't
3870 seem to be necessary to make this more general. */
3871 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3873 menu
->text
[0][7] = '\0';
3874 buffers_num_deleted
= 1;
3877 /* We need to save the current echo area message, so that we could
3878 restore it below, before we exit. See the commentary below,
3879 before the call to message_with_string. */
3880 saved_echo_area_message
= Fcurrent_message ();
3881 state
[0].menu
= menu
;
3883 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3885 /* Turn off the cursor. Otherwise it shows through the menu
3886 panes, which is ugly. */
3887 IT_display_cursor (0);
3889 /* Display the menu title. */
3890 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3891 if (buffers_num_deleted
)
3892 menu
->text
[0][7] = ' ';
3893 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3895 menu
->width
= menu
->submenu
[0]->width
;
3896 state
[0].menu
= menu
->submenu
[0];
3900 state
[0].menu
= menu
;
3902 state
[0].x
= x0
- 1;
3904 state
[0].pane
= onepane
;
3906 mouse_last_x
= -1; /* A hack that forces display. */
3910 if (!mouse_visible
) mouse_on ();
3911 mouse_check_moved ();
3912 if (sf
->mouse_moved
)
3914 sf
->mouse_moved
= 0;
3915 result
= XM_IA_SELECT
;
3916 mouse_get_xy (&x
, &y
);
3917 for (i
= 0; i
< statecount
; i
++)
3918 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3920 int dy
= y
- state
[i
].y
;
3921 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3923 if (!state
[i
].menu
->submenu
[dy
])
3924 if (state
[i
].menu
->panenumber
[dy
])
3925 result
= XM_SUCCESS
;
3927 result
= XM_IA_SELECT
;
3928 *pane
= state
[i
].pane
- 1;
3930 /* We hit some part of a menu, so drop extra menus that
3931 have been opened. That does not include an open and
3933 if (i
!= statecount
- 2
3934 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3935 while (i
!= statecount
- 1)
3939 ScreenUpdate (state
[statecount
].screen_behind
);
3940 if (screen_virtual_segment
)
3941 dosv_refresh_virtual_screen (0, screen_size
);
3942 xfree (state
[statecount
].screen_behind
);
3944 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3946 IT_menu_display (state
[i
].menu
,
3951 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3952 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3954 ScreenRetrieve (state
[statecount
].screen_behind
3955 = xmalloc (screensize
));
3957 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3958 state
[statecount
].y
= y
;
3963 IT_menu_display (state
[statecount
- 1].menu
,
3964 state
[statecount
- 1].y
,
3965 state
[statecount
- 1].x
,
3966 state
[statecount
- 1].pane
,
3971 if ((menu_help_message
|| prev_menu_help_message
)
3972 && menu_help_message
!= prev_menu_help_message
)
3974 help_callback (menu_help_message
,
3975 menu_help_paneno
, menu_help_itemno
);
3976 IT_display_cursor (0);
3977 prev_menu_help_message
= menu_help_message
;
3979 /* We are busy-waiting for the mouse to move, so let's be nice
3980 to other Windows applications by releasing our time slice. */
3983 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3985 /* Only leave if user both pressed and released the mouse, and in
3986 that order. This avoids popping down the menu pane unless
3987 the user is really done with it. */
3988 if (mouse_pressed (b
, &x
, &y
))
3990 while (mouse_button_depressed (b
, &x
, &y
))
3994 (void) mouse_released (b
, &x
, &y
);
3999 ScreenUpdate (state
[0].screen_behind
);
4000 if (screen_virtual_segment
)
4001 dosv_refresh_virtual_screen (0, screen_size
);
4003 /* We have a situation here. ScreenUpdate has just restored the
4004 screen contents as it was before we started drawing this menu.
4005 That includes any echo area message that could have been
4006 displayed back then. (In reality, that echo area message will
4007 almost always be the ``keystroke echo'' that echoes the sequence
4008 of menu items chosen by the user.) However, if the menu had some
4009 help messages, then displaying those messages caused Emacs to
4010 forget about the original echo area message. So when
4011 ScreenUpdate restored it, it created a discrepancy between the
4012 actual screen contents and what Emacs internal data structures
4015 To avoid this conflict, we force Emacs to restore the original
4016 echo area message as we found it when we entered this function.
4017 The irony of this is that we then erase the restored message
4018 right away, so the only purpose of restoring it is so that
4019 erasing it works correctly... */
4020 if (! NILP (saved_echo_area_message
))
4021 message_with_string ("%s", saved_echo_area_message
, 0);
4023 while (statecount
--)
4024 xfree (state
[statecount
].screen_behind
);
4025 IT_display_cursor (1); /* turn cursor back on */
4026 /* Clean up any mouse events that are waiting inside Emacs event queue.
4027 These events are likely to be generated before the menu was even
4028 displayed, probably because the user pressed and released the button
4029 (which invoked the menu) too quickly. If we don't remove these events,
4030 Emacs will process them after we return and surprise the user. */
4031 discard_mouse_events ();
4032 mouse_clear_clicks ();
4033 if (!kbd_buffer_events_waiting (1))
4034 clear_input_pending ();
4035 /* Allow mouse events generation by dos_rawgetc. */
4040 /* Dispose of a menu. */
4043 XMenuDestroy (Display
*foo
, XMenu
*menu
)
4046 if (menu
->allocated
)
4048 for (i
= 0; i
< menu
->count
; i
++)
4049 if (menu
->submenu
[i
])
4050 XMenuDestroy (foo
, menu
->submenu
[i
]);
4052 xfree (menu
->submenu
);
4053 xfree (menu
->panenumber
);
4054 xfree (menu
->help_text
);
4057 menu_help_message
= prev_menu_help_message
= NULL
;
4061 x_pixel_width (struct frame
*f
)
4063 return FRAME_WIDTH (f
);
4067 x_pixel_height (struct frame
*f
)
4069 return FRAME_HEIGHT (f
);
4071 #endif /* !HAVE_X_WINDOWS */
4073 /* ----------------------- DOS / UNIX conversion --------------------- */
4075 void msdos_downcase_filename (unsigned char *);
4077 /* Destructively turn backslashes into slashes. */
4080 dostounix_filename (p
)
4083 msdos_downcase_filename (p
);
4093 /* Destructively turn slashes into backslashes. */
4096 unixtodos_filename (p
)
4099 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4113 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4116 getdefdir (drive
, dst
)
4120 char in_path
[4], *p
= in_path
;
4123 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4126 *p
++ = drive
+ 'A' - 1;
4133 _fixpath (in_path
, dst
);
4134 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4135 it queries the LFN support, so ignore that error. */
4136 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
4139 msdos_downcase_filename (dst
);
4146 emacs_root_dir (void)
4148 static char root_dir
[4];
4150 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
4151 root_dir
[0] = tolower (root_dir
[0]);
4155 /* Remove all CR's that are followed by a LF. */
4160 register unsigned char *buf
;
4162 unsigned char *np
= buf
;
4163 unsigned char *startp
= buf
;
4164 unsigned char *endp
= buf
+ n
;
4168 while (buf
< endp
- 1)
4172 if (*(++buf
) != 0x0a)
4183 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4185 /* In DJGPP v2.0, library `write' can call `malloc', which might
4186 cause relocation of the buffer whose address we get in ADDR.
4187 Here is a version of `write' that avoids calling `malloc',
4188 to serve us until such time as the library is fixed.
4189 Actually, what we define here is called `__write', because
4190 `write' is a stub that just jmp's to `__write' (to be
4191 POSIXLY-correct with respect to the global name-space). */
4193 #include <io.h> /* for _write */
4194 #include <libc/dosio.h> /* for __file_handle_modes[] */
4196 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4198 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4201 __write (int handle
, const void *buffer
, size_t count
)
4206 if(__file_handle_modes
[handle
] & O_BINARY
)
4207 return _write (handle
, buffer
, count
);
4211 const char *bp
= buffer
;
4212 int total_written
= 0;
4213 int nmoved
= 0, ncr
= 0;
4217 /* The next test makes sure there's space for at least 2 more
4218 characters in xbuf[], so both CR and LF can be put there. */
4230 if (xbp
>= XBUF_END
|| !count
)
4232 size_t to_write
= nmoved
+ ncr
;
4233 int written
= _write (handle
, xbuf
, to_write
);
4238 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4240 /* If some, but not all were written (disk full?), return
4241 an estimate of the total written bytes not counting CRs. */
4242 if (written
< to_write
)
4243 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4250 return total_written
;
4254 /* A low-level file-renaming function which works around Windows 95 bug.
4255 This is pulled directly out of DJGPP v2.01 library sources, and only
4256 used when you compile with DJGPP v2.0. */
4260 int _rename(const char *old
, const char *new)
4263 int olen
= strlen(old
) + 1;
4265 int use_lfn
= _USE_LFN
;
4266 char tempfile
[FILENAME_MAX
];
4267 const char *orig
= old
;
4270 r
.x
.dx
= __tb_offset
;
4271 r
.x
.di
= __tb_offset
+ olen
;
4272 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4276 /* Windows 95 bug: for some filenames, when you rename
4277 file -> file~ (as in Emacs, to leave a backup), the
4278 short 8+3 alias doesn't change, which effectively
4279 makes OLD and NEW the same file. We must rename
4280 through a temporary file to work around this. */
4282 char *pbase
= 0, *p
;
4283 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4284 int idx
= sizeof(try_char
) - 1;
4286 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4287 might point to another drive, which will fail the DOS call. */
4288 strcpy(tempfile
, old
);
4289 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4290 if (*p
== '/' || *p
== '\\' || *p
== ':')
4296 strcpy(pbase
, "X$$djren$$.$$temp$$");
4302 *pbase
= try_char
[--idx
];
4303 } while (_chmod(tempfile
, 0) != -1);
4306 _put_path2(tempfile
, olen
);
4308 __dpmi_int(0x21, &r
);
4311 errno
= __doserr_to_errno(r
.x
.ax
);
4315 /* Now create a file with the original name. This will
4316 ensure that NEW will always have a 8+3 alias
4317 different from that of OLD. (Seems to be required
4318 when NameNumericTail in the Registry is set to 0.) */
4319 lfn_fd
= _creat(old
, 0);
4321 olen
= strlen(tempfile
) + 1;
4323 r
.x
.di
= __tb_offset
+ olen
;
4332 _put_path2(new, olen
);
4334 __dpmi_int(0x21, &r
);
4337 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4338 remove(new); /* and try again */
4341 errno
= __doserr_to_errno(r
.x
.ax
);
4343 /* Restore to original name if we renamed it to temporary. */
4351 _put_path2(orig
, olen
);
4352 _put_path(tempfile
);
4354 __dpmi_int(0x21, &r
);
4363 /* Success. Delete the file possibly created to work
4364 around the Windows 95 bug. */
4366 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4370 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4372 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4374 "Return non-nil if long file names are supported on MSDOS.")
4377 return (_USE_LFN
? Qt
: Qnil
);
4380 /* Convert alphabetic characters in a filename to lower-case. */
4383 msdos_downcase_filename (p
)
4384 register unsigned char *p
;
4386 /* Always lower-case drive letters a-z, even if the filesystem
4387 preserves case in filenames.
4388 This is so MSDOS filenames could be compared by string comparison
4389 functions that are case-sensitive. Even case-preserving filesystems
4390 do not distinguish case in drive letters. */
4391 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4397 /* Under LFN we expect to get pathnames in their true case. */
4398 if (NILP (Fmsdos_long_file_names ()))
4400 if (*p
>= 'A' && *p
<= 'Z')
4404 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4406 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4407 When long filenames are supported, doesn't change FILENAME.\n\
4408 If FILENAME is not a string, returns nil.\n\
4409 The argument object is never altered--the value is a copy.")
4411 Lisp_Object filename
;
4415 if (! STRINGP (filename
))
4418 tem
= Fcopy_sequence (filename
);
4419 msdos_downcase_filename (XSTRING (tem
)->data
);
4423 /* The Emacs root directory as determined by init_environment. */
4425 static char emacsroot
[MAXPATHLEN
];
4428 rootrelativepath (rel
)
4431 static char result
[MAXPATHLEN
+ 10];
4433 strcpy (result
, emacsroot
);
4434 strcat (result
, "/");
4435 strcat (result
, rel
);
4439 /* Define a lot of environment variables if not already defined. Don't
4440 remove anything unless you know what you're doing -- lots of code will
4441 break if one or more of these are missing. */
4444 init_environment (argc
, argv
, skip_args
)
4451 static const char * const tempdirs
[] = {
4452 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4455 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4457 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4458 temporary files and assume "/tmp" if $TMPDIR is unset, which
4459 will break on DOS/Windows. Refuse to work if we cannot find
4460 a directory, not even "c:/", usable for that purpose. */
4461 for (i
= 0; i
< imax
; i
++)
4463 const char *tmp
= tempdirs
[i
];
4466 tmp
= getenv (tmp
+ 1);
4467 /* Note that `access' can lie to us if the directory resides on a
4468 read-only filesystem, like CD-ROM or a write-protected floppy.
4469 The only way to be really sure is to actually create a file and
4470 see if it succeeds. But I think that's too much to ask. */
4471 if (tmp
&& access (tmp
, D_OK
) == 0)
4473 setenv ("TMPDIR", tmp
, 1);
4480 Fcons (build_string ("no usable temporary directories found!!"),
4482 "While setting TMPDIR: ");
4484 /* Note the startup time, so we know not to clear the screen if we
4485 exit immediately; see IT_reset_terminal_modes.
4486 (Yes, I know `clock' returns zero the first time it's called, but
4487 I do this anyway, in case some wiseguy changes that at some point.) */
4488 startup_time
= clock ();
4490 /* Find our root from argv[0]. Assuming argv[0] is, say,
4491 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4492 root
= alloca (MAXPATHLEN
+ 20);
4493 _fixpath (argv
[0], root
);
4494 msdos_downcase_filename (root
);
4495 len
= strlen (root
);
4496 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4500 && (strcmp (root
+ len
- 4, "/bin") == 0
4501 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4502 root
[len
- 4] = '\0';
4504 strcpy (root
, "c:/emacs"); /* let's be defensive */
4505 len
= strlen (root
);
4506 strcpy (emacsroot
, root
);
4508 /* We default HOME to our root. */
4509 setenv ("HOME", root
, 0);
4511 /* We default EMACSPATH to root + "/bin". */
4512 strcpy (root
+ len
, "/bin");
4513 setenv ("EMACSPATH", root
, 0);
4515 /* I don't expect anybody to ever use other terminals so the internal
4516 terminal is the default. */
4517 setenv ("TERM", "internal", 0);
4519 #ifdef HAVE_X_WINDOWS
4520 /* Emacs expects DISPLAY to be set. */
4521 setenv ("DISPLAY", "unix:0.0", 0);
4524 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4525 downcase it and mirror the backslashes. */
4526 s
= getenv ("COMSPEC");
4527 if (!s
) s
= "c:/command.com";
4528 t
= alloca (strlen (s
) + 1);
4530 dostounix_filename (t
);
4531 setenv ("SHELL", t
, 0);
4533 /* PATH is also downcased and backslashes mirrored. */
4534 s
= getenv ("PATH");
4536 t
= alloca (strlen (s
) + 3);
4537 /* Current directory is always considered part of MsDos's path but it is
4538 not normally mentioned. Now it is. */
4539 strcat (strcpy (t
, ".;"), s
);
4540 dostounix_filename (t
); /* Not a single file name, but this should work. */
4541 setenv ("PATH", t
, 1);
4543 /* In some sense all dos users have root privileges, so... */
4544 setenv ("USER", "root", 0);
4545 setenv ("NAME", getenv ("USER"), 0);
4547 /* Time zone determined from country code. To make this possible, the
4548 country code may not span more than one time zone. In other words,
4549 in the USA, you lose. */
4551 switch (dos_country_code
)
4553 case 31: /* Belgium */
4554 case 32: /* The Netherlands */
4555 case 33: /* France */
4556 case 34: /* Spain */
4557 case 36: /* Hungary */
4558 case 38: /* Yugoslavia (or what's left of it?) */
4559 case 39: /* Italy */
4560 case 41: /* Switzerland */
4561 case 42: /* Tjekia */
4562 case 45: /* Denmark */
4563 case 46: /* Sweden */
4564 case 47: /* Norway */
4565 case 48: /* Poland */
4566 case 49: /* Germany */
4567 /* Daylight saving from last Sunday in March to last Sunday in
4568 September, both at 2AM. */
4569 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4571 case 44: /* United Kingdom */
4572 case 351: /* Portugal */
4573 case 354: /* Iceland */
4574 setenv ("TZ", "GMT+00", 0);
4576 case 81: /* Japan */
4577 case 82: /* Korea */
4578 setenv ("TZ", "JST-09", 0);
4580 case 90: /* Turkey */
4581 case 358: /* Finland */
4582 setenv ("TZ", "EET-02", 0);
4584 case 972: /* Israel */
4585 /* This is an approximation. (For exact rules, use the
4586 `zoneinfo/israel' file which comes with DJGPP, but you need
4587 to install it in `/usr/share/zoneinfo/' directory first.) */
4588 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4596 static int break_stat
; /* BREAK check mode status. */
4597 static int stdin_stat
; /* stdin IOCTL status. */
4601 /* These must be global. */
4602 static _go32_dpmi_seginfo ctrl_break_vector
;
4603 static _go32_dpmi_registers ctrl_break_regs
;
4604 static int ctrlbreakinstalled
= 0;
4606 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4609 ctrl_break_func (regs
)
4610 _go32_dpmi_registers
*regs
;
4616 install_ctrl_break_check ()
4618 if (!ctrlbreakinstalled
)
4620 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4621 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4622 ctrlbreakinstalled
= 1;
4623 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4624 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4626 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4630 #endif /* __DJGPP__ < 2 */
4632 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4633 control chars by DOS. Determine the keyboard type. */
4638 union REGS inregs
, outregs
;
4639 static int first_time
= 1;
4641 break_stat
= getcbrk ();
4644 install_ctrl_break_check ();
4650 int86 (0x15, &inregs
, &outregs
);
4651 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4655 if (internal_terminal
4656 #ifdef HAVE_X_WINDOWS
4657 && inhibit_window_system
4661 inregs
.x
.ax
= 0x0021;
4662 int86 (0x33, &inregs
, &outregs
);
4663 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4666 /* Reportedly, the above doesn't work for some mouse drivers. There
4667 is an additional detection method that should work, but might be
4668 a little slower. Use that as an alternative. */
4669 inregs
.x
.ax
= 0x0000;
4670 int86 (0x33, &inregs
, &outregs
);
4671 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4676 have_mouse
= 1; /* enable mouse */
4678 mouse_setup_buttons (outregs
.x
.bx
);
4679 mouse_position_hook
= &mouse_get_pos
;
4683 #ifndef HAVE_X_WINDOWS
4685 /* Save the cursor shape used outside Emacs. */
4686 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4695 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4696 return (stdin_stat
!= -1);
4699 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4701 #else /* __DJGPP__ < 2 */
4705 /* I think it is wrong to overwrite `stdin_stat' every time
4706 but the first one this function is called, but I don't
4707 want to change the way it used to work in v1.x.--EZ */
4709 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4710 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4711 intdos (&inregs
, &outregs
);
4712 stdin_stat
= outregs
.h
.dl
;
4714 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4715 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4716 intdos (&inregs
, &outregs
);
4717 return !outregs
.x
.cflag
;
4719 #endif /* __DJGPP__ < 2 */
4722 /* Restore status of standard input and Ctrl-C checking. */
4727 union REGS inregs
, outregs
;
4729 setcbrk (break_stat
);
4734 #ifndef HAVE_X_WINDOWS
4735 /* Restore the cursor shape we found on startup. */
4739 inregs
.x
.cx
= outside_cursor
;
4740 int86 (0x10, &inregs
, &outregs
);
4744 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4746 #else /* not __DJGPP__ >= 2 */
4748 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4749 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4750 inregs
.x
.dx
= stdin_stat
;
4751 intdos (&inregs
, &outregs
);
4752 return !outregs
.x
.cflag
;
4754 #endif /* not __DJGPP__ >= 2 */
4758 /* Run command as specified by ARGV in directory DIR.
4759 The command is run with input from TEMPIN, output to
4760 file TEMPOUT and stderr to TEMPERR. */
4763 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4764 unsigned char **argv
;
4765 const char *working_dir
;
4766 int tempin
, tempout
, temperr
;
4769 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4770 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4771 int msshell
, result
= -1;
4772 int inbak
, outbak
, errbak
;
4776 /* Get current directory as MSDOS cwd is not per-process. */
4779 /* If argv[0] is the shell, it might come in any lettercase.
4780 Since `Fmember' is case-sensitive, we need to downcase
4781 argv[0], even if we are on case-preserving filesystems. */
4782 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4783 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4786 if (*pl
>= 'A' && *pl
<= 'Z')
4791 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4792 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4793 && !strcmp ("-c", argv
[1]);
4796 saveargv1
= argv
[1];
4797 saveargv2
= argv
[2];
4799 /* We only need to mirror slashes if a DOS shell will be invoked
4800 not via `system' (which does the mirroring itself). Yes, that
4801 means DJGPP v1.x will lose here. */
4802 if (argv
[2] && argv
[3])
4804 char *p
= alloca (strlen (argv
[2]) + 1);
4806 strcpy (argv
[2] = p
, saveargv2
);
4807 while (*p
&& isspace (*p
))
4819 chdir (working_dir
);
4823 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4824 goto done
; /* Allocation might fail due to lack of descriptors. */
4827 mouse_get_xy (&x
, &y
);
4829 dos_ttcooked (); /* do it here while 0 = stdin */
4837 if (msshell
&& !argv
[3])
4839 /* MS-DOS native shells are too restrictive. For starters, they
4840 cannot grok commands longer than 126 characters. In DJGPP v2
4841 and later, `system' is much smarter, so we'll call it instead. */
4845 /* A shell gets a single argument--its full command
4846 line--whose original was saved in `saveargv2'. */
4848 /* Don't let them pass empty command lines to `system', since
4849 with some shells it will try to invoke an interactive shell,
4850 which will hang Emacs. */
4851 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4855 extern char **environ
;
4856 char **save_env
= environ
;
4857 int save_system_flags
= __system_flags
;
4859 /* Request the most powerful version of `system'. We need
4860 all the help we can get to avoid calling stock DOS shells. */
4861 __system_flags
= (__system_redirect
4862 | __system_use_shell
4863 | __system_allow_multiple_cmds
4864 | __system_allow_long_cmds
4865 | __system_handle_null_commands
4866 | __system_emulate_chdir
);
4869 result
= system (cmnd
);
4870 __system_flags
= save_system_flags
;
4874 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4878 #endif /* __DJGPP__ > 1 */
4880 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4885 emacs_close (inbak
);
4886 emacs_close (outbak
);
4887 emacs_close (errbak
);
4893 mouse_moveto (x
, y
);
4896 /* Some programs might change the meaning of the highest bit of the
4897 text attribute byte, so we get blinking characters instead of the
4898 bright background colors. Restore that. */
4905 argv
[1] = saveargv1
;
4906 argv
[2] = saveargv2
;
4914 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4921 /* ------------------------- Compatibility functions -------------------
4926 /* Hostnames for a pc are not really funny,
4927 but they are used in change log so we emulate the best we can. */
4929 gethostname (p
, size
)
4933 char *q
= egetenv ("HOSTNAME");
4940 /* When time zones are set from Ms-Dos too many C-libraries are playing
4941 tricks with time values. We solve this by defining our own version
4942 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4943 once and after each call to `tzset' with TZ changed. That is
4944 accomplished by aliasing tzset to init_gettimeofday. */
4946 static struct tm time_rec
;
4949 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4957 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4961 time_rec
.tm_year
= d
.da_year
- 1900;
4962 time_rec
.tm_mon
= d
.da_mon
- 1;
4963 time_rec
.tm_mday
= d
.da_day
;
4966 time_rec
.tm_hour
= t
.ti_hour
;
4967 time_rec
.tm_min
= t
.ti_min
;
4968 time_rec
.tm_sec
= t
.ti_sec
;
4971 tm
.tm_gmtoff
= dos_timezone_offset
;
4973 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4974 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4976 /* Ignore tzp; it's obsolescent. */
4980 #endif /* __DJGPP__ < 2 */
4983 * A list of unimplemented functions that we silently ignore.
4987 unsigned alarm (s
) unsigned s
; {}
4988 fork () { return 0; }
4989 int kill (x
, y
) int x
, y
; { return -1; }
4991 void volatile pause () {}
4992 sigsetmask (x
) int x
; { return 0; }
4993 sigblock (mask
) int mask
; { return 0; }
4996 void request_sigio (void) {}
4997 setpgrp () {return 0; }
4998 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4999 void unrequest_sigio (void) {}
5003 #ifdef POSIX_SIGNALS
5005 /* Augment DJGPP library POSIX signal functions. This is needed
5006 as of DJGPP v2.01, but might be in the library in later releases. */
5008 #include <libc/bss.h>
5010 /* A counter to know when to re-initialize the static sets. */
5011 static int sigprocmask_count
= -1;
5013 /* Which signals are currently blocked (initially none). */
5014 static sigset_t current_mask
;
5016 /* Which signals are pending (initially none). */
5017 static sigset_t pending_signals
;
5019 /* Previous handlers to restore when the blocked signals are unblocked. */
5020 typedef void (*sighandler_t
)(int);
5021 static sighandler_t prev_handlers
[320];
5023 /* A signal handler which just records that a signal occured
5024 (it will be raised later, if and when the signal is unblocked). */
5026 sig_suspender (signo
)
5029 sigaddset (&pending_signals
, signo
);
5033 sigprocmask (how
, new_set
, old_set
)
5035 const sigset_t
*new_set
;
5041 /* If called for the first time, initialize. */
5042 if (sigprocmask_count
!= __bss_count
)
5044 sigprocmask_count
= __bss_count
;
5045 sigemptyset (&pending_signals
);
5046 sigemptyset (¤t_mask
);
5047 for (signo
= 0; signo
< 320; signo
++)
5048 prev_handlers
[signo
] = SIG_ERR
;
5052 *old_set
= current_mask
;
5057 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
5063 sigemptyset (&new_mask
);
5065 /* DJGPP supports upto 320 signals. */
5066 for (signo
= 0; signo
< 320; signo
++)
5068 if (sigismember (¤t_mask
, signo
))
5069 sigaddset (&new_mask
, signo
);
5070 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
5072 sigaddset (&new_mask
, signo
);
5074 /* SIGKILL is silently ignored, as on other platforms. */
5075 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
5076 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
5078 if (( how
== SIG_UNBLOCK
5079 && sigismember (&new_mask
, signo
)
5080 && sigismember (new_set
, signo
))
5081 || (how
== SIG_SETMASK
5082 && sigismember (&new_mask
, signo
)
5083 && !sigismember (new_set
, signo
)))
5085 sigdelset (&new_mask
, signo
);
5086 if (prev_handlers
[signo
] != SIG_ERR
)
5088 signal (signo
, prev_handlers
[signo
]);
5089 prev_handlers
[signo
] = SIG_ERR
;
5091 if (sigismember (&pending_signals
, signo
))
5093 sigdelset (&pending_signals
, signo
);
5098 current_mask
= new_mask
;
5102 #else /* not POSIX_SIGNALS */
5104 sigsetmask (x
) int x
; { return 0; }
5105 sigblock (mask
) int mask
; { return 0; }
5107 #endif /* not POSIX_SIGNALS */
5108 #endif /* __DJGPP__ > 1 */
5111 #include "sysselect.h"
5113 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5114 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5115 ((long)(time).tv_sec < 0 \
5116 || ((time).tv_sec == 0 \
5117 && (long)(time).tv_usec <= 0))
5120 /* This yields the rest of the current time slice to the task manager.
5121 It should be called by any code which knows that it has nothing
5122 useful to do except idle.
5124 I don't use __dpmi_yield here, since versions of library before 2.02
5125 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5126 on some versions of Windows 9X. */
5129 dos_yield_time_slice (void)
5131 _go32_dpmi_registers r
;
5134 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
5135 _go32_dpmi_simulate_int (0x2f, &r
);
5140 /* Only event queue is checked. */
5141 /* We don't have to call timer_check here
5142 because wait_reading_process_input takes care of that. */
5144 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5146 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5147 EMACS_TIME
*timeout
;
5155 check_input
= FD_ISSET (0, rfds
);
5166 /* If we are looking only for the terminal, with no timeout,
5167 just read it and wait -- that's more efficient. */
5170 while (!detect_input_pending ())
5172 dos_yield_time_slice ();
5177 EMACS_TIME clnow
, cllast
, cldiff
;
5180 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5182 while (!check_input
|| !detect_input_pending ())
5185 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5186 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5188 /* When seconds wrap around, we assume that no more than
5189 1 minute passed since last `gettime'. */
5190 if (EMACS_TIME_NEG_P (cldiff
))
5191 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5192 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5194 /* Stop when timeout value crosses zero. */
5195 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5198 dos_yield_time_slice ();
5208 * Define overlaid functions:
5210 * chdir -> sys_chdir
5211 * tzset -> init_gettimeofday
5212 * abort -> dos_abort
5217 extern int chdir ();
5223 int len
= strlen (path
);
5224 char *tmp
= (char *)path
;
5226 if (*tmp
&& tmp
[1] == ':')
5228 if (getdisk () != tolower (tmp
[0]) - 'a')
5229 setdisk (tolower (tmp
[0]) - 'a');
5230 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5234 if (len
> 1 && (tmp
[len
- 1] == '/'))
5236 char *tmp1
= (char *) alloca (len
+ 1);
5247 extern void tzset (void);
5250 init_gettimeofday ()
5256 ltm
= gtm
= time (NULL
);
5257 ltm
= mktime (lstm
= localtime (<m
));
5258 gtm
= mktime (gmtime (>m
));
5259 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5260 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5261 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5268 dos_abort (file
, line
)
5272 char buffer1
[200], buffer2
[400];
5275 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5276 for (i
= j
= 0; buffer1
[i
]; i
++) {
5277 buffer2
[j
++] = buffer1
[i
];
5278 buffer2
[j
++] = 0x70;
5280 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5281 ScreenSetCursor (2, 0);
5289 ScreenSetCursor (10, 0);
5290 cputs ("\r\n\nEmacs aborted!\r\n");
5292 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5293 if (screen_virtual_segment
)
5294 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5295 /* Generate traceback, so we could tell whodunit. */
5296 signal (SIGINT
, SIG_DFL
);
5297 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5298 #else /* __DJGPP_MINOR__ >= 2 */
5300 #endif /* __DJGPP_MINOR__ >= 2 */
5306 /* The following variables are required so that cus-start.el won't
5307 complain about unbound variables. */
5308 #ifndef HAVE_X_WINDOWS
5309 /* Search path for bitmap files (xfns.c). */
5310 Lisp_Object Vx_bitmap_file_path
;
5311 int x_stretch_cursor_p
;
5313 #ifndef subprocesses
5314 /* Nonzero means delete a process right away if it exits (process.c). */
5315 static int delete_exited_processes
;
5320 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5321 staticpro (&recent_doskeys
);
5322 #ifndef HAVE_X_WINDOWS
5324 staticpro (&help_echo
);
5325 help_echo_object
= Qnil
;
5326 staticpro (&help_echo_object
);
5327 help_echo_window
= Qnil
;
5328 staticpro (&help_echo_window
);
5329 previous_help_echo
= Qnil
;
5330 staticpro (&previous_help_echo
);
5333 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
5334 "List of directories to search for bitmap files for X.");
5335 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
5337 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p
,
5338 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5339 For example, if a block cursor is over a tab, it will be drawn as\n\
5340 wide as that tab on the display. (No effect on MS-DOS.)");
5341 x_stretch_cursor_p
= 0;
5343 /* The following two are from xfns.c: */
5344 Qbar
= intern ("bar");
5346 Qcursor_type
= intern ("cursor-type");
5347 staticpro (&Qcursor_type
);
5348 Qreverse
= intern ("reverse");
5349 staticpro (&Qreverse
);
5351 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5352 "*Glyph to display instead of chars not supported by current codepage.\n\
5354 This variable is used only by MSDOS terminals.");
5355 Vdos_unsupported_char_glyph
= '\177';
5357 #ifndef subprocesses
5358 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5359 "*Non-nil means delete processes immediately when they exit.\n\
5360 nil means don't delete them until `list-processes' is run.");
5361 delete_exited_processes
= 0;
5364 defsubr (&Srecent_doskeys
);
5365 defsubr (&Smsdos_long_file_names
);
5366 defsubr (&Smsdos_downcase_filename
);
5367 defsubr (&Smsdos_remember_default_colors
);
5368 defsubr (&Smsdos_set_mouse_buttons
);