Minor NEWS fix.
[emacs.git] / src / msdos.c
blob086cad2ff84889db4b2b49e6309bcc70040ba294
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26 #include <config.h>
28 #ifdef MSDOS
29 #include <setjmp.h>
30 #include "lisp.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <sys/param.h>
35 #include <sys/time.h>
36 #include <dos.h>
37 #include <errno.h>
38 #include <string.h> /* for memset and string functions */
39 #include <sys/stat.h> /* for _fixpath */
40 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #include <dir.h> /* for getdisk */
42 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
43 #include <fcntl.h>
44 #include <io.h> /* for setmode */
45 #include <dpmi.h> /* for __dpmi_xxx stuff */
46 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
47 #include <libc/dosio.h> /* for _USE_LFN */
48 #include <conio.h> /* for cputs */
50 #include "msdos.h"
51 #include "systime.h"
52 #include "frame.h"
53 #include "termhooks.h"
54 #include "termchar.h"
55 #include "dispextern.h"
56 #include "dosfns.h"
57 #include "termopts.h"
58 #include "character.h"
59 #include "coding.h"
60 #include "disptab.h"
61 #include "window.h"
62 #include "buffer.h"
63 #include "commands.h"
64 #include "blockinput.h"
65 #include "keyboard.h"
66 #include "intervals.h"
67 #include <go32.h>
68 #include <pc.h>
69 #include <ctype.h>
70 /* #include <process.h> */
71 /* Damn that local process.h! Instead we can define P_WAIT and
72 spawnve ourselves. */
73 #define P_WAIT 1
74 extern int spawnve (int, const char *, char *const [], char *const []);
76 #ifndef _USE_LFN
77 #define _USE_LFN 0
78 #endif
80 #ifndef _dos_ds
81 #define _dos_ds _go32_info_block.selector_for_linear_memory
82 #endif
84 #include <signal.h>
85 #include "syssignal.h"
87 #ifndef SYSTEM_MALLOC
89 #ifdef GNU_MALLOC
91 /* If other `malloc' than ours is used, force our `sbrk' behave like
92 Unix programs expect (resize memory blocks to keep them contiguous).
93 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
94 because that's what `gmalloc' expects to get. */
95 #include <crt0.h>
97 #ifdef REL_ALLOC
98 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
99 #else /* not REL_ALLOC */
100 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
101 #endif /* not REL_ALLOC */
102 #endif /* GNU_MALLOC */
104 #endif /* not SYSTEM_MALLOC */
106 static unsigned long
107 event_timestamp (void)
109 struct time t;
110 unsigned long s;
112 gettime (&t);
113 s = t.ti_min;
114 s *= 60;
115 s += t.ti_sec;
116 s *= 1000;
117 s += t.ti_hund * 10;
119 return s;
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;
142 void
143 mouse_on (void)
145 union REGS regs;
147 if (have_mouse > 0 && !mouse_visible)
149 struct tty_display_info *tty = CURTTY ();
151 if (tty->termscript)
152 fprintf (tty->termscript, "<M_ON>");
153 regs.x.ax = 0x0001;
154 int86 (0x33, &regs, &regs);
155 mouse_visible = 1;
159 void
160 mouse_off (void)
162 union REGS regs;
164 if (have_mouse > 0 && mouse_visible)
166 struct tty_display_info *tty = CURTTY ();
168 if (tty->termscript)
169 fprintf (tty->termscript, "<M_OFF>");
170 regs.x.ax = 0x0002;
171 int86 (0x33, &regs, &regs);
172 mouse_visible = 0;
176 static void
177 mouse_setup_buttons (int n_buttons)
179 if (n_buttons == 3)
181 mouse_button_count = 3;
182 mouse_button_translate[0] = 0; /* Left */
183 mouse_button_translate[1] = 2; /* Middle */
184 mouse_button_translate[2] = 1; /* Right */
186 else /* two, what else? */
188 mouse_button_count = 2;
189 mouse_button_translate[0] = 0;
190 mouse_button_translate[1] = 1;
194 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
195 1, 1, "NSet number of mouse buttons to: ",
196 doc: /* Set the number of mouse buttons to use by Emacs.
197 This is useful with mice that report the number of buttons inconsistently,
198 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
199 them. This happens with wheeled mice on Windows 9X, for example. */)
200 (Lisp_Object nbuttons)
202 int n;
204 CHECK_NUMBER (nbuttons);
205 n = XINT (nbuttons);
206 if (n < 2 || n > 3)
207 xsignal2 (Qargs_out_of_range,
208 build_string ("only 2 or 3 mouse buttons are supported"),
209 nbuttons);
210 mouse_setup_buttons (n);
211 return Qnil;
214 static void
215 mouse_get_xy (int *x, int *y)
217 union REGS regs;
219 regs.x.ax = 0x0003;
220 int86 (0x33, &regs, &regs);
221 *x = regs.x.cx / 8;
222 *y = regs.x.dx / 8;
225 void
226 mouse_moveto (int x, int y)
228 union REGS regs;
229 struct tty_display_info *tty = CURTTY ();
231 if (tty->termscript)
232 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
233 regs.x.ax = 0x0004;
234 mouse_last_x = regs.x.cx = x * 8;
235 mouse_last_y = regs.x.dx = y * 8;
236 int86 (0x33, &regs, &regs);
239 static int
240 mouse_pressed (int b, int *xp, int *yp)
242 union REGS regs;
244 if (b >= mouse_button_count)
245 return 0;
246 regs.x.ax = 0x0005;
247 regs.x.bx = mouse_button_translate[b];
248 int86 (0x33, &regs, &regs);
249 if (regs.x.bx)
250 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
251 return (regs.x.bx != 0);
254 static int
255 mouse_released (int b, int *xp, int *yp)
257 union REGS regs;
259 if (b >= mouse_button_count)
260 return 0;
261 regs.x.ax = 0x0006;
262 regs.x.bx = mouse_button_translate[b];
263 int86 (0x33, &regs, &regs);
264 if (regs.x.bx)
265 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
266 return (regs.x.bx != 0);
269 static int
270 mouse_button_depressed (int b, int *xp, int *yp)
272 union REGS regs;
274 if (b >= mouse_button_count)
275 return 0;
276 regs.x.ax = 0x0003;
277 int86 (0x33, &regs, &regs);
278 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
280 *xp = regs.x.cx / 8;
281 *yp = regs.x.dx / 8;
282 return 1;
284 return 0;
287 void
288 mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
289 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
290 unsigned long *time)
292 int ix, iy;
293 Lisp_Object frame, tail;
295 /* Clear the mouse-moved flag for every frame on this display. */
296 FOR_EACH_FRAME (tail, frame)
297 XFRAME (frame)->mouse_moved = 0;
299 *f = SELECTED_FRAME();
300 *bar_window = Qnil;
301 mouse_get_xy (&ix, &iy);
302 *time = event_timestamp ();
303 *x = make_number (mouse_last_x = ix);
304 *y = make_number (mouse_last_y = iy);
307 static void
308 mouse_check_moved (void)
310 int x, y;
312 mouse_get_xy (&x, &y);
313 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
314 mouse_last_x = x;
315 mouse_last_y = y;
318 /* Force the mouse driver to ``forget'' about any button clicks until
319 now. */
320 static void
321 mouse_clear_clicks (void)
323 int b;
325 for (b = 0; b < mouse_button_count; b++)
327 int dummy_x, dummy_y;
329 (void) mouse_pressed (b, &dummy_x, &dummy_y);
330 (void) mouse_released (b, &dummy_x, &dummy_y);
334 void
335 mouse_init (void)
337 union REGS regs;
338 struct tty_display_info *tty = CURTTY ();
340 if (tty->termscript)
341 fprintf (tty->termscript, "<M_INIT>");
343 regs.x.ax = 0x0021;
344 int86 (0x33, &regs, &regs);
346 /* Reset the mouse last press/release info. It seems that Windows
347 doesn't do that automatically when function 21h is called, which
348 causes Emacs to ``remember'' the click that switched focus to the
349 window just before Emacs was started from that window. */
350 mouse_clear_clicks ();
352 regs.x.ax = 0x0007;
353 regs.x.cx = 0;
354 regs.x.dx = 8 * (ScreenCols () - 1);
355 int86 (0x33, &regs, &regs);
357 regs.x.ax = 0x0008;
358 regs.x.cx = 0;
359 regs.x.dx = 8 * (ScreenRows () - 1);
360 int86 (0x33, &regs, &regs);
362 mouse_moveto (0, 0);
363 mouse_visible = 0;
366 /* ------------------------- Screen control ----------------------
370 static int internal_terminal = 0;
372 #ifndef HAVE_X_WINDOWS
373 extern unsigned char ScreenAttrib;
374 static int screen_face;
376 static int screen_size_X;
377 static int screen_size_Y;
378 static int screen_size;
380 static int current_pos_X;
381 static int current_pos_Y;
382 static int new_pos_X;
383 static int new_pos_Y;
385 static void *startup_screen_buffer;
386 static int startup_screen_size_X;
387 static int startup_screen_size_Y;
388 static int startup_pos_X;
389 static int startup_pos_Y;
390 static unsigned char startup_screen_attrib;
392 static clock_t startup_time;
394 static int term_setup_done;
396 static unsigned short outside_cursor;
398 /* Similar to the_only_frame. */
399 struct tty_display_info the_only_display_info;
401 /* Support for DOS/V (allows Japanese characters to be displayed on
402 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
404 /* Holds the address of the text-mode screen buffer. */
405 static unsigned long screen_old_address = 0;
406 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
407 static unsigned short screen_virtual_segment = 0;
408 static unsigned short screen_virtual_offset = 0;
409 /* A flag to control how to display unibyte 8-bit characters. */
410 extern int unibyte_display_via_language_environment;
412 extern Lisp_Object Qcursor_type;
413 extern Lisp_Object Qbar, Qhbar;
415 /* The screen colors of the current frame, which serve as the default
416 colors for newly-created frames. */
417 static int initial_screen_colors[2];
419 /* Update the screen from a part of relocated DOS/V screen buffer which
420 begins at OFFSET and includes COUNT characters. */
421 static void
422 dosv_refresh_virtual_screen (int offset, int count)
424 __dpmi_regs regs;
426 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
427 return;
429 regs.h.ah = 0xff; /* update relocated screen */
430 regs.x.es = screen_virtual_segment;
431 regs.x.di = screen_virtual_offset + offset;
432 regs.x.cx = count;
433 __dpmi_int (0x10, &regs);
436 static void
437 dos_direct_output (int y, int x, char *buf, int len)
439 int t0 = 2 * (x + y * screen_size_X);
440 int t = t0 + (int) ScreenPrimary;
441 int l0 = len;
443 /* This is faster. */
444 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
445 _farnspokeb (t, *buf);
447 if (screen_virtual_segment)
448 dosv_refresh_virtual_screen (t0, l0);
450 #endif
452 #ifndef HAVE_X_WINDOWS
454 static int blink_bit = -1; /* the state of the blink bit at startup */
456 /* Enable bright background colors. */
457 static void
458 bright_bg (void)
460 union REGS regs;
462 /* Remember the original state of the blink/bright-background bit.
463 It is stored at 0040:0065h in the BIOS data area. */
464 if (blink_bit == -1)
465 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
467 regs.h.bl = 0;
468 regs.x.ax = 0x1003;
469 int86 (0x10, &regs, &regs);
472 /* Disable bright background colors (and enable blinking) if we found
473 the video system in that state at startup. */
474 static void
475 maybe_enable_blinking (void)
477 if (blink_bit == 1)
479 union REGS regs;
481 regs.h.bl = 1;
482 regs.x.ax = 0x1003;
483 int86 (0x10, &regs, &regs);
487 /* Return non-zero if the system has a VGA adapter. */
488 static int
489 vga_installed (void)
491 union REGS regs;
493 regs.x.ax = 0x1a00;
494 int86 (0x10, &regs, &regs);
495 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
496 return 1;
497 return 0;
500 /* Set the screen dimensions so that it can show no less than
501 ROWS x COLS frame. */
503 void
504 dos_set_window_size (int *rows, int *cols)
506 char video_name[30];
507 union REGS regs;
508 Lisp_Object video_mode;
509 int video_mode_value, have_vga = 0;
510 int current_rows = ScreenRows (), current_cols = ScreenCols ();
512 if (*rows == current_rows && *cols == current_cols)
513 return;
515 mouse_off ();
516 have_vga = vga_installed ();
518 /* If the user specified a special video mode for these dimensions,
519 use that mode. */
520 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
521 video_mode = Fsymbol_value (Fintern_soft (build_string (video_name), Qnil));
523 if (INTEGERP (video_mode)
524 && (video_mode_value = XINT (video_mode)) > 0)
526 regs.x.ax = video_mode_value;
527 int86 (0x10, &regs, &regs);
529 if (have_mouse)
531 /* Must hardware-reset the mouse, or else it won't update
532 its notion of screen dimensions for some non-standard
533 video modes. This is *painfully* slow... */
534 regs.x.ax = 0;
535 int86 (0x33, &regs, &regs);
539 /* Find one of the dimensions supported by standard EGA/VGA
540 which gives us at least the required dimensions. */
541 else
543 static struct {
544 int rows, need_vga;
545 } std_dimension[] = {
546 {25, 0},
547 {28, 1},
548 {35, 0},
549 {40, 1},
550 {43, 0},
551 {50, 1}
553 int i = 0;
555 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
557 if (std_dimension[i].need_vga <= have_vga
558 && std_dimension[i].rows >= *rows)
560 if (std_dimension[i].rows != current_rows
561 || *cols != current_cols)
562 _set_screen_lines (std_dimension[i].rows);
563 break;
565 i++;
570 if (have_mouse)
572 mouse_init ();
573 mouse_on ();
576 /* Tell the caller what dimensions have been REALLY set. */
577 *rows = ScreenRows ();
578 *cols = ScreenCols ();
580 /* Update Emacs' notion of screen dimensions. */
581 screen_size_X = *cols;
582 screen_size_Y = *rows;
583 screen_size = *cols * *rows;
585 /* If the dimensions changed, the mouse highlight info is invalid. */
586 if (current_rows != *rows || current_cols != *cols)
588 struct frame *f = SELECTED_FRAME();
589 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
590 Lisp_Object window = dpyinfo->mouse_face_window;
592 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
594 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
595 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
596 dpyinfo->mouse_face_window = Qnil;
600 /* Enable bright background colors. */
601 bright_bg ();
603 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
604 be defensive anyway. */
605 if (screen_virtual_segment)
606 dosv_refresh_virtual_screen (0, *cols * *rows);
609 /* If we write a character in the position where the mouse is,
610 the mouse cursor may need to be refreshed. */
612 static void
613 mouse_off_maybe (void)
615 int x, y;
617 if (!mouse_visible)
618 return;
620 mouse_get_xy (&x, &y);
621 if (y != new_pos_Y || x < new_pos_X)
622 return;
624 mouse_off ();
627 #define DEFAULT_CURSOR_START (-1)
628 #define DEFAULT_CURSOR_WIDTH (-1)
629 #define BOX_CURSOR_WIDTH (-32)
631 /* Set cursor to begin at scan line START_LINE in the character cell
632 and extend for WIDTH scan lines. Scan lines are counted from top
633 of the character cell, starting from zero. */
634 static void
635 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
637 unsigned desired_cursor;
638 __dpmi_regs regs;
639 int max_line, top_line, bot_line;
640 struct tty_display_info *tty = FRAME_TTY (f);
642 /* Avoid the costly BIOS call if F isn't the currently selected
643 frame. Allow for NULL as unconditionally meaning the selected
644 frame. */
645 if (f && f != SELECTED_FRAME())
646 return;
648 if (tty->termscript)
649 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
651 /* The character cell size in scan lines is stored at 40:85 in the
652 BIOS data area. */
653 max_line = _farpeekw (_dos_ds, 0x485) - 1;
654 switch (max_line)
656 default: /* this relies on CGA cursor emulation being ON! */
657 case 7:
658 bot_line = 7;
659 break;
660 case 9:
661 bot_line = 9;
662 break;
663 case 13:
664 bot_line = 12;
665 break;
666 case 15:
667 bot_line = 14;
668 break;
671 if (width < 0)
673 if (width == BOX_CURSOR_WIDTH)
675 top_line = 0;
676 bot_line = max_line;
678 else if (start_line != DEFAULT_CURSOR_START)
680 top_line = start_line;
681 bot_line = top_line - width - 1;
683 else if (width != DEFAULT_CURSOR_WIDTH)
685 top_line = 0;
686 bot_line = -1 - width;
688 else
689 top_line = bot_line + 1;
691 else if (width == 0)
693 /* [31, 0] seems to DTRT for all screen sizes. */
694 top_line = 31;
695 bot_line = 0;
697 else /* WIDTH is positive */
699 if (start_line != DEFAULT_CURSOR_START)
700 bot_line = start_line;
701 top_line = bot_line - (width - 1);
704 /* If the current cursor shape is already what they want, we are
705 history here. */
706 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
707 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
708 return;
710 regs.h.ah = 1;
711 regs.x.cx = desired_cursor;
712 __dpmi_int (0x10, &regs);
715 static void
716 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
718 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
720 /* Just BAR means the normal EGA/VGA cursor. */
721 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
723 else if (CONSP (cursor_type)
724 && (EQ (XCAR (cursor_type), Qbar)
725 || EQ (XCAR (cursor_type), Qhbar)))
727 Lisp_Object bar_parms = XCDR (cursor_type);
728 int width;
730 if (INTEGERP (bar_parms))
732 /* Feature: negative WIDTH means cursor at the top
733 of the character cell, zero means invisible cursor. */
734 width = XINT (bar_parms);
735 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
736 width);
738 else if (CONSP (bar_parms)
739 && INTEGERP (XCAR (bar_parms))
740 && INTEGERP (XCDR (bar_parms)))
742 int start_line = XINT (XCDR (bar_parms));
744 width = XINT (XCAR (bar_parms));
745 msdos_set_cursor_shape (f, start_line, width);
748 else
750 /* Treat anything unknown as "box cursor". This includes nil, so
751 that a frame which doesn't specify a cursor type gets a box,
752 which is the default in Emacs. */
753 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
757 static void
758 IT_ring_bell (struct frame *f)
760 if (visible_bell)
762 mouse_off ();
763 ScreenVisualBell ();
765 else
767 union REGS inregs, outregs;
768 inregs.h.ah = 2;
769 inregs.h.dl = 7;
770 intdos (&inregs, &outregs);
774 /* Given a face id FACE, extract the face parameters to be used for
775 display until the face changes. The face parameters (actually, its
776 color) are used to construct the video attribute byte for each
777 glyph during the construction of the buffer that is then blitted to
778 the video RAM. */
779 static void
780 IT_set_face (int face)
782 struct frame *sf = SELECTED_FRAME();
783 struct face *fp = FACE_FROM_ID (sf, face);
784 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
785 unsigned long fg, bg, dflt_fg, dflt_bg;
786 struct tty_display_info *tty = FRAME_TTY (sf);
788 if (!fp)
790 fp = dfp;
791 /* The default face for the frame should always be realized and
792 cached. */
793 if (!fp)
794 abort ();
796 screen_face = face;
797 fg = fp->foreground;
798 bg = fp->background;
799 dflt_fg = dfp->foreground;
800 dflt_bg = dfp->background;
802 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
803 mean use the colors of the default face. Note that we assume all
804 16 colors to be available for the background, since Emacs switches
805 on this mode (and loses the blinking attribute) at startup. */
806 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
807 fg = FRAME_FOREGROUND_PIXEL (sf);
808 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
809 fg = FRAME_BACKGROUND_PIXEL (sf);
810 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
811 bg = FRAME_BACKGROUND_PIXEL (sf);
812 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
813 bg = FRAME_FOREGROUND_PIXEL (sf);
815 /* Make sure highlighted lines really stand out, come what may. */
816 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
818 unsigned long tem = fg;
820 fg = bg;
821 bg = tem;
823 /* If the user requested inverse video, obey. */
824 if (inverse_video)
826 unsigned long tem2 = fg;
828 fg = bg;
829 bg = tem2;
831 if (tty->termscript)
832 fprintf (tty->termscript, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face,
833 fp->foreground, fp->background, fg, bg);
834 if (fg >= 0 && fg < 16)
836 ScreenAttrib &= 0xf0;
837 ScreenAttrib |= fg;
839 if (bg >= 0 && bg < 16)
841 ScreenAttrib &= 0x0f;
842 ScreenAttrib |= ((bg & 0x0f) << 4);
846 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
847 width of a DOS display in any known text mode. We multiply by 2 to
848 accomodate the screen attribute byte. */
849 #define MAX_SCREEN_BUF 160*2
851 Lisp_Object Vdos_unsupported_char_glyph;
852 extern unsigned char *encode_terminal_code (struct glyph *, int,
853 struct coding_system *);
854 static void
855 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
857 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
858 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
859 register int sl = str_len;
860 struct tty_display_info *tty = FRAME_TTY (f);
861 struct frame *sf;
862 unsigned char *conversion_buffer;
864 /* If terminal_coding does any conversion, use it, otherwise use
865 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
866 because it always returns 1 if terminal_coding.src_multibyte is 1. */
867 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
869 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
870 coding = &safe_terminal_coding;
872 if (str_len <= 0) return;
874 sf = SELECTED_FRAME();
876 /* Since faces get cached and uncached behind our back, we can't
877 rely on their indices in the cache being consistent across
878 invocations. So always reset the screen face to the default
879 face of the frame, before writing glyphs, and let the glyphs
880 set the right face if it's different from the default. */
881 IT_set_face (DEFAULT_FACE_ID);
883 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
884 the tail. */
885 coding->mode &= ~CODING_MODE_LAST_BLOCK;
886 screen_bp = &screen_buf[0];
887 while (sl > 0)
889 int cf;
890 int n;
892 /* If the face of this glyph is different from the current
893 screen face, update the screen attribute byte. */
894 cf = str->face_id;
895 if (cf != screen_face)
896 IT_set_face (cf); /* handles invalid faces gracefully */
898 /* Identify a run of glyphs with the same face. */
899 for (n = 1; n < sl; ++n)
900 if (str[n].face_id != cf)
901 break;
903 if (n >= sl)
904 /* This is the last glyph. */
905 coding->mode |= CODING_MODE_LAST_BLOCK;
907 conversion_buffer = encode_terminal_code (str, n, coding);
908 if (coding->produced > 0)
910 /* Copy the encoded bytes to the screen buffer. */
911 for (bp = conversion_buffer; coding->produced--; bp++)
913 /* Paranoia: discard bytes that would overrun the end of
914 the screen buffer. */
915 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
917 *screen_bp++ = (unsigned char)*bp;
918 *screen_bp++ = ScreenAttrib;
920 if (tty->termscript)
921 fputc (*bp, tty->termscript);
924 /* Update STR and its remaining length. */
925 str += n;
926 sl -= n;
929 /* Dump whatever we have in the screen buffer. */
930 mouse_off_maybe ();
931 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
932 if (screen_virtual_segment)
933 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
934 new_pos_X += (screen_bp - screen_buf) / 2;
937 /************************************************************************
938 Mouse Highlight (and friends..)
939 ************************************************************************/
941 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
942 static Lisp_Object last_mouse_window;
944 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
946 /* Set the mouse pointer shape according to whether it is in the
947 area where the mouse highlight is in effect. */
948 static void
949 IT_set_mouse_pointer (int mode)
951 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
952 many possibilities to change its shape, and the available
953 functionality pretty much sucks (e.g., almost every reasonable
954 shape will conceal the character it is on). Since the color of
955 the pointer changes in the highlighted area, it is not clear to
956 me whether anything else is required, anyway. */
959 /* Display the active region described by mouse_face_*
960 in its mouse-face if HL > 0, in its normal face if HL = 0. */
961 static void
962 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
964 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
965 struct frame *f = XFRAME (WINDOW_FRAME (w));
966 int i;
967 struct face *fp;
968 struct tty_display_info *tty = FRAME_TTY (f);
971 /* If window is in the process of being destroyed, don't bother
972 doing anything. */
973 if (w->current_matrix == NULL)
974 goto set_cursor_shape;
976 /* Recognize when we are called to operate on rows that don't exist
977 anymore. This can happen when a window is split. */
978 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
979 goto set_cursor_shape;
981 /* There's no sense to do anything if the mouse face isn't realized. */
982 if (hl > 0)
984 if (dpyinfo->mouse_face_hidden)
985 goto set_cursor_shape;
987 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
988 if (!fp)
989 goto set_cursor_shape;
992 /* Note that mouse_face_beg_row etc. are window relative. */
993 for (i = dpyinfo->mouse_face_beg_row;
994 i <= dpyinfo->mouse_face_end_row;
995 i++)
997 int start_hpos, end_hpos;
998 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1000 /* Don't do anything if row doesn't have valid contents. */
1001 if (!row->enabled_p)
1002 continue;
1004 /* For all but the first row, the highlight starts at column 0. */
1005 if (i == dpyinfo->mouse_face_beg_row)
1006 start_hpos = dpyinfo->mouse_face_beg_col;
1007 else
1008 start_hpos = 0;
1010 if (i == dpyinfo->mouse_face_end_row)
1011 end_hpos = dpyinfo->mouse_face_end_col;
1012 else
1013 end_hpos = row->used[TEXT_AREA];
1015 if (end_hpos <= start_hpos)
1016 continue;
1017 /* Record that some glyphs of this row are displayed in
1018 mouse-face. */
1019 row->mouse_face_p = hl > 0;
1020 if (hl > 0)
1022 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1023 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1024 int nglyphs = end_hpos - start_hpos;
1025 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1026 int start_offset = offset;
1028 if (tty->termscript)
1029 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1030 kstart, kstart + nglyphs - 1, vpos);
1032 mouse_off ();
1033 IT_set_face (dpyinfo->mouse_face_face_id);
1034 /* Since we are going to change only the _colors_ of the
1035 displayed text, there's no need to go through all the
1036 pain of generating and encoding the text from the glyphs.
1037 Instead, we simply poke the attribute byte of each
1038 affected position in video memory with the colors
1039 computed by IT_set_face! */
1040 _farsetsel (_dos_ds);
1041 while (nglyphs--)
1043 _farnspokeb (offset, ScreenAttrib);
1044 offset += 2;
1046 if (screen_virtual_segment)
1047 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1048 mouse_on ();
1050 else
1052 /* We are removing a previously-drawn mouse highlight. The
1053 safest way to do so is to redraw the glyphs anew, since
1054 all kinds of faces and display tables could have changed
1055 behind our back. */
1056 int nglyphs = end_hpos - start_hpos;
1057 int save_x = new_pos_X, save_y = new_pos_Y;
1059 if (end_hpos >= row->used[TEXT_AREA])
1060 nglyphs = row->used[TEXT_AREA] - start_hpos;
1062 /* IT_write_glyphs writes at cursor position, so we need to
1063 temporarily move cursor coordinates to the beginning of
1064 the highlight region. */
1065 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1066 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1068 if (tty->termscript)
1069 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1070 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1071 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1072 if (tty->termscript)
1073 fputs ("\n", tty->termscript);
1074 new_pos_X = save_x;
1075 new_pos_Y = save_y;
1079 set_cursor_shape:
1080 /* Change the mouse pointer shape. */
1081 IT_set_mouse_pointer (hl);
1084 /* Clear out the mouse-highlighted active region.
1085 Redraw it un-highlighted first. */
1086 static void
1087 clear_mouse_face (struct tty_display_info *dpyinfo)
1089 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1090 show_mouse_face (dpyinfo, 0);
1092 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1093 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1094 dpyinfo->mouse_face_window = Qnil;
1097 /* Find the glyph matrix position of buffer position POS in window W.
1098 *HPOS and *VPOS are set to the positions found. W's current glyphs
1099 must be up to date. If POS is above window start return (0, 0).
1100 If POS is after end of W, return end of last line in W. */
1101 static int
1102 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1104 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1105 int yb = window_text_bottom_y (w);
1106 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1108 while (row->y < yb)
1110 if (row->used[TEXT_AREA])
1111 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1112 else
1113 line_start_position = 0;
1115 if (line_start_position > pos)
1116 break;
1117 /* If the position sought is the end of the buffer,
1118 don't include the blank lines at the bottom of the window. */
1119 else if (line_start_position == pos
1120 && pos == BUF_ZV (XBUFFER (w->buffer)))
1122 maybe_next_line_p = 1;
1123 break;
1125 else if (line_start_position > 0)
1126 best_row = row;
1128 /* Don't overstep the last matrix row, lest we get into the
1129 never-never land... */
1130 if (row->y + 1 >= yb)
1131 break;
1133 ++row;
1136 /* Find the right column within BEST_ROW. */
1137 lastcol = 0;
1138 row = best_row;
1139 for (i = 0; i < row->used[TEXT_AREA]; i++)
1141 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1142 int charpos;
1144 charpos = glyph->charpos;
1145 if (charpos == pos)
1147 *hpos = i;
1148 *vpos = row->y;
1149 return 1;
1151 else if (charpos > pos)
1152 break;
1153 else if (charpos > 0)
1154 lastcol = i;
1157 /* If we're looking for the end of the buffer,
1158 and we didn't find it in the line we scanned,
1159 use the start of the following line. */
1160 if (maybe_next_line_p)
1162 ++row;
1163 lastcol = 0;
1166 *vpos = row->y;
1167 *hpos = lastcol + 1;
1168 return 0;
1171 /* Take proper action when mouse has moved to the mode or top line of
1172 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1173 mode line. X is relative to the start of the text display area of
1174 W, so the width of fringes and scroll bars must be subtracted
1175 to get a position relative to the start of the mode line. */
1176 static void
1177 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1179 struct glyph_row *row;
1181 if (mode_line_p)
1182 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1183 else
1184 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1186 if (row->enabled_p)
1188 struct glyph *glyph, *end;
1189 Lisp_Object help;
1191 /* Find the glyph under X. */
1192 glyph = (row->glyphs[TEXT_AREA]
1194 /* in case someone implements scroll bars some day... */
1195 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1196 end = glyph + row->used[TEXT_AREA];
1197 if (glyph < end
1198 && STRINGP (glyph->object)
1199 && STRING_INTERVALS (glyph->object)
1200 && glyph->charpos >= 0
1201 && glyph->charpos < SCHARS (glyph->object))
1203 /* If we're on a string with `help-echo' text property,
1204 arrange for the help to be displayed. This is done by
1205 setting the global variable help_echo to the help string. */
1206 help = Fget_text_property (make_number (glyph->charpos),
1207 Qhelp_echo, glyph->object);
1208 if (!NILP (help))
1210 help_echo_string = help;
1211 XSETWINDOW (help_echo_window, w);
1212 help_echo_object = glyph->object;
1213 help_echo_pos = glyph->charpos;
1219 /* Take proper action when the mouse has moved to position X, Y on
1220 frame F as regards highlighting characters that have mouse-face
1221 properties. Also de-highlighting chars where the mouse was before.
1222 X and Y can be negative or out of range. */
1223 static void
1224 IT_note_mouse_highlight (struct frame *f, int x, int y)
1226 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1227 enum window_part part = ON_NOTHING;
1228 Lisp_Object window;
1229 struct window *w;
1231 /* When a menu is active, don't highlight because this looks odd. */
1232 if (mouse_preempted)
1233 return;
1235 if (NILP (Vmouse_highlight)
1236 || !f->glyphs_initialized_p)
1237 return;
1239 dpyinfo->mouse_face_mouse_x = x;
1240 dpyinfo->mouse_face_mouse_y = y;
1241 dpyinfo->mouse_face_mouse_frame = f;
1243 if (dpyinfo->mouse_face_defer)
1244 return;
1246 if (gc_in_progress)
1248 dpyinfo->mouse_face_deferred_gc = 1;
1249 return;
1252 /* Which window is that in? */
1253 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1255 /* If we were displaying active text in another window, clear that. */
1256 if (! EQ (window, dpyinfo->mouse_face_window))
1257 clear_mouse_face (dpyinfo);
1259 /* Not on a window -> return. */
1260 if (!WINDOWP (window))
1261 return;
1263 /* Convert to window-relative coordinates. */
1264 w = XWINDOW (window);
1266 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1268 /* Mouse is on the mode or top line. */
1269 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1270 return;
1273 IT_set_mouse_pointer (0);
1275 /* Are we in a window whose display is up to date?
1276 And verify the buffer's text has not changed. */
1277 if (part == ON_TEXT
1278 && EQ (w->window_end_valid, w->buffer)
1279 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1280 && (XFASTINT (w->last_overlay_modified)
1281 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1283 int pos, i, nrows = w->current_matrix->nrows;
1284 struct glyph_row *row;
1285 struct glyph *glyph;
1287 /* Find the glyph under X/Y. */
1288 glyph = NULL;
1289 if (y >= 0 && y < nrows)
1291 row = MATRIX_ROW (w->current_matrix, y);
1292 /* Give up if some row before the one we are looking for is
1293 not enabled. */
1294 for (i = 0; i <= y; i++)
1295 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1296 break;
1297 if (i > y /* all rows upto and including the one at Y are enabled */
1298 && row->displays_text_p
1299 && x < window_box_width (w, TEXT_AREA))
1301 glyph = row->glyphs[TEXT_AREA];
1302 if (x >= row->used[TEXT_AREA])
1303 glyph = NULL;
1304 else
1306 glyph += x;
1307 if (!BUFFERP (glyph->object))
1308 glyph = NULL;
1313 /* Clear mouse face if X/Y not over text. */
1314 if (glyph == NULL)
1316 clear_mouse_face (dpyinfo);
1317 return;
1320 if (!BUFFERP (glyph->object))
1321 abort ();
1322 pos = glyph->charpos;
1324 /* Check for mouse-face and help-echo. */
1326 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1327 int noverlays, obegv, ozv;
1328 struct buffer *obuf;
1330 /* If we get an out-of-range value, return now; avoid an error. */
1331 if (pos > BUF_Z (XBUFFER (w->buffer)))
1332 return;
1334 /* Make the window's buffer temporarily current for
1335 overlays_at and compute_char_face. */
1336 obuf = current_buffer;
1337 current_buffer = XBUFFER (w->buffer);
1338 obegv = BEGV;
1339 ozv = ZV;
1340 BEGV = BEG;
1341 ZV = Z;
1343 /* Is this char mouse-active or does it have help-echo? */
1344 XSETINT (position, pos);
1346 /* Put all the overlays we want in a vector in overlay_vec. */
1347 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1348 /* Sort overlays into increasing priority order. */
1349 noverlays = sort_overlays (overlay_vec, noverlays, w);
1351 /* Check mouse-face highlighting. */
1352 if (! (EQ (window, dpyinfo->mouse_face_window)
1353 && y >= dpyinfo->mouse_face_beg_row
1354 && y <= dpyinfo->mouse_face_end_row
1355 && (y > dpyinfo->mouse_face_beg_row
1356 || x >= dpyinfo->mouse_face_beg_col)
1357 && (y < dpyinfo->mouse_face_end_row
1358 || x < dpyinfo->mouse_face_end_col
1359 || dpyinfo->mouse_face_past_end)))
1361 /* Clear the display of the old active region, if any. */
1362 clear_mouse_face (dpyinfo);
1364 /* Find highest priority overlay that has a mouse-face prop. */
1365 overlay = Qnil;
1366 for (i = noverlays - 1; i >= 0; --i)
1368 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1369 if (!NILP (mouse_face))
1371 overlay = overlay_vec[i];
1372 break;
1376 /* If no overlay applies, get a text property. */
1377 if (NILP (overlay))
1378 mouse_face = Fget_text_property (position, Qmouse_face,
1379 w->buffer);
1381 /* Handle the overlay case. */
1382 if (! NILP (overlay))
1384 /* Find the range of text around this char that
1385 should be active. */
1386 Lisp_Object before, after;
1387 EMACS_INT ignore;
1389 before = Foverlay_start (overlay);
1390 after = Foverlay_end (overlay);
1391 /* Record this as the current active region. */
1392 fast_find_position (w, XFASTINT (before),
1393 &dpyinfo->mouse_face_beg_col,
1394 &dpyinfo->mouse_face_beg_row);
1395 dpyinfo->mouse_face_past_end
1396 = !fast_find_position (w, XFASTINT (after),
1397 &dpyinfo->mouse_face_end_col,
1398 &dpyinfo->mouse_face_end_row);
1399 dpyinfo->mouse_face_window = window;
1400 dpyinfo->mouse_face_face_id
1401 = face_at_buffer_position (w, pos, 0, 0,
1402 &ignore, pos + 1,
1403 !dpyinfo->mouse_face_hidden,
1404 -1);
1406 /* Display it as active. */
1407 show_mouse_face (dpyinfo, 1);
1409 /* Handle the text property case. */
1410 else if (! NILP (mouse_face))
1412 /* Find the range of text around this char that
1413 should be active. */
1414 Lisp_Object before, after, beginning, end;
1415 EMACS_INT ignore;
1417 beginning = Fmarker_position (w->start);
1418 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1419 - XFASTINT (w->window_end_pos)));
1420 before
1421 = Fprevious_single_property_change (make_number (pos + 1),
1422 Qmouse_face,
1423 w->buffer, beginning);
1424 after
1425 = Fnext_single_property_change (position, Qmouse_face,
1426 w->buffer, end);
1427 /* Record this as the current active region. */
1428 fast_find_position (w, XFASTINT (before),
1429 &dpyinfo->mouse_face_beg_col,
1430 &dpyinfo->mouse_face_beg_row);
1431 dpyinfo->mouse_face_past_end
1432 = !fast_find_position (w, XFASTINT (after),
1433 &dpyinfo->mouse_face_end_col,
1434 &dpyinfo->mouse_face_end_row);
1435 dpyinfo->mouse_face_window = window;
1436 dpyinfo->mouse_face_face_id
1437 = face_at_buffer_position (w, pos, 0, 0,
1438 &ignore, pos + 1,
1439 !dpyinfo->mouse_face_hidden,
1440 -1);
1442 /* Display it as active. */
1443 show_mouse_face (dpyinfo, 1);
1447 /* Look for a `help-echo' property. */
1449 Lisp_Object help;
1451 /* Check overlays first. */
1452 help = Qnil;
1453 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1455 overlay = overlay_vec[i];
1456 help = Foverlay_get (overlay, Qhelp_echo);
1459 if (!NILP (help))
1461 help_echo_string = help;
1462 help_echo_window = window;
1463 help_echo_object = overlay;
1464 help_echo_pos = pos;
1466 /* Try text properties. */
1467 else if (NILP (help)
1468 && ((STRINGP (glyph->object)
1469 && glyph->charpos >= 0
1470 && glyph->charpos < SCHARS (glyph->object))
1471 || (BUFFERP (glyph->object)
1472 && glyph->charpos >= BEGV
1473 && glyph->charpos < ZV)))
1475 help = Fget_text_property (make_number (glyph->charpos),
1476 Qhelp_echo, glyph->object);
1477 if (!NILP (help))
1479 help_echo_string = help;
1480 help_echo_window = window;
1481 help_echo_object = glyph->object;
1482 help_echo_pos = glyph->charpos;
1487 BEGV = obegv;
1488 ZV = ozv;
1489 current_buffer = obuf;
1494 static void
1495 IT_clear_end_of_line (struct frame *f, int first_unused)
1497 char *spaces, *sp;
1498 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1499 extern int fatal_error_in_progress;
1500 struct tty_display_info *tty = FRAME_TTY (f);
1502 if (new_pos_X >= first_unused || fatal_error_in_progress)
1503 return;
1505 IT_set_face (0);
1506 i = (j = first_unused - new_pos_X) * 2;
1507 if (tty->termscript)
1508 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1509 spaces = sp = alloca (i);
1511 while (--j >= 0)
1513 *sp++ = ' ';
1514 *sp++ = ScreenAttrib;
1517 mouse_off_maybe ();
1518 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1519 if (screen_virtual_segment)
1520 dosv_refresh_virtual_screen (offset, i / 2);
1522 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1523 Let's follow their lead, in case someone relies on this. */
1524 new_pos_X = first_unused;
1527 static void
1528 IT_clear_screen (struct frame *f)
1530 struct tty_display_info *tty = FRAME_TTY (f);
1532 if (tty->termscript)
1533 fprintf (tty->termscript, "<CLR:SCR>");
1534 /* We are sometimes called (from clear_garbaged_frames) when a new
1535 frame is being created, but its faces are not yet realized. In
1536 such a case we cannot call IT_set_face, since it will fail to find
1537 any valid faces and will abort. Instead, use the initial screen
1538 colors; that should mimic what a Unix tty does, which simply clears
1539 the screen with whatever default colors are in use. */
1540 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1541 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1542 else
1543 IT_set_face (0);
1544 mouse_off ();
1545 ScreenClear ();
1546 if (screen_virtual_segment)
1547 dosv_refresh_virtual_screen (0, screen_size);
1548 new_pos_X = new_pos_Y = 0;
1551 static void
1552 IT_clear_to_end (struct frame *f)
1554 struct tty_display_info *tty = FRAME_TTY (f);
1556 if (tty->termscript)
1557 fprintf (tty->termscript, "<CLR:EOS>");
1559 while (new_pos_Y < screen_size_Y) {
1560 new_pos_X = 0;
1561 IT_clear_end_of_line (f, screen_size_X);
1562 new_pos_Y++;
1566 static void
1567 IT_cursor_to (struct frame *f, int y, int x)
1569 struct tty_display_info *tty = FRAME_TTY (f);
1571 if (tty->termscript)
1572 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1573 new_pos_X = x;
1574 new_pos_Y = y;
1577 static int cursor_cleared;
1579 static void
1580 IT_display_cursor (int on)
1582 struct tty_display_info *tty = CURTTY ();
1584 if (on && cursor_cleared)
1586 ScreenSetCursor (current_pos_Y, current_pos_X);
1587 cursor_cleared = 0;
1588 if (tty->termscript)
1589 fprintf (tty->termscript, "\nCURSOR ON (%dx%d)",
1590 current_pos_Y, current_pos_X);
1592 else if (!on && !cursor_cleared)
1594 ScreenSetCursor (-1, -1);
1595 cursor_cleared = 1;
1596 if (tty->termscript)
1597 fprintf (tty->termscript, "\nCURSOR OFF (%dx%d)",
1598 current_pos_Y, current_pos_X);
1602 /* Emacs calls cursor-movement functions a lot when it updates the
1603 display (probably a legacy of old terminals where you cannot
1604 update a screen line without first moving the cursor there).
1605 However, cursor movement is expensive on MSDOS (it calls a slow
1606 BIOS function and requires 2 mode switches), while actual screen
1607 updates access the video memory directly and don't depend on
1608 cursor position. To avoid slowing down the redisplay, we cheat:
1609 all functions that move the cursor only set internal variables
1610 which record the cursor position, whereas the cursor is only
1611 moved to its final position whenever screen update is complete.
1613 `IT_cmgoto' is called from the keyboard reading loop and when the
1614 frame update is complete. This means that we are ready for user
1615 input, so we update the cursor position to show where the point is,
1616 and also make the mouse pointer visible.
1618 Special treatment is required when the cursor is in the echo area,
1619 to put the cursor at the end of the text displayed there. */
1621 static void
1622 IT_cmgoto (FRAME_PTR f)
1624 /* Only set the cursor to where it should be if the display is
1625 already in sync with the window contents. */
1626 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1627 struct tty_display_info *tty = FRAME_TTY (f);
1629 /* FIXME: This needs to be rewritten for the new redisplay, or
1630 removed. */
1631 #if 0
1632 static int previous_pos_X = -1;
1634 update_cursor_pos = 1; /* temporary!!! */
1636 /* If the display is in sync, forget any previous knowledge about
1637 cursor position. This is primarily for unexpected events like
1638 C-g in the minibuffer. */
1639 if (update_cursor_pos && previous_pos_X >= 0)
1640 previous_pos_X = -1;
1641 /* If we are in the echo area, put the cursor at the
1642 end of the echo area message. */
1643 if (!update_cursor_pos
1644 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1646 int tem_X = current_pos_X, dummy;
1648 if (echo_area_glyphs)
1650 tem_X = echo_area_glyphs_length;
1651 /* Save current cursor position, to be restored after the
1652 echo area message is erased. Only remember one level
1653 of previous cursor position. */
1654 if (previous_pos_X == -1)
1655 ScreenGetCursor (&dummy, &previous_pos_X);
1657 else if (previous_pos_X >= 0)
1659 /* We wind up here after the echo area message is erased.
1660 Restore the cursor position we remembered above. */
1661 tem_X = previous_pos_X;
1662 previous_pos_X = -1;
1665 if (current_pos_X != tem_X)
1667 new_pos_X = tem_X;
1668 update_cursor_pos = 1;
1671 #endif
1673 if (update_cursor_pos
1674 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1676 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1677 if (tty->termscript)
1678 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1681 /* Maybe cursor is invisible, so make it visible. */
1682 IT_display_cursor (1);
1684 /* Mouse pointer should be always visible if we are waiting for
1685 keyboard input. */
1686 if (!mouse_visible)
1687 mouse_on ();
1690 static void
1691 IT_update_begin (struct frame *f)
1693 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1694 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1696 if (display_info->termscript)
1697 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1699 BLOCK_INPUT;
1701 if (f && f == mouse_face_frame)
1703 /* Don't do highlighting for mouse motion during the update. */
1704 display_info->mouse_face_defer = 1;
1706 /* If F needs to be redrawn, simply forget about any prior mouse
1707 highlighting. */
1708 if (FRAME_GARBAGED_P (f))
1709 display_info->mouse_face_window = Qnil;
1711 /* Can we tell that this update does not affect the window
1712 where the mouse highlight is? If so, no need to turn off.
1713 Likewise, don't do anything if none of the enabled rows
1714 contains glyphs highlighted in mouse face. */
1715 if (!NILP (display_info->mouse_face_window)
1716 && WINDOWP (display_info->mouse_face_window))
1718 struct window *w = XWINDOW (display_info->mouse_face_window);
1719 int i;
1721 /* If the mouse highlight is in the window that was deleted
1722 (e.g., if it was popped by completion), clear highlight
1723 unconditionally. */
1724 if (NILP (w->buffer))
1725 display_info->mouse_face_window = Qnil;
1726 else
1728 for (i = 0; i < w->desired_matrix->nrows; ++i)
1729 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1730 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1731 break;
1734 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1735 clear_mouse_face (display_info);
1738 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1740 /* If the frame with mouse highlight was deleted, invalidate the
1741 highlight info. */
1742 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1743 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1744 display_info->mouse_face_window = Qnil;
1745 display_info->mouse_face_deferred_gc = 0;
1746 display_info->mouse_face_mouse_frame = NULL;
1749 UNBLOCK_INPUT;
1752 static void
1753 IT_update_end (struct frame *f)
1755 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1757 if (dpyinfo->termscript)
1758 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1759 dpyinfo->mouse_face_defer = 0;
1762 static void
1763 IT_frame_up_to_date (struct frame *f)
1765 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1766 Lisp_Object new_cursor, frame_desired_cursor;
1767 struct window *sw;
1769 if (dpyinfo->mouse_face_deferred_gc
1770 || (f && f == dpyinfo->mouse_face_mouse_frame))
1772 BLOCK_INPUT;
1773 if (dpyinfo->mouse_face_mouse_frame)
1774 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1775 dpyinfo->mouse_face_mouse_x,
1776 dpyinfo->mouse_face_mouse_y);
1777 dpyinfo->mouse_face_deferred_gc = 0;
1778 UNBLOCK_INPUT;
1781 /* Set the cursor type to whatever they wanted. In a minibuffer
1782 window, we want the cursor to appear only if we are reading input
1783 from this window, and we want the cursor to be taken from the
1784 frame parameters. For the selected window, we use either its
1785 buffer-local value or the value from the frame parameters if the
1786 buffer doesn't define its local value for the cursor type. */
1787 sw = XWINDOW (f->selected_window);
1788 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1789 if (cursor_in_echo_area
1790 && FRAME_HAS_MINIBUF_P (f)
1791 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1792 && sw == XWINDOW (echo_area_window))
1793 new_cursor = frame_desired_cursor;
1794 else
1796 struct buffer *b = XBUFFER (sw->buffer);
1798 if (EQ (b->cursor_type, Qt))
1799 new_cursor = frame_desired_cursor;
1800 else if (NILP (b->cursor_type)) /* nil means no cursor */
1801 new_cursor = Fcons (Qbar, make_number (0));
1802 else
1803 new_cursor = b->cursor_type;
1806 IT_set_cursor_type (f, new_cursor);
1808 IT_cmgoto (f); /* position cursor when update is done */
1811 /* Copy LEN glyphs displayed on a single line whose vertical position
1812 is YPOS, beginning at horizontal position XFROM to horizontal
1813 position XTO, by moving blocks in the video memory. Used by
1814 functions that insert and delete glyphs. */
1815 static void
1816 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1818 /* The offsets of source and destination relative to the
1819 conventional memorty selector. */
1820 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1821 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1823 if (from == to || len <= 0)
1824 return;
1826 _farsetsel (_dos_ds);
1828 /* The source and destination might overlap, so we need to move
1829 glyphs non-destructively. */
1830 if (from > to)
1832 for ( ; len; from += 2, to += 2, len--)
1833 _farnspokew (to, _farnspeekw (from));
1835 else
1837 from += (len - 1) * 2;
1838 to += (len - 1) * 2;
1839 for ( ; len; from -= 2, to -= 2, len--)
1840 _farnspokew (to, _farnspeekw (from));
1842 if (screen_virtual_segment)
1843 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1846 /* Insert and delete glyphs. */
1847 static void
1848 IT_insert_glyphs (struct frame *f, struct glyph *start, int len)
1850 int shift_by_width = screen_size_X - (new_pos_X + len);
1852 /* Shift right the glyphs from the nominal cursor position to the
1853 end of this line. */
1854 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1856 /* Now write the glyphs to be inserted. */
1857 IT_write_glyphs (f, start, len);
1860 static void
1861 IT_delete_glyphs (struct frame *f, int n)
1863 abort ();
1866 /* set-window-configuration on window.c needs this. */
1867 void
1868 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1870 extern void set_menu_bar_lines (struct frame *, Lisp_Object, Lisp_Object);
1872 set_menu_bar_lines (f, value, oldval);
1875 /* This was copied from xfaces.c */
1877 extern Lisp_Object Qbackground_color;
1878 extern Lisp_Object Qforeground_color;
1879 Lisp_Object Qreverse;
1880 extern Lisp_Object Qtitle;
1882 /* IT_set_terminal_modes is called when emacs is started,
1883 resumed, and whenever the screen is redrawn! */
1885 static void
1886 IT_set_terminal_modes (struct terminal *term)
1888 struct tty_display_info *tty;
1890 /* If called with initial terminal, it's too early to do anything
1891 useful. */
1892 if (term->type == output_initial)
1893 return;
1895 tty = term->display_info.tty;
1897 if (tty->termscript)
1898 fprintf (tty->termscript, "\n<SET_TERM>");
1900 screen_size_X = ScreenCols ();
1901 screen_size_Y = ScreenRows ();
1902 screen_size = screen_size_X * screen_size_Y;
1904 new_pos_X = new_pos_Y = 0;
1905 current_pos_X = current_pos_Y = -1;
1907 if (term_setup_done)
1908 return;
1909 term_setup_done = 1;
1911 startup_screen_size_X = screen_size_X;
1912 startup_screen_size_Y = screen_size_Y;
1913 startup_screen_attrib = ScreenAttrib;
1915 /* Is DOS/V (or any other RSIS software which relocates
1916 the screen) installed? */
1918 unsigned short es_value;
1919 __dpmi_regs regs;
1921 regs.h.ah = 0xfe; /* get relocated screen address */
1922 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1923 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1924 else if (screen_old_address) /* already switched to Japanese mode once */
1925 regs.x.es = (screen_old_address >> 4) & 0xffff;
1926 else
1927 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1928 regs.x.di = 0;
1929 es_value = regs.x.es;
1930 __dpmi_int (0x10, &regs);
1932 if (regs.x.es != es_value)
1934 /* screen_old_address is only set if ScreenPrimary does NOT
1935 already point to the relocated buffer address returned by
1936 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1937 ScreenPrimary to that address at startup under DOS/V. */
1938 if (regs.x.es != ((ScreenPrimary >> 4) & 0xffff))
1939 screen_old_address = ScreenPrimary;
1940 screen_virtual_segment = regs.x.es;
1941 screen_virtual_offset = regs.x.di;
1942 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1946 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1947 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1949 bright_bg ();
1952 /* IT_reset_terminal_modes is called when emacs is
1953 suspended or killed. */
1955 static void
1956 IT_reset_terminal_modes (struct terminal *term)
1958 int display_row_start = (int) ScreenPrimary;
1959 int saved_row_len = startup_screen_size_X * 2;
1960 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1961 int to_next_row = update_row_len;
1962 unsigned char *saved_row = startup_screen_buffer;
1963 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1964 struct tty_display_info *tty = term->display_info.tty;
1966 if (tty->termscript)
1967 fprintf (tty->termscript, "\n<RESET_TERM>");
1969 if (!term_setup_done)
1970 return;
1972 mouse_off ();
1974 /* Leave the video system in the same state as we found it,
1975 as far as the blink/bright-background bit is concerned. */
1976 maybe_enable_blinking ();
1978 /* We have a situation here.
1979 We cannot just do ScreenUpdate(startup_screen_buffer) because
1980 the luser could have changed screen dimensions inside Emacs
1981 and failed (or didn't want) to restore them before killing
1982 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1983 thus will happily use memory outside what was allocated for
1984 `startup_screen_buffer'.
1985 Thus we only restore as much as the current screen dimensions
1986 can hold, and clear the rest (if the saved screen is smaller than
1987 the current) with the color attribute saved at startup. The cursor
1988 is also restored within the visible dimensions. */
1990 ScreenAttrib = startup_screen_attrib;
1992 /* Don't restore the screen if we are exiting less than 2 seconds
1993 after startup: we might be crashing, and the screen might show
1994 some vital clues to what's wrong. */
1995 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1997 ScreenClear ();
1998 if (screen_virtual_segment)
1999 dosv_refresh_virtual_screen (0, screen_size);
2001 if (update_row_len > saved_row_len)
2002 update_row_len = saved_row_len;
2003 if (current_rows > startup_screen_size_Y)
2004 current_rows = startup_screen_size_Y;
2006 if (tty->termscript)
2007 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2008 update_row_len / 2, current_rows);
2010 while (current_rows--)
2012 dosmemput (saved_row, update_row_len, display_row_start);
2013 if (screen_virtual_segment)
2014 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2015 update_row_len / 2);
2016 saved_row += saved_row_len;
2017 display_row_start += to_next_row;
2020 if (startup_pos_X < cursor_pos_X)
2021 cursor_pos_X = startup_pos_X;
2022 if (startup_pos_Y < cursor_pos_Y)
2023 cursor_pos_Y = startup_pos_Y;
2025 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2026 xfree (startup_screen_buffer);
2027 startup_screen_buffer = NULL;
2029 term_setup_done = 0;
2032 static void
2033 IT_set_terminal_window (struct frame *f, int foo)
2037 /* Remember the screen colors of the curent frame, to serve as the
2038 default colors for newly-created frames. */
2039 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2040 Smsdos_remember_default_colors, 1, 1, 0,
2041 doc: /* Remember the screen colors of the current frame. */)
2042 (Lisp_Object frame)
2044 struct frame *f;
2046 CHECK_FRAME (frame);
2047 f = XFRAME (frame);
2049 /* This function is called after applying default-frame-alist to the
2050 initial frame. At that time, if reverse-colors option was
2051 specified in default-frame-alist, it was already applied, and
2052 frame colors are reversed. */
2053 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2054 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2056 return Qnil;
2059 void
2060 IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
2062 Lisp_Object tail;
2063 int i, j, length = XINT (Flength (alist));
2064 Lisp_Object *parms
2065 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2066 Lisp_Object *values
2067 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2068 /* Do we have to reverse the foreground and background colors? */
2069 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2070 int redraw = 0, fg_set = 0, bg_set = 0;
2071 unsigned long orig_fg, orig_bg;
2072 struct tty_display_info *tty = FRAME_TTY (f);
2074 /* If we are creating a new frame, begin with the original screen colors
2075 used for the initial frame. */
2076 if (!f->default_face_done_p
2077 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2079 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2080 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2081 init_frame_faces (f);
2082 f->default_face_done_p = 1;
2084 orig_fg = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
2085 orig_bg = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
2087 /* Extract parm names and values into those vectors. */
2088 i = 0;
2089 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2091 Lisp_Object elt;
2093 elt = Fcar (tail);
2094 parms[i] = Fcar (elt);
2095 CHECK_SYMBOL (parms[i]);
2096 values[i] = Fcdr (elt);
2097 i++;
2100 j = i;
2102 for (i = 0; i < j; i++)
2104 Lisp_Object prop, val;
2106 prop = parms[i];
2107 val = values[i];
2109 if (EQ (prop, Qreverse))
2110 reverse = EQ (val, Qt);
2113 if (tty->termscript && reverse)
2114 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2116 /* Now process the alist elements in reverse of specified order. */
2117 for (i--; i >= 0; i--)
2119 Lisp_Object prop, val;
2121 prop = parms[i];
2122 val = values[i];
2124 if (EQ (prop, Qforeground_color))
2126 unsigned long new_color = load_color (f, NULL, val, reverse
2127 ? LFACE_BACKGROUND_INDEX
2128 : LFACE_FOREGROUND_INDEX);
2129 if (new_color != FACE_TTY_DEFAULT_COLOR
2130 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2131 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2133 if (!reverse)
2135 FRAME_FOREGROUND_PIXEL (f) = new_color;
2136 /* Make sure the foreground of the default face for
2137 this frame is changed as well. */
2138 update_face_from_frame_parameter (f, Qforeground_color, val);
2139 fg_set = 1;
2140 if (tty->termscript)
2141 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2143 else
2145 FRAME_BACKGROUND_PIXEL (f) = new_color;
2146 update_face_from_frame_parameter (f, Qbackground_color, val);
2147 bg_set = 1;
2148 if (tty->termscript)
2149 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2151 redraw = 1;
2154 else if (EQ (prop, Qbackground_color))
2156 unsigned long new_color = load_color (f, NULL, val, reverse
2157 ? LFACE_FOREGROUND_INDEX
2158 : LFACE_BACKGROUND_INDEX);
2159 if (new_color != FACE_TTY_DEFAULT_COLOR
2160 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2161 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2163 if (!reverse)
2165 FRAME_BACKGROUND_PIXEL (f) = new_color;
2166 /* Make sure the background of the default face for
2167 this frame is changed as well. */
2168 bg_set = 1;
2169 update_face_from_frame_parameter (f, Qbackground_color, val);
2170 if (tty->termscript)
2171 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2173 else
2175 FRAME_FOREGROUND_PIXEL (f) = new_color;
2176 fg_set = 1;
2177 update_face_from_frame_parameter (f, Qforeground_color, val);
2178 if (tty->termscript)
2179 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2181 redraw = 1;
2184 else if (EQ (prop, Qtitle))
2186 x_set_title (f, val);
2187 if (tty->termscript)
2188 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2190 else if (EQ (prop, Qcursor_type))
2192 IT_set_cursor_type (f, val);
2193 if (tty->termscript)
2194 fprintf (tty->termscript, "<CTYPE: %s>\n",
2195 EQ (val, Qbar)
2196 || EQ (val, Qhbar)
2197 || (CONSP (val) && (EQ (XCAR (val), Qbar)
2198 || EQ (XCAR (val), Qhbar)))
2199 ? "bar" : "box");
2201 else if (EQ (prop, Qtty_type))
2203 internal_terminal_init ();
2204 if (tty->termscript)
2205 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2206 SBYTES (val), SDATA (val));
2208 store_frame_param (f, prop, val);
2211 /* If they specified "reverse", but not the colors, we need to swap
2212 the current frame colors. */
2213 if (reverse)
2215 if (!fg_set)
2217 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
2218 update_face_from_frame_parameter (f, Qforeground_color,
2219 tty_color_name (f, orig_bg));
2220 redraw = 1;
2222 if (!bg_set)
2224 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
2225 update_face_from_frame_parameter (f, Qbackground_color,
2226 tty_color_name (f, orig_fg));
2227 redraw = 1;
2231 if (redraw)
2233 face_change_count++; /* forces xdisp.c to recompute basic faces */
2234 if (f == SELECTED_FRAME())
2235 redraw_frame (f);
2239 extern void init_frame_faces (FRAME_PTR);
2241 #endif /* !HAVE_X_WINDOWS */
2244 /* Do we need the internal terminal? */
2246 void
2247 internal_terminal_init (void)
2249 static int init_needed = 1;
2250 char *term = getenv ("TERM"), *colors;
2251 struct frame *sf = SELECTED_FRAME();
2252 struct tty_display_info *tty;
2254 #ifdef HAVE_X_WINDOWS
2255 if (!inhibit_window_system)
2256 return;
2257 #endif
2259 /* If this is the initial terminal, we are done here. */
2260 if (sf->output_method == output_initial)
2261 return;
2263 internal_terminal
2264 = (!noninteractive) && term && !strcmp (term, "internal");
2266 #ifndef HAVE_X_WINDOWS
2267 if (!internal_terminal || inhibit_window_system)
2269 sf->output_method = output_termcap;
2270 return;
2273 tty = FRAME_TTY (sf);
2274 current_kboard->Vwindow_system = Qpc;
2275 sf->output_method = output_msdos_raw;
2276 if (init_needed)
2278 if (!tty->termscript && getenv ("EMACSTEST"))
2279 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2280 if (tty->termscript)
2282 time_t now = time (NULL);
2283 struct tm *tnow = localtime (&now);
2284 char tbuf[100];
2286 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2287 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2288 fprintf (tty->termscript, "=====================\n\n");
2291 Vinitial_window_system = Qpc;
2292 Vwindow_system_version = make_number (23); /* RE Emacs version */
2293 tty->terminal->type = output_msdos_raw;
2295 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2296 address. */
2297 screen_old_address = 0;
2299 /* Forget the stale screen colors as well. */
2300 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2302 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2303 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2304 bright_bg ();
2305 colors = getenv ("EMACSCOLORS");
2306 if (colors && strlen (colors) >= 2)
2308 /* The colors use 4 bits each (we enable bright background). */
2309 if (isdigit (colors[0]))
2310 colors[0] -= '0';
2311 else if (isxdigit (colors[0]))
2312 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2313 if (colors[0] >= 0 && colors[0] < 16)
2314 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2315 if (isdigit (colors[1]))
2316 colors[1] -= '0';
2317 else if (isxdigit (colors[1]))
2318 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2319 if (colors[1] >= 0 && colors[1] < 16)
2320 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2322 the_only_display_info.mouse_face_mouse_frame = NULL;
2323 the_only_display_info.mouse_face_deferred_gc = 0;
2324 the_only_display_info.mouse_face_beg_row =
2325 the_only_display_info.mouse_face_beg_col = -1;
2326 the_only_display_info.mouse_face_end_row =
2327 the_only_display_info.mouse_face_end_col = -1;
2328 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2329 the_only_display_info.mouse_face_window = Qnil;
2330 the_only_display_info.mouse_face_mouse_x =
2331 the_only_display_info.mouse_face_mouse_y = 0;
2332 the_only_display_info.mouse_face_defer = 0;
2333 the_only_display_info.mouse_face_hidden = 0;
2335 if (have_mouse) /* detected in dos_ttraw, which see */
2337 have_mouse = 1; /* enable mouse */
2338 mouse_visible = 0;
2339 mouse_setup_buttons (mouse_button_count);
2340 tty->terminal->mouse_position_hook = &mouse_get_pos;
2341 mouse_init ();
2344 if (tty->termscript && screen_size)
2345 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2346 screen_size_X, screen_size_Y);
2348 init_frame_faces (sf);
2349 init_needed = 0;
2351 #endif
2354 void
2355 initialize_msdos_display (struct terminal *term)
2357 term->rif = 0; /* we don't support window-based display */
2358 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2359 term->clear_to_end_hook = IT_clear_to_end;
2360 term->clear_frame_hook = IT_clear_screen;
2361 term->clear_end_of_line_hook = IT_clear_end_of_line;
2362 term->ins_del_lines_hook = 0;
2363 term->insert_glyphs_hook = IT_insert_glyphs;
2364 term->write_glyphs_hook = IT_write_glyphs;
2365 term->delete_glyphs_hook = IT_delete_glyphs;
2366 term->ring_bell_hook = IT_ring_bell;
2367 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2368 term->set_terminal_modes_hook = IT_set_terminal_modes;
2369 term->set_terminal_window_hook = IT_set_terminal_window;
2370 term->update_begin_hook = IT_update_begin;
2371 term->update_end_hook = IT_update_end;
2372 term->frame_up_to_date_hook = IT_frame_up_to_date;
2373 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2374 term->frame_rehighlight_hook = 0;
2375 term->frame_raise_lower_hook = 0;
2376 term->set_vertical_scroll_bar_hook = 0;
2377 term->condemn_scroll_bars_hook = 0;
2378 term->redeem_scroll_bar_hook = 0;
2379 term->judge_scroll_bars_hook = 0;
2380 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2384 dos_get_saved_screen (char **screen, int *rows, int *cols)
2386 #ifndef HAVE_X_WINDOWS
2387 *screen = startup_screen_buffer;
2388 *cols = startup_screen_size_X;
2389 *rows = startup_screen_size_Y;
2390 return *screen != (char *)0;
2391 #else
2392 return 0;
2393 #endif
2396 #ifndef HAVE_X_WINDOWS
2398 /* We are not X, but we can emulate it well enough for our needs... */
2399 void
2400 check_x (void)
2402 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2403 error ("Not running under a window system");
2406 #endif
2409 /* ----------------------- Keyboard control ----------------------
2411 * Keymaps reflect the following keyboard layout:
2413 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2414 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2415 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2416 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2417 * SPACE
2420 #define Ignore 0x0000
2421 #define Normal 0x0000 /* normal key - alt changes scan-code */
2422 #define FctKey 0x1000 /* func key if c == 0, else c */
2423 #define Special 0x2000 /* func key even if c != 0 */
2424 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2425 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2426 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2427 #define Grey 0x6000 /* Grey keypad key */
2429 #define Alt 0x0100 /* alt scan-code */
2430 #define Ctrl 0x0200 /* ctrl scan-code */
2431 #define Shift 0x0400 /* shift scan-code */
2433 static int extended_kbd; /* 101 (102) keyboard present. */
2435 struct kbd_translate {
2436 unsigned char sc;
2437 unsigned char ch;
2438 unsigned short code;
2441 struct dos_keyboard_map
2443 char *unshifted;
2444 char *shifted;
2445 char *alt_gr;
2446 struct kbd_translate *translate_table;
2450 static struct dos_keyboard_map us_keyboard = {
2451 /* 0 1 2 3 4 5 */
2452 /* 01234567890123456789012345678901234567890 12345678901234 */
2453 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2454 /* 0123456789012345678901234567890123456789 012345678901234 */
2455 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2456 0, /* no Alt-Gr key */
2457 0 /* no translate table */
2460 static struct dos_keyboard_map fr_keyboard = {
2461 /* 0 1 2 3 4 5 */
2462 /* 012 3456789012345678901234567890123456789012345678901234 */
2463 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2464 /* 0123456789012345678901234567890123456789012345678901234 */
2465 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2466 /* 01234567 89012345678901234567890123456789012345678901234 */
2467 " ~#{[|`\\^@]} Ï ",
2468 0 /* no translate table */
2472 * Italian keyboard support, country code 39.
2473 * '<' 56:3c*0000
2474 * '>' 56:3e*0000
2475 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2476 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2479 static struct kbd_translate it_kbd_translate_table[] = {
2480 { 0x56, 0x3c, Normal | 13 },
2481 { 0x56, 0x3e, Normal | 27 },
2482 { 0, 0, 0 }
2484 static struct dos_keyboard_map it_keyboard = {
2485 /* 0 1 2 3 4 5 */
2486 /* 0 123456789012345678901234567890123456789012345678901234 */
2487 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2488 /* 01 23456789012345678901234567890123456789012345678901234 */
2489 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2490 /* 0123456789012345678901234567890123456789012345678901234 */
2491 " {}~` [] @# ",
2492 it_kbd_translate_table
2495 static struct dos_keyboard_map dk_keyboard = {
2496 /* 0 1 2 3 4 5 */
2497 /* 0123456789012345678901234567890123456789012345678901234 */
2498 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2499 /* 01 23456789012345678901234567890123456789012345678901234 */
2500 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2501 /* 0123456789012345678901234567890123456789012345678901234 */
2502 " @œ$ {[]} | ",
2503 0 /* no translate table */
2506 static struct kbd_translate jp_kbd_translate_table[] = {
2507 { 0x73, 0x5c, Normal | 0 },
2508 { 0x73, 0x5f, Normal | 0 },
2509 { 0x73, 0x1c, Map | 0 },
2510 { 0x7d, 0x5c, Normal | 13 },
2511 { 0x7d, 0x7c, Normal | 13 },
2512 { 0x7d, 0x1c, Map | 13 },
2513 { 0, 0, 0 }
2515 static struct dos_keyboard_map jp_keyboard = {
2516 /* 0 1 2 3 4 5 */
2517 /* 0123456789012 345678901234567890123456789012345678901234 */
2518 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2519 /* 01 23456789012345678901234567890123456789012345678901234 */
2520 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2521 0, /* no Alt-Gr key */
2522 jp_kbd_translate_table
2525 static struct keyboard_layout_list
2527 int country_code;
2528 struct dos_keyboard_map *keyboard_map;
2529 } keyboard_layout_list[] =
2531 { 1, &us_keyboard },
2532 { 33, &fr_keyboard },
2533 { 39, &it_keyboard },
2534 { 45, &dk_keyboard },
2535 { 81, &jp_keyboard }
2538 static struct dos_keyboard_map *keyboard;
2539 static int keyboard_map_all;
2540 static int international_keyboard;
2543 dos_set_keyboard (int code, int always)
2545 int i;
2546 _go32_dpmi_registers regs;
2548 /* See if Keyb.Com is installed (for international keyboard support).
2549 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2550 of Windows 9X! So don't do that! */
2551 regs.x.ax = 0xad80;
2552 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2553 _go32_dpmi_simulate_int (0x2f, &regs);
2554 if (regs.h.al == 0xff)
2555 international_keyboard = 1;
2557 /* Initialize to US settings, for countries that don't have their own. */
2558 keyboard = keyboard_layout_list[0].keyboard_map;
2559 keyboard_map_all = always;
2560 dos_keyboard_layout = 1;
2562 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2563 if (code == keyboard_layout_list[i].country_code)
2565 keyboard = keyboard_layout_list[i].keyboard_map;
2566 keyboard_map_all = always;
2567 dos_keyboard_layout = code;
2568 return 1;
2570 return 0;
2573 static struct
2575 unsigned char char_code; /* normal code */
2576 unsigned char meta_code; /* M- code */
2577 unsigned char keypad_code; /* keypad code */
2578 unsigned char editkey_code; /* edit key */
2579 } keypad_translate_map[] = {
2580 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2581 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2582 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2583 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2584 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2585 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2586 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2587 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2588 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2589 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2590 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2593 static struct
2595 unsigned char char_code; /* normal code */
2596 unsigned char keypad_code; /* keypad code */
2597 } grey_key_translate_map[] = {
2598 { '/', 0xaf /* kp-decimal */ },
2599 { '*', 0xaa /* kp-multiply */ },
2600 { '-', 0xad /* kp-subtract */ },
2601 { '+', 0xab /* kp-add */ },
2602 { '\r', 0x8d /* kp-enter */ }
2605 static unsigned short
2606 ibmpc_translate_map[] =
2608 /* --------------- 00 to 0f --------------- */
2609 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2610 Alt | ModFct | 0x1b, /* Escape */
2611 Normal | 1, /* '1' */
2612 Normal | 2, /* '2' */
2613 Normal | 3, /* '3' */
2614 Normal | 4, /* '4' */
2615 Normal | 5, /* '5' */
2616 Normal | 6, /* '6' */
2617 Normal | 7, /* '7' */
2618 Normal | 8, /* '8' */
2619 Normal | 9, /* '9' */
2620 Normal | 10, /* '0' */
2621 Normal | 11, /* '-' */
2622 Normal | 12, /* '=' */
2623 Special | 0x08, /* Backspace */
2624 ModFct | 0x74, /* Tab/Backtab */
2626 /* --------------- 10 to 1f --------------- */
2627 Map | 15, /* 'q' */
2628 Map | 16, /* 'w' */
2629 Map | 17, /* 'e' */
2630 Map | 18, /* 'r' */
2631 Map | 19, /* 't' */
2632 Map | 20, /* 'y' */
2633 Map | 21, /* 'u' */
2634 Map | 22, /* 'i' */
2635 Map | 23, /* 'o' */
2636 Map | 24, /* 'p' */
2637 Map | 25, /* '[' */
2638 Map | 26, /* ']' */
2639 ModFct | 0x0d, /* Return */
2640 Ignore, /* Ctrl */
2641 Map | 30, /* 'a' */
2642 Map | 31, /* 's' */
2644 /* --------------- 20 to 2f --------------- */
2645 Map | 32, /* 'd' */
2646 Map | 33, /* 'f' */
2647 Map | 34, /* 'g' */
2648 Map | 35, /* 'h' */
2649 Map | 36, /* 'j' */
2650 Map | 37, /* 'k' */
2651 Map | 38, /* 'l' */
2652 Map | 39, /* ';' */
2653 Map | 40, /* '\'' */
2654 Map | 0, /* '`' */
2655 Ignore, /* Left shift */
2656 Map | 41, /* '\\' */
2657 Map | 45, /* 'z' */
2658 Map | 46, /* 'x' */
2659 Map | 47, /* 'c' */
2660 Map | 48, /* 'v' */
2662 /* --------------- 30 to 3f --------------- */
2663 Map | 49, /* 'b' */
2664 Map | 50, /* 'n' */
2665 Map | 51, /* 'm' */
2666 Map | 52, /* ',' */
2667 Map | 53, /* '.' */
2668 Map | 54, /* '/' */
2669 Ignore, /* Right shift */
2670 Grey | 1, /* Grey * */
2671 Ignore, /* Alt */
2672 Normal | 55, /* ' ' */
2673 Ignore, /* Caps Lock */
2674 FctKey | 0xbe, /* F1 */
2675 FctKey | 0xbf, /* F2 */
2676 FctKey | 0xc0, /* F3 */
2677 FctKey | 0xc1, /* F4 */
2678 FctKey | 0xc2, /* F5 */
2680 /* --------------- 40 to 4f --------------- */
2681 FctKey | 0xc3, /* F6 */
2682 FctKey | 0xc4, /* F7 */
2683 FctKey | 0xc5, /* F8 */
2684 FctKey | 0xc6, /* F9 */
2685 FctKey | 0xc7, /* F10 */
2686 Ignore, /* Num Lock */
2687 Ignore, /* Scroll Lock */
2688 KeyPad | 7, /* Home */
2689 KeyPad | 8, /* Up */
2690 KeyPad | 9, /* Page Up */
2691 Grey | 2, /* Grey - */
2692 KeyPad | 4, /* Left */
2693 KeyPad | 5, /* Keypad 5 */
2694 KeyPad | 6, /* Right */
2695 Grey | 3, /* Grey + */
2696 KeyPad | 1, /* End */
2698 /* --------------- 50 to 5f --------------- */
2699 KeyPad | 2, /* Down */
2700 KeyPad | 3, /* Page Down */
2701 KeyPad | 0, /* Insert */
2702 KeyPad | 10, /* Delete */
2703 Shift | FctKey | 0xbe, /* (Shift) F1 */
2704 Shift | FctKey | 0xbf, /* (Shift) F2 */
2705 Shift | FctKey | 0xc0, /* (Shift) F3 */
2706 Shift | FctKey | 0xc1, /* (Shift) F4 */
2707 Shift | FctKey | 0xc2, /* (Shift) F5 */
2708 Shift | FctKey | 0xc3, /* (Shift) F6 */
2709 Shift | FctKey | 0xc4, /* (Shift) F7 */
2710 Shift | FctKey | 0xc5, /* (Shift) F8 */
2711 Shift | FctKey | 0xc6, /* (Shift) F9 */
2712 Shift | FctKey | 0xc7, /* (Shift) F10 */
2713 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2714 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2716 /* --------------- 60 to 6f --------------- */
2717 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2718 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2719 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2720 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2721 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2722 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2723 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2724 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2725 Alt | FctKey | 0xbe, /* (Alt) F1 */
2726 Alt | FctKey | 0xbf, /* (Alt) F2 */
2727 Alt | FctKey | 0xc0, /* (Alt) F3 */
2728 Alt | FctKey | 0xc1, /* (Alt) F4 */
2729 Alt | FctKey | 0xc2, /* (Alt) F5 */
2730 Alt | FctKey | 0xc3, /* (Alt) F6 */
2731 Alt | FctKey | 0xc4, /* (Alt) F7 */
2732 Alt | FctKey | 0xc5, /* (Alt) F8 */
2734 /* --------------- 70 to 7f --------------- */
2735 Alt | FctKey | 0xc6, /* (Alt) F9 */
2736 Alt | FctKey | 0xc7, /* (Alt) F10 */
2737 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2738 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2739 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2740 Ctrl | KeyPad | 1, /* (Ctrl) End */
2741 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2742 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2743 Alt | Map | 1, /* '1' */
2744 Alt | Map | 2, /* '2' */
2745 Alt | Map | 3, /* '3' */
2746 Alt | Map | 4, /* '4' */
2747 Alt | Map | 5, /* '5' */
2748 Alt | Map | 6, /* '6' */
2749 Alt | Map | 7, /* '7' */
2750 Alt | Map | 8, /* '8' */
2752 /* --------------- 80 to 8f --------------- */
2753 Alt | Map | 9, /* '9' */
2754 Alt | Map | 10, /* '0' */
2755 Alt | Map | 11, /* '-' */
2756 Alt | Map | 12, /* '=' */
2757 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2758 FctKey | 0xc8, /* F11 */
2759 FctKey | 0xc9, /* F12 */
2760 Shift | FctKey | 0xc8, /* (Shift) F11 */
2761 Shift | FctKey | 0xc9, /* (Shift) F12 */
2762 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2763 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2764 Alt | FctKey | 0xc8, /* (Alt) F11 */
2765 Alt | FctKey | 0xc9, /* (Alt) F12 */
2766 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2767 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2768 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2770 /* --------------- 90 to 9f --------------- */
2771 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2772 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2773 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2774 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2775 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2776 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2777 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2778 Alt | FctKey | 0x50, /* (Alt) Home */
2779 Alt | FctKey | 0x52, /* (Alt) Up */
2780 Alt | FctKey | 0x55, /* (Alt) Page Up */
2781 Ignore, /* NO KEY */
2782 Alt | FctKey | 0x51, /* (Alt) Left */
2783 Ignore, /* NO KEY */
2784 Alt | FctKey | 0x53, /* (Alt) Right */
2785 Ignore, /* NO KEY */
2786 Alt | FctKey | 0x57, /* (Alt) End */
2788 /* --------------- a0 to af --------------- */
2789 Alt | KeyPad | 2, /* (Alt) Down */
2790 Alt | KeyPad | 3, /* (Alt) Page Down */
2791 Alt | KeyPad | 0, /* (Alt) Insert */
2792 Alt | KeyPad | 10, /* (Alt) Delete */
2793 Alt | Grey | 0, /* (Alt) Grey / */
2794 Alt | FctKey | 0x09, /* (Alt) Tab */
2795 Alt | Grey | 4 /* (Alt) Keypad Enter */
2798 /* These bit-positions corresponds to values returned by BIOS */
2799 #define SHIFT_P 0x0003 /* two bits! */
2800 #define CTRL_P 0x0004
2801 #define ALT_P 0x0008
2802 #define SCRLOCK_P 0x0010
2803 #define NUMLOCK_P 0x0020
2804 #define CAPSLOCK_P 0x0040
2805 #define ALT_GR_P 0x0800
2806 #define SUPER_P 0x4000 /* pseudo */
2807 #define HYPER_P 0x8000 /* pseudo */
2809 static int
2810 dos_get_modifiers (int *keymask)
2812 union REGS regs;
2813 int mask, modifiers = 0;
2815 /* Calculate modifier bits */
2816 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2817 int86 (0x16, &regs, &regs);
2819 if (!extended_kbd)
2821 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2822 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2824 else
2826 mask = regs.h.al & (SHIFT_P |
2827 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2829 /* Do not break international keyboard support. */
2830 /* When Keyb.Com is loaded, the right Alt key is */
2831 /* used for accessing characters like { and } */
2832 if (regs.h.ah & 2) /* Left ALT pressed ? */
2833 mask |= ALT_P;
2835 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2837 mask |= ALT_GR_P;
2838 if (dos_hyper_key == 1)
2840 mask |= HYPER_P;
2841 modifiers |= hyper_modifier;
2843 else if (dos_super_key == 1)
2845 mask |= SUPER_P;
2846 modifiers |= super_modifier;
2848 else if (!international_keyboard)
2850 /* If Keyb.Com is NOT installed, let Right Alt behave
2851 like the Left Alt. */
2852 mask &= ~ALT_GR_P;
2853 mask |= ALT_P;
2857 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2858 mask |= CTRL_P;
2860 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2862 if (dos_hyper_key == 2)
2864 mask |= HYPER_P;
2865 modifiers |= hyper_modifier;
2867 else if (dos_super_key == 2)
2869 mask |= SUPER_P;
2870 modifiers |= super_modifier;
2872 else
2873 mask |= CTRL_P;
2877 if (mask & SHIFT_P)
2878 modifiers |= shift_modifier;
2879 if (mask & CTRL_P)
2880 modifiers |= ctrl_modifier;
2881 if (mask & ALT_P)
2882 modifiers |= meta_modifier;
2884 if (keymask)
2885 *keymask = mask;
2886 return modifiers;
2889 #define NUM_RECENT_DOSKEYS (100)
2890 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2891 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2892 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2894 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2895 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2896 Each input key receives two values in this vector: first the ASCII code,
2897 and then the scan code. */)
2898 (void)
2900 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2902 if (total_doskeys < NUM_RECENT_DOSKEYS)
2903 return Fvector (total_doskeys, keys);
2904 else
2906 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2907 memcpy (XVECTOR (val)->contents, keys + recent_doskeys_index,
2908 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2909 memcpy (XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2910 keys, recent_doskeys_index * sizeof (Lisp_Object));
2911 return val;
2915 /* Get a char from keyboard. Function keys are put into the event queue. */
2916 static int
2917 dos_rawgetc (void)
2919 struct input_event event;
2920 union REGS regs;
2921 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
2922 EVENT_INIT (event);
2924 #ifndef HAVE_X_WINDOWS
2925 /* Maybe put the cursor where it should be. */
2926 IT_cmgoto (SELECTED_FRAME());
2927 #endif
2929 /* The following condition is equivalent to `kbhit ()', except that
2930 it uses the bios to do its job. This pleases DESQview/X. */
2931 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2932 int86 (0x16, &regs, &regs),
2933 (regs.x.flags & 0x40) == 0)
2935 union REGS regs;
2936 register unsigned char c;
2937 int modifiers, sc, code = -1, mask, kp_mode;
2939 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2940 int86 (0x16, &regs, &regs);
2941 c = regs.h.al;
2942 sc = regs.h.ah;
2944 total_doskeys += 2;
2945 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2946 = make_number (c);
2947 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2948 recent_doskeys_index = 0;
2949 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2950 = make_number (sc);
2951 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2952 recent_doskeys_index = 0;
2954 modifiers = dos_get_modifiers (&mask);
2956 #ifndef HAVE_X_WINDOWS
2957 if (!NILP (Vdos_display_scancodes))
2959 char buf[11];
2960 sprintf (buf, "%02x:%02x*%04x",
2961 (unsigned) (sc&0xff), (unsigned) c, mask);
2962 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2964 #endif
2966 if (sc == 0xe0)
2968 switch (c)
2970 case 10: /* Ctrl Grey Enter */
2971 code = Ctrl | Grey | 4;
2972 break;
2973 case 13: /* Grey Enter */
2974 code = Grey | 4;
2975 break;
2976 case '/': /* Grey / */
2977 code = Grey | 0;
2978 break;
2979 default:
2980 continue;
2982 c = 0;
2984 else
2986 /* Try the keyboard-private translation table first. */
2987 if (keyboard->translate_table)
2989 struct kbd_translate *p = keyboard->translate_table;
2991 while (p->sc)
2993 if (p->sc == sc && p->ch == c)
2995 code = p->code;
2996 break;
2998 p++;
3001 /* If the private table didn't translate it, use the general
3002 one. */
3003 if (code == -1)
3005 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3006 continue;
3007 if ((code = ibmpc_translate_map[sc]) == Ignore)
3008 continue;
3012 if (c == 0)
3014 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3015 Emacs is ready to read a key. Therefore, if they press
3016 `Alt-x' when Emacs is busy, by the time we get to
3017 `dos_get_modifiers', they might have already released the
3018 Alt key, and Emacs gets just `x', which is BAD.
3019 However, for keys with the `Map' property set, the ASCII
3020 code returns zero only if Alt is pressed. So, when we DON'T
3021 have to support international_keyboard, we don't have to
3022 distinguish between the left and right Alt keys, and we
3023 can set the META modifier for any keys with the `Map'
3024 property if they return zero ASCII code (c = 0). */
3025 if ( (code & Alt)
3026 || ( (code & 0xf000) == Map && !international_keyboard))
3027 modifiers |= meta_modifier;
3028 if (code & Ctrl)
3029 modifiers |= ctrl_modifier;
3030 if (code & Shift)
3031 modifiers |= shift_modifier;
3034 switch (code & 0xf000)
3036 case ModFct:
3037 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3038 return c;
3039 c = 0; /* Special */
3041 case FctKey:
3042 if (c != 0)
3043 return c;
3045 case Special:
3046 code |= 0xff00;
3047 break;
3049 case Normal:
3050 if (sc == 0)
3052 if (c == 0) /* ctrl-break */
3053 continue;
3054 return c; /* ALT-nnn */
3056 if (!keyboard_map_all)
3058 if (c != ' ')
3059 return c;
3060 code = c;
3061 break;
3064 case Map:
3065 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3066 if (!keyboard_map_all)
3067 return c;
3069 code &= 0xff;
3070 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3071 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3073 if (mask & SHIFT_P)
3075 code = keyboard->shifted[code];
3076 mask -= SHIFT_P;
3077 modifiers &= ~shift_modifier;
3079 else
3080 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3081 code = keyboard->alt_gr[code];
3082 else
3083 code = keyboard->unshifted[code];
3084 break;
3086 case KeyPad:
3087 code &= 0xff;
3088 if (c == 0xe0) /* edit key */
3089 kp_mode = 3;
3090 else
3091 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3092 kp_mode = dos_keypad_mode & 0x03;
3093 else
3094 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3096 switch (kp_mode)
3098 case 0:
3099 if (code == 10 && dos_decimal_point)
3100 return dos_decimal_point;
3101 return keypad_translate_map[code].char_code;
3103 case 1:
3104 code = 0xff00 | keypad_translate_map[code].keypad_code;
3105 break;
3107 case 2:
3108 code = keypad_translate_map[code].meta_code;
3109 modifiers = meta_modifier;
3110 break;
3112 case 3:
3113 code = 0xff00 | keypad_translate_map[code].editkey_code;
3114 break;
3116 break;
3118 case Grey:
3119 code &= 0xff;
3120 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3121 if (dos_keypad_mode & kp_mode)
3122 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3123 else
3124 code = grey_key_translate_map[code].char_code;
3125 break;
3128 if (code == 0)
3129 continue;
3131 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3133 clear_mouse_face (dpyinfo);
3134 dpyinfo->mouse_face_hidden = 1;
3137 if (code >= 0x100)
3138 event.kind = NON_ASCII_KEYSTROKE_EVENT;
3139 else
3140 event.kind = ASCII_KEYSTROKE_EVENT;
3141 event.code = code;
3142 event.modifiers = modifiers;
3143 event.frame_or_window = selected_frame;
3144 event.arg = Qnil;
3145 event.timestamp = event_timestamp ();
3146 kbd_buffer_store_event (&event);
3149 if (have_mouse > 0 && !mouse_preempted)
3151 int but, press, x, y, ok;
3152 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3153 Lisp_Object mouse_window = Qnil;
3155 /* Check for mouse movement *before* buttons. */
3156 mouse_check_moved ();
3158 /* If the mouse moved from the spot of its last sighting, we
3159 might need to update mouse highlight. */
3160 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3162 if (dpyinfo->mouse_face_hidden)
3164 dpyinfo->mouse_face_hidden = 0;
3165 clear_mouse_face (dpyinfo);
3168 /* Generate SELECT_WINDOW_EVENTs when needed. */
3169 if (!NILP (Vmouse_autoselect_window))
3171 mouse_window = window_from_coordinates (SELECTED_FRAME(),
3172 mouse_last_x,
3173 mouse_last_y,
3174 0, 0, 0, 0);
3175 /* A window will be selected only when it is not
3176 selected now, and the last mouse movement event was
3177 not in it. A minibuffer window will be selected iff
3178 it is active. */
3179 if (WINDOWP (mouse_window)
3180 && !EQ (mouse_window, last_mouse_window)
3181 && !EQ (mouse_window, selected_window))
3183 event.kind = SELECT_WINDOW_EVENT;
3184 event.frame_or_window = mouse_window;
3185 event.arg = Qnil;
3186 event.timestamp = event_timestamp ();
3187 kbd_buffer_store_event (&event);
3189 last_mouse_window = mouse_window;
3191 else
3192 last_mouse_window = Qnil;
3194 previous_help_echo_string = help_echo_string;
3195 help_echo_string = help_echo_object = help_echo_window = Qnil;
3196 help_echo_pos = -1;
3197 IT_note_mouse_highlight (SELECTED_FRAME(),
3198 mouse_last_x, mouse_last_y);
3199 /* If the contents of the global variable help_echo has
3200 changed, generate a HELP_EVENT. */
3201 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3203 event.kind = HELP_EVENT;
3204 event.frame_or_window = selected_frame;
3205 event.arg = help_echo_object;
3206 event.x = WINDOWP (help_echo_window)
3207 ? help_echo_window : selected_frame;
3208 event.y = help_echo_string;
3209 event.timestamp = event_timestamp ();
3210 event.code = help_echo_pos;
3211 kbd_buffer_store_event (&event);
3215 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3216 for (press = 0; press < 2; press++)
3218 int button_num = but;
3220 if (press)
3221 ok = mouse_pressed (but, &x, &y);
3222 else
3223 ok = mouse_released (but, &x, &y);
3224 if (ok)
3226 /* Allow a simultaneous press/release of Mouse-1 and
3227 Mouse-2 to simulate Mouse-3 on two-button mice. */
3228 if (mouse_button_count == 2 && but < 2)
3230 int x2, y2; /* don't clobber original coordinates */
3232 /* If only one button is pressed, wait 100 msec and
3233 check again. This way, Speedy Gonzales isn't
3234 punished, while the slow get their chance. */
3235 if ((press && mouse_pressed (1-but, &x2, &y2))
3236 || (!press && mouse_released (1-but, &x2, &y2)))
3237 button_num = 2;
3238 else
3240 delay (100);
3241 if ((press && mouse_pressed (1-but, &x2, &y2))
3242 || (!press && mouse_released (1-but, &x2, &y2)))
3243 button_num = 2;
3247 event.kind = MOUSE_CLICK_EVENT;
3248 event.code = button_num;
3249 event.modifiers = dos_get_modifiers (0)
3250 | (press ? down_modifier : up_modifier);
3251 event.x = make_number (x);
3252 event.y = make_number (y);
3253 event.frame_or_window = selected_frame;
3254 event.arg = Qnil;
3255 event.timestamp = event_timestamp ();
3256 kbd_buffer_store_event (&event);
3261 return -1;
3264 static int prev_get_char = -1;
3266 /* Return 1 if a key is ready to be read without suspending execution. */
3268 dos_keysns (void)
3270 if (prev_get_char != -1)
3271 return 1;
3272 else
3273 return ((prev_get_char = dos_rawgetc ()) != -1);
3276 /* Read a key. Return -1 if no key is ready. */
3278 dos_keyread (void)
3280 if (prev_get_char != -1)
3282 int c = prev_get_char;
3283 prev_get_char = -1;
3284 return c;
3286 else
3287 return dos_rawgetc ();
3290 #ifndef HAVE_X_WINDOWS
3292 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3293 for now.
3295 Actually, I don't know the meaning of all the parameters of the functions
3296 here -- I only know how they are called by xmenu.c. I could of course
3297 grab the nearest Xlib manual (down the hall, second-to-last door on the
3298 left), but I don't think it's worth the effort. */
3300 /* These hold text of the current and the previous menu help messages. */
3301 static char *menu_help_message, *prev_menu_help_message;
3302 /* Pane number and item number of the menu item which generated the
3303 last menu help message. */
3304 static int menu_help_paneno, menu_help_itemno;
3306 static XMenu *
3307 IT_menu_create (void)
3309 XMenu *menu;
3311 menu = (XMenu *) xmalloc (sizeof (XMenu));
3312 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3313 return menu;
3316 /* Allocate some (more) memory for MENU ensuring that there is room for one
3317 for item. */
3319 static void
3320 IT_menu_make_room (XMenu *menu)
3322 if (menu->allocated == 0)
3324 int count = menu->allocated = 10;
3325 menu->text = (char **) xmalloc (count * sizeof (char *));
3326 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3327 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3328 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3330 else if (menu->allocated == menu->count)
3332 int count = menu->allocated = menu->allocated + 10;
3333 menu->text
3334 = (char **) xrealloc (menu->text, count * sizeof (char *));
3335 menu->submenu
3336 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3337 menu->panenumber
3338 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3339 menu->help_text
3340 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3344 /* Search the given menu structure for a given pane number. */
3346 static XMenu *
3347 IT_menu_search_pane (XMenu *menu, int pane)
3349 int i;
3350 XMenu *try;
3352 for (i = 0; i < menu->count; i++)
3353 if (menu->submenu[i])
3355 if (pane == menu->panenumber[i])
3356 return menu->submenu[i];
3357 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3358 return try;
3360 return (XMenu *) 0;
3363 /* Determine how much screen space a given menu needs. */
3365 static void
3366 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3368 int i, h2, w2, maxsubwidth, maxheight;
3370 maxsubwidth = 0;
3371 maxheight = menu->count;
3372 for (i = 0; i < menu->count; i++)
3374 if (menu->submenu[i])
3376 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3377 if (w2 > maxsubwidth) maxsubwidth = w2;
3378 if (i + h2 > maxheight) maxheight = i + h2;
3381 *width = menu->width + maxsubwidth;
3382 *height = maxheight;
3385 /* Display MENU at (X,Y) using FACES. */
3387 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3388 do \
3390 (GLYPH).type = CHAR_GLYPH; \
3391 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3392 (GLYPH).charpos = -1; \
3394 while (0)
3396 static void
3397 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3399 int i, j, face, width, mx, my, enabled, mousehere, row, col;
3400 struct glyph *text, *p;
3401 const unsigned char *q;
3402 struct frame *sf = SELECTED_FRAME();
3404 menu_help_message = NULL;
3406 width = menu->width;
3407 /* We multiply width by 2 to account for possible control characters.
3408 FIXME: cater to non-ASCII characters in menus. */
3409 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3410 ScreenGetCursor (&row, &col);
3411 mouse_get_xy (&mx, &my);
3412 IT_update_begin (sf);
3413 for (i = 0; i < menu->count; i++)
3415 int max_width = width + 2;
3417 IT_cursor_to (sf, y + i, x);
3418 enabled
3419 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3420 mousehere = (y + i == my && x <= mx && mx < x + max_width);
3421 face = faces[enabled + mousehere * 2];
3422 /* The following if clause means that we display the menu help
3423 strings even if the menu item is currently disabled. */
3424 if (disp_help && enabled + mousehere * 2 >= 2)
3426 menu_help_message = menu->help_text[i];
3427 menu_help_paneno = pn - 1;
3428 menu_help_itemno = i;
3430 p = text;
3431 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3432 p++;
3433 for (j = 0, q = menu->text[i]; *q; j++)
3435 unsigned c = STRING_CHAR_ADVANCE (q);
3437 if (c > 26)
3439 BUILD_CHAR_GLYPH (*p, c, face, 0);
3440 p++;
3442 else /* make '^x' */
3444 BUILD_CHAR_GLYPH (*p, '^', face, 0);
3445 p++;
3446 j++;
3447 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3448 p++;
3451 /* Don't let the menu text overflow into the next screen row. */
3452 if (x + max_width > screen_size_X)
3454 max_width = screen_size_X - x;
3455 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3457 for (; j < max_width - 2; j++, p++)
3458 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3460 /* 16 is the character code of a character that on DOS terminal
3461 produces a nice-looking right-pointing arrow glyph. */
3462 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3463 p++;
3464 IT_write_glyphs (sf, text, max_width);
3466 IT_update_end (sf);
3467 IT_cursor_to (sf, row, col);
3468 xfree (text);
3471 /* --------------------------- X Menu emulation ---------------------- */
3473 /* Report availability of menus. */
3476 have_menus_p (void) { return 1; }
3478 /* Create a brand new menu structure. */
3480 XMenu *
3481 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3483 return IT_menu_create ();
3486 /* Create a new pane and place it on the outer-most level. It is not
3487 clear that it should be placed out there, but I don't know what else
3488 to do. */
3491 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3493 int len;
3494 char *p;
3496 if (!enable)
3497 abort ();
3499 IT_menu_make_room (menu);
3500 menu->submenu[menu->count] = IT_menu_create ();
3501 menu->text[menu->count] = txt;
3502 menu->panenumber[menu->count] = ++menu->panecount;
3503 menu->help_text[menu->count] = NULL;
3504 menu->count++;
3506 /* Adjust length for possible control characters (which will
3507 be written as ^x). */
3508 for (len = strlen (txt), p = txt; *p; p++)
3509 if (*p < 27)
3510 len++;
3512 if (len > menu->width)
3513 menu->width = len;
3515 return menu->panecount;
3518 /* Create a new item in a menu pane. */
3521 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3522 int foo, char *txt, int enable, char *help_text)
3524 int len;
3525 char *p;
3527 if (pane)
3528 if (!(menu = IT_menu_search_pane (menu, pane)))
3529 return XM_FAILURE;
3530 IT_menu_make_room (menu);
3531 menu->submenu[menu->count] = (XMenu *) 0;
3532 menu->text[menu->count] = txt;
3533 menu->panenumber[menu->count] = enable;
3534 menu->help_text[menu->count] = help_text;
3535 menu->count++;
3537 /* Adjust length for possible control characters (which will
3538 be written as ^x). */
3539 for (len = strlen (txt), p = txt; *p; p++)
3540 if (*p < 27)
3541 len++;
3543 if (len > menu->width)
3544 menu->width = len;
3546 return XM_SUCCESS;
3549 /* Decide where the menu would be placed if requested at (X,Y). */
3551 void
3552 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3553 int *ulx, int *uly, int *width, int *height)
3555 IT_menu_calc_size (menu, width, height);
3556 *ulx = x + 1;
3557 *uly = y;
3558 *width += 2;
3561 struct IT_menu_state
3563 void *screen_behind;
3564 XMenu *menu;
3565 int pane;
3566 int x, y;
3570 /* Display menu, wait for user's response, and return that response. */
3573 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3574 int x0, int y0, unsigned ButtonMask, char **txt,
3575 void (*help_callback)(char *, int, int))
3577 struct IT_menu_state *state;
3578 int statecount, x, y, i, b, screensize, leave, result, onepane;
3579 int title_faces[4]; /* face to display the menu title */
3580 int faces[4], buffers_num_deleted = 0;
3581 struct frame *sf = SELECTED_FRAME();
3582 Lisp_Object saved_echo_area_message, selectface;
3584 /* Just in case we got here without a mouse present... */
3585 if (have_mouse <= 0)
3586 return XM_IA_SELECT;
3587 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3588 around the display. */
3589 if (x0 <= 0)
3590 x0 = 1;
3591 if (y0 <= 0)
3592 y0 = 1;
3594 /* We will process all the mouse events directly, so we had
3595 better prevent dos_rawgetc from stealing them from us. */
3596 mouse_preempted++;
3598 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3599 screensize = screen_size * 2;
3600 faces[0]
3601 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3602 DEFAULT_FACE_ID, 1);
3603 faces[1]
3604 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3605 DEFAULT_FACE_ID, 1);
3606 selectface = intern ("msdos-menu-select-face");
3607 faces[2] = lookup_derived_face (sf, selectface,
3608 faces[0], 1);
3609 faces[3] = lookup_derived_face (sf, selectface,
3610 faces[1], 1);
3612 /* Make sure the menu title is always displayed with
3613 `msdos-menu-active-face', no matter where the mouse pointer is. */
3614 for (i = 0; i < 4; i++)
3615 title_faces[i] = faces[3];
3617 statecount = 1;
3619 /* Don't let the title for the "Buffers" popup menu include a
3620 digit (which is ugly).
3622 This is a terrible kludge, but I think the "Buffers" case is
3623 the only one where the title includes a number, so it doesn't
3624 seem to be necessary to make this more general. */
3625 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3627 menu->text[0][7] = '\0';
3628 buffers_num_deleted = 1;
3631 /* We need to save the current echo area message, so that we could
3632 restore it below, before we exit. See the commentary below,
3633 before the call to message_with_string. */
3634 saved_echo_area_message = Fcurrent_message ();
3635 state[0].menu = menu;
3636 mouse_off ();
3637 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3639 /* Turn off the cursor. Otherwise it shows through the menu
3640 panes, which is ugly. */
3641 IT_display_cursor (0);
3643 /* Display the menu title. */
3644 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3645 if (buffers_num_deleted)
3646 menu->text[0][7] = ' ';
3647 if ((onepane = menu->count == 1 && menu->submenu[0]))
3649 menu->width = menu->submenu[0]->width;
3650 state[0].menu = menu->submenu[0];
3652 else
3654 state[0].menu = menu;
3656 state[0].x = x0 - 1;
3657 state[0].y = y0;
3658 state[0].pane = onepane;
3660 mouse_last_x = -1; /* A hack that forces display. */
3661 leave = 0;
3662 while (!leave)
3664 if (!mouse_visible) mouse_on ();
3665 mouse_check_moved ();
3666 if (sf->mouse_moved)
3668 sf->mouse_moved = 0;
3669 result = XM_IA_SELECT;
3670 mouse_get_xy (&x, &y);
3671 for (i = 0; i < statecount; i++)
3672 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3674 int dy = y - state[i].y;
3675 if (0 <= dy && dy < state[i].menu->count)
3677 if (!state[i].menu->submenu[dy])
3679 if (state[i].menu->panenumber[dy])
3680 result = XM_SUCCESS;
3681 else
3682 result = XM_IA_SELECT;
3684 *pane = state[i].pane - 1;
3685 *selidx = dy;
3686 /* We hit some part of a menu, so drop extra menus that
3687 have been opened. That does not include an open and
3688 active submenu. */
3689 if (i != statecount - 2
3690 || state[i].menu->submenu[dy] != state[i+1].menu)
3691 while (i != statecount - 1)
3693 statecount--;
3694 mouse_off ();
3695 ScreenUpdate (state[statecount].screen_behind);
3696 if (screen_virtual_segment)
3697 dosv_refresh_virtual_screen (0, screen_size);
3698 xfree (state[statecount].screen_behind);
3700 if (i == statecount - 1 && state[i].menu->submenu[dy])
3702 IT_menu_display (state[i].menu,
3703 state[i].y,
3704 state[i].x,
3705 state[i].pane,
3706 faces, 1);
3707 state[statecount].menu = state[i].menu->submenu[dy];
3708 state[statecount].pane = state[i].menu->panenumber[dy];
3709 mouse_off ();
3710 ScreenRetrieve (state[statecount].screen_behind
3711 = xmalloc (screensize));
3712 state[statecount].x
3713 = state[i].x + state[i].menu->width + 2;
3714 state[statecount].y = y;
3715 statecount++;
3719 IT_menu_display (state[statecount - 1].menu,
3720 state[statecount - 1].y,
3721 state[statecount - 1].x,
3722 state[statecount - 1].pane,
3723 faces, 1);
3725 else
3727 if ((menu_help_message || prev_menu_help_message)
3728 && menu_help_message != prev_menu_help_message)
3730 help_callback (menu_help_message,
3731 menu_help_paneno, menu_help_itemno);
3732 IT_display_cursor (0);
3733 prev_menu_help_message = menu_help_message;
3735 /* We are busy-waiting for the mouse to move, so let's be nice
3736 to other Windows applications by releasing our time slice. */
3737 __dpmi_yield ();
3739 for (b = 0; b < mouse_button_count && !leave; b++)
3741 /* Only leave if user both pressed and released the mouse, and in
3742 that order. This avoids popping down the menu pane unless
3743 the user is really done with it. */
3744 if (mouse_pressed (b, &x, &y))
3746 while (mouse_button_depressed (b, &x, &y))
3747 __dpmi_yield ();
3748 leave = 1;
3750 (void) mouse_released (b, &x, &y);
3754 mouse_off ();
3755 ScreenUpdate (state[0].screen_behind);
3756 if (screen_virtual_segment)
3757 dosv_refresh_virtual_screen (0, screen_size);
3759 /* We have a situation here. ScreenUpdate has just restored the
3760 screen contents as it was before we started drawing this menu.
3761 That includes any echo area message that could have been
3762 displayed back then. (In reality, that echo area message will
3763 almost always be the ``keystroke echo'' that echoes the sequence
3764 of menu items chosen by the user.) However, if the menu had some
3765 help messages, then displaying those messages caused Emacs to
3766 forget about the original echo area message. So when
3767 ScreenUpdate restored it, it created a discrepancy between the
3768 actual screen contents and what Emacs internal data structures
3769 know about it.
3771 To avoid this conflict, we force Emacs to restore the original
3772 echo area message as we found it when we entered this function.
3773 The irony of this is that we then erase the restored message
3774 right away, so the only purpose of restoring it is so that
3775 erasing it works correctly... */
3776 if (! NILP (saved_echo_area_message))
3777 message_with_string ("%s", saved_echo_area_message, 0);
3778 message (0);
3779 while (statecount--)
3780 xfree (state[statecount].screen_behind);
3781 IT_display_cursor (1); /* turn cursor back on */
3782 /* Clean up any mouse events that are waiting inside Emacs event queue.
3783 These events are likely to be generated before the menu was even
3784 displayed, probably because the user pressed and released the button
3785 (which invoked the menu) too quickly. If we don't remove these events,
3786 Emacs will process them after we return and surprise the user. */
3787 discard_mouse_events ();
3788 mouse_clear_clicks ();
3789 if (!kbd_buffer_events_waiting (1))
3790 clear_input_pending ();
3791 /* Allow mouse events generation by dos_rawgetc. */
3792 mouse_preempted--;
3793 return result;
3796 /* Dispose of a menu. */
3798 void
3799 XMenuDestroy (Display *foo, XMenu *menu)
3801 int i;
3802 if (menu->allocated)
3804 for (i = 0; i < menu->count; i++)
3805 if (menu->submenu[i])
3806 XMenuDestroy (foo, menu->submenu[i]);
3807 xfree (menu->text);
3808 xfree (menu->submenu);
3809 xfree (menu->panenumber);
3810 xfree (menu->help_text);
3812 xfree (menu);
3813 menu_help_message = prev_menu_help_message = NULL;
3817 x_pixel_width (struct frame *f)
3819 return FRAME_COLS (f);
3823 x_pixel_height (struct frame *f)
3825 return FRAME_LINES (f);
3827 #endif /* !HAVE_X_WINDOWS */
3829 /* ----------------------- DOS / UNIX conversion --------------------- */
3831 void msdos_downcase_filename (unsigned char *);
3833 /* Destructively turn backslashes into slashes. */
3835 void
3836 dostounix_filename (char *p)
3838 msdos_downcase_filename (p);
3840 while (*p)
3842 if (*p == '\\')
3843 *p = '/';
3844 p++;
3848 /* Destructively turn slashes into backslashes. */
3850 void
3851 unixtodos_filename (char *p)
3853 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3855 *p += 'a' - 'A';
3856 p += 2;
3859 while (*p)
3861 if (*p == '/')
3862 *p = '\\';
3863 p++;
3867 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3870 getdefdir (int drive, char *dst)
3872 char in_path[4], *p = in_path, e = errno;
3874 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3875 if (drive != 0)
3877 *p++ = drive + 'A' - 1;
3878 *p++ = ':';
3881 *p++ = '.';
3882 *p = '\0';
3883 errno = 0;
3884 _fixpath (in_path, dst);
3885 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3886 it queries the LFN support, so ignore that error. */
3887 if ((errno && errno != ENOSYS) || *dst == '\0')
3888 return 0;
3890 msdos_downcase_filename (dst);
3892 errno = e;
3893 return 1;
3896 char *
3897 emacs_root_dir (void)
3899 static char root_dir[4];
3901 sprintf (root_dir, "%c:/", 'A' + getdisk ());
3902 root_dir[0] = tolower (root_dir[0]);
3903 return root_dir;
3906 /* Remove all CR's that are followed by a LF. */
3909 crlf_to_lf (int n, unsigned char *buf)
3911 unsigned char *np = buf, *startp = buf, *endp = buf + n;
3913 if (n == 0)
3914 return n;
3915 while (buf < endp - 1)
3917 if (*buf == 0x0d)
3919 if (*(++buf) != 0x0a)
3920 *np++ = 0x0d;
3922 else
3923 *np++ = *buf++;
3925 if (buf < endp)
3926 *np++ = *buf++;
3927 return np - startp;
3930 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3931 0, 0, 0,
3932 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
3933 (void)
3935 return (_USE_LFN ? Qt : Qnil);
3938 /* Convert alphabetic characters in a filename to lower-case. */
3940 void
3941 msdos_downcase_filename (unsigned char *p)
3943 /* Always lower-case drive letters a-z, even if the filesystem
3944 preserves case in filenames.
3945 This is so MSDOS filenames could be compared by string comparison
3946 functions that are case-sensitive. Even case-preserving filesystems
3947 do not distinguish case in drive letters. */
3948 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3950 *p += 'a' - 'A';
3951 p += 2;
3954 /* Under LFN we expect to get pathnames in their true case. */
3955 if (NILP (Fmsdos_long_file_names ()))
3956 for ( ; *p; p++)
3957 if (*p >= 'A' && *p <= 'Z')
3958 *p += 'a' - 'A';
3961 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3962 1, 1, 0,
3963 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
3964 When long filenames are supported, doesn't change FILENAME.
3965 If FILENAME is not a string, returns nil.
3966 The argument object is never altered--the value is a copy. */)
3967 (Lisp_Object filename)
3969 Lisp_Object tem;
3971 if (! STRINGP (filename))
3972 return Qnil;
3974 tem = Fcopy_sequence (filename);
3975 msdos_downcase_filename (SDATA (tem));
3976 return tem;
3979 /* The Emacs root directory as determined by init_environment. */
3981 static char emacsroot[MAXPATHLEN];
3983 char *
3984 rootrelativepath (char *rel)
3986 static char result[MAXPATHLEN + 10];
3988 strcpy (result, emacsroot);
3989 strcat (result, "/");
3990 strcat (result, rel);
3991 return result;
3994 /* Define a lot of environment variables if not already defined. Don't
3995 remove anything unless you know what you're doing -- lots of code will
3996 break if one or more of these are missing. */
3998 void
3999 init_environment (int argc, char **argv, int skip_args)
4001 char *s, *t, *root;
4002 int len, i;
4003 static const char * const tempdirs[] = {
4004 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4006 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4008 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4009 temporary files and assume "/tmp" if $TMPDIR is unset, which
4010 will break on DOS/Windows. Refuse to work if we cannot find
4011 a directory, not even "c:/", usable for that purpose. */
4012 for (i = 0; i < imax ; i++)
4014 const char *tmp = tempdirs[i];
4015 char buf[FILENAME_MAX];
4017 if (*tmp == '$')
4019 int tmp_len;
4021 tmp = getenv (tmp + 1);
4022 if (!tmp)
4023 continue;
4025 /* Some lusers set TMPDIR=e:, probably because some losing
4026 programs cannot handle multiple slashes if they use e:/.
4027 e: fails in `access' below, so we interpret e: as e:/. */
4028 tmp_len = strlen(tmp);
4029 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4031 strcpy(buf, tmp);
4032 buf[tmp_len++] = '/', buf[tmp_len] = 0;
4033 tmp = buf;
4037 /* Note that `access' can lie to us if the directory resides on a
4038 read-only filesystem, like CD-ROM or a write-protected floppy.
4039 The only way to be really sure is to actually create a file and
4040 see if it succeeds. But I think that's too much to ask. */
4041 if (tmp && access (tmp, D_OK) == 0)
4043 setenv ("TMPDIR", tmp, 1);
4044 break;
4047 if (i >= imax)
4048 cmd_error_internal
4049 (Fcons (Qerror,
4050 Fcons (build_string ("no usable temporary directories found!!"),
4051 Qnil)),
4052 "While setting TMPDIR: ");
4054 /* Note the startup time, so we know not to clear the screen if we
4055 exit immediately; see IT_reset_terminal_modes.
4056 (Yes, I know `clock' returns zero the first time it's called, but
4057 I do this anyway, in case some wiseguy changes that at some point.) */
4058 startup_time = clock ();
4060 /* Find our root from argv[0]. Assuming argv[0] is, say,
4061 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4062 root = alloca (MAXPATHLEN + 20);
4063 _fixpath (argv[0], root);
4064 msdos_downcase_filename (root);
4065 len = strlen (root);
4066 while (len > 0 && root[len] != '/' && root[len] != ':')
4067 len--;
4068 root[len] = '\0';
4069 if (len > 4
4070 && (strcmp (root + len - 4, "/bin") == 0
4071 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4072 root[len - 4] = '\0';
4073 else
4074 strcpy (root, "c:/emacs"); /* let's be defensive */
4075 len = strlen (root);
4076 strcpy (emacsroot, root);
4078 /* We default HOME to our root. */
4079 setenv ("HOME", root, 0);
4081 /* We default EMACSPATH to root + "/bin". */
4082 strcpy (root + len, "/bin");
4083 setenv ("EMACSPATH", root, 0);
4085 /* I don't expect anybody to ever use other terminals so the internal
4086 terminal is the default. */
4087 setenv ("TERM", "internal", 0);
4089 #ifdef HAVE_X_WINDOWS
4090 /* Emacs expects DISPLAY to be set. */
4091 setenv ("DISPLAY", "unix:0.0", 0);
4092 #endif
4094 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4095 downcase it and mirror the backslashes. */
4096 s = getenv ("COMSPEC");
4097 if (!s) s = "c:/command.com";
4098 t = alloca (strlen (s) + 1);
4099 strcpy (t, s);
4100 dostounix_filename (t);
4101 setenv ("SHELL", t, 0);
4103 /* PATH is also downcased and backslashes mirrored. */
4104 s = getenv ("PATH");
4105 if (!s) s = "";
4106 t = alloca (strlen (s) + 3);
4107 /* Current directory is always considered part of MsDos's path but it is
4108 not normally mentioned. Now it is. */
4109 strcat (strcpy (t, ".;"), s);
4110 dostounix_filename (t); /* Not a single file name, but this should work. */
4111 setenv ("PATH", t, 1);
4113 /* In some sense all dos users have root privileges, so... */
4114 setenv ("USER", "root", 0);
4115 setenv ("NAME", getenv ("USER"), 0);
4117 /* Time zone determined from country code. To make this possible, the
4118 country code may not span more than one time zone. In other words,
4119 in the USA, you lose. */
4120 if (!getenv ("TZ"))
4121 switch (dos_country_code)
4123 case 31: /* Belgium */
4124 case 32: /* The Netherlands */
4125 case 33: /* France */
4126 case 34: /* Spain */
4127 case 36: /* Hungary */
4128 case 38: /* Yugoslavia (or what's left of it?) */
4129 case 39: /* Italy */
4130 case 41: /* Switzerland */
4131 case 42: /* Tjekia */
4132 case 45: /* Denmark */
4133 case 46: /* Sweden */
4134 case 47: /* Norway */
4135 case 48: /* Poland */
4136 case 49: /* Germany */
4137 /* Daylight saving from last Sunday in March to last Sunday in
4138 September, both at 2AM. */
4139 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4140 break;
4141 case 44: /* United Kingdom */
4142 case 351: /* Portugal */
4143 case 354: /* Iceland */
4144 setenv ("TZ", "GMT+00", 0);
4145 break;
4146 case 81: /* Japan */
4147 case 82: /* Korea */
4148 setenv ("TZ", "JST-09", 0);
4149 break;
4150 case 90: /* Turkey */
4151 case 358: /* Finland */
4152 setenv ("TZ", "EET-02", 0);
4153 break;
4154 case 972: /* Israel */
4155 /* This is an approximation. (For exact rules, use the
4156 `zoneinfo/israel' file which comes with DJGPP, but you need
4157 to install it in `/usr/share/zoneinfo/' directory first.) */
4158 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4159 break;
4161 tzset ();
4166 static int break_stat; /* BREAK check mode status. */
4167 static int stdin_stat; /* stdin IOCTL status. */
4169 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4170 control chars by DOS. Determine the keyboard type. */
4173 dos_ttraw (struct tty_display_info *tty)
4175 union REGS inregs, outregs;
4176 static int first_time = 1;
4178 /* If we are called for the initial terminal, it's too early to do
4179 anything, and termscript isn't set up. */
4180 if (tty->terminal->type == output_initial)
4181 return 2;
4183 break_stat = getcbrk ();
4184 setcbrk (0);
4186 if (first_time)
4188 inregs.h.ah = 0xc0;
4189 int86 (0x15, &inregs, &outregs);
4190 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4192 have_mouse = 0;
4194 if (1
4195 #ifdef HAVE_X_WINDOWS
4196 && inhibit_window_system
4197 #endif
4200 inregs.x.ax = 0x0021;
4201 int86 (0x33, &inregs, &outregs);
4202 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4203 if (!have_mouse)
4205 /* Reportedly, the above doesn't work for some mouse drivers. There
4206 is an additional detection method that should work, but might be
4207 a little slower. Use that as an alternative. */
4208 inregs.x.ax = 0x0000;
4209 int86 (0x33, &inregs, &outregs);
4210 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4212 if (have_mouse)
4213 mouse_button_count = outregs.x.bx;
4215 #ifndef HAVE_X_WINDOWS
4216 /* Save the cursor shape used outside Emacs. */
4217 outside_cursor = _farpeekw (_dos_ds, 0x460);
4218 #endif
4221 first_time = 0;
4223 stdin_stat = setmode (fileno (stdin), O_BINARY);
4224 return (stdin_stat != -1);
4226 else
4227 return (setmode (fileno (stdin), O_BINARY) != -1);
4230 /* Restore status of standard input and Ctrl-C checking. */
4233 dos_ttcooked (void)
4235 union REGS inregs, outregs;
4237 setcbrk (break_stat);
4238 mouse_off ();
4240 #ifndef HAVE_X_WINDOWS
4241 /* Restore the cursor shape we found on startup. */
4242 if (outside_cursor)
4244 inregs.h.ah = 1;
4245 inregs.x.cx = outside_cursor;
4246 int86 (0x10, &inregs, &outregs);
4248 #endif
4250 return (setmode (fileno (stdin), stdin_stat) != -1);
4254 /* Run command as specified by ARGV in directory DIR.
4255 The command is run with input from TEMPIN, output to
4256 file TEMPOUT and stderr to TEMPERR. */
4259 run_msdos_command (unsigned char **argv, const char *working_dir,
4260 int tempin, int tempout, int temperr, char **envv)
4262 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4263 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4264 int msshell, result = -1, inbak, outbak, errbak, x, y;
4265 Lisp_Object cmd;
4267 /* Get current directory as MSDOS cwd is not per-process. */
4268 getwd (oldwd);
4270 /* If argv[0] is the shell, it might come in any lettercase.
4271 Since `Fmember' is case-sensitive, we need to downcase
4272 argv[0], even if we are on case-preserving filesystems. */
4273 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4274 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4276 *pl = *pa++;
4277 if (*pl >= 'A' && *pl <= 'Z')
4278 *pl += 'a' - 'A';
4280 *pl = '\0';
4282 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4283 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4284 && !strcmp ("-c", argv[1]);
4285 if (msshell)
4287 saveargv1 = argv[1];
4288 saveargv2 = argv[2];
4289 argv[1] = "/c";
4290 /* We only need to mirror slashes if a DOS shell will be invoked
4291 not via `system' (which does the mirroring itself). Yes, that
4292 means DJGPP v1.x will lose here. */
4293 if (argv[2] && argv[3])
4295 char *p = alloca (strlen (argv[2]) + 1);
4297 strcpy (argv[2] = p, saveargv2);
4298 while (*p && isspace (*p))
4299 p++;
4300 while (*p)
4302 if (*p == '/')
4303 *p++ = '\\';
4304 else
4305 p++;
4310 chdir (working_dir);
4311 inbak = dup (0);
4312 outbak = dup (1);
4313 errbak = dup (2);
4314 if (inbak < 0 || outbak < 0 || errbak < 0)
4315 goto done; /* Allocation might fail due to lack of descriptors. */
4317 if (have_mouse > 0)
4318 mouse_get_xy (&x, &y);
4320 if (!noninteractive)
4321 dos_ttcooked (); /* do it here while 0 = stdin */
4323 dup2 (tempin, 0);
4324 dup2 (tempout, 1);
4325 dup2 (temperr, 2);
4327 if (msshell && !argv[3])
4329 /* MS-DOS native shells are too restrictive. For starters, they
4330 cannot grok commands longer than 126 characters. In DJGPP v2
4331 and later, `system' is much smarter, so we'll call it instead. */
4333 const char *cmnd;
4335 /* A shell gets a single argument--its full command
4336 line--whose original was saved in `saveargv2'. */
4338 /* Don't let them pass empty command lines to `system', since
4339 with some shells it will try to invoke an interactive shell,
4340 which will hang Emacs. */
4341 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4343 if (*cmnd)
4345 extern char **environ;
4346 char **save_env = environ;
4347 int save_system_flags = __system_flags;
4349 /* Request the most powerful version of `system'. We need
4350 all the help we can get to avoid calling stock DOS shells. */
4351 __system_flags = (__system_redirect
4352 | __system_use_shell
4353 | __system_allow_multiple_cmds
4354 | __system_allow_long_cmds
4355 | __system_handle_null_commands
4356 | __system_emulate_chdir);
4358 environ = envv;
4359 result = system (cmnd);
4360 __system_flags = save_system_flags;
4361 environ = save_env;
4363 else
4364 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4366 else
4367 result = spawnve (P_WAIT, argv[0], (char **)argv, envv);
4369 dup2 (inbak, 0);
4370 dup2 (outbak, 1);
4371 dup2 (errbak, 2);
4372 emacs_close (inbak);
4373 emacs_close (outbak);
4374 emacs_close (errbak);
4376 if (!noninteractive)
4377 dos_ttraw (CURTTY ());
4378 if (have_mouse > 0)
4380 mouse_init ();
4381 mouse_moveto (x, y);
4384 /* Some programs might change the meaning of the highest bit of the
4385 text attribute byte, so we get blinking characters instead of the
4386 bright background colors. Restore that. */
4387 if (!noninteractive)
4388 bright_bg ();
4390 done:
4391 chdir (oldwd);
4392 if (msshell)
4394 argv[1] = saveargv1;
4395 argv[2] = saveargv2;
4397 return result;
4400 void
4401 croak (char *badfunc)
4403 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4404 reset_all_sys_modes ();
4405 exit (1);
4409 * A few unimplemented functions that we silently ignore.
4411 int setpgrp (void) {return 0; }
4412 int setpriority (int x, int y, int z) { return 0; }
4414 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4416 /* Augment DJGPP library POSIX signal functions. This is needed
4417 as of DJGPP v2.01, but might be in the library in later releases. */
4419 #include <libc/bss.h>
4421 /* A counter to know when to re-initialize the static sets. */
4422 static int sigprocmask_count = -1;
4424 /* Which signals are currently blocked (initially none). */
4425 static sigset_t current_mask;
4427 /* Which signals are pending (initially none). */
4428 static sigset_t msdos_pending_signals;
4430 /* Previous handlers to restore when the blocked signals are unblocked. */
4431 typedef void (*sighandler_t)(int);
4432 static sighandler_t prev_handlers[320];
4434 /* A signal handler which just records that a signal occurred
4435 (it will be raised later, if and when the signal is unblocked). */
4436 static void
4437 sig_suspender (int signo)
4439 sigaddset (&msdos_pending_signals, signo);
4443 sigprocmask (int how, const sigset_t *new_set, sigset_t *old_set)
4445 int signo;
4446 sigset_t new_mask;
4448 /* If called for the first time, initialize. */
4449 if (sigprocmask_count != __bss_count)
4451 sigprocmask_count = __bss_count;
4452 sigemptyset (&msdos_pending_signals);
4453 sigemptyset (&current_mask);
4454 for (signo = 0; signo < 320; signo++)
4455 prev_handlers[signo] = SIG_ERR;
4458 if (old_set)
4459 *old_set = current_mask;
4461 if (new_set == 0)
4462 return 0;
4464 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4466 errno = EINVAL;
4467 return -1;
4470 sigemptyset (&new_mask);
4472 /* DJGPP supports upto 320 signals. */
4473 for (signo = 0; signo < 320; signo++)
4475 if (sigismember (&current_mask, signo))
4476 sigaddset (&new_mask, signo);
4477 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4479 sigaddset (&new_mask, signo);
4481 /* SIGKILL is silently ignored, as on other platforms. */
4482 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4483 prev_handlers[signo] = signal (signo, sig_suspender);
4485 if (( how == SIG_UNBLOCK
4486 && sigismember (&new_mask, signo)
4487 && sigismember (new_set, signo))
4488 || (how == SIG_SETMASK
4489 && sigismember (&new_mask, signo)
4490 && !sigismember (new_set, signo)))
4492 sigdelset (&new_mask, signo);
4493 if (prev_handlers[signo] != SIG_ERR)
4495 signal (signo, prev_handlers[signo]);
4496 prev_handlers[signo] = SIG_ERR;
4498 if (sigismember (&msdos_pending_signals, signo))
4500 sigdelset (&msdos_pending_signals, signo);
4501 raise (signo);
4505 current_mask = new_mask;
4506 return 0;
4509 #endif /* not __DJGPP_MINOR__ < 2 */
4511 #ifndef HAVE_SELECT
4512 #include "sysselect.h"
4514 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4515 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4516 ((long)(time).tv_sec < 0 \
4517 || ((time).tv_sec == 0 \
4518 && (long)(time).tv_usec <= 0))
4519 #endif
4521 /* This yields the rest of the current time slice to the task manager.
4522 It should be called by any code which knows that it has nothing
4523 useful to do except idle.
4525 I don't use __dpmi_yield here, since versions of library before 2.02
4526 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4527 on some versions of Windows 9X. */
4529 void
4530 dos_yield_time_slice (void)
4532 _go32_dpmi_registers r;
4534 r.x.ax = 0x1680;
4535 r.x.ss = r.x.sp = r.x.flags = 0;
4536 _go32_dpmi_simulate_int (0x2f, &r);
4537 if (r.h.al == 0x80)
4538 errno = ENOSYS;
4541 /* Only event queue is checked. */
4542 /* We don't have to call timer_check here
4543 because wait_reading_process_output takes care of that. */
4545 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
4546 EMACS_TIME *timeout)
4548 int check_input;
4549 struct time t;
4551 check_input = 0;
4552 if (rfds)
4554 check_input = FD_ISSET (0, rfds);
4555 FD_ZERO (rfds);
4557 if (wfds)
4558 FD_ZERO (wfds);
4559 if (efds)
4560 FD_ZERO (efds);
4562 if (nfds != 1)
4563 abort ();
4565 /* If we are looking only for the terminal, with no timeout,
4566 just read it and wait -- that's more efficient. */
4567 if (!timeout)
4569 while (!detect_input_pending ())
4571 dos_yield_time_slice ();
4574 else
4576 EMACS_TIME clnow, cllast, cldiff;
4578 gettime (&t);
4579 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4581 while (!check_input || !detect_input_pending ())
4583 gettime (&t);
4584 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4585 EMACS_SUB_TIME (cldiff, clnow, cllast);
4587 /* When seconds wrap around, we assume that no more than
4588 1 minute passed since last `gettime'. */
4589 if (EMACS_TIME_NEG_P (cldiff))
4590 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4591 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4593 /* Stop when timeout value crosses zero. */
4594 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4595 return 0;
4596 cllast = clnow;
4597 dos_yield_time_slice ();
4601 FD_SET (0, rfds);
4602 return 1;
4604 #endif
4607 * Define overlaid functions:
4609 * chdir -> sys_chdir
4610 * tzset -> init_gettimeofday
4611 * abort -> dos_abort
4614 #ifdef chdir
4615 #undef chdir
4616 extern int chdir (const char *);
4619 sys_chdir (const char *path)
4621 int len = strlen (path);
4622 char *tmp = (char *)path;
4624 if (*tmp && tmp[1] == ':')
4626 if (getdisk () != tolower (tmp[0]) - 'a')
4627 setdisk (tolower (tmp[0]) - 'a');
4628 tmp += 2; /* strip drive: KFS 1995-07-06 */
4629 len -= 2;
4632 if (len > 1 && (tmp[len - 1] == '/'))
4634 char *tmp1 = (char *) alloca (len + 1);
4635 strcpy (tmp1, tmp);
4636 tmp1[len - 1] = 0;
4637 tmp = tmp1;
4639 return chdir (tmp);
4641 #endif
4643 #ifdef tzset
4644 #undef tzset
4645 extern void tzset (void);
4647 void
4648 init_gettimeofday (void)
4650 time_t ltm, gtm;
4651 struct tm *lstm;
4653 tzset ();
4654 ltm = gtm = time (NULL);
4655 ltm = mktime (lstm = localtime (&ltm));
4656 gtm = mktime (gmtime (&gtm));
4657 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4658 time_rec.tm_isdst = lstm->tm_isdst;
4659 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4661 #endif
4663 #ifdef abort
4664 #undef abort
4665 void
4666 dos_abort (char *file, int line)
4668 char buffer1[200], buffer2[400];
4669 int i, j;
4671 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4672 for (i = j = 0; buffer1[i]; i++) {
4673 buffer2[j++] = buffer1[i];
4674 buffer2[j++] = 0x70;
4676 dosmemput (buffer2, j, (int)ScreenPrimary);
4677 ScreenSetCursor (2, 0);
4678 abort ();
4680 #else
4681 void
4682 abort (void)
4684 dos_ttcooked ();
4685 ScreenSetCursor (10, 0);
4686 cputs ("\r\n\nEmacs aborted!\r\n");
4687 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4688 if (screen_virtual_segment)
4689 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4690 /* Generate traceback, so we could tell whodunit. */
4691 signal (SIGINT, SIG_DFL);
4692 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4693 #else /* __DJGPP_MINOR__ >= 2 */
4694 raise (SIGABRT);
4695 #endif /* __DJGPP_MINOR__ >= 2 */
4696 exit (2);
4698 #endif
4700 void
4701 syms_of_msdos (void)
4703 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4704 staticpro (&recent_doskeys);
4706 #ifndef HAVE_X_WINDOWS
4708 /* The following two are from xfns.c: */
4709 Qreverse = intern ("reverse");
4710 staticpro (&Qreverse);
4712 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4713 doc: /* *Glyph to display instead of chars not supported by current codepage.
4714 This variable is used only by MS-DOS terminals. */);
4715 Vdos_unsupported_char_glyph = make_number ('\177');
4717 #endif
4719 defsubr (&Srecent_doskeys);
4720 defsubr (&Smsdos_long_file_names);
4721 defsubr (&Smsdos_downcase_filename);
4722 defsubr (&Smsdos_remember_default_colors);
4723 defsubr (&Smsdos_set_mouse_buttons);
4726 #endif /* MSDOS */
4728 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
4729 (do not change this comment) */