Merge from trunk.
[emacs.git] / src / msdos.c
blobdda24cc868f3e2074f5fe8881a2fc1f8dd6aa9c8
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26 #include <config.h>
28 #ifdef MSDOS
29 #include <setjmp.h>
30 #include "lisp.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <sys/param.h>
35 #include <sys/time.h>
36 #include <dos.h>
37 #include <errno.h>
38 #include <string.h> /* for memset and string functions */
39 #include <sys/stat.h> /* for _fixpath */
40 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #include <dir.h> /* for getdisk */
42 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
43 #include <fcntl.h>
44 #include <io.h> /* for setmode */
45 #include <dpmi.h> /* for __dpmi_xxx stuff */
46 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
47 #include <libc/dosio.h> /* for _USE_LFN */
48 #include <conio.h> /* for cputs */
50 #include "msdos.h"
51 #include "systime.h"
52 #include "frame.h"
53 #include "termhooks.h"
54 #include "termchar.h"
55 #include "dispextern.h"
56 #include "dosfns.h"
57 #include "termopts.h"
58 #include "character.h"
59 #include "coding.h"
60 #include "disptab.h"
61 #include "window.h"
62 #include "buffer.h"
63 #include "commands.h"
64 #include "blockinput.h"
65 #include "keyboard.h"
66 #include "intervals.h"
67 #include <go32.h>
68 #include <pc.h>
69 #include <ctype.h>
70 /* #include <process.h> */
71 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
72 #define P_WAIT 1
74 #ifndef _USE_LFN
75 #define _USE_LFN 0
76 #endif
78 #ifndef _dos_ds
79 #define _dos_ds _go32_info_block.selector_for_linear_memory
80 #endif
82 #include <signal.h>
83 #include "syssignal.h"
85 #ifndef SYSTEM_MALLOC
87 #ifdef GNU_MALLOC
89 /* If other `malloc' than ours is used, force our `sbrk' behave like
90 Unix programs expect (resize memory blocks to keep them contiguous).
91 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
92 because that's what `gmalloc' expects to get. */
93 #include <crt0.h>
95 #ifdef REL_ALLOC
96 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
97 #else /* not REL_ALLOC */
98 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
99 #endif /* not REL_ALLOC */
100 #endif /* GNU_MALLOC */
102 #endif /* not SYSTEM_MALLOC */
104 static unsigned long
105 event_timestamp (void)
107 struct time t;
108 unsigned long s;
110 gettime (&t);
111 s = t.ti_min;
112 s *= 60;
113 s += t.ti_sec;
114 s *= 1000;
115 s += t.ti_hund * 10;
117 return s;
121 /* ------------------------ Mouse control ---------------------------
123 * Coordinates are in screen positions and zero based.
124 * Mouse buttons are numbered from left to right and also zero based.
127 /* This used to be in termhooks.h, but mainstream Emacs code no longer
128 uses it, and it was removed... */
129 #define NUM_MOUSE_BUTTONS (5)
131 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
132 static int mouse_visible;
134 static int mouse_last_x;
135 static int mouse_last_y;
137 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
138 static int mouse_button_count;
140 void
141 mouse_on (void)
143 union REGS regs;
145 if (have_mouse > 0 && !mouse_visible)
147 struct tty_display_info *tty = CURTTY ();
149 if (tty->termscript)
150 fprintf (tty->termscript, "<M_ON>");
151 regs.x.ax = 0x0001;
152 int86 (0x33, &regs, &regs);
153 mouse_visible = 1;
157 void
158 mouse_off (void)
160 union REGS regs;
162 if (have_mouse > 0 && mouse_visible)
164 struct tty_display_info *tty = CURTTY ();
166 if (tty->termscript)
167 fprintf (tty->termscript, "<M_OFF>");
168 regs.x.ax = 0x0002;
169 int86 (0x33, &regs, &regs);
170 mouse_visible = 0;
174 static void
175 mouse_setup_buttons (int n_buttons)
177 if (n_buttons == 3)
179 mouse_button_count = 3;
180 mouse_button_translate[0] = 0; /* Left */
181 mouse_button_translate[1] = 2; /* Middle */
182 mouse_button_translate[2] = 1; /* Right */
184 else /* two, what else? */
186 mouse_button_count = 2;
187 mouse_button_translate[0] = 0;
188 mouse_button_translate[1] = 1;
192 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
193 1, 1, "NSet number of mouse buttons to: ",
194 doc: /* Set the number of mouse buttons to use by Emacs.
195 This is useful with mice that report the number of buttons inconsistently,
196 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
197 them. This happens with wheeled mice on Windows 9X, for example. */)
198 (Lisp_Object nbuttons)
200 int n;
202 CHECK_NUMBER (nbuttons);
203 n = XINT (nbuttons);
204 if (n < 2 || n > 3)
205 xsignal2 (Qargs_out_of_range,
206 build_string ("only 2 or 3 mouse buttons are supported"),
207 nbuttons);
208 mouse_setup_buttons (n);
209 return Qnil;
212 static void
213 mouse_get_xy (int *x, int *y)
215 union REGS regs;
217 regs.x.ax = 0x0003;
218 int86 (0x33, &regs, &regs);
219 *x = regs.x.cx / 8;
220 *y = regs.x.dx / 8;
223 void
224 mouse_moveto (int x, int y)
226 union REGS regs;
227 struct tty_display_info *tty = CURTTY ();
229 if (tty->termscript)
230 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
231 regs.x.ax = 0x0004;
232 mouse_last_x = regs.x.cx = x * 8;
233 mouse_last_y = regs.x.dx = y * 8;
234 int86 (0x33, &regs, &regs);
237 static int
238 mouse_pressed (int b, int *xp, int *yp)
240 union REGS regs;
242 if (b >= mouse_button_count)
243 return 0;
244 regs.x.ax = 0x0005;
245 regs.x.bx = mouse_button_translate[b];
246 int86 (0x33, &regs, &regs);
247 if (regs.x.bx)
248 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
249 return (regs.x.bx != 0);
252 static int
253 mouse_released (int b, int *xp, int *yp)
255 union REGS regs;
257 if (b >= mouse_button_count)
258 return 0;
259 regs.x.ax = 0x0006;
260 regs.x.bx = mouse_button_translate[b];
261 int86 (0x33, &regs, &regs);
262 if (regs.x.bx)
263 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
264 return (regs.x.bx != 0);
267 static int
268 mouse_button_depressed (int b, int *xp, int *yp)
270 union REGS regs;
272 if (b >= mouse_button_count)
273 return 0;
274 regs.x.ax = 0x0003;
275 int86 (0x33, &regs, &regs);
276 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
278 *xp = regs.x.cx / 8;
279 *yp = regs.x.dx / 8;
280 return 1;
282 return 0;
285 void
286 mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
287 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
288 unsigned long *time)
290 int ix, iy;
291 Lisp_Object frame, tail;
293 /* Clear the mouse-moved flag for every frame on this display. */
294 FOR_EACH_FRAME (tail, frame)
295 XFRAME (frame)->mouse_moved = 0;
297 *f = SELECTED_FRAME();
298 *bar_window = Qnil;
299 mouse_get_xy (&ix, &iy);
300 *time = event_timestamp ();
301 *x = make_number (mouse_last_x = ix);
302 *y = make_number (mouse_last_y = iy);
305 static void
306 mouse_check_moved (void)
308 int x, y;
310 mouse_get_xy (&x, &y);
311 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
312 mouse_last_x = x;
313 mouse_last_y = y;
316 /* Force the mouse driver to ``forget'' about any button clicks until
317 now. */
318 static void
319 mouse_clear_clicks (void)
321 int b;
323 for (b = 0; b < mouse_button_count; b++)
325 int dummy_x, dummy_y;
327 (void) mouse_pressed (b, &dummy_x, &dummy_y);
328 (void) mouse_released (b, &dummy_x, &dummy_y);
332 void
333 mouse_init (void)
335 union REGS regs;
336 struct tty_display_info *tty = CURTTY ();
338 if (tty->termscript)
339 fprintf (tty->termscript, "<M_INIT>");
341 regs.x.ax = 0x0021;
342 int86 (0x33, &regs, &regs);
344 /* Reset the mouse last press/release info. It seems that Windows
345 doesn't do that automatically when function 21h is called, which
346 causes Emacs to ``remember'' the click that switched focus to the
347 window just before Emacs was started from that window. */
348 mouse_clear_clicks ();
350 regs.x.ax = 0x0007;
351 regs.x.cx = 0;
352 regs.x.dx = 8 * (ScreenCols () - 1);
353 int86 (0x33, &regs, &regs);
355 regs.x.ax = 0x0008;
356 regs.x.cx = 0;
357 regs.x.dx = 8 * (ScreenRows () - 1);
358 int86 (0x33, &regs, &regs);
360 mouse_moveto (0, 0);
361 mouse_visible = 0;
364 /* ------------------------- Screen control ----------------------
368 static int internal_terminal = 0;
370 #ifndef HAVE_X_WINDOWS
371 extern unsigned char ScreenAttrib;
372 static int screen_face;
374 static int screen_size_X;
375 static int screen_size_Y;
376 static int screen_size;
378 static int current_pos_X;
379 static int current_pos_Y;
380 static int new_pos_X;
381 static int new_pos_Y;
383 static void *startup_screen_buffer;
384 static int startup_screen_size_X;
385 static int startup_screen_size_Y;
386 static int startup_pos_X;
387 static int startup_pos_Y;
388 static unsigned char startup_screen_attrib;
390 static clock_t startup_time;
392 static int term_setup_done;
394 static unsigned short outside_cursor;
396 /* Similar to the_only_frame. */
397 struct tty_display_info the_only_display_info;
399 /* Support for DOS/V (allows Japanese characters to be displayed on
400 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
402 /* Holds the address of the text-mode screen buffer. */
403 static unsigned long screen_old_address = 0;
404 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
405 static unsigned short screen_virtual_segment = 0;
406 static unsigned short screen_virtual_offset = 0;
407 /* A flag to control how to display unibyte 8-bit characters. */
408 extern int unibyte_display_via_language_environment;
410 extern Lisp_Object Qcursor_type;
411 extern Lisp_Object Qbar, Qhbar;
413 /* The screen colors of the current frame, which serve as the default
414 colors for newly-created frames. */
415 static int initial_screen_colors[2];
417 /* Update the screen from a part of relocated DOS/V screen buffer which
418 begins at OFFSET and includes COUNT characters. */
419 static void
420 dosv_refresh_virtual_screen (int offset, int count)
422 __dpmi_regs regs;
424 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
425 return;
427 regs.h.ah = 0xff; /* update relocated screen */
428 regs.x.es = screen_virtual_segment;
429 regs.x.di = screen_virtual_offset + offset;
430 regs.x.cx = count;
431 __dpmi_int (0x10, &regs);
434 static void
435 dos_direct_output (int y, int x, char *buf, int len)
437 int t0 = 2 * (x + y * screen_size_X);
438 int t = t0 + (int) ScreenPrimary;
439 int l0 = len;
441 /* This is faster. */
442 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
443 _farnspokeb (t, *buf);
445 if (screen_virtual_segment)
446 dosv_refresh_virtual_screen (t0, l0);
448 #endif
450 #ifndef HAVE_X_WINDOWS
452 static int blink_bit = -1; /* the state of the blink bit at startup */
454 /* Enable bright background colors. */
455 static void
456 bright_bg (void)
458 union REGS regs;
460 /* Remember the original state of the blink/bright-background bit.
461 It is stored at 0040:0065h in the BIOS data area. */
462 if (blink_bit == -1)
463 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
465 regs.h.bl = 0;
466 regs.x.ax = 0x1003;
467 int86 (0x10, &regs, &regs);
470 /* Disable bright background colors (and enable blinking) if we found
471 the video system in that state at startup. */
472 static void
473 maybe_enable_blinking (void)
475 if (blink_bit == 1)
477 union REGS regs;
479 regs.h.bl = 1;
480 regs.x.ax = 0x1003;
481 int86 (0x10, &regs, &regs);
485 /* Return non-zero if the system has a VGA adapter. */
486 static int
487 vga_installed (void)
489 union REGS regs;
491 regs.x.ax = 0x1a00;
492 int86 (0x10, &regs, &regs);
493 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
494 return 1;
495 return 0;
498 /* Set the screen dimensions so that it can show no less than
499 ROWS x COLS frame. */
501 void
502 dos_set_window_size (int *rows, int *cols)
504 char video_name[30];
505 union REGS regs;
506 Lisp_Object video_mode;
507 int video_mode_value, have_vga = 0;
508 int current_rows = ScreenRows (), current_cols = ScreenCols ();
510 if (*rows == current_rows && *cols == current_cols)
511 return;
513 mouse_off ();
514 have_vga = vga_installed ();
516 /* If the user specified a special video mode for these dimensions,
517 use that mode. */
518 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
519 video_mode = Fsymbol_value (Fintern_soft (build_string (video_name), Qnil));
521 if (INTEGERP (video_mode)
522 && (video_mode_value = XINT (video_mode)) > 0)
524 regs.x.ax = video_mode_value;
525 int86 (0x10, &regs, &regs);
527 if (have_mouse)
529 /* Must hardware-reset the mouse, or else it won't update
530 its notion of screen dimensions for some non-standard
531 video modes. This is *painfully* slow... */
532 regs.x.ax = 0;
533 int86 (0x33, &regs, &regs);
537 /* Find one of the dimensions supported by standard EGA/VGA
538 which gives us at least the required dimensions. */
539 else
541 static struct {
542 int rows, need_vga;
543 } std_dimension[] = {
544 {25, 0},
545 {28, 1},
546 {35, 0},
547 {40, 1},
548 {43, 0},
549 {50, 1}
551 int i = 0;
553 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
555 if (std_dimension[i].need_vga <= have_vga
556 && std_dimension[i].rows >= *rows)
558 if (std_dimension[i].rows != current_rows
559 || *cols != current_cols)
560 _set_screen_lines (std_dimension[i].rows);
561 break;
563 i++;
568 if (have_mouse)
570 mouse_init ();
571 mouse_on ();
574 /* Tell the caller what dimensions have been REALLY set. */
575 *rows = ScreenRows ();
576 *cols = ScreenCols ();
578 /* Update Emacs' notion of screen dimensions. */
579 screen_size_X = *cols;
580 screen_size_Y = *rows;
581 screen_size = *cols * *rows;
583 /* If the dimensions changed, the mouse highlight info is invalid. */
584 if (current_rows != *rows || current_cols != *cols)
586 struct frame *f = SELECTED_FRAME();
587 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
588 Lisp_Object window = dpyinfo->mouse_face_window;
590 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
592 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
593 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
594 dpyinfo->mouse_face_window = Qnil;
598 /* Enable bright background colors. */
599 bright_bg ();
601 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
602 be defensive anyway. */
603 if (screen_virtual_segment)
604 dosv_refresh_virtual_screen (0, *cols * *rows);
607 /* If we write a character in the position where the mouse is,
608 the mouse cursor may need to be refreshed. */
610 static void
611 mouse_off_maybe (void)
613 int x, y;
615 if (!mouse_visible)
616 return;
618 mouse_get_xy (&x, &y);
619 if (y != new_pos_Y || x < new_pos_X)
620 return;
622 mouse_off ();
625 #define DEFAULT_CURSOR_START (-1)
626 #define DEFAULT_CURSOR_WIDTH (-1)
627 #define BOX_CURSOR_WIDTH (-32)
629 /* Set cursor to begin at scan line START_LINE in the character cell
630 and extend for WIDTH scan lines. Scan lines are counted from top
631 of the character cell, starting from zero. */
632 static void
633 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
635 unsigned desired_cursor;
636 __dpmi_regs regs;
637 int max_line, top_line, bot_line;
638 struct tty_display_info *tty = FRAME_TTY (f);
640 /* Avoid the costly BIOS call if F isn't the currently selected
641 frame. Allow for NULL as unconditionally meaning the selected
642 frame. */
643 if (f && f != SELECTED_FRAME())
644 return;
646 if (tty->termscript)
647 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
649 /* The character cell size in scan lines is stored at 40:85 in the
650 BIOS data area. */
651 max_line = _farpeekw (_dos_ds, 0x485) - 1;
652 switch (max_line)
654 default: /* this relies on CGA cursor emulation being ON! */
655 case 7:
656 bot_line = 7;
657 break;
658 case 9:
659 bot_line = 9;
660 break;
661 case 13:
662 bot_line = 12;
663 break;
664 case 15:
665 bot_line = 14;
666 break;
669 if (width < 0)
671 if (width == BOX_CURSOR_WIDTH)
673 top_line = 0;
674 bot_line = max_line;
676 else if (start_line != DEFAULT_CURSOR_START)
678 top_line = start_line;
679 bot_line = top_line - width - 1;
681 else if (width != DEFAULT_CURSOR_WIDTH)
683 top_line = 0;
684 bot_line = -1 - width;
686 else
687 top_line = bot_line + 1;
689 else if (width == 0)
691 /* [31, 0] seems to DTRT for all screen sizes. */
692 top_line = 31;
693 bot_line = 0;
695 else /* WIDTH is positive */
697 if (start_line != DEFAULT_CURSOR_START)
698 bot_line = start_line;
699 top_line = bot_line - (width - 1);
702 /* If the current cursor shape is already what they want, we are
703 history here. */
704 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
705 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
706 return;
708 regs.h.ah = 1;
709 regs.x.cx = desired_cursor;
710 __dpmi_int (0x10, &regs);
713 static void
714 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
716 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
718 /* Just BAR means the normal EGA/VGA cursor. */
719 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
721 else if (CONSP (cursor_type)
722 && (EQ (XCAR (cursor_type), Qbar)
723 || EQ (XCAR (cursor_type), Qhbar)))
725 Lisp_Object bar_parms = XCDR (cursor_type);
726 int width;
728 if (INTEGERP (bar_parms))
730 /* Feature: negative WIDTH means cursor at the top
731 of the character cell, zero means invisible cursor. */
732 width = XINT (bar_parms);
733 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
734 width);
736 else if (CONSP (bar_parms)
737 && INTEGERP (XCAR (bar_parms))
738 && INTEGERP (XCDR (bar_parms)))
740 int start_line = XINT (XCDR (bar_parms));
742 width = XINT (XCAR (bar_parms));
743 msdos_set_cursor_shape (f, start_line, width);
746 else
748 /* Treat anything unknown as "box cursor". This includes nil, so
749 that a frame which doesn't specify a cursor type gets a box,
750 which is the default in Emacs. */
751 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
755 static void
756 IT_ring_bell (struct frame *f)
758 if (visible_bell)
760 mouse_off ();
761 ScreenVisualBell ();
763 else
765 union REGS inregs, outregs;
766 inregs.h.ah = 2;
767 inregs.h.dl = 7;
768 intdos (&inregs, &outregs);
772 /* Given a face id FACE, extract the face parameters to be used for
773 display until the face changes. The face parameters (actually, its
774 color) are used to construct the video attribute byte for each
775 glyph during the construction of the buffer that is then blitted to
776 the video RAM. */
777 static void
778 IT_set_face (int face)
780 struct frame *sf = SELECTED_FRAME();
781 struct face *fp = FACE_FROM_ID (sf, face);
782 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
783 unsigned long fg, bg, dflt_fg, dflt_bg;
784 struct tty_display_info *tty = FRAME_TTY (sf);
786 if (!fp)
788 fp = dfp;
789 /* The default face for the frame should always be realized and
790 cached. */
791 if (!fp)
792 abort ();
794 screen_face = face;
795 fg = fp->foreground;
796 bg = fp->background;
797 dflt_fg = dfp->foreground;
798 dflt_bg = dfp->background;
800 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
801 mean use the colors of the default face. Note that we assume all
802 16 colors to be available for the background, since Emacs switches
803 on this mode (and loses the blinking attribute) at startup. */
804 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
805 fg = FRAME_FOREGROUND_PIXEL (sf);
806 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
807 fg = FRAME_BACKGROUND_PIXEL (sf);
808 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
809 bg = FRAME_BACKGROUND_PIXEL (sf);
810 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
811 bg = FRAME_FOREGROUND_PIXEL (sf);
813 /* Make sure highlighted lines really stand out, come what may. */
814 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
816 unsigned long tem = fg;
818 fg = bg;
819 bg = tem;
821 /* If the user requested inverse video, obey. */
822 if (inverse_video)
824 unsigned long tem2 = fg;
826 fg = bg;
827 bg = tem2;
829 if (tty->termscript)
830 fprintf (tty->termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
831 fp->foreground, fp->background, fg, bg);
832 if (fg >= 0 && fg < 16)
834 ScreenAttrib &= 0xf0;
835 ScreenAttrib |= fg;
837 if (bg >= 0 && bg < 16)
839 ScreenAttrib &= 0x0f;
840 ScreenAttrib |= ((bg & 0x0f) << 4);
844 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
845 width of a DOS display in any known text mode. We multiply by 2 to
846 accomodate the screen attribute byte. */
847 #define MAX_SCREEN_BUF 160*2
849 Lisp_Object Vdos_unsupported_char_glyph;
850 extern unsigned char *encode_terminal_code (struct glyph *, int,
851 struct coding_system *);
852 static void
853 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
855 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
856 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
857 register int sl = str_len;
858 struct tty_display_info *tty = FRAME_TTY (f);
859 struct frame *sf;
860 unsigned char *conversion_buffer;
862 /* Do we need to consider conversion of unibyte characters to
863 multibyte? */
864 int convert_unibyte_characters
865 = (NILP (current_buffer->enable_multibyte_characters)
866 && unibyte_display_via_language_environment);
868 /* If terminal_coding does any conversion, use it, otherwise use
869 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
870 because it always returns 1 if terminal_coding.src_multibyte is 1. */
871 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
873 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
874 coding = &safe_terminal_coding;
876 if (str_len <= 0) return;
878 sf = SELECTED_FRAME();
880 /* Since faces get cached and uncached behind our back, we can't
881 rely on their indices in the cache being consistent across
882 invocations. So always reset the screen face to the default
883 face of the frame, before writing glyphs, and let the glyphs
884 set the right face if it's different from the default. */
885 IT_set_face (DEFAULT_FACE_ID);
887 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
888 the tail. */
889 coding->mode &= ~CODING_MODE_LAST_BLOCK;
890 screen_bp = &screen_buf[0];
891 while (sl > 0)
893 int cf;
894 int n;
896 /* If the face of this glyph is different from the current
897 screen face, update the screen attribute byte. */
898 cf = str->face_id;
899 if (cf != screen_face)
900 IT_set_face (cf); /* handles invalid faces gracefully */
902 /* Identify a run of glyphs with the same face. */
903 for (n = 1; n < sl; ++n)
904 if (str[n].face_id != cf)
905 break;
907 if (n >= sl)
908 /* This is the last glyph. */
909 coding->mode |= CODING_MODE_LAST_BLOCK;
911 conversion_buffer = encode_terminal_code (str, n, coding);
912 if (coding->produced > 0)
914 /* Copy the encoded bytes to the screen buffer. */
915 for (bp = conversion_buffer; coding->produced--; bp++)
917 /* Paranoia: discard bytes that would overrun the end of
918 the screen buffer. */
919 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
921 *screen_bp++ = (unsigned char)*bp;
922 *screen_bp++ = ScreenAttrib;
924 if (tty->termscript)
925 fputc (*bp, tty->termscript);
928 /* Update STR and its remaining length. */
929 str += n;
930 sl -= n;
933 /* Dump whatever we have in the screen buffer. */
934 mouse_off_maybe ();
935 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
936 if (screen_virtual_segment)
937 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
938 new_pos_X += (screen_bp - screen_buf) / 2;
941 /************************************************************************
942 Mouse Highlight (and friends..)
943 ************************************************************************/
945 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
946 static Lisp_Object last_mouse_window;
948 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
950 /* Set the mouse pointer shape according to whether it is in the
951 area where the mouse highlight is in effect. */
952 static void
953 IT_set_mouse_pointer (int mode)
955 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
956 many possibilities to change its shape, and the available
957 functionality pretty much sucks (e.g., almost every reasonable
958 shape will conceal the character it is on). Since the color of
959 the pointer changes in the highlighted area, it is not clear to
960 me whether anything else is required, anyway. */
963 /* Display the active region described by mouse_face_*
964 in its mouse-face if HL > 0, in its normal face if HL = 0. */
965 static void
966 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
968 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
969 struct frame *f = XFRAME (WINDOW_FRAME (w));
970 int i;
971 struct face *fp;
972 struct tty_display_info *tty = FRAME_TTY (f);
975 /* If window is in the process of being destroyed, don't bother
976 doing anything. */
977 if (w->current_matrix == NULL)
978 goto set_cursor_shape;
980 /* Recognize when we are called to operate on rows that don't exist
981 anymore. This can happen when a window is split. */
982 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
983 goto set_cursor_shape;
985 /* There's no sense to do anything if the mouse face isn't realized. */
986 if (hl > 0)
988 if (dpyinfo->mouse_face_hidden)
989 goto set_cursor_shape;
991 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
992 if (!fp)
993 goto set_cursor_shape;
996 /* Note that mouse_face_beg_row etc. are window relative. */
997 for (i = dpyinfo->mouse_face_beg_row;
998 i <= dpyinfo->mouse_face_end_row;
999 i++)
1001 int start_hpos, end_hpos;
1002 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1004 /* Don't do anything if row doesn't have valid contents. */
1005 if (!row->enabled_p)
1006 continue;
1008 /* For all but the first row, the highlight starts at column 0. */
1009 if (i == dpyinfo->mouse_face_beg_row)
1010 start_hpos = dpyinfo->mouse_face_beg_col;
1011 else
1012 start_hpos = 0;
1014 if (i == dpyinfo->mouse_face_end_row)
1015 end_hpos = dpyinfo->mouse_face_end_col;
1016 else
1017 end_hpos = row->used[TEXT_AREA];
1019 if (end_hpos <= start_hpos)
1020 continue;
1021 /* Record that some glyphs of this row are displayed in
1022 mouse-face. */
1023 row->mouse_face_p = hl > 0;
1024 if (hl > 0)
1026 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1027 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1028 int nglyphs = end_hpos - start_hpos;
1029 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1030 int start_offset = offset;
1032 if (tty->termscript)
1033 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1034 kstart, kstart + nglyphs - 1, vpos);
1036 mouse_off ();
1037 IT_set_face (dpyinfo->mouse_face_face_id);
1038 /* Since we are going to change only the _colors_ of the
1039 displayed text, there's no need to go through all the
1040 pain of generating and encoding the text from the glyphs.
1041 Instead, we simply poke the attribute byte of each
1042 affected position in video memory with the colors
1043 computed by IT_set_face! */
1044 _farsetsel (_dos_ds);
1045 while (nglyphs--)
1047 _farnspokeb (offset, ScreenAttrib);
1048 offset += 2;
1050 if (screen_virtual_segment)
1051 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1052 mouse_on ();
1054 else
1056 /* We are removing a previously-drawn mouse highlight. The
1057 safest way to do so is to redraw the glyphs anew, since
1058 all kinds of faces and display tables could have changed
1059 behind our back. */
1060 int nglyphs = end_hpos - start_hpos;
1061 int save_x = new_pos_X, save_y = new_pos_Y;
1063 if (end_hpos >= row->used[TEXT_AREA])
1064 nglyphs = row->used[TEXT_AREA] - start_hpos;
1066 /* IT_write_glyphs writes at cursor position, so we need to
1067 temporarily move cursor coordinates to the beginning of
1068 the highlight region. */
1069 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1070 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1072 if (tty->termscript)
1073 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1074 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1075 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1076 if (tty->termscript)
1077 fputs ("\n", tty->termscript);
1078 new_pos_X = save_x;
1079 new_pos_Y = save_y;
1083 set_cursor_shape:
1084 /* Change the mouse pointer shape. */
1085 IT_set_mouse_pointer (hl);
1088 /* Clear out the mouse-highlighted active region.
1089 Redraw it un-highlighted first. */
1090 static void
1091 clear_mouse_face (struct tty_display_info *dpyinfo)
1093 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1094 show_mouse_face (dpyinfo, 0);
1096 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1097 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1098 dpyinfo->mouse_face_window = Qnil;
1101 /* Find the glyph matrix position of buffer position POS in window W.
1102 *HPOS and *VPOS are set to the positions found. W's current glyphs
1103 must be up to date. If POS is above window start return (0, 0).
1104 If POS is after end of W, return end of last line in W. */
1105 static int
1106 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1108 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1109 int yb = window_text_bottom_y (w);
1110 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1112 while (row->y < yb)
1114 if (row->used[TEXT_AREA])
1115 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1116 else
1117 line_start_position = 0;
1119 if (line_start_position > pos)
1120 break;
1121 /* If the position sought is the end of the buffer,
1122 don't include the blank lines at the bottom of the window. */
1123 else if (line_start_position == pos
1124 && pos == BUF_ZV (XBUFFER (w->buffer)))
1126 maybe_next_line_p = 1;
1127 break;
1129 else if (line_start_position > 0)
1130 best_row = row;
1132 /* Don't overstep the last matrix row, lest we get into the
1133 never-never land... */
1134 if (row->y + 1 >= yb)
1135 break;
1137 ++row;
1140 /* Find the right column within BEST_ROW. */
1141 lastcol = 0;
1142 row = best_row;
1143 for (i = 0; i < row->used[TEXT_AREA]; i++)
1145 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1146 int charpos;
1148 charpos = glyph->charpos;
1149 if (charpos == pos)
1151 *hpos = i;
1152 *vpos = row->y;
1153 return 1;
1155 else if (charpos > pos)
1156 break;
1157 else if (charpos > 0)
1158 lastcol = i;
1161 /* If we're looking for the end of the buffer,
1162 and we didn't find it in the line we scanned,
1163 use the start of the following line. */
1164 if (maybe_next_line_p)
1166 ++row;
1167 lastcol = 0;
1170 *vpos = row->y;
1171 *hpos = lastcol + 1;
1172 return 0;
1175 /* Take proper action when mouse has moved to the mode or top line of
1176 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1177 mode line. X is relative to the start of the text display area of
1178 W, so the width of fringes and scroll bars must be subtracted
1179 to get a position relative to the start of the mode line. */
1180 static void
1181 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1183 struct frame *f = XFRAME (w->frame);
1184 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1185 struct glyph_row *row;
1187 if (mode_line_p)
1188 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1189 else
1190 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1192 if (row->enabled_p)
1194 struct glyph *glyph, *end;
1195 Lisp_Object help, map;
1197 /* Find the glyph under X. */
1198 glyph = (row->glyphs[TEXT_AREA]
1200 /* in case someone implements scroll bars some day... */
1201 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1202 end = glyph + row->used[TEXT_AREA];
1203 if (glyph < end
1204 && STRINGP (glyph->object)
1205 && STRING_INTERVALS (glyph->object)
1206 && glyph->charpos >= 0
1207 && glyph->charpos < SCHARS (glyph->object))
1209 /* If we're on a string with `help-echo' text property,
1210 arrange for the help to be displayed. This is done by
1211 setting the global variable help_echo to the help string. */
1212 help = Fget_text_property (make_number (glyph->charpos),
1213 Qhelp_echo, glyph->object);
1214 if (!NILP (help))
1216 help_echo_string = help;
1217 XSETWINDOW (help_echo_window, w);
1218 help_echo_object = glyph->object;
1219 help_echo_pos = glyph->charpos;
1225 /* Take proper action when the mouse has moved to position X, Y on
1226 frame F as regards highlighting characters that have mouse-face
1227 properties. Also de-highlighting chars where the mouse was before.
1228 X and Y can be negative or out of range. */
1229 static void
1230 IT_note_mouse_highlight (struct frame *f, int x, int y)
1232 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1233 enum window_part part = ON_NOTHING;
1234 Lisp_Object window;
1235 struct window *w;
1237 /* When a menu is active, don't highlight because this looks odd. */
1238 if (mouse_preempted)
1239 return;
1241 if (NILP (Vmouse_highlight)
1242 || !f->glyphs_initialized_p)
1243 return;
1245 dpyinfo->mouse_face_mouse_x = x;
1246 dpyinfo->mouse_face_mouse_y = y;
1247 dpyinfo->mouse_face_mouse_frame = f;
1249 if (dpyinfo->mouse_face_defer)
1250 return;
1252 if (gc_in_progress)
1254 dpyinfo->mouse_face_deferred_gc = 1;
1255 return;
1258 /* Which window is that in? */
1259 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1261 /* If we were displaying active text in another window, clear that. */
1262 if (! EQ (window, dpyinfo->mouse_face_window))
1263 clear_mouse_face (dpyinfo);
1265 /* Not on a window -> return. */
1266 if (!WINDOWP (window))
1267 return;
1269 /* Convert to window-relative coordinates. */
1270 w = XWINDOW (window);
1272 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1274 /* Mouse is on the mode or top line. */
1275 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1276 return;
1279 IT_set_mouse_pointer (0);
1281 /* Are we in a window whose display is up to date?
1282 And verify the buffer's text has not changed. */
1283 if (part == ON_TEXT
1284 && EQ (w->window_end_valid, w->buffer)
1285 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1286 && (XFASTINT (w->last_overlay_modified)
1287 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1289 int pos, i, nrows = w->current_matrix->nrows;
1290 struct glyph_row *row;
1291 struct glyph *glyph;
1293 /* Find the glyph under X/Y. */
1294 glyph = NULL;
1295 if (y >= 0 && y < nrows)
1297 row = MATRIX_ROW (w->current_matrix, y);
1298 /* Give up if some row before the one we are looking for is
1299 not enabled. */
1300 for (i = 0; i <= y; i++)
1301 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1302 break;
1303 if (i > y /* all rows upto and including the one at Y are enabled */
1304 && row->displays_text_p
1305 && x < window_box_width (w, TEXT_AREA))
1307 glyph = row->glyphs[TEXT_AREA];
1308 if (x >= row->used[TEXT_AREA])
1309 glyph = NULL;
1310 else
1312 glyph += x;
1313 if (!BUFFERP (glyph->object))
1314 glyph = NULL;
1319 /* Clear mouse face if X/Y not over text. */
1320 if (glyph == NULL)
1322 clear_mouse_face (dpyinfo);
1323 return;
1326 if (!BUFFERP (glyph->object))
1327 abort ();
1328 pos = glyph->charpos;
1330 /* Check for mouse-face and help-echo. */
1332 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1333 int noverlays, obegv, ozv;
1334 struct buffer *obuf;
1336 /* If we get an out-of-range value, return now; avoid an error. */
1337 if (pos > BUF_Z (XBUFFER (w->buffer)))
1338 return;
1340 /* Make the window's buffer temporarily current for
1341 overlays_at and compute_char_face. */
1342 obuf = current_buffer;
1343 current_buffer = XBUFFER (w->buffer);
1344 obegv = BEGV;
1345 ozv = ZV;
1346 BEGV = BEG;
1347 ZV = Z;
1349 /* Is this char mouse-active or does it have help-echo? */
1350 XSETINT (position, pos);
1352 /* Put all the overlays we want in a vector in overlay_vec. */
1353 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1354 /* Sort overlays into increasing priority order. */
1355 noverlays = sort_overlays (overlay_vec, noverlays, w);
1357 /* Check mouse-face highlighting. */
1358 if (! (EQ (window, dpyinfo->mouse_face_window)
1359 && y >= dpyinfo->mouse_face_beg_row
1360 && y <= dpyinfo->mouse_face_end_row
1361 && (y > dpyinfo->mouse_face_beg_row
1362 || x >= dpyinfo->mouse_face_beg_col)
1363 && (y < dpyinfo->mouse_face_end_row
1364 || x < dpyinfo->mouse_face_end_col
1365 || dpyinfo->mouse_face_past_end)))
1367 /* Clear the display of the old active region, if any. */
1368 clear_mouse_face (dpyinfo);
1370 /* Find highest priority overlay that has a mouse-face prop. */
1371 overlay = Qnil;
1372 for (i = noverlays - 1; i >= 0; --i)
1374 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1375 if (!NILP (mouse_face))
1377 overlay = overlay_vec[i];
1378 break;
1382 /* If no overlay applies, get a text property. */
1383 if (NILP (overlay))
1384 mouse_face = Fget_text_property (position, Qmouse_face,
1385 w->buffer);
1387 /* Handle the overlay case. */
1388 if (! NILP (overlay))
1390 /* Find the range of text around this char that
1391 should be active. */
1392 Lisp_Object before, after;
1393 EMACS_INT ignore;
1395 before = Foverlay_start (overlay);
1396 after = Foverlay_end (overlay);
1397 /* Record this as the current active region. */
1398 fast_find_position (w, XFASTINT (before),
1399 &dpyinfo->mouse_face_beg_col,
1400 &dpyinfo->mouse_face_beg_row);
1401 dpyinfo->mouse_face_past_end
1402 = !fast_find_position (w, XFASTINT (after),
1403 &dpyinfo->mouse_face_end_col,
1404 &dpyinfo->mouse_face_end_row);
1405 dpyinfo->mouse_face_window = window;
1406 dpyinfo->mouse_face_face_id
1407 = face_at_buffer_position (w, pos, 0, 0,
1408 &ignore, pos + 1,
1409 !dpyinfo->mouse_face_hidden,
1410 -1);
1412 /* Display it as active. */
1413 show_mouse_face (dpyinfo, 1);
1415 /* Handle the text property case. */
1416 else if (! NILP (mouse_face))
1418 /* Find the range of text around this char that
1419 should be active. */
1420 Lisp_Object before, after, beginning, end;
1421 EMACS_INT ignore;
1423 beginning = Fmarker_position (w->start);
1424 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1425 - XFASTINT (w->window_end_pos)));
1426 before
1427 = Fprevious_single_property_change (make_number (pos + 1),
1428 Qmouse_face,
1429 w->buffer, beginning);
1430 after
1431 = Fnext_single_property_change (position, Qmouse_face,
1432 w->buffer, end);
1433 /* Record this as the current active region. */
1434 fast_find_position (w, XFASTINT (before),
1435 &dpyinfo->mouse_face_beg_col,
1436 &dpyinfo->mouse_face_beg_row);
1437 dpyinfo->mouse_face_past_end
1438 = !fast_find_position (w, XFASTINT (after),
1439 &dpyinfo->mouse_face_end_col,
1440 &dpyinfo->mouse_face_end_row);
1441 dpyinfo->mouse_face_window = window;
1442 dpyinfo->mouse_face_face_id
1443 = face_at_buffer_position (w, pos, 0, 0,
1444 &ignore, pos + 1,
1445 !dpyinfo->mouse_face_hidden,
1446 -1);
1448 /* Display it as active. */
1449 show_mouse_face (dpyinfo, 1);
1453 /* Look for a `help-echo' property. */
1455 Lisp_Object help;
1456 extern Lisp_Object Qhelp_echo;
1458 /* Check overlays first. */
1459 help = Qnil;
1460 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1462 overlay = overlay_vec[i];
1463 help = Foverlay_get (overlay, Qhelp_echo);
1466 if (!NILP (help))
1468 help_echo_string = help;
1469 help_echo_window = window;
1470 help_echo_object = overlay;
1471 help_echo_pos = pos;
1473 /* Try text properties. */
1474 else if (NILP (help)
1475 && ((STRINGP (glyph->object)
1476 && glyph->charpos >= 0
1477 && glyph->charpos < SCHARS (glyph->object))
1478 || (BUFFERP (glyph->object)
1479 && glyph->charpos >= BEGV
1480 && glyph->charpos < ZV)))
1482 help = Fget_text_property (make_number (glyph->charpos),
1483 Qhelp_echo, glyph->object);
1484 if (!NILP (help))
1486 help_echo_string = help;
1487 help_echo_window = window;
1488 help_echo_object = glyph->object;
1489 help_echo_pos = glyph->charpos;
1494 BEGV = obegv;
1495 ZV = ozv;
1496 current_buffer = obuf;
1501 static void
1502 IT_clear_end_of_line (struct frame *f, int first_unused)
1504 char *spaces, *sp;
1505 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1506 extern int fatal_error_in_progress;
1507 struct tty_display_info *tty = FRAME_TTY (f);
1509 if (new_pos_X >= first_unused || fatal_error_in_progress)
1510 return;
1512 IT_set_face (0);
1513 i = (j = first_unused - new_pos_X) * 2;
1514 if (tty->termscript)
1515 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1516 spaces = sp = alloca (i);
1518 while (--j >= 0)
1520 *sp++ = ' ';
1521 *sp++ = ScreenAttrib;
1524 mouse_off_maybe ();
1525 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1526 if (screen_virtual_segment)
1527 dosv_refresh_virtual_screen (offset, i / 2);
1529 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1530 Let's follow their lead, in case someone relies on this. */
1531 new_pos_X = first_unused;
1534 static void
1535 IT_clear_screen (struct frame *f)
1537 struct tty_display_info *tty = FRAME_TTY (f);
1539 if (tty->termscript)
1540 fprintf (tty->termscript, "<CLR:SCR>");
1541 /* We are sometimes called (from clear_garbaged_frames) when a new
1542 frame is being created, but its faces are not yet realized. In
1543 such a case we cannot call IT_set_face, since it will fail to find
1544 any valid faces and will abort. Instead, use the initial screen
1545 colors; that should mimic what a Unix tty does, which simply clears
1546 the screen with whatever default colors are in use. */
1547 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1548 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1549 else
1550 IT_set_face (0);
1551 mouse_off ();
1552 ScreenClear ();
1553 if (screen_virtual_segment)
1554 dosv_refresh_virtual_screen (0, screen_size);
1555 new_pos_X = new_pos_Y = 0;
1558 static void
1559 IT_clear_to_end (struct frame *f)
1561 struct tty_display_info *tty = FRAME_TTY (f);
1563 if (tty->termscript)
1564 fprintf (tty->termscript, "<CLR:EOS>");
1566 while (new_pos_Y < screen_size_Y) {
1567 new_pos_X = 0;
1568 IT_clear_end_of_line (f, screen_size_X);
1569 new_pos_Y++;
1573 static void
1574 IT_cursor_to (struct frame *f, int y, int x)
1576 struct tty_display_info *tty = FRAME_TTY (f);
1578 if (tty->termscript)
1579 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1580 new_pos_X = x;
1581 new_pos_Y = y;
1584 static int cursor_cleared;
1586 static void
1587 IT_display_cursor (int on)
1589 struct tty_display_info *tty = CURTTY ();
1591 if (on && cursor_cleared)
1593 ScreenSetCursor (current_pos_Y, current_pos_X);
1594 cursor_cleared = 0;
1595 if (tty->termscript)
1596 fprintf (tty->termscript, "\nCURSOR ON");
1598 else if (!on && !cursor_cleared)
1600 ScreenSetCursor (-1, -1);
1601 cursor_cleared = 1;
1602 if (tty->termscript)
1603 fprintf (tty->termscript, "\nCURSOR OFF");
1607 /* Emacs calls cursor-movement functions a lot when it updates the
1608 display (probably a legacy of old terminals where you cannot
1609 update a screen line without first moving the cursor there).
1610 However, cursor movement is expensive on MSDOS (it calls a slow
1611 BIOS function and requires 2 mode switches), while actual screen
1612 updates access the video memory directly and don't depend on
1613 cursor position. To avoid slowing down the redisplay, we cheat:
1614 all functions that move the cursor only set internal variables
1615 which record the cursor position, whereas the cursor is only
1616 moved to its final position whenever screen update is complete.
1618 `IT_cmgoto' is called from the keyboard reading loop and when the
1619 frame update is complete. This means that we are ready for user
1620 input, so we update the cursor position to show where the point is,
1621 and also make the mouse pointer visible.
1623 Special treatment is required when the cursor is in the echo area,
1624 to put the cursor at the end of the text displayed there. */
1626 static void
1627 IT_cmgoto (FRAME_PTR f)
1629 /* Only set the cursor to where it should be if the display is
1630 already in sync with the window contents. */
1631 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1632 struct tty_display_info *tty = FRAME_TTY (f);
1634 /* FIXME: This needs to be rewritten for the new redisplay, or
1635 removed. */
1636 #if 0
1637 static int previous_pos_X = -1;
1639 update_cursor_pos = 1; /* temporary!!! */
1641 /* If the display is in sync, forget any previous knowledge about
1642 cursor position. This is primarily for unexpected events like
1643 C-g in the minibuffer. */
1644 if (update_cursor_pos && previous_pos_X >= 0)
1645 previous_pos_X = -1;
1646 /* If we are in the echo area, put the cursor at the
1647 end of the echo area message. */
1648 if (!update_cursor_pos
1649 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1651 int tem_X = current_pos_X, dummy;
1653 if (echo_area_glyphs)
1655 tem_X = echo_area_glyphs_length;
1656 /* Save current cursor position, to be restored after the
1657 echo area message is erased. Only remember one level
1658 of previous cursor position. */
1659 if (previous_pos_X == -1)
1660 ScreenGetCursor (&dummy, &previous_pos_X);
1662 else if (previous_pos_X >= 0)
1664 /* We wind up here after the echo area message is erased.
1665 Restore the cursor position we remembered above. */
1666 tem_X = previous_pos_X;
1667 previous_pos_X = -1;
1670 if (current_pos_X != tem_X)
1672 new_pos_X = tem_X;
1673 update_cursor_pos = 1;
1676 #endif
1678 if (update_cursor_pos
1679 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1681 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1682 if (tty->termscript)
1683 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1686 /* Maybe cursor is invisible, so make it visible. */
1687 IT_display_cursor (1);
1689 /* Mouse pointer should be always visible if we are waiting for
1690 keyboard input. */
1691 if (!mouse_visible)
1692 mouse_on ();
1695 static void
1696 IT_update_begin (struct frame *f)
1698 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1699 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1701 if (display_info->termscript)
1702 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1704 BLOCK_INPUT;
1706 if (f && f == mouse_face_frame)
1708 /* Don't do highlighting for mouse motion during the update. */
1709 display_info->mouse_face_defer = 1;
1711 /* If F needs to be redrawn, simply forget about any prior mouse
1712 highlighting. */
1713 if (FRAME_GARBAGED_P (f))
1714 display_info->mouse_face_window = Qnil;
1716 /* Can we tell that this update does not affect the window
1717 where the mouse highlight is? If so, no need to turn off.
1718 Likewise, don't do anything if none of the enabled rows
1719 contains glyphs highlighted in mouse face. */
1720 if (!NILP (display_info->mouse_face_window)
1721 && WINDOWP (display_info->mouse_face_window))
1723 struct window *w = XWINDOW (display_info->mouse_face_window);
1724 int i;
1726 /* If the mouse highlight is in the window that was deleted
1727 (e.g., if it was popped by completion), clear highlight
1728 unconditionally. */
1729 if (NILP (w->buffer))
1730 display_info->mouse_face_window = Qnil;
1731 else
1733 for (i = 0; i < w->desired_matrix->nrows; ++i)
1734 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1735 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1736 break;
1739 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1740 clear_mouse_face (display_info);
1743 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1745 /* If the frame with mouse highlight was deleted, invalidate the
1746 highlight info. */
1747 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1748 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1749 display_info->mouse_face_window = Qnil;
1750 display_info->mouse_face_deferred_gc = 0;
1751 display_info->mouse_face_mouse_frame = NULL;
1754 UNBLOCK_INPUT;
1757 static void
1758 IT_update_end (struct frame *f)
1760 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1762 if (dpyinfo->termscript)
1763 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1764 dpyinfo->mouse_face_defer = 0;
1767 static void
1768 IT_frame_up_to_date (struct frame *f)
1770 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1771 Lisp_Object new_cursor, frame_desired_cursor;
1772 struct window *sw;
1774 if (dpyinfo->mouse_face_deferred_gc
1775 || (f && f == dpyinfo->mouse_face_mouse_frame))
1777 BLOCK_INPUT;
1778 if (dpyinfo->mouse_face_mouse_frame)
1779 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1780 dpyinfo->mouse_face_mouse_x,
1781 dpyinfo->mouse_face_mouse_y);
1782 dpyinfo->mouse_face_deferred_gc = 0;
1783 UNBLOCK_INPUT;
1786 /* Set the cursor type to whatever they wanted. In a minibuffer
1787 window, we want the cursor to appear only if we are reading input
1788 from this window, and we want the cursor to be taken from the
1789 frame parameters. For the selected window, we use either its
1790 buffer-local value or the value from the frame parameters if the
1791 buffer doesn't define its local value for the cursor type. */
1792 sw = XWINDOW (f->selected_window);
1793 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1794 if (cursor_in_echo_area
1795 && FRAME_HAS_MINIBUF_P (f)
1796 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1797 && sw == XWINDOW (echo_area_window))
1798 new_cursor = frame_desired_cursor;
1799 else
1801 struct buffer *b = XBUFFER (sw->buffer);
1803 if (EQ (b->cursor_type, Qt))
1804 new_cursor = frame_desired_cursor;
1805 else if (NILP (b->cursor_type)) /* nil means no cursor */
1806 new_cursor = Fcons (Qbar, make_number (0));
1807 else
1808 new_cursor = b->cursor_type;
1811 IT_set_cursor_type (f, new_cursor);
1813 IT_cmgoto (f); /* position cursor when update is done */
1816 /* Copy LEN glyphs displayed on a single line whose vertical position
1817 is YPOS, beginning at horizontal position XFROM to horizontal
1818 position XTO, by moving blocks in the video memory. Used by
1819 functions that insert and delete glyphs. */
1820 static void
1821 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1823 /* The offsets of source and destination relative to the
1824 conventional memorty selector. */
1825 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1826 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1828 if (from == to || len <= 0)
1829 return;
1831 _farsetsel (_dos_ds);
1833 /* The source and destination might overlap, so we need to move
1834 glyphs non-destructively. */
1835 if (from > to)
1837 for ( ; len; from += 2, to += 2, len--)
1838 _farnspokew (to, _farnspeekw (from));
1840 else
1842 from += (len - 1) * 2;
1843 to += (len - 1) * 2;
1844 for ( ; len; from -= 2, to -= 2, len--)
1845 _farnspokew (to, _farnspeekw (from));
1847 if (screen_virtual_segment)
1848 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1851 /* Insert and delete glyphs. */
1852 static void
1853 IT_insert_glyphs (struct frame *f, struct glyph *start, int len)
1855 int shift_by_width = screen_size_X - (new_pos_X + len);
1857 /* Shift right the glyphs from the nominal cursor position to the
1858 end of this line. */
1859 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1861 /* Now write the glyphs to be inserted. */
1862 IT_write_glyphs (f, start, len);
1865 static void
1866 IT_delete_glyphs (struct frame *f, int n)
1868 abort ();
1871 /* set-window-configuration on window.c needs this. */
1872 void
1873 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1875 set_menu_bar_lines (f, value, oldval);
1878 /* This was copied from xfaces.c */
1880 extern Lisp_Object Qbackground_color;
1881 extern Lisp_Object Qforeground_color;
1882 Lisp_Object Qreverse;
1883 extern Lisp_Object Qtitle;
1885 /* IT_set_terminal_modes is called when emacs is started,
1886 resumed, and whenever the screen is redrawn! */
1888 static void
1889 IT_set_terminal_modes (struct terminal *term)
1891 struct tty_display_info *tty;
1893 /* If called with initial terminal, it's too early to do anything
1894 useful. */
1895 if (term->type == output_initial)
1896 return;
1898 tty = term->display_info.tty;
1900 if (tty->termscript)
1901 fprintf (tty->termscript, "\n<SET_TERM>");
1903 screen_size_X = ScreenCols ();
1904 screen_size_Y = ScreenRows ();
1905 screen_size = screen_size_X * screen_size_Y;
1907 new_pos_X = new_pos_Y = 0;
1908 current_pos_X = current_pos_Y = -1;
1910 if (term_setup_done)
1911 return;
1912 term_setup_done = 1;
1914 startup_screen_size_X = screen_size_X;
1915 startup_screen_size_Y = screen_size_Y;
1916 startup_screen_attrib = ScreenAttrib;
1918 /* Is DOS/V (or any other RSIS software which relocates
1919 the screen) installed? */
1921 unsigned short es_value;
1922 __dpmi_regs regs;
1924 regs.h.ah = 0xfe; /* get relocated screen address */
1925 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1926 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1927 else if (screen_old_address) /* already switched to Japanese mode once */
1928 regs.x.es = (screen_old_address >> 4) & 0xffff;
1929 else
1930 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1931 regs.x.di = 0;
1932 es_value = regs.x.es;
1933 __dpmi_int (0x10, &regs);
1935 if (regs.x.es != es_value)
1937 /* screen_old_address is only set if ScreenPrimary does NOT
1938 already point to the relocated buffer address returned by
1939 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1940 ScreenPrimary to that address at startup under DOS/V. */
1941 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1942 screen_old_address = ScreenPrimary;
1943 screen_virtual_segment = regs.x.es;
1944 screen_virtual_offset = regs.x.di;
1945 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1949 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1950 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1952 bright_bg ();
1955 /* IT_reset_terminal_modes is called when emacs is
1956 suspended or killed. */
1958 static void
1959 IT_reset_terminal_modes (struct terminal *term)
1961 int display_row_start = (int) ScreenPrimary;
1962 int saved_row_len = startup_screen_size_X * 2;
1963 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1964 int to_next_row = update_row_len;
1965 unsigned char *saved_row = startup_screen_buffer;
1966 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1967 struct tty_display_info *tty = term->display_info.tty;
1969 if (tty->termscript)
1970 fprintf (tty->termscript, "\n<RESET_TERM>");
1972 if (!term_setup_done)
1973 return;
1975 mouse_off ();
1977 /* Leave the video system in the same state as we found it,
1978 as far as the blink/bright-background bit is concerned. */
1979 maybe_enable_blinking ();
1981 /* We have a situation here.
1982 We cannot just do ScreenUpdate(startup_screen_buffer) because
1983 the luser could have changed screen dimensions inside Emacs
1984 and failed (or didn't want) to restore them before killing
1985 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1986 thus will happily use memory outside what was allocated for
1987 `startup_screen_buffer'.
1988 Thus we only restore as much as the current screen dimensions
1989 can hold, and clear the rest (if the saved screen is smaller than
1990 the current) with the color attribute saved at startup. The cursor
1991 is also restored within the visible dimensions. */
1993 ScreenAttrib = startup_screen_attrib;
1995 /* Don't restore the screen if we are exiting less than 2 seconds
1996 after startup: we might be crashing, and the screen might show
1997 some vital clues to what's wrong. */
1998 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2000 ScreenClear ();
2001 if (screen_virtual_segment)
2002 dosv_refresh_virtual_screen (0, screen_size);
2004 if (update_row_len > saved_row_len)
2005 update_row_len = saved_row_len;
2006 if (current_rows > startup_screen_size_Y)
2007 current_rows = startup_screen_size_Y;
2009 if (tty->termscript)
2010 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2011 update_row_len / 2, current_rows);
2013 while (current_rows--)
2015 dosmemput (saved_row, update_row_len, display_row_start);
2016 if (screen_virtual_segment)
2017 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2018 update_row_len / 2);
2019 saved_row += saved_row_len;
2020 display_row_start += to_next_row;
2023 if (startup_pos_X < cursor_pos_X)
2024 cursor_pos_X = startup_pos_X;
2025 if (startup_pos_Y < cursor_pos_Y)
2026 cursor_pos_Y = startup_pos_Y;
2028 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2029 xfree (startup_screen_buffer);
2030 startup_screen_buffer = NULL;
2032 term_setup_done = 0;
2035 static void
2036 IT_set_terminal_window (struct frame *f, int foo)
2040 /* Remember the screen colors of the curent frame, to serve as the
2041 default colors for newly-created frames. */
2042 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2043 Smsdos_remember_default_colors, 1, 1, 0,
2044 doc: /* Remember the screen colors of the current frame. */)
2045 (Lisp_Object frame)
2047 struct frame *f;
2049 CHECK_FRAME (frame);
2050 f = XFRAME (frame);
2052 /* This function is called after applying default-frame-alist to the
2053 initial frame. At that time, if reverse-colors option was
2054 specified in default-frame-alist, it was already applied, and
2055 frame colors are reversed. */
2056 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2057 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2060 void
2061 IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
2063 Lisp_Object tail;
2064 int i, j, length = XINT (Flength (alist));
2065 Lisp_Object *parms
2066 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2067 Lisp_Object *values
2068 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2069 /* Do we have to reverse the foreground and background colors? */
2070 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2071 int redraw = 0, fg_set = 0, bg_set = 0;
2072 unsigned long orig_fg, orig_bg;
2073 Lisp_Object frame_bg, frame_fg;
2074 struct tty_display_info *tty = FRAME_TTY (f);
2076 /* If we are creating a new frame, begin with the original screen colors
2077 used for the initial frame. */
2078 if (!f->default_face_done_p
2079 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2081 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2082 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2083 init_frame_faces (f);
2084 f->default_face_done_p = 1;
2086 orig_fg = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
2087 orig_bg = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
2089 /* Extract parm names and values into those vectors. */
2090 i = 0;
2091 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2093 Lisp_Object elt;
2095 elt = Fcar (tail);
2096 parms[i] = Fcar (elt);
2097 CHECK_SYMBOL (parms[i]);
2098 values[i] = Fcdr (elt);
2099 i++;
2102 j = i;
2104 for (i = 0; i < j; i++)
2106 Lisp_Object prop, val;
2108 prop = parms[i];
2109 val = values[i];
2111 if (EQ (prop, Qreverse))
2112 reverse = EQ (val, Qt);
2115 if (tty->termscript && reverse)
2116 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2118 /* Now process the alist elements in reverse of specified order. */
2119 for (i--; i >= 0; i--)
2121 Lisp_Object prop, val;
2123 prop = parms[i];
2124 val = values[i];
2126 if (EQ (prop, Qforeground_color))
2128 unsigned long new_color = load_color (f, NULL, val, reverse
2129 ? LFACE_BACKGROUND_INDEX
2130 : LFACE_FOREGROUND_INDEX);
2131 if (new_color != FACE_TTY_DEFAULT_COLOR
2132 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2133 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2135 if (!reverse)
2137 FRAME_FOREGROUND_PIXEL (f) = new_color;
2138 /* Make sure the foreground of the default face for
2139 this frame is changed as well. */
2140 update_face_from_frame_parameter (f, Qforeground_color, val);
2141 fg_set = 1;
2142 if (tty->termscript)
2143 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2145 else
2147 FRAME_BACKGROUND_PIXEL (f) = new_color;
2148 update_face_from_frame_parameter (f, Qbackground_color, val);
2149 bg_set = 1;
2150 if (tty->termscript)
2151 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2153 redraw = 1;
2156 else if (EQ (prop, Qbackground_color))
2158 unsigned long new_color = load_color (f, NULL, val, reverse
2159 ? LFACE_FOREGROUND_INDEX
2160 : LFACE_BACKGROUND_INDEX);
2161 if (new_color != FACE_TTY_DEFAULT_COLOR
2162 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2163 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2165 if (!reverse)
2167 FRAME_BACKGROUND_PIXEL (f) = new_color;
2168 /* Make sure the background of the default face for
2169 this frame is changed as well. */
2170 bg_set = 1;
2171 update_face_from_frame_parameter (f, Qbackground_color, val);
2172 if (tty->termscript)
2173 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2175 else
2177 FRAME_FOREGROUND_PIXEL (f) = new_color;
2178 fg_set = 1;
2179 update_face_from_frame_parameter (f, Qforeground_color, val);
2180 if (tty->termscript)
2181 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2183 redraw = 1;
2186 else if (EQ (prop, Qtitle))
2188 x_set_title (f, val);
2189 if (tty->termscript)
2190 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2192 else if (EQ (prop, Qcursor_type))
2194 IT_set_cursor_type (f, val);
2195 if (tty->termscript)
2196 fprintf (tty->termscript, "<CTYPE: %s>\n",
2197 EQ (val, Qbar) || EQ (val, Qhbar)
2198 || CONSP (val) && (EQ (XCAR (val), Qbar)
2199 || EQ (XCAR (val), Qhbar))
2200 ? "bar" : "box");
2202 else if (EQ (prop, Qtty_type))
2204 internal_terminal_init ();
2205 if (tty->termscript)
2206 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2207 SBYTES (val), SDATA (val));
2209 store_frame_param (f, prop, val);
2212 /* If they specified "reverse", but not the colors, we need to swap
2213 the current frame colors. */
2214 if (reverse)
2216 Lisp_Object frame;
2218 if (!fg_set)
2220 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
2221 update_face_from_frame_parameter (f, Qforeground_color,
2222 tty_color_name (f, orig_bg));
2223 redraw = 1;
2225 if (!bg_set)
2227 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
2228 update_face_from_frame_parameter (f, Qbackground_color,
2229 tty_color_name (f, orig_fg));
2230 redraw = 1;
2234 if (redraw)
2236 face_change_count++; /* forces xdisp.c to recompute basic faces */
2237 if (f == SELECTED_FRAME())
2238 redraw_frame (f);
2242 extern void init_frame_faces (FRAME_PTR);
2244 #endif /* !HAVE_X_WINDOWS */
2247 /* Do we need the internal terminal? */
2249 void
2250 internal_terminal_init (void)
2252 static int init_needed = 1;
2253 char *term = getenv ("TERM"), *colors;
2254 struct frame *sf = SELECTED_FRAME();
2255 struct tty_display_info *tty;
2257 #ifdef HAVE_X_WINDOWS
2258 if (!inhibit_window_system)
2259 return;
2260 #endif
2262 /* If this is the initial terminal, we are done here. */
2263 if (sf->output_method == output_initial)
2264 return;
2266 internal_terminal
2267 = (!noninteractive) && term && !strcmp (term, "internal");
2269 #ifndef HAVE_X_WINDOWS
2270 if (!internal_terminal || inhibit_window_system)
2272 sf->output_method = output_termcap;
2273 return;
2276 tty = FRAME_TTY (sf);
2277 current_kboard->Vwindow_system = Qpc;
2278 sf->output_method = output_msdos_raw;
2279 if (init_needed)
2281 if (!tty->termscript && getenv ("EMACSTEST"))
2282 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2283 if (tty->termscript)
2285 time_t now = time (NULL);
2286 struct tm *tnow = localtime (&now);
2287 char tbuf[100];
2289 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2290 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2291 fprintf (tty->termscript, "=====================\n\n");
2294 Vinitial_window_system = Qpc;
2295 Vwindow_system_version = make_number (23); /* RE Emacs version */
2296 tty->terminal->type = output_msdos_raw;
2298 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2299 address. */
2300 screen_old_address = 0;
2302 /* Forget the stale screen colors as well. */
2303 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2305 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2306 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2307 bright_bg ();
2308 colors = getenv ("EMACSCOLORS");
2309 if (colors && strlen (colors) >= 2)
2311 /* The colors use 4 bits each (we enable bright background). */
2312 if (isdigit (colors[0]))
2313 colors[0] -= '0';
2314 else if (isxdigit (colors[0]))
2315 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2316 if (colors[0] >= 0 && colors[0] < 16)
2317 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2318 if (isdigit (colors[1]))
2319 colors[1] -= '0';
2320 else if (isxdigit (colors[1]))
2321 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2322 if (colors[1] >= 0 && colors[1] < 16)
2323 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2325 the_only_display_info.mouse_face_mouse_frame = NULL;
2326 the_only_display_info.mouse_face_deferred_gc = 0;
2327 the_only_display_info.mouse_face_beg_row =
2328 the_only_display_info.mouse_face_beg_col = -1;
2329 the_only_display_info.mouse_face_end_row =
2330 the_only_display_info.mouse_face_end_col = -1;
2331 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2332 the_only_display_info.mouse_face_window = Qnil;
2333 the_only_display_info.mouse_face_mouse_x =
2334 the_only_display_info.mouse_face_mouse_y = 0;
2335 the_only_display_info.mouse_face_defer = 0;
2336 the_only_display_info.mouse_face_hidden = 0;
2338 if (have_mouse) /* detected in dos_ttraw, which see */
2340 have_mouse = 1; /* enable mouse */
2341 mouse_visible = 0;
2342 mouse_setup_buttons (mouse_button_count);
2343 tty->terminal->mouse_position_hook = &mouse_get_pos;
2344 mouse_init ();
2347 if (tty->termscript && screen_size)
2348 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2349 screen_size_X, screen_size_Y);
2351 init_frame_faces (sf);
2352 init_needed = 0;
2354 #endif
2357 void
2358 initialize_msdos_display (struct terminal *term)
2360 term->rif = 0; /* we don't support window-based display */
2361 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2362 term->clear_to_end_hook = IT_clear_to_end;
2363 term->clear_frame_hook = IT_clear_screen;
2364 term->clear_end_of_line_hook = IT_clear_end_of_line;
2365 term->ins_del_lines_hook = 0;
2366 term->insert_glyphs_hook = IT_insert_glyphs;
2367 term->write_glyphs_hook = IT_write_glyphs;
2368 term->delete_glyphs_hook = IT_delete_glyphs;
2369 term->ring_bell_hook = IT_ring_bell;
2370 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2371 term->set_terminal_modes_hook = IT_set_terminal_modes;
2372 term->set_terminal_window_hook = IT_set_terminal_window;
2373 term->update_begin_hook = IT_update_begin;
2374 term->update_end_hook = IT_update_end;
2375 term->frame_up_to_date_hook = IT_frame_up_to_date;
2376 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2377 term->frame_rehighlight_hook = 0;
2378 term->frame_raise_lower_hook = 0;
2379 term->set_vertical_scroll_bar_hook = 0;
2380 term->condemn_scroll_bars_hook = 0;
2381 term->redeem_scroll_bar_hook = 0;
2382 term->judge_scroll_bars_hook = 0;
2383 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2387 dos_get_saved_screen (char **screen, int *rows, int *cols)
2389 #ifndef HAVE_X_WINDOWS
2390 *screen = startup_screen_buffer;
2391 *cols = startup_screen_size_X;
2392 *rows = startup_screen_size_Y;
2393 return *screen != (char *)0;
2394 #else
2395 return 0;
2396 #endif
2399 #ifndef HAVE_X_WINDOWS
2401 /* We are not X, but we can emulate it well enough for our needs... */
2402 void
2403 check_x (void)
2405 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2406 error ("Not running under a window system");
2409 #endif
2412 /* ----------------------- Keyboard control ----------------------
2414 * Keymaps reflect the following keyboard layout:
2416 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2417 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2418 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2419 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2420 * SPACE
2423 #define Ignore 0x0000
2424 #define Normal 0x0000 /* normal key - alt changes scan-code */
2425 #define FctKey 0x1000 /* func key if c == 0, else c */
2426 #define Special 0x2000 /* func key even if c != 0 */
2427 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2428 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2429 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2430 #define Grey 0x6000 /* Grey keypad key */
2432 #define Alt 0x0100 /* alt scan-code */
2433 #define Ctrl 0x0200 /* ctrl scan-code */
2434 #define Shift 0x0400 /* shift scan-code */
2436 static int extended_kbd; /* 101 (102) keyboard present. */
2438 struct kbd_translate {
2439 unsigned char sc;
2440 unsigned char ch;
2441 unsigned short code;
2444 struct dos_keyboard_map
2446 char *unshifted;
2447 char *shifted;
2448 char *alt_gr;
2449 struct kbd_translate *translate_table;
2453 static struct dos_keyboard_map us_keyboard = {
2454 /* 0 1 2 3 4 5 */
2455 /* 01234567890123456789012345678901234567890 12345678901234 */
2456 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2457 /* 0123456789012345678901234567890123456789 012345678901234 */
2458 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2459 0, /* no Alt-Gr key */
2460 0 /* no translate table */
2463 static struct dos_keyboard_map fr_keyboard = {
2464 /* 0 1 2 3 4 5 */
2465 /* 012 3456789012345678901234567890123456789012345678901234 */
2466 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2467 /* 0123456789012345678901234567890123456789012345678901234 */
2468 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2469 /* 01234567 89012345678901234567890123456789012345678901234 */
2470 " ~#{[|`\\^@]} Ï ",
2471 0 /* no translate table */
2475 * Italian keyboard support, country code 39.
2476 * '<' 56:3c*0000
2477 * '>' 56:3e*0000
2478 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2479 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2482 static struct kbd_translate it_kbd_translate_table[] = {
2483 { 0x56, 0x3c, Normal | 13 },
2484 { 0x56, 0x3e, Normal | 27 },
2485 { 0, 0, 0 }
2487 static struct dos_keyboard_map it_keyboard = {
2488 /* 0 1 2 3 4 5 */
2489 /* 0 123456789012345678901234567890123456789012345678901234 */
2490 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2491 /* 01 23456789012345678901234567890123456789012345678901234 */
2492 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2493 /* 0123456789012345678901234567890123456789012345678901234 */
2494 " {}~` [] @# ",
2495 it_kbd_translate_table
2498 static struct dos_keyboard_map dk_keyboard = {
2499 /* 0 1 2 3 4 5 */
2500 /* 0123456789012345678901234567890123456789012345678901234 */
2501 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2502 /* 01 23456789012345678901234567890123456789012345678901234 */
2503 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2504 /* 0123456789012345678901234567890123456789012345678901234 */
2505 " @œ$ {[]} | ",
2506 0 /* no translate table */
2509 static struct kbd_translate jp_kbd_translate_table[] = {
2510 { 0x73, 0x5c, Normal | 0 },
2511 { 0x73, 0x5f, Normal | 0 },
2512 { 0x73, 0x1c, Map | 0 },
2513 { 0x7d, 0x5c, Normal | 13 },
2514 { 0x7d, 0x7c, Normal | 13 },
2515 { 0x7d, 0x1c, Map | 13 },
2516 { 0, 0, 0 }
2518 static struct dos_keyboard_map jp_keyboard = {
2519 /* 0 1 2 3 4 5 */
2520 /* 0123456789012 345678901234567890123456789012345678901234 */
2521 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2522 /* 01 23456789012345678901234567890123456789012345678901234 */
2523 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2524 0, /* no Alt-Gr key */
2525 jp_kbd_translate_table
2528 static struct keyboard_layout_list
2530 int country_code;
2531 struct dos_keyboard_map *keyboard_map;
2532 } keyboard_layout_list[] =
2534 1, &us_keyboard,
2535 33, &fr_keyboard,
2536 39, &it_keyboard,
2537 45, &dk_keyboard,
2538 81, &jp_keyboard
2541 static struct dos_keyboard_map *keyboard;
2542 static int keyboard_map_all;
2543 static int international_keyboard;
2546 dos_set_keyboard (int code, int always)
2548 int i;
2549 _go32_dpmi_registers regs;
2551 /* See if Keyb.Com is installed (for international keyboard support).
2552 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2553 of Windows 9X! So don't do that! */
2554 regs.x.ax = 0xad80;
2555 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2556 _go32_dpmi_simulate_int (0x2f, &regs);
2557 if (regs.h.al == 0xff)
2558 international_keyboard = 1;
2560 /* Initialize to US settings, for countries that don't have their own. */
2561 keyboard = keyboard_layout_list[0].keyboard_map;
2562 keyboard_map_all = always;
2563 dos_keyboard_layout = 1;
2565 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2566 if (code == keyboard_layout_list[i].country_code)
2568 keyboard = keyboard_layout_list[i].keyboard_map;
2569 keyboard_map_all = always;
2570 dos_keyboard_layout = code;
2571 return 1;
2573 return 0;
2576 static struct
2578 unsigned char char_code; /* normal code */
2579 unsigned char meta_code; /* M- code */
2580 unsigned char keypad_code; /* keypad code */
2581 unsigned char editkey_code; /* edit key */
2582 } keypad_translate_map[] = {
2583 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2584 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2585 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2586 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2587 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2588 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2589 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2590 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2591 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2592 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2593 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2596 static struct
2598 unsigned char char_code; /* normal code */
2599 unsigned char keypad_code; /* keypad code */
2600 } grey_key_translate_map[] = {
2601 '/', 0xaf, /* kp-decimal */
2602 '*', 0xaa, /* kp-multiply */
2603 '-', 0xad, /* kp-subtract */
2604 '+', 0xab, /* kp-add */
2605 '\r', 0x8d /* kp-enter */
2608 static unsigned short
2609 ibmpc_translate_map[] =
2611 /* --------------- 00 to 0f --------------- */
2612 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2613 Alt | ModFct | 0x1b, /* Escape */
2614 Normal | 1, /* '1' */
2615 Normal | 2, /* '2' */
2616 Normal | 3, /* '3' */
2617 Normal | 4, /* '4' */
2618 Normal | 5, /* '5' */
2619 Normal | 6, /* '6' */
2620 Normal | 7, /* '7' */
2621 Normal | 8, /* '8' */
2622 Normal | 9, /* '9' */
2623 Normal | 10, /* '0' */
2624 Normal | 11, /* '-' */
2625 Normal | 12, /* '=' */
2626 Special | 0x08, /* Backspace */
2627 ModFct | 0x74, /* Tab/Backtab */
2629 /* --------------- 10 to 1f --------------- */
2630 Map | 15, /* 'q' */
2631 Map | 16, /* 'w' */
2632 Map | 17, /* 'e' */
2633 Map | 18, /* 'r' */
2634 Map | 19, /* 't' */
2635 Map | 20, /* 'y' */
2636 Map | 21, /* 'u' */
2637 Map | 22, /* 'i' */
2638 Map | 23, /* 'o' */
2639 Map | 24, /* 'p' */
2640 Map | 25, /* '[' */
2641 Map | 26, /* ']' */
2642 ModFct | 0x0d, /* Return */
2643 Ignore, /* Ctrl */
2644 Map | 30, /* 'a' */
2645 Map | 31, /* 's' */
2647 /* --------------- 20 to 2f --------------- */
2648 Map | 32, /* 'd' */
2649 Map | 33, /* 'f' */
2650 Map | 34, /* 'g' */
2651 Map | 35, /* 'h' */
2652 Map | 36, /* 'j' */
2653 Map | 37, /* 'k' */
2654 Map | 38, /* 'l' */
2655 Map | 39, /* ';' */
2656 Map | 40, /* '\'' */
2657 Map | 0, /* '`' */
2658 Ignore, /* Left shift */
2659 Map | 41, /* '\\' */
2660 Map | 45, /* 'z' */
2661 Map | 46, /* 'x' */
2662 Map | 47, /* 'c' */
2663 Map | 48, /* 'v' */
2665 /* --------------- 30 to 3f --------------- */
2666 Map | 49, /* 'b' */
2667 Map | 50, /* 'n' */
2668 Map | 51, /* 'm' */
2669 Map | 52, /* ',' */
2670 Map | 53, /* '.' */
2671 Map | 54, /* '/' */
2672 Ignore, /* Right shift */
2673 Grey | 1, /* Grey * */
2674 Ignore, /* Alt */
2675 Normal | 55, /* ' ' */
2676 Ignore, /* Caps Lock */
2677 FctKey | 0xbe, /* F1 */
2678 FctKey | 0xbf, /* F2 */
2679 FctKey | 0xc0, /* F3 */
2680 FctKey | 0xc1, /* F4 */
2681 FctKey | 0xc2, /* F5 */
2683 /* --------------- 40 to 4f --------------- */
2684 FctKey | 0xc3, /* F6 */
2685 FctKey | 0xc4, /* F7 */
2686 FctKey | 0xc5, /* F8 */
2687 FctKey | 0xc6, /* F9 */
2688 FctKey | 0xc7, /* F10 */
2689 Ignore, /* Num Lock */
2690 Ignore, /* Scroll Lock */
2691 KeyPad | 7, /* Home */
2692 KeyPad | 8, /* Up */
2693 KeyPad | 9, /* Page Up */
2694 Grey | 2, /* Grey - */
2695 KeyPad | 4, /* Left */
2696 KeyPad | 5, /* Keypad 5 */
2697 KeyPad | 6, /* Right */
2698 Grey | 3, /* Grey + */
2699 KeyPad | 1, /* End */
2701 /* --------------- 50 to 5f --------------- */
2702 KeyPad | 2, /* Down */
2703 KeyPad | 3, /* Page Down */
2704 KeyPad | 0, /* Insert */
2705 KeyPad | 10, /* Delete */
2706 Shift | FctKey | 0xbe, /* (Shift) F1 */
2707 Shift | FctKey | 0xbf, /* (Shift) F2 */
2708 Shift | FctKey | 0xc0, /* (Shift) F3 */
2709 Shift | FctKey | 0xc1, /* (Shift) F4 */
2710 Shift | FctKey | 0xc2, /* (Shift) F5 */
2711 Shift | FctKey | 0xc3, /* (Shift) F6 */
2712 Shift | FctKey | 0xc4, /* (Shift) F7 */
2713 Shift | FctKey | 0xc5, /* (Shift) F8 */
2714 Shift | FctKey | 0xc6, /* (Shift) F9 */
2715 Shift | FctKey | 0xc7, /* (Shift) F10 */
2716 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2717 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2719 /* --------------- 60 to 6f --------------- */
2720 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2721 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2722 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2723 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2724 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2725 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2726 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2727 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2728 Alt | FctKey | 0xbe, /* (Alt) F1 */
2729 Alt | FctKey | 0xbf, /* (Alt) F2 */
2730 Alt | FctKey | 0xc0, /* (Alt) F3 */
2731 Alt | FctKey | 0xc1, /* (Alt) F4 */
2732 Alt | FctKey | 0xc2, /* (Alt) F5 */
2733 Alt | FctKey | 0xc3, /* (Alt) F6 */
2734 Alt | FctKey | 0xc4, /* (Alt) F7 */
2735 Alt | FctKey | 0xc5, /* (Alt) F8 */
2737 /* --------------- 70 to 7f --------------- */
2738 Alt | FctKey | 0xc6, /* (Alt) F9 */
2739 Alt | FctKey | 0xc7, /* (Alt) F10 */
2740 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2741 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2742 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2743 Ctrl | KeyPad | 1, /* (Ctrl) End */
2744 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2745 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2746 Alt | Map | 1, /* '1' */
2747 Alt | Map | 2, /* '2' */
2748 Alt | Map | 3, /* '3' */
2749 Alt | Map | 4, /* '4' */
2750 Alt | Map | 5, /* '5' */
2751 Alt | Map | 6, /* '6' */
2752 Alt | Map | 7, /* '7' */
2753 Alt | Map | 8, /* '8' */
2755 /* --------------- 80 to 8f --------------- */
2756 Alt | Map | 9, /* '9' */
2757 Alt | Map | 10, /* '0' */
2758 Alt | Map | 11, /* '-' */
2759 Alt | Map | 12, /* '=' */
2760 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2761 FctKey | 0xc8, /* F11 */
2762 FctKey | 0xc9, /* F12 */
2763 Shift | FctKey | 0xc8, /* (Shift) F11 */
2764 Shift | FctKey | 0xc9, /* (Shift) F12 */
2765 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2766 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2767 Alt | FctKey | 0xc8, /* (Alt) F11 */
2768 Alt | FctKey | 0xc9, /* (Alt) F12 */
2769 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2770 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2771 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2773 /* --------------- 90 to 9f --------------- */
2774 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2775 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2776 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2777 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2778 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2779 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2780 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2781 Alt | FctKey | 0x50, /* (Alt) Home */
2782 Alt | FctKey | 0x52, /* (Alt) Up */
2783 Alt | FctKey | 0x55, /* (Alt) Page Up */
2784 Ignore, /* NO KEY */
2785 Alt | FctKey | 0x51, /* (Alt) Left */
2786 Ignore, /* NO KEY */
2787 Alt | FctKey | 0x53, /* (Alt) Right */
2788 Ignore, /* NO KEY */
2789 Alt | FctKey | 0x57, /* (Alt) End */
2791 /* --------------- a0 to af --------------- */
2792 Alt | KeyPad | 2, /* (Alt) Down */
2793 Alt | KeyPad | 3, /* (Alt) Page Down */
2794 Alt | KeyPad | 0, /* (Alt) Insert */
2795 Alt | KeyPad | 10, /* (Alt) Delete */
2796 Alt | Grey | 0, /* (Alt) Grey / */
2797 Alt | FctKey | 0x09, /* (Alt) Tab */
2798 Alt | Grey | 4 /* (Alt) Keypad Enter */
2801 /* These bit-positions corresponds to values returned by BIOS */
2802 #define SHIFT_P 0x0003 /* two bits! */
2803 #define CTRL_P 0x0004
2804 #define ALT_P 0x0008
2805 #define SCRLOCK_P 0x0010
2806 #define NUMLOCK_P 0x0020
2807 #define CAPSLOCK_P 0x0040
2808 #define ALT_GR_P 0x0800
2809 #define SUPER_P 0x4000 /* pseudo */
2810 #define HYPER_P 0x8000 /* pseudo */
2812 static int
2813 dos_get_modifiers (int *keymask)
2815 union REGS regs;
2816 int mask, modifiers = 0;
2818 /* Calculate modifier bits */
2819 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2820 int86 (0x16, &regs, &regs);
2822 if (!extended_kbd)
2824 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2825 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2827 else
2829 mask = regs.h.al & (SHIFT_P |
2830 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2832 /* Do not break international keyboard support. */
2833 /* When Keyb.Com is loaded, the right Alt key is */
2834 /* used for accessing characters like { and } */
2835 if (regs.h.ah & 2) /* Left ALT pressed ? */
2836 mask |= ALT_P;
2838 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2840 mask |= ALT_GR_P;
2841 if (dos_hyper_key == 1)
2843 mask |= HYPER_P;
2844 modifiers |= hyper_modifier;
2846 else if (dos_super_key == 1)
2848 mask |= SUPER_P;
2849 modifiers |= super_modifier;
2851 else if (!international_keyboard)
2853 /* If Keyb.Com is NOT installed, let Right Alt behave
2854 like the Left Alt. */
2855 mask &= ~ALT_GR_P;
2856 mask |= ALT_P;
2860 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2861 mask |= CTRL_P;
2863 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2865 if (dos_hyper_key == 2)
2867 mask |= HYPER_P;
2868 modifiers |= hyper_modifier;
2870 else if (dos_super_key == 2)
2872 mask |= SUPER_P;
2873 modifiers |= super_modifier;
2875 else
2876 mask |= CTRL_P;
2880 if (mask & SHIFT_P)
2881 modifiers |= shift_modifier;
2882 if (mask & CTRL_P)
2883 modifiers |= ctrl_modifier;
2884 if (mask & ALT_P)
2885 modifiers |= meta_modifier;
2887 if (keymask)
2888 *keymask = mask;
2889 return modifiers;
2892 #define NUM_RECENT_DOSKEYS (100)
2893 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2894 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2895 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2897 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2898 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2899 Each input key receives two values in this vector: first the ASCII code,
2900 and then the scan code. */)
2901 (void)
2903 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2905 if (total_doskeys < NUM_RECENT_DOSKEYS)
2906 return Fvector (total_doskeys, keys);
2907 else
2909 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2910 memcpy (XVECTOR (val)->contents, keys + recent_doskeys_index,
2911 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2912 memcpy (XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2913 keys, recent_doskeys_index * sizeof (Lisp_Object));
2914 return val;
2918 /* Get a char from keyboard. Function keys are put into the event queue. */
2919 static int
2920 dos_rawgetc (void)
2922 struct input_event event;
2923 union REGS regs;
2924 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
2925 EVENT_INIT (event);
2927 #ifndef HAVE_X_WINDOWS
2928 /* Maybe put the cursor where it should be. */
2929 IT_cmgoto (SELECTED_FRAME());
2930 #endif
2932 /* The following condition is equivalent to `kbhit ()', except that
2933 it uses the bios to do its job. This pleases DESQview/X. */
2934 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2935 int86 (0x16, &regs, &regs),
2936 (regs.x.flags & 0x40) == 0)
2938 union REGS regs;
2939 register unsigned char c;
2940 int modifiers, sc, code = -1, mask, kp_mode;
2942 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2943 int86 (0x16, &regs, &regs);
2944 c = regs.h.al;
2945 sc = regs.h.ah;
2947 total_doskeys += 2;
2948 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2949 = make_number (c);
2950 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2951 recent_doskeys_index = 0;
2952 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2953 = make_number (sc);
2954 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2955 recent_doskeys_index = 0;
2957 modifiers = dos_get_modifiers (&mask);
2959 #ifndef HAVE_X_WINDOWS
2960 if (!NILP (Vdos_display_scancodes))
2962 char buf[11];
2963 sprintf (buf, "%02x:%02x*%04x",
2964 (unsigned) (sc&0xff), (unsigned) c, mask);
2965 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2967 #endif
2969 if (sc == 0xe0)
2971 switch (c)
2973 case 10: /* Ctrl Grey Enter */
2974 code = Ctrl | Grey | 4;
2975 break;
2976 case 13: /* Grey Enter */
2977 code = Grey | 4;
2978 break;
2979 case '/': /* Grey / */
2980 code = Grey | 0;
2981 break;
2982 default:
2983 continue;
2985 c = 0;
2987 else
2989 /* Try the keyboard-private translation table first. */
2990 if (keyboard->translate_table)
2992 struct kbd_translate *p = keyboard->translate_table;
2994 while (p->sc)
2996 if (p->sc == sc && p->ch == c)
2998 code = p->code;
2999 break;
3001 p++;
3004 /* If the private table didn't translate it, use the general
3005 one. */
3006 if (code == -1)
3008 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3009 continue;
3010 if ((code = ibmpc_translate_map[sc]) == Ignore)
3011 continue;
3015 if (c == 0)
3017 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3018 Emacs is ready to read a key. Therefore, if they press
3019 `Alt-x' when Emacs is busy, by the time we get to
3020 `dos_get_modifiers', they might have already released the
3021 Alt key, and Emacs gets just `x', which is BAD.
3022 However, for keys with the `Map' property set, the ASCII
3023 code returns zero only if Alt is pressed. So, when we DON'T
3024 have to support international_keyboard, we don't have to
3025 distinguish between the left and right Alt keys, and we
3026 can set the META modifier for any keys with the `Map'
3027 property if they return zero ASCII code (c = 0). */
3028 if ( (code & Alt)
3029 || ( (code & 0xf000) == Map && !international_keyboard))
3030 modifiers |= meta_modifier;
3031 if (code & Ctrl)
3032 modifiers |= ctrl_modifier;
3033 if (code & Shift)
3034 modifiers |= shift_modifier;
3037 switch (code & 0xf000)
3039 case ModFct:
3040 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3041 return c;
3042 c = 0; /* Special */
3044 case FctKey:
3045 if (c != 0)
3046 return c;
3048 case Special:
3049 code |= 0xff00;
3050 break;
3052 case Normal:
3053 if (sc == 0)
3055 if (c == 0) /* ctrl-break */
3056 continue;
3057 return c; /* ALT-nnn */
3059 if (!keyboard_map_all)
3061 if (c != ' ')
3062 return c;
3063 code = c;
3064 break;
3067 case Map:
3068 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3069 if (!keyboard_map_all)
3070 return c;
3072 code &= 0xff;
3073 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3074 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3076 if (mask & SHIFT_P)
3078 code = keyboard->shifted[code];
3079 mask -= SHIFT_P;
3080 modifiers &= ~shift_modifier;
3082 else
3083 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3084 code = keyboard->alt_gr[code];
3085 else
3086 code = keyboard->unshifted[code];
3087 break;
3089 case KeyPad:
3090 code &= 0xff;
3091 if (c == 0xe0) /* edit key */
3092 kp_mode = 3;
3093 else
3094 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3095 kp_mode = dos_keypad_mode & 0x03;
3096 else
3097 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3099 switch (kp_mode)
3101 case 0:
3102 if (code == 10 && dos_decimal_point)
3103 return dos_decimal_point;
3104 return keypad_translate_map[code].char_code;
3106 case 1:
3107 code = 0xff00 | keypad_translate_map[code].keypad_code;
3108 break;
3110 case 2:
3111 code = keypad_translate_map[code].meta_code;
3112 modifiers = meta_modifier;
3113 break;
3115 case 3:
3116 code = 0xff00 | keypad_translate_map[code].editkey_code;
3117 break;
3119 break;
3121 case Grey:
3122 code &= 0xff;
3123 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3124 if (dos_keypad_mode & kp_mode)
3125 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3126 else
3127 code = grey_key_translate_map[code].char_code;
3128 break;
3131 make_event:
3132 if (code == 0)
3133 continue;
3135 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3137 clear_mouse_face (dpyinfo);
3138 dpyinfo->mouse_face_hidden = 1;
3141 if (code >= 0x100)
3142 event.kind = NON_ASCII_KEYSTROKE_EVENT;
3143 else
3144 event.kind = ASCII_KEYSTROKE_EVENT;
3145 event.code = code;
3146 event.modifiers = modifiers;
3147 event.frame_or_window = selected_frame;
3148 event.arg = Qnil;
3149 event.timestamp = event_timestamp ();
3150 kbd_buffer_store_event (&event);
3153 if (have_mouse > 0 && !mouse_preempted)
3155 int but, press, x, y, ok;
3156 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3157 Lisp_Object mouse_window = Qnil;
3159 /* Check for mouse movement *before* buttons. */
3160 mouse_check_moved ();
3162 /* If the mouse moved from the spot of its last sighting, we
3163 might need to update mouse highlight. */
3164 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3166 if (dpyinfo->mouse_face_hidden)
3168 dpyinfo->mouse_face_hidden = 0;
3169 clear_mouse_face (dpyinfo);
3172 /* Generate SELECT_WINDOW_EVENTs when needed. */
3173 if (!NILP (Vmouse_autoselect_window))
3175 mouse_window = window_from_coordinates (SELECTED_FRAME(),
3176 mouse_last_x,
3177 mouse_last_y,
3178 0, 0, 0, 0);
3179 /* A window will be selected only when it is not
3180 selected now, and the last mouse movement event was
3181 not in it. A minibuffer window will be selected iff
3182 it is active. */
3183 if (WINDOWP (mouse_window)
3184 && !EQ (mouse_window, last_mouse_window)
3185 && !EQ (mouse_window, selected_window))
3187 event.kind = SELECT_WINDOW_EVENT;
3188 event.frame_or_window = mouse_window;
3189 event.arg = Qnil;
3190 event.timestamp = event_timestamp ();
3191 kbd_buffer_store_event (&event);
3193 last_mouse_window = mouse_window;
3195 else
3196 last_mouse_window = Qnil;
3198 previous_help_echo_string = help_echo_string;
3199 help_echo_string = help_echo_object = help_echo_window = Qnil;
3200 help_echo_pos = -1;
3201 IT_note_mouse_highlight (SELECTED_FRAME(),
3202 mouse_last_x, mouse_last_y);
3203 /* If the contents of the global variable help_echo has
3204 changed, generate a HELP_EVENT. */
3205 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3207 event.kind = HELP_EVENT;
3208 event.frame_or_window = selected_frame;
3209 event.arg = help_echo_object;
3210 event.x = WINDOWP (help_echo_window)
3211 ? help_echo_window : selected_frame;
3212 event.y = help_echo_string;
3213 event.timestamp = event_timestamp ();
3214 event.code = help_echo_pos;
3215 kbd_buffer_store_event (&event);
3219 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3220 for (press = 0; press < 2; press++)
3222 int button_num = but;
3224 if (press)
3225 ok = mouse_pressed (but, &x, &y);
3226 else
3227 ok = mouse_released (but, &x, &y);
3228 if (ok)
3230 /* Allow a simultaneous press/release of Mouse-1 and
3231 Mouse-2 to simulate Mouse-3 on two-button mice. */
3232 if (mouse_button_count == 2 && but < 2)
3234 int x2, y2; /* don't clobber original coordinates */
3236 /* If only one button is pressed, wait 100 msec and
3237 check again. This way, Speedy Gonzales isn't
3238 punished, while the slow get their chance. */
3239 if (press && mouse_pressed (1-but, &x2, &y2)
3240 || !press && mouse_released (1-but, &x2, &y2))
3241 button_num = 2;
3242 else
3244 delay (100);
3245 if (press && mouse_pressed (1-but, &x2, &y2)
3246 || !press && mouse_released (1-but, &x2, &y2))
3247 button_num = 2;
3251 event.kind = MOUSE_CLICK_EVENT;
3252 event.code = button_num;
3253 event.modifiers = dos_get_modifiers (0)
3254 | (press ? down_modifier : up_modifier);
3255 event.x = make_number (x);
3256 event.y = make_number (y);
3257 event.frame_or_window = selected_frame;
3258 event.arg = Qnil;
3259 event.timestamp = event_timestamp ();
3260 kbd_buffer_store_event (&event);
3265 return -1;
3268 static int prev_get_char = -1;
3270 /* Return 1 if a key is ready to be read without suspending execution. */
3272 dos_keysns (void)
3274 if (prev_get_char != -1)
3275 return 1;
3276 else
3277 return ((prev_get_char = dos_rawgetc ()) != -1);
3280 /* Read a key. Return -1 if no key is ready. */
3282 dos_keyread (void)
3284 if (prev_get_char != -1)
3286 int c = prev_get_char;
3287 prev_get_char = -1;
3288 return c;
3290 else
3291 return dos_rawgetc ();
3294 #ifndef HAVE_X_WINDOWS
3296 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3297 for now.
3299 Actually, I don't know the meaning of all the parameters of the functions
3300 here -- I only know how they are called by xmenu.c. I could of course
3301 grab the nearest Xlib manual (down the hall, second-to-last door on the
3302 left), but I don't think it's worth the effort. */
3304 /* These hold text of the current and the previous menu help messages. */
3305 static char *menu_help_message, *prev_menu_help_message;
3306 /* Pane number and item number of the menu item which generated the
3307 last menu help message. */
3308 static int menu_help_paneno, menu_help_itemno;
3310 static XMenu *
3311 IT_menu_create (void)
3313 XMenu *menu;
3315 menu = (XMenu *) xmalloc (sizeof (XMenu));
3316 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3317 return menu;
3320 /* Allocate some (more) memory for MENU ensuring that there is room for one
3321 for item. */
3323 static void
3324 IT_menu_make_room (XMenu *menu)
3326 if (menu->allocated == 0)
3328 int count = menu->allocated = 10;
3329 menu->text = (char **) xmalloc (count * sizeof (char *));
3330 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3331 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3332 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3334 else if (menu->allocated == menu->count)
3336 int count = menu->allocated = menu->allocated + 10;
3337 menu->text
3338 = (char **) xrealloc (menu->text, count * sizeof (char *));
3339 menu->submenu
3340 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3341 menu->panenumber
3342 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3343 menu->help_text
3344 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3348 /* Search the given menu structure for a given pane number. */
3350 static XMenu *
3351 IT_menu_search_pane (XMenu *menu, int pane)
3353 int i;
3354 XMenu *try;
3356 for (i = 0; i < menu->count; i++)
3357 if (menu->submenu[i])
3359 if (pane == menu->panenumber[i])
3360 return menu->submenu[i];
3361 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3362 return try;
3364 return (XMenu *) 0;
3367 /* Determine how much screen space a given menu needs. */
3369 static void
3370 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3372 int i, h2, w2, maxsubwidth, maxheight;
3374 maxsubwidth = 0;
3375 maxheight = menu->count;
3376 for (i = 0; i < menu->count; i++)
3378 if (menu->submenu[i])
3380 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3381 if (w2 > maxsubwidth) maxsubwidth = w2;
3382 if (i + h2 > maxheight) maxheight = i + h2;
3385 *width = menu->width + maxsubwidth;
3386 *height = maxheight;
3389 /* Display MENU at (X,Y) using FACES. */
3391 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3392 do \
3394 (GLYPH).type = CHAR_GLYPH; \
3395 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3396 (GLYPH).charpos = -1; \
3398 while (0)
3400 static void
3401 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3403 int i, j, face, width, mx, my, enabled, mousehere, row, col;
3404 struct glyph *text, *p;
3405 const unsigned char *q;
3406 struct frame *sf = SELECTED_FRAME();
3408 menu_help_message = NULL;
3410 width = menu->width;
3411 /* We multiply width by 2 to account for possible control characters.
3412 FIXME: cater to non-ASCII characters in menus. */
3413 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3414 ScreenGetCursor (&row, &col);
3415 mouse_get_xy (&mx, &my);
3416 IT_update_begin (sf);
3417 for (i = 0; i < menu->count; i++)
3419 int max_width = width + 2;
3421 IT_cursor_to (sf, y + i, x);
3422 enabled
3423 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3424 mousehere = (y + i == my && x <= mx && mx < x + max_width);
3425 face = faces[enabled + mousehere * 2];
3426 /* The following if clause means that we display the menu help
3427 strings even if the menu item is currently disabled. */
3428 if (disp_help && enabled + mousehere * 2 >= 2)
3430 menu_help_message = menu->help_text[i];
3431 menu_help_paneno = pn - 1;
3432 menu_help_itemno = i;
3434 p = text;
3435 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3436 p++;
3437 for (j = 0, q = menu->text[i]; *q; j++)
3439 unsigned c = STRING_CHAR_ADVANCE (q);
3441 if (c > 26)
3443 BUILD_CHAR_GLYPH (*p, c, face, 0);
3444 p++;
3446 else /* make '^x' */
3448 BUILD_CHAR_GLYPH (*p, '^', face, 0);
3449 p++;
3450 j++;
3451 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3452 p++;
3455 /* Don't let the menu text overflow into the next screen row. */
3456 if (x + max_width > screen_size_X)
3458 max_width = screen_size_X - x;
3459 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3461 for (; j < max_width - 2; j++, p++)
3462 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3464 /* 16 is the character code of a character that on DOS terminal
3465 produces a nice-looking right-pointing arrow glyph. */
3466 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3467 p++;
3468 IT_write_glyphs (sf, text, max_width);
3470 IT_update_end (sf);
3471 IT_cursor_to (sf, row, col);
3472 xfree (text);
3475 /* --------------------------- X Menu emulation ---------------------- */
3477 /* Report availability of menus. */
3480 have_menus_p (void) { return 1; }
3482 /* Create a brand new menu structure. */
3484 XMenu *
3485 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3487 return IT_menu_create ();
3490 /* Create a new pane and place it on the outer-most level. It is not
3491 clear that it should be placed out there, but I don't know what else
3492 to do. */
3495 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3497 int len;
3498 char *p;
3500 if (!enable)
3501 abort ();
3503 IT_menu_make_room (menu);
3504 menu->submenu[menu->count] = IT_menu_create ();
3505 menu->text[menu->count] = txt;
3506 menu->panenumber[menu->count] = ++menu->panecount;
3507 menu->help_text[menu->count] = NULL;
3508 menu->count++;
3510 /* Adjust length for possible control characters (which will
3511 be written as ^x). */
3512 for (len = strlen (txt), p = txt; *p; p++)
3513 if (*p < 27)
3514 len++;
3516 if (len > menu->width)
3517 menu->width = len;
3519 return menu->panecount;
3522 /* Create a new item in a menu pane. */
3525 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3526 int foo, char *txt, int enable, char *help_text)
3528 int len;
3529 char *p;
3531 if (pane)
3532 if (!(menu = IT_menu_search_pane (menu, pane)))
3533 return XM_FAILURE;
3534 IT_menu_make_room (menu);
3535 menu->submenu[menu->count] = (XMenu *) 0;
3536 menu->text[menu->count] = txt;
3537 menu->panenumber[menu->count] = enable;
3538 menu->help_text[menu->count] = help_text;
3539 menu->count++;
3541 /* Adjust length for possible control characters (which will
3542 be written as ^x). */
3543 for (len = strlen (txt), p = txt; *p; p++)
3544 if (*p < 27)
3545 len++;
3547 if (len > menu->width)
3548 menu->width = len;
3550 return XM_SUCCESS;
3553 /* Decide where the menu would be placed if requested at (X,Y). */
3555 void
3556 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3557 int *ulx, int *uly, int *width, int *height)
3559 IT_menu_calc_size (menu, width, height);
3560 *ulx = x + 1;
3561 *uly = y;
3562 *width += 2;
3565 struct IT_menu_state
3567 void *screen_behind;
3568 XMenu *menu;
3569 int pane;
3570 int x, y;
3574 /* Display menu, wait for user's response, and return that response. */
3577 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3578 int x0, int y0, unsigned ButtonMask, char **txt,
3579 void (*help_callback)(char *, int, int))
3581 struct IT_menu_state *state;
3582 int statecount, x, y, i, b, screensize, leave, result, onepane;
3583 int title_faces[4]; /* face to display the menu title */
3584 int faces[4], buffers_num_deleted = 0;
3585 struct frame *sf = SELECTED_FRAME();
3586 Lisp_Object saved_echo_area_message, selectface;
3588 /* Just in case we got here without a mouse present... */
3589 if (have_mouse <= 0)
3590 return XM_IA_SELECT;
3591 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3592 around the display. */
3593 if (x0 <= 0)
3594 x0 = 1;
3595 if (y0 <= 0)
3596 y0 = 1;
3598 /* We will process all the mouse events directly, so we had
3599 better prevent dos_rawgetc from stealing them from us. */
3600 mouse_preempted++;
3602 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3603 screensize = screen_size * 2;
3604 faces[0]
3605 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3606 DEFAULT_FACE_ID, 1);
3607 faces[1]
3608 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3609 DEFAULT_FACE_ID, 1);
3610 selectface = intern ("msdos-menu-select-face");
3611 faces[2] = lookup_derived_face (sf, selectface,
3612 faces[0], 1);
3613 faces[3] = lookup_derived_face (sf, selectface,
3614 faces[1], 1);
3616 /* Make sure the menu title is always displayed with
3617 `msdos-menu-active-face', no matter where the mouse pointer is. */
3618 for (i = 0; i < 4; i++)
3619 title_faces[i] = faces[3];
3621 statecount = 1;
3623 /* Don't let the title for the "Buffers" popup menu include a
3624 digit (which is ugly).
3626 This is a terrible kludge, but I think the "Buffers" case is
3627 the only one where the title includes a number, so it doesn't
3628 seem to be necessary to make this more general. */
3629 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3631 menu->text[0][7] = '\0';
3632 buffers_num_deleted = 1;
3635 /* We need to save the current echo area message, so that we could
3636 restore it below, before we exit. See the commentary below,
3637 before the call to message_with_string. */
3638 saved_echo_area_message = Fcurrent_message ();
3639 state[0].menu = menu;
3640 mouse_off ();
3641 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3643 /* Turn off the cursor. Otherwise it shows through the menu
3644 panes, which is ugly. */
3645 IT_display_cursor (0);
3647 /* Display the menu title. */
3648 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3649 if (buffers_num_deleted)
3650 menu->text[0][7] = ' ';
3651 if ((onepane = menu->count == 1 && menu->submenu[0]))
3653 menu->width = menu->submenu[0]->width;
3654 state[0].menu = menu->submenu[0];
3656 else
3658 state[0].menu = menu;
3660 state[0].x = x0 - 1;
3661 state[0].y = y0;
3662 state[0].pane = onepane;
3664 mouse_last_x = -1; /* A hack that forces display. */
3665 leave = 0;
3666 while (!leave)
3668 if (!mouse_visible) mouse_on ();
3669 mouse_check_moved ();
3670 if (sf->mouse_moved)
3672 sf->mouse_moved = 0;
3673 result = XM_IA_SELECT;
3674 mouse_get_xy (&x, &y);
3675 for (i = 0; i < statecount; i++)
3676 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3678 int dy = y - state[i].y;
3679 if (0 <= dy && dy < state[i].menu->count)
3681 if (!state[i].menu->submenu[dy])
3682 if (state[i].menu->panenumber[dy])
3683 result = XM_SUCCESS;
3684 else
3685 result = XM_IA_SELECT;
3686 *pane = state[i].pane - 1;
3687 *selidx = dy;
3688 /* We hit some part of a menu, so drop extra menus that
3689 have been opened. That does not include an open and
3690 active submenu. */
3691 if (i != statecount - 2
3692 || state[i].menu->submenu[dy] != state[i+1].menu)
3693 while (i != statecount - 1)
3695 statecount--;
3696 mouse_off ();
3697 ScreenUpdate (state[statecount].screen_behind);
3698 if (screen_virtual_segment)
3699 dosv_refresh_virtual_screen (0, screen_size);
3700 xfree (state[statecount].screen_behind);
3702 if (i == statecount - 1 && state[i].menu->submenu[dy])
3704 IT_menu_display (state[i].menu,
3705 state[i].y,
3706 state[i].x,
3707 state[i].pane,
3708 faces, 1);
3709 state[statecount].menu = state[i].menu->submenu[dy];
3710 state[statecount].pane = state[i].menu->panenumber[dy];
3711 mouse_off ();
3712 ScreenRetrieve (state[statecount].screen_behind
3713 = xmalloc (screensize));
3714 state[statecount].x
3715 = state[i].x + state[i].menu->width + 2;
3716 state[statecount].y = y;
3717 statecount++;
3721 IT_menu_display (state[statecount - 1].menu,
3722 state[statecount - 1].y,
3723 state[statecount - 1].x,
3724 state[statecount - 1].pane,
3725 faces, 1);
3727 else
3729 if ((menu_help_message || prev_menu_help_message)
3730 && menu_help_message != prev_menu_help_message)
3732 help_callback (menu_help_message,
3733 menu_help_paneno, menu_help_itemno);
3734 IT_display_cursor (0);
3735 prev_menu_help_message = menu_help_message;
3737 /* We are busy-waiting for the mouse to move, so let's be nice
3738 to other Windows applications by releasing our time slice. */
3739 __dpmi_yield ();
3741 for (b = 0; b < mouse_button_count && !leave; b++)
3743 /* Only leave if user both pressed and released the mouse, and in
3744 that order. This avoids popping down the menu pane unless
3745 the user is really done with it. */
3746 if (mouse_pressed (b, &x, &y))
3748 while (mouse_button_depressed (b, &x, &y))
3749 __dpmi_yield ();
3750 leave = 1;
3752 (void) mouse_released (b, &x, &y);
3756 mouse_off ();
3757 ScreenUpdate (state[0].screen_behind);
3758 if (screen_virtual_segment)
3759 dosv_refresh_virtual_screen (0, screen_size);
3761 /* We have a situation here. ScreenUpdate has just restored the
3762 screen contents as it was before we started drawing this menu.
3763 That includes any echo area message that could have been
3764 displayed back then. (In reality, that echo area message will
3765 almost always be the ``keystroke echo'' that echoes the sequence
3766 of menu items chosen by the user.) However, if the menu had some
3767 help messages, then displaying those messages caused Emacs to
3768 forget about the original echo area message. So when
3769 ScreenUpdate restored it, it created a discrepancy between the
3770 actual screen contents and what Emacs internal data structures
3771 know about it.
3773 To avoid this conflict, we force Emacs to restore the original
3774 echo area message as we found it when we entered this function.
3775 The irony of this is that we then erase the restored message
3776 right away, so the only purpose of restoring it is so that
3777 erasing it works correctly... */
3778 if (! NILP (saved_echo_area_message))
3779 message_with_string ("%s", saved_echo_area_message, 0);
3780 message (0);
3781 while (statecount--)
3782 xfree (state[statecount].screen_behind);
3783 IT_display_cursor (1); /* turn cursor back on */
3784 /* Clean up any mouse events that are waiting inside Emacs event queue.
3785 These events are likely to be generated before the menu was even
3786 displayed, probably because the user pressed and released the button
3787 (which invoked the menu) too quickly. If we don't remove these events,
3788 Emacs will process them after we return and surprise the user. */
3789 discard_mouse_events ();
3790 mouse_clear_clicks ();
3791 if (!kbd_buffer_events_waiting (1))
3792 clear_input_pending ();
3793 /* Allow mouse events generation by dos_rawgetc. */
3794 mouse_preempted--;
3795 return result;
3798 /* Dispose of a menu. */
3800 void
3801 XMenuDestroy (Display *foo, XMenu *menu)
3803 int i;
3804 if (menu->allocated)
3806 for (i = 0; i < menu->count; i++)
3807 if (menu->submenu[i])
3808 XMenuDestroy (foo, menu->submenu[i]);
3809 xfree (menu->text);
3810 xfree (menu->submenu);
3811 xfree (menu->panenumber);
3812 xfree (menu->help_text);
3814 xfree (menu);
3815 menu_help_message = prev_menu_help_message = NULL;
3819 x_pixel_width (struct frame *f)
3821 return FRAME_COLS (f);
3825 x_pixel_height (struct frame *f)
3827 return FRAME_LINES (f);
3829 #endif /* !HAVE_X_WINDOWS */
3831 /* ----------------------- DOS / UNIX conversion --------------------- */
3833 void msdos_downcase_filename (unsigned char *);
3835 /* Destructively turn backslashes into slashes. */
3837 void
3838 dostounix_filename (char *p)
3840 msdos_downcase_filename (p);
3842 while (*p)
3844 if (*p == '\\')
3845 *p = '/';
3846 p++;
3850 /* Destructively turn slashes into backslashes. */
3852 void
3853 unixtodos_filename (char *p)
3855 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3857 *p += 'a' - 'A';
3858 p += 2;
3861 while (*p)
3863 if (*p == '/')
3864 *p = '\\';
3865 p++;
3869 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3872 getdefdir (int drive, char *dst)
3874 char in_path[4], *p = in_path, e = errno;
3876 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3877 if (drive != 0)
3879 *p++ = drive + 'A' - 1;
3880 *p++ = ':';
3883 *p++ = '.';
3884 *p = '\0';
3885 errno = 0;
3886 _fixpath (in_path, dst);
3887 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3888 it queries the LFN support, so ignore that error. */
3889 if ((errno && errno != ENOSYS) || *dst == '\0')
3890 return 0;
3892 msdos_downcase_filename (dst);
3894 errno = e;
3895 return 1;
3898 char *
3899 emacs_root_dir (void)
3901 static char root_dir[4];
3903 sprintf (root_dir, "%c:/", 'A' + getdisk ());
3904 root_dir[0] = tolower (root_dir[0]);
3905 return root_dir;
3908 /* Remove all CR's that are followed by a LF. */
3911 crlf_to_lf (int n, unsigned char *buf)
3913 unsigned char *np = buf, *startp = buf, *endp = buf + n;
3915 if (n == 0)
3916 return n;
3917 while (buf < endp - 1)
3919 if (*buf == 0x0d)
3921 if (*(++buf) != 0x0a)
3922 *np++ = 0x0d;
3924 else
3925 *np++ = *buf++;
3927 if (buf < endp)
3928 *np++ = *buf++;
3929 return np - startp;
3932 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3933 0, 0, 0,
3934 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
3935 (void)
3937 return (_USE_LFN ? Qt : Qnil);
3940 /* Convert alphabetic characters in a filename to lower-case. */
3942 void
3943 msdos_downcase_filename (unsigned char *p)
3945 /* Always lower-case drive letters a-z, even if the filesystem
3946 preserves case in filenames.
3947 This is so MSDOS filenames could be compared by string comparison
3948 functions that are case-sensitive. Even case-preserving filesystems
3949 do not distinguish case in drive letters. */
3950 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3952 *p += 'a' - 'A';
3953 p += 2;
3956 /* Under LFN we expect to get pathnames in their true case. */
3957 if (NILP (Fmsdos_long_file_names ()))
3958 for ( ; *p; p++)
3959 if (*p >= 'A' && *p <= 'Z')
3960 *p += 'a' - 'A';
3963 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3964 1, 1, 0,
3965 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
3966 When long filenames are supported, doesn't change FILENAME.
3967 If FILENAME is not a string, returns nil.
3968 The argument object is never altered--the value is a copy. */)
3969 (Lisp_Object filename)
3971 Lisp_Object tem;
3973 if (! STRINGP (filename))
3974 return Qnil;
3976 tem = Fcopy_sequence (filename);
3977 msdos_downcase_filename (SDATA (tem));
3978 return tem;
3981 /* The Emacs root directory as determined by init_environment. */
3983 static char emacsroot[MAXPATHLEN];
3985 char *
3986 rootrelativepath (char *rel)
3988 static char result[MAXPATHLEN + 10];
3990 strcpy (result, emacsroot);
3991 strcat (result, "/");
3992 strcat (result, rel);
3993 return result;
3996 /* Define a lot of environment variables if not already defined. Don't
3997 remove anything unless you know what you're doing -- lots of code will
3998 break if one or more of these are missing. */
4000 void
4001 init_environment (int argc, char **argv, int skip_args)
4003 char *s, *t, *root;
4004 int len, i;
4005 static const char * const tempdirs[] = {
4006 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4008 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4010 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4011 temporary files and assume "/tmp" if $TMPDIR is unset, which
4012 will break on DOS/Windows. Refuse to work if we cannot find
4013 a directory, not even "c:/", usable for that purpose. */
4014 for (i = 0; i < imax ; i++)
4016 const char *tmp = tempdirs[i];
4017 char buf[FILENAME_MAX];
4019 if (*tmp == '$')
4021 int tmp_len;
4023 tmp = getenv (tmp + 1);
4024 if (!tmp)
4025 continue;
4027 /* Some lusers set TMPDIR=e:, probably because some losing
4028 programs cannot handle multiple slashes if they use e:/.
4029 e: fails in `access' below, so we interpret e: as e:/. */
4030 tmp_len = strlen(tmp);
4031 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4033 strcpy(buf, tmp);
4034 buf[tmp_len++] = '/', buf[tmp_len] = 0;
4035 tmp = buf;
4039 /* Note that `access' can lie to us if the directory resides on a
4040 read-only filesystem, like CD-ROM or a write-protected floppy.
4041 The only way to be really sure is to actually create a file and
4042 see if it succeeds. But I think that's too much to ask. */
4043 if (tmp && access (tmp, D_OK) == 0)
4045 setenv ("TMPDIR", tmp, 1);
4046 break;
4049 if (i >= imax)
4050 cmd_error_internal
4051 (Fcons (Qerror,
4052 Fcons (build_string ("no usable temporary directories found!!"),
4053 Qnil)),
4054 "While setting TMPDIR: ");
4056 /* Note the startup time, so we know not to clear the screen if we
4057 exit immediately; see IT_reset_terminal_modes.
4058 (Yes, I know `clock' returns zero the first time it's called, but
4059 I do this anyway, in case some wiseguy changes that at some point.) */
4060 startup_time = clock ();
4062 /* Find our root from argv[0]. Assuming argv[0] is, say,
4063 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4064 root = alloca (MAXPATHLEN + 20);
4065 _fixpath (argv[0], root);
4066 msdos_downcase_filename (root);
4067 len = strlen (root);
4068 while (len > 0 && root[len] != '/' && root[len] != ':')
4069 len--;
4070 root[len] = '\0';
4071 if (len > 4
4072 && (strcmp (root + len - 4, "/bin") == 0
4073 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4074 root[len - 4] = '\0';
4075 else
4076 strcpy (root, "c:/emacs"); /* let's be defensive */
4077 len = strlen (root);
4078 strcpy (emacsroot, root);
4080 /* We default HOME to our root. */
4081 setenv ("HOME", root, 0);
4083 /* We default EMACSPATH to root + "/bin". */
4084 strcpy (root + len, "/bin");
4085 setenv ("EMACSPATH", root, 0);
4087 /* I don't expect anybody to ever use other terminals so the internal
4088 terminal is the default. */
4089 setenv ("TERM", "internal", 0);
4091 #ifdef HAVE_X_WINDOWS
4092 /* Emacs expects DISPLAY to be set. */
4093 setenv ("DISPLAY", "unix:0.0", 0);
4094 #endif
4096 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4097 downcase it and mirror the backslashes. */
4098 s = getenv ("COMSPEC");
4099 if (!s) s = "c:/command.com";
4100 t = alloca (strlen (s) + 1);
4101 strcpy (t, s);
4102 dostounix_filename (t);
4103 setenv ("SHELL", t, 0);
4105 /* PATH is also downcased and backslashes mirrored. */
4106 s = getenv ("PATH");
4107 if (!s) s = "";
4108 t = alloca (strlen (s) + 3);
4109 /* Current directory is always considered part of MsDos's path but it is
4110 not normally mentioned. Now it is. */
4111 strcat (strcpy (t, ".;"), s);
4112 dostounix_filename (t); /* Not a single file name, but this should work. */
4113 setenv ("PATH", t, 1);
4115 /* In some sense all dos users have root privileges, so... */
4116 setenv ("USER", "root", 0);
4117 setenv ("NAME", getenv ("USER"), 0);
4119 /* Time zone determined from country code. To make this possible, the
4120 country code may not span more than one time zone. In other words,
4121 in the USA, you lose. */
4122 if (!getenv ("TZ"))
4123 switch (dos_country_code)
4125 case 31: /* Belgium */
4126 case 32: /* The Netherlands */
4127 case 33: /* France */
4128 case 34: /* Spain */
4129 case 36: /* Hungary */
4130 case 38: /* Yugoslavia (or what's left of it?) */
4131 case 39: /* Italy */
4132 case 41: /* Switzerland */
4133 case 42: /* Tjekia */
4134 case 45: /* Denmark */
4135 case 46: /* Sweden */
4136 case 47: /* Norway */
4137 case 48: /* Poland */
4138 case 49: /* Germany */
4139 /* Daylight saving from last Sunday in March to last Sunday in
4140 September, both at 2AM. */
4141 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4142 break;
4143 case 44: /* United Kingdom */
4144 case 351: /* Portugal */
4145 case 354: /* Iceland */
4146 setenv ("TZ", "GMT+00", 0);
4147 break;
4148 case 81: /* Japan */
4149 case 82: /* Korea */
4150 setenv ("TZ", "JST-09", 0);
4151 break;
4152 case 90: /* Turkey */
4153 case 358: /* Finland */
4154 setenv ("TZ", "EET-02", 0);
4155 break;
4156 case 972: /* Israel */
4157 /* This is an approximation. (For exact rules, use the
4158 `zoneinfo/israel' file which comes with DJGPP, but you need
4159 to install it in `/usr/share/zoneinfo/' directory first.) */
4160 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4161 break;
4163 tzset ();
4168 static int break_stat; /* BREAK check mode status. */
4169 static int stdin_stat; /* stdin IOCTL status. */
4171 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4172 control chars by DOS. Determine the keyboard type. */
4175 dos_ttraw (struct tty_display_info *tty)
4177 union REGS inregs, outregs;
4178 static int first_time = 1;
4180 /* If we are called for the initial terminal, it's too early to do
4181 anything, and termscript isn't set up. */
4182 if (tty->terminal->type == output_initial)
4183 return;
4185 break_stat = getcbrk ();
4186 setcbrk (0);
4188 if (first_time)
4190 inregs.h.ah = 0xc0;
4191 int86 (0x15, &inregs, &outregs);
4192 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4194 have_mouse = 0;
4196 if (1
4197 #ifdef HAVE_X_WINDOWS
4198 && inhibit_window_system
4199 #endif
4202 inregs.x.ax = 0x0021;
4203 int86 (0x33, &inregs, &outregs);
4204 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4205 if (!have_mouse)
4207 /* Reportedly, the above doesn't work for some mouse drivers. There
4208 is an additional detection method that should work, but might be
4209 a little slower. Use that as an alternative. */
4210 inregs.x.ax = 0x0000;
4211 int86 (0x33, &inregs, &outregs);
4212 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4214 if (have_mouse)
4215 mouse_button_count = outregs.x.bx;
4217 #ifndef HAVE_X_WINDOWS
4218 /* Save the cursor shape used outside Emacs. */
4219 outside_cursor = _farpeekw (_dos_ds, 0x460);
4220 #endif
4223 first_time = 0;
4225 stdin_stat = setmode (fileno (stdin), O_BINARY);
4226 return (stdin_stat != -1);
4228 else
4229 return (setmode (fileno (stdin), O_BINARY) != -1);
4232 /* Restore status of standard input and Ctrl-C checking. */
4235 dos_ttcooked (void)
4237 union REGS inregs, outregs;
4239 setcbrk (break_stat);
4240 mouse_off ();
4242 #ifndef HAVE_X_WINDOWS
4243 /* Restore the cursor shape we found on startup. */
4244 if (outside_cursor)
4246 inregs.h.ah = 1;
4247 inregs.x.cx = outside_cursor;
4248 int86 (0x10, &inregs, &outregs);
4250 #endif
4252 return (setmode (fileno (stdin), stdin_stat) != -1);
4256 /* Run command as specified by ARGV in directory DIR.
4257 The command is run with input from TEMPIN, output to
4258 file TEMPOUT and stderr to TEMPERR. */
4261 run_msdos_command (unsigned char **argv, const char *working_dir,
4262 int tempin, int tempout, int temperr, char **envv)
4264 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4265 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4266 int msshell, result = -1, inbak, outbak, errbak, x, y;
4267 Lisp_Object cmd;
4269 /* Get current directory as MSDOS cwd is not per-process. */
4270 getwd (oldwd);
4272 /* If argv[0] is the shell, it might come in any lettercase.
4273 Since `Fmember' is case-sensitive, we need to downcase
4274 argv[0], even if we are on case-preserving filesystems. */
4275 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4276 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4278 *pl = *pa++;
4279 if (*pl >= 'A' && *pl <= 'Z')
4280 *pl += 'a' - 'A';
4282 *pl = '\0';
4284 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4285 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4286 && !strcmp ("-c", argv[1]);
4287 if (msshell)
4289 saveargv1 = argv[1];
4290 saveargv2 = argv[2];
4291 argv[1] = "/c";
4292 /* We only need to mirror slashes if a DOS shell will be invoked
4293 not via `system' (which does the mirroring itself). Yes, that
4294 means DJGPP v1.x will lose here. */
4295 if (argv[2] && argv[3])
4297 char *p = alloca (strlen (argv[2]) + 1);
4299 strcpy (argv[2] = p, saveargv2);
4300 while (*p && isspace (*p))
4301 p++;
4302 while (*p)
4304 if (*p == '/')
4305 *p++ = '\\';
4306 else
4307 p++;
4312 chdir (working_dir);
4313 inbak = dup (0);
4314 outbak = dup (1);
4315 errbak = dup (2);
4316 if (inbak < 0 || outbak < 0 || errbak < 0)
4317 goto done; /* Allocation might fail due to lack of descriptors. */
4319 if (have_mouse > 0)
4320 mouse_get_xy (&x, &y);
4322 if (!noninteractive)
4323 dos_ttcooked (); /* do it here while 0 = stdin */
4325 dup2 (tempin, 0);
4326 dup2 (tempout, 1);
4327 dup2 (temperr, 2);
4329 if (msshell && !argv[3])
4331 /* MS-DOS native shells are too restrictive. For starters, they
4332 cannot grok commands longer than 126 characters. In DJGPP v2
4333 and later, `system' is much smarter, so we'll call it instead. */
4335 const char *cmnd;
4337 /* A shell gets a single argument--its full command
4338 line--whose original was saved in `saveargv2'. */
4340 /* Don't let them pass empty command lines to `system', since
4341 with some shells it will try to invoke an interactive shell,
4342 which will hang Emacs. */
4343 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4345 if (*cmnd)
4347 extern char **environ;
4348 char **save_env = environ;
4349 int save_system_flags = __system_flags;
4351 /* Request the most powerful version of `system'. We need
4352 all the help we can get to avoid calling stock DOS shells. */
4353 __system_flags = (__system_redirect
4354 | __system_use_shell
4355 | __system_allow_multiple_cmds
4356 | __system_allow_long_cmds
4357 | __system_handle_null_commands
4358 | __system_emulate_chdir);
4360 environ = envv;
4361 result = system (cmnd);
4362 __system_flags = save_system_flags;
4363 environ = save_env;
4365 else
4366 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4368 else
4369 result = spawnve (P_WAIT, argv[0], argv, envv);
4371 dup2 (inbak, 0);
4372 dup2 (outbak, 1);
4373 dup2 (errbak, 2);
4374 emacs_close (inbak);
4375 emacs_close (outbak);
4376 emacs_close (errbak);
4378 if (!noninteractive)
4379 dos_ttraw (CURTTY ());
4380 if (have_mouse > 0)
4382 mouse_init ();
4383 mouse_moveto (x, y);
4386 /* Some programs might change the meaning of the highest bit of the
4387 text attribute byte, so we get blinking characters instead of the
4388 bright background colors. Restore that. */
4389 if (!noninteractive)
4390 bright_bg ();
4392 done:
4393 chdir (oldwd);
4394 if (msshell)
4396 argv[1] = saveargv1;
4397 argv[2] = saveargv2;
4399 return result;
4402 void
4403 croak (char *badfunc)
4405 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4406 reset_all_sys_modes ();
4407 exit (1);
4411 * A few unimplemented functions that we silently ignore.
4413 int setpgrp (void) {return 0; }
4414 int setpriority (int x, int y, int z) { return 0; }
4416 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4418 /* Augment DJGPP library POSIX signal functions. This is needed
4419 as of DJGPP v2.01, but might be in the library in later releases. */
4421 #include <libc/bss.h>
4423 /* A counter to know when to re-initialize the static sets. */
4424 static int sigprocmask_count = -1;
4426 /* Which signals are currently blocked (initially none). */
4427 static sigset_t current_mask;
4429 /* Which signals are pending (initially none). */
4430 static sigset_t msdos_pending_signals;
4432 /* Previous handlers to restore when the blocked signals are unblocked. */
4433 typedef void (*sighandler_t)(int);
4434 static sighandler_t prev_handlers[320];
4436 /* A signal handler which just records that a signal occurred
4437 (it will be raised later, if and when the signal is unblocked). */
4438 static void
4439 sig_suspender (int signo)
4441 sigaddset (&msdos_pending_signals, signo);
4445 sigprocmask (int how, const sigset_t *new_set, sigset_t *old_set)
4447 int signo;
4448 sigset_t new_mask;
4450 /* If called for the first time, initialize. */
4451 if (sigprocmask_count != __bss_count)
4453 sigprocmask_count = __bss_count;
4454 sigemptyset (&msdos_pending_signals);
4455 sigemptyset (&current_mask);
4456 for (signo = 0; signo < 320; signo++)
4457 prev_handlers[signo] = SIG_ERR;
4460 if (old_set)
4461 *old_set = current_mask;
4463 if (new_set == 0)
4464 return 0;
4466 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4468 errno = EINVAL;
4469 return -1;
4472 sigemptyset (&new_mask);
4474 /* DJGPP supports upto 320 signals. */
4475 for (signo = 0; signo < 320; signo++)
4477 if (sigismember (&current_mask, signo))
4478 sigaddset (&new_mask, signo);
4479 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4481 sigaddset (&new_mask, signo);
4483 /* SIGKILL is silently ignored, as on other platforms. */
4484 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4485 prev_handlers[signo] = signal (signo, sig_suspender);
4487 if (( how == SIG_UNBLOCK
4488 && sigismember (&new_mask, signo)
4489 && sigismember (new_set, signo))
4490 || (how == SIG_SETMASK
4491 && sigismember (&new_mask, signo)
4492 && !sigismember (new_set, signo)))
4494 sigdelset (&new_mask, signo);
4495 if (prev_handlers[signo] != SIG_ERR)
4497 signal (signo, prev_handlers[signo]);
4498 prev_handlers[signo] = SIG_ERR;
4500 if (sigismember (&msdos_pending_signals, signo))
4502 sigdelset (&msdos_pending_signals, signo);
4503 raise (signo);
4507 current_mask = new_mask;
4508 return 0;
4511 #endif /* not __DJGPP_MINOR__ < 2 */
4513 #ifndef HAVE_SELECT
4514 #include "sysselect.h"
4516 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4517 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4518 ((long)(time).tv_sec < 0 \
4519 || ((time).tv_sec == 0 \
4520 && (long)(time).tv_usec <= 0))
4521 #endif
4523 /* This yields the rest of the current time slice to the task manager.
4524 It should be called by any code which knows that it has nothing
4525 useful to do except idle.
4527 I don't use __dpmi_yield here, since versions of library before 2.02
4528 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4529 on some versions of Windows 9X. */
4531 void
4532 dos_yield_time_slice (void)
4534 _go32_dpmi_registers r;
4536 r.x.ax = 0x1680;
4537 r.x.ss = r.x.sp = r.x.flags = 0;
4538 _go32_dpmi_simulate_int (0x2f, &r);
4539 if (r.h.al == 0x80)
4540 errno = ENOSYS;
4543 /* Only event queue is checked. */
4544 /* We don't have to call timer_check here
4545 because wait_reading_process_output takes care of that. */
4547 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
4548 EMACS_TIME *timeout)
4550 int check_input;
4551 struct time t;
4553 check_input = 0;
4554 if (rfds)
4556 check_input = FD_ISSET (0, rfds);
4557 FD_ZERO (rfds);
4559 if (wfds)
4560 FD_ZERO (wfds);
4561 if (efds)
4562 FD_ZERO (efds);
4564 if (nfds != 1)
4565 abort ();
4567 /* If we are looking only for the terminal, with no timeout,
4568 just read it and wait -- that's more efficient. */
4569 if (!timeout)
4571 while (!detect_input_pending ())
4573 dos_yield_time_slice ();
4576 else
4578 EMACS_TIME clnow, cllast, cldiff;
4580 gettime (&t);
4581 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4583 while (!check_input || !detect_input_pending ())
4585 gettime (&t);
4586 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4587 EMACS_SUB_TIME (cldiff, clnow, cllast);
4589 /* When seconds wrap around, we assume that no more than
4590 1 minute passed since last `gettime'. */
4591 if (EMACS_TIME_NEG_P (cldiff))
4592 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4593 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4595 /* Stop when timeout value crosses zero. */
4596 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4597 return 0;
4598 cllast = clnow;
4599 dos_yield_time_slice ();
4603 FD_SET (0, rfds);
4604 return 1;
4606 #endif
4609 * Define overlaid functions:
4611 * chdir -> sys_chdir
4612 * tzset -> init_gettimeofday
4613 * abort -> dos_abort
4616 #ifdef chdir
4617 #undef chdir
4618 extern int chdir (const char *);
4621 sys_chdir (const char *path)
4623 int len = strlen (path);
4624 char *tmp = (char *)path;
4626 if (*tmp && tmp[1] == ':')
4628 if (getdisk () != tolower (tmp[0]) - 'a')
4629 setdisk (tolower (tmp[0]) - 'a');
4630 tmp += 2; /* strip drive: KFS 1995-07-06 */
4631 len -= 2;
4634 if (len > 1 && (tmp[len - 1] == '/'))
4636 char *tmp1 = (char *) alloca (len + 1);
4637 strcpy (tmp1, tmp);
4638 tmp1[len - 1] = 0;
4639 tmp = tmp1;
4641 return chdir (tmp);
4643 #endif
4645 #ifdef tzset
4646 #undef tzset
4647 extern void tzset (void);
4649 void
4650 init_gettimeofday (void)
4652 time_t ltm, gtm;
4653 struct tm *lstm;
4655 tzset ();
4656 ltm = gtm = time (NULL);
4657 ltm = mktime (lstm = localtime (&ltm));
4658 gtm = mktime (gmtime (&gtm));
4659 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4660 time_rec.tm_isdst = lstm->tm_isdst;
4661 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4663 #endif
4665 #ifdef abort
4666 #undef abort
4667 void
4668 dos_abort (char *file, int line)
4670 char buffer1[200], buffer2[400];
4671 int i, j;
4673 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4674 for (i = j = 0; buffer1[i]; i++) {
4675 buffer2[j++] = buffer1[i];
4676 buffer2[j++] = 0x70;
4678 dosmemput (buffer2, j, (int)ScreenPrimary);
4679 ScreenSetCursor (2, 0);
4680 abort ();
4682 #else
4683 void
4684 abort (void)
4686 dos_ttcooked ();
4687 ScreenSetCursor (10, 0);
4688 cputs ("\r\n\nEmacs aborted!\r\n");
4689 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4690 if (screen_virtual_segment)
4691 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4692 /* Generate traceback, so we could tell whodunit. */
4693 signal (SIGINT, SIG_DFL);
4694 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4695 #else /* __DJGPP_MINOR__ >= 2 */
4696 raise (SIGABRT);
4697 #endif /* __DJGPP_MINOR__ >= 2 */
4698 exit (2);
4700 #endif
4702 void
4703 syms_of_msdos (void)
4705 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4706 staticpro (&recent_doskeys);
4708 #ifndef HAVE_X_WINDOWS
4710 /* The following two are from xfns.c: */
4711 Qreverse = intern ("reverse");
4712 staticpro (&Qreverse);
4714 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4715 doc: /* *Glyph to display instead of chars not supported by current codepage.
4716 This variable is used only by MS-DOS terminals. */);
4717 Vdos_unsupported_char_glyph = make_number ('\177');
4719 #endif
4721 defsubr (&Srecent_doskeys);
4722 defsubr (&Smsdos_long_file_names);
4723 defsubr (&Smsdos_downcase_filename);
4724 defsubr (&Smsdos_remember_default_colors);
4725 defsubr (&Smsdos_set_mouse_buttons);
4728 #endif /* MSDOS */
4730 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
4731 (do not change this comment) */