* doc/emacs/custom.texi (Directory Variables): Fix paren typo.
[emacs.git] / src / msdos.c
blobbce7c065a7e8f2876bd4b045f31b3f2bf9dd7f34
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
3 Copyright (C) 1993-1997, 1999-2013 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_deferred_gc = 0;
1279 hlinfo->mouse_face_mouse_frame = NULL;
1282 unblock_input ();
1285 static void
1286 IT_update_end (struct frame *f)
1288 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1290 if (dpyinfo->termscript)
1291 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1292 dpyinfo->mouse_highlight.mouse_face_defer = 0;
1295 static void
1296 IT_frame_up_to_date (struct frame *f)
1298 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1299 Lisp_Object new_cursor, frame_desired_cursor;
1300 struct window *sw;
1302 if (hlinfo->mouse_face_deferred_gc
1303 || (f && f == hlinfo->mouse_face_mouse_frame))
1305 block_input ();
1306 if (hlinfo->mouse_face_mouse_frame)
1307 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1308 hlinfo->mouse_face_mouse_x,
1309 hlinfo->mouse_face_mouse_y);
1310 hlinfo->mouse_face_deferred_gc = 0;
1311 unblock_input ();
1314 /* Set the cursor type to whatever they wanted. In a minibuffer
1315 window, we want the cursor to appear only if we are reading input
1316 from this window, and we want the cursor to be taken from the
1317 frame parameters. For the selected window, we use either its
1318 buffer-local value or the value from the frame parameters if the
1319 buffer doesn't define its local value for the cursor type. */
1320 sw = XWINDOW (f->selected_window);
1321 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1322 if (cursor_in_echo_area
1323 && FRAME_HAS_MINIBUF_P (f)
1324 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1325 && sw == XWINDOW (echo_area_window))
1326 new_cursor = frame_desired_cursor;
1327 else
1329 struct buffer *b = XBUFFER (sw->buffer);
1331 if (EQ (BVAR (b,cursor_type), Qt))
1332 new_cursor = frame_desired_cursor;
1333 else if (NILP (BVAR (b, cursor_type))) /* nil means no cursor */
1334 new_cursor = Fcons (Qbar, make_number (0));
1335 else
1336 new_cursor = BVAR (b, cursor_type);
1339 IT_set_cursor_type (f, new_cursor);
1341 IT_cmgoto (f); /* position cursor when update is done */
1344 /* Copy LEN glyphs displayed on a single line whose vertical position
1345 is YPOS, beginning at horizontal position XFROM to horizontal
1346 position XTO, by moving blocks in the video memory. Used by
1347 functions that insert and delete glyphs. */
1348 static void
1349 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1351 /* The offsets of source and destination relative to the
1352 conventional memory selector. */
1353 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1354 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1356 if (from == to || len <= 0)
1357 return;
1359 _farsetsel (_dos_ds);
1361 /* The source and destination might overlap, so we need to move
1362 glyphs non-destructively. */
1363 if (from > to)
1365 for ( ; len; from += 2, to += 2, len--)
1366 _farnspokew (to, _farnspeekw (from));
1368 else
1370 from += (len - 1) * 2;
1371 to += (len - 1) * 2;
1372 for ( ; len; from -= 2, to -= 2, len--)
1373 _farnspokew (to, _farnspeekw (from));
1375 if (screen_virtual_segment)
1376 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1379 /* Insert and delete glyphs. */
1380 static void
1381 IT_insert_glyphs (struct frame *f, struct glyph *start, int len)
1383 int shift_by_width = screen_size_X - (new_pos_X + len);
1385 /* Shift right the glyphs from the nominal cursor position to the
1386 end of this line. */
1387 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1389 /* Now write the glyphs to be inserted. */
1390 IT_write_glyphs (f, start, len);
1393 static void
1394 IT_delete_glyphs (struct frame *f, int n)
1396 emacs_abort ();
1399 /* set-window-configuration on window.c needs this. */
1400 void
1401 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1403 set_menu_bar_lines (f, value, oldval);
1406 /* This was copied from xfaces.c */
1408 extern Lisp_Object Qbackground_color;
1409 extern Lisp_Object Qforeground_color;
1410 Lisp_Object Qreverse;
1411 extern Lisp_Object Qtitle;
1413 /* IT_set_terminal_modes is called when emacs is started,
1414 resumed, and whenever the screen is redrawn! */
1416 static void
1417 IT_set_terminal_modes (struct terminal *term)
1419 struct tty_display_info *tty;
1421 /* If called with initial terminal, it's too early to do anything
1422 useful. */
1423 if (term->type == output_initial)
1424 return;
1426 tty = term->display_info.tty;
1428 if (tty->termscript)
1429 fprintf (tty->termscript, "\n<SET_TERM>");
1431 screen_size_X = ScreenCols ();
1432 screen_size_Y = ScreenRows ();
1433 screen_size = screen_size_X * screen_size_Y;
1435 new_pos_X = new_pos_Y = 0;
1436 current_pos_X = current_pos_Y = -1;
1438 if (term_setup_done)
1439 return;
1440 term_setup_done = 1;
1442 startup_screen_size_X = screen_size_X;
1443 startup_screen_size_Y = screen_size_Y;
1444 startup_screen_attrib = ScreenAttrib;
1446 /* Is DOS/V (or any other RSIS software which relocates
1447 the screen) installed? */
1449 unsigned short es_value;
1450 __dpmi_regs regs;
1452 regs.h.ah = 0xfe; /* get relocated screen address */
1453 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1454 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1455 else if (screen_old_address) /* already switched to Japanese mode once */
1456 regs.x.es = (screen_old_address >> 4) & 0xffff;
1457 else
1458 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1459 regs.x.di = 0;
1460 es_value = regs.x.es;
1461 __dpmi_int (0x10, &regs);
1463 if (regs.x.es != es_value)
1465 /* screen_old_address is only set if ScreenPrimary does NOT
1466 already point to the relocated buffer address returned by
1467 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1468 ScreenPrimary to that address at startup under DOS/V. */
1469 if (regs.x.es != ((ScreenPrimary >> 4) & 0xffff))
1470 screen_old_address = ScreenPrimary;
1471 screen_virtual_segment = regs.x.es;
1472 screen_virtual_offset = regs.x.di;
1473 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1477 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1478 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1480 bright_bg ();
1483 /* IT_reset_terminal_modes is called when emacs is
1484 suspended or killed. */
1486 static void
1487 IT_reset_terminal_modes (struct terminal *term)
1489 int display_row_start = (int) ScreenPrimary;
1490 int saved_row_len = startup_screen_size_X * 2;
1491 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1492 int to_next_row = update_row_len;
1493 unsigned char *saved_row = startup_screen_buffer;
1494 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1495 struct tty_display_info *tty = term->display_info.tty;
1497 if (tty->termscript)
1498 fprintf (tty->termscript, "\n<RESET_TERM>");
1500 if (!term_setup_done)
1501 return;
1503 mouse_off ();
1505 /* Leave the video system in the same state as we found it,
1506 as far as the blink/bright-background bit is concerned. */
1507 maybe_enable_blinking ();
1509 /* We have a situation here.
1510 We cannot just do ScreenUpdate(startup_screen_buffer) because
1511 the luser could have changed screen dimensions inside Emacs
1512 and failed (or didn't want) to restore them before killing
1513 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1514 thus will happily use memory outside what was allocated for
1515 `startup_screen_buffer'.
1516 Thus we only restore as much as the current screen dimensions
1517 can hold, and clear the rest (if the saved screen is smaller than
1518 the current) with the color attribute saved at startup. The cursor
1519 is also restored within the visible dimensions. */
1521 ScreenAttrib = startup_screen_attrib;
1523 /* Don't restore the screen if we are exiting less than 2 seconds
1524 after startup: we might be crashing, and the screen might show
1525 some vital clues to what's wrong. */
1526 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1528 ScreenClear ();
1529 if (screen_virtual_segment)
1530 dosv_refresh_virtual_screen (0, screen_size);
1532 if (update_row_len > saved_row_len)
1533 update_row_len = saved_row_len;
1534 if (current_rows > startup_screen_size_Y)
1535 current_rows = startup_screen_size_Y;
1537 if (tty->termscript)
1538 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1539 update_row_len / 2, current_rows);
1541 while (current_rows--)
1543 dosmemput (saved_row, update_row_len, display_row_start);
1544 if (screen_virtual_segment)
1545 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1546 update_row_len / 2);
1547 saved_row += saved_row_len;
1548 display_row_start += to_next_row;
1551 if (startup_pos_X < cursor_pos_X)
1552 cursor_pos_X = startup_pos_X;
1553 if (startup_pos_Y < cursor_pos_Y)
1554 cursor_pos_Y = startup_pos_Y;
1556 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1557 xfree (startup_screen_buffer);
1558 startup_screen_buffer = NULL;
1560 term_setup_done = 0;
1563 static void
1564 IT_set_terminal_window (struct frame *f, int foo)
1568 /* Remember the screen colors of the current frame, to serve as the
1569 default colors for newly-created frames. */
1570 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1571 Smsdos_remember_default_colors, 1, 1, 0,
1572 doc: /* Remember the screen colors of the current frame. */)
1573 (Lisp_Object frame)
1575 struct frame *f;
1577 CHECK_FRAME (frame);
1578 f = XFRAME (frame);
1580 /* This function is called after applying default-frame-alist to the
1581 initial frame. At that time, if reverse-colors option was
1582 specified in default-frame-alist, it was already applied, and
1583 frame colors are reversed. */
1584 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
1585 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
1587 return Qnil;
1590 void
1591 IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
1593 Lisp_Object tail;
1594 int i, j, length = XINT (Flength (alist));
1595 Lisp_Object *parms
1596 = (Lisp_Object *) alloca (length * word_size);
1597 Lisp_Object *values
1598 = (Lisp_Object *) alloca (length * word_size);
1599 /* Do we have to reverse the foreground and background colors? */
1600 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
1601 int redraw = 0, fg_set = 0, bg_set = 0;
1602 unsigned long orig_fg, orig_bg;
1603 struct tty_display_info *tty = FRAME_TTY (f);
1605 /* If we are creating a new frame, begin with the original screen colors
1606 used for the initial frame. */
1607 if (!f->default_face_done_p
1608 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1610 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1611 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
1612 init_frame_faces (f);
1613 f->default_face_done_p = 1;
1615 orig_fg = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1616 orig_bg = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
1618 /* Extract parm names and values into those vectors. */
1619 i = 0;
1620 for (tail = alist; CONSP (tail); tail = XCDR (tail))
1622 Lisp_Object elt = XCAR (tail);
1623 parms[i] = Fcar (elt);
1624 CHECK_SYMBOL (parms[i]);
1625 values[i] = Fcdr (elt);
1626 i++;
1629 j = i;
1631 for (i = 0; i < j; i++)
1633 Lisp_Object prop, val;
1635 prop = parms[i];
1636 val = values[i];
1638 if (EQ (prop, Qreverse))
1639 reverse = EQ (val, Qt);
1642 if (tty->termscript && reverse)
1643 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
1645 /* Now process the alist elements in reverse of specified order. */
1646 for (i--; i >= 0; i--)
1648 Lisp_Object prop, val;
1650 prop = parms[i];
1651 val = values[i];
1653 if (EQ (prop, Qforeground_color))
1655 unsigned long new_color = load_color (f, NULL, val, reverse
1656 ? LFACE_BACKGROUND_INDEX
1657 : LFACE_FOREGROUND_INDEX);
1658 if (new_color != FACE_TTY_DEFAULT_COLOR
1659 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1660 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1662 if (!reverse)
1664 FRAME_FOREGROUND_PIXEL (f) = new_color;
1665 /* Make sure the foreground of the default face for
1666 this frame is changed as well. */
1667 update_face_from_frame_parameter (f, Qforeground_color, val);
1668 fg_set = 1;
1669 if (tty->termscript)
1670 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1672 else
1674 FRAME_BACKGROUND_PIXEL (f) = new_color;
1675 update_face_from_frame_parameter (f, Qbackground_color, val);
1676 bg_set = 1;
1677 if (tty->termscript)
1678 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1680 redraw = 1;
1683 else if (EQ (prop, Qbackground_color))
1685 unsigned long new_color = load_color (f, NULL, val, reverse
1686 ? LFACE_FOREGROUND_INDEX
1687 : LFACE_BACKGROUND_INDEX);
1688 if (new_color != FACE_TTY_DEFAULT_COLOR
1689 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1690 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1692 if (!reverse)
1694 FRAME_BACKGROUND_PIXEL (f) = new_color;
1695 /* Make sure the background of the default face for
1696 this frame is changed as well. */
1697 bg_set = 1;
1698 update_face_from_frame_parameter (f, Qbackground_color, val);
1699 if (tty->termscript)
1700 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1702 else
1704 FRAME_FOREGROUND_PIXEL (f) = new_color;
1705 fg_set = 1;
1706 update_face_from_frame_parameter (f, Qforeground_color, val);
1707 if (tty->termscript)
1708 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1710 redraw = 1;
1713 else if (EQ (prop, Qtitle))
1715 x_set_title (f, val);
1716 if (tty->termscript)
1717 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
1719 else if (EQ (prop, Qcursor_type))
1721 IT_set_cursor_type (f, val);
1722 if (tty->termscript)
1723 fprintf (tty->termscript, "<CTYPE: %s>\n",
1724 EQ (val, Qbar)
1725 || EQ (val, Qhbar)
1726 || (CONSP (val) && (EQ (XCAR (val), Qbar)
1727 || EQ (XCAR (val), Qhbar)))
1728 ? "bar" : "box");
1730 else if (EQ (prop, Qtty_type))
1732 internal_terminal_init ();
1733 if (tty->termscript)
1734 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1735 SBYTES (val), SDATA (val));
1737 store_frame_param (f, prop, val);
1740 /* If they specified "reverse", but not the colors, we need to swap
1741 the current frame colors. */
1742 if (reverse)
1744 if (!fg_set)
1746 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1747 update_face_from_frame_parameter (f, Qforeground_color,
1748 tty_color_name (f, orig_bg));
1749 redraw = 1;
1751 if (!bg_set)
1753 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1754 update_face_from_frame_parameter (f, Qbackground_color,
1755 tty_color_name (f, orig_fg));
1756 redraw = 1;
1760 if (redraw)
1762 face_change_count++; /* forces xdisp.c to recompute basic faces */
1763 if (f == SELECTED_FRAME ())
1764 redraw_frame (f);
1768 extern void init_frame_faces (FRAME_PTR);
1770 #endif /* !HAVE_X_WINDOWS */
1773 /* Do we need the internal terminal? */
1775 void
1776 internal_terminal_init (void)
1778 static int init_needed = 1;
1779 char *term = getenv ("TERM"), *colors;
1780 struct frame *sf = SELECTED_FRAME ();
1781 struct tty_display_info *tty;
1783 #ifdef HAVE_X_WINDOWS
1784 if (!inhibit_window_system)
1785 return;
1786 #endif
1788 /* If this is the initial terminal, we are done here. */
1789 if (sf->output_method == output_initial)
1790 return;
1792 internal_terminal
1793 = (!noninteractive) && term && !strcmp (term, "internal");
1795 #ifndef HAVE_X_WINDOWS
1796 if (!internal_terminal || inhibit_window_system)
1798 sf->output_method = output_termcap;
1799 return;
1802 tty = FRAME_TTY (sf);
1803 kset_window_system (current_kboard, Qpc);
1804 sf->output_method = output_msdos_raw;
1805 if (init_needed)
1807 if (!tty->termscript && getenv ("EMACSTEST"))
1808 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
1809 if (tty->termscript)
1811 time_t now = time (NULL);
1812 struct tm *tnow = localtime (&now);
1813 char tbuf[100];
1815 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
1816 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
1817 fprintf (tty->termscript, "=====================\n\n");
1820 Vinitial_window_system = Qpc;
1821 Vwindow_system_version = make_number (24); /* RE Emacs version */
1822 tty->terminal->type = output_msdos_raw;
1824 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1825 address. */
1826 screen_old_address = 0;
1828 /* Forget the stale screen colors as well. */
1829 initial_screen_colors[0] = initial_screen_colors[1] = -1;
1831 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1832 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1833 bright_bg ();
1834 colors = getenv ("EMACSCOLORS");
1835 if (colors && strlen (colors) >= 2)
1837 /* The colors use 4 bits each (we enable bright background). */
1838 if (isdigit (colors[0]))
1839 colors[0] -= '0';
1840 else if (isxdigit (colors[0]))
1841 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1842 if (colors[0] >= 0 && colors[0] < 16)
1843 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
1844 if (isdigit (colors[1]))
1845 colors[1] -= '0';
1846 else if (isxdigit (colors[1]))
1847 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1848 if (colors[1] >= 0 && colors[1] < 16)
1849 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
1851 the_only_display_info.mouse_highlight.mouse_face_mouse_frame = NULL;
1852 the_only_display_info.mouse_highlight.mouse_face_deferred_gc = 0;
1853 the_only_display_info.mouse_highlight.mouse_face_beg_row =
1854 the_only_display_info.mouse_highlight.mouse_face_beg_col = -1;
1855 the_only_display_info.mouse_highlight.mouse_face_end_row =
1856 the_only_display_info.mouse_highlight.mouse_face_end_col = -1;
1857 the_only_display_info.mouse_highlight.mouse_face_face_id = DEFAULT_FACE_ID;
1858 the_only_display_info.mouse_highlight.mouse_face_window = Qnil;
1859 the_only_display_info.mouse_highlight.mouse_face_mouse_x =
1860 the_only_display_info.mouse_highlight.mouse_face_mouse_y = 0;
1861 the_only_display_info.mouse_highlight.mouse_face_defer = 0;
1862 the_only_display_info.mouse_highlight.mouse_face_hidden = 0;
1864 if (have_mouse) /* detected in dos_ttraw, which see */
1866 have_mouse = 1; /* enable mouse */
1867 mouse_visible = 0;
1868 mouse_setup_buttons (mouse_button_count);
1869 tty->terminal->mouse_position_hook = &mouse_get_pos;
1870 mouse_init ();
1873 if (tty->termscript && screen_size)
1874 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1875 screen_size_X, screen_size_Y);
1877 init_frame_faces (sf);
1878 init_needed = 0;
1880 #endif
1883 void
1884 initialize_msdos_display (struct terminal *term)
1886 term->rif = 0; /* we don't support window-based display */
1887 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
1888 term->clear_to_end_hook = IT_clear_to_end;
1889 term->clear_frame_hook = IT_clear_screen;
1890 term->clear_end_of_line_hook = IT_clear_end_of_line;
1891 term->ins_del_lines_hook = 0;
1892 term->insert_glyphs_hook = IT_insert_glyphs;
1893 term->write_glyphs_hook = IT_write_glyphs;
1894 term->delete_glyphs_hook = IT_delete_glyphs;
1895 term->ring_bell_hook = IT_ring_bell;
1896 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
1897 term->set_terminal_modes_hook = IT_set_terminal_modes;
1898 term->set_terminal_window_hook = IT_set_terminal_window;
1899 term->update_begin_hook = IT_update_begin;
1900 term->update_end_hook = IT_update_end;
1901 term->frame_up_to_date_hook = IT_frame_up_to_date;
1902 term->mouse_position_hook = 0; /* set later by dos_ttraw */
1903 term->frame_rehighlight_hook = 0;
1904 term->frame_raise_lower_hook = 0;
1905 term->set_vertical_scroll_bar_hook = 0;
1906 term->condemn_scroll_bars_hook = 0;
1907 term->redeem_scroll_bar_hook = 0;
1908 term->judge_scroll_bars_hook = 0;
1909 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
1913 dos_get_saved_screen (char **screen, int *rows, int *cols)
1915 #ifndef HAVE_X_WINDOWS
1916 *screen = startup_screen_buffer;
1917 *cols = startup_screen_size_X;
1918 *rows = startup_screen_size_Y;
1919 return *screen != (char *)0;
1920 #else
1921 return 0;
1922 #endif
1925 #ifndef HAVE_X_WINDOWS
1927 /* We are not X, but we can emulate it well enough for our needs... */
1928 void
1929 check_x (void)
1931 if (! FRAME_MSDOS_P (SELECTED_FRAME ()))
1932 error ("Not running under a window system");
1935 #endif
1938 /* ----------------------- Keyboard control ----------------------
1940 * Keymaps reflect the following keyboard layout:
1942 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1943 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1944 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1945 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1946 * SPACE
1949 #define Ignore 0x0000
1950 #define Normal 0x0000 /* normal key - alt changes scan-code */
1951 #define FctKey 0x1000 /* func key if c == 0, else c */
1952 #define Special 0x2000 /* func key even if c != 0 */
1953 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1954 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1955 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1956 #define Grey 0x6000 /* Grey keypad key */
1958 #define Alt 0x0100 /* alt scan-code */
1959 #define Ctrl 0x0200 /* ctrl scan-code */
1960 #define Shift 0x0400 /* shift scan-code */
1962 static int extended_kbd; /* 101 (102) keyboard present. */
1964 struct kbd_translate {
1965 unsigned char sc;
1966 unsigned char ch;
1967 unsigned short code;
1970 struct dos_keyboard_map
1972 char *unshifted;
1973 char *shifted;
1974 char *alt_gr;
1975 struct kbd_translate *translate_table;
1979 static struct dos_keyboard_map us_keyboard = {
1980 /* 0 1 2 3 4 5 */
1981 /* 01234567890123456789012345678901234567890 12345678901234 */
1982 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1983 /* 0123456789012345678901234567890123456789 012345678901234 */
1984 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1985 0, /* no Alt-Gr key */
1986 0 /* no translate table */
1989 static struct dos_keyboard_map fr_keyboard = {
1990 /* 0 1 2 3 4 5 */
1991 /* 012 3456789012345678901234567890123456789012345678901234 */
1992 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1993 /* 0123456789012345678901234567890123456789012345678901234 */
1994 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1995 /* 01234567 89012345678901234567890123456789012345678901234 */
1996 " ~#{[|`\\^@]} Ï ",
1997 0 /* no translate table */
2001 * Italian keyboard support, country code 39.
2002 * '<' 56:3c*0000
2003 * '>' 56:3e*0000
2004 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2005 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2008 static struct kbd_translate it_kbd_translate_table[] = {
2009 { 0x56, 0x3c, Normal | 13 },
2010 { 0x56, 0x3e, Normal | 27 },
2011 { 0, 0, 0 }
2013 static struct dos_keyboard_map it_keyboard = {
2014 /* 0 1 2 3 4 5 */
2015 /* 0 123456789012345678901234567890123456789012345678901234 */
2016 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2017 /* 01 23456789012345678901234567890123456789012345678901234 */
2018 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2019 /* 0123456789012345678901234567890123456789012345678901234 */
2020 " {}~` [] @# ",
2021 it_kbd_translate_table
2024 static struct dos_keyboard_map dk_keyboard = {
2025 /* 0 1 2 3 4 5 */
2026 /* 0123456789012345678901234567890123456789012345678901234 */
2027 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2028 /* 01 23456789012345678901234567890123456789012345678901234 */
2029 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2030 /* 0123456789012345678901234567890123456789012345678901234 */
2031 " @œ$ {[]} | ",
2032 0 /* no translate table */
2035 static struct kbd_translate jp_kbd_translate_table[] = {
2036 { 0x73, 0x5c, Normal | 0 },
2037 { 0x73, 0x5f, Normal | 0 },
2038 { 0x73, 0x1c, Map | 0 },
2039 { 0x7d, 0x5c, Normal | 13 },
2040 { 0x7d, 0x7c, Normal | 13 },
2041 { 0x7d, 0x1c, Map | 13 },
2042 { 0, 0, 0 }
2044 static struct dos_keyboard_map jp_keyboard = {
2045 /* 0 1 2 3 4 5 */
2046 /* 0123456789012 345678901234567890123456789012345678901234 */
2047 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2048 /* 01 23456789012345678901234567890123456789012345678901234 */
2049 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2050 0, /* no Alt-Gr key */
2051 jp_kbd_translate_table
2054 static struct keyboard_layout_list
2056 int country_code;
2057 struct dos_keyboard_map *keyboard_map;
2058 } keyboard_layout_list[] =
2060 { 1, &us_keyboard },
2061 { 33, &fr_keyboard },
2062 { 39, &it_keyboard },
2063 { 45, &dk_keyboard },
2064 { 81, &jp_keyboard }
2067 static struct dos_keyboard_map *keyboard;
2068 static int keyboard_map_all;
2069 static int international_keyboard;
2072 dos_set_keyboard (int code, int always)
2074 int i;
2075 _go32_dpmi_registers regs;
2077 /* See if Keyb.Com is installed (for international keyboard support).
2078 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2079 of Windows 9X! So don't do that! */
2080 regs.x.ax = 0xad80;
2081 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2082 _go32_dpmi_simulate_int (0x2f, &regs);
2083 if (regs.h.al == 0xff)
2084 international_keyboard = 1;
2086 /* Initialize to US settings, for countries that don't have their own. */
2087 keyboard = keyboard_layout_list[0].keyboard_map;
2088 keyboard_map_all = always;
2089 dos_keyboard_layout = 1;
2091 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2092 if (code == keyboard_layout_list[i].country_code)
2094 keyboard = keyboard_layout_list[i].keyboard_map;
2095 keyboard_map_all = always;
2096 dos_keyboard_layout = code;
2097 return 1;
2099 return 0;
2102 static struct
2104 unsigned char char_code; /* normal code */
2105 unsigned char meta_code; /* M- code */
2106 unsigned char keypad_code; /* keypad code */
2107 unsigned char editkey_code; /* edit key */
2108 } keypad_translate_map[] = {
2109 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2110 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2111 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2112 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2113 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2114 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2115 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2116 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2117 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2118 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2119 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2122 static struct
2124 unsigned char char_code; /* normal code */
2125 unsigned char keypad_code; /* keypad code */
2126 } grey_key_translate_map[] = {
2127 { '/', 0xaf /* kp-decimal */ },
2128 { '*', 0xaa /* kp-multiply */ },
2129 { '-', 0xad /* kp-subtract */ },
2130 { '+', 0xab /* kp-add */ },
2131 { '\r', 0x8d /* kp-enter */ }
2134 static unsigned short
2135 ibmpc_translate_map[] =
2137 /* --------------- 00 to 0f --------------- */
2138 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2139 Alt | ModFct | 0x1b, /* Escape */
2140 Normal | 1, /* '1' */
2141 Normal | 2, /* '2' */
2142 Normal | 3, /* '3' */
2143 Normal | 4, /* '4' */
2144 Normal | 5, /* '5' */
2145 Normal | 6, /* '6' */
2146 Normal | 7, /* '7' */
2147 Normal | 8, /* '8' */
2148 Normal | 9, /* '9' */
2149 Normal | 10, /* '0' */
2150 Normal | 11, /* '-' */
2151 Normal | 12, /* '=' */
2152 Special | 0x08, /* Backspace */
2153 ModFct | 0x74, /* Tab/Backtab */
2155 /* --------------- 10 to 1f --------------- */
2156 Map | 15, /* 'q' */
2157 Map | 16, /* 'w' */
2158 Map | 17, /* 'e' */
2159 Map | 18, /* 'r' */
2160 Map | 19, /* 't' */
2161 Map | 20, /* 'y' */
2162 Map | 21, /* 'u' */
2163 Map | 22, /* 'i' */
2164 Map | 23, /* 'o' */
2165 Map | 24, /* 'p' */
2166 Map | 25, /* '[' */
2167 Map | 26, /* ']' */
2168 ModFct | 0x0d, /* Return */
2169 Ignore, /* Ctrl */
2170 Map | 30, /* 'a' */
2171 Map | 31, /* 's' */
2173 /* --------------- 20 to 2f --------------- */
2174 Map | 32, /* 'd' */
2175 Map | 33, /* 'f' */
2176 Map | 34, /* 'g' */
2177 Map | 35, /* 'h' */
2178 Map | 36, /* 'j' */
2179 Map | 37, /* 'k' */
2180 Map | 38, /* 'l' */
2181 Map | 39, /* ';' */
2182 Map | 40, /* '\'' */
2183 Map | 0, /* '`' */
2184 Ignore, /* Left shift */
2185 Map | 41, /* '\\' */
2186 Map | 45, /* 'z' */
2187 Map | 46, /* 'x' */
2188 Map | 47, /* 'c' */
2189 Map | 48, /* 'v' */
2191 /* --------------- 30 to 3f --------------- */
2192 Map | 49, /* 'b' */
2193 Map | 50, /* 'n' */
2194 Map | 51, /* 'm' */
2195 Map | 52, /* ',' */
2196 Map | 53, /* '.' */
2197 Map | 54, /* '/' */
2198 Ignore, /* Right shift */
2199 Grey | 1, /* Grey * */
2200 Ignore, /* Alt */
2201 Normal | 55, /* ' ' */
2202 Ignore, /* Caps Lock */
2203 FctKey | 0xbe, /* F1 */
2204 FctKey | 0xbf, /* F2 */
2205 FctKey | 0xc0, /* F3 */
2206 FctKey | 0xc1, /* F4 */
2207 FctKey | 0xc2, /* F5 */
2209 /* --------------- 40 to 4f --------------- */
2210 FctKey | 0xc3, /* F6 */
2211 FctKey | 0xc4, /* F7 */
2212 FctKey | 0xc5, /* F8 */
2213 FctKey | 0xc6, /* F9 */
2214 FctKey | 0xc7, /* F10 */
2215 Ignore, /* Num Lock */
2216 Ignore, /* Scroll Lock */
2217 KeyPad | 7, /* Home */
2218 KeyPad | 8, /* Up */
2219 KeyPad | 9, /* Page Up */
2220 Grey | 2, /* Grey - */
2221 KeyPad | 4, /* Left */
2222 KeyPad | 5, /* Keypad 5 */
2223 KeyPad | 6, /* Right */
2224 Grey | 3, /* Grey + */
2225 KeyPad | 1, /* End */
2227 /* --------------- 50 to 5f --------------- */
2228 KeyPad | 2, /* Down */
2229 KeyPad | 3, /* Page Down */
2230 KeyPad | 0, /* Insert */
2231 KeyPad | 10, /* Delete */
2232 Shift | FctKey | 0xbe, /* (Shift) F1 */
2233 Shift | FctKey | 0xbf, /* (Shift) F2 */
2234 Shift | FctKey | 0xc0, /* (Shift) F3 */
2235 Shift | FctKey | 0xc1, /* (Shift) F4 */
2236 Shift | FctKey | 0xc2, /* (Shift) F5 */
2237 Shift | FctKey | 0xc3, /* (Shift) F6 */
2238 Shift | FctKey | 0xc4, /* (Shift) F7 */
2239 Shift | FctKey | 0xc5, /* (Shift) F8 */
2240 Shift | FctKey | 0xc6, /* (Shift) F9 */
2241 Shift | FctKey | 0xc7, /* (Shift) F10 */
2242 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2243 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2245 /* --------------- 60 to 6f --------------- */
2246 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2247 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2248 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2249 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2250 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2251 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2252 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2253 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2254 Alt | FctKey | 0xbe, /* (Alt) F1 */
2255 Alt | FctKey | 0xbf, /* (Alt) F2 */
2256 Alt | FctKey | 0xc0, /* (Alt) F3 */
2257 Alt | FctKey | 0xc1, /* (Alt) F4 */
2258 Alt | FctKey | 0xc2, /* (Alt) F5 */
2259 Alt | FctKey | 0xc3, /* (Alt) F6 */
2260 Alt | FctKey | 0xc4, /* (Alt) F7 */
2261 Alt | FctKey | 0xc5, /* (Alt) F8 */
2263 /* --------------- 70 to 7f --------------- */
2264 Alt | FctKey | 0xc6, /* (Alt) F9 */
2265 Alt | FctKey | 0xc7, /* (Alt) F10 */
2266 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2267 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2268 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2269 Ctrl | KeyPad | 1, /* (Ctrl) End */
2270 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2271 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2272 Alt | Map | 1, /* '1' */
2273 Alt | Map | 2, /* '2' */
2274 Alt | Map | 3, /* '3' */
2275 Alt | Map | 4, /* '4' */
2276 Alt | Map | 5, /* '5' */
2277 Alt | Map | 6, /* '6' */
2278 Alt | Map | 7, /* '7' */
2279 Alt | Map | 8, /* '8' */
2281 /* --------------- 80 to 8f --------------- */
2282 Alt | Map | 9, /* '9' */
2283 Alt | Map | 10, /* '0' */
2284 Alt | Map | 11, /* '-' */
2285 Alt | Map | 12, /* '=' */
2286 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2287 FctKey | 0xc8, /* F11 */
2288 FctKey | 0xc9, /* F12 */
2289 Shift | FctKey | 0xc8, /* (Shift) F11 */
2290 Shift | FctKey | 0xc9, /* (Shift) F12 */
2291 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2292 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2293 Alt | FctKey | 0xc8, /* (Alt) F11 */
2294 Alt | FctKey | 0xc9, /* (Alt) F12 */
2295 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2296 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2297 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2299 /* --------------- 90 to 9f --------------- */
2300 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2301 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2302 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2303 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2304 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2305 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2306 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2307 Alt | FctKey | 0x50, /* (Alt) Home */
2308 Alt | FctKey | 0x52, /* (Alt) Up */
2309 Alt | FctKey | 0x55, /* (Alt) Page Up */
2310 Ignore, /* NO KEY */
2311 Alt | FctKey | 0x51, /* (Alt) Left */
2312 Ignore, /* NO KEY */
2313 Alt | FctKey | 0x53, /* (Alt) Right */
2314 Ignore, /* NO KEY */
2315 Alt | FctKey | 0x57, /* (Alt) End */
2317 /* --------------- a0 to af --------------- */
2318 Alt | KeyPad | 2, /* (Alt) Down */
2319 Alt | KeyPad | 3, /* (Alt) Page Down */
2320 Alt | KeyPad | 0, /* (Alt) Insert */
2321 Alt | KeyPad | 10, /* (Alt) Delete */
2322 Alt | Grey | 0, /* (Alt) Grey / */
2323 Alt | FctKey | 0x09, /* (Alt) Tab */
2324 Alt | Grey | 4 /* (Alt) Keypad Enter */
2327 /* These bit-positions corresponds to values returned by BIOS */
2328 #define SHIFT_P 0x0003 /* two bits! */
2329 #define CTRL_P 0x0004
2330 #define ALT_P 0x0008
2331 #define SCRLOCK_P 0x0010
2332 #define NUMLOCK_P 0x0020
2333 #define CAPSLOCK_P 0x0040
2334 #define ALT_GR_P 0x0800
2335 #define SUPER_P 0x4000 /* pseudo */
2336 #define HYPER_P 0x8000 /* pseudo */
2338 static int
2339 dos_get_modifiers (int *keymask)
2341 union REGS regs;
2342 int mask, modifiers = 0;
2344 /* Calculate modifier bits */
2345 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2346 int86 (0x16, &regs, &regs);
2348 if (!extended_kbd)
2350 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2351 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2353 else
2355 mask = regs.h.al & (SHIFT_P |
2356 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2358 /* Do not break international keyboard support. */
2359 /* When Keyb.Com is loaded, the right Alt key is */
2360 /* used for accessing characters like { and } */
2361 if (regs.h.ah & 2) /* Left ALT pressed ? */
2362 mask |= ALT_P;
2364 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2366 mask |= ALT_GR_P;
2367 if (dos_hyper_key == 1)
2369 mask |= HYPER_P;
2370 modifiers |= hyper_modifier;
2372 else if (dos_super_key == 1)
2374 mask |= SUPER_P;
2375 modifiers |= super_modifier;
2377 else if (!international_keyboard)
2379 /* If Keyb.Com is NOT installed, let Right Alt behave
2380 like the Left Alt. */
2381 mask &= ~ALT_GR_P;
2382 mask |= ALT_P;
2386 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2387 mask |= CTRL_P;
2389 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2391 if (dos_hyper_key == 2)
2393 mask |= HYPER_P;
2394 modifiers |= hyper_modifier;
2396 else if (dos_super_key == 2)
2398 mask |= SUPER_P;
2399 modifiers |= super_modifier;
2401 else
2402 mask |= CTRL_P;
2406 if (mask & SHIFT_P)
2407 modifiers |= shift_modifier;
2408 if (mask & CTRL_P)
2409 modifiers |= ctrl_modifier;
2410 if (mask & ALT_P)
2411 modifiers |= meta_modifier;
2413 if (keymask)
2414 *keymask = mask;
2415 return modifiers;
2418 #define NUM_RECENT_DOSKEYS (100)
2419 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2420 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2421 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2423 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2424 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2425 Each input key receives two values in this vector: first the ASCII code,
2426 and then the scan code. */)
2427 (void)
2429 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2431 if (total_doskeys < NUM_RECENT_DOSKEYS)
2432 return Fvector (total_doskeys, keys);
2433 else
2435 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2436 vcopy (val, 0, keys + recent_doskeys_index,
2437 NUM_RECENT_DOSKEYS - recent_doskeys_index);
2438 vcopy (val, NUM_RECENT_DOSKEYS - recent_doskeys_index,
2439 keys, recent_doskeys_index);
2440 return val;
2444 /* Get a char from keyboard. Function keys are put into the event queue. */
2445 static int
2446 dos_rawgetc (void)
2448 struct input_event event;
2449 union REGS regs;
2450 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (SELECTED_FRAME ());
2451 EVENT_INIT (event);
2453 #ifndef HAVE_X_WINDOWS
2454 /* Maybe put the cursor where it should be. */
2455 IT_cmgoto (SELECTED_FRAME ());
2456 #endif
2458 /* The following condition is equivalent to `kbhit ()', except that
2459 it uses the bios to do its job. This pleases DESQview/X. */
2460 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2461 int86 (0x16, &regs, &regs),
2462 (regs.x.flags & 0x40) == 0)
2464 union REGS regs;
2465 register unsigned char c;
2466 int modifiers, sc, code = -1, mask, kp_mode;
2468 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2469 int86 (0x16, &regs, &regs);
2470 c = regs.h.al;
2471 sc = regs.h.ah;
2473 total_doskeys += 2;
2474 ASET (recent_doskeys, recent_doskeys_index, make_number (c));
2475 recent_doskeys_index++;
2476 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2477 recent_doskeys_index = 0;
2478 ASET (recent_doskeys, recent_doskeys_index, make_number (sc));
2479 recent_doskeys_index++;
2480 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2481 recent_doskeys_index = 0;
2483 modifiers = dos_get_modifiers (&mask);
2485 #ifndef HAVE_X_WINDOWS
2486 if (!NILP (Vdos_display_scancodes))
2488 char buf[11];
2489 sprintf (buf, "%02x:%02x*%04x",
2490 (unsigned) (sc&0xff), (unsigned) c, mask);
2491 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2493 #endif
2495 if (sc == 0xe0)
2497 switch (c)
2499 case 10: /* Ctrl Grey Enter */
2500 code = Ctrl | Grey | 4;
2501 break;
2502 case 13: /* Grey Enter */
2503 code = Grey | 4;
2504 break;
2505 case '/': /* Grey / */
2506 code = Grey | 0;
2507 break;
2508 default:
2509 continue;
2511 c = 0;
2513 else
2515 /* Try the keyboard-private translation table first. */
2516 if (keyboard->translate_table)
2518 struct kbd_translate *p = keyboard->translate_table;
2520 while (p->sc)
2522 if (p->sc == sc && p->ch == c)
2524 code = p->code;
2525 break;
2527 p++;
2530 /* If the private table didn't translate it, use the general
2531 one. */
2532 if (code == -1)
2534 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
2535 continue;
2536 if ((code = ibmpc_translate_map[sc]) == Ignore)
2537 continue;
2541 if (c == 0)
2543 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2544 Emacs is ready to read a key. Therefore, if they press
2545 `Alt-x' when Emacs is busy, by the time we get to
2546 `dos_get_modifiers', they might have already released the
2547 Alt key, and Emacs gets just `x', which is BAD.
2548 However, for keys with the `Map' property set, the ASCII
2549 code returns zero only if Alt is pressed. So, when we DON'T
2550 have to support international_keyboard, we don't have to
2551 distinguish between the left and right Alt keys, and we
2552 can set the META modifier for any keys with the `Map'
2553 property if they return zero ASCII code (c = 0). */
2554 if ( (code & Alt)
2555 || ( (code & 0xf000) == Map && !international_keyboard))
2556 modifiers |= meta_modifier;
2557 if (code & Ctrl)
2558 modifiers |= ctrl_modifier;
2559 if (code & Shift)
2560 modifiers |= shift_modifier;
2563 switch (code & 0xf000)
2565 case ModFct:
2566 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
2567 return c;
2568 c = 0; /* Special */
2570 case FctKey:
2571 if (c != 0)
2572 return c;
2574 case Special:
2575 code |= 0xff00;
2576 break;
2578 case Normal:
2579 if (sc == 0)
2581 if (c == 0) /* ctrl-break */
2582 continue;
2583 return c; /* ALT-nnn */
2585 if (!keyboard_map_all)
2587 if (c != ' ')
2588 return c;
2589 code = c;
2590 break;
2593 case Map:
2594 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
2595 if (!keyboard_map_all)
2596 return c;
2598 code &= 0xff;
2599 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
2600 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
2602 if (mask & SHIFT_P)
2604 code = keyboard->shifted[code];
2605 mask -= SHIFT_P;
2606 modifiers &= ~shift_modifier;
2608 else
2609 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
2610 code = keyboard->alt_gr[code];
2611 else
2612 code = keyboard->unshifted[code];
2613 break;
2615 case KeyPad:
2616 code &= 0xff;
2617 if (c == 0xe0) /* edit key */
2618 kp_mode = 3;
2619 else
2620 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
2621 kp_mode = dos_keypad_mode & 0x03;
2622 else
2623 kp_mode = (dos_keypad_mode >> 4) & 0x03;
2625 switch (kp_mode)
2627 case 0:
2628 if (code == 10 && dos_decimal_point)
2629 return dos_decimal_point;
2630 return keypad_translate_map[code].char_code;
2632 case 1:
2633 code = 0xff00 | keypad_translate_map[code].keypad_code;
2634 break;
2636 case 2:
2637 code = keypad_translate_map[code].meta_code;
2638 modifiers = meta_modifier;
2639 break;
2641 case 3:
2642 code = 0xff00 | keypad_translate_map[code].editkey_code;
2643 break;
2645 break;
2647 case Grey:
2648 code &= 0xff;
2649 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
2650 if (dos_keypad_mode & kp_mode)
2651 code = 0xff00 | grey_key_translate_map[code].keypad_code;
2652 else
2653 code = grey_key_translate_map[code].char_code;
2654 break;
2657 if (code == 0)
2658 continue;
2660 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
2662 clear_mouse_face (hlinfo);
2663 hlinfo->mouse_face_hidden = 1;
2666 if (code >= 0x100)
2667 event.kind = NON_ASCII_KEYSTROKE_EVENT;
2668 else
2669 event.kind = ASCII_KEYSTROKE_EVENT;
2670 event.code = code;
2671 event.modifiers = modifiers;
2672 event.frame_or_window = selected_frame;
2673 event.arg = Qnil;
2674 event.timestamp = event_timestamp ();
2675 kbd_buffer_store_event (&event);
2678 if (have_mouse > 0 && !mouse_preempted)
2680 int but, press, x, y, ok;
2681 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
2682 Lisp_Object mouse_window = Qnil;
2684 /* Check for mouse movement *before* buttons. */
2685 mouse_check_moved ();
2687 /* If the mouse moved from the spot of its last sighting, we
2688 might need to update mouse highlight. */
2689 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
2691 if (hlinfo->mouse_face_hidden)
2693 hlinfo->mouse_face_hidden = 0;
2694 clear_mouse_face (hlinfo);
2697 /* Generate SELECT_WINDOW_EVENTs when needed. */
2698 if (!NILP (Vmouse_autoselect_window))
2700 mouse_window = window_from_coordinates (SELECTED_FRAME (),
2701 mouse_last_x,
2702 mouse_last_y,
2703 0, 0);
2704 /* A window will be selected only when it is not
2705 selected now, and the last mouse movement event was
2706 not in it. A minibuffer window will be selected iff
2707 it is active. */
2708 if (WINDOWP (mouse_window)
2709 && !EQ (mouse_window, last_mouse_window)
2710 && !EQ (mouse_window, selected_window))
2712 event.kind = SELECT_WINDOW_EVENT;
2713 event.frame_or_window = mouse_window;
2714 event.arg = Qnil;
2715 event.timestamp = event_timestamp ();
2716 kbd_buffer_store_event (&event);
2718 last_mouse_window = mouse_window;
2720 else
2721 last_mouse_window = Qnil;
2723 previous_help_echo_string = help_echo_string;
2724 help_echo_string = help_echo_object = help_echo_window = Qnil;
2725 help_echo_pos = -1;
2726 note_mouse_highlight (SELECTED_FRAME (), mouse_last_x, mouse_last_y);
2727 /* If the contents of the global variable help_echo has
2728 changed, generate a HELP_EVENT. */
2729 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
2730 gen_help_event (help_echo_string, selected_frame, help_echo_window,
2731 help_echo_object, help_echo_pos);
2734 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
2735 for (press = 0; press < 2; press++)
2737 int button_num = but;
2739 if (press)
2740 ok = mouse_pressed (but, &x, &y);
2741 else
2742 ok = mouse_released (but, &x, &y);
2743 if (ok)
2745 /* Allow a simultaneous press/release of Mouse-1 and
2746 Mouse-2 to simulate Mouse-3 on two-button mice. */
2747 if (mouse_button_count == 2 && but < 2)
2749 int x2, y2; /* don't clobber original coordinates */
2751 /* If only one button is pressed, wait 100 msec and
2752 check again. This way, Speedy Gonzales isn't
2753 punished, while the slow get their chance. */
2754 if ((press && mouse_pressed (1-but, &x2, &y2))
2755 || (!press && mouse_released (1-but, &x2, &y2)))
2756 button_num = 2;
2757 else
2759 delay (100);
2760 if ((press && mouse_pressed (1-but, &x2, &y2))
2761 || (!press && mouse_released (1-but, &x2, &y2)))
2762 button_num = 2;
2766 event.kind = MOUSE_CLICK_EVENT;
2767 event.code = button_num;
2768 event.modifiers = dos_get_modifiers (0)
2769 | (press ? down_modifier : up_modifier);
2770 event.x = make_number (x);
2771 event.y = make_number (y);
2772 event.frame_or_window = selected_frame;
2773 event.arg = Qnil;
2774 event.timestamp = event_timestamp ();
2775 kbd_buffer_store_event (&event);
2780 return -1;
2783 static int prev_get_char = -1;
2785 /* Return 1 if a key is ready to be read without suspending execution. */
2787 dos_keysns (void)
2789 if (prev_get_char != -1)
2790 return 1;
2791 else
2792 return ((prev_get_char = dos_rawgetc ()) != -1);
2795 /* Read a key. Return -1 if no key is ready. */
2797 dos_keyread (void)
2799 if (prev_get_char != -1)
2801 int c = prev_get_char;
2802 prev_get_char = -1;
2803 return c;
2805 else
2806 return dos_rawgetc ();
2809 #ifndef HAVE_X_WINDOWS
2811 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2812 for now.
2814 Actually, I don't know the meaning of all the parameters of the functions
2815 here -- I only know how they are called by xmenu.c. I could of course
2816 grab the nearest Xlib manual (down the hall, second-to-last door on the
2817 left), but I don't think it's worth the effort. */
2819 /* These hold text of the current and the previous menu help messages. */
2820 static const char *menu_help_message, *prev_menu_help_message;
2821 /* Pane number and item number of the menu item which generated the
2822 last menu help message. */
2823 static int menu_help_paneno, menu_help_itemno;
2825 static XMenu *
2826 IT_menu_create (void)
2828 XMenu *menu;
2830 menu = xmalloc (sizeof (XMenu));
2831 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2832 return menu;
2835 /* Allocate some (more) memory for MENU ensuring that there is room for one
2836 for item. */
2838 static void
2839 IT_menu_make_room (XMenu *menu)
2841 if (menu->allocated == 0)
2843 int count = menu->allocated = 10;
2844 menu->text = xmalloc (count * sizeof (char *));
2845 menu->submenu = xmalloc (count * sizeof (XMenu *));
2846 menu->panenumber = xmalloc (count * sizeof (int));
2847 menu->help_text = xmalloc (count * sizeof (char *));
2849 else if (menu->allocated == menu->count)
2851 int count = menu->allocated = menu->allocated + 10;
2852 menu->text
2853 = (char **) xrealloc (menu->text, count * sizeof (char *));
2854 menu->submenu
2855 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2856 menu->panenumber
2857 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2858 menu->help_text
2859 = (const char **) xrealloc (menu->help_text, count * sizeof (char *));
2863 /* Search the given menu structure for a given pane number. */
2865 static XMenu *
2866 IT_menu_search_pane (XMenu *menu, int pane)
2868 int i;
2869 XMenu *try;
2871 for (i = 0; i < menu->count; i++)
2872 if (menu->submenu[i])
2874 if (pane == menu->panenumber[i])
2875 return menu->submenu[i];
2876 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2877 return try;
2879 return (XMenu *) 0;
2882 /* Determine how much screen space a given menu needs. */
2884 static void
2885 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2887 int i, h2, w2, maxsubwidth, maxheight;
2889 maxsubwidth = 0;
2890 maxheight = menu->count;
2891 for (i = 0; i < menu->count; i++)
2893 if (menu->submenu[i])
2895 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2896 if (w2 > maxsubwidth) maxsubwidth = w2;
2897 if (i + h2 > maxheight) maxheight = i + h2;
2900 *width = menu->width + maxsubwidth;
2901 *height = maxheight;
2904 /* Display MENU at (X,Y) using FACES. */
2906 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
2907 do \
2909 (GLYPH).type = CHAR_GLYPH; \
2910 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
2911 (GLYPH).charpos = -1; \
2913 while (0)
2915 static void
2916 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
2918 int i, j, face, width, mx, my, enabled, mousehere, row, col;
2919 struct glyph *text, *p;
2920 const unsigned char *q;
2921 struct frame *sf = SELECTED_FRAME ();
2923 menu_help_message = NULL;
2925 width = menu->width;
2926 /* We multiply width by 2 to account for possible control characters.
2927 FIXME: cater to non-ASCII characters in menus. */
2928 text = xmalloc ((width * 2 + 2) * sizeof (struct glyph));
2929 ScreenGetCursor (&row, &col);
2930 mouse_get_xy (&mx, &my);
2931 IT_update_begin (sf);
2932 for (i = 0; i < menu->count; i++)
2934 int max_width = width + 2;
2936 IT_cursor_to (sf, y + i, x);
2937 enabled
2938 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2939 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2940 face = faces[enabled + mousehere * 2];
2941 /* The following if clause means that we display the menu help
2942 strings even if the menu item is currently disabled. */
2943 if (disp_help && enabled + mousehere * 2 >= 2)
2945 menu_help_message = menu->help_text[i];
2946 menu_help_paneno = pn - 1;
2947 menu_help_itemno = i;
2949 p = text;
2950 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
2951 p++;
2952 for (j = 0, q = menu->text[i]; *q; j++)
2954 unsigned c = STRING_CHAR_ADVANCE (q);
2956 if (c > 26)
2958 BUILD_CHAR_GLYPH (*p, c, face, 0);
2959 p++;
2961 else /* make '^x' */
2963 BUILD_CHAR_GLYPH (*p, '^', face, 0);
2964 p++;
2965 j++;
2966 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
2967 p++;
2970 /* Don't let the menu text overflow into the next screen row. */
2971 if (x + max_width > screen_size_X)
2973 max_width = screen_size_X - x;
2974 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
2976 for (; j < max_width - 2; j++, p++)
2977 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
2979 /* 16 is the character code of a character that on DOS terminal
2980 produces a nice-looking right-pointing arrow glyph. */
2981 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
2982 p++;
2983 IT_write_glyphs (sf, text, max_width);
2985 IT_update_end (sf);
2986 IT_cursor_to (sf, row, col);
2987 xfree (text);
2990 /* --------------------------- X Menu emulation ---------------------- */
2992 /* Report availability of menus. */
2995 have_menus_p (void) { return 1; }
2997 /* Create a brand new menu structure. */
2999 XMenu *
3000 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3002 return IT_menu_create ();
3005 /* Create a new pane and place it on the outer-most level. It is not
3006 clear that it should be placed out there, but I don't know what else
3007 to do. */
3010 XMenuAddPane (Display *foo, XMenu *menu, const char *txt, int enable)
3012 int len;
3013 const char *p;
3015 if (!enable)
3016 emacs_abort ();
3018 IT_menu_make_room (menu);
3019 menu->submenu[menu->count] = IT_menu_create ();
3020 menu->text[menu->count] = (char *)txt;
3021 menu->panenumber[menu->count] = ++menu->panecount;
3022 menu->help_text[menu->count] = NULL;
3023 menu->count++;
3025 /* Adjust length for possible control characters (which will
3026 be written as ^x). */
3027 for (len = strlen (txt), p = txt; *p; p++)
3028 if (*p < 27)
3029 len++;
3031 if (len > menu->width)
3032 menu->width = len;
3034 return menu->panecount;
3037 /* Create a new item in a menu pane. */
3040 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3041 int foo, char *txt, int enable, char const *help_text)
3043 int len;
3044 char *p;
3046 if (pane)
3047 if (!(menu = IT_menu_search_pane (menu, pane)))
3048 return XM_FAILURE;
3049 IT_menu_make_room (menu);
3050 menu->submenu[menu->count] = (XMenu *) 0;
3051 menu->text[menu->count] = txt;
3052 menu->panenumber[menu->count] = enable;
3053 menu->help_text[menu->count] = help_text;
3054 menu->count++;
3056 /* Adjust length for possible control characters (which will
3057 be written as ^x). */
3058 for (len = strlen (txt), p = txt; *p; p++)
3059 if (*p < 27)
3060 len++;
3062 if (len > menu->width)
3063 menu->width = len;
3065 return XM_SUCCESS;
3068 /* Decide where the menu would be placed if requested at (X,Y). */
3070 void
3071 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3072 int *ulx, int *uly, int *width, int *height)
3074 IT_menu_calc_size (menu, width, height);
3075 *ulx = x + 1;
3076 *uly = y;
3077 *width += 2;
3080 struct IT_menu_state
3082 void *screen_behind;
3083 XMenu *menu;
3084 int pane;
3085 int x, y;
3089 /* Display menu, wait for user's response, and return that response. */
3092 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3093 int x0, int y0, unsigned ButtonMask, char **txt,
3094 void (*help_callback)(char const *, int, int))
3096 struct IT_menu_state *state;
3097 int statecount, x, y, i, b, screensize, leave, result, onepane;
3098 int title_faces[4]; /* face to display the menu title */
3099 int faces[4], buffers_num_deleted = 0;
3100 struct frame *sf = SELECTED_FRAME ();
3101 Lisp_Object saved_echo_area_message, selectface;
3103 /* Just in case we got here without a mouse present... */
3104 if (have_mouse <= 0)
3105 return XM_IA_SELECT;
3106 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3107 around the display. */
3108 if (x0 <= 0)
3109 x0 = 1;
3110 if (y0 <= 0)
3111 y0 = 1;
3113 /* We will process all the mouse events directly, so we had
3114 better prevent dos_rawgetc from stealing them from us. */
3115 mouse_preempted++;
3117 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3118 screensize = screen_size * 2;
3119 faces[0]
3120 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3121 DEFAULT_FACE_ID, 1);
3122 faces[1]
3123 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3124 DEFAULT_FACE_ID, 1);
3125 selectface = intern ("msdos-menu-select-face");
3126 faces[2] = lookup_derived_face (sf, selectface,
3127 faces[0], 1);
3128 faces[3] = lookup_derived_face (sf, selectface,
3129 faces[1], 1);
3131 /* Make sure the menu title is always displayed with
3132 `msdos-menu-active-face', no matter where the mouse pointer is. */
3133 for (i = 0; i < 4; i++)
3134 title_faces[i] = faces[3];
3136 statecount = 1;
3138 /* Don't let the title for the "Buffers" popup menu include a
3139 digit (which is ugly).
3141 This is a terrible kludge, but I think the "Buffers" case is
3142 the only one where the title includes a number, so it doesn't
3143 seem to be necessary to make this more general. */
3144 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3146 menu->text[0][7] = '\0';
3147 buffers_num_deleted = 1;
3150 /* We need to save the current echo area message, so that we could
3151 restore it below, before we exit. See the commentary below,
3152 before the call to message_with_string. */
3153 saved_echo_area_message = Fcurrent_message ();
3154 state[0].menu = menu;
3155 mouse_off ();
3156 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3158 /* Turn off the cursor. Otherwise it shows through the menu
3159 panes, which is ugly. */
3160 IT_display_cursor (0);
3162 /* Display the menu title. */
3163 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3164 if (buffers_num_deleted)
3165 menu->text[0][7] = ' ';
3166 if ((onepane = menu->count == 1 && menu->submenu[0]))
3168 menu->width = menu->submenu[0]->width;
3169 state[0].menu = menu->submenu[0];
3171 else
3173 state[0].menu = menu;
3175 state[0].x = x0 - 1;
3176 state[0].y = y0;
3177 state[0].pane = onepane;
3179 mouse_last_x = -1; /* A hack that forces display. */
3180 leave = 0;
3181 while (!leave)
3183 if (!mouse_visible) mouse_on ();
3184 mouse_check_moved ();
3185 if (sf->mouse_moved)
3187 sf->mouse_moved = 0;
3188 result = XM_IA_SELECT;
3189 mouse_get_xy (&x, &y);
3190 for (i = 0; i < statecount; i++)
3191 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3193 int dy = y - state[i].y;
3194 if (0 <= dy && dy < state[i].menu->count)
3196 if (!state[i].menu->submenu[dy])
3198 if (state[i].menu->panenumber[dy])
3199 result = XM_SUCCESS;
3200 else
3201 result = XM_IA_SELECT;
3203 *pane = state[i].pane - 1;
3204 *selidx = dy;
3205 /* We hit some part of a menu, so drop extra menus that
3206 have been opened. That does not include an open and
3207 active submenu. */
3208 if (i != statecount - 2
3209 || state[i].menu->submenu[dy] != state[i+1].menu)
3210 while (i != statecount - 1)
3212 statecount--;
3213 mouse_off ();
3214 ScreenUpdate (state[statecount].screen_behind);
3215 if (screen_virtual_segment)
3216 dosv_refresh_virtual_screen (0, screen_size);
3217 xfree (state[statecount].screen_behind);
3219 if (i == statecount - 1 && state[i].menu->submenu[dy])
3221 IT_menu_display (state[i].menu,
3222 state[i].y,
3223 state[i].x,
3224 state[i].pane,
3225 faces, 1);
3226 state[statecount].menu = state[i].menu->submenu[dy];
3227 state[statecount].pane = state[i].menu->panenumber[dy];
3228 mouse_off ();
3229 ScreenRetrieve (state[statecount].screen_behind
3230 = xmalloc (screensize));
3231 state[statecount].x
3232 = state[i].x + state[i].menu->width + 2;
3233 state[statecount].y = y;
3234 statecount++;
3238 IT_menu_display (state[statecount - 1].menu,
3239 state[statecount - 1].y,
3240 state[statecount - 1].x,
3241 state[statecount - 1].pane,
3242 faces, 1);
3244 else
3246 if ((menu_help_message || prev_menu_help_message)
3247 && menu_help_message != prev_menu_help_message)
3249 help_callback (menu_help_message,
3250 menu_help_paneno, menu_help_itemno);
3251 IT_display_cursor (0);
3252 prev_menu_help_message = menu_help_message;
3254 /* We are busy-waiting for the mouse to move, so let's be nice
3255 to other Windows applications by releasing our time slice. */
3256 __dpmi_yield ();
3258 for (b = 0; b < mouse_button_count && !leave; b++)
3260 /* Only leave if user both pressed and released the mouse, and in
3261 that order. This avoids popping down the menu pane unless
3262 the user is really done with it. */
3263 if (mouse_pressed (b, &x, &y))
3265 while (mouse_button_depressed (b, &x, &y))
3266 __dpmi_yield ();
3267 leave = 1;
3269 (void) mouse_released (b, &x, &y);
3273 mouse_off ();
3274 ScreenUpdate (state[0].screen_behind);
3275 if (screen_virtual_segment)
3276 dosv_refresh_virtual_screen (0, screen_size);
3278 /* We have a situation here. ScreenUpdate has just restored the
3279 screen contents as it was before we started drawing this menu.
3280 That includes any echo area message that could have been
3281 displayed back then. (In reality, that echo area message will
3282 almost always be the ``keystroke echo'' that echoes the sequence
3283 of menu items chosen by the user.) However, if the menu had some
3284 help messages, then displaying those messages caused Emacs to
3285 forget about the original echo area message. So when
3286 ScreenUpdate restored it, it created a discrepancy between the
3287 actual screen contents and what Emacs internal data structures
3288 know about it.
3290 To avoid this conflict, we force Emacs to restore the original
3291 echo area message as we found it when we entered this function.
3292 The irony of this is that we then erase the restored message
3293 right away, so the only purpose of restoring it is so that
3294 erasing it works correctly... */
3295 if (! NILP (saved_echo_area_message))
3296 message_with_string ("%s", saved_echo_area_message, 0);
3297 message (0);
3298 while (statecount--)
3299 xfree (state[statecount].screen_behind);
3300 IT_display_cursor (1); /* turn cursor back on */
3301 /* Clean up any mouse events that are waiting inside Emacs event queue.
3302 These events are likely to be generated before the menu was even
3303 displayed, probably because the user pressed and released the button
3304 (which invoked the menu) too quickly. If we don't remove these events,
3305 Emacs will process them after we return and surprise the user. */
3306 discard_mouse_events ();
3307 mouse_clear_clicks ();
3308 if (!kbd_buffer_events_waiting ())
3309 clear_input_pending ();
3310 /* Allow mouse events generation by dos_rawgetc. */
3311 mouse_preempted--;
3312 return result;
3315 /* Dispose of a menu. */
3317 void
3318 XMenuDestroy (Display *foo, XMenu *menu)
3320 int i;
3321 if (menu->allocated)
3323 for (i = 0; i < menu->count; i++)
3324 if (menu->submenu[i])
3325 XMenuDestroy (foo, menu->submenu[i]);
3326 xfree (menu->text);
3327 xfree (menu->submenu);
3328 xfree (menu->panenumber);
3329 xfree (menu->help_text);
3331 xfree (menu);
3332 menu_help_message = prev_menu_help_message = NULL;
3336 x_pixel_width (struct frame *f)
3338 return FRAME_COLS (f);
3342 x_pixel_height (struct frame *f)
3344 return FRAME_LINES (f);
3346 #endif /* !HAVE_X_WINDOWS */
3348 /* ----------------------- DOS / UNIX conversion --------------------- */
3350 void msdos_downcase_filename (unsigned char *);
3352 /* Destructively turn backslashes into slashes. */
3354 void
3355 dostounix_filename (char *p)
3357 msdos_downcase_filename (p);
3359 while (*p)
3361 if (*p == '\\')
3362 *p = '/';
3363 p++;
3367 /* Destructively turn slashes into backslashes. */
3369 void
3370 unixtodos_filename (char *p)
3372 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3374 *p += 'a' - 'A';
3375 p += 2;
3378 while (*p)
3380 if (*p == '/')
3381 *p = '\\';
3382 p++;
3386 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3389 getdefdir (int drive, char *dst)
3391 char in_path[4], *p = in_path, e = errno;
3393 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3394 if (drive != 0)
3396 *p++ = drive + 'A' - 1;
3397 *p++ = ':';
3400 *p++ = '.';
3401 *p = '\0';
3402 errno = 0;
3403 _fixpath (in_path, dst);
3404 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3405 it queries the LFN support, so ignore that error. */
3406 if ((errno && errno != ENOSYS) || *dst == '\0')
3407 return 0;
3409 msdos_downcase_filename (dst);
3411 errno = e;
3412 return 1;
3415 char *
3416 emacs_root_dir (void)
3418 static char root_dir[4];
3420 sprintf (root_dir, "%c:/", 'A' + getdisk ());
3421 root_dir[0] = tolower (root_dir[0]);
3422 return root_dir;
3425 /* Remove all CR's that are followed by a LF. */
3428 crlf_to_lf (int n, unsigned char *buf)
3430 unsigned char *np = buf, *startp = buf, *endp = buf + n;
3432 if (n == 0)
3433 return n;
3434 while (buf < endp - 1)
3436 if (*buf == 0x0d)
3438 if (*(++buf) != 0x0a)
3439 *np++ = 0x0d;
3441 else
3442 *np++ = *buf++;
3444 if (buf < endp)
3445 *np++ = *buf++;
3446 return np - startp;
3449 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3450 0, 0, 0,
3451 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
3452 (void)
3454 return (_USE_LFN ? Qt : Qnil);
3457 /* Convert alphabetic characters in a filename to lower-case. */
3459 void
3460 msdos_downcase_filename (unsigned char *p)
3462 /* Always lower-case drive letters a-z, even if the filesystem
3463 preserves case in filenames.
3464 This is so MSDOS filenames could be compared by string comparison
3465 functions that are case-sensitive. Even case-preserving filesystems
3466 do not distinguish case in drive letters. */
3467 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3469 *p += 'a' - 'A';
3470 p += 2;
3473 /* Under LFN we expect to get pathnames in their true case. */
3474 if (NILP (Fmsdos_long_file_names ()))
3475 for ( ; *p; p++)
3476 if (*p >= 'A' && *p <= 'Z')
3477 *p += 'a' - 'A';
3480 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3481 1, 1, 0,
3482 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
3483 When long filenames are supported, doesn't change FILENAME.
3484 If FILENAME is not a string, returns nil.
3485 The argument object is never altered--the value is a copy. */)
3486 (Lisp_Object filename)
3488 Lisp_Object tem;
3490 if (! STRINGP (filename))
3491 return Qnil;
3493 tem = Fcopy_sequence (filename);
3494 msdos_downcase_filename (SDATA (tem));
3495 return tem;
3498 /* The Emacs root directory as determined by init_environment. */
3500 static char emacsroot[MAXPATHLEN];
3502 char *
3503 rootrelativepath (char *rel)
3505 static char result[MAXPATHLEN + 10];
3507 strcpy (result, emacsroot);
3508 strcat (result, "/");
3509 strcat (result, rel);
3510 return result;
3513 /* Define a lot of environment variables if not already defined. Don't
3514 remove anything unless you know what you're doing -- lots of code will
3515 break if one or more of these are missing. */
3517 void
3518 init_environment (int argc, char **argv, int skip_args)
3520 char *s, *t, *root;
3521 int len, i;
3522 static const char * const tempdirs[] = {
3523 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3525 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
3527 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3528 temporary files and assume "/tmp" if $TMPDIR is unset, which
3529 will break on DOS/Windows. Refuse to work if we cannot find
3530 a directory, not even "c:/", usable for that purpose. */
3531 for (i = 0; i < imax ; i++)
3533 const char *tmp = tempdirs[i];
3534 char buf[FILENAME_MAX];
3536 if (*tmp == '$')
3538 int tmp_len;
3540 tmp = getenv (tmp + 1);
3541 if (!tmp)
3542 continue;
3544 /* Some lusers set TMPDIR=e:, probably because some losing
3545 programs cannot handle multiple slashes if they use e:/.
3546 e: fails in `access' below, so we interpret e: as e:/. */
3547 tmp_len = strlen (tmp);
3548 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
3550 strcpy (buf, tmp);
3551 buf[tmp_len++] = '/', buf[tmp_len] = 0;
3552 tmp = buf;
3556 /* Note that `access' can lie to us if the directory resides on a
3557 read-only filesystem, like CD-ROM or a write-protected floppy.
3558 The only way to be really sure is to actually create a file and
3559 see if it succeeds. But I think that's too much to ask. */
3560 if (tmp && access (tmp, D_OK) == 0)
3562 setenv ("TMPDIR", tmp, 1);
3563 break;
3566 if (i >= imax)
3567 cmd_error_internal
3568 (Fcons (Qerror,
3569 Fcons (build_string ("no usable temporary directories found!!"),
3570 Qnil)),
3571 "While setting TMPDIR: ");
3573 /* Note the startup time, so we know not to clear the screen if we
3574 exit immediately; see IT_reset_terminal_modes.
3575 (Yes, I know `clock' returns zero the first time it's called, but
3576 I do this anyway, in case some wiseguy changes that at some point.) */
3577 startup_time = clock ();
3579 /* Find our root from argv[0]. Assuming argv[0] is, say,
3580 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3581 root = alloca (MAXPATHLEN + 20);
3582 _fixpath (argv[0], root);
3583 msdos_downcase_filename (root);
3584 len = strlen (root);
3585 while (len > 0 && root[len] != '/' && root[len] != ':')
3586 len--;
3587 root[len] = '\0';
3588 if (len > 4
3589 && (strcmp (root + len - 4, "/bin") == 0
3590 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
3591 root[len - 4] = '\0';
3592 else
3593 strcpy (root, "c:/emacs"); /* let's be defensive */
3594 len = strlen (root);
3595 strcpy (emacsroot, root);
3597 /* We default HOME to our root. */
3598 setenv ("HOME", root, 0);
3600 /* We default EMACSPATH to root + "/bin". */
3601 strcpy (root + len, "/bin");
3602 setenv ("EMACSPATH", root, 0);
3604 /* I don't expect anybody to ever use other terminals so the internal
3605 terminal is the default. */
3606 setenv ("TERM", "internal", 0);
3608 #ifdef HAVE_X_WINDOWS
3609 /* Emacs expects DISPLAY to be set. */
3610 setenv ("DISPLAY", "unix:0.0", 0);
3611 #endif
3613 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3614 downcase it and mirror the backslashes. */
3615 s = getenv ("COMSPEC");
3616 if (!s) s = "c:/command.com";
3617 t = alloca (strlen (s) + 1);
3618 strcpy (t, s);
3619 dostounix_filename (t);
3620 setenv ("SHELL", t, 0);
3622 /* PATH is also downcased and backslashes mirrored. */
3623 s = getenv ("PATH");
3624 if (!s) s = "";
3625 t = alloca (strlen (s) + 3);
3626 /* Current directory is always considered part of MsDos's path but it is
3627 not normally mentioned. Now it is. */
3628 strcat (strcpy (t, ".;"), s);
3629 dostounix_filename (t); /* Not a single file name, but this should work. */
3630 setenv ("PATH", t, 1);
3632 /* In some sense all dos users have root privileges, so... */
3633 setenv ("USER", "root", 0);
3634 setenv ("NAME", getenv ("USER"), 0);
3636 /* Time zone determined from country code. To make this possible, the
3637 country code may not span more than one time zone. In other words,
3638 in the USA, you lose. */
3639 if (!getenv ("TZ"))
3640 switch (dos_country_code)
3642 case 31: /* Belgium */
3643 case 32: /* The Netherlands */
3644 case 33: /* France */
3645 case 34: /* Spain */
3646 case 36: /* Hungary */
3647 case 38: /* Yugoslavia (or what's left of it?) */
3648 case 39: /* Italy */
3649 case 41: /* Switzerland */
3650 case 42: /* Tjekia */
3651 case 45: /* Denmark */
3652 case 46: /* Sweden */
3653 case 47: /* Norway */
3654 case 48: /* Poland */
3655 case 49: /* Germany */
3656 /* Daylight saving from last Sunday in March to last Sunday in
3657 September, both at 2AM. */
3658 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3659 break;
3660 case 44: /* United Kingdom */
3661 case 351: /* Portugal */
3662 case 354: /* Iceland */
3663 setenv ("TZ", "GMT+00", 0);
3664 break;
3665 case 81: /* Japan */
3666 case 82: /* Korea */
3667 setenv ("TZ", "JST-09", 0);
3668 break;
3669 case 90: /* Turkey */
3670 case 358: /* Finland */
3671 setenv ("TZ", "EET-02", 0);
3672 break;
3673 case 972: /* Israel */
3674 /* This is an approximation. (For exact rules, use the
3675 `zoneinfo/israel' file which comes with DJGPP, but you need
3676 to install it in `/usr/share/zoneinfo/' directory first.) */
3677 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3678 break;
3680 tzset ();
3685 static int break_stat; /* BREAK check mode status. */
3686 static int stdin_stat; /* stdin IOCTL status. */
3688 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3689 control chars by DOS. Determine the keyboard type. */
3692 dos_ttraw (struct tty_display_info *tty)
3694 union REGS inregs, outregs;
3695 static int first_time = 1;
3697 /* If we are called for the initial terminal, it's too early to do
3698 anything, and termscript isn't set up. */
3699 if (tty->terminal->type == output_initial)
3700 return 2;
3702 break_stat = getcbrk ();
3703 setcbrk (0);
3705 if (first_time)
3707 inregs.h.ah = 0xc0;
3708 int86 (0x15, &inregs, &outregs);
3709 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
3711 have_mouse = 0;
3713 if (1
3714 #ifdef HAVE_X_WINDOWS
3715 && inhibit_window_system
3716 #endif
3719 inregs.x.ax = 0x0021;
3720 int86 (0x33, &inregs, &outregs);
3721 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3722 if (!have_mouse)
3724 /* Reportedly, the above doesn't work for some mouse drivers. There
3725 is an additional detection method that should work, but might be
3726 a little slower. Use that as an alternative. */
3727 inregs.x.ax = 0x0000;
3728 int86 (0x33, &inregs, &outregs);
3729 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3731 if (have_mouse)
3732 mouse_button_count = outregs.x.bx;
3734 #ifndef HAVE_X_WINDOWS
3735 /* Save the cursor shape used outside Emacs. */
3736 outside_cursor = _farpeekw (_dos_ds, 0x460);
3737 #endif
3740 first_time = 0;
3742 stdin_stat = setmode (fileno (stdin), O_BINARY);
3743 return (stdin_stat != -1);
3745 else
3746 return (setmode (fileno (stdin), O_BINARY) != -1);
3749 /* Restore status of standard input and Ctrl-C checking. */
3752 dos_ttcooked (void)
3754 union REGS inregs, outregs;
3756 setcbrk (break_stat);
3757 mouse_off ();
3759 #ifndef HAVE_X_WINDOWS
3760 /* Restore the cursor shape we found on startup. */
3761 if (outside_cursor)
3763 inregs.h.ah = 1;
3764 inregs.x.cx = outside_cursor;
3765 int86 (0x10, &inregs, &outregs);
3767 #endif
3769 return (setmode (fileno (stdin), stdin_stat) != -1);
3773 /* Run command as specified by ARGV in directory DIR.
3774 The command is run with input from TEMPIN, output to
3775 file TEMPOUT and stderr to TEMPERR. */
3778 run_msdos_command (unsigned char **argv, const char *working_dir,
3779 int tempin, int tempout, int temperr, char **envv)
3781 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
3782 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3783 int msshell, result = -1, inbak, outbak, errbak, x, y;
3784 Lisp_Object cmd;
3786 /* Get current directory as MSDOS cwd is not per-process. */
3787 getwd (oldwd);
3789 /* If argv[0] is the shell, it might come in any lettercase.
3790 Since `Fmember' is case-sensitive, we need to downcase
3791 argv[0], even if we are on case-preserving filesystems. */
3792 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3793 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3795 *pl = *pa++;
3796 if (*pl >= 'A' && *pl <= 'Z')
3797 *pl += 'a' - 'A';
3799 *pl = '\0';
3801 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3802 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3803 && !strcmp ("-c", argv[1]);
3804 if (msshell)
3806 saveargv1 = argv[1];
3807 saveargv2 = argv[2];
3808 argv[1] = "/c";
3809 /* We only need to mirror slashes if a DOS shell will be invoked
3810 not via `system' (which does the mirroring itself). Yes, that
3811 means DJGPP v1.x will lose here. */
3812 if (argv[2] && argv[3])
3814 char *p = alloca (strlen (argv[2]) + 1);
3816 strcpy (argv[2] = p, saveargv2);
3817 while (*p && isspace (*p))
3818 p++;
3819 while (*p)
3821 if (*p == '/')
3822 *p++ = '\\';
3823 else
3824 p++;
3829 chdir (working_dir);
3830 inbak = dup (0);
3831 outbak = dup (1);
3832 errbak = dup (2);
3833 if (inbak < 0 || outbak < 0 || errbak < 0)
3834 goto done; /* Allocation might fail due to lack of descriptors. */
3836 if (have_mouse > 0)
3837 mouse_get_xy (&x, &y);
3839 if (!noninteractive)
3840 dos_ttcooked (); /* do it here while 0 = stdin */
3842 dup2 (tempin, 0);
3843 dup2 (tempout, 1);
3844 dup2 (temperr, 2);
3846 if (msshell && !argv[3])
3848 /* MS-DOS native shells are too restrictive. For starters, they
3849 cannot grok commands longer than 126 characters. In DJGPP v2
3850 and later, `system' is much smarter, so we'll call it instead. */
3852 const char *cmnd;
3854 /* A shell gets a single argument--its full command
3855 line--whose original was saved in `saveargv2'. */
3857 /* Don't let them pass empty command lines to `system', since
3858 with some shells it will try to invoke an interactive shell,
3859 which will hang Emacs. */
3860 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
3862 if (*cmnd)
3864 extern char **environ;
3865 char **save_env = environ;
3866 int save_system_flags = __system_flags;
3868 /* Request the most powerful version of `system'. We need
3869 all the help we can get to avoid calling stock DOS shells. */
3870 __system_flags = (__system_redirect
3871 | __system_use_shell
3872 | __system_allow_multiple_cmds
3873 | __system_allow_long_cmds
3874 | __system_handle_null_commands
3875 | __system_emulate_chdir);
3877 environ = envv;
3878 result = system (cmnd);
3879 __system_flags = save_system_flags;
3880 environ = save_env;
3882 else
3883 result = 0; /* emulate Unixy shell behavior with empty cmd line */
3885 else
3886 result = spawnve (P_WAIT, argv[0], (char **)argv, envv);
3888 dup2 (inbak, 0);
3889 dup2 (outbak, 1);
3890 dup2 (errbak, 2);
3891 emacs_close (inbak);
3892 emacs_close (outbak);
3893 emacs_close (errbak);
3895 if (!noninteractive)
3896 dos_ttraw (CURTTY ());
3897 if (have_mouse > 0)
3899 mouse_init ();
3900 mouse_moveto (x, y);
3903 /* Some programs might change the meaning of the highest bit of the
3904 text attribute byte, so we get blinking characters instead of the
3905 bright background colors. Restore that. */
3906 if (!noninteractive)
3907 bright_bg ();
3909 done:
3910 chdir (oldwd);
3911 if (msshell)
3913 argv[1] = saveargv1;
3914 argv[2] = saveargv2;
3916 return result;
3919 void
3920 croak (char *badfunc)
3922 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3923 reset_all_sys_modes ();
3924 exit (1);
3928 * A few unimplemented functions that we silently ignore.
3930 int setpgrp (void) {return 0; }
3931 int setpriority (int x, int y, int z) { return 0; }
3933 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
3934 ssize_t
3935 readlink (const char *name, char *dummy1, size_t dummy2)
3937 /* `access' is much faster than `stat' on MS-DOS. */
3938 if (access (name, F_OK) == 0)
3939 errno = EINVAL;
3940 return -1;
3942 #endif
3944 char *
3945 careadlinkat (int fd, char const *filename,
3946 char *buffer, size_t buffer_size,
3947 struct allocator const *alloc,
3948 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
3950 if (!buffer)
3952 /* We don't support the fancy auto-allocation feature. */
3953 if (!buffer_size)
3954 errno = ENOSYS;
3955 else
3956 errno = EINVAL;
3957 buffer = NULL;
3959 else
3961 ssize_t len = preadlinkat (fd, filename, buffer, buffer_size);
3963 if (len < 0 || len == buffer_size)
3964 buffer = NULL;
3965 else
3966 buffer[len + 1] = '\0';
3968 return buffer;
3971 ssize_t
3972 careadlinkatcwd (int fd, char const *filename, char *buffer,
3973 size_t buffer_size)
3975 (void) fd;
3976 return readlink (filename, buffer, buffer_size);
3980 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3982 /* Augment DJGPP library POSIX signal functions. This is needed
3983 as of DJGPP v2.01, but might be in the library in later releases. */
3985 #include <libc/bss.h>
3987 /* A counter to know when to re-initialize the static sets. */
3988 static int sigprocmask_count = -1;
3990 /* Which signals are currently blocked (initially none). */
3991 static sigset_t current_mask;
3993 /* Which signals are pending (initially none). */
3994 static sigset_t msdos_pending_signals;
3996 /* Previous handlers to restore when the blocked signals are unblocked. */
3997 typedef void (*sighandler_t)(int);
3998 static sighandler_t prev_handlers[320];
4000 /* A signal handler which just records that a signal occurred
4001 (it will be raised later, if and when the signal is unblocked). */
4002 static void
4003 sig_suspender (int signo)
4005 sigaddset (&msdos_pending_signals, signo);
4009 sigprocmask (int how, const sigset_t *new_set, sigset_t *old_set)
4011 int signo;
4012 sigset_t new_mask;
4014 /* If called for the first time, initialize. */
4015 if (sigprocmask_count != __bss_count)
4017 sigprocmask_count = __bss_count;
4018 sigemptyset (&msdos_pending_signals);
4019 sigemptyset (&current_mask);
4020 for (signo = 0; signo < 320; signo++)
4021 prev_handlers[signo] = SIG_ERR;
4024 if (old_set)
4025 *old_set = current_mask;
4027 if (new_set == 0)
4028 return 0;
4030 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4032 errno = EINVAL;
4033 return -1;
4036 sigemptyset (&new_mask);
4038 /* DJGPP supports upto 320 signals. */
4039 for (signo = 0; signo < 320; signo++)
4041 if (sigismember (&current_mask, signo))
4042 sigaddset (&new_mask, signo);
4043 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4045 sigaddset (&new_mask, signo);
4047 /* SIGKILL is silently ignored, as on other platforms. */
4048 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4049 prev_handlers[signo] = signal (signo, sig_suspender);
4051 if (( how == SIG_UNBLOCK
4052 && sigismember (&new_mask, signo)
4053 && sigismember (new_set, signo))
4054 || (how == SIG_SETMASK
4055 && sigismember (&new_mask, signo)
4056 && !sigismember (new_set, signo)))
4058 sigdelset (&new_mask, signo);
4059 if (prev_handlers[signo] != SIG_ERR)
4061 signal (signo, prev_handlers[signo]);
4062 prev_handlers[signo] = SIG_ERR;
4064 if (sigismember (&msdos_pending_signals, signo))
4066 sigdelset (&msdos_pending_signals, signo);
4067 raise (signo);
4071 current_mask = new_mask;
4072 return 0;
4075 #endif /* not __DJGPP_MINOR__ < 2 */
4077 #ifndef HAVE_SELECT
4078 #include "sysselect.h"
4080 /* This yields the rest of the current time slice to the task manager.
4081 It should be called by any code which knows that it has nothing
4082 useful to do except idle.
4084 I don't use __dpmi_yield here, since versions of library before 2.02
4085 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4086 on some versions of Windows 9X. */
4088 void
4089 dos_yield_time_slice (void)
4091 _go32_dpmi_registers r;
4093 r.x.ax = 0x1680;
4094 r.x.ss = r.x.sp = r.x.flags = 0;
4095 _go32_dpmi_simulate_int (0x2f, &r);
4096 if (r.h.al == 0x80)
4097 errno = ENOSYS;
4100 /* Only event queue is checked. */
4101 /* We don't have to call timer_check here
4102 because wait_reading_process_output takes care of that. */
4104 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
4105 EMACS_TIME *timeout, void *ignored)
4107 int check_input;
4108 struct timespec t;
4110 check_input = 0;
4111 if (rfds)
4113 check_input = FD_ISSET (0, rfds);
4114 FD_ZERO (rfds);
4116 if (wfds)
4117 FD_ZERO (wfds);
4118 if (efds)
4119 FD_ZERO (efds);
4121 if (nfds != 1)
4122 emacs_abort ();
4124 /* If we are looking only for the terminal, with no timeout,
4125 just read it and wait -- that's more efficient. */
4126 if (!timeout)
4128 while (!detect_input_pending ())
4130 dos_yield_time_slice ();
4133 else
4135 EMACS_TIME clnow, cllast, cldiff;
4137 gettime (&t);
4138 cllast = make_emacs_time (t.tv_sec, t.tv_nsec);
4140 while (!check_input || !detect_input_pending ())
4142 gettime (&t);
4143 clnow = make_emacs_time (t.tv_sec, t.tv_nsec);
4144 cldiff = sub_emacs_time (clnow, cllast);
4145 *timeout = sub_emacs_time (*timeout, cldiff);
4147 /* Stop when timeout value crosses zero. */
4148 if (EMACS_TIME_SIGN (*timeout) <= 0)
4149 return 0;
4150 cllast = clnow;
4151 dos_yield_time_slice ();
4155 FD_SET (0, rfds);
4156 return 1;
4158 #endif
4161 * Define overlaid functions:
4163 * chdir -> sys_chdir
4164 * tzset -> init_gettimeofday
4165 * abort -> dos_abort
4168 #ifdef chdir
4169 #undef chdir
4170 extern int chdir (const char *);
4173 sys_chdir (const char *path)
4175 int len = strlen (path);
4176 char *tmp = (char *)path;
4178 if (*tmp && tmp[1] == ':')
4180 if (getdisk () != tolower (tmp[0]) - 'a')
4181 setdisk (tolower (tmp[0]) - 'a');
4182 tmp += 2; /* strip drive: KFS 1995-07-06 */
4183 len -= 2;
4186 if (len > 1 && (tmp[len - 1] == '/'))
4188 char *tmp1 = (char *) alloca (len + 1);
4189 strcpy (tmp1, tmp);
4190 tmp1[len - 1] = 0;
4191 tmp = tmp1;
4193 return chdir (tmp);
4195 #endif
4197 #ifdef tzset
4198 #undef tzset
4199 extern void tzset (void);
4201 void
4202 init_gettimeofday (void)
4204 time_t ltm, gtm;
4205 struct tm *lstm;
4207 tzset ();
4208 ltm = gtm = time (NULL);
4209 ltm = mktime (lstm = localtime (&ltm));
4210 gtm = mktime (gmtime (&gtm));
4211 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4212 time_rec.tm_isdst = lstm->tm_isdst;
4213 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4215 #endif
4217 static void
4218 msdos_abort (void)
4220 dos_ttcooked ();
4221 ScreenSetCursor (10, 0);
4222 cputs ("\r\n\nEmacs aborted!\r\n");
4223 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4224 if (screen_virtual_segment)
4225 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4226 /* Generate traceback, so we could tell whodunit. */
4227 signal (SIGINT, SIG_DFL);
4228 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4229 #else /* __DJGPP_MINOR__ >= 2 */
4230 raise (SIGABRT);
4231 #endif /* __DJGPP_MINOR__ >= 2 */
4232 exit (2);
4235 void
4236 msdos_fatal_signal (int sig)
4238 if (sig == SIGABRT)
4239 msdos_abort ();
4240 else
4241 raise (sig);
4244 void
4245 syms_of_msdos (void)
4247 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4248 staticpro (&recent_doskeys);
4250 #ifndef HAVE_X_WINDOWS
4252 /* The following two are from xfns.c: */
4253 DEFSYM (Qreverse, "reverse");
4255 DEFVAR_LISP ("dos-unsupported-char-glyph", Vdos_unsupported_char_glyph,
4256 doc: /* Glyph to display instead of chars not supported by current codepage.
4257 This variable is used only by MS-DOS terminals. */);
4258 Vdos_unsupported_char_glyph = make_number ('\177');
4260 #endif
4262 defsubr (&Srecent_doskeys);
4263 defsubr (&Smsdos_long_file_names);
4264 defsubr (&Smsdos_downcase_filename);
4265 defsubr (&Smsdos_remember_default_colors);
4266 defsubr (&Smsdos_set_mouse_buttons);
4269 #endif /* MSDOS */