Merge from mainline.
[emacs.git] / src / msdos.c
blob75cc7605f3cc481d57c0f04d06bb38164cc2e43c
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, 2011
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 <time.h>
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <dos.h>
36 #include <errno.h>
37 #include <sys/stat.h> /* for _fixpath */
38 #include <unistd.h> /* for chdir, dup, dup2, etc. */
39 #include <dir.h> /* for getdisk */
40 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
41 #include <fcntl.h>
42 #include <io.h> /* for setmode */
43 #include <dpmi.h> /* for __dpmi_xxx stuff */
44 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
45 #include <libc/dosio.h> /* for _USE_LFN */
46 #include <conio.h> /* for cputs */
48 #include "msdos.h"
49 #include "systime.h"
50 #include "frame.h"
51 #include "termhooks.h"
52 #include "termchar.h"
53 #include "dispextern.h"
54 #include "dosfns.h"
55 #include "termopts.h"
56 #include "character.h"
57 #include "coding.h"
58 #include "disptab.h"
59 #include "window.h"
60 #include "buffer.h"
61 #include "commands.h"
62 #include "blockinput.h"
63 #include "keyboard.h"
64 #include "intervals.h"
65 #include <go32.h>
66 #include <pc.h>
67 #include <ctype.h>
68 /* #include <process.h> */
69 /* Damn that local process.h! Instead we can define P_WAIT and
70 spawnve ourselves. */
71 #define P_WAIT 1
72 extern int spawnve (int, const char *, char *const [], char *const []);
74 #ifndef _USE_LFN
75 #define _USE_LFN 0
76 #endif
78 #ifndef _dos_ds
79 #define _dos_ds _go32_info_block.selector_for_linear_memory
80 #endif
82 #include <signal.h>
83 #include "syssignal.h"
85 #ifndef SYSTEM_MALLOC
87 #ifdef GNU_MALLOC
89 /* If other `malloc' than ours is used, force our `sbrk' behave like
90 Unix programs expect (resize memory blocks to keep them contiguous).
91 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
92 because that's what `gmalloc' expects to get. */
93 #include <crt0.h>
95 #ifdef REL_ALLOC
96 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
97 #else /* not REL_ALLOC */
98 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
99 #endif /* not REL_ALLOC */
100 #endif /* GNU_MALLOC */
102 #endif /* not SYSTEM_MALLOC */
104 static unsigned long
105 event_timestamp (void)
107 struct time t;
108 unsigned long s;
110 gettime (&t);
111 s = t.ti_min;
112 s *= 60;
113 s += t.ti_sec;
114 s *= 1000;
115 s += t.ti_hund * 10;
117 return s;
121 /* ------------------------ Mouse control ---------------------------
123 * Coordinates are in screen positions and zero based.
124 * Mouse buttons are numbered from left to right and also zero based.
127 /* This used to be in termhooks.h, but mainstream Emacs code no longer
128 uses it, and it was removed... */
129 #define NUM_MOUSE_BUTTONS (5)
131 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
132 static int mouse_visible;
134 static int mouse_last_x;
135 static int mouse_last_y;
137 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
138 static int mouse_button_count;
140 void
141 mouse_on (void)
143 union REGS regs;
145 if (have_mouse > 0 && !mouse_visible)
147 struct tty_display_info *tty = CURTTY ();
149 if (tty->termscript)
150 fprintf (tty->termscript, "<M_ON>");
151 regs.x.ax = 0x0001;
152 int86 (0x33, &regs, &regs);
153 mouse_visible = 1;
157 void
158 mouse_off (void)
160 union REGS regs;
162 if (have_mouse > 0 && mouse_visible)
164 struct tty_display_info *tty = CURTTY ();
166 if (tty->termscript)
167 fprintf (tty->termscript, "<M_OFF>");
168 regs.x.ax = 0x0002;
169 int86 (0x33, &regs, &regs);
170 mouse_visible = 0;
174 static void
175 mouse_setup_buttons (int n_buttons)
177 if (n_buttons == 3)
179 mouse_button_count = 3;
180 mouse_button_translate[0] = 0; /* Left */
181 mouse_button_translate[1] = 2; /* Middle */
182 mouse_button_translate[2] = 1; /* Right */
184 else /* two, what else? */
186 mouse_button_count = 2;
187 mouse_button_translate[0] = 0;
188 mouse_button_translate[1] = 1;
192 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
193 1, 1, "NSet number of mouse buttons to: ",
194 doc: /* Set the number of mouse buttons to use by Emacs.
195 This is useful with mice that report the number of buttons inconsistently,
196 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
197 them. This happens with wheeled mice on Windows 9X, for example. */)
198 (Lisp_Object nbuttons)
200 int n;
202 CHECK_NUMBER (nbuttons);
203 n = XINT (nbuttons);
204 if (n < 2 || n > 3)
205 xsignal2 (Qargs_out_of_range,
206 build_string ("only 2 or 3 mouse buttons are supported"),
207 nbuttons);
208 mouse_setup_buttons (n);
209 return Qnil;
212 static void
213 mouse_get_xy (int *x, int *y)
215 union REGS regs;
217 regs.x.ax = 0x0003;
218 int86 (0x33, &regs, &regs);
219 *x = regs.x.cx / 8;
220 *y = regs.x.dx / 8;
223 void
224 mouse_moveto (int x, int y)
226 union REGS regs;
227 struct tty_display_info *tty = CURTTY ();
229 if (tty->termscript)
230 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
231 regs.x.ax = 0x0004;
232 mouse_last_x = regs.x.cx = x * 8;
233 mouse_last_y = regs.x.dx = y * 8;
234 int86 (0x33, &regs, &regs);
237 static int
238 mouse_pressed (int b, int *xp, int *yp)
240 union REGS regs;
242 if (b >= mouse_button_count)
243 return 0;
244 regs.x.ax = 0x0005;
245 regs.x.bx = mouse_button_translate[b];
246 int86 (0x33, &regs, &regs);
247 if (regs.x.bx)
248 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
249 return (regs.x.bx != 0);
252 static int
253 mouse_released (int b, int *xp, int *yp)
255 union REGS regs;
257 if (b >= mouse_button_count)
258 return 0;
259 regs.x.ax = 0x0006;
260 regs.x.bx = mouse_button_translate[b];
261 int86 (0x33, &regs, &regs);
262 if (regs.x.bx)
263 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
264 return (regs.x.bx != 0);
267 static int
268 mouse_button_depressed (int b, int *xp, int *yp)
270 union REGS regs;
272 if (b >= mouse_button_count)
273 return 0;
274 regs.x.ax = 0x0003;
275 int86 (0x33, &regs, &regs);
276 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
278 *xp = regs.x.cx / 8;
279 *yp = regs.x.dx / 8;
280 return 1;
282 return 0;
285 void
286 mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
287 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
288 unsigned long *time)
290 int ix, iy;
291 Lisp_Object frame, tail;
293 /* Clear the mouse-moved flag for every frame on this display. */
294 FOR_EACH_FRAME (tail, frame)
295 XFRAME (frame)->mouse_moved = 0;
297 *f = SELECTED_FRAME();
298 *bar_window = Qnil;
299 mouse_get_xy (&ix, &iy);
300 *time = event_timestamp ();
301 *x = make_number (mouse_last_x = ix);
302 *y = make_number (mouse_last_y = iy);
305 static void
306 mouse_check_moved (void)
308 int x, y;
310 mouse_get_xy (&x, &y);
311 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
312 mouse_last_x = x;
313 mouse_last_y = y;
316 /* Force the mouse driver to ``forget'' about any button clicks until
317 now. */
318 static void
319 mouse_clear_clicks (void)
321 int b;
323 for (b = 0; b < mouse_button_count; b++)
325 int dummy_x, dummy_y;
327 (void) mouse_pressed (b, &dummy_x, &dummy_y);
328 (void) mouse_released (b, &dummy_x, &dummy_y);
332 void
333 mouse_init (void)
335 union REGS regs;
336 struct tty_display_info *tty = CURTTY ();
338 if (tty->termscript)
339 fprintf (tty->termscript, "<M_INIT>");
341 regs.x.ax = 0x0021;
342 int86 (0x33, &regs, &regs);
344 /* Reset the mouse last press/release info. It seems that Windows
345 doesn't do that automatically when function 21h is called, which
346 causes Emacs to ``remember'' the click that switched focus to the
347 window just before Emacs was started from that window. */
348 mouse_clear_clicks ();
350 regs.x.ax = 0x0007;
351 regs.x.cx = 0;
352 regs.x.dx = 8 * (ScreenCols () - 1);
353 int86 (0x33, &regs, &regs);
355 regs.x.ax = 0x0008;
356 regs.x.cx = 0;
357 regs.x.dx = 8 * (ScreenRows () - 1);
358 int86 (0x33, &regs, &regs);
360 mouse_moveto (0, 0);
361 mouse_visible = 0;
364 /* ------------------------- Screen control ----------------------
368 static int internal_terminal = 0;
370 #ifndef HAVE_X_WINDOWS
371 extern unsigned char ScreenAttrib;
372 static int screen_face;
374 static int screen_size_X;
375 static int screen_size_Y;
376 static int screen_size;
378 static int current_pos_X;
379 static int current_pos_Y;
380 static int new_pos_X;
381 static int new_pos_Y;
383 static void *startup_screen_buffer;
384 static int startup_screen_size_X;
385 static int startup_screen_size_Y;
386 static int startup_pos_X;
387 static int startup_pos_Y;
388 static unsigned char startup_screen_attrib;
390 static clock_t startup_time;
392 static int term_setup_done;
394 static unsigned short outside_cursor;
396 /* Similar to the_only_frame. */
397 struct tty_display_info the_only_display_info;
399 /* Support for DOS/V (allows Japanese characters to be displayed on
400 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
402 /* Holds the address of the text-mode screen buffer. */
403 static unsigned long screen_old_address = 0;
404 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
405 static unsigned short screen_virtual_segment = 0;
406 static unsigned short screen_virtual_offset = 0;
407 extern Lisp_Object Qcursor_type;
408 extern Lisp_Object Qbar, Qhbar;
410 /* The screen colors of the current frame, which serve as the default
411 colors for newly-created frames. */
412 static int initial_screen_colors[2];
414 /* Update the screen from a part of relocated DOS/V screen buffer which
415 begins at OFFSET and includes COUNT characters. */
416 static void
417 dosv_refresh_virtual_screen (int offset, int count)
419 __dpmi_regs regs;
421 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
422 return;
424 regs.h.ah = 0xff; /* update relocated screen */
425 regs.x.es = screen_virtual_segment;
426 regs.x.di = screen_virtual_offset + offset;
427 regs.x.cx = count;
428 __dpmi_int (0x10, &regs);
431 static void
432 dos_direct_output (int y, int x, char *buf, int len)
434 int t0 = 2 * (x + y * screen_size_X);
435 int t = t0 + (int) ScreenPrimary;
436 int l0 = len;
438 /* This is faster. */
439 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
440 _farnspokeb (t, *buf);
442 if (screen_virtual_segment)
443 dosv_refresh_virtual_screen (t0, l0);
445 #endif
447 #ifndef HAVE_X_WINDOWS
449 static int blink_bit = -1; /* the state of the blink bit at startup */
451 /* Enable bright background colors. */
452 static void
453 bright_bg (void)
455 union REGS regs;
457 /* Remember the original state of the blink/bright-background bit.
458 It is stored at 0040:0065h in the BIOS data area. */
459 if (blink_bit == -1)
460 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
462 regs.h.bl = 0;
463 regs.x.ax = 0x1003;
464 int86 (0x10, &regs, &regs);
467 /* Disable bright background colors (and enable blinking) if we found
468 the video system in that state at startup. */
469 static void
470 maybe_enable_blinking (void)
472 if (blink_bit == 1)
474 union REGS regs;
476 regs.h.bl = 1;
477 regs.x.ax = 0x1003;
478 int86 (0x10, &regs, &regs);
482 /* Return non-zero if the system has a VGA adapter. */
483 static int
484 vga_installed (void)
486 union REGS regs;
488 regs.x.ax = 0x1a00;
489 int86 (0x10, &regs, &regs);
490 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
491 return 1;
492 return 0;
495 /* Set the screen dimensions so that it can show no less than
496 ROWS x COLS frame. */
498 void
499 dos_set_window_size (int *rows, int *cols)
501 char video_name[30];
502 union REGS regs;
503 Lisp_Object video_mode;
504 int video_mode_value, have_vga = 0;
505 int current_rows = ScreenRows (), current_cols = ScreenCols ();
507 if (*rows == current_rows && *cols == current_cols)
508 return;
510 mouse_off ();
511 have_vga = vga_installed ();
513 /* If the user specified a special video mode for these dimensions,
514 use that mode. */
515 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
516 video_mode = Fsymbol_value (Fintern_soft (build_string (video_name), Qnil));
518 if (INTEGERP (video_mode)
519 && (video_mode_value = XINT (video_mode)) > 0)
521 regs.x.ax = video_mode_value;
522 int86 (0x10, &regs, &regs);
524 if (have_mouse)
526 /* Must hardware-reset the mouse, or else it won't update
527 its notion of screen dimensions for some non-standard
528 video modes. This is *painfully* slow... */
529 regs.x.ax = 0;
530 int86 (0x33, &regs, &regs);
534 /* Find one of the dimensions supported by standard EGA/VGA
535 which gives us at least the required dimensions. */
536 else
538 static struct {
539 int rows, need_vga;
540 } std_dimension[] = {
541 {25, 0},
542 {28, 1},
543 {35, 0},
544 {40, 1},
545 {43, 0},
546 {50, 1}
548 int i = 0;
550 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
552 if (std_dimension[i].need_vga <= have_vga
553 && std_dimension[i].rows >= *rows)
555 if (std_dimension[i].rows != current_rows
556 || *cols != current_cols)
557 _set_screen_lines (std_dimension[i].rows);
558 break;
560 i++;
565 if (have_mouse)
567 mouse_init ();
568 mouse_on ();
571 /* Tell the caller what dimensions have been REALLY set. */
572 *rows = ScreenRows ();
573 *cols = ScreenCols ();
575 /* Update Emacs' notion of screen dimensions. */
576 screen_size_X = *cols;
577 screen_size_Y = *rows;
578 screen_size = *cols * *rows;
580 /* If the dimensions changed, the mouse highlight info is invalid. */
581 if (current_rows != *rows || current_cols != *cols)
583 struct frame *f = SELECTED_FRAME();
584 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
585 Lisp_Object window = hlinfo->mouse_face_window;
587 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
589 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
590 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
591 hlinfo->mouse_face_window = Qnil;
595 /* Enable bright background colors. */
596 bright_bg ();
598 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
599 be defensive anyway. */
600 if (screen_virtual_segment)
601 dosv_refresh_virtual_screen (0, *cols * *rows);
604 /* If we write a character in the position where the mouse is,
605 the mouse cursor may need to be refreshed. */
607 static void
608 mouse_off_maybe (void)
610 int x, y;
612 if (!mouse_visible)
613 return;
615 mouse_get_xy (&x, &y);
616 if (y != new_pos_Y || x < new_pos_X)
617 return;
619 mouse_off ();
622 #define DEFAULT_CURSOR_START (-1)
623 #define DEFAULT_CURSOR_WIDTH (-1)
624 #define BOX_CURSOR_WIDTH (-32)
626 /* Set cursor to begin at scan line START_LINE in the character cell
627 and extend for WIDTH scan lines. Scan lines are counted from top
628 of the character cell, starting from zero. */
629 static void
630 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
632 unsigned desired_cursor;
633 __dpmi_regs regs;
634 int max_line, top_line, bot_line;
635 struct tty_display_info *tty = FRAME_TTY (f);
637 /* Avoid the costly BIOS call if F isn't the currently selected
638 frame. Allow for NULL as unconditionally meaning the selected
639 frame. */
640 if (f && f != SELECTED_FRAME())
641 return;
643 if (tty->termscript)
644 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
646 /* The character cell size in scan lines is stored at 40:85 in the
647 BIOS data area. */
648 max_line = _farpeekw (_dos_ds, 0x485) - 1;
649 switch (max_line)
651 default: /* this relies on CGA cursor emulation being ON! */
652 case 7:
653 bot_line = 7;
654 break;
655 case 9:
656 bot_line = 9;
657 break;
658 case 13:
659 bot_line = 12;
660 break;
661 case 15:
662 bot_line = 14;
663 break;
666 if (width < 0)
668 if (width == BOX_CURSOR_WIDTH)
670 top_line = 0;
671 bot_line = max_line;
673 else if (start_line != DEFAULT_CURSOR_START)
675 top_line = start_line;
676 bot_line = top_line - width - 1;
678 else if (width != DEFAULT_CURSOR_WIDTH)
680 top_line = 0;
681 bot_line = -1 - width;
683 else
684 top_line = bot_line + 1;
686 else if (width == 0)
688 /* [31, 0] seems to DTRT for all screen sizes. */
689 top_line = 31;
690 bot_line = 0;
692 else /* WIDTH is positive */
694 if (start_line != DEFAULT_CURSOR_START)
695 bot_line = start_line;
696 top_line = bot_line - (width - 1);
699 /* If the current cursor shape is already what they want, we are
700 history here. */
701 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
702 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
703 return;
705 regs.h.ah = 1;
706 regs.x.cx = desired_cursor;
707 __dpmi_int (0x10, &regs);
710 static void
711 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
713 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
715 /* Just BAR means the normal EGA/VGA cursor. */
716 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
718 else if (CONSP (cursor_type)
719 && (EQ (XCAR (cursor_type), Qbar)
720 || EQ (XCAR (cursor_type), Qhbar)))
722 Lisp_Object bar_parms = XCDR (cursor_type);
723 int width;
725 if (INTEGERP (bar_parms))
727 /* Feature: negative WIDTH means cursor at the top
728 of the character cell, zero means invisible cursor. */
729 width = XINT (bar_parms);
730 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
731 width);
733 else if (CONSP (bar_parms)
734 && INTEGERP (XCAR (bar_parms))
735 && INTEGERP (XCDR (bar_parms)))
737 int start_line = XINT (XCDR (bar_parms));
739 width = XINT (XCAR (bar_parms));
740 msdos_set_cursor_shape (f, start_line, width);
743 else
745 /* Treat anything unknown as "box cursor". This includes nil, so
746 that a frame which doesn't specify a cursor type gets a box,
747 which is the default in Emacs. */
748 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
752 static void
753 IT_ring_bell (struct frame *f)
755 if (visible_bell)
757 mouse_off ();
758 ScreenVisualBell ();
760 else
762 union REGS inregs, outregs;
763 inregs.h.ah = 2;
764 inregs.h.dl = 7;
765 intdos (&inregs, &outregs);
769 /* Given a face id FACE, extract the face parameters to be used for
770 display until the face changes. The face parameters (actually, its
771 color) are used to construct the video attribute byte for each
772 glyph during the construction of the buffer that is then blitted to
773 the video RAM. */
774 static void
775 IT_set_face (int face)
777 struct frame *sf = SELECTED_FRAME();
778 struct face *fp = FACE_FROM_ID (sf, face);
779 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
780 unsigned long fg, bg, dflt_fg, dflt_bg;
781 struct tty_display_info *tty = FRAME_TTY (sf);
783 if (!fp)
785 fp = dfp;
786 /* The default face for the frame should always be realized and
787 cached. */
788 if (!fp)
789 abort ();
791 screen_face = face;
792 fg = fp->foreground;
793 bg = fp->background;
794 dflt_fg = dfp->foreground;
795 dflt_bg = dfp->background;
797 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
798 mean use the colors of the default face. Note that we assume all
799 16 colors to be available for the background, since Emacs switches
800 on this mode (and loses the blinking attribute) at startup. */
801 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
802 fg = FRAME_FOREGROUND_PIXEL (sf);
803 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
804 fg = FRAME_BACKGROUND_PIXEL (sf);
805 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
806 bg = FRAME_BACKGROUND_PIXEL (sf);
807 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
808 bg = FRAME_FOREGROUND_PIXEL (sf);
810 /* Make sure highlighted lines really stand out, come what may. */
811 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
813 unsigned long tem = fg;
815 fg = bg;
816 bg = tem;
818 /* If the user requested inverse video, obey. */
819 if (inverse_video)
821 unsigned long tem2 = fg;
823 fg = bg;
824 bg = tem2;
826 if (tty->termscript)
827 fprintf (tty->termscript, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face,
828 fp->foreground, fp->background, fg, bg);
829 if (fg >= 0 && fg < 16)
831 ScreenAttrib &= 0xf0;
832 ScreenAttrib |= fg;
834 if (bg >= 0 && bg < 16)
836 ScreenAttrib &= 0x0f;
837 ScreenAttrib |= ((bg & 0x0f) << 4);
841 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
842 width of a DOS display in any known text mode. We multiply by 2 to
843 accomodate the screen attribute byte. */
844 #define MAX_SCREEN_BUF 160*2
846 extern unsigned char *encode_terminal_code (struct glyph *, int,
847 struct coding_system *);
848 static void
849 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
851 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
852 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
853 register int sl = str_len;
854 struct tty_display_info *tty = FRAME_TTY (f);
855 struct frame *sf;
856 unsigned char *conversion_buffer;
858 /* If terminal_coding does any conversion, use it, otherwise use
859 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
860 because it always returns 1 if terminal_coding.src_multibyte is 1. */
861 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
863 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
864 coding = &safe_terminal_coding;
866 if (str_len <= 0) return;
868 sf = SELECTED_FRAME();
870 /* Since faces get cached and uncached behind our back, we can't
871 rely on their indices in the cache being consistent across
872 invocations. So always reset the screen face to the default
873 face of the frame, before writing glyphs, and let the glyphs
874 set the right face if it's different from the default. */
875 IT_set_face (DEFAULT_FACE_ID);
877 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
878 the tail. */
879 coding->mode &= ~CODING_MODE_LAST_BLOCK;
880 screen_bp = &screen_buf[0];
881 while (sl > 0)
883 int cf;
884 int n;
886 /* If the face of this glyph is different from the current
887 screen face, update the screen attribute byte. */
888 cf = str->face_id;
889 if (cf != screen_face)
890 IT_set_face (cf); /* handles invalid faces gracefully */
892 /* Identify a run of glyphs with the same face. */
893 for (n = 1; n < sl; ++n)
894 if (str[n].face_id != cf)
895 break;
897 if (n >= sl)
898 /* This is the last glyph. */
899 coding->mode |= CODING_MODE_LAST_BLOCK;
901 conversion_buffer = encode_terminal_code (str, n, coding);
902 if (coding->produced > 0)
904 /* Copy the encoded bytes to the screen buffer. */
905 for (bp = conversion_buffer; coding->produced--; bp++)
907 /* Paranoia: discard bytes that would overrun the end of
908 the screen buffer. */
909 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
911 *screen_bp++ = (unsigned char)*bp;
912 *screen_bp++ = ScreenAttrib;
914 if (tty->termscript)
915 fputc (*bp, tty->termscript);
918 /* Update STR and its remaining length. */
919 str += n;
920 sl -= n;
923 /* Dump whatever we have in the screen buffer. */
924 mouse_off_maybe ();
925 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
926 if (screen_virtual_segment)
927 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
928 new_pos_X += (screen_bp - screen_buf) / 2;
931 /************************************************************************
932 Mouse Highlight (and friends..)
933 ************************************************************************/
935 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
936 static Lisp_Object last_mouse_window;
938 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
941 popup_activated (void)
943 return mouse_preempted;
946 /* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
947 window W. X is relative to TEXT_AREA in W. HL is a face override
948 for drawing the glyphs. */
949 void
950 tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
951 int start_hpos, int end_hpos,
952 enum draw_glyphs_face hl)
954 struct frame *f = XFRAME (WINDOW_FRAME (w));
955 struct tty_display_info *tty = FRAME_TTY (f);
956 Mouse_HLInfo *hlinfo = &tty->mouse_highlight;
958 if (hl == DRAW_MOUSE_FACE)
960 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
961 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
962 int nglyphs = end_hpos - start_hpos;
963 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
964 int start_offset = offset;
966 if (tty->termscript)
967 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
968 kstart, kstart + nglyphs - 1, vpos);
970 mouse_off ();
971 IT_set_face (hlinfo->mouse_face_face_id);
972 /* Since we are going to change only the _colors_ of already
973 displayed text, there's no need to go through all the pain of
974 generating and encoding the text from the glyphs. Instead,
975 we simply poke the attribute byte of each affected position
976 in video memory with the colors computed by IT_set_face! */
977 _farsetsel (_dos_ds);
978 while (nglyphs--)
980 _farnspokeb (offset, ScreenAttrib);
981 offset += 2;
983 if (screen_virtual_segment)
984 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
985 mouse_on ();
987 else if (hl == DRAW_NORMAL_TEXT)
989 /* We are removing a previously-drawn mouse highlight. The
990 safest way to do so is to redraw the glyphs anew, since all
991 kinds of faces and display tables could have changed behind
992 our back. */
993 int nglyphs = end_hpos - start_hpos;
994 int save_x = new_pos_X, save_y = new_pos_Y;
996 if (end_hpos >= row->used[TEXT_AREA])
997 nglyphs = row->used[TEXT_AREA] - start_hpos;
999 /* IT_write_glyphs writes at cursor position, so we need to
1000 temporarily move cursor coordinates to the beginning of
1001 the highlight region. */
1002 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1003 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1005 if (tty->termscript)
1006 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1007 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1008 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1009 if (tty->termscript)
1010 fputs ("\n", tty->termscript);
1011 new_pos_X = save_x;
1012 new_pos_Y = save_y;
1016 static void
1017 IT_clear_end_of_line (struct frame *f, int first_unused)
1019 char *spaces, *sp;
1020 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1021 extern int fatal_error_in_progress;
1022 struct tty_display_info *tty = FRAME_TTY (f);
1024 if (new_pos_X >= first_unused || fatal_error_in_progress)
1025 return;
1027 IT_set_face (0);
1028 i = (j = first_unused - new_pos_X) * 2;
1029 if (tty->termscript)
1030 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1031 spaces = sp = alloca (i);
1033 while (--j >= 0)
1035 *sp++ = ' ';
1036 *sp++ = ScreenAttrib;
1039 mouse_off_maybe ();
1040 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1041 if (screen_virtual_segment)
1042 dosv_refresh_virtual_screen (offset, i / 2);
1044 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1045 Let's follow their lead, in case someone relies on this. */
1046 new_pos_X = first_unused;
1049 static void
1050 IT_clear_screen (struct frame *f)
1052 struct tty_display_info *tty = FRAME_TTY (f);
1054 if (tty->termscript)
1055 fprintf (tty->termscript, "<CLR:SCR>");
1056 /* We are sometimes called (from clear_garbaged_frames) when a new
1057 frame is being created, but its faces are not yet realized. In
1058 such a case we cannot call IT_set_face, since it will fail to find
1059 any valid faces and will abort. Instead, use the initial screen
1060 colors; that should mimic what a Unix tty does, which simply clears
1061 the screen with whatever default colors are in use. */
1062 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1063 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1064 else
1065 IT_set_face (0);
1066 mouse_off ();
1067 ScreenClear ();
1068 if (screen_virtual_segment)
1069 dosv_refresh_virtual_screen (0, screen_size);
1070 new_pos_X = new_pos_Y = 0;
1073 static void
1074 IT_clear_to_end (struct frame *f)
1076 struct tty_display_info *tty = FRAME_TTY (f);
1078 if (tty->termscript)
1079 fprintf (tty->termscript, "<CLR:EOS>");
1081 while (new_pos_Y < screen_size_Y) {
1082 new_pos_X = 0;
1083 IT_clear_end_of_line (f, screen_size_X);
1084 new_pos_Y++;
1088 static void
1089 IT_cursor_to (struct frame *f, int y, int x)
1091 struct tty_display_info *tty = FRAME_TTY (f);
1093 if (tty->termscript)
1094 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1095 new_pos_X = x;
1096 new_pos_Y = y;
1099 static int cursor_cleared;
1101 static void
1102 IT_display_cursor (int on)
1104 struct tty_display_info *tty = CURTTY ();
1106 if (on && cursor_cleared)
1108 ScreenSetCursor (current_pos_Y, current_pos_X);
1109 cursor_cleared = 0;
1110 if (tty->termscript)
1111 fprintf (tty->termscript, "\nCURSOR ON (%dx%d)",
1112 current_pos_Y, current_pos_X);
1114 else if (!on && !cursor_cleared)
1116 ScreenSetCursor (-1, -1);
1117 cursor_cleared = 1;
1118 if (tty->termscript)
1119 fprintf (tty->termscript, "\nCURSOR OFF (%dx%d)",
1120 current_pos_Y, current_pos_X);
1124 /* Emacs calls cursor-movement functions a lot when it updates the
1125 display (probably a legacy of old terminals where you cannot
1126 update a screen line without first moving the cursor there).
1127 However, cursor movement is expensive on MSDOS (it calls a slow
1128 BIOS function and requires 2 mode switches), while actual screen
1129 updates access the video memory directly and don't depend on
1130 cursor position. To avoid slowing down the redisplay, we cheat:
1131 all functions that move the cursor only set internal variables
1132 which record the cursor position, whereas the cursor is only
1133 moved to its final position whenever screen update is complete.
1135 `IT_cmgoto' is called from the keyboard reading loop and when the
1136 frame update is complete. This means that we are ready for user
1137 input, so we update the cursor position to show where the point is,
1138 and also make the mouse pointer visible.
1140 Special treatment is required when the cursor is in the echo area,
1141 to put the cursor at the end of the text displayed there. */
1143 static void
1144 IT_cmgoto (FRAME_PTR f)
1146 /* Only set the cursor to where it should be if the display is
1147 already in sync with the window contents. */
1148 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1149 struct tty_display_info *tty = FRAME_TTY (f);
1151 /* FIXME: This needs to be rewritten for the new redisplay, or
1152 removed. */
1153 #if 0
1154 static int previous_pos_X = -1;
1156 update_cursor_pos = 1; /* temporary!!! */
1158 /* If the display is in sync, forget any previous knowledge about
1159 cursor position. This is primarily for unexpected events like
1160 C-g in the minibuffer. */
1161 if (update_cursor_pos && previous_pos_X >= 0)
1162 previous_pos_X = -1;
1163 /* If we are in the echo area, put the cursor at the
1164 end of the echo area message. */
1165 if (!update_cursor_pos
1166 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1168 int tem_X = current_pos_X, dummy;
1170 if (echo_area_glyphs)
1172 tem_X = echo_area_glyphs_length;
1173 /* Save current cursor position, to be restored after the
1174 echo area message is erased. Only remember one level
1175 of previous cursor position. */
1176 if (previous_pos_X == -1)
1177 ScreenGetCursor (&dummy, &previous_pos_X);
1179 else if (previous_pos_X >= 0)
1181 /* We wind up here after the echo area message is erased.
1182 Restore the cursor position we remembered above. */
1183 tem_X = previous_pos_X;
1184 previous_pos_X = -1;
1187 if (current_pos_X != tem_X)
1189 new_pos_X = tem_X;
1190 update_cursor_pos = 1;
1193 #endif
1195 if (update_cursor_pos
1196 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1198 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1199 if (tty->termscript)
1200 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1203 /* Maybe cursor is invisible, so make it visible. */
1204 IT_display_cursor (1);
1206 /* Mouse pointer should be always visible if we are waiting for
1207 keyboard input. */
1208 if (!mouse_visible)
1209 mouse_on ();
1212 static void
1213 IT_update_begin (struct frame *f)
1215 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1216 Mouse_HLInfo *hlinfo = &display_info->mouse_highlight;
1217 struct frame *mouse_face_frame = hlinfo->mouse_face_mouse_frame;
1219 if (display_info->termscript)
1220 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1222 BLOCK_INPUT;
1224 if (f && f == mouse_face_frame)
1226 /* Don't do highlighting for mouse motion during the update. */
1227 hlinfo->mouse_face_defer = 1;
1229 /* If F needs to be redrawn, simply forget about any prior mouse
1230 highlighting. */
1231 if (FRAME_GARBAGED_P (f))
1232 hlinfo->mouse_face_window = Qnil;
1234 /* Can we tell that this update does not affect the window
1235 where the mouse highlight is? If so, no need to turn off.
1236 Likewise, don't do anything if none of the enabled rows
1237 contains glyphs highlighted in mouse face. */
1238 if (!NILP (hlinfo->mouse_face_window)
1239 && WINDOWP (hlinfo->mouse_face_window))
1241 struct window *w = XWINDOW (hlinfo->mouse_face_window);
1242 int i;
1244 /* If the mouse highlight is in the window that was deleted
1245 (e.g., if it was popped by completion), clear highlight
1246 unconditionally. */
1247 if (NILP (w->buffer))
1248 hlinfo->mouse_face_window = Qnil;
1249 else
1251 for (i = 0; i < w->desired_matrix->nrows; ++i)
1252 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1253 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1254 break;
1257 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1258 clear_mouse_face (hlinfo);
1261 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1263 /* If the frame with mouse highlight was deleted, invalidate the
1264 highlight info. */
1265 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1266 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1267 hlinfo->mouse_face_window = Qnil;
1268 hlinfo->mouse_face_deferred_gc = 0;
1269 hlinfo->mouse_face_mouse_frame = NULL;
1272 UNBLOCK_INPUT;
1275 static void
1276 IT_update_end (struct frame *f)
1278 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1280 if (dpyinfo->termscript)
1281 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1282 dpyinfo->mouse_highlight.mouse_face_defer = 0;
1285 static void
1286 IT_frame_up_to_date (struct frame *f)
1288 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1289 Lisp_Object new_cursor, frame_desired_cursor;
1290 struct window *sw;
1292 if (hlinfo->mouse_face_deferred_gc
1293 || (f && f == hlinfo->mouse_face_mouse_frame))
1295 BLOCK_INPUT;
1296 if (hlinfo->mouse_face_mouse_frame)
1297 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1298 hlinfo->mouse_face_mouse_x,
1299 hlinfo->mouse_face_mouse_y);
1300 hlinfo->mouse_face_deferred_gc = 0;
1301 UNBLOCK_INPUT;
1304 /* Set the cursor type to whatever they wanted. In a minibuffer
1305 window, we want the cursor to appear only if we are reading input
1306 from this window, and we want the cursor to be taken from the
1307 frame parameters. For the selected window, we use either its
1308 buffer-local value or the value from the frame parameters if the
1309 buffer doesn't define its local value for the cursor type. */
1310 sw = XWINDOW (f->selected_window);
1311 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1312 if (cursor_in_echo_area
1313 && FRAME_HAS_MINIBUF_P (f)
1314 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1315 && sw == XWINDOW (echo_area_window))
1316 new_cursor = frame_desired_cursor;
1317 else
1319 struct buffer *b = XBUFFER (sw->buffer);
1321 if (EQ (b->cursor_type, Qt))
1322 new_cursor = frame_desired_cursor;
1323 else if (NILP (b->cursor_type)) /* nil means no cursor */
1324 new_cursor = Fcons (Qbar, make_number (0));
1325 else
1326 new_cursor = b->cursor_type;
1329 IT_set_cursor_type (f, new_cursor);
1331 IT_cmgoto (f); /* position cursor when update is done */
1334 /* Copy LEN glyphs displayed on a single line whose vertical position
1335 is YPOS, beginning at horizontal position XFROM to horizontal
1336 position XTO, by moving blocks in the video memory. Used by
1337 functions that insert and delete glyphs. */
1338 static void
1339 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1341 /* The offsets of source and destination relative to the
1342 conventional memorty selector. */
1343 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1344 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1346 if (from == to || len <= 0)
1347 return;
1349 _farsetsel (_dos_ds);
1351 /* The source and destination might overlap, so we need to move
1352 glyphs non-destructively. */
1353 if (from > to)
1355 for ( ; len; from += 2, to += 2, len--)
1356 _farnspokew (to, _farnspeekw (from));
1358 else
1360 from += (len - 1) * 2;
1361 to += (len - 1) * 2;
1362 for ( ; len; from -= 2, to -= 2, len--)
1363 _farnspokew (to, _farnspeekw (from));
1365 if (screen_virtual_segment)
1366 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1369 /* Insert and delete glyphs. */
1370 static void
1371 IT_insert_glyphs (struct frame *f, struct glyph *start, int len)
1373 int shift_by_width = screen_size_X - (new_pos_X + len);
1375 /* Shift right the glyphs from the nominal cursor position to the
1376 end of this line. */
1377 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1379 /* Now write the glyphs to be inserted. */
1380 IT_write_glyphs (f, start, len);
1383 static void
1384 IT_delete_glyphs (struct frame *f, int n)
1386 abort ();
1389 /* set-window-configuration on window.c needs this. */
1390 void
1391 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1393 extern void set_menu_bar_lines (struct frame *, Lisp_Object, Lisp_Object);
1395 set_menu_bar_lines (f, value, oldval);
1398 /* This was copied from xfaces.c */
1400 extern Lisp_Object Qbackground_color;
1401 extern Lisp_Object Qforeground_color;
1402 Lisp_Object Qreverse;
1403 extern Lisp_Object Qtitle;
1405 /* IT_set_terminal_modes is called when emacs is started,
1406 resumed, and whenever the screen is redrawn! */
1408 static void
1409 IT_set_terminal_modes (struct terminal *term)
1411 struct tty_display_info *tty;
1413 /* If called with initial terminal, it's too early to do anything
1414 useful. */
1415 if (term->type == output_initial)
1416 return;
1418 tty = term->display_info.tty;
1420 if (tty->termscript)
1421 fprintf (tty->termscript, "\n<SET_TERM>");
1423 screen_size_X = ScreenCols ();
1424 screen_size_Y = ScreenRows ();
1425 screen_size = screen_size_X * screen_size_Y;
1427 new_pos_X = new_pos_Y = 0;
1428 current_pos_X = current_pos_Y = -1;
1430 if (term_setup_done)
1431 return;
1432 term_setup_done = 1;
1434 startup_screen_size_X = screen_size_X;
1435 startup_screen_size_Y = screen_size_Y;
1436 startup_screen_attrib = ScreenAttrib;
1438 /* Is DOS/V (or any other RSIS software which relocates
1439 the screen) installed? */
1441 unsigned short es_value;
1442 __dpmi_regs regs;
1444 regs.h.ah = 0xfe; /* get relocated screen address */
1445 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1446 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1447 else if (screen_old_address) /* already switched to Japanese mode once */
1448 regs.x.es = (screen_old_address >> 4) & 0xffff;
1449 else
1450 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1451 regs.x.di = 0;
1452 es_value = regs.x.es;
1453 __dpmi_int (0x10, &regs);
1455 if (regs.x.es != es_value)
1457 /* screen_old_address is only set if ScreenPrimary does NOT
1458 already point to the relocated buffer address returned by
1459 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1460 ScreenPrimary to that address at startup under DOS/V. */
1461 if (regs.x.es != ((ScreenPrimary >> 4) & 0xffff))
1462 screen_old_address = ScreenPrimary;
1463 screen_virtual_segment = regs.x.es;
1464 screen_virtual_offset = regs.x.di;
1465 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1469 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1470 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1472 bright_bg ();
1475 /* IT_reset_terminal_modes is called when emacs is
1476 suspended or killed. */
1478 static void
1479 IT_reset_terminal_modes (struct terminal *term)
1481 int display_row_start = (int) ScreenPrimary;
1482 int saved_row_len = startup_screen_size_X * 2;
1483 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1484 int to_next_row = update_row_len;
1485 unsigned char *saved_row = startup_screen_buffer;
1486 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1487 struct tty_display_info *tty = term->display_info.tty;
1489 if (tty->termscript)
1490 fprintf (tty->termscript, "\n<RESET_TERM>");
1492 if (!term_setup_done)
1493 return;
1495 mouse_off ();
1497 /* Leave the video system in the same state as we found it,
1498 as far as the blink/bright-background bit is concerned. */
1499 maybe_enable_blinking ();
1501 /* We have a situation here.
1502 We cannot just do ScreenUpdate(startup_screen_buffer) because
1503 the luser could have changed screen dimensions inside Emacs
1504 and failed (or didn't want) to restore them before killing
1505 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1506 thus will happily use memory outside what was allocated for
1507 `startup_screen_buffer'.
1508 Thus we only restore as much as the current screen dimensions
1509 can hold, and clear the rest (if the saved screen is smaller than
1510 the current) with the color attribute saved at startup. The cursor
1511 is also restored within the visible dimensions. */
1513 ScreenAttrib = startup_screen_attrib;
1515 /* Don't restore the screen if we are exiting less than 2 seconds
1516 after startup: we might be crashing, and the screen might show
1517 some vital clues to what's wrong. */
1518 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1520 ScreenClear ();
1521 if (screen_virtual_segment)
1522 dosv_refresh_virtual_screen (0, screen_size);
1524 if (update_row_len > saved_row_len)
1525 update_row_len = saved_row_len;
1526 if (current_rows > startup_screen_size_Y)
1527 current_rows = startup_screen_size_Y;
1529 if (tty->termscript)
1530 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1531 update_row_len / 2, current_rows);
1533 while (current_rows--)
1535 dosmemput (saved_row, update_row_len, display_row_start);
1536 if (screen_virtual_segment)
1537 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1538 update_row_len / 2);
1539 saved_row += saved_row_len;
1540 display_row_start += to_next_row;
1543 if (startup_pos_X < cursor_pos_X)
1544 cursor_pos_X = startup_pos_X;
1545 if (startup_pos_Y < cursor_pos_Y)
1546 cursor_pos_Y = startup_pos_Y;
1548 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1549 xfree (startup_screen_buffer);
1550 startup_screen_buffer = NULL;
1552 term_setup_done = 0;
1555 static void
1556 IT_set_terminal_window (struct frame *f, int foo)
1560 /* Remember the screen colors of the curent frame, to serve as the
1561 default colors for newly-created frames. */
1562 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1563 Smsdos_remember_default_colors, 1, 1, 0,
1564 doc: /* Remember the screen colors of the current frame. */)
1565 (Lisp_Object frame)
1567 struct frame *f;
1569 CHECK_FRAME (frame);
1570 f = XFRAME (frame);
1572 /* This function is called after applying default-frame-alist to the
1573 initial frame. At that time, if reverse-colors option was
1574 specified in default-frame-alist, it was already applied, and
1575 frame colors are reversed. */
1576 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
1577 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
1579 return Qnil;
1582 void
1583 IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
1585 Lisp_Object tail;
1586 int i, j, length = XINT (Flength (alist));
1587 Lisp_Object *parms
1588 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1589 Lisp_Object *values
1590 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1591 /* Do we have to reverse the foreground and background colors? */
1592 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
1593 int redraw = 0, fg_set = 0, bg_set = 0;
1594 unsigned long orig_fg, orig_bg;
1595 struct tty_display_info *tty = FRAME_TTY (f);
1597 /* If we are creating a new frame, begin with the original screen colors
1598 used for the initial frame. */
1599 if (!f->default_face_done_p
1600 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1602 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1603 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
1604 init_frame_faces (f);
1605 f->default_face_done_p = 1;
1607 orig_fg = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1608 orig_bg = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
1610 /* Extract parm names and values into those vectors. */
1611 i = 0;
1612 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1614 Lisp_Object elt;
1616 elt = Fcar (tail);
1617 parms[i] = Fcar (elt);
1618 CHECK_SYMBOL (parms[i]);
1619 values[i] = Fcdr (elt);
1620 i++;
1623 j = i;
1625 for (i = 0; i < j; i++)
1627 Lisp_Object prop, val;
1629 prop = parms[i];
1630 val = values[i];
1632 if (EQ (prop, Qreverse))
1633 reverse = EQ (val, Qt);
1636 if (tty->termscript && reverse)
1637 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
1639 /* Now process the alist elements in reverse of specified order. */
1640 for (i--; i >= 0; i--)
1642 Lisp_Object prop, val;
1644 prop = parms[i];
1645 val = values[i];
1647 if (EQ (prop, Qforeground_color))
1649 unsigned long new_color = load_color (f, NULL, val, reverse
1650 ? LFACE_BACKGROUND_INDEX
1651 : LFACE_FOREGROUND_INDEX);
1652 if (new_color != FACE_TTY_DEFAULT_COLOR
1653 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1654 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1656 if (!reverse)
1658 FRAME_FOREGROUND_PIXEL (f) = new_color;
1659 /* Make sure the foreground of the default face for
1660 this frame is changed as well. */
1661 update_face_from_frame_parameter (f, Qforeground_color, val);
1662 fg_set = 1;
1663 if (tty->termscript)
1664 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1666 else
1668 FRAME_BACKGROUND_PIXEL (f) = new_color;
1669 update_face_from_frame_parameter (f, Qbackground_color, val);
1670 bg_set = 1;
1671 if (tty->termscript)
1672 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1674 redraw = 1;
1677 else if (EQ (prop, Qbackground_color))
1679 unsigned long new_color = load_color (f, NULL, val, reverse
1680 ? LFACE_FOREGROUND_INDEX
1681 : LFACE_BACKGROUND_INDEX);
1682 if (new_color != FACE_TTY_DEFAULT_COLOR
1683 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1684 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1686 if (!reverse)
1688 FRAME_BACKGROUND_PIXEL (f) = new_color;
1689 /* Make sure the background of the default face for
1690 this frame is changed as well. */
1691 bg_set = 1;
1692 update_face_from_frame_parameter (f, Qbackground_color, val);
1693 if (tty->termscript)
1694 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1696 else
1698 FRAME_FOREGROUND_PIXEL (f) = new_color;
1699 fg_set = 1;
1700 update_face_from_frame_parameter (f, Qforeground_color, val);
1701 if (tty->termscript)
1702 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1704 redraw = 1;
1707 else if (EQ (prop, Qtitle))
1709 x_set_title (f, val);
1710 if (tty->termscript)
1711 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
1713 else if (EQ (prop, Qcursor_type))
1715 IT_set_cursor_type (f, val);
1716 if (tty->termscript)
1717 fprintf (tty->termscript, "<CTYPE: %s>\n",
1718 EQ (val, Qbar)
1719 || EQ (val, Qhbar)
1720 || (CONSP (val) && (EQ (XCAR (val), Qbar)
1721 || EQ (XCAR (val), Qhbar)))
1722 ? "bar" : "box");
1724 else if (EQ (prop, Qtty_type))
1726 internal_terminal_init ();
1727 if (tty->termscript)
1728 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1729 SBYTES (val), SDATA (val));
1731 store_frame_param (f, prop, val);
1734 /* If they specified "reverse", but not the colors, we need to swap
1735 the current frame colors. */
1736 if (reverse)
1738 if (!fg_set)
1740 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1741 update_face_from_frame_parameter (f, Qforeground_color,
1742 tty_color_name (f, orig_bg));
1743 redraw = 1;
1745 if (!bg_set)
1747 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1748 update_face_from_frame_parameter (f, Qbackground_color,
1749 tty_color_name (f, orig_fg));
1750 redraw = 1;
1754 if (redraw)
1756 face_change_count++; /* forces xdisp.c to recompute basic faces */
1757 if (f == SELECTED_FRAME())
1758 redraw_frame (f);
1762 extern void init_frame_faces (FRAME_PTR);
1764 #endif /* !HAVE_X_WINDOWS */
1767 /* Do we need the internal terminal? */
1769 void
1770 internal_terminal_init (void)
1772 static int init_needed = 1;
1773 char *term = getenv ("TERM"), *colors;
1774 struct frame *sf = SELECTED_FRAME();
1775 struct tty_display_info *tty;
1777 #ifdef HAVE_X_WINDOWS
1778 if (!inhibit_window_system)
1779 return;
1780 #endif
1782 /* If this is the initial terminal, we are done here. */
1783 if (sf->output_method == output_initial)
1784 return;
1786 internal_terminal
1787 = (!noninteractive) && term && !strcmp (term, "internal");
1789 #ifndef HAVE_X_WINDOWS
1790 if (!internal_terminal || inhibit_window_system)
1792 sf->output_method = output_termcap;
1793 return;
1796 tty = FRAME_TTY (sf);
1797 current_kboard->Vwindow_system = Qpc;
1798 sf->output_method = output_msdos_raw;
1799 if (init_needed)
1801 if (!tty->termscript && getenv ("EMACSTEST"))
1802 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
1803 if (tty->termscript)
1805 time_t now = time (NULL);
1806 struct tm *tnow = localtime (&now);
1807 char tbuf[100];
1809 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
1810 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
1811 fprintf (tty->termscript, "=====================\n\n");
1814 Vinitial_window_system = Qpc;
1815 Vwindow_system_version = make_number (23); /* RE Emacs version */
1816 tty->terminal->type = output_msdos_raw;
1818 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1819 address. */
1820 screen_old_address = 0;
1822 /* Forget the stale screen colors as well. */
1823 initial_screen_colors[0] = initial_screen_colors[1] = -1;
1825 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1826 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1827 bright_bg ();
1828 colors = getenv ("EMACSCOLORS");
1829 if (colors && strlen (colors) >= 2)
1831 /* The colors use 4 bits each (we enable bright background). */
1832 if (isdigit (colors[0]))
1833 colors[0] -= '0';
1834 else if (isxdigit (colors[0]))
1835 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1836 if (colors[0] >= 0 && colors[0] < 16)
1837 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
1838 if (isdigit (colors[1]))
1839 colors[1] -= '0';
1840 else if (isxdigit (colors[1]))
1841 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1842 if (colors[1] >= 0 && colors[1] < 16)
1843 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
1845 the_only_display_info.mouse_highlight.mouse_face_mouse_frame = NULL;
1846 the_only_display_info.mouse_highlight.mouse_face_deferred_gc = 0;
1847 the_only_display_info.mouse_highlight.mouse_face_beg_row =
1848 the_only_display_info.mouse_highlight.mouse_face_beg_col = -1;
1849 the_only_display_info.mouse_highlight.mouse_face_end_row =
1850 the_only_display_info.mouse_highlight.mouse_face_end_col = -1;
1851 the_only_display_info.mouse_highlight.mouse_face_face_id = DEFAULT_FACE_ID;
1852 the_only_display_info.mouse_highlight.mouse_face_window = Qnil;
1853 the_only_display_info.mouse_highlight.mouse_face_mouse_x =
1854 the_only_display_info.mouse_highlight.mouse_face_mouse_y = 0;
1855 the_only_display_info.mouse_highlight.mouse_face_defer = 0;
1856 the_only_display_info.mouse_highlight.mouse_face_hidden = 0;
1858 if (have_mouse) /* detected in dos_ttraw, which see */
1860 have_mouse = 1; /* enable mouse */
1861 mouse_visible = 0;
1862 mouse_setup_buttons (mouse_button_count);
1863 tty->terminal->mouse_position_hook = &mouse_get_pos;
1864 mouse_init ();
1867 if (tty->termscript && screen_size)
1868 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1869 screen_size_X, screen_size_Y);
1871 init_frame_faces (sf);
1872 init_needed = 0;
1874 #endif
1877 void
1878 initialize_msdos_display (struct terminal *term)
1880 term->rif = 0; /* we don't support window-based display */
1881 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
1882 term->clear_to_end_hook = IT_clear_to_end;
1883 term->clear_frame_hook = IT_clear_screen;
1884 term->clear_end_of_line_hook = IT_clear_end_of_line;
1885 term->ins_del_lines_hook = 0;
1886 term->insert_glyphs_hook = IT_insert_glyphs;
1887 term->write_glyphs_hook = IT_write_glyphs;
1888 term->delete_glyphs_hook = IT_delete_glyphs;
1889 term->ring_bell_hook = IT_ring_bell;
1890 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
1891 term->set_terminal_modes_hook = IT_set_terminal_modes;
1892 term->set_terminal_window_hook = IT_set_terminal_window;
1893 term->update_begin_hook = IT_update_begin;
1894 term->update_end_hook = IT_update_end;
1895 term->frame_up_to_date_hook = IT_frame_up_to_date;
1896 term->mouse_position_hook = 0; /* set later by dos_ttraw */
1897 term->frame_rehighlight_hook = 0;
1898 term->frame_raise_lower_hook = 0;
1899 term->set_vertical_scroll_bar_hook = 0;
1900 term->condemn_scroll_bars_hook = 0;
1901 term->redeem_scroll_bar_hook = 0;
1902 term->judge_scroll_bars_hook = 0;
1903 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
1907 dos_get_saved_screen (char **screen, int *rows, int *cols)
1909 #ifndef HAVE_X_WINDOWS
1910 *screen = startup_screen_buffer;
1911 *cols = startup_screen_size_X;
1912 *rows = startup_screen_size_Y;
1913 return *screen != (char *)0;
1914 #else
1915 return 0;
1916 #endif
1919 #ifndef HAVE_X_WINDOWS
1921 /* We are not X, but we can emulate it well enough for our needs... */
1922 void
1923 check_x (void)
1925 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
1926 error ("Not running under a window system");
1929 #endif
1932 /* ----------------------- Keyboard control ----------------------
1934 * Keymaps reflect the following keyboard layout:
1936 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1937 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1938 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1939 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1940 * SPACE
1943 #define Ignore 0x0000
1944 #define Normal 0x0000 /* normal key - alt changes scan-code */
1945 #define FctKey 0x1000 /* func key if c == 0, else c */
1946 #define Special 0x2000 /* func key even if c != 0 */
1947 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1948 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1949 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1950 #define Grey 0x6000 /* Grey keypad key */
1952 #define Alt 0x0100 /* alt scan-code */
1953 #define Ctrl 0x0200 /* ctrl scan-code */
1954 #define Shift 0x0400 /* shift scan-code */
1956 static int extended_kbd; /* 101 (102) keyboard present. */
1958 struct kbd_translate {
1959 unsigned char sc;
1960 unsigned char ch;
1961 unsigned short code;
1964 struct dos_keyboard_map
1966 char *unshifted;
1967 char *shifted;
1968 char *alt_gr;
1969 struct kbd_translate *translate_table;
1973 static struct dos_keyboard_map us_keyboard = {
1974 /* 0 1 2 3 4 5 */
1975 /* 01234567890123456789012345678901234567890 12345678901234 */
1976 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1977 /* 0123456789012345678901234567890123456789 012345678901234 */
1978 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1979 0, /* no Alt-Gr key */
1980 0 /* no translate table */
1983 static struct dos_keyboard_map fr_keyboard = {
1984 /* 0 1 2 3 4 5 */
1985 /* 012 3456789012345678901234567890123456789012345678901234 */
1986 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1987 /* 0123456789012345678901234567890123456789012345678901234 */
1988 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1989 /* 01234567 89012345678901234567890123456789012345678901234 */
1990 " ~#{[|`\\^@]} Ï ",
1991 0 /* no translate table */
1995 * Italian keyboard support, country code 39.
1996 * '<' 56:3c*0000
1997 * '>' 56:3e*0000
1998 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1999 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2002 static struct kbd_translate it_kbd_translate_table[] = {
2003 { 0x56, 0x3c, Normal | 13 },
2004 { 0x56, 0x3e, Normal | 27 },
2005 { 0, 0, 0 }
2007 static struct dos_keyboard_map it_keyboard = {
2008 /* 0 1 2 3 4 5 */
2009 /* 0 123456789012345678901234567890123456789012345678901234 */
2010 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2011 /* 01 23456789012345678901234567890123456789012345678901234 */
2012 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2013 /* 0123456789012345678901234567890123456789012345678901234 */
2014 " {}~` [] @# ",
2015 it_kbd_translate_table
2018 static struct dos_keyboard_map dk_keyboard = {
2019 /* 0 1 2 3 4 5 */
2020 /* 0123456789012345678901234567890123456789012345678901234 */
2021 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2022 /* 01 23456789012345678901234567890123456789012345678901234 */
2023 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2024 /* 0123456789012345678901234567890123456789012345678901234 */
2025 " @œ$ {[]} | ",
2026 0 /* no translate table */
2029 static struct kbd_translate jp_kbd_translate_table[] = {
2030 { 0x73, 0x5c, Normal | 0 },
2031 { 0x73, 0x5f, Normal | 0 },
2032 { 0x73, 0x1c, Map | 0 },
2033 { 0x7d, 0x5c, Normal | 13 },
2034 { 0x7d, 0x7c, Normal | 13 },
2035 { 0x7d, 0x1c, Map | 13 },
2036 { 0, 0, 0 }
2038 static struct dos_keyboard_map jp_keyboard = {
2039 /* 0 1 2 3 4 5 */
2040 /* 0123456789012 345678901234567890123456789012345678901234 */
2041 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2042 /* 01 23456789012345678901234567890123456789012345678901234 */
2043 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2044 0, /* no Alt-Gr key */
2045 jp_kbd_translate_table
2048 static struct keyboard_layout_list
2050 int country_code;
2051 struct dos_keyboard_map *keyboard_map;
2052 } keyboard_layout_list[] =
2054 { 1, &us_keyboard },
2055 { 33, &fr_keyboard },
2056 { 39, &it_keyboard },
2057 { 45, &dk_keyboard },
2058 { 81, &jp_keyboard }
2061 static struct dos_keyboard_map *keyboard;
2062 static int keyboard_map_all;
2063 static int international_keyboard;
2066 dos_set_keyboard (int code, int always)
2068 int i;
2069 _go32_dpmi_registers regs;
2071 /* See if Keyb.Com is installed (for international keyboard support).
2072 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2073 of Windows 9X! So don't do that! */
2074 regs.x.ax = 0xad80;
2075 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2076 _go32_dpmi_simulate_int (0x2f, &regs);
2077 if (regs.h.al == 0xff)
2078 international_keyboard = 1;
2080 /* Initialize to US settings, for countries that don't have their own. */
2081 keyboard = keyboard_layout_list[0].keyboard_map;
2082 keyboard_map_all = always;
2083 dos_keyboard_layout = 1;
2085 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2086 if (code == keyboard_layout_list[i].country_code)
2088 keyboard = keyboard_layout_list[i].keyboard_map;
2089 keyboard_map_all = always;
2090 dos_keyboard_layout = code;
2091 return 1;
2093 return 0;
2096 static struct
2098 unsigned char char_code; /* normal code */
2099 unsigned char meta_code; /* M- code */
2100 unsigned char keypad_code; /* keypad code */
2101 unsigned char editkey_code; /* edit key */
2102 } keypad_translate_map[] = {
2103 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2104 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2105 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2106 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2107 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2108 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2109 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2110 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2111 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2112 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2113 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2116 static struct
2118 unsigned char char_code; /* normal code */
2119 unsigned char keypad_code; /* keypad code */
2120 } grey_key_translate_map[] = {
2121 { '/', 0xaf /* kp-decimal */ },
2122 { '*', 0xaa /* kp-multiply */ },
2123 { '-', 0xad /* kp-subtract */ },
2124 { '+', 0xab /* kp-add */ },
2125 { '\r', 0x8d /* kp-enter */ }
2128 static unsigned short
2129 ibmpc_translate_map[] =
2131 /* --------------- 00 to 0f --------------- */
2132 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2133 Alt | ModFct | 0x1b, /* Escape */
2134 Normal | 1, /* '1' */
2135 Normal | 2, /* '2' */
2136 Normal | 3, /* '3' */
2137 Normal | 4, /* '4' */
2138 Normal | 5, /* '5' */
2139 Normal | 6, /* '6' */
2140 Normal | 7, /* '7' */
2141 Normal | 8, /* '8' */
2142 Normal | 9, /* '9' */
2143 Normal | 10, /* '0' */
2144 Normal | 11, /* '-' */
2145 Normal | 12, /* '=' */
2146 Special | 0x08, /* Backspace */
2147 ModFct | 0x74, /* Tab/Backtab */
2149 /* --------------- 10 to 1f --------------- */
2150 Map | 15, /* 'q' */
2151 Map | 16, /* 'w' */
2152 Map | 17, /* 'e' */
2153 Map | 18, /* 'r' */
2154 Map | 19, /* 't' */
2155 Map | 20, /* 'y' */
2156 Map | 21, /* 'u' */
2157 Map | 22, /* 'i' */
2158 Map | 23, /* 'o' */
2159 Map | 24, /* 'p' */
2160 Map | 25, /* '[' */
2161 Map | 26, /* ']' */
2162 ModFct | 0x0d, /* Return */
2163 Ignore, /* Ctrl */
2164 Map | 30, /* 'a' */
2165 Map | 31, /* 's' */
2167 /* --------------- 20 to 2f --------------- */
2168 Map | 32, /* 'd' */
2169 Map | 33, /* 'f' */
2170 Map | 34, /* 'g' */
2171 Map | 35, /* 'h' */
2172 Map | 36, /* 'j' */
2173 Map | 37, /* 'k' */
2174 Map | 38, /* 'l' */
2175 Map | 39, /* ';' */
2176 Map | 40, /* '\'' */
2177 Map | 0, /* '`' */
2178 Ignore, /* Left shift */
2179 Map | 41, /* '\\' */
2180 Map | 45, /* 'z' */
2181 Map | 46, /* 'x' */
2182 Map | 47, /* 'c' */
2183 Map | 48, /* 'v' */
2185 /* --------------- 30 to 3f --------------- */
2186 Map | 49, /* 'b' */
2187 Map | 50, /* 'n' */
2188 Map | 51, /* 'm' */
2189 Map | 52, /* ',' */
2190 Map | 53, /* '.' */
2191 Map | 54, /* '/' */
2192 Ignore, /* Right shift */
2193 Grey | 1, /* Grey * */
2194 Ignore, /* Alt */
2195 Normal | 55, /* ' ' */
2196 Ignore, /* Caps Lock */
2197 FctKey | 0xbe, /* F1 */
2198 FctKey | 0xbf, /* F2 */
2199 FctKey | 0xc0, /* F3 */
2200 FctKey | 0xc1, /* F4 */
2201 FctKey | 0xc2, /* F5 */
2203 /* --------------- 40 to 4f --------------- */
2204 FctKey | 0xc3, /* F6 */
2205 FctKey | 0xc4, /* F7 */
2206 FctKey | 0xc5, /* F8 */
2207 FctKey | 0xc6, /* F9 */
2208 FctKey | 0xc7, /* F10 */
2209 Ignore, /* Num Lock */
2210 Ignore, /* Scroll Lock */
2211 KeyPad | 7, /* Home */
2212 KeyPad | 8, /* Up */
2213 KeyPad | 9, /* Page Up */
2214 Grey | 2, /* Grey - */
2215 KeyPad | 4, /* Left */
2216 KeyPad | 5, /* Keypad 5 */
2217 KeyPad | 6, /* Right */
2218 Grey | 3, /* Grey + */
2219 KeyPad | 1, /* End */
2221 /* --------------- 50 to 5f --------------- */
2222 KeyPad | 2, /* Down */
2223 KeyPad | 3, /* Page Down */
2224 KeyPad | 0, /* Insert */
2225 KeyPad | 10, /* Delete */
2226 Shift | FctKey | 0xbe, /* (Shift) F1 */
2227 Shift | FctKey | 0xbf, /* (Shift) F2 */
2228 Shift | FctKey | 0xc0, /* (Shift) F3 */
2229 Shift | FctKey | 0xc1, /* (Shift) F4 */
2230 Shift | FctKey | 0xc2, /* (Shift) F5 */
2231 Shift | FctKey | 0xc3, /* (Shift) F6 */
2232 Shift | FctKey | 0xc4, /* (Shift) F7 */
2233 Shift | FctKey | 0xc5, /* (Shift) F8 */
2234 Shift | FctKey | 0xc6, /* (Shift) F9 */
2235 Shift | FctKey | 0xc7, /* (Shift) F10 */
2236 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2237 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2239 /* --------------- 60 to 6f --------------- */
2240 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2241 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2242 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2243 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2244 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2245 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2246 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2247 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2248 Alt | FctKey | 0xbe, /* (Alt) F1 */
2249 Alt | FctKey | 0xbf, /* (Alt) F2 */
2250 Alt | FctKey | 0xc0, /* (Alt) F3 */
2251 Alt | FctKey | 0xc1, /* (Alt) F4 */
2252 Alt | FctKey | 0xc2, /* (Alt) F5 */
2253 Alt | FctKey | 0xc3, /* (Alt) F6 */
2254 Alt | FctKey | 0xc4, /* (Alt) F7 */
2255 Alt | FctKey | 0xc5, /* (Alt) F8 */
2257 /* --------------- 70 to 7f --------------- */
2258 Alt | FctKey | 0xc6, /* (Alt) F9 */
2259 Alt | FctKey | 0xc7, /* (Alt) F10 */
2260 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2261 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2262 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2263 Ctrl | KeyPad | 1, /* (Ctrl) End */
2264 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2265 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2266 Alt | Map | 1, /* '1' */
2267 Alt | Map | 2, /* '2' */
2268 Alt | Map | 3, /* '3' */
2269 Alt | Map | 4, /* '4' */
2270 Alt | Map | 5, /* '5' */
2271 Alt | Map | 6, /* '6' */
2272 Alt | Map | 7, /* '7' */
2273 Alt | Map | 8, /* '8' */
2275 /* --------------- 80 to 8f --------------- */
2276 Alt | Map | 9, /* '9' */
2277 Alt | Map | 10, /* '0' */
2278 Alt | Map | 11, /* '-' */
2279 Alt | Map | 12, /* '=' */
2280 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2281 FctKey | 0xc8, /* F11 */
2282 FctKey | 0xc9, /* F12 */
2283 Shift | FctKey | 0xc8, /* (Shift) F11 */
2284 Shift | FctKey | 0xc9, /* (Shift) F12 */
2285 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2286 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2287 Alt | FctKey | 0xc8, /* (Alt) F11 */
2288 Alt | FctKey | 0xc9, /* (Alt) F12 */
2289 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2290 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2291 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2293 /* --------------- 90 to 9f --------------- */
2294 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2295 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2296 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2297 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2298 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2299 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2300 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2301 Alt | FctKey | 0x50, /* (Alt) Home */
2302 Alt | FctKey | 0x52, /* (Alt) Up */
2303 Alt | FctKey | 0x55, /* (Alt) Page Up */
2304 Ignore, /* NO KEY */
2305 Alt | FctKey | 0x51, /* (Alt) Left */
2306 Ignore, /* NO KEY */
2307 Alt | FctKey | 0x53, /* (Alt) Right */
2308 Ignore, /* NO KEY */
2309 Alt | FctKey | 0x57, /* (Alt) End */
2311 /* --------------- a0 to af --------------- */
2312 Alt | KeyPad | 2, /* (Alt) Down */
2313 Alt | KeyPad | 3, /* (Alt) Page Down */
2314 Alt | KeyPad | 0, /* (Alt) Insert */
2315 Alt | KeyPad | 10, /* (Alt) Delete */
2316 Alt | Grey | 0, /* (Alt) Grey / */
2317 Alt | FctKey | 0x09, /* (Alt) Tab */
2318 Alt | Grey | 4 /* (Alt) Keypad Enter */
2321 /* These bit-positions corresponds to values returned by BIOS */
2322 #define SHIFT_P 0x0003 /* two bits! */
2323 #define CTRL_P 0x0004
2324 #define ALT_P 0x0008
2325 #define SCRLOCK_P 0x0010
2326 #define NUMLOCK_P 0x0020
2327 #define CAPSLOCK_P 0x0040
2328 #define ALT_GR_P 0x0800
2329 #define SUPER_P 0x4000 /* pseudo */
2330 #define HYPER_P 0x8000 /* pseudo */
2332 static int
2333 dos_get_modifiers (int *keymask)
2335 union REGS regs;
2336 int mask, modifiers = 0;
2338 /* Calculate modifier bits */
2339 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2340 int86 (0x16, &regs, &regs);
2342 if (!extended_kbd)
2344 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2345 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2347 else
2349 mask = regs.h.al & (SHIFT_P |
2350 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2352 /* Do not break international keyboard support. */
2353 /* When Keyb.Com is loaded, the right Alt key is */
2354 /* used for accessing characters like { and } */
2355 if (regs.h.ah & 2) /* Left ALT pressed ? */
2356 mask |= ALT_P;
2358 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2360 mask |= ALT_GR_P;
2361 if (dos_hyper_key == 1)
2363 mask |= HYPER_P;
2364 modifiers |= hyper_modifier;
2366 else if (dos_super_key == 1)
2368 mask |= SUPER_P;
2369 modifiers |= super_modifier;
2371 else if (!international_keyboard)
2373 /* If Keyb.Com is NOT installed, let Right Alt behave
2374 like the Left Alt. */
2375 mask &= ~ALT_GR_P;
2376 mask |= ALT_P;
2380 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2381 mask |= CTRL_P;
2383 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2385 if (dos_hyper_key == 2)
2387 mask |= HYPER_P;
2388 modifiers |= hyper_modifier;
2390 else if (dos_super_key == 2)
2392 mask |= SUPER_P;
2393 modifiers |= super_modifier;
2395 else
2396 mask |= CTRL_P;
2400 if (mask & SHIFT_P)
2401 modifiers |= shift_modifier;
2402 if (mask & CTRL_P)
2403 modifiers |= ctrl_modifier;
2404 if (mask & ALT_P)
2405 modifiers |= meta_modifier;
2407 if (keymask)
2408 *keymask = mask;
2409 return modifiers;
2412 #define NUM_RECENT_DOSKEYS (100)
2413 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2414 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2415 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2417 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2418 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2419 Each input key receives two values in this vector: first the ASCII code,
2420 and then the scan code. */)
2421 (void)
2423 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2425 if (total_doskeys < NUM_RECENT_DOSKEYS)
2426 return Fvector (total_doskeys, keys);
2427 else
2429 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2430 memcpy (XVECTOR (val)->contents, keys + recent_doskeys_index,
2431 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2432 memcpy (XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2433 keys, recent_doskeys_index * sizeof (Lisp_Object));
2434 return val;
2438 /* Get a char from keyboard. Function keys are put into the event queue. */
2439 static int
2440 dos_rawgetc (void)
2442 struct input_event event;
2443 union REGS regs;
2444 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (SELECTED_FRAME());
2445 EVENT_INIT (event);
2447 #ifndef HAVE_X_WINDOWS
2448 /* Maybe put the cursor where it should be. */
2449 IT_cmgoto (SELECTED_FRAME());
2450 #endif
2452 /* The following condition is equivalent to `kbhit ()', except that
2453 it uses the bios to do its job. This pleases DESQview/X. */
2454 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2455 int86 (0x16, &regs, &regs),
2456 (regs.x.flags & 0x40) == 0)
2458 union REGS regs;
2459 register unsigned char c;
2460 int modifiers, sc, code = -1, mask, kp_mode;
2462 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2463 int86 (0x16, &regs, &regs);
2464 c = regs.h.al;
2465 sc = regs.h.ah;
2467 total_doskeys += 2;
2468 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2469 = make_number (c);
2470 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2471 recent_doskeys_index = 0;
2472 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2473 = make_number (sc);
2474 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2475 recent_doskeys_index = 0;
2477 modifiers = dos_get_modifiers (&mask);
2479 #ifndef HAVE_X_WINDOWS
2480 if (!NILP (Vdos_display_scancodes))
2482 char buf[11];
2483 sprintf (buf, "%02x:%02x*%04x",
2484 (unsigned) (sc&0xff), (unsigned) c, mask);
2485 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2487 #endif
2489 if (sc == 0xe0)
2491 switch (c)
2493 case 10: /* Ctrl Grey Enter */
2494 code = Ctrl | Grey | 4;
2495 break;
2496 case 13: /* Grey Enter */
2497 code = Grey | 4;
2498 break;
2499 case '/': /* Grey / */
2500 code = Grey | 0;
2501 break;
2502 default:
2503 continue;
2505 c = 0;
2507 else
2509 /* Try the keyboard-private translation table first. */
2510 if (keyboard->translate_table)
2512 struct kbd_translate *p = keyboard->translate_table;
2514 while (p->sc)
2516 if (p->sc == sc && p->ch == c)
2518 code = p->code;
2519 break;
2521 p++;
2524 /* If the private table didn't translate it, use the general
2525 one. */
2526 if (code == -1)
2528 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
2529 continue;
2530 if ((code = ibmpc_translate_map[sc]) == Ignore)
2531 continue;
2535 if (c == 0)
2537 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2538 Emacs is ready to read a key. Therefore, if they press
2539 `Alt-x' when Emacs is busy, by the time we get to
2540 `dos_get_modifiers', they might have already released the
2541 Alt key, and Emacs gets just `x', which is BAD.
2542 However, for keys with the `Map' property set, the ASCII
2543 code returns zero only if Alt is pressed. So, when we DON'T
2544 have to support international_keyboard, we don't have to
2545 distinguish between the left and right Alt keys, and we
2546 can set the META modifier for any keys with the `Map'
2547 property if they return zero ASCII code (c = 0). */
2548 if ( (code & Alt)
2549 || ( (code & 0xf000) == Map && !international_keyboard))
2550 modifiers |= meta_modifier;
2551 if (code & Ctrl)
2552 modifiers |= ctrl_modifier;
2553 if (code & Shift)
2554 modifiers |= shift_modifier;
2557 switch (code & 0xf000)
2559 case ModFct:
2560 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
2561 return c;
2562 c = 0; /* Special */
2564 case FctKey:
2565 if (c != 0)
2566 return c;
2568 case Special:
2569 code |= 0xff00;
2570 break;
2572 case Normal:
2573 if (sc == 0)
2575 if (c == 0) /* ctrl-break */
2576 continue;
2577 return c; /* ALT-nnn */
2579 if (!keyboard_map_all)
2581 if (c != ' ')
2582 return c;
2583 code = c;
2584 break;
2587 case Map:
2588 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
2589 if (!keyboard_map_all)
2590 return c;
2592 code &= 0xff;
2593 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
2594 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
2596 if (mask & SHIFT_P)
2598 code = keyboard->shifted[code];
2599 mask -= SHIFT_P;
2600 modifiers &= ~shift_modifier;
2602 else
2603 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
2604 code = keyboard->alt_gr[code];
2605 else
2606 code = keyboard->unshifted[code];
2607 break;
2609 case KeyPad:
2610 code &= 0xff;
2611 if (c == 0xe0) /* edit key */
2612 kp_mode = 3;
2613 else
2614 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
2615 kp_mode = dos_keypad_mode & 0x03;
2616 else
2617 kp_mode = (dos_keypad_mode >> 4) & 0x03;
2619 switch (kp_mode)
2621 case 0:
2622 if (code == 10 && dos_decimal_point)
2623 return dos_decimal_point;
2624 return keypad_translate_map[code].char_code;
2626 case 1:
2627 code = 0xff00 | keypad_translate_map[code].keypad_code;
2628 break;
2630 case 2:
2631 code = keypad_translate_map[code].meta_code;
2632 modifiers = meta_modifier;
2633 break;
2635 case 3:
2636 code = 0xff00 | keypad_translate_map[code].editkey_code;
2637 break;
2639 break;
2641 case Grey:
2642 code &= 0xff;
2643 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
2644 if (dos_keypad_mode & kp_mode)
2645 code = 0xff00 | grey_key_translate_map[code].keypad_code;
2646 else
2647 code = grey_key_translate_map[code].char_code;
2648 break;
2651 if (code == 0)
2652 continue;
2654 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
2656 clear_mouse_face (hlinfo);
2657 hlinfo->mouse_face_hidden = 1;
2660 if (code >= 0x100)
2661 event.kind = NON_ASCII_KEYSTROKE_EVENT;
2662 else
2663 event.kind = ASCII_KEYSTROKE_EVENT;
2664 event.code = code;
2665 event.modifiers = modifiers;
2666 event.frame_or_window = selected_frame;
2667 event.arg = Qnil;
2668 event.timestamp = event_timestamp ();
2669 kbd_buffer_store_event (&event);
2672 if (have_mouse > 0 && !mouse_preempted)
2674 int but, press, x, y, ok;
2675 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
2676 Lisp_Object mouse_window = Qnil;
2678 /* Check for mouse movement *before* buttons. */
2679 mouse_check_moved ();
2681 /* If the mouse moved from the spot of its last sighting, we
2682 might need to update mouse highlight. */
2683 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
2685 if (hlinfo->mouse_face_hidden)
2687 hlinfo->mouse_face_hidden = 0;
2688 clear_mouse_face (hlinfo);
2691 /* Generate SELECT_WINDOW_EVENTs when needed. */
2692 if (!NILP (Vmouse_autoselect_window))
2694 mouse_window = window_from_coordinates (SELECTED_FRAME(),
2695 mouse_last_x,
2696 mouse_last_y,
2697 0, 0);
2698 /* A window will be selected only when it is not
2699 selected now, and the last mouse movement event was
2700 not in it. A minibuffer window will be selected iff
2701 it is active. */
2702 if (WINDOWP (mouse_window)
2703 && !EQ (mouse_window, last_mouse_window)
2704 && !EQ (mouse_window, selected_window))
2706 event.kind = SELECT_WINDOW_EVENT;
2707 event.frame_or_window = mouse_window;
2708 event.arg = Qnil;
2709 event.timestamp = event_timestamp ();
2710 kbd_buffer_store_event (&event);
2712 last_mouse_window = mouse_window;
2714 else
2715 last_mouse_window = Qnil;
2717 previous_help_echo_string = help_echo_string;
2718 help_echo_string = help_echo_object = help_echo_window = Qnil;
2719 help_echo_pos = -1;
2720 note_mouse_highlight (SELECTED_FRAME(), mouse_last_x, mouse_last_y);
2721 /* If the contents of the global variable help_echo has
2722 changed, generate a HELP_EVENT. */
2723 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
2724 gen_help_event (help_echo_string, selected_frame, help_echo_window,
2725 help_echo_object, help_echo_pos);
2728 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
2729 for (press = 0; press < 2; press++)
2731 int button_num = but;
2733 if (press)
2734 ok = mouse_pressed (but, &x, &y);
2735 else
2736 ok = mouse_released (but, &x, &y);
2737 if (ok)
2739 /* Allow a simultaneous press/release of Mouse-1 and
2740 Mouse-2 to simulate Mouse-3 on two-button mice. */
2741 if (mouse_button_count == 2 && but < 2)
2743 int x2, y2; /* don't clobber original coordinates */
2745 /* If only one button is pressed, wait 100 msec and
2746 check again. This way, Speedy Gonzales isn't
2747 punished, while the slow get their chance. */
2748 if ((press && mouse_pressed (1-but, &x2, &y2))
2749 || (!press && mouse_released (1-but, &x2, &y2)))
2750 button_num = 2;
2751 else
2753 delay (100);
2754 if ((press && mouse_pressed (1-but, &x2, &y2))
2755 || (!press && mouse_released (1-but, &x2, &y2)))
2756 button_num = 2;
2760 event.kind = MOUSE_CLICK_EVENT;
2761 event.code = button_num;
2762 event.modifiers = dos_get_modifiers (0)
2763 | (press ? down_modifier : up_modifier);
2764 event.x = make_number (x);
2765 event.y = make_number (y);
2766 event.frame_or_window = selected_frame;
2767 event.arg = Qnil;
2768 event.timestamp = event_timestamp ();
2769 kbd_buffer_store_event (&event);
2774 return -1;
2777 static int prev_get_char = -1;
2779 /* Return 1 if a key is ready to be read without suspending execution. */
2781 dos_keysns (void)
2783 if (prev_get_char != -1)
2784 return 1;
2785 else
2786 return ((prev_get_char = dos_rawgetc ()) != -1);
2789 /* Read a key. Return -1 if no key is ready. */
2791 dos_keyread (void)
2793 if (prev_get_char != -1)
2795 int c = prev_get_char;
2796 prev_get_char = -1;
2797 return c;
2799 else
2800 return dos_rawgetc ();
2803 #ifndef HAVE_X_WINDOWS
2805 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2806 for now.
2808 Actually, I don't know the meaning of all the parameters of the functions
2809 here -- I only know how they are called by xmenu.c. I could of course
2810 grab the nearest Xlib manual (down the hall, second-to-last door on the
2811 left), but I don't think it's worth the effort. */
2813 /* These hold text of the current and the previous menu help messages. */
2814 static char *menu_help_message, *prev_menu_help_message;
2815 /* Pane number and item number of the menu item which generated the
2816 last menu help message. */
2817 static int menu_help_paneno, menu_help_itemno;
2819 static XMenu *
2820 IT_menu_create (void)
2822 XMenu *menu;
2824 menu = (XMenu *) xmalloc (sizeof (XMenu));
2825 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2826 return menu;
2829 /* Allocate some (more) memory for MENU ensuring that there is room for one
2830 for item. */
2832 static void
2833 IT_menu_make_room (XMenu *menu)
2835 if (menu->allocated == 0)
2837 int count = menu->allocated = 10;
2838 menu->text = (char **) xmalloc (count * sizeof (char *));
2839 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
2840 menu->panenumber = (int *) xmalloc (count * sizeof (int));
2841 menu->help_text = (char **) xmalloc (count * sizeof (char *));
2843 else if (menu->allocated == menu->count)
2845 int count = menu->allocated = menu->allocated + 10;
2846 menu->text
2847 = (char **) xrealloc (menu->text, count * sizeof (char *));
2848 menu->submenu
2849 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2850 menu->panenumber
2851 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2852 menu->help_text
2853 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
2857 /* Search the given menu structure for a given pane number. */
2859 static XMenu *
2860 IT_menu_search_pane (XMenu *menu, int pane)
2862 int i;
2863 XMenu *try;
2865 for (i = 0; i < menu->count; i++)
2866 if (menu->submenu[i])
2868 if (pane == menu->panenumber[i])
2869 return menu->submenu[i];
2870 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2871 return try;
2873 return (XMenu *) 0;
2876 /* Determine how much screen space a given menu needs. */
2878 static void
2879 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2881 int i, h2, w2, maxsubwidth, maxheight;
2883 maxsubwidth = 0;
2884 maxheight = menu->count;
2885 for (i = 0; i < menu->count; i++)
2887 if (menu->submenu[i])
2889 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2890 if (w2 > maxsubwidth) maxsubwidth = w2;
2891 if (i + h2 > maxheight) maxheight = i + h2;
2894 *width = menu->width + maxsubwidth;
2895 *height = maxheight;
2898 /* Display MENU at (X,Y) using FACES. */
2900 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
2901 do \
2903 (GLYPH).type = CHAR_GLYPH; \
2904 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
2905 (GLYPH).charpos = -1; \
2907 while (0)
2909 static void
2910 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
2912 int i, j, face, width, mx, my, enabled, mousehere, row, col;
2913 struct glyph *text, *p;
2914 const unsigned char *q;
2915 struct frame *sf = SELECTED_FRAME();
2917 menu_help_message = NULL;
2919 width = menu->width;
2920 /* We multiply width by 2 to account for possible control characters.
2921 FIXME: cater to non-ASCII characters in menus. */
2922 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
2923 ScreenGetCursor (&row, &col);
2924 mouse_get_xy (&mx, &my);
2925 IT_update_begin (sf);
2926 for (i = 0; i < menu->count; i++)
2928 int max_width = width + 2;
2930 IT_cursor_to (sf, y + i, x);
2931 enabled
2932 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2933 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2934 face = faces[enabled + mousehere * 2];
2935 /* The following if clause means that we display the menu help
2936 strings even if the menu item is currently disabled. */
2937 if (disp_help && enabled + mousehere * 2 >= 2)
2939 menu_help_message = menu->help_text[i];
2940 menu_help_paneno = pn - 1;
2941 menu_help_itemno = i;
2943 p = text;
2944 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
2945 p++;
2946 for (j = 0, q = menu->text[i]; *q; j++)
2948 unsigned c = STRING_CHAR_ADVANCE (q);
2950 if (c > 26)
2952 BUILD_CHAR_GLYPH (*p, c, face, 0);
2953 p++;
2955 else /* make '^x' */
2957 BUILD_CHAR_GLYPH (*p, '^', face, 0);
2958 p++;
2959 j++;
2960 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
2961 p++;
2964 /* Don't let the menu text overflow into the next screen row. */
2965 if (x + max_width > screen_size_X)
2967 max_width = screen_size_X - x;
2968 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
2970 for (; j < max_width - 2; j++, p++)
2971 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
2973 /* 16 is the character code of a character that on DOS terminal
2974 produces a nice-looking right-pointing arrow glyph. */
2975 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
2976 p++;
2977 IT_write_glyphs (sf, text, max_width);
2979 IT_update_end (sf);
2980 IT_cursor_to (sf, row, col);
2981 xfree (text);
2984 /* --------------------------- X Menu emulation ---------------------- */
2986 /* Report availability of menus. */
2989 have_menus_p (void) { return 1; }
2991 /* Create a brand new menu structure. */
2993 XMenu *
2994 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2996 return IT_menu_create ();
2999 /* Create a new pane and place it on the outer-most level. It is not
3000 clear that it should be placed out there, but I don't know what else
3001 to do. */
3004 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3006 int len;
3007 char *p;
3009 if (!enable)
3010 abort ();
3012 IT_menu_make_room (menu);
3013 menu->submenu[menu->count] = IT_menu_create ();
3014 menu->text[menu->count] = txt;
3015 menu->panenumber[menu->count] = ++menu->panecount;
3016 menu->help_text[menu->count] = NULL;
3017 menu->count++;
3019 /* Adjust length for possible control characters (which will
3020 be written as ^x). */
3021 for (len = strlen (txt), p = txt; *p; p++)
3022 if (*p < 27)
3023 len++;
3025 if (len > menu->width)
3026 menu->width = len;
3028 return menu->panecount;
3031 /* Create a new item in a menu pane. */
3034 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3035 int foo, char *txt, int enable, char *help_text)
3037 int len;
3038 char *p;
3040 if (pane)
3041 if (!(menu = IT_menu_search_pane (menu, pane)))
3042 return XM_FAILURE;
3043 IT_menu_make_room (menu);
3044 menu->submenu[menu->count] = (XMenu *) 0;
3045 menu->text[menu->count] = txt;
3046 menu->panenumber[menu->count] = enable;
3047 menu->help_text[menu->count] = help_text;
3048 menu->count++;
3050 /* Adjust length for possible control characters (which will
3051 be written as ^x). */
3052 for (len = strlen (txt), p = txt; *p; p++)
3053 if (*p < 27)
3054 len++;
3056 if (len > menu->width)
3057 menu->width = len;
3059 return XM_SUCCESS;
3062 /* Decide where the menu would be placed if requested at (X,Y). */
3064 void
3065 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3066 int *ulx, int *uly, int *width, int *height)
3068 IT_menu_calc_size (menu, width, height);
3069 *ulx = x + 1;
3070 *uly = y;
3071 *width += 2;
3074 struct IT_menu_state
3076 void *screen_behind;
3077 XMenu *menu;
3078 int pane;
3079 int x, y;
3083 /* Display menu, wait for user's response, and return that response. */
3086 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3087 int x0, int y0, unsigned ButtonMask, char **txt,
3088 void (*help_callback)(char *, int, int))
3090 struct IT_menu_state *state;
3091 int statecount, x, y, i, b, screensize, leave, result, onepane;
3092 int title_faces[4]; /* face to display the menu title */
3093 int faces[4], buffers_num_deleted = 0;
3094 struct frame *sf = SELECTED_FRAME();
3095 Lisp_Object saved_echo_area_message, selectface;
3097 /* Just in case we got here without a mouse present... */
3098 if (have_mouse <= 0)
3099 return XM_IA_SELECT;
3100 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3101 around the display. */
3102 if (x0 <= 0)
3103 x0 = 1;
3104 if (y0 <= 0)
3105 y0 = 1;
3107 /* We will process all the mouse events directly, so we had
3108 better prevent dos_rawgetc from stealing them from us. */
3109 mouse_preempted++;
3111 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3112 screensize = screen_size * 2;
3113 faces[0]
3114 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3115 DEFAULT_FACE_ID, 1);
3116 faces[1]
3117 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3118 DEFAULT_FACE_ID, 1);
3119 selectface = intern ("msdos-menu-select-face");
3120 faces[2] = lookup_derived_face (sf, selectface,
3121 faces[0], 1);
3122 faces[3] = lookup_derived_face (sf, selectface,
3123 faces[1], 1);
3125 /* Make sure the menu title is always displayed with
3126 `msdos-menu-active-face', no matter where the mouse pointer is. */
3127 for (i = 0; i < 4; i++)
3128 title_faces[i] = faces[3];
3130 statecount = 1;
3132 /* Don't let the title for the "Buffers" popup menu include a
3133 digit (which is ugly).
3135 This is a terrible kludge, but I think the "Buffers" case is
3136 the only one where the title includes a number, so it doesn't
3137 seem to be necessary to make this more general. */
3138 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3140 menu->text[0][7] = '\0';
3141 buffers_num_deleted = 1;
3144 /* We need to save the current echo area message, so that we could
3145 restore it below, before we exit. See the commentary below,
3146 before the call to message_with_string. */
3147 saved_echo_area_message = Fcurrent_message ();
3148 state[0].menu = menu;
3149 mouse_off ();
3150 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3152 /* Turn off the cursor. Otherwise it shows through the menu
3153 panes, which is ugly. */
3154 IT_display_cursor (0);
3156 /* Display the menu title. */
3157 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3158 if (buffers_num_deleted)
3159 menu->text[0][7] = ' ';
3160 if ((onepane = menu->count == 1 && menu->submenu[0]))
3162 menu->width = menu->submenu[0]->width;
3163 state[0].menu = menu->submenu[0];
3165 else
3167 state[0].menu = menu;
3169 state[0].x = x0 - 1;
3170 state[0].y = y0;
3171 state[0].pane = onepane;
3173 mouse_last_x = -1; /* A hack that forces display. */
3174 leave = 0;
3175 while (!leave)
3177 if (!mouse_visible) mouse_on ();
3178 mouse_check_moved ();
3179 if (sf->mouse_moved)
3181 sf->mouse_moved = 0;
3182 result = XM_IA_SELECT;
3183 mouse_get_xy (&x, &y);
3184 for (i = 0; i < statecount; i++)
3185 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3187 int dy = y - state[i].y;
3188 if (0 <= dy && dy < state[i].menu->count)
3190 if (!state[i].menu->submenu[dy])
3192 if (state[i].menu->panenumber[dy])
3193 result = XM_SUCCESS;
3194 else
3195 result = XM_IA_SELECT;
3197 *pane = state[i].pane - 1;
3198 *selidx = dy;
3199 /* We hit some part of a menu, so drop extra menus that
3200 have been opened. That does not include an open and
3201 active submenu. */
3202 if (i != statecount - 2
3203 || state[i].menu->submenu[dy] != state[i+1].menu)
3204 while (i != statecount - 1)
3206 statecount--;
3207 mouse_off ();
3208 ScreenUpdate (state[statecount].screen_behind);
3209 if (screen_virtual_segment)
3210 dosv_refresh_virtual_screen (0, screen_size);
3211 xfree (state[statecount].screen_behind);
3213 if (i == statecount - 1 && state[i].menu->submenu[dy])
3215 IT_menu_display (state[i].menu,
3216 state[i].y,
3217 state[i].x,
3218 state[i].pane,
3219 faces, 1);
3220 state[statecount].menu = state[i].menu->submenu[dy];
3221 state[statecount].pane = state[i].menu->panenumber[dy];
3222 mouse_off ();
3223 ScreenRetrieve (state[statecount].screen_behind
3224 = xmalloc (screensize));
3225 state[statecount].x
3226 = state[i].x + state[i].menu->width + 2;
3227 state[statecount].y = y;
3228 statecount++;
3232 IT_menu_display (state[statecount - 1].menu,
3233 state[statecount - 1].y,
3234 state[statecount - 1].x,
3235 state[statecount - 1].pane,
3236 faces, 1);
3238 else
3240 if ((menu_help_message || prev_menu_help_message)
3241 && menu_help_message != prev_menu_help_message)
3243 help_callback (menu_help_message,
3244 menu_help_paneno, menu_help_itemno);
3245 IT_display_cursor (0);
3246 prev_menu_help_message = menu_help_message;
3248 /* We are busy-waiting for the mouse to move, so let's be nice
3249 to other Windows applications by releasing our time slice. */
3250 __dpmi_yield ();
3252 for (b = 0; b < mouse_button_count && !leave; b++)
3254 /* Only leave if user both pressed and released the mouse, and in
3255 that order. This avoids popping down the menu pane unless
3256 the user is really done with it. */
3257 if (mouse_pressed (b, &x, &y))
3259 while (mouse_button_depressed (b, &x, &y))
3260 __dpmi_yield ();
3261 leave = 1;
3263 (void) mouse_released (b, &x, &y);
3267 mouse_off ();
3268 ScreenUpdate (state[0].screen_behind);
3269 if (screen_virtual_segment)
3270 dosv_refresh_virtual_screen (0, screen_size);
3272 /* We have a situation here. ScreenUpdate has just restored the
3273 screen contents as it was before we started drawing this menu.
3274 That includes any echo area message that could have been
3275 displayed back then. (In reality, that echo area message will
3276 almost always be the ``keystroke echo'' that echoes the sequence
3277 of menu items chosen by the user.) However, if the menu had some
3278 help messages, then displaying those messages caused Emacs to
3279 forget about the original echo area message. So when
3280 ScreenUpdate restored it, it created a discrepancy between the
3281 actual screen contents and what Emacs internal data structures
3282 know about it.
3284 To avoid this conflict, we force Emacs to restore the original
3285 echo area message as we found it when we entered this function.
3286 The irony of this is that we then erase the restored message
3287 right away, so the only purpose of restoring it is so that
3288 erasing it works correctly... */
3289 if (! NILP (saved_echo_area_message))
3290 message_with_string ("%s", saved_echo_area_message, 0);
3291 message (0);
3292 while (statecount--)
3293 xfree (state[statecount].screen_behind);
3294 IT_display_cursor (1); /* turn cursor back on */
3295 /* Clean up any mouse events that are waiting inside Emacs event queue.
3296 These events are likely to be generated before the menu was even
3297 displayed, probably because the user pressed and released the button
3298 (which invoked the menu) too quickly. If we don't remove these events,
3299 Emacs will process them after we return and surprise the user. */
3300 discard_mouse_events ();
3301 mouse_clear_clicks ();
3302 if (!kbd_buffer_events_waiting (1))
3303 clear_input_pending ();
3304 /* Allow mouse events generation by dos_rawgetc. */
3305 mouse_preempted--;
3306 return result;
3309 /* Dispose of a menu. */
3311 void
3312 XMenuDestroy (Display *foo, XMenu *menu)
3314 int i;
3315 if (menu->allocated)
3317 for (i = 0; i < menu->count; i++)
3318 if (menu->submenu[i])
3319 XMenuDestroy (foo, menu->submenu[i]);
3320 xfree (menu->text);
3321 xfree (menu->submenu);
3322 xfree (menu->panenumber);
3323 xfree (menu->help_text);
3325 xfree (menu);
3326 menu_help_message = prev_menu_help_message = NULL;
3330 x_pixel_width (struct frame *f)
3332 return FRAME_COLS (f);
3336 x_pixel_height (struct frame *f)
3338 return FRAME_LINES (f);
3340 #endif /* !HAVE_X_WINDOWS */
3342 /* ----------------------- DOS / UNIX conversion --------------------- */
3344 void msdos_downcase_filename (unsigned char *);
3346 /* Destructively turn backslashes into slashes. */
3348 void
3349 dostounix_filename (char *p)
3351 msdos_downcase_filename (p);
3353 while (*p)
3355 if (*p == '\\')
3356 *p = '/';
3357 p++;
3361 /* Destructively turn slashes into backslashes. */
3363 void
3364 unixtodos_filename (char *p)
3366 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3368 *p += 'a' - 'A';
3369 p += 2;
3372 while (*p)
3374 if (*p == '/')
3375 *p = '\\';
3376 p++;
3380 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3383 getdefdir (int drive, char *dst)
3385 char in_path[4], *p = in_path, e = errno;
3387 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3388 if (drive != 0)
3390 *p++ = drive + 'A' - 1;
3391 *p++ = ':';
3394 *p++ = '.';
3395 *p = '\0';
3396 errno = 0;
3397 _fixpath (in_path, dst);
3398 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3399 it queries the LFN support, so ignore that error. */
3400 if ((errno && errno != ENOSYS) || *dst == '\0')
3401 return 0;
3403 msdos_downcase_filename (dst);
3405 errno = e;
3406 return 1;
3409 char *
3410 emacs_root_dir (void)
3412 static char root_dir[4];
3414 sprintf (root_dir, "%c:/", 'A' + getdisk ());
3415 root_dir[0] = tolower (root_dir[0]);
3416 return root_dir;
3419 /* Remove all CR's that are followed by a LF. */
3422 crlf_to_lf (int n, unsigned char *buf)
3424 unsigned char *np = buf, *startp = buf, *endp = buf + n;
3426 if (n == 0)
3427 return n;
3428 while (buf < endp - 1)
3430 if (*buf == 0x0d)
3432 if (*(++buf) != 0x0a)
3433 *np++ = 0x0d;
3435 else
3436 *np++ = *buf++;
3438 if (buf < endp)
3439 *np++ = *buf++;
3440 return np - startp;
3443 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3444 0, 0, 0,
3445 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
3446 (void)
3448 return (_USE_LFN ? Qt : Qnil);
3451 /* Convert alphabetic characters in a filename to lower-case. */
3453 void
3454 msdos_downcase_filename (unsigned char *p)
3456 /* Always lower-case drive letters a-z, even if the filesystem
3457 preserves case in filenames.
3458 This is so MSDOS filenames could be compared by string comparison
3459 functions that are case-sensitive. Even case-preserving filesystems
3460 do not distinguish case in drive letters. */
3461 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3463 *p += 'a' - 'A';
3464 p += 2;
3467 /* Under LFN we expect to get pathnames in their true case. */
3468 if (NILP (Fmsdos_long_file_names ()))
3469 for ( ; *p; p++)
3470 if (*p >= 'A' && *p <= 'Z')
3471 *p += 'a' - 'A';
3474 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3475 1, 1, 0,
3476 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
3477 When long filenames are supported, doesn't change FILENAME.
3478 If FILENAME is not a string, returns nil.
3479 The argument object is never altered--the value is a copy. */)
3480 (Lisp_Object filename)
3482 Lisp_Object tem;
3484 if (! STRINGP (filename))
3485 return Qnil;
3487 tem = Fcopy_sequence (filename);
3488 msdos_downcase_filename (SDATA (tem));
3489 return tem;
3492 /* The Emacs root directory as determined by init_environment. */
3494 static char emacsroot[MAXPATHLEN];
3496 char *
3497 rootrelativepath (char *rel)
3499 static char result[MAXPATHLEN + 10];
3501 strcpy (result, emacsroot);
3502 strcat (result, "/");
3503 strcat (result, rel);
3504 return result;
3507 /* Define a lot of environment variables if not already defined. Don't
3508 remove anything unless you know what you're doing -- lots of code will
3509 break if one or more of these are missing. */
3511 void
3512 init_environment (int argc, char **argv, int skip_args)
3514 char *s, *t, *root;
3515 int len, i;
3516 static const char * const tempdirs[] = {
3517 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3519 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
3521 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3522 temporary files and assume "/tmp" if $TMPDIR is unset, which
3523 will break on DOS/Windows. Refuse to work if we cannot find
3524 a directory, not even "c:/", usable for that purpose. */
3525 for (i = 0; i < imax ; i++)
3527 const char *tmp = tempdirs[i];
3528 char buf[FILENAME_MAX];
3530 if (*tmp == '$')
3532 int tmp_len;
3534 tmp = getenv (tmp + 1);
3535 if (!tmp)
3536 continue;
3538 /* Some lusers set TMPDIR=e:, probably because some losing
3539 programs cannot handle multiple slashes if they use e:/.
3540 e: fails in `access' below, so we interpret e: as e:/. */
3541 tmp_len = strlen(tmp);
3542 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
3544 strcpy(buf, tmp);
3545 buf[tmp_len++] = '/', buf[tmp_len] = 0;
3546 tmp = buf;
3550 /* Note that `access' can lie to us if the directory resides on a
3551 read-only filesystem, like CD-ROM or a write-protected floppy.
3552 The only way to be really sure is to actually create a file and
3553 see if it succeeds. But I think that's too much to ask. */
3554 if (tmp && access (tmp, D_OK) == 0)
3556 setenv ("TMPDIR", tmp, 1);
3557 break;
3560 if (i >= imax)
3561 cmd_error_internal
3562 (Fcons (Qerror,
3563 Fcons (build_string ("no usable temporary directories found!!"),
3564 Qnil)),
3565 "While setting TMPDIR: ");
3567 /* Note the startup time, so we know not to clear the screen if we
3568 exit immediately; see IT_reset_terminal_modes.
3569 (Yes, I know `clock' returns zero the first time it's called, but
3570 I do this anyway, in case some wiseguy changes that at some point.) */
3571 startup_time = clock ();
3573 /* Find our root from argv[0]. Assuming argv[0] is, say,
3574 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3575 root = alloca (MAXPATHLEN + 20);
3576 _fixpath (argv[0], root);
3577 msdos_downcase_filename (root);
3578 len = strlen (root);
3579 while (len > 0 && root[len] != '/' && root[len] != ':')
3580 len--;
3581 root[len] = '\0';
3582 if (len > 4
3583 && (strcmp (root + len - 4, "/bin") == 0
3584 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
3585 root[len - 4] = '\0';
3586 else
3587 strcpy (root, "c:/emacs"); /* let's be defensive */
3588 len = strlen (root);
3589 strcpy (emacsroot, root);
3591 /* We default HOME to our root. */
3592 setenv ("HOME", root, 0);
3594 /* We default EMACSPATH to root + "/bin". */
3595 strcpy (root + len, "/bin");
3596 setenv ("EMACSPATH", root, 0);
3598 /* I don't expect anybody to ever use other terminals so the internal
3599 terminal is the default. */
3600 setenv ("TERM", "internal", 0);
3602 #ifdef HAVE_X_WINDOWS
3603 /* Emacs expects DISPLAY to be set. */
3604 setenv ("DISPLAY", "unix:0.0", 0);
3605 #endif
3607 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3608 downcase it and mirror the backslashes. */
3609 s = getenv ("COMSPEC");
3610 if (!s) s = "c:/command.com";
3611 t = alloca (strlen (s) + 1);
3612 strcpy (t, s);
3613 dostounix_filename (t);
3614 setenv ("SHELL", t, 0);
3616 /* PATH is also downcased and backslashes mirrored. */
3617 s = getenv ("PATH");
3618 if (!s) s = "";
3619 t = alloca (strlen (s) + 3);
3620 /* Current directory is always considered part of MsDos's path but it is
3621 not normally mentioned. Now it is. */
3622 strcat (strcpy (t, ".;"), s);
3623 dostounix_filename (t); /* Not a single file name, but this should work. */
3624 setenv ("PATH", t, 1);
3626 /* In some sense all dos users have root privileges, so... */
3627 setenv ("USER", "root", 0);
3628 setenv ("NAME", getenv ("USER"), 0);
3630 /* Time zone determined from country code. To make this possible, the
3631 country code may not span more than one time zone. In other words,
3632 in the USA, you lose. */
3633 if (!getenv ("TZ"))
3634 switch (dos_country_code)
3636 case 31: /* Belgium */
3637 case 32: /* The Netherlands */
3638 case 33: /* France */
3639 case 34: /* Spain */
3640 case 36: /* Hungary */
3641 case 38: /* Yugoslavia (or what's left of it?) */
3642 case 39: /* Italy */
3643 case 41: /* Switzerland */
3644 case 42: /* Tjekia */
3645 case 45: /* Denmark */
3646 case 46: /* Sweden */
3647 case 47: /* Norway */
3648 case 48: /* Poland */
3649 case 49: /* Germany */
3650 /* Daylight saving from last Sunday in March to last Sunday in
3651 September, both at 2AM. */
3652 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3653 break;
3654 case 44: /* United Kingdom */
3655 case 351: /* Portugal */
3656 case 354: /* Iceland */
3657 setenv ("TZ", "GMT+00", 0);
3658 break;
3659 case 81: /* Japan */
3660 case 82: /* Korea */
3661 setenv ("TZ", "JST-09", 0);
3662 break;
3663 case 90: /* Turkey */
3664 case 358: /* Finland */
3665 setenv ("TZ", "EET-02", 0);
3666 break;
3667 case 972: /* Israel */
3668 /* This is an approximation. (For exact rules, use the
3669 `zoneinfo/israel' file which comes with DJGPP, but you need
3670 to install it in `/usr/share/zoneinfo/' directory first.) */
3671 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3672 break;
3674 tzset ();
3679 static int break_stat; /* BREAK check mode status. */
3680 static int stdin_stat; /* stdin IOCTL status. */
3682 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3683 control chars by DOS. Determine the keyboard type. */
3686 dos_ttraw (struct tty_display_info *tty)
3688 union REGS inregs, outregs;
3689 static int first_time = 1;
3691 /* If we are called for the initial terminal, it's too early to do
3692 anything, and termscript isn't set up. */
3693 if (tty->terminal->type == output_initial)
3694 return 2;
3696 break_stat = getcbrk ();
3697 setcbrk (0);
3699 if (first_time)
3701 inregs.h.ah = 0xc0;
3702 int86 (0x15, &inregs, &outregs);
3703 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
3705 have_mouse = 0;
3707 if (1
3708 #ifdef HAVE_X_WINDOWS
3709 && inhibit_window_system
3710 #endif
3713 inregs.x.ax = 0x0021;
3714 int86 (0x33, &inregs, &outregs);
3715 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3716 if (!have_mouse)
3718 /* Reportedly, the above doesn't work for some mouse drivers. There
3719 is an additional detection method that should work, but might be
3720 a little slower. Use that as an alternative. */
3721 inregs.x.ax = 0x0000;
3722 int86 (0x33, &inregs, &outregs);
3723 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3725 if (have_mouse)
3726 mouse_button_count = outregs.x.bx;
3728 #ifndef HAVE_X_WINDOWS
3729 /* Save the cursor shape used outside Emacs. */
3730 outside_cursor = _farpeekw (_dos_ds, 0x460);
3731 #endif
3734 first_time = 0;
3736 stdin_stat = setmode (fileno (stdin), O_BINARY);
3737 return (stdin_stat != -1);
3739 else
3740 return (setmode (fileno (stdin), O_BINARY) != -1);
3743 /* Restore status of standard input and Ctrl-C checking. */
3746 dos_ttcooked (void)
3748 union REGS inregs, outregs;
3750 setcbrk (break_stat);
3751 mouse_off ();
3753 #ifndef HAVE_X_WINDOWS
3754 /* Restore the cursor shape we found on startup. */
3755 if (outside_cursor)
3757 inregs.h.ah = 1;
3758 inregs.x.cx = outside_cursor;
3759 int86 (0x10, &inregs, &outregs);
3761 #endif
3763 return (setmode (fileno (stdin), stdin_stat) != -1);
3767 /* Run command as specified by ARGV in directory DIR.
3768 The command is run with input from TEMPIN, output to
3769 file TEMPOUT and stderr to TEMPERR. */
3772 run_msdos_command (unsigned char **argv, const char *working_dir,
3773 int tempin, int tempout, int temperr, char **envv)
3775 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
3776 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3777 int msshell, result = -1, inbak, outbak, errbak, x, y;
3778 Lisp_Object cmd;
3780 /* Get current directory as MSDOS cwd is not per-process. */
3781 getwd (oldwd);
3783 /* If argv[0] is the shell, it might come in any lettercase.
3784 Since `Fmember' is case-sensitive, we need to downcase
3785 argv[0], even if we are on case-preserving filesystems. */
3786 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3787 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3789 *pl = *pa++;
3790 if (*pl >= 'A' && *pl <= 'Z')
3791 *pl += 'a' - 'A';
3793 *pl = '\0';
3795 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3796 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3797 && !strcmp ("-c", argv[1]);
3798 if (msshell)
3800 saveargv1 = argv[1];
3801 saveargv2 = argv[2];
3802 argv[1] = "/c";
3803 /* We only need to mirror slashes if a DOS shell will be invoked
3804 not via `system' (which does the mirroring itself). Yes, that
3805 means DJGPP v1.x will lose here. */
3806 if (argv[2] && argv[3])
3808 char *p = alloca (strlen (argv[2]) + 1);
3810 strcpy (argv[2] = p, saveargv2);
3811 while (*p && isspace (*p))
3812 p++;
3813 while (*p)
3815 if (*p == '/')
3816 *p++ = '\\';
3817 else
3818 p++;
3823 chdir (working_dir);
3824 inbak = dup (0);
3825 outbak = dup (1);
3826 errbak = dup (2);
3827 if (inbak < 0 || outbak < 0 || errbak < 0)
3828 goto done; /* Allocation might fail due to lack of descriptors. */
3830 if (have_mouse > 0)
3831 mouse_get_xy (&x, &y);
3833 if (!noninteractive)
3834 dos_ttcooked (); /* do it here while 0 = stdin */
3836 dup2 (tempin, 0);
3837 dup2 (tempout, 1);
3838 dup2 (temperr, 2);
3840 if (msshell && !argv[3])
3842 /* MS-DOS native shells are too restrictive. For starters, they
3843 cannot grok commands longer than 126 characters. In DJGPP v2
3844 and later, `system' is much smarter, so we'll call it instead. */
3846 const char *cmnd;
3848 /* A shell gets a single argument--its full command
3849 line--whose original was saved in `saveargv2'. */
3851 /* Don't let them pass empty command lines to `system', since
3852 with some shells it will try to invoke an interactive shell,
3853 which will hang Emacs. */
3854 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
3856 if (*cmnd)
3858 extern char **environ;
3859 char **save_env = environ;
3860 int save_system_flags = __system_flags;
3862 /* Request the most powerful version of `system'. We need
3863 all the help we can get to avoid calling stock DOS shells. */
3864 __system_flags = (__system_redirect
3865 | __system_use_shell
3866 | __system_allow_multiple_cmds
3867 | __system_allow_long_cmds
3868 | __system_handle_null_commands
3869 | __system_emulate_chdir);
3871 environ = envv;
3872 result = system (cmnd);
3873 __system_flags = save_system_flags;
3874 environ = save_env;
3876 else
3877 result = 0; /* emulate Unixy shell behavior with empty cmd line */
3879 else
3880 result = spawnve (P_WAIT, argv[0], (char **)argv, envv);
3882 dup2 (inbak, 0);
3883 dup2 (outbak, 1);
3884 dup2 (errbak, 2);
3885 emacs_close (inbak);
3886 emacs_close (outbak);
3887 emacs_close (errbak);
3889 if (!noninteractive)
3890 dos_ttraw (CURTTY ());
3891 if (have_mouse > 0)
3893 mouse_init ();
3894 mouse_moveto (x, y);
3897 /* Some programs might change the meaning of the highest bit of the
3898 text attribute byte, so we get blinking characters instead of the
3899 bright background colors. Restore that. */
3900 if (!noninteractive)
3901 bright_bg ();
3903 done:
3904 chdir (oldwd);
3905 if (msshell)
3907 argv[1] = saveargv1;
3908 argv[2] = saveargv2;
3910 return result;
3913 void
3914 croak (char *badfunc)
3916 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3917 reset_all_sys_modes ();
3918 exit (1);
3922 * A few unimplemented functions that we silently ignore.
3924 int setpgrp (void) {return 0; }
3925 int setpriority (int x, int y, int z) { return 0; }
3927 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3929 /* Augment DJGPP library POSIX signal functions. This is needed
3930 as of DJGPP v2.01, but might be in the library in later releases. */
3932 #include <libc/bss.h>
3934 /* A counter to know when to re-initialize the static sets. */
3935 static int sigprocmask_count = -1;
3937 /* Which signals are currently blocked (initially none). */
3938 static sigset_t current_mask;
3940 /* Which signals are pending (initially none). */
3941 static sigset_t msdos_pending_signals;
3943 /* Previous handlers to restore when the blocked signals are unblocked. */
3944 typedef void (*sighandler_t)(int);
3945 static sighandler_t prev_handlers[320];
3947 /* A signal handler which just records that a signal occurred
3948 (it will be raised later, if and when the signal is unblocked). */
3949 static void
3950 sig_suspender (int signo)
3952 sigaddset (&msdos_pending_signals, signo);
3956 sigprocmask (int how, const sigset_t *new_set, sigset_t *old_set)
3958 int signo;
3959 sigset_t new_mask;
3961 /* If called for the first time, initialize. */
3962 if (sigprocmask_count != __bss_count)
3964 sigprocmask_count = __bss_count;
3965 sigemptyset (&msdos_pending_signals);
3966 sigemptyset (&current_mask);
3967 for (signo = 0; signo < 320; signo++)
3968 prev_handlers[signo] = SIG_ERR;
3971 if (old_set)
3972 *old_set = current_mask;
3974 if (new_set == 0)
3975 return 0;
3977 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3979 errno = EINVAL;
3980 return -1;
3983 sigemptyset (&new_mask);
3985 /* DJGPP supports upto 320 signals. */
3986 for (signo = 0; signo < 320; signo++)
3988 if (sigismember (&current_mask, signo))
3989 sigaddset (&new_mask, signo);
3990 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3992 sigaddset (&new_mask, signo);
3994 /* SIGKILL is silently ignored, as on other platforms. */
3995 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3996 prev_handlers[signo] = signal (signo, sig_suspender);
3998 if (( how == SIG_UNBLOCK
3999 && sigismember (&new_mask, signo)
4000 && sigismember (new_set, signo))
4001 || (how == SIG_SETMASK
4002 && sigismember (&new_mask, signo)
4003 && !sigismember (new_set, signo)))
4005 sigdelset (&new_mask, signo);
4006 if (prev_handlers[signo] != SIG_ERR)
4008 signal (signo, prev_handlers[signo]);
4009 prev_handlers[signo] = SIG_ERR;
4011 if (sigismember (&msdos_pending_signals, signo))
4013 sigdelset (&msdos_pending_signals, signo);
4014 raise (signo);
4018 current_mask = new_mask;
4019 return 0;
4022 #endif /* not __DJGPP_MINOR__ < 2 */
4024 #ifndef HAVE_SELECT
4025 #include "sysselect.h"
4027 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4028 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4029 ((long)(time).tv_sec < 0 \
4030 || ((time).tv_sec == 0 \
4031 && (long)(time).tv_usec <= 0))
4032 #endif
4034 /* This yields the rest of the current time slice to the task manager.
4035 It should be called by any code which knows that it has nothing
4036 useful to do except idle.
4038 I don't use __dpmi_yield here, since versions of library before 2.02
4039 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4040 on some versions of Windows 9X. */
4042 void
4043 dos_yield_time_slice (void)
4045 _go32_dpmi_registers r;
4047 r.x.ax = 0x1680;
4048 r.x.ss = r.x.sp = r.x.flags = 0;
4049 _go32_dpmi_simulate_int (0x2f, &r);
4050 if (r.h.al == 0x80)
4051 errno = ENOSYS;
4054 /* Only event queue is checked. */
4055 /* We don't have to call timer_check here
4056 because wait_reading_process_output takes care of that. */
4058 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
4059 EMACS_TIME *timeout)
4061 int check_input;
4062 struct time t;
4064 check_input = 0;
4065 if (rfds)
4067 check_input = FD_ISSET (0, rfds);
4068 FD_ZERO (rfds);
4070 if (wfds)
4071 FD_ZERO (wfds);
4072 if (efds)
4073 FD_ZERO (efds);
4075 if (nfds != 1)
4076 abort ();
4078 /* If we are looking only for the terminal, with no timeout,
4079 just read it and wait -- that's more efficient. */
4080 if (!timeout)
4082 while (!detect_input_pending ())
4084 dos_yield_time_slice ();
4087 else
4089 EMACS_TIME clnow, cllast, cldiff;
4091 gettime (&t);
4092 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4094 while (!check_input || !detect_input_pending ())
4096 gettime (&t);
4097 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4098 EMACS_SUB_TIME (cldiff, clnow, cllast);
4100 /* When seconds wrap around, we assume that no more than
4101 1 minute passed since last `gettime'. */
4102 if (EMACS_TIME_NEG_P (cldiff))
4103 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4104 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4106 /* Stop when timeout value crosses zero. */
4107 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4108 return 0;
4109 cllast = clnow;
4110 dos_yield_time_slice ();
4114 FD_SET (0, rfds);
4115 return 1;
4117 #endif
4120 * Define overlaid functions:
4122 * chdir -> sys_chdir
4123 * tzset -> init_gettimeofday
4124 * abort -> dos_abort
4127 #ifdef chdir
4128 #undef chdir
4129 extern int chdir (const char *);
4132 sys_chdir (const char *path)
4134 int len = strlen (path);
4135 char *tmp = (char *)path;
4137 if (*tmp && tmp[1] == ':')
4139 if (getdisk () != tolower (tmp[0]) - 'a')
4140 setdisk (tolower (tmp[0]) - 'a');
4141 tmp += 2; /* strip drive: KFS 1995-07-06 */
4142 len -= 2;
4145 if (len > 1 && (tmp[len - 1] == '/'))
4147 char *tmp1 = (char *) alloca (len + 1);
4148 strcpy (tmp1, tmp);
4149 tmp1[len - 1] = 0;
4150 tmp = tmp1;
4152 return chdir (tmp);
4154 #endif
4156 #ifdef tzset
4157 #undef tzset
4158 extern void tzset (void);
4160 void
4161 init_gettimeofday (void)
4163 time_t ltm, gtm;
4164 struct tm *lstm;
4166 tzset ();
4167 ltm = gtm = time (NULL);
4168 ltm = mktime (lstm = localtime (&ltm));
4169 gtm = mktime (gmtime (&gtm));
4170 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4171 time_rec.tm_isdst = lstm->tm_isdst;
4172 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4174 #endif
4176 #ifdef abort
4177 #undef abort
4178 void
4179 dos_abort (char *file, int line)
4181 char buffer1[200], buffer2[400];
4182 int i, j;
4184 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4185 for (i = j = 0; buffer1[i]; i++) {
4186 buffer2[j++] = buffer1[i];
4187 buffer2[j++] = 0x70;
4189 dosmemput (buffer2, j, (int)ScreenPrimary);
4190 ScreenSetCursor (2, 0);
4191 abort ();
4193 #else
4194 void
4195 abort (void)
4197 dos_ttcooked ();
4198 ScreenSetCursor (10, 0);
4199 cputs ("\r\n\nEmacs aborted!\r\n");
4200 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4201 if (screen_virtual_segment)
4202 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4203 /* Generate traceback, so we could tell whodunit. */
4204 signal (SIGINT, SIG_DFL);
4205 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4206 #else /* __DJGPP_MINOR__ >= 2 */
4207 raise (SIGABRT);
4208 #endif /* __DJGPP_MINOR__ >= 2 */
4209 exit (2);
4211 #endif
4213 void
4214 syms_of_msdos (void)
4216 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4217 staticpro (&recent_doskeys);
4219 #ifndef HAVE_X_WINDOWS
4221 /* The following two are from xfns.c: */
4222 Qreverse = intern_c_string ("reverse");
4223 staticpro (&Qreverse);
4225 DEFVAR_LISP ("dos-unsupported-char-glyph", Vdos_unsupported_char_glyph,
4226 doc: /* *Glyph to display instead of chars not supported by current codepage.
4227 This variable is used only by MS-DOS terminals. */);
4228 Vdos_unsupported_char_glyph = make_number ('\177');
4230 #endif
4232 defsubr (&Srecent_doskeys);
4233 defsubr (&Smsdos_long_file_names);
4234 defsubr (&Smsdos_downcase_filename);
4235 defsubr (&Smsdos_remember_default_colors);
4236 defsubr (&Smsdos_set_mouse_buttons);
4239 #endif /* MSDOS */