* doc/misc/calc.texi (ISO-8601): New section.
[emacs.git] / src / msdos.c
blob433bf1074d8c3e7d82c59b57400e409e70ed4a38
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
3 Copyright (C) 1993-1997, 1999-2012 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* Contributed by Morten Welinder */
21 /* New display, keyboard, and mouse control by Kim F. Storm */
23 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
25 #include <config.h>
27 #ifdef MSDOS
28 #include <setjmp.h>
29 #include "lisp.h"
30 #include <stdio.h>
31 #include <time.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 /* gettime and settime in dos.h clash with their namesakes from
35 gnulib, so we move out of our way the prototypes in dos.h. */
36 #define gettime dos_h_gettime_
37 #define settime dos_h_settime_
38 #include <dos.h>
39 #undef gettime
40 #undef settime
41 #include <errno.h>
42 #include <sys/stat.h> /* for _fixpath */
43 #include <unistd.h> /* for chdir, dup, dup2, etc. */
44 #include <dir.h> /* for getdisk */
45 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
46 #include <fcntl.h>
47 #include <io.h> /* for setmode */
48 #include <dpmi.h> /* for __dpmi_xxx stuff */
49 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
50 #include <libc/dosio.h> /* for _USE_LFN */
51 #include <conio.h> /* for cputs */
53 #include "msdos.h"
54 #include "systime.h"
55 #include "frame.h"
56 #include "termhooks.h"
57 #include "termchar.h"
58 #include "dispextern.h"
59 #include "dosfns.h"
60 #include "termopts.h"
61 #include "character.h"
62 #include "coding.h"
63 #include "disptab.h"
64 #include "window.h"
65 #include "buffer.h"
66 #include "commands.h"
67 #include "blockinput.h"
68 #include "keyboard.h"
69 #include "intervals.h"
70 #include <go32.h>
71 #include <pc.h>
72 #include <ctype.h>
73 /* #include <process.h> */
74 /* Damn that local process.h! Instead we can define P_WAIT and
75 spawnve ourselves. */
76 #define P_WAIT 1
77 extern int spawnve (int, const char *, char *const [], char *const []);
79 #ifndef _USE_LFN
80 #define _USE_LFN 0
81 #endif
83 #ifndef _dos_ds
84 #define _dos_ds _go32_info_block.selector_for_linear_memory
85 #endif
87 #include <signal.h>
88 #include "syssignal.h"
90 #include "careadlinkat.h"
91 #include "allocator.h"
93 #ifndef SYSTEM_MALLOC
95 #ifdef GNU_MALLOC
97 /* If other `malloc' than ours is used, force our `sbrk' behave like
98 Unix programs expect (resize memory blocks to keep them contiguous).
99 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
100 because that's what `gmalloc' expects to get. */
101 #include <crt0.h>
103 #ifdef REL_ALLOC
104 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
105 #else /* not REL_ALLOC */
106 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
107 #endif /* not REL_ALLOC */
108 #endif /* GNU_MALLOC */
110 #endif /* not SYSTEM_MALLOC */
112 /* Return the current timestamp in milliseconds since midnight. */
113 static unsigned long
114 event_timestamp (void)
116 struct timespec t;
117 unsigned long s;
119 gettime (&t);
120 s = t.tv_sec;
121 s %= 86400;
122 s *= 1000;
123 s += t.tv_nsec * 1000000;
125 return s;
129 /* ------------------------ Mouse control ---------------------------
131 * Coordinates are in screen positions and zero based.
132 * Mouse buttons are numbered from left to right and also zero based.
135 /* This used to be in termhooks.h, but mainstream Emacs code no longer
136 uses it, and it was removed... */
137 #define NUM_MOUSE_BUTTONS (5)
139 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
140 static int mouse_visible;
142 static int mouse_last_x;
143 static int mouse_last_y;
145 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
146 static int mouse_button_count;
148 void
149 mouse_on (void)
151 union REGS regs;
153 if (have_mouse > 0 && !mouse_visible)
155 struct tty_display_info *tty = CURTTY ();
157 if (tty->termscript)
158 fprintf (tty->termscript, "<M_ON>");
159 regs.x.ax = 0x0001;
160 int86 (0x33, &regs, &regs);
161 mouse_visible = 1;
165 void
166 mouse_off (void)
168 union REGS regs;
170 if (have_mouse > 0 && mouse_visible)
172 struct tty_display_info *tty = CURTTY ();
174 if (tty->termscript)
175 fprintf (tty->termscript, "<M_OFF>");
176 regs.x.ax = 0x0002;
177 int86 (0x33, &regs, &regs);
178 mouse_visible = 0;
182 static void
183 mouse_setup_buttons (int n_buttons)
185 if (n_buttons == 3)
187 mouse_button_count = 3;
188 mouse_button_translate[0] = 0; /* Left */
189 mouse_button_translate[1] = 2; /* Middle */
190 mouse_button_translate[2] = 1; /* Right */
192 else /* two, what else? */
194 mouse_button_count = 2;
195 mouse_button_translate[0] = 0;
196 mouse_button_translate[1] = 1;
200 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
201 1, 1, "NSet number of mouse buttons to: ",
202 doc: /* Set the number of mouse buttons to use by Emacs.
203 This is useful with mice that report the number of buttons inconsistently,
204 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
205 them. This happens with wheeled mice on Windows 9X, for example. */)
206 (Lisp_Object nbuttons)
208 int n;
210 CHECK_NUMBER (nbuttons);
211 n = XINT (nbuttons);
212 if (n < 2 || n > 3)
213 xsignal2 (Qargs_out_of_range,
214 build_string ("only 2 or 3 mouse buttons are supported"),
215 nbuttons);
216 mouse_setup_buttons (n);
217 return Qnil;
220 static void
221 mouse_get_xy (int *x, int *y)
223 union REGS regs;
225 regs.x.ax = 0x0003;
226 int86 (0x33, &regs, &regs);
227 *x = regs.x.cx / 8;
228 *y = regs.x.dx / 8;
231 void
232 mouse_moveto (int x, int y)
234 union REGS regs;
235 struct tty_display_info *tty = CURTTY ();
237 if (tty->termscript)
238 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
239 regs.x.ax = 0x0004;
240 mouse_last_x = regs.x.cx = x * 8;
241 mouse_last_y = regs.x.dx = y * 8;
242 int86 (0x33, &regs, &regs);
245 static int
246 mouse_pressed (int b, int *xp, int *yp)
248 union REGS regs;
250 if (b >= mouse_button_count)
251 return 0;
252 regs.x.ax = 0x0005;
253 regs.x.bx = mouse_button_translate[b];
254 int86 (0x33, &regs, &regs);
255 if (regs.x.bx)
256 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
257 return (regs.x.bx != 0);
260 static int
261 mouse_released (int b, int *xp, int *yp)
263 union REGS regs;
265 if (b >= mouse_button_count)
266 return 0;
267 regs.x.ax = 0x0006;
268 regs.x.bx = mouse_button_translate[b];
269 int86 (0x33, &regs, &regs);
270 if (regs.x.bx)
271 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
272 return (regs.x.bx != 0);
275 static int
276 mouse_button_depressed (int b, int *xp, int *yp)
278 union REGS regs;
280 if (b >= mouse_button_count)
281 return 0;
282 regs.x.ax = 0x0003;
283 int86 (0x33, &regs, &regs);
284 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
286 *xp = regs.x.cx / 8;
287 *yp = regs.x.dx / 8;
288 return 1;
290 return 0;
293 void
294 mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
295 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
296 Time *time)
298 int ix, iy;
299 Lisp_Object frame, tail;
301 /* Clear the mouse-moved flag for every frame on this display. */
302 FOR_EACH_FRAME (tail, frame)
303 XFRAME (frame)->mouse_moved = 0;
305 *f = SELECTED_FRAME ();
306 *bar_window = Qnil;
307 mouse_get_xy (&ix, &iy);
308 *time = event_timestamp ();
309 *x = make_number (mouse_last_x = ix);
310 *y = make_number (mouse_last_y = iy);
313 static void
314 mouse_check_moved (void)
316 int x, y;
318 mouse_get_xy (&x, &y);
319 SELECTED_FRAME ()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
320 mouse_last_x = x;
321 mouse_last_y = y;
324 /* Force the mouse driver to ``forget'' about any button clicks until
325 now. */
326 static void
327 mouse_clear_clicks (void)
329 int b;
331 for (b = 0; b < mouse_button_count; b++)
333 int dummy_x, dummy_y;
335 (void) mouse_pressed (b, &dummy_x, &dummy_y);
336 (void) mouse_released (b, &dummy_x, &dummy_y);
340 void
341 mouse_init (void)
343 union REGS regs;
344 struct tty_display_info *tty = CURTTY ();
346 if (tty->termscript)
347 fprintf (tty->termscript, "<M_INIT>");
349 regs.x.ax = 0x0021;
350 int86 (0x33, &regs, &regs);
352 /* Reset the mouse last press/release info. It seems that Windows
353 doesn't do that automatically when function 21h is called, which
354 causes Emacs to ``remember'' the click that switched focus to the
355 window just before Emacs was started from that window. */
356 mouse_clear_clicks ();
358 regs.x.ax = 0x0007;
359 regs.x.cx = 0;
360 regs.x.dx = 8 * (ScreenCols () - 1);
361 int86 (0x33, &regs, &regs);
363 regs.x.ax = 0x0008;
364 regs.x.cx = 0;
365 regs.x.dx = 8 * (ScreenRows () - 1);
366 int86 (0x33, &regs, &regs);
368 mouse_moveto (0, 0);
369 mouse_visible = 0;
372 /* ------------------------- Screen control ----------------------
376 static int internal_terminal = 0;
378 #ifndef HAVE_X_WINDOWS
379 extern unsigned char ScreenAttrib;
380 static int screen_face;
382 static int screen_size_X;
383 static int screen_size_Y;
384 static int screen_size;
386 static int current_pos_X;
387 static int current_pos_Y;
388 static int new_pos_X;
389 static int new_pos_Y;
391 static void *startup_screen_buffer;
392 static int startup_screen_size_X;
393 static int startup_screen_size_Y;
394 static int startup_pos_X;
395 static int startup_pos_Y;
396 static unsigned char startup_screen_attrib;
398 static clock_t startup_time;
400 static int term_setup_done;
402 static unsigned short outside_cursor;
404 /* Similar to the_only_frame. */
405 struct tty_display_info the_only_display_info;
407 /* Support for DOS/V (allows Japanese characters to be displayed on
408 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
410 /* Holds the address of the text-mode screen buffer. */
411 static unsigned long screen_old_address = 0;
412 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
413 static unsigned short screen_virtual_segment = 0;
414 static unsigned short screen_virtual_offset = 0;
415 extern Lisp_Object Qcursor_type;
416 extern Lisp_Object Qbar, Qhbar;
418 /* The screen colors of the current frame, which serve as the default
419 colors for newly-created frames. */
420 static int initial_screen_colors[2];
422 /* Update the screen from a part of relocated DOS/V screen buffer which
423 begins at OFFSET and includes COUNT characters. */
424 static void
425 dosv_refresh_virtual_screen (int offset, int count)
427 __dpmi_regs regs;
429 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
430 return;
432 regs.h.ah = 0xff; /* update relocated screen */
433 regs.x.es = screen_virtual_segment;
434 regs.x.di = screen_virtual_offset + offset;
435 regs.x.cx = count;
436 __dpmi_int (0x10, &regs);
439 static void
440 dos_direct_output (int y, int x, char *buf, int len)
442 int t0 = 2 * (x + y * screen_size_X);
443 int t = t0 + (int) ScreenPrimary;
444 int l0 = len;
446 /* This is faster. */
447 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
448 _farnspokeb (t, *buf);
450 if (screen_virtual_segment)
451 dosv_refresh_virtual_screen (t0, l0);
453 #endif
455 #ifndef HAVE_X_WINDOWS
457 static int blink_bit = -1; /* the state of the blink bit at startup */
459 /* Enable bright background colors. */
460 static void
461 bright_bg (void)
463 union REGS regs;
465 /* Remember the original state of the blink/bright-background bit.
466 It is stored at 0040:0065h in the BIOS data area. */
467 if (blink_bit == -1)
468 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
470 regs.h.bl = 0;
471 regs.x.ax = 0x1003;
472 int86 (0x10, &regs, &regs);
475 /* Disable bright background colors (and enable blinking) if we found
476 the video system in that state at startup. */
477 static void
478 maybe_enable_blinking (void)
480 if (blink_bit == 1)
482 union REGS regs;
484 regs.h.bl = 1;
485 regs.x.ax = 0x1003;
486 int86 (0x10, &regs, &regs);
490 /* Return non-zero if the system has a VGA adapter. */
491 static int
492 vga_installed (void)
494 union REGS regs;
496 regs.x.ax = 0x1a00;
497 int86 (0x10, &regs, &regs);
498 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
499 return 1;
500 return 0;
503 /* Set the screen dimensions so that it can show no less than
504 ROWS x COLS frame. */
506 void
507 dos_set_window_size (int *rows, int *cols)
509 char video_name[30];
510 union REGS regs;
511 Lisp_Object video_mode;
512 int video_mode_value, have_vga = 0;
513 int current_rows = ScreenRows (), current_cols = ScreenCols ();
515 if (*rows == current_rows && *cols == current_cols)
516 return;
518 mouse_off ();
519 have_vga = vga_installed ();
521 /* If the user specified a special video mode for these dimensions,
522 use that mode. */
523 video_mode
524 = Fsymbol_value (Fintern_soft (make_formatted_string
525 (video_name, "screen-dimensions-%dx%d",
526 *rows, *cols), Qnil));
528 if (INTEGERP (video_mode)
529 && (video_mode_value = XINT (video_mode)) > 0)
531 regs.x.ax = video_mode_value;
532 int86 (0x10, &regs, &regs);
534 if (have_mouse)
536 /* Must hardware-reset the mouse, or else it won't update
537 its notion of screen dimensions for some non-standard
538 video modes. This is *painfully* slow... */
539 regs.x.ax = 0;
540 int86 (0x33, &regs, &regs);
544 /* Find one of the dimensions supported by standard EGA/VGA
545 which gives us at least the required dimensions. */
546 else
548 static struct {
549 int rows, need_vga;
550 } std_dimension[] = {
551 {25, 0},
552 {28, 1},
553 {35, 0},
554 {40, 1},
555 {43, 0},
556 {50, 1}
558 int i = 0;
560 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
562 if (std_dimension[i].need_vga <= have_vga
563 && std_dimension[i].rows >= *rows)
565 if (std_dimension[i].rows != current_rows
566 || *cols != current_cols)
567 _set_screen_lines (std_dimension[i].rows);
568 break;
570 i++;
575 if (have_mouse)
577 mouse_init ();
578 mouse_on ();
581 /* Tell the caller what dimensions have been REALLY set. */
582 *rows = ScreenRows ();
583 *cols = ScreenCols ();
585 /* Update Emacs' notion of screen dimensions. */
586 screen_size_X = *cols;
587 screen_size_Y = *rows;
588 screen_size = *cols * *rows;
590 /* If the dimensions changed, the mouse highlight info is invalid. */
591 if (current_rows != *rows || current_cols != *cols)
593 struct frame *f = SELECTED_FRAME ();
594 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
595 Lisp_Object window = hlinfo->mouse_face_window;
597 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
599 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
600 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
601 hlinfo->mouse_face_window = Qnil;
605 /* Enable bright background colors. */
606 bright_bg ();
608 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
609 be defensive anyway. */
610 if (screen_virtual_segment)
611 dosv_refresh_virtual_screen (0, *cols * *rows);
614 /* If we write a character in the position where the mouse is,
615 the mouse cursor may need to be refreshed. */
617 static void
618 mouse_off_maybe (void)
620 int x, y;
622 if (!mouse_visible)
623 return;
625 mouse_get_xy (&x, &y);
626 if (y != new_pos_Y || x < new_pos_X)
627 return;
629 mouse_off ();
632 #define DEFAULT_CURSOR_START (-1)
633 #define DEFAULT_CURSOR_WIDTH (-1)
634 #define BOX_CURSOR_WIDTH (-32)
636 /* Set cursor to begin at scan line START_LINE in the character cell
637 and extend for WIDTH scan lines. Scan lines are counted from top
638 of the character cell, starting from zero. */
639 static void
640 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
642 unsigned desired_cursor;
643 __dpmi_regs regs;
644 int max_line, top_line, bot_line;
645 struct tty_display_info *tty = FRAME_TTY (f);
647 /* Avoid the costly BIOS call if F isn't the currently selected
648 frame. Allow for NULL as unconditionally meaning the selected
649 frame. */
650 if (f && f != SELECTED_FRAME ())
651 return;
653 if (tty->termscript)
654 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
656 /* The character cell size in scan lines is stored at 40:85 in the
657 BIOS data area. */
658 max_line = _farpeekw (_dos_ds, 0x485) - 1;
659 switch (max_line)
661 default: /* this relies on CGA cursor emulation being ON! */
662 case 7:
663 bot_line = 7;
664 break;
665 case 9:
666 bot_line = 9;
667 break;
668 case 13:
669 bot_line = 12;
670 break;
671 case 15:
672 bot_line = 14;
673 break;
676 if (width < 0)
678 if (width == BOX_CURSOR_WIDTH)
680 top_line = 0;
681 bot_line = max_line;
683 else if (start_line != DEFAULT_CURSOR_START)
685 top_line = start_line;
686 bot_line = top_line - width - 1;
688 else if (width != DEFAULT_CURSOR_WIDTH)
690 top_line = 0;
691 bot_line = -1 - width;
693 else
694 top_line = bot_line + 1;
696 else if (width == 0)
698 /* [31, 0] seems to DTRT for all screen sizes. */
699 top_line = 31;
700 bot_line = 0;
702 else /* WIDTH is positive */
704 if (start_line != DEFAULT_CURSOR_START)
705 bot_line = start_line;
706 top_line = bot_line - (width - 1);
709 /* If the current cursor shape is already what they want, we are
710 history here. */
711 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
712 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
713 return;
715 regs.h.ah = 1;
716 regs.x.cx = desired_cursor;
717 __dpmi_int (0x10, &regs);
720 static void
721 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
723 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
725 /* Just BAR means the normal EGA/VGA cursor. */
726 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
728 else if (CONSP (cursor_type)
729 && (EQ (XCAR (cursor_type), Qbar)
730 || EQ (XCAR (cursor_type), Qhbar)))
732 Lisp_Object bar_parms = XCDR (cursor_type);
733 int width;
735 if (INTEGERP (bar_parms))
737 /* Feature: negative WIDTH means cursor at the top
738 of the character cell, zero means invisible cursor. */
739 width = XINT (bar_parms);
740 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
741 width);
743 else if (CONSP (bar_parms)
744 && INTEGERP (XCAR (bar_parms))
745 && INTEGERP (XCDR (bar_parms)))
747 int start_line = XINT (XCDR (bar_parms));
749 width = XINT (XCAR (bar_parms));
750 msdos_set_cursor_shape (f, start_line, width);
753 else
755 /* Treat anything unknown as "box cursor". This includes nil, so
756 that a frame which doesn't specify a cursor type gets a box,
757 which is the default in Emacs. */
758 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
762 static void
763 IT_ring_bell (struct frame *f)
765 if (visible_bell)
767 mouse_off ();
768 ScreenVisualBell ();
770 else
772 union REGS inregs, outregs;
773 inregs.h.ah = 2;
774 inregs.h.dl = 7;
775 intdos (&inregs, &outregs);
779 /* Given a face id FACE, extract the face parameters to be used for
780 display until the face changes. The face parameters (actually, its
781 color) are used to construct the video attribute byte for each
782 glyph during the construction of the buffer that is then blitted to
783 the video RAM. */
784 static void
785 IT_set_face (int face)
787 struct frame *sf = SELECTED_FRAME ();
788 struct face *fp = FACE_FROM_ID (sf, face);
789 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
790 unsigned long fg, bg, dflt_fg, dflt_bg;
791 struct tty_display_info *tty = FRAME_TTY (sf);
793 if (!fp)
795 fp = dfp;
796 /* The default face for the frame should always be realized and
797 cached. */
798 if (!fp)
799 emacs_abort ();
801 screen_face = face;
802 fg = fp->foreground;
803 bg = fp->background;
804 dflt_fg = dfp->foreground;
805 dflt_bg = dfp->background;
807 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
808 mean use the colors of the default face. Note that we assume all
809 16 colors to be available for the background, since Emacs switches
810 on this mode (and loses the blinking attribute) at startup. */
811 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
812 fg = FRAME_FOREGROUND_PIXEL (sf);
813 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
814 fg = FRAME_BACKGROUND_PIXEL (sf);
815 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
816 bg = FRAME_BACKGROUND_PIXEL (sf);
817 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
818 bg = FRAME_FOREGROUND_PIXEL (sf);
820 /* Make sure highlighted lines really stand out, come what may. */
821 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
823 unsigned long tem = fg;
825 fg = bg;
826 bg = tem;
828 /* If the user requested inverse video, obey. */
829 if (inverse_video)
831 unsigned long tem2 = fg;
833 fg = bg;
834 bg = tem2;
836 if (tty->termscript)
837 fprintf (tty->termscript, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face,
838 fp->foreground, fp->background, fg, bg);
839 if (fg >= 0 && fg < 16)
841 ScreenAttrib &= 0xf0;
842 ScreenAttrib |= fg;
844 if (bg >= 0 && bg < 16)
846 ScreenAttrib &= 0x0f;
847 ScreenAttrib |= ((bg & 0x0f) << 4);
851 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
852 width of a DOS display in any known text mode. We multiply by 2 to
853 accommodate the screen attribute byte. */
854 #define MAX_SCREEN_BUF 160*2
856 extern unsigned char *encode_terminal_code (struct glyph *, int,
857 struct coding_system *);
859 static void
860 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
862 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
863 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
864 register int sl = str_len;
865 struct tty_display_info *tty = FRAME_TTY (f);
866 struct frame *sf;
867 unsigned char *conversion_buffer;
869 /* If terminal_coding does any conversion, use it, otherwise use
870 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
871 because it always returns 1 if terminal_coding.src_multibyte is 1. */
872 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
874 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
875 coding = &safe_terminal_coding;
877 if (str_len <= 0) return;
879 sf = SELECTED_FRAME ();
881 /* Since faces get cached and uncached behind our back, we can't
882 rely on their indices in the cache being consistent across
883 invocations. So always reset the screen face to the default
884 face of the frame, before writing glyphs, and let the glyphs
885 set the right face if it's different from the default. */
886 IT_set_face (DEFAULT_FACE_ID);
888 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
889 the tail. */
890 coding->mode &= ~CODING_MODE_LAST_BLOCK;
891 screen_bp = &screen_buf[0];
892 while (sl > 0)
894 int cf;
895 int n;
897 /* If the face of this glyph is different from the current
898 screen face, update the screen attribute byte. */
899 cf = str->face_id;
900 if (cf != screen_face)
901 IT_set_face (cf); /* handles invalid faces gracefully */
903 /* Identify a run of glyphs with the same face. */
904 for (n = 1; n < sl; ++n)
905 if (str[n].face_id != cf)
906 break;
908 if (n >= sl)
909 /* This is the last glyph. */
910 coding->mode |= CODING_MODE_LAST_BLOCK;
912 conversion_buffer = encode_terminal_code (str, n, coding);
913 if (coding->produced > 0)
915 /* Copy the encoded bytes to the screen buffer. */
916 for (bp = conversion_buffer; coding->produced--; bp++)
918 /* Paranoia: discard bytes that would overrun the end of
919 the screen buffer. */
920 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
922 *screen_bp++ = (unsigned char)*bp;
923 *screen_bp++ = ScreenAttrib;
925 if (tty->termscript)
926 fputc (*bp, tty->termscript);
929 /* Update STR and its remaining length. */
930 str += n;
931 sl -= n;
934 /* Dump whatever we have in the screen buffer. */
935 mouse_off_maybe ();
936 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
937 if (screen_virtual_segment)
938 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
939 new_pos_X += (screen_bp - screen_buf) / 2;
942 /************************************************************************
943 Mouse Highlight (and friends..)
944 ************************************************************************/
946 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
947 static Lisp_Object last_mouse_window;
949 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
952 popup_activated (void)
954 return mouse_preempted;
957 /* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
958 window W. X is relative to TEXT_AREA in W. HL is a face override
959 for drawing the glyphs. */
960 void
961 tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
962 int start_hpos, int end_hpos,
963 enum draw_glyphs_face hl)
965 struct frame *f = XFRAME (WINDOW_FRAME (w));
966 struct tty_display_info *tty = FRAME_TTY (f);
967 Mouse_HLInfo *hlinfo = &tty->mouse_highlight;
969 if (hl == DRAW_MOUSE_FACE)
971 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
972 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
973 int nglyphs = end_hpos - start_hpos;
974 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
975 int start_offset = offset;
977 if (tty->termscript)
978 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
979 kstart, kstart + nglyphs - 1, vpos);
981 mouse_off ();
982 IT_set_face (hlinfo->mouse_face_face_id);
983 /* Since we are going to change only the _colors_ of already
984 displayed text, there's no need to go through all the pain of
985 generating and encoding the text from the glyphs. Instead,
986 we simply poke the attribute byte of each affected position
987 in video memory with the colors computed by IT_set_face! */
988 _farsetsel (_dos_ds);
989 while (nglyphs--)
991 _farnspokeb (offset, ScreenAttrib);
992 offset += 2;
994 if (screen_virtual_segment)
995 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
996 mouse_on ();
998 else if (hl == DRAW_NORMAL_TEXT)
1000 /* We are removing a previously-drawn mouse highlight. The
1001 safest way to do so is to redraw the glyphs anew, since all
1002 kinds of faces and display tables could have changed behind
1003 our back. */
1004 int nglyphs = end_hpos - start_hpos;
1005 int save_x = new_pos_X, save_y = new_pos_Y;
1007 if (end_hpos >= row->used[TEXT_AREA])
1008 nglyphs = row->used[TEXT_AREA] - start_hpos;
1010 /* IT_write_glyphs writes at cursor position, so we need to
1011 temporarily move cursor coordinates to the beginning of
1012 the highlight region. */
1013 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1014 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1016 if (tty->termscript)
1017 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1018 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1019 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1020 if (tty->termscript)
1021 fputs ("\n", tty->termscript);
1022 new_pos_X = save_x;
1023 new_pos_Y = save_y;
1027 static void
1028 IT_clear_end_of_line (struct frame *f, int first_unused)
1030 char *spaces, *sp;
1031 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1032 struct tty_display_info *tty = FRAME_TTY (f);
1034 if (new_pos_X >= first_unused || fatal_error_in_progress)
1035 return;
1037 IT_set_face (0);
1038 i = (j = first_unused - new_pos_X) * 2;
1039 if (tty->termscript)
1040 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1041 spaces = sp = alloca (i);
1043 while (--j >= 0)
1045 *sp++ = ' ';
1046 *sp++ = ScreenAttrib;
1049 mouse_off_maybe ();
1050 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1051 if (screen_virtual_segment)
1052 dosv_refresh_virtual_screen (offset, i / 2);
1054 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1055 Let's follow their lead, in case someone relies on this. */
1056 new_pos_X = first_unused;
1059 static void
1060 IT_clear_screen (struct frame *f)
1062 struct tty_display_info *tty = FRAME_TTY (f);
1064 if (tty->termscript)
1065 fprintf (tty->termscript, "<CLR:SCR>");
1066 /* We are sometimes called (from clear_garbaged_frames) when a new
1067 frame is being created, but its faces are not yet realized. In
1068 such a case we cannot call IT_set_face, since it will fail to find
1069 any valid faces and will abort. Instead, use the initial screen
1070 colors; that should mimic what a Unix tty does, which simply clears
1071 the screen with whatever default colors are in use. */
1072 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1073 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1074 else
1075 IT_set_face (0);
1076 mouse_off ();
1077 ScreenClear ();
1078 if (screen_virtual_segment)
1079 dosv_refresh_virtual_screen (0, screen_size);
1080 new_pos_X = new_pos_Y = 0;
1083 static void
1084 IT_clear_to_end (struct frame *f)
1086 struct tty_display_info *tty = FRAME_TTY (f);
1088 if (tty->termscript)
1089 fprintf (tty->termscript, "<CLR:EOS>");
1091 while (new_pos_Y < screen_size_Y) {
1092 new_pos_X = 0;
1093 IT_clear_end_of_line (f, screen_size_X);
1094 new_pos_Y++;
1098 static void
1099 IT_cursor_to (struct frame *f, int y, int x)
1101 struct tty_display_info *tty = FRAME_TTY (f);
1103 if (tty->termscript)
1104 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1105 new_pos_X = x;
1106 new_pos_Y = y;
1109 static int cursor_cleared;
1111 static void
1112 IT_display_cursor (int on)
1114 struct tty_display_info *tty = CURTTY ();
1116 if (on && cursor_cleared)
1118 ScreenSetCursor (current_pos_Y, current_pos_X);
1119 cursor_cleared = 0;
1120 if (tty->termscript)
1121 fprintf (tty->termscript, "\nCURSOR ON (%dx%d)",
1122 current_pos_Y, current_pos_X);
1124 else if (!on && !cursor_cleared)
1126 ScreenSetCursor (-1, -1);
1127 cursor_cleared = 1;
1128 if (tty->termscript)
1129 fprintf (tty->termscript, "\nCURSOR OFF (%dx%d)",
1130 current_pos_Y, current_pos_X);
1134 /* Emacs calls cursor-movement functions a lot when it updates the
1135 display (probably a legacy of old terminals where you cannot
1136 update a screen line without first moving the cursor there).
1137 However, cursor movement is expensive on MSDOS (it calls a slow
1138 BIOS function and requires 2 mode switches), while actual screen
1139 updates access the video memory directly and don't depend on
1140 cursor position. To avoid slowing down the redisplay, we cheat:
1141 all functions that move the cursor only set internal variables
1142 which record the cursor position, whereas the cursor is only
1143 moved to its final position whenever screen update is complete.
1145 `IT_cmgoto' is called from the keyboard reading loop and when the
1146 frame update is complete. This means that we are ready for user
1147 input, so we update the cursor position to show where the point is,
1148 and also make the mouse pointer visible.
1150 Special treatment is required when the cursor is in the echo area,
1151 to put the cursor at the end of the text displayed there. */
1153 static void
1154 IT_cmgoto (FRAME_PTR f)
1156 /* Only set the cursor to where it should be if the display is
1157 already in sync with the window contents. */
1158 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1159 struct tty_display_info *tty = FRAME_TTY (f);
1161 /* FIXME: This needs to be rewritten for the new redisplay, or
1162 removed. */
1163 #if 0
1164 static int previous_pos_X = -1;
1166 update_cursor_pos = 1; /* temporary!!! */
1168 /* If the display is in sync, forget any previous knowledge about
1169 cursor position. This is primarily for unexpected events like
1170 C-g in the minibuffer. */
1171 if (update_cursor_pos && previous_pos_X >= 0)
1172 previous_pos_X = -1;
1173 /* If we are in the echo area, put the cursor at the
1174 end of the echo area message. */
1175 if (!update_cursor_pos
1176 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1178 int tem_X = current_pos_X, dummy;
1180 if (echo_area_glyphs)
1182 tem_X = echo_area_glyphs_length;
1183 /* Save current cursor position, to be restored after the
1184 echo area message is erased. Only remember one level
1185 of previous cursor position. */
1186 if (previous_pos_X == -1)
1187 ScreenGetCursor (&dummy, &previous_pos_X);
1189 else if (previous_pos_X >= 0)
1191 /* We wind up here after the echo area message is erased.
1192 Restore the cursor position we remembered above. */
1193 tem_X = previous_pos_X;
1194 previous_pos_X = -1;
1197 if (current_pos_X != tem_X)
1199 new_pos_X = tem_X;
1200 update_cursor_pos = 1;
1203 #endif
1205 if (update_cursor_pos
1206 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1208 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1209 if (tty->termscript)
1210 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1213 /* Maybe cursor is invisible, so make it visible. */
1214 IT_display_cursor (1);
1216 /* Mouse pointer should be always visible if we are waiting for
1217 keyboard input. */
1218 if (!mouse_visible)
1219 mouse_on ();
1222 static void
1223 IT_update_begin (struct frame *f)
1225 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1226 Mouse_HLInfo *hlinfo = &display_info->mouse_highlight;
1227 struct frame *mouse_face_frame = hlinfo->mouse_face_mouse_frame;
1229 if (display_info->termscript)
1230 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1232 block_input ();
1234 if (f && f == mouse_face_frame)
1236 /* Don't do highlighting for mouse motion during the update. */
1237 hlinfo->mouse_face_defer = 1;
1239 /* If F needs to be redrawn, simply forget about any prior mouse
1240 highlighting. */
1241 if (FRAME_GARBAGED_P (f))
1242 hlinfo->mouse_face_window = Qnil;
1244 /* Can we tell that this update does not affect the window
1245 where the mouse highlight is? If so, no need to turn off.
1246 Likewise, don't do anything if none of the enabled rows
1247 contains glyphs highlighted in mouse face. */
1248 if (!NILP (hlinfo->mouse_face_window)
1249 && WINDOWP (hlinfo->mouse_face_window))
1251 struct window *w = XWINDOW (hlinfo->mouse_face_window);
1252 int i;
1254 /* If the mouse highlight is in the window that was deleted
1255 (e.g., if it was popped by completion), clear highlight
1256 unconditionally. */
1257 if (NILP (w->buffer))
1258 hlinfo->mouse_face_window = Qnil;
1259 else
1261 for (i = 0; i < w->desired_matrix->nrows; ++i)
1262 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1263 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1264 break;
1267 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1268 clear_mouse_face (hlinfo);
1271 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1273 /* If the frame with mouse highlight was deleted, invalidate the
1274 highlight info. */
1275 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1276 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1277 hlinfo->mouse_face_window = Qnil;
1278 hlinfo->mouse_face_mouse_frame = NULL;
1281 unblock_input ();
1284 static void
1285 IT_update_end (struct frame *f)
1287 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1289 if (dpyinfo->termscript)
1290 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1291 dpyinfo->mouse_highlight.mouse_face_defer = 0;
1294 static void
1295 IT_frame_up_to_date (struct frame *f)
1297 Lisp_Object new_cursor, frame_desired_cursor;
1298 struct window *sw;
1300 FRAME_MOUSE_UPDATE (f);
1302 /* Set the cursor type to whatever they wanted. In a minibuffer
1303 window, we want the cursor to appear only if we are reading input
1304 from this window, and we want the cursor to be taken from the
1305 frame parameters. For the selected window, we use either its
1306 buffer-local value or the value from the frame parameters if the
1307 buffer doesn't define its local value for the cursor type. */
1308 sw = XWINDOW (f->selected_window);
1309 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1310 if (cursor_in_echo_area
1311 && FRAME_HAS_MINIBUF_P (f)
1312 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1313 && sw == XWINDOW (echo_area_window))
1314 new_cursor = frame_desired_cursor;
1315 else
1317 struct buffer *b = XBUFFER (sw->buffer);
1319 if (EQ (BVAR (b,cursor_type), Qt))
1320 new_cursor = frame_desired_cursor;
1321 else if (NILP (BVAR (b, cursor_type))) /* nil means no cursor */
1322 new_cursor = Fcons (Qbar, make_number (0));
1323 else
1324 new_cursor = BVAR (b, cursor_type);
1327 IT_set_cursor_type (f, new_cursor);
1329 IT_cmgoto (f); /* position cursor when update is done */
1332 /* Copy LEN glyphs displayed on a single line whose vertical position
1333 is YPOS, beginning at horizontal position XFROM to horizontal
1334 position XTO, by moving blocks in the video memory. Used by
1335 functions that insert and delete glyphs. */
1336 static void
1337 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1339 /* The offsets of source and destination relative to the
1340 conventional memory selector. */
1341 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1342 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1344 if (from == to || len <= 0)
1345 return;
1347 _farsetsel (_dos_ds);
1349 /* The source and destination might overlap, so we need to move
1350 glyphs non-destructively. */
1351 if (from > to)
1353 for ( ; len; from += 2, to += 2, len--)
1354 _farnspokew (to, _farnspeekw (from));
1356 else
1358 from += (len - 1) * 2;
1359 to += (len - 1) * 2;
1360 for ( ; len; from -= 2, to -= 2, len--)
1361 _farnspokew (to, _farnspeekw (from));
1363 if (screen_virtual_segment)
1364 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1367 /* Insert and delete glyphs. */
1368 static void
1369 IT_insert_glyphs (struct frame *f, struct glyph *start, int len)
1371 int shift_by_width = screen_size_X - (new_pos_X + len);
1373 /* Shift right the glyphs from the nominal cursor position to the
1374 end of this line. */
1375 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1377 /* Now write the glyphs to be inserted. */
1378 IT_write_glyphs (f, start, len);
1381 static void
1382 IT_delete_glyphs (struct frame *f, int n)
1384 emacs_abort ();
1387 /* set-window-configuration on window.c needs this. */
1388 void
1389 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1391 set_menu_bar_lines (f, value, oldval);
1394 /* This was copied from xfaces.c */
1396 extern Lisp_Object Qbackground_color;
1397 extern Lisp_Object Qforeground_color;
1398 Lisp_Object Qreverse;
1399 extern Lisp_Object Qtitle;
1401 /* IT_set_terminal_modes is called when emacs is started,
1402 resumed, and whenever the screen is redrawn! */
1404 static void
1405 IT_set_terminal_modes (struct terminal *term)
1407 struct tty_display_info *tty;
1409 /* If called with initial terminal, it's too early to do anything
1410 useful. */
1411 if (term->type == output_initial)
1412 return;
1414 tty = term->display_info.tty;
1416 if (tty->termscript)
1417 fprintf (tty->termscript, "\n<SET_TERM>");
1419 screen_size_X = ScreenCols ();
1420 screen_size_Y = ScreenRows ();
1421 screen_size = screen_size_X * screen_size_Y;
1423 new_pos_X = new_pos_Y = 0;
1424 current_pos_X = current_pos_Y = -1;
1426 if (term_setup_done)
1427 return;
1428 term_setup_done = 1;
1430 startup_screen_size_X = screen_size_X;
1431 startup_screen_size_Y = screen_size_Y;
1432 startup_screen_attrib = ScreenAttrib;
1434 /* Is DOS/V (or any other RSIS software which relocates
1435 the screen) installed? */
1437 unsigned short es_value;
1438 __dpmi_regs regs;
1440 regs.h.ah = 0xfe; /* get relocated screen address */
1441 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1442 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1443 else if (screen_old_address) /* already switched to Japanese mode once */
1444 regs.x.es = (screen_old_address >> 4) & 0xffff;
1445 else
1446 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1447 regs.x.di = 0;
1448 es_value = regs.x.es;
1449 __dpmi_int (0x10, &regs);
1451 if (regs.x.es != es_value)
1453 /* screen_old_address is only set if ScreenPrimary does NOT
1454 already point to the relocated buffer address returned by
1455 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1456 ScreenPrimary to that address at startup under DOS/V. */
1457 if (regs.x.es != ((ScreenPrimary >> 4) & 0xffff))
1458 screen_old_address = ScreenPrimary;
1459 screen_virtual_segment = regs.x.es;
1460 screen_virtual_offset = regs.x.di;
1461 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1465 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1466 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1468 bright_bg ();
1471 /* IT_reset_terminal_modes is called when emacs is
1472 suspended or killed. */
1474 static void
1475 IT_reset_terminal_modes (struct terminal *term)
1477 int display_row_start = (int) ScreenPrimary;
1478 int saved_row_len = startup_screen_size_X * 2;
1479 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1480 int to_next_row = update_row_len;
1481 unsigned char *saved_row = startup_screen_buffer;
1482 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1483 struct tty_display_info *tty = term->display_info.tty;
1485 if (tty->termscript)
1486 fprintf (tty->termscript, "\n<RESET_TERM>");
1488 if (!term_setup_done)
1489 return;
1491 mouse_off ();
1493 /* Leave the video system in the same state as we found it,
1494 as far as the blink/bright-background bit is concerned. */
1495 maybe_enable_blinking ();
1497 /* We have a situation here.
1498 We cannot just do ScreenUpdate(startup_screen_buffer) because
1499 the luser could have changed screen dimensions inside Emacs
1500 and failed (or didn't want) to restore them before killing
1501 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1502 thus will happily use memory outside what was allocated for
1503 `startup_screen_buffer'.
1504 Thus we only restore as much as the current screen dimensions
1505 can hold, and clear the rest (if the saved screen is smaller than
1506 the current) with the color attribute saved at startup. The cursor
1507 is also restored within the visible dimensions. */
1509 ScreenAttrib = startup_screen_attrib;
1511 /* Don't restore the screen if we are exiting less than 2 seconds
1512 after startup: we might be crashing, and the screen might show
1513 some vital clues to what's wrong. */
1514 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1516 ScreenClear ();
1517 if (screen_virtual_segment)
1518 dosv_refresh_virtual_screen (0, screen_size);
1520 if (update_row_len > saved_row_len)
1521 update_row_len = saved_row_len;
1522 if (current_rows > startup_screen_size_Y)
1523 current_rows = startup_screen_size_Y;
1525 if (tty->termscript)
1526 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1527 update_row_len / 2, current_rows);
1529 while (current_rows--)
1531 dosmemput (saved_row, update_row_len, display_row_start);
1532 if (screen_virtual_segment)
1533 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1534 update_row_len / 2);
1535 saved_row += saved_row_len;
1536 display_row_start += to_next_row;
1539 if (startup_pos_X < cursor_pos_X)
1540 cursor_pos_X = startup_pos_X;
1541 if (startup_pos_Y < cursor_pos_Y)
1542 cursor_pos_Y = startup_pos_Y;
1544 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1545 xfree (startup_screen_buffer);
1546 startup_screen_buffer = NULL;
1548 term_setup_done = 0;
1551 static void
1552 IT_set_terminal_window (struct frame *f, int foo)
1556 /* Remember the screen colors of the current frame, to serve as the
1557 default colors for newly-created frames. */
1558 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1559 Smsdos_remember_default_colors, 1, 1, 0,
1560 doc: /* Remember the screen colors of the current frame. */)
1561 (Lisp_Object frame)
1563 struct frame *f;
1565 CHECK_FRAME (frame);
1566 f = XFRAME (frame);
1568 /* This function is called after applying default-frame-alist to the
1569 initial frame. At that time, if reverse-colors option was
1570 specified in default-frame-alist, it was already applied, and
1571 frame colors are reversed. */
1572 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
1573 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
1575 return Qnil;
1578 void
1579 IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
1581 Lisp_Object tail;
1582 int i, j, length = XINT (Flength (alist));
1583 Lisp_Object *parms
1584 = (Lisp_Object *) alloca (length * word_size);
1585 Lisp_Object *values
1586 = (Lisp_Object *) alloca (length * word_size);
1587 /* Do we have to reverse the foreground and background colors? */
1588 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
1589 int redraw = 0, fg_set = 0, bg_set = 0;
1590 unsigned long orig_fg, orig_bg;
1591 struct tty_display_info *tty = FRAME_TTY (f);
1593 /* If we are creating a new frame, begin with the original screen colors
1594 used for the initial frame. */
1595 if (!f->default_face_done_p
1596 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1598 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1599 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
1600 init_frame_faces (f);
1601 f->default_face_done_p = 1;
1603 orig_fg = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1604 orig_bg = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
1606 /* Extract parm names and values into those vectors. */
1607 i = 0;
1608 for (tail = alist; CONSP (tail); tail = XCDR (tail))
1610 Lisp_Object elt = XCAR (tail);
1611 parms[i] = Fcar (elt);
1612 CHECK_SYMBOL (parms[i]);
1613 values[i] = Fcdr (elt);
1614 i++;
1617 j = i;
1619 for (i = 0; i < j; i++)
1621 Lisp_Object prop, val;
1623 prop = parms[i];
1624 val = values[i];
1626 if (EQ (prop, Qreverse))
1627 reverse = EQ (val, Qt);
1630 if (tty->termscript && reverse)
1631 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
1633 /* Now process the alist elements in reverse of specified order. */
1634 for (i--; i >= 0; i--)
1636 Lisp_Object prop, val;
1638 prop = parms[i];
1639 val = values[i];
1641 if (EQ (prop, Qforeground_color))
1643 unsigned long new_color = load_color (f, NULL, val, reverse
1644 ? LFACE_BACKGROUND_INDEX
1645 : LFACE_FOREGROUND_INDEX);
1646 if (new_color != FACE_TTY_DEFAULT_COLOR
1647 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1648 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1650 if (!reverse)
1652 FRAME_FOREGROUND_PIXEL (f) = new_color;
1653 /* Make sure the foreground of the default face for
1654 this frame is changed as well. */
1655 update_face_from_frame_parameter (f, Qforeground_color, val);
1656 fg_set = 1;
1657 if (tty->termscript)
1658 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1660 else
1662 FRAME_BACKGROUND_PIXEL (f) = new_color;
1663 update_face_from_frame_parameter (f, Qbackground_color, val);
1664 bg_set = 1;
1665 if (tty->termscript)
1666 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1668 redraw = 1;
1671 else if (EQ (prop, Qbackground_color))
1673 unsigned long new_color = load_color (f, NULL, val, reverse
1674 ? LFACE_FOREGROUND_INDEX
1675 : LFACE_BACKGROUND_INDEX);
1676 if (new_color != FACE_TTY_DEFAULT_COLOR
1677 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1678 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1680 if (!reverse)
1682 FRAME_BACKGROUND_PIXEL (f) = new_color;
1683 /* Make sure the background of the default face for
1684 this frame is changed as well. */
1685 bg_set = 1;
1686 update_face_from_frame_parameter (f, Qbackground_color, val);
1687 if (tty->termscript)
1688 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1690 else
1692 FRAME_FOREGROUND_PIXEL (f) = new_color;
1693 fg_set = 1;
1694 update_face_from_frame_parameter (f, Qforeground_color, val);
1695 if (tty->termscript)
1696 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1698 redraw = 1;
1701 else if (EQ (prop, Qtitle))
1703 x_set_title (f, val);
1704 if (tty->termscript)
1705 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
1707 else if (EQ (prop, Qcursor_type))
1709 IT_set_cursor_type (f, val);
1710 if (tty->termscript)
1711 fprintf (tty->termscript, "<CTYPE: %s>\n",
1712 EQ (val, Qbar)
1713 || EQ (val, Qhbar)
1714 || (CONSP (val) && (EQ (XCAR (val), Qbar)
1715 || EQ (XCAR (val), Qhbar)))
1716 ? "bar" : "box");
1718 else if (EQ (prop, Qtty_type))
1720 internal_terminal_init ();
1721 if (tty->termscript)
1722 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1723 SBYTES (val), SDATA (val));
1725 store_frame_param (f, prop, val);
1728 /* If they specified "reverse", but not the colors, we need to swap
1729 the current frame colors. */
1730 if (reverse)
1732 if (!fg_set)
1734 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1735 update_face_from_frame_parameter (f, Qforeground_color,
1736 tty_color_name (f, orig_bg));
1737 redraw = 1;
1739 if (!bg_set)
1741 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1742 update_face_from_frame_parameter (f, Qbackground_color,
1743 tty_color_name (f, orig_fg));
1744 redraw = 1;
1748 if (redraw)
1750 face_change_count++; /* forces xdisp.c to recompute basic faces */
1751 if (f == SELECTED_FRAME ())
1752 redraw_frame (f);
1756 extern void init_frame_faces (FRAME_PTR);
1758 #endif /* !HAVE_X_WINDOWS */
1761 /* Do we need the internal terminal? */
1763 void
1764 internal_terminal_init (void)
1766 static int init_needed = 1;
1767 char *term = getenv ("TERM"), *colors;
1768 struct frame *sf = SELECTED_FRAME ();
1769 struct tty_display_info *tty;
1771 #ifdef HAVE_X_WINDOWS
1772 if (!inhibit_window_system)
1773 return;
1774 #endif
1776 /* If this is the initial terminal, we are done here. */
1777 if (sf->output_method == output_initial)
1778 return;
1780 internal_terminal
1781 = (!noninteractive) && term && !strcmp (term, "internal");
1783 #ifndef HAVE_X_WINDOWS
1784 if (!internal_terminal || inhibit_window_system)
1786 sf->output_method = output_termcap;
1787 return;
1790 tty = FRAME_TTY (sf);
1791 kset_window_system (current_kboard, Qpc);
1792 sf->output_method = output_msdos_raw;
1793 if (init_needed)
1795 if (!tty->termscript && getenv ("EMACSTEST"))
1796 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
1797 if (tty->termscript)
1799 time_t now = time (NULL);
1800 struct tm *tnow = localtime (&now);
1801 char tbuf[100];
1803 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
1804 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
1805 fprintf (tty->termscript, "=====================\n\n");
1808 Vinitial_window_system = Qpc;
1809 Vwindow_system_version = make_number (24); /* RE Emacs version */
1810 tty->terminal->type = output_msdos_raw;
1812 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1813 address. */
1814 screen_old_address = 0;
1816 /* Forget the stale screen colors as well. */
1817 initial_screen_colors[0] = initial_screen_colors[1] = -1;
1819 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1820 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1821 bright_bg ();
1822 colors = getenv ("EMACSCOLORS");
1823 if (colors && strlen (colors) >= 2)
1825 /* The colors use 4 bits each (we enable bright background). */
1826 if (isdigit (colors[0]))
1827 colors[0] -= '0';
1828 else if (isxdigit (colors[0]))
1829 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1830 if (colors[0] >= 0 && colors[0] < 16)
1831 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
1832 if (isdigit (colors[1]))
1833 colors[1] -= '0';
1834 else if (isxdigit (colors[1]))
1835 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1836 if (colors[1] >= 0 && colors[1] < 16)
1837 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
1839 the_only_display_info.mouse_highlight.mouse_face_mouse_frame = NULL;
1840 the_only_display_info.mouse_highlight.mouse_face_beg_row =
1841 the_only_display_info.mouse_highlight.mouse_face_beg_col = -1;
1842 the_only_display_info.mouse_highlight.mouse_face_end_row =
1843 the_only_display_info.mouse_highlight.mouse_face_end_col = -1;
1844 the_only_display_info.mouse_highlight.mouse_face_face_id = DEFAULT_FACE_ID;
1845 the_only_display_info.mouse_highlight.mouse_face_window = Qnil;
1846 the_only_display_info.mouse_highlight.mouse_face_mouse_x =
1847 the_only_display_info.mouse_highlight.mouse_face_mouse_y = 0;
1848 the_only_display_info.mouse_highlight.mouse_face_defer = 0;
1849 the_only_display_info.mouse_highlight.mouse_face_hidden = 0;
1851 if (have_mouse) /* detected in dos_ttraw, which see */
1853 have_mouse = 1; /* enable mouse */
1854 mouse_visible = 0;
1855 mouse_setup_buttons (mouse_button_count);
1856 tty->terminal->mouse_position_hook = &mouse_get_pos;
1857 mouse_init ();
1860 if (tty->termscript && screen_size)
1861 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1862 screen_size_X, screen_size_Y);
1864 init_frame_faces (sf);
1865 init_needed = 0;
1867 #endif
1870 void
1871 initialize_msdos_display (struct terminal *term)
1873 term->rif = 0; /* we don't support window-based display */
1874 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
1875 term->clear_to_end_hook = IT_clear_to_end;
1876 term->clear_frame_hook = IT_clear_screen;
1877 term->clear_end_of_line_hook = IT_clear_end_of_line;
1878 term->ins_del_lines_hook = 0;
1879 term->insert_glyphs_hook = IT_insert_glyphs;
1880 term->write_glyphs_hook = IT_write_glyphs;
1881 term->delete_glyphs_hook = IT_delete_glyphs;
1882 term->ring_bell_hook = IT_ring_bell;
1883 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
1884 term->set_terminal_modes_hook = IT_set_terminal_modes;
1885 term->set_terminal_window_hook = IT_set_terminal_window;
1886 term->update_begin_hook = IT_update_begin;
1887 term->update_end_hook = IT_update_end;
1888 term->frame_up_to_date_hook = IT_frame_up_to_date;
1889 term->mouse_position_hook = 0; /* set later by dos_ttraw */
1890 term->frame_rehighlight_hook = 0;
1891 term->frame_raise_lower_hook = 0;
1892 term->set_vertical_scroll_bar_hook = 0;
1893 term->condemn_scroll_bars_hook = 0;
1894 term->redeem_scroll_bar_hook = 0;
1895 term->judge_scroll_bars_hook = 0;
1896 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
1900 dos_get_saved_screen (char **screen, int *rows, int *cols)
1902 #ifndef HAVE_X_WINDOWS
1903 *screen = startup_screen_buffer;
1904 *cols = startup_screen_size_X;
1905 *rows = startup_screen_size_Y;
1906 return *screen != (char *)0;
1907 #else
1908 return 0;
1909 #endif
1912 #ifndef HAVE_X_WINDOWS
1914 /* We are not X, but we can emulate it well enough for our needs... */
1915 void
1916 check_x (void)
1918 if (! FRAME_MSDOS_P (SELECTED_FRAME ()))
1919 error ("Not running under a window system");
1922 #endif
1925 /* ----------------------- Keyboard control ----------------------
1927 * Keymaps reflect the following keyboard layout:
1929 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1930 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1931 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1932 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1933 * SPACE
1936 #define Ignore 0x0000
1937 #define Normal 0x0000 /* normal key - alt changes scan-code */
1938 #define FctKey 0x1000 /* func key if c == 0, else c */
1939 #define Special 0x2000 /* func key even if c != 0 */
1940 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1941 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1942 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1943 #define Grey 0x6000 /* Grey keypad key */
1945 #define Alt 0x0100 /* alt scan-code */
1946 #define Ctrl 0x0200 /* ctrl scan-code */
1947 #define Shift 0x0400 /* shift scan-code */
1949 static int extended_kbd; /* 101 (102) keyboard present. */
1951 struct kbd_translate {
1952 unsigned char sc;
1953 unsigned char ch;
1954 unsigned short code;
1957 struct dos_keyboard_map
1959 char *unshifted;
1960 char *shifted;
1961 char *alt_gr;
1962 struct kbd_translate *translate_table;
1966 static struct dos_keyboard_map us_keyboard = {
1967 /* 0 1 2 3 4 5 */
1968 /* 01234567890123456789012345678901234567890 12345678901234 */
1969 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1970 /* 0123456789012345678901234567890123456789 012345678901234 */
1971 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1972 0, /* no Alt-Gr key */
1973 0 /* no translate table */
1976 static struct dos_keyboard_map fr_keyboard = {
1977 /* 0 1 2 3 4 5 */
1978 /* 012 3456789012345678901234567890123456789012345678901234 */
1979 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1980 /* 0123456789012345678901234567890123456789012345678901234 */
1981 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1982 /* 01234567 89012345678901234567890123456789012345678901234 */
1983 " ~#{[|`\\^@]} Ï ",
1984 0 /* no translate table */
1988 * Italian keyboard support, country code 39.
1989 * '<' 56:3c*0000
1990 * '>' 56:3e*0000
1991 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1992 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1995 static struct kbd_translate it_kbd_translate_table[] = {
1996 { 0x56, 0x3c, Normal | 13 },
1997 { 0x56, 0x3e, Normal | 27 },
1998 { 0, 0, 0 }
2000 static struct dos_keyboard_map it_keyboard = {
2001 /* 0 1 2 3 4 5 */
2002 /* 0 123456789012345678901234567890123456789012345678901234 */
2003 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2004 /* 01 23456789012345678901234567890123456789012345678901234 */
2005 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2006 /* 0123456789012345678901234567890123456789012345678901234 */
2007 " {}~` [] @# ",
2008 it_kbd_translate_table
2011 static struct dos_keyboard_map dk_keyboard = {
2012 /* 0 1 2 3 4 5 */
2013 /* 0123456789012345678901234567890123456789012345678901234 */
2014 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2015 /* 01 23456789012345678901234567890123456789012345678901234 */
2016 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2017 /* 0123456789012345678901234567890123456789012345678901234 */
2018 " @œ$ {[]} | ",
2019 0 /* no translate table */
2022 static struct kbd_translate jp_kbd_translate_table[] = {
2023 { 0x73, 0x5c, Normal | 0 },
2024 { 0x73, 0x5f, Normal | 0 },
2025 { 0x73, 0x1c, Map | 0 },
2026 { 0x7d, 0x5c, Normal | 13 },
2027 { 0x7d, 0x7c, Normal | 13 },
2028 { 0x7d, 0x1c, Map | 13 },
2029 { 0, 0, 0 }
2031 static struct dos_keyboard_map jp_keyboard = {
2032 /* 0 1 2 3 4 5 */
2033 /* 0123456789012 345678901234567890123456789012345678901234 */
2034 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2035 /* 01 23456789012345678901234567890123456789012345678901234 */
2036 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2037 0, /* no Alt-Gr key */
2038 jp_kbd_translate_table
2041 static struct keyboard_layout_list
2043 int country_code;
2044 struct dos_keyboard_map *keyboard_map;
2045 } keyboard_layout_list[] =
2047 { 1, &us_keyboard },
2048 { 33, &fr_keyboard },
2049 { 39, &it_keyboard },
2050 { 45, &dk_keyboard },
2051 { 81, &jp_keyboard }
2054 static struct dos_keyboard_map *keyboard;
2055 static int keyboard_map_all;
2056 static int international_keyboard;
2059 dos_set_keyboard (int code, int always)
2061 int i;
2062 _go32_dpmi_registers regs;
2064 /* See if Keyb.Com is installed (for international keyboard support).
2065 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2066 of Windows 9X! So don't do that! */
2067 regs.x.ax = 0xad80;
2068 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2069 _go32_dpmi_simulate_int (0x2f, &regs);
2070 if (regs.h.al == 0xff)
2071 international_keyboard = 1;
2073 /* Initialize to US settings, for countries that don't have their own. */
2074 keyboard = keyboard_layout_list[0].keyboard_map;
2075 keyboard_map_all = always;
2076 dos_keyboard_layout = 1;
2078 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2079 if (code == keyboard_layout_list[i].country_code)
2081 keyboard = keyboard_layout_list[i].keyboard_map;
2082 keyboard_map_all = always;
2083 dos_keyboard_layout = code;
2084 return 1;
2086 return 0;
2089 static struct
2091 unsigned char char_code; /* normal code */
2092 unsigned char meta_code; /* M- code */
2093 unsigned char keypad_code; /* keypad code */
2094 unsigned char editkey_code; /* edit key */
2095 } keypad_translate_map[] = {
2096 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2097 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2098 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2099 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2100 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2101 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2102 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2103 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2104 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2105 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2106 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2109 static struct
2111 unsigned char char_code; /* normal code */
2112 unsigned char keypad_code; /* keypad code */
2113 } grey_key_translate_map[] = {
2114 { '/', 0xaf /* kp-decimal */ },
2115 { '*', 0xaa /* kp-multiply */ },
2116 { '-', 0xad /* kp-subtract */ },
2117 { '+', 0xab /* kp-add */ },
2118 { '\r', 0x8d /* kp-enter */ }
2121 static unsigned short
2122 ibmpc_translate_map[] =
2124 /* --------------- 00 to 0f --------------- */
2125 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2126 Alt | ModFct | 0x1b, /* Escape */
2127 Normal | 1, /* '1' */
2128 Normal | 2, /* '2' */
2129 Normal | 3, /* '3' */
2130 Normal | 4, /* '4' */
2131 Normal | 5, /* '5' */
2132 Normal | 6, /* '6' */
2133 Normal | 7, /* '7' */
2134 Normal | 8, /* '8' */
2135 Normal | 9, /* '9' */
2136 Normal | 10, /* '0' */
2137 Normal | 11, /* '-' */
2138 Normal | 12, /* '=' */
2139 Special | 0x08, /* Backspace */
2140 ModFct | 0x74, /* Tab/Backtab */
2142 /* --------------- 10 to 1f --------------- */
2143 Map | 15, /* 'q' */
2144 Map | 16, /* 'w' */
2145 Map | 17, /* 'e' */
2146 Map | 18, /* 'r' */
2147 Map | 19, /* 't' */
2148 Map | 20, /* 'y' */
2149 Map | 21, /* 'u' */
2150 Map | 22, /* 'i' */
2151 Map | 23, /* 'o' */
2152 Map | 24, /* 'p' */
2153 Map | 25, /* '[' */
2154 Map | 26, /* ']' */
2155 ModFct | 0x0d, /* Return */
2156 Ignore, /* Ctrl */
2157 Map | 30, /* 'a' */
2158 Map | 31, /* 's' */
2160 /* --------------- 20 to 2f --------------- */
2161 Map | 32, /* 'd' */
2162 Map | 33, /* 'f' */
2163 Map | 34, /* 'g' */
2164 Map | 35, /* 'h' */
2165 Map | 36, /* 'j' */
2166 Map | 37, /* 'k' */
2167 Map | 38, /* 'l' */
2168 Map | 39, /* ';' */
2169 Map | 40, /* '\'' */
2170 Map | 0, /* '`' */
2171 Ignore, /* Left shift */
2172 Map | 41, /* '\\' */
2173 Map | 45, /* 'z' */
2174 Map | 46, /* 'x' */
2175 Map | 47, /* 'c' */
2176 Map | 48, /* 'v' */
2178 /* --------------- 30 to 3f --------------- */
2179 Map | 49, /* 'b' */
2180 Map | 50, /* 'n' */
2181 Map | 51, /* 'm' */
2182 Map | 52, /* ',' */
2183 Map | 53, /* '.' */
2184 Map | 54, /* '/' */
2185 Ignore, /* Right shift */
2186 Grey | 1, /* Grey * */
2187 Ignore, /* Alt */
2188 Normal | 55, /* ' ' */
2189 Ignore, /* Caps Lock */
2190 FctKey | 0xbe, /* F1 */
2191 FctKey | 0xbf, /* F2 */
2192 FctKey | 0xc0, /* F3 */
2193 FctKey | 0xc1, /* F4 */
2194 FctKey | 0xc2, /* F5 */
2196 /* --------------- 40 to 4f --------------- */
2197 FctKey | 0xc3, /* F6 */
2198 FctKey | 0xc4, /* F7 */
2199 FctKey | 0xc5, /* F8 */
2200 FctKey | 0xc6, /* F9 */
2201 FctKey | 0xc7, /* F10 */
2202 Ignore, /* Num Lock */
2203 Ignore, /* Scroll Lock */
2204 KeyPad | 7, /* Home */
2205 KeyPad | 8, /* Up */
2206 KeyPad | 9, /* Page Up */
2207 Grey | 2, /* Grey - */
2208 KeyPad | 4, /* Left */
2209 KeyPad | 5, /* Keypad 5 */
2210 KeyPad | 6, /* Right */
2211 Grey | 3, /* Grey + */
2212 KeyPad | 1, /* End */
2214 /* --------------- 50 to 5f --------------- */
2215 KeyPad | 2, /* Down */
2216 KeyPad | 3, /* Page Down */
2217 KeyPad | 0, /* Insert */
2218 KeyPad | 10, /* Delete */
2219 Shift | FctKey | 0xbe, /* (Shift) F1 */
2220 Shift | FctKey | 0xbf, /* (Shift) F2 */
2221 Shift | FctKey | 0xc0, /* (Shift) F3 */
2222 Shift | FctKey | 0xc1, /* (Shift) F4 */
2223 Shift | FctKey | 0xc2, /* (Shift) F5 */
2224 Shift | FctKey | 0xc3, /* (Shift) F6 */
2225 Shift | FctKey | 0xc4, /* (Shift) F7 */
2226 Shift | FctKey | 0xc5, /* (Shift) F8 */
2227 Shift | FctKey | 0xc6, /* (Shift) F9 */
2228 Shift | FctKey | 0xc7, /* (Shift) F10 */
2229 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2230 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2232 /* --------------- 60 to 6f --------------- */
2233 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2234 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2235 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2236 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2237 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2238 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2239 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2240 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2241 Alt | FctKey | 0xbe, /* (Alt) F1 */
2242 Alt | FctKey | 0xbf, /* (Alt) F2 */
2243 Alt | FctKey | 0xc0, /* (Alt) F3 */
2244 Alt | FctKey | 0xc1, /* (Alt) F4 */
2245 Alt | FctKey | 0xc2, /* (Alt) F5 */
2246 Alt | FctKey | 0xc3, /* (Alt) F6 */
2247 Alt | FctKey | 0xc4, /* (Alt) F7 */
2248 Alt | FctKey | 0xc5, /* (Alt) F8 */
2250 /* --------------- 70 to 7f --------------- */
2251 Alt | FctKey | 0xc6, /* (Alt) F9 */
2252 Alt | FctKey | 0xc7, /* (Alt) F10 */
2253 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2254 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2255 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2256 Ctrl | KeyPad | 1, /* (Ctrl) End */
2257 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2258 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2259 Alt | Map | 1, /* '1' */
2260 Alt | Map | 2, /* '2' */
2261 Alt | Map | 3, /* '3' */
2262 Alt | Map | 4, /* '4' */
2263 Alt | Map | 5, /* '5' */
2264 Alt | Map | 6, /* '6' */
2265 Alt | Map | 7, /* '7' */
2266 Alt | Map | 8, /* '8' */
2268 /* --------------- 80 to 8f --------------- */
2269 Alt | Map | 9, /* '9' */
2270 Alt | Map | 10, /* '0' */
2271 Alt | Map | 11, /* '-' */
2272 Alt | Map | 12, /* '=' */
2273 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2274 FctKey | 0xc8, /* F11 */
2275 FctKey | 0xc9, /* F12 */
2276 Shift | FctKey | 0xc8, /* (Shift) F11 */
2277 Shift | FctKey | 0xc9, /* (Shift) F12 */
2278 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2279 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2280 Alt | FctKey | 0xc8, /* (Alt) F11 */
2281 Alt | FctKey | 0xc9, /* (Alt) F12 */
2282 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2283 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2284 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2286 /* --------------- 90 to 9f --------------- */
2287 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2288 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2289 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2290 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2291 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2292 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2293 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2294 Alt | FctKey | 0x50, /* (Alt) Home */
2295 Alt | FctKey | 0x52, /* (Alt) Up */
2296 Alt | FctKey | 0x55, /* (Alt) Page Up */
2297 Ignore, /* NO KEY */
2298 Alt | FctKey | 0x51, /* (Alt) Left */
2299 Ignore, /* NO KEY */
2300 Alt | FctKey | 0x53, /* (Alt) Right */
2301 Ignore, /* NO KEY */
2302 Alt | FctKey | 0x57, /* (Alt) End */
2304 /* --------------- a0 to af --------------- */
2305 Alt | KeyPad | 2, /* (Alt) Down */
2306 Alt | KeyPad | 3, /* (Alt) Page Down */
2307 Alt | KeyPad | 0, /* (Alt) Insert */
2308 Alt | KeyPad | 10, /* (Alt) Delete */
2309 Alt | Grey | 0, /* (Alt) Grey / */
2310 Alt | FctKey | 0x09, /* (Alt) Tab */
2311 Alt | Grey | 4 /* (Alt) Keypad Enter */
2314 /* These bit-positions corresponds to values returned by BIOS */
2315 #define SHIFT_P 0x0003 /* two bits! */
2316 #define CTRL_P 0x0004
2317 #define ALT_P 0x0008
2318 #define SCRLOCK_P 0x0010
2319 #define NUMLOCK_P 0x0020
2320 #define CAPSLOCK_P 0x0040
2321 #define ALT_GR_P 0x0800
2322 #define SUPER_P 0x4000 /* pseudo */
2323 #define HYPER_P 0x8000 /* pseudo */
2325 static int
2326 dos_get_modifiers (int *keymask)
2328 union REGS regs;
2329 int mask, modifiers = 0;
2331 /* Calculate modifier bits */
2332 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2333 int86 (0x16, &regs, &regs);
2335 if (!extended_kbd)
2337 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2338 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2340 else
2342 mask = regs.h.al & (SHIFT_P |
2343 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2345 /* Do not break international keyboard support. */
2346 /* When Keyb.Com is loaded, the right Alt key is */
2347 /* used for accessing characters like { and } */
2348 if (regs.h.ah & 2) /* Left ALT pressed ? */
2349 mask |= ALT_P;
2351 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2353 mask |= ALT_GR_P;
2354 if (dos_hyper_key == 1)
2356 mask |= HYPER_P;
2357 modifiers |= hyper_modifier;
2359 else if (dos_super_key == 1)
2361 mask |= SUPER_P;
2362 modifiers |= super_modifier;
2364 else if (!international_keyboard)
2366 /* If Keyb.Com is NOT installed, let Right Alt behave
2367 like the Left Alt. */
2368 mask &= ~ALT_GR_P;
2369 mask |= ALT_P;
2373 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2374 mask |= CTRL_P;
2376 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2378 if (dos_hyper_key == 2)
2380 mask |= HYPER_P;
2381 modifiers |= hyper_modifier;
2383 else if (dos_super_key == 2)
2385 mask |= SUPER_P;
2386 modifiers |= super_modifier;
2388 else
2389 mask |= CTRL_P;
2393 if (mask & SHIFT_P)
2394 modifiers |= shift_modifier;
2395 if (mask & CTRL_P)
2396 modifiers |= ctrl_modifier;
2397 if (mask & ALT_P)
2398 modifiers |= meta_modifier;
2400 if (keymask)
2401 *keymask = mask;
2402 return modifiers;
2405 #define NUM_RECENT_DOSKEYS (100)
2406 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2407 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2408 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2410 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2411 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2412 Each input key receives two values in this vector: first the ASCII code,
2413 and then the scan code. */)
2414 (void)
2416 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2418 if (total_doskeys < NUM_RECENT_DOSKEYS)
2419 return Fvector (total_doskeys, keys);
2420 else
2422 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2423 vcopy (val, 0, keys + recent_doskeys_index,
2424 NUM_RECENT_DOSKEYS - recent_doskeys_index);
2425 vcopy (val, NUM_RECENT_DOSKEYS - recent_doskeys_index,
2426 keys, recent_doskeys_index);
2427 return val;
2431 /* Get a char from keyboard. Function keys are put into the event queue. */
2432 static int
2433 dos_rawgetc (void)
2435 struct input_event event;
2436 union REGS regs;
2437 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (SELECTED_FRAME ());
2438 EVENT_INIT (event);
2440 #ifndef HAVE_X_WINDOWS
2441 /* Maybe put the cursor where it should be. */
2442 IT_cmgoto (SELECTED_FRAME ());
2443 #endif
2445 /* The following condition is equivalent to `kbhit ()', except that
2446 it uses the bios to do its job. This pleases DESQview/X. */
2447 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2448 int86 (0x16, &regs, &regs),
2449 (regs.x.flags & 0x40) == 0)
2451 union REGS regs;
2452 register unsigned char c;
2453 int modifiers, sc, code = -1, mask, kp_mode;
2455 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2456 int86 (0x16, &regs, &regs);
2457 c = regs.h.al;
2458 sc = regs.h.ah;
2460 total_doskeys += 2;
2461 ASET (recent_doskeys, recent_doskeys_index, make_number (c));
2462 recent_doskeys_index++;
2463 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2464 recent_doskeys_index = 0;
2465 ASET (recent_doskeys, recent_doskeys_index, make_number (sc));
2466 recent_doskeys_index++;
2467 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2468 recent_doskeys_index = 0;
2470 modifiers = dos_get_modifiers (&mask);
2472 #ifndef HAVE_X_WINDOWS
2473 if (!NILP (Vdos_display_scancodes))
2475 char buf[11];
2476 sprintf (buf, "%02x:%02x*%04x",
2477 (unsigned) (sc&0xff), (unsigned) c, mask);
2478 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2480 #endif
2482 if (sc == 0xe0)
2484 switch (c)
2486 case 10: /* Ctrl Grey Enter */
2487 code = Ctrl | Grey | 4;
2488 break;
2489 case 13: /* Grey Enter */
2490 code = Grey | 4;
2491 break;
2492 case '/': /* Grey / */
2493 code = Grey | 0;
2494 break;
2495 default:
2496 continue;
2498 c = 0;
2500 else
2502 /* Try the keyboard-private translation table first. */
2503 if (keyboard->translate_table)
2505 struct kbd_translate *p = keyboard->translate_table;
2507 while (p->sc)
2509 if (p->sc == sc && p->ch == c)
2511 code = p->code;
2512 break;
2514 p++;
2517 /* If the private table didn't translate it, use the general
2518 one. */
2519 if (code == -1)
2521 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
2522 continue;
2523 if ((code = ibmpc_translate_map[sc]) == Ignore)
2524 continue;
2528 if (c == 0)
2530 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2531 Emacs is ready to read a key. Therefore, if they press
2532 `Alt-x' when Emacs is busy, by the time we get to
2533 `dos_get_modifiers', they might have already released the
2534 Alt key, and Emacs gets just `x', which is BAD.
2535 However, for keys with the `Map' property set, the ASCII
2536 code returns zero only if Alt is pressed. So, when we DON'T
2537 have to support international_keyboard, we don't have to
2538 distinguish between the left and right Alt keys, and we
2539 can set the META modifier for any keys with the `Map'
2540 property if they return zero ASCII code (c = 0). */
2541 if ( (code & Alt)
2542 || ( (code & 0xf000) == Map && !international_keyboard))
2543 modifiers |= meta_modifier;
2544 if (code & Ctrl)
2545 modifiers |= ctrl_modifier;
2546 if (code & Shift)
2547 modifiers |= shift_modifier;
2550 switch (code & 0xf000)
2552 case ModFct:
2553 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
2554 return c;
2555 c = 0; /* Special */
2557 case FctKey:
2558 if (c != 0)
2559 return c;
2561 case Special:
2562 code |= 0xff00;
2563 break;
2565 case Normal:
2566 if (sc == 0)
2568 if (c == 0) /* ctrl-break */
2569 continue;
2570 return c; /* ALT-nnn */
2572 if (!keyboard_map_all)
2574 if (c != ' ')
2575 return c;
2576 code = c;
2577 break;
2580 case Map:
2581 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
2582 if (!keyboard_map_all)
2583 return c;
2585 code &= 0xff;
2586 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
2587 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
2589 if (mask & SHIFT_P)
2591 code = keyboard->shifted[code];
2592 mask -= SHIFT_P;
2593 modifiers &= ~shift_modifier;
2595 else
2596 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
2597 code = keyboard->alt_gr[code];
2598 else
2599 code = keyboard->unshifted[code];
2600 break;
2602 case KeyPad:
2603 code &= 0xff;
2604 if (c == 0xe0) /* edit key */
2605 kp_mode = 3;
2606 else
2607 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
2608 kp_mode = dos_keypad_mode & 0x03;
2609 else
2610 kp_mode = (dos_keypad_mode >> 4) & 0x03;
2612 switch (kp_mode)
2614 case 0:
2615 if (code == 10 && dos_decimal_point)
2616 return dos_decimal_point;
2617 return keypad_translate_map[code].char_code;
2619 case 1:
2620 code = 0xff00 | keypad_translate_map[code].keypad_code;
2621 break;
2623 case 2:
2624 code = keypad_translate_map[code].meta_code;
2625 modifiers = meta_modifier;
2626 break;
2628 case 3:
2629 code = 0xff00 | keypad_translate_map[code].editkey_code;
2630 break;
2632 break;
2634 case Grey:
2635 code &= 0xff;
2636 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
2637 if (dos_keypad_mode & kp_mode)
2638 code = 0xff00 | grey_key_translate_map[code].keypad_code;
2639 else
2640 code = grey_key_translate_map[code].char_code;
2641 break;
2644 if (code == 0)
2645 continue;
2647 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
2649 clear_mouse_face (hlinfo);
2650 hlinfo->mouse_face_hidden = 1;
2653 if (code >= 0x100)
2654 event.kind = NON_ASCII_KEYSTROKE_EVENT;
2655 else
2656 event.kind = ASCII_KEYSTROKE_EVENT;
2657 event.code = code;
2658 event.modifiers = modifiers;
2659 event.frame_or_window = selected_frame;
2660 event.arg = Qnil;
2661 event.timestamp = event_timestamp ();
2662 kbd_buffer_store_event (&event);
2665 if (have_mouse > 0 && !mouse_preempted)
2667 int but, press, x, y, ok;
2668 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
2669 Lisp_Object mouse_window = Qnil;
2671 /* Check for mouse movement *before* buttons. */
2672 mouse_check_moved ();
2674 /* If the mouse moved from the spot of its last sighting, we
2675 might need to update mouse highlight. */
2676 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
2678 if (hlinfo->mouse_face_hidden)
2680 hlinfo->mouse_face_hidden = 0;
2681 clear_mouse_face (hlinfo);
2684 /* Generate SELECT_WINDOW_EVENTs when needed. */
2685 if (!NILP (Vmouse_autoselect_window))
2687 mouse_window = window_from_coordinates (SELECTED_FRAME (),
2688 mouse_last_x,
2689 mouse_last_y,
2690 0, 0);
2691 /* A window will be selected only when it is not
2692 selected now, and the last mouse movement event was
2693 not in it. A minibuffer window will be selected iff
2694 it is active. */
2695 if (WINDOWP (mouse_window)
2696 && !EQ (mouse_window, last_mouse_window)
2697 && !EQ (mouse_window, selected_window))
2699 event.kind = SELECT_WINDOW_EVENT;
2700 event.frame_or_window = mouse_window;
2701 event.arg = Qnil;
2702 event.timestamp = event_timestamp ();
2703 kbd_buffer_store_event (&event);
2705 last_mouse_window = mouse_window;
2707 else
2708 last_mouse_window = Qnil;
2710 previous_help_echo_string = help_echo_string;
2711 help_echo_string = help_echo_object = help_echo_window = Qnil;
2712 help_echo_pos = -1;
2713 note_mouse_highlight (SELECTED_FRAME (), mouse_last_x, mouse_last_y);
2714 /* If the contents of the global variable help_echo has
2715 changed, generate a HELP_EVENT. */
2716 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
2717 gen_help_event (help_echo_string, selected_frame, help_echo_window,
2718 help_echo_object, help_echo_pos);
2721 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
2722 for (press = 0; press < 2; press++)
2724 int button_num = but;
2726 if (press)
2727 ok = mouse_pressed (but, &x, &y);
2728 else
2729 ok = mouse_released (but, &x, &y);
2730 if (ok)
2732 /* Allow a simultaneous press/release of Mouse-1 and
2733 Mouse-2 to simulate Mouse-3 on two-button mice. */
2734 if (mouse_button_count == 2 && but < 2)
2736 int x2, y2; /* don't clobber original coordinates */
2738 /* If only one button is pressed, wait 100 msec and
2739 check again. This way, Speedy Gonzales isn't
2740 punished, while the slow get their chance. */
2741 if ((press && mouse_pressed (1-but, &x2, &y2))
2742 || (!press && mouse_released (1-but, &x2, &y2)))
2743 button_num = 2;
2744 else
2746 delay (100);
2747 if ((press && mouse_pressed (1-but, &x2, &y2))
2748 || (!press && mouse_released (1-but, &x2, &y2)))
2749 button_num = 2;
2753 event.kind = MOUSE_CLICK_EVENT;
2754 event.code = button_num;
2755 event.modifiers = dos_get_modifiers (0)
2756 | (press ? down_modifier : up_modifier);
2757 event.x = make_number (x);
2758 event.y = make_number (y);
2759 event.frame_or_window = selected_frame;
2760 event.arg = Qnil;
2761 event.timestamp = event_timestamp ();
2762 kbd_buffer_store_event (&event);
2767 return -1;
2770 static int prev_get_char = -1;
2772 /* Return 1 if a key is ready to be read without suspending execution. */
2774 dos_keysns (void)
2776 if (prev_get_char != -1)
2777 return 1;
2778 else
2779 return ((prev_get_char = dos_rawgetc ()) != -1);
2782 /* Read a key. Return -1 if no key is ready. */
2784 dos_keyread (void)
2786 if (prev_get_char != -1)
2788 int c = prev_get_char;
2789 prev_get_char = -1;
2790 return c;
2792 else
2793 return dos_rawgetc ();
2796 #ifndef HAVE_X_WINDOWS
2798 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2799 for now.
2801 Actually, I don't know the meaning of all the parameters of the functions
2802 here -- I only know how they are called by xmenu.c. I could of course
2803 grab the nearest Xlib manual (down the hall, second-to-last door on the
2804 left), but I don't think it's worth the effort. */
2806 /* These hold text of the current and the previous menu help messages. */
2807 static const char *menu_help_message, *prev_menu_help_message;
2808 /* Pane number and item number of the menu item which generated the
2809 last menu help message. */
2810 static int menu_help_paneno, menu_help_itemno;
2812 static XMenu *
2813 IT_menu_create (void)
2815 XMenu *menu;
2817 menu = xmalloc (sizeof (XMenu));
2818 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2819 return menu;
2822 /* Allocate some (more) memory for MENU ensuring that there is room for one
2823 for item. */
2825 static void
2826 IT_menu_make_room (XMenu *menu)
2828 if (menu->allocated == 0)
2830 int count = menu->allocated = 10;
2831 menu->text = xmalloc (count * sizeof (char *));
2832 menu->submenu = xmalloc (count * sizeof (XMenu *));
2833 menu->panenumber = xmalloc (count * sizeof (int));
2834 menu->help_text = xmalloc (count * sizeof (char *));
2836 else if (menu->allocated == menu->count)
2838 int count = menu->allocated = menu->allocated + 10;
2839 menu->text
2840 = (char **) xrealloc (menu->text, count * sizeof (char *));
2841 menu->submenu
2842 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2843 menu->panenumber
2844 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2845 menu->help_text
2846 = (const char **) xrealloc (menu->help_text, count * sizeof (char *));
2850 /* Search the given menu structure for a given pane number. */
2852 static XMenu *
2853 IT_menu_search_pane (XMenu *menu, int pane)
2855 int i;
2856 XMenu *try;
2858 for (i = 0; i < menu->count; i++)
2859 if (menu->submenu[i])
2861 if (pane == menu->panenumber[i])
2862 return menu->submenu[i];
2863 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2864 return try;
2866 return (XMenu *) 0;
2869 /* Determine how much screen space a given menu needs. */
2871 static void
2872 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2874 int i, h2, w2, maxsubwidth, maxheight;
2876 maxsubwidth = 0;
2877 maxheight = menu->count;
2878 for (i = 0; i < menu->count; i++)
2880 if (menu->submenu[i])
2882 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2883 if (w2 > maxsubwidth) maxsubwidth = w2;
2884 if (i + h2 > maxheight) maxheight = i + h2;
2887 *width = menu->width + maxsubwidth;
2888 *height = maxheight;
2891 /* Display MENU at (X,Y) using FACES. */
2893 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
2894 do \
2896 (GLYPH).type = CHAR_GLYPH; \
2897 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
2898 (GLYPH).charpos = -1; \
2900 while (0)
2902 static void
2903 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
2905 int i, j, face, width, mx, my, enabled, mousehere, row, col;
2906 struct glyph *text, *p;
2907 const unsigned char *q;
2908 struct frame *sf = SELECTED_FRAME ();
2910 menu_help_message = NULL;
2912 width = menu->width;
2913 /* We multiply width by 2 to account for possible control characters.
2914 FIXME: cater to non-ASCII characters in menus. */
2915 text = xmalloc ((width * 2 + 2) * sizeof (struct glyph));
2916 ScreenGetCursor (&row, &col);
2917 mouse_get_xy (&mx, &my);
2918 IT_update_begin (sf);
2919 for (i = 0; i < menu->count; i++)
2921 int max_width = width + 2;
2923 IT_cursor_to (sf, y + i, x);
2924 enabled
2925 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2926 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2927 face = faces[enabled + mousehere * 2];
2928 /* The following if clause means that we display the menu help
2929 strings even if the menu item is currently disabled. */
2930 if (disp_help && enabled + mousehere * 2 >= 2)
2932 menu_help_message = menu->help_text[i];
2933 menu_help_paneno = pn - 1;
2934 menu_help_itemno = i;
2936 p = text;
2937 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
2938 p++;
2939 for (j = 0, q = menu->text[i]; *q; j++)
2941 unsigned c = STRING_CHAR_ADVANCE (q);
2943 if (c > 26)
2945 BUILD_CHAR_GLYPH (*p, c, face, 0);
2946 p++;
2948 else /* make '^x' */
2950 BUILD_CHAR_GLYPH (*p, '^', face, 0);
2951 p++;
2952 j++;
2953 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
2954 p++;
2957 /* Don't let the menu text overflow into the next screen row. */
2958 if (x + max_width > screen_size_X)
2960 max_width = screen_size_X - x;
2961 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
2963 for (; j < max_width - 2; j++, p++)
2964 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
2966 /* 16 is the character code of a character that on DOS terminal
2967 produces a nice-looking right-pointing arrow glyph. */
2968 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
2969 p++;
2970 IT_write_glyphs (sf, text, max_width);
2972 IT_update_end (sf);
2973 IT_cursor_to (sf, row, col);
2974 xfree (text);
2977 /* --------------------------- X Menu emulation ---------------------- */
2979 /* Report availability of menus. */
2982 have_menus_p (void) { return 1; }
2984 /* Create a brand new menu structure. */
2986 XMenu *
2987 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2989 return IT_menu_create ();
2992 /* Create a new pane and place it on the outer-most level. It is not
2993 clear that it should be placed out there, but I don't know what else
2994 to do. */
2997 XMenuAddPane (Display *foo, XMenu *menu, const char *txt, int enable)
2999 int len;
3000 const char *p;
3002 if (!enable)
3003 emacs_abort ();
3005 IT_menu_make_room (menu);
3006 menu->submenu[menu->count] = IT_menu_create ();
3007 menu->text[menu->count] = (char *)txt;
3008 menu->panenumber[menu->count] = ++menu->panecount;
3009 menu->help_text[menu->count] = NULL;
3010 menu->count++;
3012 /* Adjust length for possible control characters (which will
3013 be written as ^x). */
3014 for (len = strlen (txt), p = txt; *p; p++)
3015 if (*p < 27)
3016 len++;
3018 if (len > menu->width)
3019 menu->width = len;
3021 return menu->panecount;
3024 /* Create a new item in a menu pane. */
3027 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3028 int foo, char *txt, int enable, char const *help_text)
3030 int len;
3031 char *p;
3033 if (pane)
3034 if (!(menu = IT_menu_search_pane (menu, pane)))
3035 return XM_FAILURE;
3036 IT_menu_make_room (menu);
3037 menu->submenu[menu->count] = (XMenu *) 0;
3038 menu->text[menu->count] = txt;
3039 menu->panenumber[menu->count] = enable;
3040 menu->help_text[menu->count] = help_text;
3041 menu->count++;
3043 /* Adjust length for possible control characters (which will
3044 be written as ^x). */
3045 for (len = strlen (txt), p = txt; *p; p++)
3046 if (*p < 27)
3047 len++;
3049 if (len > menu->width)
3050 menu->width = len;
3052 return XM_SUCCESS;
3055 /* Decide where the menu would be placed if requested at (X,Y). */
3057 void
3058 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3059 int *ulx, int *uly, int *width, int *height)
3061 IT_menu_calc_size (menu, width, height);
3062 *ulx = x + 1;
3063 *uly = y;
3064 *width += 2;
3067 struct IT_menu_state
3069 void *screen_behind;
3070 XMenu *menu;
3071 int pane;
3072 int x, y;
3076 /* Display menu, wait for user's response, and return that response. */
3079 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3080 int x0, int y0, unsigned ButtonMask, char **txt,
3081 void (*help_callback)(char const *, int, int))
3083 struct IT_menu_state *state;
3084 int statecount, x, y, i, b, screensize, leave, result, onepane;
3085 int title_faces[4]; /* face to display the menu title */
3086 int faces[4], buffers_num_deleted = 0;
3087 struct frame *sf = SELECTED_FRAME ();
3088 Lisp_Object saved_echo_area_message, selectface;
3090 /* Just in case we got here without a mouse present... */
3091 if (have_mouse <= 0)
3092 return XM_IA_SELECT;
3093 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3094 around the display. */
3095 if (x0 <= 0)
3096 x0 = 1;
3097 if (y0 <= 0)
3098 y0 = 1;
3100 /* We will process all the mouse events directly, so we had
3101 better prevent dos_rawgetc from stealing them from us. */
3102 mouse_preempted++;
3104 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3105 screensize = screen_size * 2;
3106 faces[0]
3107 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3108 DEFAULT_FACE_ID, 1);
3109 faces[1]
3110 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3111 DEFAULT_FACE_ID, 1);
3112 selectface = intern ("msdos-menu-select-face");
3113 faces[2] = lookup_derived_face (sf, selectface,
3114 faces[0], 1);
3115 faces[3] = lookup_derived_face (sf, selectface,
3116 faces[1], 1);
3118 /* Make sure the menu title is always displayed with
3119 `msdos-menu-active-face', no matter where the mouse pointer is. */
3120 for (i = 0; i < 4; i++)
3121 title_faces[i] = faces[3];
3123 statecount = 1;
3125 /* Don't let the title for the "Buffers" popup menu include a
3126 digit (which is ugly).
3128 This is a terrible kludge, but I think the "Buffers" case is
3129 the only one where the title includes a number, so it doesn't
3130 seem to be necessary to make this more general. */
3131 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3133 menu->text[0][7] = '\0';
3134 buffers_num_deleted = 1;
3137 /* We need to save the current echo area message, so that we could
3138 restore it below, before we exit. See the commentary below,
3139 before the call to message_with_string. */
3140 saved_echo_area_message = Fcurrent_message ();
3141 state[0].menu = menu;
3142 mouse_off ();
3143 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3145 /* Turn off the cursor. Otherwise it shows through the menu
3146 panes, which is ugly. */
3147 IT_display_cursor (0);
3149 /* Display the menu title. */
3150 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3151 if (buffers_num_deleted)
3152 menu->text[0][7] = ' ';
3153 if ((onepane = menu->count == 1 && menu->submenu[0]))
3155 menu->width = menu->submenu[0]->width;
3156 state[0].menu = menu->submenu[0];
3158 else
3160 state[0].menu = menu;
3162 state[0].x = x0 - 1;
3163 state[0].y = y0;
3164 state[0].pane = onepane;
3166 mouse_last_x = -1; /* A hack that forces display. */
3167 leave = 0;
3168 while (!leave)
3170 if (!mouse_visible) mouse_on ();
3171 mouse_check_moved ();
3172 if (sf->mouse_moved)
3174 sf->mouse_moved = 0;
3175 result = XM_IA_SELECT;
3176 mouse_get_xy (&x, &y);
3177 for (i = 0; i < statecount; i++)
3178 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3180 int dy = y - state[i].y;
3181 if (0 <= dy && dy < state[i].menu->count)
3183 if (!state[i].menu->submenu[dy])
3185 if (state[i].menu->panenumber[dy])
3186 result = XM_SUCCESS;
3187 else
3188 result = XM_IA_SELECT;
3190 *pane = state[i].pane - 1;
3191 *selidx = dy;
3192 /* We hit some part of a menu, so drop extra menus that
3193 have been opened. That does not include an open and
3194 active submenu. */
3195 if (i != statecount - 2
3196 || state[i].menu->submenu[dy] != state[i+1].menu)
3197 while (i != statecount - 1)
3199 statecount--;
3200 mouse_off ();
3201 ScreenUpdate (state[statecount].screen_behind);
3202 if (screen_virtual_segment)
3203 dosv_refresh_virtual_screen (0, screen_size);
3204 xfree (state[statecount].screen_behind);
3206 if (i == statecount - 1 && state[i].menu->submenu[dy])
3208 IT_menu_display (state[i].menu,
3209 state[i].y,
3210 state[i].x,
3211 state[i].pane,
3212 faces, 1);
3213 state[statecount].menu = state[i].menu->submenu[dy];
3214 state[statecount].pane = state[i].menu->panenumber[dy];
3215 mouse_off ();
3216 ScreenRetrieve (state[statecount].screen_behind
3217 = xmalloc (screensize));
3218 state[statecount].x
3219 = state[i].x + state[i].menu->width + 2;
3220 state[statecount].y = y;
3221 statecount++;
3225 IT_menu_display (state[statecount - 1].menu,
3226 state[statecount - 1].y,
3227 state[statecount - 1].x,
3228 state[statecount - 1].pane,
3229 faces, 1);
3231 else
3233 if ((menu_help_message || prev_menu_help_message)
3234 && menu_help_message != prev_menu_help_message)
3236 help_callback (menu_help_message,
3237 menu_help_paneno, menu_help_itemno);
3238 IT_display_cursor (0);
3239 prev_menu_help_message = menu_help_message;
3241 /* We are busy-waiting for the mouse to move, so let's be nice
3242 to other Windows applications by releasing our time slice. */
3243 __dpmi_yield ();
3245 for (b = 0; b < mouse_button_count && !leave; b++)
3247 /* Only leave if user both pressed and released the mouse, and in
3248 that order. This avoids popping down the menu pane unless
3249 the user is really done with it. */
3250 if (mouse_pressed (b, &x, &y))
3252 while (mouse_button_depressed (b, &x, &y))
3253 __dpmi_yield ();
3254 leave = 1;
3256 (void) mouse_released (b, &x, &y);
3260 mouse_off ();
3261 ScreenUpdate (state[0].screen_behind);
3262 if (screen_virtual_segment)
3263 dosv_refresh_virtual_screen (0, screen_size);
3265 /* We have a situation here. ScreenUpdate has just restored the
3266 screen contents as it was before we started drawing this menu.
3267 That includes any echo area message that could have been
3268 displayed back then. (In reality, that echo area message will
3269 almost always be the ``keystroke echo'' that echoes the sequence
3270 of menu items chosen by the user.) However, if the menu had some
3271 help messages, then displaying those messages caused Emacs to
3272 forget about the original echo area message. So when
3273 ScreenUpdate restored it, it created a discrepancy between the
3274 actual screen contents and what Emacs internal data structures
3275 know about it.
3277 To avoid this conflict, we force Emacs to restore the original
3278 echo area message as we found it when we entered this function.
3279 The irony of this is that we then erase the restored message
3280 right away, so the only purpose of restoring it is so that
3281 erasing it works correctly... */
3282 if (! NILP (saved_echo_area_message))
3283 message_with_string ("%s", saved_echo_area_message, 0);
3284 message (0);
3285 while (statecount--)
3286 xfree (state[statecount].screen_behind);
3287 IT_display_cursor (1); /* turn cursor back on */
3288 /* Clean up any mouse events that are waiting inside Emacs event queue.
3289 These events are likely to be generated before the menu was even
3290 displayed, probably because the user pressed and released the button
3291 (which invoked the menu) too quickly. If we don't remove these events,
3292 Emacs will process them after we return and surprise the user. */
3293 discard_mouse_events ();
3294 mouse_clear_clicks ();
3295 if (!kbd_buffer_events_waiting ())
3296 clear_input_pending ();
3297 /* Allow mouse events generation by dos_rawgetc. */
3298 mouse_preempted--;
3299 return result;
3302 /* Dispose of a menu. */
3304 void
3305 XMenuDestroy (Display *foo, XMenu *menu)
3307 int i;
3308 if (menu->allocated)
3310 for (i = 0; i < menu->count; i++)
3311 if (menu->submenu[i])
3312 XMenuDestroy (foo, menu->submenu[i]);
3313 xfree (menu->text);
3314 xfree (menu->submenu);
3315 xfree (menu->panenumber);
3316 xfree (menu->help_text);
3318 xfree (menu);
3319 menu_help_message = prev_menu_help_message = NULL;
3323 x_pixel_width (struct frame *f)
3325 return FRAME_COLS (f);
3329 x_pixel_height (struct frame *f)
3331 return FRAME_LINES (f);
3333 #endif /* !HAVE_X_WINDOWS */
3335 /* ----------------------- DOS / UNIX conversion --------------------- */
3337 void msdos_downcase_filename (unsigned char *);
3339 /* Destructively turn backslashes into slashes. */
3341 void
3342 dostounix_filename (char *p)
3344 msdos_downcase_filename (p);
3346 while (*p)
3348 if (*p == '\\')
3349 *p = '/';
3350 p++;
3354 /* Destructively turn slashes into backslashes. */
3356 void
3357 unixtodos_filename (char *p)
3359 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3361 *p += 'a' - 'A';
3362 p += 2;
3365 while (*p)
3367 if (*p == '/')
3368 *p = '\\';
3369 p++;
3373 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3376 getdefdir (int drive, char *dst)
3378 char in_path[4], *p = in_path, e = errno;
3380 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3381 if (drive != 0)
3383 *p++ = drive + 'A' - 1;
3384 *p++ = ':';
3387 *p++ = '.';
3388 *p = '\0';
3389 errno = 0;
3390 _fixpath (in_path, dst);
3391 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3392 it queries the LFN support, so ignore that error. */
3393 if ((errno && errno != ENOSYS) || *dst == '\0')
3394 return 0;
3396 msdos_downcase_filename (dst);
3398 errno = e;
3399 return 1;
3402 char *
3403 emacs_root_dir (void)
3405 static char root_dir[4];
3407 sprintf (root_dir, "%c:/", 'A' + getdisk ());
3408 root_dir[0] = tolower (root_dir[0]);
3409 return root_dir;
3412 /* Remove all CR's that are followed by a LF. */
3415 crlf_to_lf (int n, unsigned char *buf)
3417 unsigned char *np = buf, *startp = buf, *endp = buf + n;
3419 if (n == 0)
3420 return n;
3421 while (buf < endp - 1)
3423 if (*buf == 0x0d)
3425 if (*(++buf) != 0x0a)
3426 *np++ = 0x0d;
3428 else
3429 *np++ = *buf++;
3431 if (buf < endp)
3432 *np++ = *buf++;
3433 return np - startp;
3436 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3437 0, 0, 0,
3438 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
3439 (void)
3441 return (_USE_LFN ? Qt : Qnil);
3444 /* Convert alphabetic characters in a filename to lower-case. */
3446 void
3447 msdos_downcase_filename (unsigned char *p)
3449 /* Always lower-case drive letters a-z, even if the filesystem
3450 preserves case in filenames.
3451 This is so MSDOS filenames could be compared by string comparison
3452 functions that are case-sensitive. Even case-preserving filesystems
3453 do not distinguish case in drive letters. */
3454 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3456 *p += 'a' - 'A';
3457 p += 2;
3460 /* Under LFN we expect to get pathnames in their true case. */
3461 if (NILP (Fmsdos_long_file_names ()))
3462 for ( ; *p; p++)
3463 if (*p >= 'A' && *p <= 'Z')
3464 *p += 'a' - 'A';
3467 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3468 1, 1, 0,
3469 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
3470 When long filenames are supported, doesn't change FILENAME.
3471 If FILENAME is not a string, returns nil.
3472 The argument object is never altered--the value is a copy. */)
3473 (Lisp_Object filename)
3475 Lisp_Object tem;
3477 if (! STRINGP (filename))
3478 return Qnil;
3480 tem = Fcopy_sequence (filename);
3481 msdos_downcase_filename (SDATA (tem));
3482 return tem;
3485 /* The Emacs root directory as determined by init_environment. */
3487 static char emacsroot[MAXPATHLEN];
3489 char *
3490 rootrelativepath (char *rel)
3492 static char result[MAXPATHLEN + 10];
3494 strcpy (result, emacsroot);
3495 strcat (result, "/");
3496 strcat (result, rel);
3497 return result;
3500 /* Define a lot of environment variables if not already defined. Don't
3501 remove anything unless you know what you're doing -- lots of code will
3502 break if one or more of these are missing. */
3504 void
3505 init_environment (int argc, char **argv, int skip_args)
3507 char *s, *t, *root;
3508 int len, i;
3509 static const char * const tempdirs[] = {
3510 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3512 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
3514 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3515 temporary files and assume "/tmp" if $TMPDIR is unset, which
3516 will break on DOS/Windows. Refuse to work if we cannot find
3517 a directory, not even "c:/", usable for that purpose. */
3518 for (i = 0; i < imax ; i++)
3520 const char *tmp = tempdirs[i];
3521 char buf[FILENAME_MAX];
3523 if (*tmp == '$')
3525 int tmp_len;
3527 tmp = getenv (tmp + 1);
3528 if (!tmp)
3529 continue;
3531 /* Some lusers set TMPDIR=e:, probably because some losing
3532 programs cannot handle multiple slashes if they use e:/.
3533 e: fails in `access' below, so we interpret e: as e:/. */
3534 tmp_len = strlen (tmp);
3535 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
3537 strcpy (buf, tmp);
3538 buf[tmp_len++] = '/', buf[tmp_len] = 0;
3539 tmp = buf;
3543 /* Note that `access' can lie to us if the directory resides on a
3544 read-only filesystem, like CD-ROM or a write-protected floppy.
3545 The only way to be really sure is to actually create a file and
3546 see if it succeeds. But I think that's too much to ask. */
3547 if (tmp && access (tmp, D_OK) == 0)
3549 setenv ("TMPDIR", tmp, 1);
3550 break;
3553 if (i >= imax)
3554 cmd_error_internal
3555 (Fcons (Qerror,
3556 Fcons (build_string ("no usable temporary directories found!!"),
3557 Qnil)),
3558 "While setting TMPDIR: ");
3560 /* Note the startup time, so we know not to clear the screen if we
3561 exit immediately; see IT_reset_terminal_modes.
3562 (Yes, I know `clock' returns zero the first time it's called, but
3563 I do this anyway, in case some wiseguy changes that at some point.) */
3564 startup_time = clock ();
3566 /* Find our root from argv[0]. Assuming argv[0] is, say,
3567 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3568 root = alloca (MAXPATHLEN + 20);
3569 _fixpath (argv[0], root);
3570 msdos_downcase_filename (root);
3571 len = strlen (root);
3572 while (len > 0 && root[len] != '/' && root[len] != ':')
3573 len--;
3574 root[len] = '\0';
3575 if (len > 4
3576 && (strcmp (root + len - 4, "/bin") == 0
3577 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
3578 root[len - 4] = '\0';
3579 else
3580 strcpy (root, "c:/emacs"); /* let's be defensive */
3581 len = strlen (root);
3582 strcpy (emacsroot, root);
3584 /* We default HOME to our root. */
3585 setenv ("HOME", root, 0);
3587 /* We default EMACSPATH to root + "/bin". */
3588 strcpy (root + len, "/bin");
3589 setenv ("EMACSPATH", root, 0);
3591 /* I don't expect anybody to ever use other terminals so the internal
3592 terminal is the default. */
3593 setenv ("TERM", "internal", 0);
3595 #ifdef HAVE_X_WINDOWS
3596 /* Emacs expects DISPLAY to be set. */
3597 setenv ("DISPLAY", "unix:0.0", 0);
3598 #endif
3600 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3601 downcase it and mirror the backslashes. */
3602 s = getenv ("COMSPEC");
3603 if (!s) s = "c:/command.com";
3604 t = alloca (strlen (s) + 1);
3605 strcpy (t, s);
3606 dostounix_filename (t);
3607 setenv ("SHELL", t, 0);
3609 /* PATH is also downcased and backslashes mirrored. */
3610 s = getenv ("PATH");
3611 if (!s) s = "";
3612 t = alloca (strlen (s) + 3);
3613 /* Current directory is always considered part of MsDos's path but it is
3614 not normally mentioned. Now it is. */
3615 strcat (strcpy (t, ".;"), s);
3616 dostounix_filename (t); /* Not a single file name, but this should work. */
3617 setenv ("PATH", t, 1);
3619 /* In some sense all dos users have root privileges, so... */
3620 setenv ("USER", "root", 0);
3621 setenv ("NAME", getenv ("USER"), 0);
3623 /* Time zone determined from country code. To make this possible, the
3624 country code may not span more than one time zone. In other words,
3625 in the USA, you lose. */
3626 if (!getenv ("TZ"))
3627 switch (dos_country_code)
3629 case 31: /* Belgium */
3630 case 32: /* The Netherlands */
3631 case 33: /* France */
3632 case 34: /* Spain */
3633 case 36: /* Hungary */
3634 case 38: /* Yugoslavia (or what's left of it?) */
3635 case 39: /* Italy */
3636 case 41: /* Switzerland */
3637 case 42: /* Tjekia */
3638 case 45: /* Denmark */
3639 case 46: /* Sweden */
3640 case 47: /* Norway */
3641 case 48: /* Poland */
3642 case 49: /* Germany */
3643 /* Daylight saving from last Sunday in March to last Sunday in
3644 September, both at 2AM. */
3645 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3646 break;
3647 case 44: /* United Kingdom */
3648 case 351: /* Portugal */
3649 case 354: /* Iceland */
3650 setenv ("TZ", "GMT+00", 0);
3651 break;
3652 case 81: /* Japan */
3653 case 82: /* Korea */
3654 setenv ("TZ", "JST-09", 0);
3655 break;
3656 case 90: /* Turkey */
3657 case 358: /* Finland */
3658 setenv ("TZ", "EET-02", 0);
3659 break;
3660 case 972: /* Israel */
3661 /* This is an approximation. (For exact rules, use the
3662 `zoneinfo/israel' file which comes with DJGPP, but you need
3663 to install it in `/usr/share/zoneinfo/' directory first.) */
3664 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3665 break;
3667 tzset ();
3672 static int break_stat; /* BREAK check mode status. */
3673 static int stdin_stat; /* stdin IOCTL status. */
3675 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3676 control chars by DOS. Determine the keyboard type. */
3679 dos_ttraw (struct tty_display_info *tty)
3681 union REGS inregs, outregs;
3682 static int first_time = 1;
3684 /* If we are called for the initial terminal, it's too early to do
3685 anything, and termscript isn't set up. */
3686 if (tty->terminal->type == output_initial)
3687 return 2;
3689 break_stat = getcbrk ();
3690 setcbrk (0);
3692 if (first_time)
3694 inregs.h.ah = 0xc0;
3695 int86 (0x15, &inregs, &outregs);
3696 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
3698 have_mouse = 0;
3700 if (1
3701 #ifdef HAVE_X_WINDOWS
3702 && inhibit_window_system
3703 #endif
3706 inregs.x.ax = 0x0021;
3707 int86 (0x33, &inregs, &outregs);
3708 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3709 if (!have_mouse)
3711 /* Reportedly, the above doesn't work for some mouse drivers. There
3712 is an additional detection method that should work, but might be
3713 a little slower. Use that as an alternative. */
3714 inregs.x.ax = 0x0000;
3715 int86 (0x33, &inregs, &outregs);
3716 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3718 if (have_mouse)
3719 mouse_button_count = outregs.x.bx;
3721 #ifndef HAVE_X_WINDOWS
3722 /* Save the cursor shape used outside Emacs. */
3723 outside_cursor = _farpeekw (_dos_ds, 0x460);
3724 #endif
3727 first_time = 0;
3729 stdin_stat = setmode (fileno (stdin), O_BINARY);
3730 return (stdin_stat != -1);
3732 else
3733 return (setmode (fileno (stdin), O_BINARY) != -1);
3736 /* Restore status of standard input and Ctrl-C checking. */
3739 dos_ttcooked (void)
3741 union REGS inregs, outregs;
3743 setcbrk (break_stat);
3744 mouse_off ();
3746 #ifndef HAVE_X_WINDOWS
3747 /* Restore the cursor shape we found on startup. */
3748 if (outside_cursor)
3750 inregs.h.ah = 1;
3751 inregs.x.cx = outside_cursor;
3752 int86 (0x10, &inregs, &outregs);
3754 #endif
3756 return (setmode (fileno (stdin), stdin_stat) != -1);
3760 /* Run command as specified by ARGV in directory DIR.
3761 The command is run with input from TEMPIN, output to
3762 file TEMPOUT and stderr to TEMPERR. */
3765 run_msdos_command (unsigned char **argv, const char *working_dir,
3766 int tempin, int tempout, int temperr, char **envv)
3768 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
3769 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3770 int msshell, result = -1, inbak, outbak, errbak, x, y;
3771 Lisp_Object cmd;
3773 /* Get current directory as MSDOS cwd is not per-process. */
3774 getwd (oldwd);
3776 /* If argv[0] is the shell, it might come in any lettercase.
3777 Since `Fmember' is case-sensitive, we need to downcase
3778 argv[0], even if we are on case-preserving filesystems. */
3779 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3780 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3782 *pl = *pa++;
3783 if (*pl >= 'A' && *pl <= 'Z')
3784 *pl += 'a' - 'A';
3786 *pl = '\0';
3788 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3789 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3790 && !strcmp ("-c", argv[1]);
3791 if (msshell)
3793 saveargv1 = argv[1];
3794 saveargv2 = argv[2];
3795 argv[1] = "/c";
3796 /* We only need to mirror slashes if a DOS shell will be invoked
3797 not via `system' (which does the mirroring itself). Yes, that
3798 means DJGPP v1.x will lose here. */
3799 if (argv[2] && argv[3])
3801 char *p = alloca (strlen (argv[2]) + 1);
3803 strcpy (argv[2] = p, saveargv2);
3804 while (*p && isspace (*p))
3805 p++;
3806 while (*p)
3808 if (*p == '/')
3809 *p++ = '\\';
3810 else
3811 p++;
3816 chdir (working_dir);
3817 inbak = dup (0);
3818 outbak = dup (1);
3819 errbak = dup (2);
3820 if (inbak < 0 || outbak < 0 || errbak < 0)
3821 goto done; /* Allocation might fail due to lack of descriptors. */
3823 if (have_mouse > 0)
3824 mouse_get_xy (&x, &y);
3826 if (!noninteractive)
3827 dos_ttcooked (); /* do it here while 0 = stdin */
3829 dup2 (tempin, 0);
3830 dup2 (tempout, 1);
3831 dup2 (temperr, 2);
3833 if (msshell && !argv[3])
3835 /* MS-DOS native shells are too restrictive. For starters, they
3836 cannot grok commands longer than 126 characters. In DJGPP v2
3837 and later, `system' is much smarter, so we'll call it instead. */
3839 const char *cmnd;
3841 /* A shell gets a single argument--its full command
3842 line--whose original was saved in `saveargv2'. */
3844 /* Don't let them pass empty command lines to `system', since
3845 with some shells it will try to invoke an interactive shell,
3846 which will hang Emacs. */
3847 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
3849 if (*cmnd)
3851 extern char **environ;
3852 char **save_env = environ;
3853 int save_system_flags = __system_flags;
3855 /* Request the most powerful version of `system'. We need
3856 all the help we can get to avoid calling stock DOS shells. */
3857 __system_flags = (__system_redirect
3858 | __system_use_shell
3859 | __system_allow_multiple_cmds
3860 | __system_allow_long_cmds
3861 | __system_handle_null_commands
3862 | __system_emulate_chdir);
3864 environ = envv;
3865 result = system (cmnd);
3866 __system_flags = save_system_flags;
3867 environ = save_env;
3869 else
3870 result = 0; /* emulate Unixy shell behavior with empty cmd line */
3872 else
3873 result = spawnve (P_WAIT, argv[0], (char **)argv, envv);
3875 dup2 (inbak, 0);
3876 dup2 (outbak, 1);
3877 dup2 (errbak, 2);
3878 emacs_close (inbak);
3879 emacs_close (outbak);
3880 emacs_close (errbak);
3882 if (!noninteractive)
3883 dos_ttraw (CURTTY ());
3884 if (have_mouse > 0)
3886 mouse_init ();
3887 mouse_moveto (x, y);
3890 /* Some programs might change the meaning of the highest bit of the
3891 text attribute byte, so we get blinking characters instead of the
3892 bright background colors. Restore that. */
3893 if (!noninteractive)
3894 bright_bg ();
3896 done:
3897 chdir (oldwd);
3898 if (msshell)
3900 argv[1] = saveargv1;
3901 argv[2] = saveargv2;
3903 return result;
3906 void
3907 croak (char *badfunc)
3909 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3910 reset_all_sys_modes ();
3911 exit (1);
3915 * A few unimplemented functions that we silently ignore.
3917 pid_t tcgetpgrp (int fd) { return 0; }
3918 int setpgid (int pid, int pgid) { return 0; }
3919 int setpriority (int x, int y, int z) { return 0; }
3920 pid_t setsid (void) { return 0; }
3922 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
3923 ssize_t
3924 readlink (const char *name, char *dummy1, size_t dummy2)
3926 /* `access' is much faster than `stat' on MS-DOS. */
3927 if (access (name, F_OK) == 0)
3928 errno = EINVAL;
3929 return -1;
3931 #endif
3933 char *
3934 careadlinkat (int fd, char const *filename,
3935 char *buffer, size_t buffer_size,
3936 struct allocator const *alloc,
3937 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
3939 if (!buffer)
3941 /* We don't support the fancy auto-allocation feature. */
3942 if (!buffer_size)
3943 errno = ENOSYS;
3944 else
3945 errno = EINVAL;
3946 buffer = NULL;
3948 else
3950 ssize_t len = preadlinkat (fd, filename, buffer, buffer_size);
3952 if (len < 0 || len == buffer_size)
3953 buffer = NULL;
3954 else
3955 buffer[len + 1] = '\0';
3957 return buffer;
3960 ssize_t
3961 careadlinkatcwd (int fd, char const *filename, char *buffer,
3962 size_t buffer_size)
3964 (void) fd;
3965 return readlink (filename, buffer, buffer_size);
3969 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3971 /* Augment DJGPP library POSIX signal functions. This is needed
3972 as of DJGPP v2.01, but might be in the library in later releases. */
3974 #include <libc/bss.h>
3976 /* A counter to know when to re-initialize the static sets. */
3977 static int sigprocmask_count = -1;
3979 /* Which signals are currently blocked (initially none). */
3980 static sigset_t current_mask;
3982 /* Which signals are pending (initially none). */
3983 static sigset_t msdos_pending_signals;
3985 /* Previous handlers to restore when the blocked signals are unblocked. */
3986 typedef void (*sighandler_t)(int);
3987 static sighandler_t prev_handlers[320];
3989 /* A signal handler which just records that a signal occurred
3990 (it will be raised later, if and when the signal is unblocked). */
3991 static void
3992 sig_suspender (int signo)
3994 sigaddset (&msdos_pending_signals, signo);
3998 sigprocmask (int how, const sigset_t *new_set, sigset_t *old_set)
4000 int signo;
4001 sigset_t new_mask;
4003 /* If called for the first time, initialize. */
4004 if (sigprocmask_count != __bss_count)
4006 sigprocmask_count = __bss_count;
4007 sigemptyset (&msdos_pending_signals);
4008 sigemptyset (&current_mask);
4009 for (signo = 0; signo < 320; signo++)
4010 prev_handlers[signo] = SIG_ERR;
4013 if (old_set)
4014 *old_set = current_mask;
4016 if (new_set == 0)
4017 return 0;
4019 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4021 errno = EINVAL;
4022 return -1;
4025 sigemptyset (&new_mask);
4027 /* DJGPP supports upto 320 signals. */
4028 for (signo = 0; signo < 320; signo++)
4030 if (sigismember (&current_mask, signo))
4031 sigaddset (&new_mask, signo);
4032 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4034 sigaddset (&new_mask, signo);
4036 /* SIGKILL is silently ignored, as on other platforms. */
4037 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4038 prev_handlers[signo] = signal (signo, sig_suspender);
4040 if (( how == SIG_UNBLOCK
4041 && sigismember (&new_mask, signo)
4042 && sigismember (new_set, signo))
4043 || (how == SIG_SETMASK
4044 && sigismember (&new_mask, signo)
4045 && !sigismember (new_set, signo)))
4047 sigdelset (&new_mask, signo);
4048 if (prev_handlers[signo] != SIG_ERR)
4050 signal (signo, prev_handlers[signo]);
4051 prev_handlers[signo] = SIG_ERR;
4053 if (sigismember (&msdos_pending_signals, signo))
4055 sigdelset (&msdos_pending_signals, signo);
4056 raise (signo);
4060 current_mask = new_mask;
4061 return 0;
4064 #endif /* not __DJGPP_MINOR__ < 2 */
4066 #ifndef HAVE_SELECT
4067 #include "sysselect.h"
4069 /* This yields the rest of the current time slice to the task manager.
4070 It should be called by any code which knows that it has nothing
4071 useful to do except idle.
4073 I don't use __dpmi_yield here, since versions of library before 2.02
4074 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4075 on some versions of Windows 9X. */
4077 void
4078 dos_yield_time_slice (void)
4080 _go32_dpmi_registers r;
4082 r.x.ax = 0x1680;
4083 r.x.ss = r.x.sp = r.x.flags = 0;
4084 _go32_dpmi_simulate_int (0x2f, &r);
4085 if (r.h.al == 0x80)
4086 errno = ENOSYS;
4089 /* Only event queue is checked. */
4090 /* We don't have to call timer_check here
4091 because wait_reading_process_output takes care of that. */
4093 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
4094 EMACS_TIME *timeout, void *ignored)
4096 int check_input;
4097 struct timespec t;
4099 check_input = 0;
4100 if (rfds)
4102 check_input = FD_ISSET (0, rfds);
4103 FD_ZERO (rfds);
4105 if (wfds)
4106 FD_ZERO (wfds);
4107 if (efds)
4108 FD_ZERO (efds);
4110 if (nfds != 1)
4111 emacs_abort ();
4113 /* If we are looking only for the terminal, with no timeout,
4114 just read it and wait -- that's more efficient. */
4115 if (!timeout)
4117 while (!detect_input_pending ())
4119 dos_yield_time_slice ();
4122 else
4124 EMACS_TIME clnow, cllast, cldiff;
4126 gettime (&t);
4127 cllast = make_emacs_time (t.tv_sec, t.tv_nsec);
4129 while (!check_input || !detect_input_pending ())
4131 gettime (&t);
4132 clnow = make_emacs_time (t.tv_sec, t.tv_nsec);
4133 cldiff = sub_emacs_time (clnow, cllast);
4134 *timeout = sub_emacs_time (*timeout, cldiff);
4136 /* Stop when timeout value crosses zero. */
4137 if (EMACS_TIME_SIGN (*timeout) <= 0)
4138 return 0;
4139 cllast = clnow;
4140 dos_yield_time_slice ();
4144 FD_SET (0, rfds);
4145 return 1;
4147 #endif
4150 * Define overlaid functions:
4152 * chdir -> sys_chdir
4153 * tzset -> init_gettimeofday
4154 * abort -> dos_abort
4157 #ifdef chdir
4158 #undef chdir
4159 extern int chdir (const char *);
4162 sys_chdir (const char *path)
4164 int len = strlen (path);
4165 char *tmp = (char *)path;
4167 if (*tmp && tmp[1] == ':')
4169 if (getdisk () != tolower (tmp[0]) - 'a')
4170 setdisk (tolower (tmp[0]) - 'a');
4171 tmp += 2; /* strip drive: KFS 1995-07-06 */
4172 len -= 2;
4175 if (len > 1 && (tmp[len - 1] == '/'))
4177 char *tmp1 = (char *) alloca (len + 1);
4178 strcpy (tmp1, tmp);
4179 tmp1[len - 1] = 0;
4180 tmp = tmp1;
4182 return chdir (tmp);
4184 #endif
4186 #ifdef tzset
4187 #undef tzset
4188 extern void tzset (void);
4190 void
4191 init_gettimeofday (void)
4193 time_t ltm, gtm;
4194 struct tm *lstm;
4196 tzset ();
4197 ltm = gtm = time (NULL);
4198 ltm = mktime (lstm = localtime (&ltm));
4199 gtm = mktime (gmtime (&gtm));
4200 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4201 time_rec.tm_isdst = lstm->tm_isdst;
4202 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4204 #endif
4206 static void
4207 msdos_abort (void)
4209 dos_ttcooked ();
4210 ScreenSetCursor (10, 0);
4211 cputs ("\r\n\nEmacs aborted!\r\n");
4212 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4213 if (screen_virtual_segment)
4214 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4215 /* Generate traceback, so we could tell whodunit. */
4216 signal (SIGINT, SIG_DFL);
4217 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4218 #else /* __DJGPP_MINOR__ >= 2 */
4219 raise (SIGABRT);
4220 #endif /* __DJGPP_MINOR__ >= 2 */
4221 exit (2);
4224 void
4225 msdos_fatal_signal (int sig)
4227 if (sig == SIGABRT)
4228 msdos_abort ();
4229 else
4230 raise (sig);
4233 void
4234 syms_of_msdos (void)
4236 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4237 staticpro (&recent_doskeys);
4239 #ifndef HAVE_X_WINDOWS
4241 /* The following two are from xfns.c: */
4242 DEFSYM (Qreverse, "reverse");
4244 DEFVAR_LISP ("dos-unsupported-char-glyph", Vdos_unsupported_char_glyph,
4245 doc: /* Glyph to display instead of chars not supported by current codepage.
4246 This variable is used only by MS-DOS terminals. */);
4247 Vdos_unsupported_char_glyph = make_number ('\177');
4249 #endif
4251 defsubr (&Srecent_doskeys);
4252 defsubr (&Smsdos_long_file_names);
4253 defsubr (&Smsdos_downcase_filename);
4254 defsubr (&Smsdos_remember_default_colors);
4255 defsubr (&Smsdos_set_mouse_buttons);
4258 #endif /* MSDOS */