* files.el (directory-files-no-dot-files-regexp): Doc fix (bug#6298).
[emacs.git] / src / msdos.c
blobea604d299927367d941486ec19ba59f71629ac4d
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 bzero 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 ()
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 ()
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 ()
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 (nbuttons)
199 Lisp_Object nbuttons;
201 int n;
203 CHECK_NUMBER (nbuttons);
204 n = XINT (nbuttons);
205 if (n < 2 || n > 3)
206 xsignal2 (Qargs_out_of_range,
207 build_string ("only 2 or 3 mouse buttons are supported"),
208 nbuttons);
209 mouse_setup_buttons (n);
210 return Qnil;
213 static void
214 mouse_get_xy (int *x, int *y)
216 union REGS regs;
218 regs.x.ax = 0x0003;
219 int86 (0x33, &regs, &regs);
220 *x = regs.x.cx / 8;
221 *y = regs.x.dx / 8;
224 void
225 mouse_moveto (x, y)
226 int x, y;
228 union REGS regs;
229 struct tty_display_info *tty = CURTTY ();
231 if (tty->termscript)
232 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
233 regs.x.ax = 0x0004;
234 mouse_last_x = regs.x.cx = x * 8;
235 mouse_last_y = regs.x.dx = y * 8;
236 int86 (0x33, &regs, &regs);
239 static int
240 mouse_pressed (b, xp, yp)
241 int b, *xp, *yp;
243 union REGS regs;
245 if (b >= mouse_button_count)
246 return 0;
247 regs.x.ax = 0x0005;
248 regs.x.bx = mouse_button_translate[b];
249 int86 (0x33, &regs, &regs);
250 if (regs.x.bx)
251 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
252 return (regs.x.bx != 0);
255 static int
256 mouse_released (b, xp, yp)
257 int b, *xp, *yp;
259 union REGS regs;
261 if (b >= mouse_button_count)
262 return 0;
263 regs.x.ax = 0x0006;
264 regs.x.bx = mouse_button_translate[b];
265 int86 (0x33, &regs, &regs);
266 if (regs.x.bx)
267 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
268 return (regs.x.bx != 0);
271 static int
272 mouse_button_depressed (b, xp, yp)
273 int b, *xp, *yp;
275 union REGS regs;
277 if (b >= mouse_button_count)
278 return 0;
279 regs.x.ax = 0x0003;
280 int86 (0x33, &regs, &regs);
281 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
283 *xp = regs.x.cx / 8;
284 *yp = regs.x.dx / 8;
285 return 1;
287 return 0;
290 void
291 mouse_get_pos (f, insist, bar_window, part, x, y, time)
292 FRAME_PTR *f;
293 int insist;
294 Lisp_Object *bar_window, *x, *y;
295 enum scroll_bar_part *part;
296 unsigned long *time;
298 int ix, iy;
299 Lisp_Object frame, tail;
301 /* Clear the mouse-moved flag for every frame on this display. */
302 FOR_EACH_FRAME (tail, frame)
303 XFRAME (frame)->mouse_moved = 0;
305 *f = SELECTED_FRAME();
306 *bar_window = Qnil;
307 mouse_get_xy (&ix, &iy);
308 *time = event_timestamp ();
309 *x = make_number (mouse_last_x = ix);
310 *y = make_number (mouse_last_y = iy);
313 static void
314 mouse_check_moved ()
316 int x, y;
318 mouse_get_xy (&x, &y);
319 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
320 mouse_last_x = x;
321 mouse_last_y = y;
324 /* Force the mouse driver to ``forget'' about any button clicks until
325 now. */
326 static void
327 mouse_clear_clicks (void)
329 int b;
331 for (b = 0; b < mouse_button_count; b++)
333 int dummy_x, dummy_y;
335 (void) mouse_pressed (b, &dummy_x, &dummy_y);
336 (void) mouse_released (b, &dummy_x, &dummy_y);
340 void
341 mouse_init ()
343 union REGS regs;
344 struct tty_display_info *tty = CURTTY ();
346 if (tty->termscript)
347 fprintf (tty->termscript, "<M_INIT>");
349 regs.x.ax = 0x0021;
350 int86 (0x33, &regs, &regs);
352 /* Reset the mouse last press/release info. It seems that Windows
353 doesn't do that automatically when function 21h is called, which
354 causes Emacs to ``remember'' the click that switched focus to the
355 window just before Emacs was started from that window. */
356 mouse_clear_clicks ();
358 regs.x.ax = 0x0007;
359 regs.x.cx = 0;
360 regs.x.dx = 8 * (ScreenCols () - 1);
361 int86 (0x33, &regs, &regs);
363 regs.x.ax = 0x0008;
364 regs.x.cx = 0;
365 regs.x.dx = 8 * (ScreenRows () - 1);
366 int86 (0x33, &regs, &regs);
368 mouse_moveto (0, 0);
369 mouse_visible = 0;
372 /* ------------------------- Screen control ----------------------
376 static int internal_terminal = 0;
378 #ifndef HAVE_X_WINDOWS
379 extern unsigned char ScreenAttrib;
380 static int screen_face;
382 static int screen_size_X;
383 static int screen_size_Y;
384 static int screen_size;
386 static int current_pos_X;
387 static int current_pos_Y;
388 static int new_pos_X;
389 static int new_pos_Y;
391 static void *startup_screen_buffer;
392 static int startup_screen_size_X;
393 static int startup_screen_size_Y;
394 static int startup_pos_X;
395 static int startup_pos_Y;
396 static unsigned char startup_screen_attrib;
398 static clock_t startup_time;
400 static int term_setup_done;
402 static unsigned short outside_cursor;
404 /* Similar to the_only_frame. */
405 struct tty_display_info the_only_display_info;
407 /* Support for DOS/V (allows Japanese characters to be displayed on
408 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
410 /* Holds the address of the text-mode screen buffer. */
411 static unsigned long screen_old_address = 0;
412 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
413 static unsigned short screen_virtual_segment = 0;
414 static unsigned short screen_virtual_offset = 0;
415 /* A flag to control how to display unibyte 8-bit characters. */
416 extern int unibyte_display_via_language_environment;
418 extern Lisp_Object Qcursor_type;
419 extern Lisp_Object Qbar, Qhbar;
421 /* The screen colors of the current frame, which serve as the default
422 colors for newly-created frames. */
423 static int initial_screen_colors[2];
425 /* Update the screen from a part of relocated DOS/V screen buffer which
426 begins at OFFSET and includes COUNT characters. */
427 static void
428 dosv_refresh_virtual_screen (int offset, int count)
430 __dpmi_regs regs;
432 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
433 return;
435 regs.h.ah = 0xff; /* update relocated screen */
436 regs.x.es = screen_virtual_segment;
437 regs.x.di = screen_virtual_offset + offset;
438 regs.x.cx = count;
439 __dpmi_int (0x10, &regs);
442 static void
443 dos_direct_output (y, x, buf, len)
444 int x, y;
445 char *buf;
446 int len;
448 int t0 = 2 * (x + y * screen_size_X);
449 int t = t0 + (int) ScreenPrimary;
450 int l0 = len;
452 /* This is faster. */
453 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
454 _farnspokeb (t, *buf);
456 if (screen_virtual_segment)
457 dosv_refresh_virtual_screen (t0, l0);
459 #endif
461 #ifndef HAVE_X_WINDOWS
463 static int blink_bit = -1; /* the state of the blink bit at startup */
465 /* Enable bright background colors. */
466 static void
467 bright_bg (void)
469 union REGS regs;
471 /* Remember the original state of the blink/bright-background bit.
472 It is stored at 0040:0065h in the BIOS data area. */
473 if (blink_bit == -1)
474 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
476 regs.h.bl = 0;
477 regs.x.ax = 0x1003;
478 int86 (0x10, &regs, &regs);
481 /* Disable bright background colors (and enable blinking) if we found
482 the video system in that state at startup. */
483 static void
484 maybe_enable_blinking (void)
486 if (blink_bit == 1)
488 union REGS regs;
490 regs.h.bl = 1;
491 regs.x.ax = 0x1003;
492 int86 (0x10, &regs, &regs);
496 /* Return non-zero if the system has a VGA adapter. */
497 static int
498 vga_installed (void)
500 union REGS regs;
502 regs.x.ax = 0x1a00;
503 int86 (0x10, &regs, &regs);
504 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
505 return 1;
506 return 0;
509 /* Set the screen dimensions so that it can show no less than
510 ROWS x COLS frame. */
512 void
513 dos_set_window_size (rows, cols)
514 int *rows, *cols;
516 char video_name[30];
517 union REGS regs;
518 Lisp_Object video_mode;
519 int video_mode_value, have_vga = 0;
520 int current_rows = ScreenRows (), current_cols = ScreenCols ();
522 if (*rows == current_rows && *cols == current_cols)
523 return;
525 mouse_off ();
526 have_vga = vga_installed ();
528 /* If the user specified a special video mode for these dimensions,
529 use that mode. */
530 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
531 video_mode = Fsymbol_value (Fintern_soft (build_string (video_name), Qnil));
533 if (INTEGERP (video_mode)
534 && (video_mode_value = XINT (video_mode)) > 0)
536 regs.x.ax = video_mode_value;
537 int86 (0x10, &regs, &regs);
539 if (have_mouse)
541 /* Must hardware-reset the mouse, or else it won't update
542 its notion of screen dimensions for some non-standard
543 video modes. This is *painfully* slow... */
544 regs.x.ax = 0;
545 int86 (0x33, &regs, &regs);
549 /* Find one of the dimensions supported by standard EGA/VGA
550 which gives us at least the required dimensions. */
551 else
553 static struct {
554 int rows, need_vga;
555 } std_dimension[] = {
556 {25, 0},
557 {28, 1},
558 {35, 0},
559 {40, 1},
560 {43, 0},
561 {50, 1}
563 int i = 0;
565 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
567 if (std_dimension[i].need_vga <= have_vga
568 && std_dimension[i].rows >= *rows)
570 if (std_dimension[i].rows != current_rows
571 || *cols != current_cols)
572 _set_screen_lines (std_dimension[i].rows);
573 break;
575 i++;
580 if (have_mouse)
582 mouse_init ();
583 mouse_on ();
586 /* Tell the caller what dimensions have been REALLY set. */
587 *rows = ScreenRows ();
588 *cols = ScreenCols ();
590 /* Update Emacs' notion of screen dimensions. */
591 screen_size_X = *cols;
592 screen_size_Y = *rows;
593 screen_size = *cols * *rows;
595 /* If the dimensions changed, the mouse highlight info is invalid. */
596 if (current_rows != *rows || current_cols != *cols)
598 struct frame *f = SELECTED_FRAME();
599 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
600 Lisp_Object window = dpyinfo->mouse_face_window;
602 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
604 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
605 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
606 dpyinfo->mouse_face_window = Qnil;
610 /* Enable bright background colors. */
611 bright_bg ();
613 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
614 be defensive anyway. */
615 if (screen_virtual_segment)
616 dosv_refresh_virtual_screen (0, *cols * *rows);
619 /* If we write a character in the position where the mouse is,
620 the mouse cursor may need to be refreshed. */
622 static void
623 mouse_off_maybe ()
625 int x, y;
627 if (!mouse_visible)
628 return;
630 mouse_get_xy (&x, &y);
631 if (y != new_pos_Y || x < new_pos_X)
632 return;
634 mouse_off ();
637 #define DEFAULT_CURSOR_START (-1)
638 #define DEFAULT_CURSOR_WIDTH (-1)
639 #define BOX_CURSOR_WIDTH (-32)
641 /* Set cursor to begin at scan line START_LINE in the character cell
642 and extend for WIDTH scan lines. Scan lines are counted from top
643 of the character cell, starting from zero. */
644 static void
645 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
647 unsigned desired_cursor;
648 __dpmi_regs regs;
649 int max_line, top_line, bot_line;
650 struct tty_display_info *tty = FRAME_TTY (f);
652 /* Avoid the costly BIOS call if F isn't the currently selected
653 frame. Allow for NULL as unconditionally meaning the selected
654 frame. */
655 if (f && f != SELECTED_FRAME())
656 return;
658 if (tty->termscript)
659 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
661 /* The character cell size in scan lines is stored at 40:85 in the
662 BIOS data area. */
663 max_line = _farpeekw (_dos_ds, 0x485) - 1;
664 switch (max_line)
666 default: /* this relies on CGA cursor emulation being ON! */
667 case 7:
668 bot_line = 7;
669 break;
670 case 9:
671 bot_line = 9;
672 break;
673 case 13:
674 bot_line = 12;
675 break;
676 case 15:
677 bot_line = 14;
678 break;
681 if (width < 0)
683 if (width == BOX_CURSOR_WIDTH)
685 top_line = 0;
686 bot_line = max_line;
688 else if (start_line != DEFAULT_CURSOR_START)
690 top_line = start_line;
691 bot_line = top_line - width - 1;
693 else if (width != DEFAULT_CURSOR_WIDTH)
695 top_line = 0;
696 bot_line = -1 - width;
698 else
699 top_line = bot_line + 1;
701 else if (width == 0)
703 /* [31, 0] seems to DTRT for all screen sizes. */
704 top_line = 31;
705 bot_line = 0;
707 else /* WIDTH is positive */
709 if (start_line != DEFAULT_CURSOR_START)
710 bot_line = start_line;
711 top_line = bot_line - (width - 1);
714 /* If the current cursor shape is already what they want, we are
715 history here. */
716 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
717 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
718 return;
720 regs.h.ah = 1;
721 regs.x.cx = desired_cursor;
722 __dpmi_int (0x10, &regs);
725 static void
726 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
728 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
730 /* Just BAR means the normal EGA/VGA cursor. */
731 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
733 else if (CONSP (cursor_type)
734 && (EQ (XCAR (cursor_type), Qbar)
735 || EQ (XCAR (cursor_type), Qhbar)))
737 Lisp_Object bar_parms = XCDR (cursor_type);
738 int width;
740 if (INTEGERP (bar_parms))
742 /* Feature: negative WIDTH means cursor at the top
743 of the character cell, zero means invisible cursor. */
744 width = XINT (bar_parms);
745 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
746 width);
748 else if (CONSP (bar_parms)
749 && INTEGERP (XCAR (bar_parms))
750 && INTEGERP (XCDR (bar_parms)))
752 int start_line = XINT (XCDR (bar_parms));
754 width = XINT (XCAR (bar_parms));
755 msdos_set_cursor_shape (f, start_line, width);
758 else
760 /* Treat anything unknown as "box cursor". This includes nil, so
761 that a frame which doesn't specify a cursor type gets a box,
762 which is the default in Emacs. */
763 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
767 static void
768 IT_ring_bell (struct frame *f)
770 if (visible_bell)
772 mouse_off ();
773 ScreenVisualBell ();
775 else
777 union REGS inregs, outregs;
778 inregs.h.ah = 2;
779 inregs.h.dl = 7;
780 intdos (&inregs, &outregs);
784 /* Given a face id FACE, extract the face parameters to be used for
785 display until the face changes. The face parameters (actually, its
786 color) are used to construct the video attribute byte for each
787 glyph during the construction of the buffer that is then blitted to
788 the video RAM. */
789 static void
790 IT_set_face (int face)
792 struct frame *sf = SELECTED_FRAME();
793 struct face *fp = FACE_FROM_ID (sf, face);
794 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
795 unsigned long fg, bg, dflt_fg, dflt_bg;
796 struct tty_display_info *tty = FRAME_TTY (sf);
798 if (!fp)
800 fp = dfp;
801 /* The default face for the frame should always be realized and
802 cached. */
803 if (!fp)
804 abort ();
806 screen_face = face;
807 fg = fp->foreground;
808 bg = fp->background;
809 dflt_fg = dfp->foreground;
810 dflt_bg = dfp->background;
812 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
813 mean use the colors of the default face. Note that we assume all
814 16 colors to be available for the background, since Emacs switches
815 on this mode (and loses the blinking attribute) at startup. */
816 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
817 fg = FRAME_FOREGROUND_PIXEL (sf);
818 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
819 fg = FRAME_BACKGROUND_PIXEL (sf);
820 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
821 bg = FRAME_BACKGROUND_PIXEL (sf);
822 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
823 bg = FRAME_FOREGROUND_PIXEL (sf);
825 /* Make sure highlighted lines really stand out, come what may. */
826 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
828 unsigned long tem = fg;
830 fg = bg;
831 bg = tem;
833 /* If the user requested inverse video, obey. */
834 if (inverse_video)
836 unsigned long tem2 = fg;
838 fg = bg;
839 bg = tem2;
841 if (tty->termscript)
842 fprintf (tty->termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
843 fp->foreground, fp->background, fg, bg);
844 if (fg >= 0 && fg < 16)
846 ScreenAttrib &= 0xf0;
847 ScreenAttrib |= fg;
849 if (bg >= 0 && bg < 16)
851 ScreenAttrib &= 0x0f;
852 ScreenAttrib |= ((bg & 0x0f) << 4);
856 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
857 width of a DOS display in any known text mode. We multiply by 2 to
858 accomodate the screen attribute byte. */
859 #define MAX_SCREEN_BUF 160*2
861 Lisp_Object Vdos_unsupported_char_glyph;
862 extern unsigned char *encode_terminal_code (struct glyph *, int,
863 struct coding_system *);
864 static void
865 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
867 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
868 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
869 register int sl = str_len;
870 struct tty_display_info *tty = FRAME_TTY (f);
871 struct frame *sf;
872 unsigned char *conversion_buffer;
874 /* Do we need to consider conversion of unibyte characters to
875 multibyte? */
876 int convert_unibyte_characters
877 = (NILP (current_buffer->enable_multibyte_characters)
878 && unibyte_display_via_language_environment);
880 /* If terminal_coding does any conversion, use it, otherwise use
881 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
882 because it always returns 1 if terminal_coding.src_multibyte is 1. */
883 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
885 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
886 coding = &safe_terminal_coding;
888 if (str_len <= 0) return;
890 sf = SELECTED_FRAME();
892 /* Since faces get cached and uncached behind our back, we can't
893 rely on their indices in the cache being consistent across
894 invocations. So always reset the screen face to the default
895 face of the frame, before writing glyphs, and let the glyphs
896 set the right face if it's different from the default. */
897 IT_set_face (DEFAULT_FACE_ID);
899 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
900 the tail. */
901 coding->mode &= ~CODING_MODE_LAST_BLOCK;
902 screen_bp = &screen_buf[0];
903 while (sl > 0)
905 int cf;
906 int n;
908 /* If the face of this glyph is different from the current
909 screen face, update the screen attribute byte. */
910 cf = str->face_id;
911 if (cf != screen_face)
912 IT_set_face (cf); /* handles invalid faces gracefully */
914 /* Identify a run of glyphs with the same face. */
915 for (n = 1; n < sl; ++n)
916 if (str[n].face_id != cf)
917 break;
919 if (n >= sl)
920 /* This is the last glyph. */
921 coding->mode |= CODING_MODE_LAST_BLOCK;
923 conversion_buffer = encode_terminal_code (str, n, coding);
924 if (coding->produced > 0)
926 /* Copy the encoded bytes to the screen buffer. */
927 for (bp = conversion_buffer; coding->produced--; bp++)
929 /* Paranoia: discard bytes that would overrun the end of
930 the screen buffer. */
931 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
933 *screen_bp++ = (unsigned char)*bp;
934 *screen_bp++ = ScreenAttrib;
936 if (tty->termscript)
937 fputc (*bp, tty->termscript);
940 /* Update STR and its remaining length. */
941 str += n;
942 sl -= n;
945 /* Dump whatever we have in the screen buffer. */
946 mouse_off_maybe ();
947 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
948 if (screen_virtual_segment)
949 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
950 new_pos_X += (screen_bp - screen_buf) / 2;
953 /************************************************************************
954 Mouse Highlight (and friends..)
955 ************************************************************************/
957 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
958 static Lisp_Object last_mouse_window;
960 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
962 /* Set the mouse pointer shape according to whether it is in the
963 area where the mouse highlight is in effect. */
964 static void
965 IT_set_mouse_pointer (int mode)
967 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
968 many possibilities to change its shape, and the available
969 functionality pretty much sucks (e.g., almost every reasonable
970 shape will conceal the character it is on). Since the color of
971 the pointer changes in the highlighted area, it is not clear to
972 me whether anything else is required, anyway. */
975 /* Display the active region described by mouse_face_*
976 in its mouse-face if HL > 0, in its normal face if HL = 0. */
977 static void
978 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
980 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
981 struct frame *f = XFRAME (WINDOW_FRAME (w));
982 int i;
983 struct face *fp;
984 struct tty_display_info *tty = FRAME_TTY (f);
987 /* If window is in the process of being destroyed, don't bother
988 doing anything. */
989 if (w->current_matrix == NULL)
990 goto set_cursor_shape;
992 /* Recognize when we are called to operate on rows that don't exist
993 anymore. This can happen when a window is split. */
994 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
995 goto set_cursor_shape;
997 /* There's no sense to do anything if the mouse face isn't realized. */
998 if (hl > 0)
1000 if (dpyinfo->mouse_face_hidden)
1001 goto set_cursor_shape;
1003 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1004 if (!fp)
1005 goto set_cursor_shape;
1008 /* Note that mouse_face_beg_row etc. are window relative. */
1009 for (i = dpyinfo->mouse_face_beg_row;
1010 i <= dpyinfo->mouse_face_end_row;
1011 i++)
1013 int start_hpos, end_hpos;
1014 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1016 /* Don't do anything if row doesn't have valid contents. */
1017 if (!row->enabled_p)
1018 continue;
1020 /* For all but the first row, the highlight starts at column 0. */
1021 if (i == dpyinfo->mouse_face_beg_row)
1022 start_hpos = dpyinfo->mouse_face_beg_col;
1023 else
1024 start_hpos = 0;
1026 if (i == dpyinfo->mouse_face_end_row)
1027 end_hpos = dpyinfo->mouse_face_end_col;
1028 else
1029 end_hpos = row->used[TEXT_AREA];
1031 if (end_hpos <= start_hpos)
1032 continue;
1033 /* Record that some glyphs of this row are displayed in
1034 mouse-face. */
1035 row->mouse_face_p = hl > 0;
1036 if (hl > 0)
1038 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1039 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1040 int nglyphs = end_hpos - start_hpos;
1041 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1042 int start_offset = offset;
1044 if (tty->termscript)
1045 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1046 kstart, kstart + nglyphs - 1, vpos);
1048 mouse_off ();
1049 IT_set_face (dpyinfo->mouse_face_face_id);
1050 /* Since we are going to change only the _colors_ of the
1051 displayed text, there's no need to go through all the
1052 pain of generating and encoding the text from the glyphs.
1053 Instead, we simply poke the attribute byte of each
1054 affected position in video memory with the colors
1055 computed by IT_set_face! */
1056 _farsetsel (_dos_ds);
1057 while (nglyphs--)
1059 _farnspokeb (offset, ScreenAttrib);
1060 offset += 2;
1062 if (screen_virtual_segment)
1063 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1064 mouse_on ();
1066 else
1068 /* We are removing a previously-drawn mouse highlight. The
1069 safest way to do so is to redraw the glyphs anew, since
1070 all kinds of faces and display tables could have changed
1071 behind our back. */
1072 int nglyphs = end_hpos - start_hpos;
1073 int save_x = new_pos_X, save_y = new_pos_Y;
1075 if (end_hpos >= row->used[TEXT_AREA])
1076 nglyphs = row->used[TEXT_AREA] - start_hpos;
1078 /* IT_write_glyphs writes at cursor position, so we need to
1079 temporarily move cursor coordinates to the beginning of
1080 the highlight region. */
1081 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1082 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1084 if (tty->termscript)
1085 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1086 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1087 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1088 if (tty->termscript)
1089 fputs ("\n", tty->termscript);
1090 new_pos_X = save_x;
1091 new_pos_Y = save_y;
1095 set_cursor_shape:
1096 /* Change the mouse pointer shape. */
1097 IT_set_mouse_pointer (hl);
1100 /* Clear out the mouse-highlighted active region.
1101 Redraw it un-highlighted first. */
1102 static void
1103 clear_mouse_face (struct tty_display_info *dpyinfo)
1105 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1106 show_mouse_face (dpyinfo, 0);
1108 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1109 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1110 dpyinfo->mouse_face_window = Qnil;
1113 /* Find the glyph matrix position of buffer position POS in window W.
1114 *HPOS and *VPOS are set to the positions found. W's current glyphs
1115 must be up to date. If POS is above window start return (0, 0).
1116 If POS is after end of W, return end of last line in W. */
1117 static int
1118 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1120 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1121 int yb = window_text_bottom_y (w);
1122 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1124 while (row->y < yb)
1126 if (row->used[TEXT_AREA])
1127 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1128 else
1129 line_start_position = 0;
1131 if (line_start_position > pos)
1132 break;
1133 /* If the position sought is the end of the buffer,
1134 don't include the blank lines at the bottom of the window. */
1135 else if (line_start_position == pos
1136 && pos == BUF_ZV (XBUFFER (w->buffer)))
1138 maybe_next_line_p = 1;
1139 break;
1141 else if (line_start_position > 0)
1142 best_row = row;
1144 /* Don't overstep the last matrix row, lest we get into the
1145 never-never land... */
1146 if (row->y + 1 >= yb)
1147 break;
1149 ++row;
1152 /* Find the right column within BEST_ROW. */
1153 lastcol = 0;
1154 row = best_row;
1155 for (i = 0; i < row->used[TEXT_AREA]; i++)
1157 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1158 int charpos;
1160 charpos = glyph->charpos;
1161 if (charpos == pos)
1163 *hpos = i;
1164 *vpos = row->y;
1165 return 1;
1167 else if (charpos > pos)
1168 break;
1169 else if (charpos > 0)
1170 lastcol = i;
1173 /* If we're looking for the end of the buffer,
1174 and we didn't find it in the line we scanned,
1175 use the start of the following line. */
1176 if (maybe_next_line_p)
1178 ++row;
1179 lastcol = 0;
1182 *vpos = row->y;
1183 *hpos = lastcol + 1;
1184 return 0;
1187 /* Take proper action when mouse has moved to the mode or top line of
1188 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1189 mode line. X is relative to the start of the text display area of
1190 W, so the width of fringes and scroll bars must be subtracted
1191 to get a position relative to the start of the mode line. */
1192 static void
1193 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1195 struct frame *f = XFRAME (w->frame);
1196 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1197 struct glyph_row *row;
1199 if (mode_line_p)
1200 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1201 else
1202 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1204 if (row->enabled_p)
1206 extern Lisp_Object Qhelp_echo;
1207 struct glyph *glyph, *end;
1208 Lisp_Object help, map;
1210 /* Find the glyph under X. */
1211 glyph = (row->glyphs[TEXT_AREA]
1213 /* in case someone implements scroll bars some day... */
1214 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1215 end = glyph + row->used[TEXT_AREA];
1216 if (glyph < end
1217 && STRINGP (glyph->object)
1218 && STRING_INTERVALS (glyph->object)
1219 && glyph->charpos >= 0
1220 && glyph->charpos < SCHARS (glyph->object))
1222 /* If we're on a string with `help-echo' text property,
1223 arrange for the help to be displayed. This is done by
1224 setting the global variable help_echo to the help string. */
1225 help = Fget_text_property (make_number (glyph->charpos),
1226 Qhelp_echo, glyph->object);
1227 if (!NILP (help))
1229 help_echo_string = help;
1230 XSETWINDOW (help_echo_window, w);
1231 help_echo_object = glyph->object;
1232 help_echo_pos = glyph->charpos;
1238 /* Take proper action when the mouse has moved to position X, Y on
1239 frame F as regards highlighting characters that have mouse-face
1240 properties. Also de-highlighting chars where the mouse was before.
1241 X and Y can be negative or out of range. */
1242 static void
1243 IT_note_mouse_highlight (struct frame *f, int x, int y)
1245 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1246 enum window_part part = ON_NOTHING;
1247 Lisp_Object window;
1248 struct window *w;
1250 /* When a menu is active, don't highlight because this looks odd. */
1251 if (mouse_preempted)
1252 return;
1254 if (NILP (Vmouse_highlight)
1255 || !f->glyphs_initialized_p)
1256 return;
1258 dpyinfo->mouse_face_mouse_x = x;
1259 dpyinfo->mouse_face_mouse_y = y;
1260 dpyinfo->mouse_face_mouse_frame = f;
1262 if (dpyinfo->mouse_face_defer)
1263 return;
1265 if (gc_in_progress)
1267 dpyinfo->mouse_face_deferred_gc = 1;
1268 return;
1271 /* Which window is that in? */
1272 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1274 /* If we were displaying active text in another window, clear that. */
1275 if (! EQ (window, dpyinfo->mouse_face_window))
1276 clear_mouse_face (dpyinfo);
1278 /* Not on a window -> return. */
1279 if (!WINDOWP (window))
1280 return;
1282 /* Convert to window-relative coordinates. */
1283 w = XWINDOW (window);
1285 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1287 /* Mouse is on the mode or top line. */
1288 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1289 return;
1292 IT_set_mouse_pointer (0);
1294 /* Are we in a window whose display is up to date?
1295 And verify the buffer's text has not changed. */
1296 if (part == ON_TEXT
1297 && EQ (w->window_end_valid, w->buffer)
1298 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1299 && (XFASTINT (w->last_overlay_modified)
1300 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1302 int pos, i, nrows = w->current_matrix->nrows;
1303 struct glyph_row *row;
1304 struct glyph *glyph;
1306 /* Find the glyph under X/Y. */
1307 glyph = NULL;
1308 if (y >= 0 && y < nrows)
1310 row = MATRIX_ROW (w->current_matrix, y);
1311 /* Give up if some row before the one we are looking for is
1312 not enabled. */
1313 for (i = 0; i <= y; i++)
1314 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1315 break;
1316 if (i > y /* all rows upto and including the one at Y are enabled */
1317 && row->displays_text_p
1318 && x < window_box_width (w, TEXT_AREA))
1320 glyph = row->glyphs[TEXT_AREA];
1321 if (x >= row->used[TEXT_AREA])
1322 glyph = NULL;
1323 else
1325 glyph += x;
1326 if (!BUFFERP (glyph->object))
1327 glyph = NULL;
1332 /* Clear mouse face if X/Y not over text. */
1333 if (glyph == NULL)
1335 clear_mouse_face (dpyinfo);
1336 return;
1339 if (!BUFFERP (glyph->object))
1340 abort ();
1341 pos = glyph->charpos;
1343 /* Check for mouse-face and help-echo. */
1345 extern Lisp_Object Qmouse_face;
1346 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1347 int noverlays, obegv, ozv;
1348 struct buffer *obuf;
1350 /* If we get an out-of-range value, return now; avoid an error. */
1351 if (pos > BUF_Z (XBUFFER (w->buffer)))
1352 return;
1354 /* Make the window's buffer temporarily current for
1355 overlays_at and compute_char_face. */
1356 obuf = current_buffer;
1357 current_buffer = XBUFFER (w->buffer);
1358 obegv = BEGV;
1359 ozv = ZV;
1360 BEGV = BEG;
1361 ZV = Z;
1363 /* Is this char mouse-active or does it have help-echo? */
1364 XSETINT (position, pos);
1366 /* Put all the overlays we want in a vector in overlay_vec. */
1367 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1368 /* Sort overlays into increasing priority order. */
1369 noverlays = sort_overlays (overlay_vec, noverlays, w);
1371 /* Check mouse-face highlighting. */
1372 if (! (EQ (window, dpyinfo->mouse_face_window)
1373 && y >= dpyinfo->mouse_face_beg_row
1374 && y <= dpyinfo->mouse_face_end_row
1375 && (y > dpyinfo->mouse_face_beg_row
1376 || x >= dpyinfo->mouse_face_beg_col)
1377 && (y < dpyinfo->mouse_face_end_row
1378 || x < dpyinfo->mouse_face_end_col
1379 || dpyinfo->mouse_face_past_end)))
1381 /* Clear the display of the old active region, if any. */
1382 clear_mouse_face (dpyinfo);
1384 /* Find highest priority overlay that has a mouse-face prop. */
1385 overlay = Qnil;
1386 for (i = noverlays - 1; i >= 0; --i)
1388 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1389 if (!NILP (mouse_face))
1391 overlay = overlay_vec[i];
1392 break;
1396 /* If no overlay applies, get a text property. */
1397 if (NILP (overlay))
1398 mouse_face = Fget_text_property (position, Qmouse_face,
1399 w->buffer);
1401 /* Handle the overlay case. */
1402 if (! NILP (overlay))
1404 /* Find the range of text around this char that
1405 should be active. */
1406 Lisp_Object before, after;
1407 EMACS_INT ignore;
1409 before = Foverlay_start (overlay);
1410 after = Foverlay_end (overlay);
1411 /* Record this as the current active region. */
1412 fast_find_position (w, XFASTINT (before),
1413 &dpyinfo->mouse_face_beg_col,
1414 &dpyinfo->mouse_face_beg_row);
1415 dpyinfo->mouse_face_past_end
1416 = !fast_find_position (w, XFASTINT (after),
1417 &dpyinfo->mouse_face_end_col,
1418 &dpyinfo->mouse_face_end_row);
1419 dpyinfo->mouse_face_window = window;
1420 dpyinfo->mouse_face_face_id
1421 = face_at_buffer_position (w, pos, 0, 0,
1422 &ignore, pos + 1,
1423 !dpyinfo->mouse_face_hidden,
1424 -1);
1426 /* Display it as active. */
1427 show_mouse_face (dpyinfo, 1);
1429 /* Handle the text property case. */
1430 else if (! NILP (mouse_face))
1432 /* Find the range of text around this char that
1433 should be active. */
1434 Lisp_Object before, after, beginning, end;
1435 EMACS_INT ignore;
1437 beginning = Fmarker_position (w->start);
1438 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1439 - XFASTINT (w->window_end_pos)));
1440 before
1441 = Fprevious_single_property_change (make_number (pos + 1),
1442 Qmouse_face,
1443 w->buffer, beginning);
1444 after
1445 = Fnext_single_property_change (position, Qmouse_face,
1446 w->buffer, end);
1447 /* Record this as the current active region. */
1448 fast_find_position (w, XFASTINT (before),
1449 &dpyinfo->mouse_face_beg_col,
1450 &dpyinfo->mouse_face_beg_row);
1451 dpyinfo->mouse_face_past_end
1452 = !fast_find_position (w, XFASTINT (after),
1453 &dpyinfo->mouse_face_end_col,
1454 &dpyinfo->mouse_face_end_row);
1455 dpyinfo->mouse_face_window = window;
1456 dpyinfo->mouse_face_face_id
1457 = face_at_buffer_position (w, pos, 0, 0,
1458 &ignore, pos + 1,
1459 !dpyinfo->mouse_face_hidden,
1460 -1);
1462 /* Display it as active. */
1463 show_mouse_face (dpyinfo, 1);
1467 /* Look for a `help-echo' property. */
1469 Lisp_Object help;
1470 extern Lisp_Object Qhelp_echo;
1472 /* Check overlays first. */
1473 help = Qnil;
1474 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1476 overlay = overlay_vec[i];
1477 help = Foverlay_get (overlay, Qhelp_echo);
1480 if (!NILP (help))
1482 help_echo_string = help;
1483 help_echo_window = window;
1484 help_echo_object = overlay;
1485 help_echo_pos = pos;
1487 /* Try text properties. */
1488 else if (NILP (help)
1489 && ((STRINGP (glyph->object)
1490 && glyph->charpos >= 0
1491 && glyph->charpos < SCHARS (glyph->object))
1492 || (BUFFERP (glyph->object)
1493 && glyph->charpos >= BEGV
1494 && glyph->charpos < ZV)))
1496 help = Fget_text_property (make_number (glyph->charpos),
1497 Qhelp_echo, glyph->object);
1498 if (!NILP (help))
1500 help_echo_string = help;
1501 help_echo_window = window;
1502 help_echo_object = glyph->object;
1503 help_echo_pos = glyph->charpos;
1508 BEGV = obegv;
1509 ZV = ozv;
1510 current_buffer = obuf;
1515 static void
1516 IT_clear_end_of_line (struct frame *f, int first_unused)
1518 char *spaces, *sp;
1519 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1520 extern int fatal_error_in_progress;
1521 struct tty_display_info *tty = FRAME_TTY (f);
1523 if (new_pos_X >= first_unused || fatal_error_in_progress)
1524 return;
1526 IT_set_face (0);
1527 i = (j = first_unused - new_pos_X) * 2;
1528 if (tty->termscript)
1529 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1530 spaces = sp = alloca (i);
1532 while (--j >= 0)
1534 *sp++ = ' ';
1535 *sp++ = ScreenAttrib;
1538 mouse_off_maybe ();
1539 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1540 if (screen_virtual_segment)
1541 dosv_refresh_virtual_screen (offset, i / 2);
1543 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1544 Let's follow their lead, in case someone relies on this. */
1545 new_pos_X = first_unused;
1548 static void
1549 IT_clear_screen (struct frame *f)
1551 struct tty_display_info *tty = FRAME_TTY (f);
1553 if (tty->termscript)
1554 fprintf (tty->termscript, "<CLR:SCR>");
1555 /* We are sometimes called (from clear_garbaged_frames) when a new
1556 frame is being created, but its faces are not yet realized. In
1557 such a case we cannot call IT_set_face, since it will fail to find
1558 any valid faces and will abort. Instead, use the initial screen
1559 colors; that should mimic what a Unix tty does, which simply clears
1560 the screen with whatever default colors are in use. */
1561 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1562 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1563 else
1564 IT_set_face (0);
1565 mouse_off ();
1566 ScreenClear ();
1567 if (screen_virtual_segment)
1568 dosv_refresh_virtual_screen (0, screen_size);
1569 new_pos_X = new_pos_Y = 0;
1572 static void
1573 IT_clear_to_end (struct frame *f)
1575 struct tty_display_info *tty = FRAME_TTY (f);
1577 if (tty->termscript)
1578 fprintf (tty->termscript, "<CLR:EOS>");
1580 while (new_pos_Y < screen_size_Y) {
1581 new_pos_X = 0;
1582 IT_clear_end_of_line (f, screen_size_X);
1583 new_pos_Y++;
1587 static void
1588 IT_cursor_to (struct frame *f, int y, int x)
1590 struct tty_display_info *tty = FRAME_TTY (f);
1592 if (tty->termscript)
1593 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1594 new_pos_X = x;
1595 new_pos_Y = y;
1598 static int cursor_cleared;
1600 static void
1601 IT_display_cursor (int on)
1603 struct tty_display_info *tty = CURTTY ();
1605 if (on && cursor_cleared)
1607 ScreenSetCursor (current_pos_Y, current_pos_X);
1608 cursor_cleared = 0;
1609 if (tty->termscript)
1610 fprintf (tty->termscript, "\nCURSOR ON");
1612 else if (!on && !cursor_cleared)
1614 ScreenSetCursor (-1, -1);
1615 cursor_cleared = 1;
1616 if (tty->termscript)
1617 fprintf (tty->termscript, "\nCURSOR OFF");
1621 /* Emacs calls cursor-movement functions a lot when it updates the
1622 display (probably a legacy of old terminals where you cannot
1623 update a screen line without first moving the cursor there).
1624 However, cursor movement is expensive on MSDOS (it calls a slow
1625 BIOS function and requires 2 mode switches), while actual screen
1626 updates access the video memory directly and don't depend on
1627 cursor position. To avoid slowing down the redisplay, we cheat:
1628 all functions that move the cursor only set internal variables
1629 which record the cursor position, whereas the cursor is only
1630 moved to its final position whenever screen update is complete.
1632 `IT_cmgoto' is called from the keyboard reading loop and when the
1633 frame update is complete. This means that we are ready for user
1634 input, so we update the cursor position to show where the point is,
1635 and also make the mouse pointer visible.
1637 Special treatment is required when the cursor is in the echo area,
1638 to put the cursor at the end of the text displayed there. */
1640 static void
1641 IT_cmgoto (FRAME_PTR f)
1643 /* Only set the cursor to where it should be if the display is
1644 already in sync with the window contents. */
1645 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1646 struct tty_display_info *tty = FRAME_TTY (f);
1648 /* FIXME: This needs to be rewritten for the new redisplay, or
1649 removed. */
1650 #if 0
1651 static int previous_pos_X = -1;
1653 update_cursor_pos = 1; /* temporary!!! */
1655 /* If the display is in sync, forget any previous knowledge about
1656 cursor position. This is primarily for unexpected events like
1657 C-g in the minibuffer. */
1658 if (update_cursor_pos && previous_pos_X >= 0)
1659 previous_pos_X = -1;
1660 /* If we are in the echo area, put the cursor at the
1661 end of the echo area message. */
1662 if (!update_cursor_pos
1663 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1665 int tem_X = current_pos_X, dummy;
1667 if (echo_area_glyphs)
1669 tem_X = echo_area_glyphs_length;
1670 /* Save current cursor position, to be restored after the
1671 echo area message is erased. Only remember one level
1672 of previous cursor position. */
1673 if (previous_pos_X == -1)
1674 ScreenGetCursor (&dummy, &previous_pos_X);
1676 else if (previous_pos_X >= 0)
1678 /* We wind up here after the echo area message is erased.
1679 Restore the cursor position we remembered above. */
1680 tem_X = previous_pos_X;
1681 previous_pos_X = -1;
1684 if (current_pos_X != tem_X)
1686 new_pos_X = tem_X;
1687 update_cursor_pos = 1;
1690 #endif
1692 if (update_cursor_pos
1693 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1695 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1696 if (tty->termscript)
1697 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1700 /* Maybe cursor is invisible, so make it visible. */
1701 IT_display_cursor (1);
1703 /* Mouse pointer should be always visible if we are waiting for
1704 keyboard input. */
1705 if (!mouse_visible)
1706 mouse_on ();
1709 static void
1710 IT_update_begin (struct frame *f)
1712 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1713 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1715 if (display_info->termscript)
1716 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1718 BLOCK_INPUT;
1720 if (f && f == mouse_face_frame)
1722 /* Don't do highlighting for mouse motion during the update. */
1723 display_info->mouse_face_defer = 1;
1725 /* If F needs to be redrawn, simply forget about any prior mouse
1726 highlighting. */
1727 if (FRAME_GARBAGED_P (f))
1728 display_info->mouse_face_window = Qnil;
1730 /* Can we tell that this update does not affect the window
1731 where the mouse highlight is? If so, no need to turn off.
1732 Likewise, don't do anything if none of the enabled rows
1733 contains glyphs highlighted in mouse face. */
1734 if (!NILP (display_info->mouse_face_window)
1735 && WINDOWP (display_info->mouse_face_window))
1737 struct window *w = XWINDOW (display_info->mouse_face_window);
1738 int i;
1740 /* If the mouse highlight is in the window that was deleted
1741 (e.g., if it was popped by completion), clear highlight
1742 unconditionally. */
1743 if (NILP (w->buffer))
1744 display_info->mouse_face_window = Qnil;
1745 else
1747 for (i = 0; i < w->desired_matrix->nrows; ++i)
1748 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1749 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1750 break;
1753 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1754 clear_mouse_face (display_info);
1757 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1759 /* If the frame with mouse highlight was deleted, invalidate the
1760 highlight info. */
1761 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1762 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1763 display_info->mouse_face_window = Qnil;
1764 display_info->mouse_face_deferred_gc = 0;
1765 display_info->mouse_face_mouse_frame = NULL;
1768 UNBLOCK_INPUT;
1771 static void
1772 IT_update_end (struct frame *f)
1774 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1776 if (dpyinfo->termscript)
1777 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1778 dpyinfo->mouse_face_defer = 0;
1781 static void
1782 IT_frame_up_to_date (struct frame *f)
1784 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1785 Lisp_Object new_cursor, frame_desired_cursor;
1786 struct window *sw;
1788 if (dpyinfo->mouse_face_deferred_gc
1789 || (f && f == dpyinfo->mouse_face_mouse_frame))
1791 BLOCK_INPUT;
1792 if (dpyinfo->mouse_face_mouse_frame)
1793 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1794 dpyinfo->mouse_face_mouse_x,
1795 dpyinfo->mouse_face_mouse_y);
1796 dpyinfo->mouse_face_deferred_gc = 0;
1797 UNBLOCK_INPUT;
1800 /* Set the cursor type to whatever they wanted. In a minibuffer
1801 window, we want the cursor to appear only if we are reading input
1802 from this window, and we want the cursor to be taken from the
1803 frame parameters. For the selected window, we use either its
1804 buffer-local value or the value from the frame parameters if the
1805 buffer doesn't define its local value for the cursor type. */
1806 sw = XWINDOW (f->selected_window);
1807 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1808 if (cursor_in_echo_area
1809 && FRAME_HAS_MINIBUF_P (f)
1810 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1811 && sw == XWINDOW (echo_area_window))
1812 new_cursor = frame_desired_cursor;
1813 else
1815 struct buffer *b = XBUFFER (sw->buffer);
1817 if (EQ (b->cursor_type, Qt))
1818 new_cursor = frame_desired_cursor;
1819 else if (NILP (b->cursor_type)) /* nil means no cursor */
1820 new_cursor = Fcons (Qbar, make_number (0));
1821 else
1822 new_cursor = b->cursor_type;
1825 IT_set_cursor_type (f, new_cursor);
1827 IT_cmgoto (f); /* position cursor when update is done */
1830 /* Copy LEN glyphs displayed on a single line whose vertical position
1831 is YPOS, beginning at horizontal position XFROM to horizontal
1832 position XTO, by moving blocks in the video memory. Used by
1833 functions that insert and delete glyphs. */
1834 static void
1835 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1837 /* The offsets of source and destination relative to the
1838 conventional memorty selector. */
1839 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1840 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1842 if (from == to || len <= 0)
1843 return;
1845 _farsetsel (_dos_ds);
1847 /* The source and destination might overlap, so we need to move
1848 glyphs non-destructively. */
1849 if (from > to)
1851 for ( ; len; from += 2, to += 2, len--)
1852 _farnspokew (to, _farnspeekw (from));
1854 else
1856 from += (len - 1) * 2;
1857 to += (len - 1) * 2;
1858 for ( ; len; from -= 2, to -= 2, len--)
1859 _farnspokew (to, _farnspeekw (from));
1861 if (screen_virtual_segment)
1862 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1865 /* Insert and delete glyphs. */
1866 static void
1867 IT_insert_glyphs (f, start, len)
1868 struct frame *f;
1869 register struct glyph *start;
1870 register int len;
1872 int shift_by_width = screen_size_X - (new_pos_X + len);
1874 /* Shift right the glyphs from the nominal cursor position to the
1875 end of this line. */
1876 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1878 /* Now write the glyphs to be inserted. */
1879 IT_write_glyphs (f, start, len);
1882 static void
1883 IT_delete_glyphs (f, n)
1884 struct frame *f;
1885 register int n;
1887 abort ();
1890 /* set-window-configuration on window.c needs this. */
1891 void
1892 x_set_menu_bar_lines (f, value, oldval)
1893 struct frame *f;
1894 Lisp_Object value, oldval;
1896 set_menu_bar_lines (f, value, oldval);
1899 /* This was copied from xfaces.c */
1901 extern Lisp_Object Qbackground_color;
1902 extern Lisp_Object Qforeground_color;
1903 Lisp_Object Qreverse;
1904 extern Lisp_Object Qtitle;
1906 /* IT_set_terminal_modes is called when emacs is started,
1907 resumed, and whenever the screen is redrawn! */
1909 static void
1910 IT_set_terminal_modes (struct terminal *term)
1912 struct tty_display_info *tty;
1914 /* If called with initial terminal, it's too early to do anything
1915 useful. */
1916 if (term->type == output_initial)
1917 return;
1919 tty = term->display_info.tty;
1921 if (tty->termscript)
1922 fprintf (tty->termscript, "\n<SET_TERM>");
1924 screen_size_X = ScreenCols ();
1925 screen_size_Y = ScreenRows ();
1926 screen_size = screen_size_X * screen_size_Y;
1928 new_pos_X = new_pos_Y = 0;
1929 current_pos_X = current_pos_Y = -1;
1931 if (term_setup_done)
1932 return;
1933 term_setup_done = 1;
1935 startup_screen_size_X = screen_size_X;
1936 startup_screen_size_Y = screen_size_Y;
1937 startup_screen_attrib = ScreenAttrib;
1939 /* Is DOS/V (or any other RSIS software which relocates
1940 the screen) installed? */
1942 unsigned short es_value;
1943 __dpmi_regs regs;
1945 regs.h.ah = 0xfe; /* get relocated screen address */
1946 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1947 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1948 else if (screen_old_address) /* already switched to Japanese mode once */
1949 regs.x.es = (screen_old_address >> 4) & 0xffff;
1950 else
1951 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1952 regs.x.di = 0;
1953 es_value = regs.x.es;
1954 __dpmi_int (0x10, &regs);
1956 if (regs.x.es != es_value)
1958 /* screen_old_address is only set if ScreenPrimary does NOT
1959 already point to the relocated buffer address returned by
1960 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1961 ScreenPrimary to that address at startup under DOS/V. */
1962 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1963 screen_old_address = ScreenPrimary;
1964 screen_virtual_segment = regs.x.es;
1965 screen_virtual_offset = regs.x.di;
1966 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1970 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1971 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1973 bright_bg ();
1976 /* IT_reset_terminal_modes is called when emacs is
1977 suspended or killed. */
1979 static void
1980 IT_reset_terminal_modes (struct terminal *term)
1982 int display_row_start = (int) ScreenPrimary;
1983 int saved_row_len = startup_screen_size_X * 2;
1984 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1985 int to_next_row = update_row_len;
1986 unsigned char *saved_row = startup_screen_buffer;
1987 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1988 struct tty_display_info *tty = term->display_info.tty;
1990 if (tty->termscript)
1991 fprintf (tty->termscript, "\n<RESET_TERM>");
1993 if (!term_setup_done)
1994 return;
1996 mouse_off ();
1998 /* Leave the video system in the same state as we found it,
1999 as far as the blink/bright-background bit is concerned. */
2000 maybe_enable_blinking ();
2002 /* We have a situation here.
2003 We cannot just do ScreenUpdate(startup_screen_buffer) because
2004 the luser could have changed screen dimensions inside Emacs
2005 and failed (or didn't want) to restore them before killing
2006 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2007 thus will happily use memory outside what was allocated for
2008 `startup_screen_buffer'.
2009 Thus we only restore as much as the current screen dimensions
2010 can hold, and clear the rest (if the saved screen is smaller than
2011 the current) with the color attribute saved at startup. The cursor
2012 is also restored within the visible dimensions. */
2014 ScreenAttrib = startup_screen_attrib;
2016 /* Don't restore the screen if we are exiting less than 2 seconds
2017 after startup: we might be crashing, and the screen might show
2018 some vital clues to what's wrong. */
2019 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2021 ScreenClear ();
2022 if (screen_virtual_segment)
2023 dosv_refresh_virtual_screen (0, screen_size);
2025 if (update_row_len > saved_row_len)
2026 update_row_len = saved_row_len;
2027 if (current_rows > startup_screen_size_Y)
2028 current_rows = startup_screen_size_Y;
2030 if (tty->termscript)
2031 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2032 update_row_len / 2, current_rows);
2034 while (current_rows--)
2036 dosmemput (saved_row, update_row_len, display_row_start);
2037 if (screen_virtual_segment)
2038 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2039 update_row_len / 2);
2040 saved_row += saved_row_len;
2041 display_row_start += to_next_row;
2044 if (startup_pos_X < cursor_pos_X)
2045 cursor_pos_X = startup_pos_X;
2046 if (startup_pos_Y < cursor_pos_Y)
2047 cursor_pos_Y = startup_pos_Y;
2049 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2050 xfree (startup_screen_buffer);
2051 startup_screen_buffer = NULL;
2053 term_setup_done = 0;
2056 static void
2057 IT_set_terminal_window (struct frame *f, int foo)
2061 /* Remember the screen colors of the curent frame, to serve as the
2062 default colors for newly-created frames. */
2063 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2064 Smsdos_remember_default_colors, 1, 1, 0,
2065 doc: /* Remember the screen colors of the current frame. */)
2066 (frame)
2067 Lisp_Object frame;
2069 struct frame *f;
2071 CHECK_FRAME (frame);
2072 f = XFRAME (frame);
2074 /* This function is called after applying default-frame-alist to the
2075 initial frame. At that time, if reverse-colors option was
2076 specified in default-frame-alist, it was already applied, and
2077 frame colors are reversed. */
2078 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2079 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2082 void
2083 IT_set_frame_parameters (f, alist)
2084 struct frame *f;
2085 Lisp_Object alist;
2087 Lisp_Object tail;
2088 int i, j, length = XINT (Flength (alist));
2089 Lisp_Object *parms
2090 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2091 Lisp_Object *values
2092 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2093 /* Do we have to reverse the foreground and background colors? */
2094 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2095 int need_to_reverse, was_reverse = reverse;
2096 int redraw = 0, fg_set = 0, bg_set = 0;
2097 unsigned long orig_fg, orig_bg;
2098 Lisp_Object frame_bg, frame_fg;
2099 extern Lisp_Object Qdefault, QCforeground, QCbackground;
2100 struct tty_display_info *tty = FRAME_TTY (f);
2102 /* If we are creating a new frame, begin with the original screen colors
2103 used for the initial frame. */
2104 if (EQ (alist, Vdefault_frame_alist)
2105 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2107 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2108 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2109 init_frame_faces (f);
2111 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2112 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2113 frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2114 frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2115 /* frame_fg and frame_bg could be nil if, for example,
2116 f->param_alist is nil, e.g. if we are called from
2117 Fmake_terminal_frame. */
2118 if (NILP (frame_fg))
2119 frame_fg = build_string (unspecified_fg);
2120 if (NILP (frame_bg))
2121 frame_bg = build_string (unspecified_bg);
2123 /* Extract parm names and values into those vectors. */
2124 i = 0;
2125 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2127 Lisp_Object elt;
2129 elt = Fcar (tail);
2130 parms[i] = Fcar (elt);
2131 CHECK_SYMBOL (parms[i]);
2132 values[i] = Fcdr (elt);
2133 i++;
2136 j = i;
2138 for (i = 0; i < j; i++)
2140 Lisp_Object prop, val;
2142 prop = parms[i];
2143 val = values[i];
2145 if (EQ (prop, Qreverse))
2146 reverse = EQ (val, Qt);
2149 need_to_reverse = reverse && !was_reverse;
2150 if (tty->termscript && need_to_reverse)
2151 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2153 /* Now process the alist elements in reverse of specified order. */
2154 for (i--; i >= 0; i--)
2156 Lisp_Object prop, val, frame;
2158 prop = parms[i];
2159 val = values[i];
2161 if (EQ (prop, Qforeground_color))
2163 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2164 ? LFACE_BACKGROUND_INDEX
2165 : LFACE_FOREGROUND_INDEX);
2166 if (new_color != FACE_TTY_DEFAULT_COLOR
2167 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2168 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2170 FRAME_FOREGROUND_PIXEL (f) = new_color;
2171 /* Make sure the foreground of the default face for this
2172 frame is changed as well. */
2173 XSETFRAME (frame, f);
2174 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2175 val, frame);
2176 fg_set = 1;
2177 redraw = 1;
2178 if (tty->termscript)
2179 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2182 else if (EQ (prop, Qbackground_color))
2184 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2185 ? LFACE_FOREGROUND_INDEX
2186 : LFACE_BACKGROUND_INDEX);
2187 if (new_color != FACE_TTY_DEFAULT_COLOR
2188 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2189 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2191 FRAME_BACKGROUND_PIXEL (f) = new_color;
2192 /* Make sure the background of the default face for this
2193 frame is changed as well. */
2194 XSETFRAME (frame, f);
2195 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2196 val, frame);
2197 bg_set = 1;
2198 redraw = 1;
2199 if (tty->termscript)
2200 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2203 else if (EQ (prop, Qtitle))
2205 x_set_title (f, val);
2206 if (tty->termscript)
2207 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2209 else if (EQ (prop, Qcursor_type))
2211 IT_set_cursor_type (f, val);
2212 if (tty->termscript)
2213 fprintf (tty->termscript, "<CTYPE: %s>\n",
2214 EQ (val, Qbar) || EQ (val, Qhbar)
2215 || CONSP (val) && (EQ (XCAR (val), Qbar)
2216 || EQ (XCAR (val), Qhbar))
2217 ? "bar" : "box");
2219 else if (EQ (prop, Qtty_type))
2221 internal_terminal_init ();
2222 if (tty->termscript)
2223 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2224 SBYTES (val), SDATA (val));
2226 store_frame_param (f, prop, val);
2229 /* If they specified "reverse", but not the colors, we need to swap
2230 the current frame colors. */
2231 if (need_to_reverse)
2233 Lisp_Object frame;
2235 if (!fg_set)
2237 XSETFRAME (frame, f);
2238 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2239 tty_color_name (f, orig_bg),
2240 frame);
2241 redraw = 1;
2243 if (!bg_set)
2245 XSETFRAME (frame, f);
2246 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2247 tty_color_name (f, orig_fg),
2248 frame);
2249 redraw = 1;
2253 if (redraw)
2255 face_change_count++; /* forces xdisp.c to recompute basic faces */
2256 if (f == SELECTED_FRAME())
2257 redraw_frame (f);
2261 extern void init_frame_faces (FRAME_PTR);
2263 #endif /* !HAVE_X_WINDOWS */
2266 /* Do we need the internal terminal? */
2268 void
2269 internal_terminal_init ()
2271 static int init_needed = 1;
2272 char *term = getenv ("TERM"), *colors;
2273 struct frame *sf = SELECTED_FRAME();
2274 struct tty_display_info *tty;
2276 #ifdef HAVE_X_WINDOWS
2277 if (!inhibit_window_system)
2278 return;
2279 #endif
2281 /* If this is the initial terminal, we are done here. */
2282 if (sf->output_method == output_initial)
2283 return;
2285 internal_terminal
2286 = (!noninteractive) && term && !strcmp (term, "internal");
2288 #ifndef HAVE_X_WINDOWS
2289 if (!internal_terminal || inhibit_window_system)
2291 sf->output_method = output_termcap;
2292 return;
2295 tty = FRAME_TTY (sf);
2296 current_kboard->Vwindow_system = Qpc;
2297 sf->output_method = output_msdos_raw;
2298 if (init_needed)
2300 if (!tty->termscript && getenv ("EMACSTEST"))
2301 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2302 if (tty->termscript)
2304 time_t now = time (NULL);
2305 struct tm *tnow = localtime (&now);
2306 char tbuf[100];
2308 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2309 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2310 fprintf (tty->termscript, "=====================\n\n");
2313 Vinitial_window_system = Qpc;
2314 Vwindow_system_version = make_number (23); /* RE Emacs version */
2315 tty->terminal->type = output_msdos_raw;
2317 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2318 address. */
2319 screen_old_address = 0;
2321 /* Forget the stale screen colors as well. */
2322 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2324 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2325 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2326 bright_bg ();
2327 colors = getenv ("EMACSCOLORS");
2328 if (colors && strlen (colors) >= 2)
2330 /* The colors use 4 bits each (we enable bright background). */
2331 if (isdigit (colors[0]))
2332 colors[0] -= '0';
2333 else if (isxdigit (colors[0]))
2334 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2335 if (colors[0] >= 0 && colors[0] < 16)
2336 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2337 if (isdigit (colors[1]))
2338 colors[1] -= '0';
2339 else if (isxdigit (colors[1]))
2340 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2341 if (colors[1] >= 0 && colors[1] < 16)
2342 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2344 the_only_display_info.mouse_face_mouse_frame = NULL;
2345 the_only_display_info.mouse_face_deferred_gc = 0;
2346 the_only_display_info.mouse_face_beg_row =
2347 the_only_display_info.mouse_face_beg_col = -1;
2348 the_only_display_info.mouse_face_end_row =
2349 the_only_display_info.mouse_face_end_col = -1;
2350 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2351 the_only_display_info.mouse_face_window = Qnil;
2352 the_only_display_info.mouse_face_mouse_x =
2353 the_only_display_info.mouse_face_mouse_y = 0;
2354 the_only_display_info.mouse_face_defer = 0;
2355 the_only_display_info.mouse_face_hidden = 0;
2357 if (have_mouse) /* detected in dos_ttraw, which see */
2359 have_mouse = 1; /* enable mouse */
2360 mouse_visible = 0;
2361 mouse_setup_buttons (mouse_button_count);
2362 tty->terminal->mouse_position_hook = &mouse_get_pos;
2363 mouse_init ();
2366 if (tty->termscript && screen_size)
2367 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2368 screen_size_X, screen_size_Y);
2370 init_frame_faces (sf);
2371 init_needed = 0;
2373 #endif
2376 void
2377 initialize_msdos_display (struct terminal *term)
2379 term->rif = 0; /* we don't support window-based display */
2380 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2381 term->clear_to_end_hook = IT_clear_to_end;
2382 term->clear_frame_hook = IT_clear_screen;
2383 term->clear_end_of_line_hook = IT_clear_end_of_line;
2384 term->ins_del_lines_hook = 0;
2385 term->insert_glyphs_hook = IT_insert_glyphs;
2386 term->write_glyphs_hook = IT_write_glyphs;
2387 term->delete_glyphs_hook = IT_delete_glyphs;
2388 term->ring_bell_hook = IT_ring_bell;
2389 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2390 term->set_terminal_modes_hook = IT_set_terminal_modes;
2391 term->set_terminal_window_hook = IT_set_terminal_window;
2392 term->update_begin_hook = IT_update_begin;
2393 term->update_end_hook = IT_update_end;
2394 term->frame_up_to_date_hook = IT_frame_up_to_date;
2395 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2396 term->frame_rehighlight_hook = 0;
2397 term->frame_raise_lower_hook = 0;
2398 term->set_vertical_scroll_bar_hook = 0;
2399 term->condemn_scroll_bars_hook = 0;
2400 term->redeem_scroll_bar_hook = 0;
2401 term->judge_scroll_bars_hook = 0;
2402 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2405 dos_get_saved_screen (screen, rows, cols)
2406 char **screen;
2407 int *rows;
2408 int *cols;
2410 #ifndef HAVE_X_WINDOWS
2411 *screen = startup_screen_buffer;
2412 *cols = startup_screen_size_X;
2413 *rows = startup_screen_size_Y;
2414 return *screen != (char *)0;
2415 #else
2416 return 0;
2417 #endif
2420 #ifndef HAVE_X_WINDOWS
2422 /* We are not X, but we can emulate it well enough for our needs... */
2423 void
2424 check_x (void)
2426 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2427 error ("Not running under a window system");
2430 #endif
2433 /* ----------------------- Keyboard control ----------------------
2435 * Keymaps reflect the following keyboard layout:
2437 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2438 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2439 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2440 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2441 * SPACE
2444 #define Ignore 0x0000
2445 #define Normal 0x0000 /* normal key - alt changes scan-code */
2446 #define FctKey 0x1000 /* func key if c == 0, else c */
2447 #define Special 0x2000 /* func key even if c != 0 */
2448 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2449 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2450 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2451 #define Grey 0x6000 /* Grey keypad key */
2453 #define Alt 0x0100 /* alt scan-code */
2454 #define Ctrl 0x0200 /* ctrl scan-code */
2455 #define Shift 0x0400 /* shift scan-code */
2457 static int extended_kbd; /* 101 (102) keyboard present. */
2459 struct kbd_translate {
2460 unsigned char sc;
2461 unsigned char ch;
2462 unsigned short code;
2465 struct dos_keyboard_map
2467 char *unshifted;
2468 char *shifted;
2469 char *alt_gr;
2470 struct kbd_translate *translate_table;
2474 static struct dos_keyboard_map us_keyboard = {
2475 /* 0 1 2 3 4 5 */
2476 /* 01234567890123456789012345678901234567890 12345678901234 */
2477 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2478 /* 0123456789012345678901234567890123456789 012345678901234 */
2479 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2480 0, /* no Alt-Gr key */
2481 0 /* no translate table */
2484 static struct dos_keyboard_map fr_keyboard = {
2485 /* 0 1 2 3 4 5 */
2486 /* 012 3456789012345678901234567890123456789012345678901234 */
2487 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2488 /* 0123456789012345678901234567890123456789012345678901234 */
2489 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2490 /* 01234567 89012345678901234567890123456789012345678901234 */
2491 " ~#{[|`\\^@]} Ï ",
2492 0 /* no translate table */
2496 * Italian keyboard support, country code 39.
2497 * '<' 56:3c*0000
2498 * '>' 56:3e*0000
2499 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2500 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2503 static struct kbd_translate it_kbd_translate_table[] = {
2504 { 0x56, 0x3c, Normal | 13 },
2505 { 0x56, 0x3e, Normal | 27 },
2506 { 0, 0, 0 }
2508 static struct dos_keyboard_map it_keyboard = {
2509 /* 0 1 2 3 4 5 */
2510 /* 0 123456789012345678901234567890123456789012345678901234 */
2511 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2512 /* 01 23456789012345678901234567890123456789012345678901234 */
2513 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2514 /* 0123456789012345678901234567890123456789012345678901234 */
2515 " {}~` [] @# ",
2516 it_kbd_translate_table
2519 static struct dos_keyboard_map dk_keyboard = {
2520 /* 0 1 2 3 4 5 */
2521 /* 0123456789012345678901234567890123456789012345678901234 */
2522 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2523 /* 01 23456789012345678901234567890123456789012345678901234 */
2524 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2525 /* 0123456789012345678901234567890123456789012345678901234 */
2526 " @œ$ {[]} | ",
2527 0 /* no translate table */
2530 static struct kbd_translate jp_kbd_translate_table[] = {
2531 { 0x73, 0x5c, Normal | 0 },
2532 { 0x73, 0x5f, Normal | 0 },
2533 { 0x73, 0x1c, Map | 0 },
2534 { 0x7d, 0x5c, Normal | 13 },
2535 { 0x7d, 0x7c, Normal | 13 },
2536 { 0x7d, 0x1c, Map | 13 },
2537 { 0, 0, 0 }
2539 static struct dos_keyboard_map jp_keyboard = {
2540 /* 0 1 2 3 4 5 */
2541 /* 0123456789012 345678901234567890123456789012345678901234 */
2542 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2543 /* 01 23456789012345678901234567890123456789012345678901234 */
2544 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2545 0, /* no Alt-Gr key */
2546 jp_kbd_translate_table
2549 static struct keyboard_layout_list
2551 int country_code;
2552 struct dos_keyboard_map *keyboard_map;
2553 } keyboard_layout_list[] =
2555 1, &us_keyboard,
2556 33, &fr_keyboard,
2557 39, &it_keyboard,
2558 45, &dk_keyboard,
2559 81, &jp_keyboard
2562 static struct dos_keyboard_map *keyboard;
2563 static int keyboard_map_all;
2564 static int international_keyboard;
2567 dos_set_keyboard (code, always)
2568 int code;
2569 int always;
2571 int i;
2572 _go32_dpmi_registers regs;
2574 /* See if Keyb.Com is installed (for international keyboard support).
2575 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2576 of Windows 9X! So don't do that! */
2577 regs.x.ax = 0xad80;
2578 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2579 _go32_dpmi_simulate_int (0x2f, &regs);
2580 if (regs.h.al == 0xff)
2581 international_keyboard = 1;
2583 /* Initialize to US settings, for countries that don't have their own. */
2584 keyboard = keyboard_layout_list[0].keyboard_map;
2585 keyboard_map_all = always;
2586 dos_keyboard_layout = 1;
2588 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2589 if (code == keyboard_layout_list[i].country_code)
2591 keyboard = keyboard_layout_list[i].keyboard_map;
2592 keyboard_map_all = always;
2593 dos_keyboard_layout = code;
2594 return 1;
2596 return 0;
2599 static struct
2601 unsigned char char_code; /* normal code */
2602 unsigned char meta_code; /* M- code */
2603 unsigned char keypad_code; /* keypad code */
2604 unsigned char editkey_code; /* edit key */
2605 } keypad_translate_map[] = {
2606 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2607 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2608 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2609 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2610 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2611 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2612 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2613 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2614 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2615 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2616 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2619 static struct
2621 unsigned char char_code; /* normal code */
2622 unsigned char keypad_code; /* keypad code */
2623 } grey_key_translate_map[] = {
2624 '/', 0xaf, /* kp-decimal */
2625 '*', 0xaa, /* kp-multiply */
2626 '-', 0xad, /* kp-subtract */
2627 '+', 0xab, /* kp-add */
2628 '\r', 0x8d /* kp-enter */
2631 static unsigned short
2632 ibmpc_translate_map[] =
2634 /* --------------- 00 to 0f --------------- */
2635 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2636 Alt | ModFct | 0x1b, /* Escape */
2637 Normal | 1, /* '1' */
2638 Normal | 2, /* '2' */
2639 Normal | 3, /* '3' */
2640 Normal | 4, /* '4' */
2641 Normal | 5, /* '5' */
2642 Normal | 6, /* '6' */
2643 Normal | 7, /* '7' */
2644 Normal | 8, /* '8' */
2645 Normal | 9, /* '9' */
2646 Normal | 10, /* '0' */
2647 Normal | 11, /* '-' */
2648 Normal | 12, /* '=' */
2649 Special | 0x08, /* Backspace */
2650 ModFct | 0x74, /* Tab/Backtab */
2652 /* --------------- 10 to 1f --------------- */
2653 Map | 15, /* 'q' */
2654 Map | 16, /* 'w' */
2655 Map | 17, /* 'e' */
2656 Map | 18, /* 'r' */
2657 Map | 19, /* 't' */
2658 Map | 20, /* 'y' */
2659 Map | 21, /* 'u' */
2660 Map | 22, /* 'i' */
2661 Map | 23, /* 'o' */
2662 Map | 24, /* 'p' */
2663 Map | 25, /* '[' */
2664 Map | 26, /* ']' */
2665 ModFct | 0x0d, /* Return */
2666 Ignore, /* Ctrl */
2667 Map | 30, /* 'a' */
2668 Map | 31, /* 's' */
2670 /* --------------- 20 to 2f --------------- */
2671 Map | 32, /* 'd' */
2672 Map | 33, /* 'f' */
2673 Map | 34, /* 'g' */
2674 Map | 35, /* 'h' */
2675 Map | 36, /* 'j' */
2676 Map | 37, /* 'k' */
2677 Map | 38, /* 'l' */
2678 Map | 39, /* ';' */
2679 Map | 40, /* '\'' */
2680 Map | 0, /* '`' */
2681 Ignore, /* Left shift */
2682 Map | 41, /* '\\' */
2683 Map | 45, /* 'z' */
2684 Map | 46, /* 'x' */
2685 Map | 47, /* 'c' */
2686 Map | 48, /* 'v' */
2688 /* --------------- 30 to 3f --------------- */
2689 Map | 49, /* 'b' */
2690 Map | 50, /* 'n' */
2691 Map | 51, /* 'm' */
2692 Map | 52, /* ',' */
2693 Map | 53, /* '.' */
2694 Map | 54, /* '/' */
2695 Ignore, /* Right shift */
2696 Grey | 1, /* Grey * */
2697 Ignore, /* Alt */
2698 Normal | 55, /* ' ' */
2699 Ignore, /* Caps Lock */
2700 FctKey | 0xbe, /* F1 */
2701 FctKey | 0xbf, /* F2 */
2702 FctKey | 0xc0, /* F3 */
2703 FctKey | 0xc1, /* F4 */
2704 FctKey | 0xc2, /* F5 */
2706 /* --------------- 40 to 4f --------------- */
2707 FctKey | 0xc3, /* F6 */
2708 FctKey | 0xc4, /* F7 */
2709 FctKey | 0xc5, /* F8 */
2710 FctKey | 0xc6, /* F9 */
2711 FctKey | 0xc7, /* F10 */
2712 Ignore, /* Num Lock */
2713 Ignore, /* Scroll Lock */
2714 KeyPad | 7, /* Home */
2715 KeyPad | 8, /* Up */
2716 KeyPad | 9, /* Page Up */
2717 Grey | 2, /* Grey - */
2718 KeyPad | 4, /* Left */
2719 KeyPad | 5, /* Keypad 5 */
2720 KeyPad | 6, /* Right */
2721 Grey | 3, /* Grey + */
2722 KeyPad | 1, /* End */
2724 /* --------------- 50 to 5f --------------- */
2725 KeyPad | 2, /* Down */
2726 KeyPad | 3, /* Page Down */
2727 KeyPad | 0, /* Insert */
2728 KeyPad | 10, /* Delete */
2729 Shift | FctKey | 0xbe, /* (Shift) F1 */
2730 Shift | FctKey | 0xbf, /* (Shift) F2 */
2731 Shift | FctKey | 0xc0, /* (Shift) F3 */
2732 Shift | FctKey | 0xc1, /* (Shift) F4 */
2733 Shift | FctKey | 0xc2, /* (Shift) F5 */
2734 Shift | FctKey | 0xc3, /* (Shift) F6 */
2735 Shift | FctKey | 0xc4, /* (Shift) F7 */
2736 Shift | FctKey | 0xc5, /* (Shift) F8 */
2737 Shift | FctKey | 0xc6, /* (Shift) F9 */
2738 Shift | FctKey | 0xc7, /* (Shift) F10 */
2739 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2740 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2742 /* --------------- 60 to 6f --------------- */
2743 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2744 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2745 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2746 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2747 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2748 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2749 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2750 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2751 Alt | FctKey | 0xbe, /* (Alt) F1 */
2752 Alt | FctKey | 0xbf, /* (Alt) F2 */
2753 Alt | FctKey | 0xc0, /* (Alt) F3 */
2754 Alt | FctKey | 0xc1, /* (Alt) F4 */
2755 Alt | FctKey | 0xc2, /* (Alt) F5 */
2756 Alt | FctKey | 0xc3, /* (Alt) F6 */
2757 Alt | FctKey | 0xc4, /* (Alt) F7 */
2758 Alt | FctKey | 0xc5, /* (Alt) F8 */
2760 /* --------------- 70 to 7f --------------- */
2761 Alt | FctKey | 0xc6, /* (Alt) F9 */
2762 Alt | FctKey | 0xc7, /* (Alt) F10 */
2763 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2764 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2765 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2766 Ctrl | KeyPad | 1, /* (Ctrl) End */
2767 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2768 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2769 Alt | Map | 1, /* '1' */
2770 Alt | Map | 2, /* '2' */
2771 Alt | Map | 3, /* '3' */
2772 Alt | Map | 4, /* '4' */
2773 Alt | Map | 5, /* '5' */
2774 Alt | Map | 6, /* '6' */
2775 Alt | Map | 7, /* '7' */
2776 Alt | Map | 8, /* '8' */
2778 /* --------------- 80 to 8f --------------- */
2779 Alt | Map | 9, /* '9' */
2780 Alt | Map | 10, /* '0' */
2781 Alt | Map | 11, /* '-' */
2782 Alt | Map | 12, /* '=' */
2783 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2784 FctKey | 0xc8, /* F11 */
2785 FctKey | 0xc9, /* F12 */
2786 Shift | FctKey | 0xc8, /* (Shift) F11 */
2787 Shift | FctKey | 0xc9, /* (Shift) F12 */
2788 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2789 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2790 Alt | FctKey | 0xc8, /* (Alt) F11 */
2791 Alt | FctKey | 0xc9, /* (Alt) F12 */
2792 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2793 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2794 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2796 /* --------------- 90 to 9f --------------- */
2797 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2798 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2799 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2800 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2801 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2802 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2803 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2804 Alt | FctKey | 0x50, /* (Alt) Home */
2805 Alt | FctKey | 0x52, /* (Alt) Up */
2806 Alt | FctKey | 0x55, /* (Alt) Page Up */
2807 Ignore, /* NO KEY */
2808 Alt | FctKey | 0x51, /* (Alt) Left */
2809 Ignore, /* NO KEY */
2810 Alt | FctKey | 0x53, /* (Alt) Right */
2811 Ignore, /* NO KEY */
2812 Alt | FctKey | 0x57, /* (Alt) End */
2814 /* --------------- a0 to af --------------- */
2815 Alt | KeyPad | 2, /* (Alt) Down */
2816 Alt | KeyPad | 3, /* (Alt) Page Down */
2817 Alt | KeyPad | 0, /* (Alt) Insert */
2818 Alt | KeyPad | 10, /* (Alt) Delete */
2819 Alt | Grey | 0, /* (Alt) Grey / */
2820 Alt | FctKey | 0x09, /* (Alt) Tab */
2821 Alt | Grey | 4 /* (Alt) Keypad Enter */
2824 /* These bit-positions corresponds to values returned by BIOS */
2825 #define SHIFT_P 0x0003 /* two bits! */
2826 #define CTRL_P 0x0004
2827 #define ALT_P 0x0008
2828 #define SCRLOCK_P 0x0010
2829 #define NUMLOCK_P 0x0020
2830 #define CAPSLOCK_P 0x0040
2831 #define ALT_GR_P 0x0800
2832 #define SUPER_P 0x4000 /* pseudo */
2833 #define HYPER_P 0x8000 /* pseudo */
2835 static int
2836 dos_get_modifiers (keymask)
2837 int *keymask;
2839 union REGS regs;
2840 int mask, modifiers = 0;
2842 /* Calculate modifier bits */
2843 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2844 int86 (0x16, &regs, &regs);
2846 if (!extended_kbd)
2848 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2849 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2851 else
2853 mask = regs.h.al & (SHIFT_P |
2854 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2856 /* Do not break international keyboard support. */
2857 /* When Keyb.Com is loaded, the right Alt key is */
2858 /* used for accessing characters like { and } */
2859 if (regs.h.ah & 2) /* Left ALT pressed ? */
2860 mask |= ALT_P;
2862 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2864 mask |= ALT_GR_P;
2865 if (dos_hyper_key == 1)
2867 mask |= HYPER_P;
2868 modifiers |= hyper_modifier;
2870 else if (dos_super_key == 1)
2872 mask |= SUPER_P;
2873 modifiers |= super_modifier;
2875 else if (!international_keyboard)
2877 /* If Keyb.Com is NOT installed, let Right Alt behave
2878 like the Left Alt. */
2879 mask &= ~ALT_GR_P;
2880 mask |= ALT_P;
2884 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2885 mask |= CTRL_P;
2887 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2889 if (dos_hyper_key == 2)
2891 mask |= HYPER_P;
2892 modifiers |= hyper_modifier;
2894 else if (dos_super_key == 2)
2896 mask |= SUPER_P;
2897 modifiers |= super_modifier;
2899 else
2900 mask |= CTRL_P;
2904 if (mask & SHIFT_P)
2905 modifiers |= shift_modifier;
2906 if (mask & CTRL_P)
2907 modifiers |= ctrl_modifier;
2908 if (mask & ALT_P)
2909 modifiers |= meta_modifier;
2911 if (keymask)
2912 *keymask = mask;
2913 return modifiers;
2916 #define NUM_RECENT_DOSKEYS (100)
2917 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2918 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2919 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2921 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2922 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2923 Each input key receives two values in this vector: first the ASCII code,
2924 and then the scan code. */)
2927 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2929 if (total_doskeys < NUM_RECENT_DOSKEYS)
2930 return Fvector (total_doskeys, keys);
2931 else
2933 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2934 bcopy (keys + recent_doskeys_index,
2935 XVECTOR (val)->contents,
2936 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2937 bcopy (keys,
2938 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2939 recent_doskeys_index * sizeof (Lisp_Object));
2940 return val;
2944 /* Get a char from keyboard. Function keys are put into the event queue. */
2945 static int
2946 dos_rawgetc ()
2948 struct input_event event;
2949 union REGS regs;
2950 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
2951 EVENT_INIT (event);
2953 #ifndef HAVE_X_WINDOWS
2954 /* Maybe put the cursor where it should be. */
2955 IT_cmgoto (SELECTED_FRAME());
2956 #endif
2958 /* The following condition is equivalent to `kbhit ()', except that
2959 it uses the bios to do its job. This pleases DESQview/X. */
2960 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2961 int86 (0x16, &regs, &regs),
2962 (regs.x.flags & 0x40) == 0)
2964 union REGS regs;
2965 register unsigned char c;
2966 int modifiers, sc, code = -1, mask, kp_mode;
2968 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2969 int86 (0x16, &regs, &regs);
2970 c = regs.h.al;
2971 sc = regs.h.ah;
2973 total_doskeys += 2;
2974 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2975 = make_number (c);
2976 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2977 recent_doskeys_index = 0;
2978 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2979 = make_number (sc);
2980 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2981 recent_doskeys_index = 0;
2983 modifiers = dos_get_modifiers (&mask);
2985 #ifndef HAVE_X_WINDOWS
2986 if (!NILP (Vdos_display_scancodes))
2988 char buf[11];
2989 sprintf (buf, "%02x:%02x*%04x",
2990 (unsigned) (sc&0xff), (unsigned) c, mask);
2991 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2993 #endif
2995 if (sc == 0xe0)
2997 switch (c)
2999 case 10: /* Ctrl Grey Enter */
3000 code = Ctrl | Grey | 4;
3001 break;
3002 case 13: /* Grey Enter */
3003 code = Grey | 4;
3004 break;
3005 case '/': /* Grey / */
3006 code = Grey | 0;
3007 break;
3008 default:
3009 continue;
3011 c = 0;
3013 else
3015 /* Try the keyboard-private translation table first. */
3016 if (keyboard->translate_table)
3018 struct kbd_translate *p = keyboard->translate_table;
3020 while (p->sc)
3022 if (p->sc == sc && p->ch == c)
3024 code = p->code;
3025 break;
3027 p++;
3030 /* If the private table didn't translate it, use the general
3031 one. */
3032 if (code == -1)
3034 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3035 continue;
3036 if ((code = ibmpc_translate_map[sc]) == Ignore)
3037 continue;
3041 if (c == 0)
3043 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3044 Emacs is ready to read a key. Therefore, if they press
3045 `Alt-x' when Emacs is busy, by the time we get to
3046 `dos_get_modifiers', they might have already released the
3047 Alt key, and Emacs gets just `x', which is BAD.
3048 However, for keys with the `Map' property set, the ASCII
3049 code returns zero only if Alt is pressed. So, when we DON'T
3050 have to support international_keyboard, we don't have to
3051 distinguish between the left and right Alt keys, and we
3052 can set the META modifier for any keys with the `Map'
3053 property if they return zero ASCII code (c = 0). */
3054 if ( (code & Alt)
3055 || ( (code & 0xf000) == Map && !international_keyboard))
3056 modifiers |= meta_modifier;
3057 if (code & Ctrl)
3058 modifiers |= ctrl_modifier;
3059 if (code & Shift)
3060 modifiers |= shift_modifier;
3063 switch (code & 0xf000)
3065 case ModFct:
3066 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3067 return c;
3068 c = 0; /* Special */
3070 case FctKey:
3071 if (c != 0)
3072 return c;
3074 case Special:
3075 code |= 0xff00;
3076 break;
3078 case Normal:
3079 if (sc == 0)
3081 if (c == 0) /* ctrl-break */
3082 continue;
3083 return c; /* ALT-nnn */
3085 if (!keyboard_map_all)
3087 if (c != ' ')
3088 return c;
3089 code = c;
3090 break;
3093 case Map:
3094 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3095 if (!keyboard_map_all)
3096 return c;
3098 code &= 0xff;
3099 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3100 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3102 if (mask & SHIFT_P)
3104 code = keyboard->shifted[code];
3105 mask -= SHIFT_P;
3106 modifiers &= ~shift_modifier;
3108 else
3109 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3110 code = keyboard->alt_gr[code];
3111 else
3112 code = keyboard->unshifted[code];
3113 break;
3115 case KeyPad:
3116 code &= 0xff;
3117 if (c == 0xe0) /* edit key */
3118 kp_mode = 3;
3119 else
3120 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3121 kp_mode = dos_keypad_mode & 0x03;
3122 else
3123 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3125 switch (kp_mode)
3127 case 0:
3128 if (code == 10 && dos_decimal_point)
3129 return dos_decimal_point;
3130 return keypad_translate_map[code].char_code;
3132 case 1:
3133 code = 0xff00 | keypad_translate_map[code].keypad_code;
3134 break;
3136 case 2:
3137 code = keypad_translate_map[code].meta_code;
3138 modifiers = meta_modifier;
3139 break;
3141 case 3:
3142 code = 0xff00 | keypad_translate_map[code].editkey_code;
3143 break;
3145 break;
3147 case Grey:
3148 code &= 0xff;
3149 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3150 if (dos_keypad_mode & kp_mode)
3151 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3152 else
3153 code = grey_key_translate_map[code].char_code;
3154 break;
3157 make_event:
3158 if (code == 0)
3159 continue;
3161 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3163 clear_mouse_face (dpyinfo);
3164 dpyinfo->mouse_face_hidden = 1;
3167 if (code >= 0x100)
3168 event.kind = NON_ASCII_KEYSTROKE_EVENT;
3169 else
3170 event.kind = ASCII_KEYSTROKE_EVENT;
3171 event.code = code;
3172 event.modifiers = modifiers;
3173 event.frame_or_window = selected_frame;
3174 event.arg = Qnil;
3175 event.timestamp = event_timestamp ();
3176 kbd_buffer_store_event (&event);
3179 if (have_mouse > 0 && !mouse_preempted)
3181 int but, press, x, y, ok;
3182 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3183 Lisp_Object mouse_window = Qnil;
3185 /* Check for mouse movement *before* buttons. */
3186 mouse_check_moved ();
3188 /* If the mouse moved from the spot of its last sighting, we
3189 might need to update mouse highlight. */
3190 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3192 if (dpyinfo->mouse_face_hidden)
3194 dpyinfo->mouse_face_hidden = 0;
3195 clear_mouse_face (dpyinfo);
3198 /* Generate SELECT_WINDOW_EVENTs when needed. */
3199 if (!NILP (Vmouse_autoselect_window))
3201 mouse_window = window_from_coordinates (SELECTED_FRAME(),
3202 mouse_last_x,
3203 mouse_last_y,
3204 0, 0, 0, 0);
3205 /* A window will be selected only when it is not
3206 selected now, and the last mouse movement event was
3207 not in it. A minibuffer window will be selected iff
3208 it is active. */
3209 if (WINDOWP (mouse_window)
3210 && !EQ (mouse_window, last_mouse_window)
3211 && !EQ (mouse_window, selected_window))
3213 event.kind = SELECT_WINDOW_EVENT;
3214 event.frame_or_window = mouse_window;
3215 event.arg = Qnil;
3216 event.timestamp = event_timestamp ();
3217 kbd_buffer_store_event (&event);
3219 last_mouse_window = mouse_window;
3221 else
3222 last_mouse_window = Qnil;
3224 previous_help_echo_string = help_echo_string;
3225 help_echo_string = help_echo_object = help_echo_window = Qnil;
3226 help_echo_pos = -1;
3227 IT_note_mouse_highlight (SELECTED_FRAME(),
3228 mouse_last_x, mouse_last_y);
3229 /* If the contents of the global variable help_echo has
3230 changed, generate a HELP_EVENT. */
3231 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3233 event.kind = HELP_EVENT;
3234 event.frame_or_window = selected_frame;
3235 event.arg = help_echo_object;
3236 event.x = WINDOWP (help_echo_window)
3237 ? help_echo_window : selected_frame;
3238 event.y = help_echo_string;
3239 event.timestamp = event_timestamp ();
3240 event.code = help_echo_pos;
3241 kbd_buffer_store_event (&event);
3245 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3246 for (press = 0; press < 2; press++)
3248 int button_num = but;
3250 if (press)
3251 ok = mouse_pressed (but, &x, &y);
3252 else
3253 ok = mouse_released (but, &x, &y);
3254 if (ok)
3256 /* Allow a simultaneous press/release of Mouse-1 and
3257 Mouse-2 to simulate Mouse-3 on two-button mice. */
3258 if (mouse_button_count == 2 && but < 2)
3260 int x2, y2; /* don't clobber original coordinates */
3262 /* If only one button is pressed, wait 100 msec and
3263 check again. This way, Speedy Gonzales isn't
3264 punished, while the slow get their chance. */
3265 if (press && mouse_pressed (1-but, &x2, &y2)
3266 || !press && mouse_released (1-but, &x2, &y2))
3267 button_num = 2;
3268 else
3270 delay (100);
3271 if (press && mouse_pressed (1-but, &x2, &y2)
3272 || !press && mouse_released (1-but, &x2, &y2))
3273 button_num = 2;
3277 event.kind = MOUSE_CLICK_EVENT;
3278 event.code = button_num;
3279 event.modifiers = dos_get_modifiers (0)
3280 | (press ? down_modifier : up_modifier);
3281 event.x = make_number (x);
3282 event.y = make_number (y);
3283 event.frame_or_window = selected_frame;
3284 event.arg = Qnil;
3285 event.timestamp = event_timestamp ();
3286 kbd_buffer_store_event (&event);
3291 return -1;
3294 static int prev_get_char = -1;
3296 /* Return 1 if a key is ready to be read without suspending execution. */
3298 dos_keysns ()
3300 if (prev_get_char != -1)
3301 return 1;
3302 else
3303 return ((prev_get_char = dos_rawgetc ()) != -1);
3306 /* Read a key. Return -1 if no key is ready. */
3308 dos_keyread ()
3310 if (prev_get_char != -1)
3312 int c = prev_get_char;
3313 prev_get_char = -1;
3314 return c;
3316 else
3317 return dos_rawgetc ();
3320 #ifndef HAVE_X_WINDOWS
3322 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3323 for now.
3325 Actually, I don't know the meaning of all the parameters of the functions
3326 here -- I only know how they are called by xmenu.c. I could of course
3327 grab the nearest Xlib manual (down the hall, second-to-last door on the
3328 left), but I don't think it's worth the effort. */
3330 /* These hold text of the current and the previous menu help messages. */
3331 static char *menu_help_message, *prev_menu_help_message;
3332 /* Pane number and item number of the menu item which generated the
3333 last menu help message. */
3334 static int menu_help_paneno, menu_help_itemno;
3336 static XMenu *
3337 IT_menu_create ()
3339 XMenu *menu;
3341 menu = (XMenu *) xmalloc (sizeof (XMenu));
3342 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3343 return menu;
3346 /* Allocate some (more) memory for MENU ensuring that there is room for one
3347 for item. */
3349 static void
3350 IT_menu_make_room (XMenu *menu)
3352 if (menu->allocated == 0)
3354 int count = menu->allocated = 10;
3355 menu->text = (char **) xmalloc (count * sizeof (char *));
3356 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3357 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3358 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3360 else if (menu->allocated == menu->count)
3362 int count = menu->allocated = menu->allocated + 10;
3363 menu->text
3364 = (char **) xrealloc (menu->text, count * sizeof (char *));
3365 menu->submenu
3366 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3367 menu->panenumber
3368 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3369 menu->help_text
3370 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3374 /* Search the given menu structure for a given pane number. */
3376 static XMenu *
3377 IT_menu_search_pane (XMenu *menu, int pane)
3379 int i;
3380 XMenu *try;
3382 for (i = 0; i < menu->count; i++)
3383 if (menu->submenu[i])
3385 if (pane == menu->panenumber[i])
3386 return menu->submenu[i];
3387 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3388 return try;
3390 return (XMenu *) 0;
3393 /* Determine how much screen space a given menu needs. */
3395 static void
3396 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3398 int i, h2, w2, maxsubwidth, maxheight;
3400 maxsubwidth = 0;
3401 maxheight = menu->count;
3402 for (i = 0; i < menu->count; i++)
3404 if (menu->submenu[i])
3406 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3407 if (w2 > maxsubwidth) maxsubwidth = w2;
3408 if (i + h2 > maxheight) maxheight = i + h2;
3411 *width = menu->width + maxsubwidth;
3412 *height = maxheight;
3415 /* Display MENU at (X,Y) using FACES. */
3417 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3418 do \
3420 (GLYPH).type = CHAR_GLYPH; \
3421 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3422 (GLYPH).charpos = -1; \
3424 while (0)
3426 static void
3427 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3429 int i, j, face, width, mx, my, enabled, mousehere, row, col;
3430 struct glyph *text, *p;
3431 const unsigned char *q;
3432 struct frame *sf = SELECTED_FRAME();
3434 menu_help_message = NULL;
3436 width = menu->width;
3437 /* We multiply width by 2 to account for possible control characters.
3438 FIXME: cater to non-ASCII characters in menus. */
3439 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3440 ScreenGetCursor (&row, &col);
3441 mouse_get_xy (&mx, &my);
3442 IT_update_begin (sf);
3443 for (i = 0; i < menu->count; i++)
3445 int max_width = width + 2;
3447 IT_cursor_to (sf, y + i, x);
3448 enabled
3449 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3450 mousehere = (y + i == my && x <= mx && mx < x + max_width);
3451 face = faces[enabled + mousehere * 2];
3452 /* The following if clause means that we display the menu help
3453 strings even if the menu item is currently disabled. */
3454 if (disp_help && enabled + mousehere * 2 >= 2)
3456 menu_help_message = menu->help_text[i];
3457 menu_help_paneno = pn - 1;
3458 menu_help_itemno = i;
3460 p = text;
3461 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3462 p++;
3463 for (j = 0, q = menu->text[i]; *q; j++)
3465 unsigned c = STRING_CHAR_ADVANCE (q);
3467 if (c > 26)
3469 BUILD_CHAR_GLYPH (*p, c, face, 0);
3470 p++;
3472 else /* make '^x' */
3474 BUILD_CHAR_GLYPH (*p, '^', face, 0);
3475 p++;
3476 j++;
3477 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3478 p++;
3481 /* Don't let the menu text overflow into the next screen row. */
3482 if (x + max_width > screen_size_X)
3484 max_width = screen_size_X - x;
3485 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3487 for (; j < max_width - 2; j++, p++)
3488 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3490 /* 16 is the character code of a character that on DOS terminal
3491 produces a nice-looking right-pointing arrow glyph. */
3492 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3493 p++;
3494 IT_write_glyphs (sf, text, max_width);
3496 IT_update_end (sf);
3497 IT_cursor_to (sf, row, col);
3498 xfree (text);
3501 /* --------------------------- X Menu emulation ---------------------- */
3503 /* Report availability of menus. */
3506 have_menus_p () { return 1; }
3508 /* Create a brand new menu structure. */
3510 XMenu *
3511 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3513 return IT_menu_create ();
3516 /* Create a new pane and place it on the outer-most level. It is not
3517 clear that it should be placed out there, but I don't know what else
3518 to do. */
3521 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3523 int len;
3524 char *p;
3526 if (!enable)
3527 abort ();
3529 IT_menu_make_room (menu);
3530 menu->submenu[menu->count] = IT_menu_create ();
3531 menu->text[menu->count] = txt;
3532 menu->panenumber[menu->count] = ++menu->panecount;
3533 menu->help_text[menu->count] = NULL;
3534 menu->count++;
3536 /* Adjust length for possible control characters (which will
3537 be written as ^x). */
3538 for (len = strlen (txt), p = txt; *p; p++)
3539 if (*p < 27)
3540 len++;
3542 if (len > menu->width)
3543 menu->width = len;
3545 return menu->panecount;
3548 /* Create a new item in a menu pane. */
3551 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3552 int foo, char *txt, int enable, char *help_text)
3554 int len;
3555 char *p;
3557 if (pane)
3558 if (!(menu = IT_menu_search_pane (menu, pane)))
3559 return XM_FAILURE;
3560 IT_menu_make_room (menu);
3561 menu->submenu[menu->count] = (XMenu *) 0;
3562 menu->text[menu->count] = txt;
3563 menu->panenumber[menu->count] = enable;
3564 menu->help_text[menu->count] = help_text;
3565 menu->count++;
3567 /* Adjust length for possible control characters (which will
3568 be written as ^x). */
3569 for (len = strlen (txt), p = txt; *p; p++)
3570 if (*p < 27)
3571 len++;
3573 if (len > menu->width)
3574 menu->width = len;
3576 return XM_SUCCESS;
3579 /* Decide where the menu would be placed if requested at (X,Y). */
3581 void
3582 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3583 int *ulx, int *uly, int *width, int *height)
3585 IT_menu_calc_size (menu, width, height);
3586 *ulx = x + 1;
3587 *uly = y;
3588 *width += 2;
3591 struct IT_menu_state
3593 void *screen_behind;
3594 XMenu *menu;
3595 int pane;
3596 int x, y;
3600 /* Display menu, wait for user's response, and return that response. */
3603 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3604 int x0, int y0, unsigned ButtonMask, char **txt,
3605 void (*help_callback)(char *, int, int))
3607 struct IT_menu_state *state;
3608 int statecount, x, y, i, b, screensize, leave, result, onepane;
3609 int title_faces[4]; /* face to display the menu title */
3610 int faces[4], buffers_num_deleted = 0;
3611 struct frame *sf = SELECTED_FRAME();
3612 Lisp_Object saved_echo_area_message, selectface;
3614 /* Just in case we got here without a mouse present... */
3615 if (have_mouse <= 0)
3616 return XM_IA_SELECT;
3617 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3618 around the display. */
3619 if (x0 <= 0)
3620 x0 = 1;
3621 if (y0 <= 0)
3622 y0 = 1;
3624 /* We will process all the mouse events directly, so we had
3625 better prevent dos_rawgetc from stealing them from us. */
3626 mouse_preempted++;
3628 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3629 screensize = screen_size * 2;
3630 faces[0]
3631 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3632 DEFAULT_FACE_ID, 1);
3633 faces[1]
3634 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3635 DEFAULT_FACE_ID, 1);
3636 selectface = intern ("msdos-menu-select-face");
3637 faces[2] = lookup_derived_face (sf, selectface,
3638 faces[0], 1);
3639 faces[3] = lookup_derived_face (sf, selectface,
3640 faces[1], 1);
3642 /* Make sure the menu title is always displayed with
3643 `msdos-menu-active-face', no matter where the mouse pointer is. */
3644 for (i = 0; i < 4; i++)
3645 title_faces[i] = faces[3];
3647 statecount = 1;
3649 /* Don't let the title for the "Buffers" popup menu include a
3650 digit (which is ugly).
3652 This is a terrible kludge, but I think the "Buffers" case is
3653 the only one where the title includes a number, so it doesn't
3654 seem to be necessary to make this more general. */
3655 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3657 menu->text[0][7] = '\0';
3658 buffers_num_deleted = 1;
3661 /* We need to save the current echo area message, so that we could
3662 restore it below, before we exit. See the commentary below,
3663 before the call to message_with_string. */
3664 saved_echo_area_message = Fcurrent_message ();
3665 state[0].menu = menu;
3666 mouse_off ();
3667 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3669 /* Turn off the cursor. Otherwise it shows through the menu
3670 panes, which is ugly. */
3671 IT_display_cursor (0);
3673 /* Display the menu title. */
3674 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3675 if (buffers_num_deleted)
3676 menu->text[0][7] = ' ';
3677 if ((onepane = menu->count == 1 && menu->submenu[0]))
3679 menu->width = menu->submenu[0]->width;
3680 state[0].menu = menu->submenu[0];
3682 else
3684 state[0].menu = menu;
3686 state[0].x = x0 - 1;
3687 state[0].y = y0;
3688 state[0].pane = onepane;
3690 mouse_last_x = -1; /* A hack that forces display. */
3691 leave = 0;
3692 while (!leave)
3694 if (!mouse_visible) mouse_on ();
3695 mouse_check_moved ();
3696 if (sf->mouse_moved)
3698 sf->mouse_moved = 0;
3699 result = XM_IA_SELECT;
3700 mouse_get_xy (&x, &y);
3701 for (i = 0; i < statecount; i++)
3702 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3704 int dy = y - state[i].y;
3705 if (0 <= dy && dy < state[i].menu->count)
3707 if (!state[i].menu->submenu[dy])
3708 if (state[i].menu->panenumber[dy])
3709 result = XM_SUCCESS;
3710 else
3711 result = XM_IA_SELECT;
3712 *pane = state[i].pane - 1;
3713 *selidx = dy;
3714 /* We hit some part of a menu, so drop extra menus that
3715 have been opened. That does not include an open and
3716 active submenu. */
3717 if (i != statecount - 2
3718 || state[i].menu->submenu[dy] != state[i+1].menu)
3719 while (i != statecount - 1)
3721 statecount--;
3722 mouse_off ();
3723 ScreenUpdate (state[statecount].screen_behind);
3724 if (screen_virtual_segment)
3725 dosv_refresh_virtual_screen (0, screen_size);
3726 xfree (state[statecount].screen_behind);
3728 if (i == statecount - 1 && state[i].menu->submenu[dy])
3730 IT_menu_display (state[i].menu,
3731 state[i].y,
3732 state[i].x,
3733 state[i].pane,
3734 faces, 1);
3735 state[statecount].menu = state[i].menu->submenu[dy];
3736 state[statecount].pane = state[i].menu->panenumber[dy];
3737 mouse_off ();
3738 ScreenRetrieve (state[statecount].screen_behind
3739 = xmalloc (screensize));
3740 state[statecount].x
3741 = state[i].x + state[i].menu->width + 2;
3742 state[statecount].y = y;
3743 statecount++;
3747 IT_menu_display (state[statecount - 1].menu,
3748 state[statecount - 1].y,
3749 state[statecount - 1].x,
3750 state[statecount - 1].pane,
3751 faces, 1);
3753 else
3755 if ((menu_help_message || prev_menu_help_message)
3756 && menu_help_message != prev_menu_help_message)
3758 help_callback (menu_help_message,
3759 menu_help_paneno, menu_help_itemno);
3760 IT_display_cursor (0);
3761 prev_menu_help_message = menu_help_message;
3763 /* We are busy-waiting for the mouse to move, so let's be nice
3764 to other Windows applications by releasing our time slice. */
3765 __dpmi_yield ();
3767 for (b = 0; b < mouse_button_count && !leave; b++)
3769 /* Only leave if user both pressed and released the mouse, and in
3770 that order. This avoids popping down the menu pane unless
3771 the user is really done with it. */
3772 if (mouse_pressed (b, &x, &y))
3774 while (mouse_button_depressed (b, &x, &y))
3775 __dpmi_yield ();
3776 leave = 1;
3778 (void) mouse_released (b, &x, &y);
3782 mouse_off ();
3783 ScreenUpdate (state[0].screen_behind);
3784 if (screen_virtual_segment)
3785 dosv_refresh_virtual_screen (0, screen_size);
3787 /* We have a situation here. ScreenUpdate has just restored the
3788 screen contents as it was before we started drawing this menu.
3789 That includes any echo area message that could have been
3790 displayed back then. (In reality, that echo area message will
3791 almost always be the ``keystroke echo'' that echoes the sequence
3792 of menu items chosen by the user.) However, if the menu had some
3793 help messages, then displaying those messages caused Emacs to
3794 forget about the original echo area message. So when
3795 ScreenUpdate restored it, it created a discrepancy between the
3796 actual screen contents and what Emacs internal data structures
3797 know about it.
3799 To avoid this conflict, we force Emacs to restore the original
3800 echo area message as we found it when we entered this function.
3801 The irony of this is that we then erase the restored message
3802 right away, so the only purpose of restoring it is so that
3803 erasing it works correctly... */
3804 if (! NILP (saved_echo_area_message))
3805 message_with_string ("%s", saved_echo_area_message, 0);
3806 message (0);
3807 while (statecount--)
3808 xfree (state[statecount].screen_behind);
3809 IT_display_cursor (1); /* turn cursor back on */
3810 /* Clean up any mouse events that are waiting inside Emacs event queue.
3811 These events are likely to be generated before the menu was even
3812 displayed, probably because the user pressed and released the button
3813 (which invoked the menu) too quickly. If we don't remove these events,
3814 Emacs will process them after we return and surprise the user. */
3815 discard_mouse_events ();
3816 mouse_clear_clicks ();
3817 if (!kbd_buffer_events_waiting (1))
3818 clear_input_pending ();
3819 /* Allow mouse events generation by dos_rawgetc. */
3820 mouse_preempted--;
3821 return result;
3824 /* Dispose of a menu. */
3826 void
3827 XMenuDestroy (Display *foo, XMenu *menu)
3829 int i;
3830 if (menu->allocated)
3832 for (i = 0; i < menu->count; i++)
3833 if (menu->submenu[i])
3834 XMenuDestroy (foo, menu->submenu[i]);
3835 xfree (menu->text);
3836 xfree (menu->submenu);
3837 xfree (menu->panenumber);
3838 xfree (menu->help_text);
3840 xfree (menu);
3841 menu_help_message = prev_menu_help_message = NULL;
3845 x_pixel_width (struct frame *f)
3847 return FRAME_COLS (f);
3851 x_pixel_height (struct frame *f)
3853 return FRAME_LINES (f);
3855 #endif /* !HAVE_X_WINDOWS */
3857 /* ----------------------- DOS / UNIX conversion --------------------- */
3859 void msdos_downcase_filename (unsigned char *);
3861 /* Destructively turn backslashes into slashes. */
3863 void
3864 dostounix_filename (p)
3865 register char *p;
3867 msdos_downcase_filename (p);
3869 while (*p)
3871 if (*p == '\\')
3872 *p = '/';
3873 p++;
3877 /* Destructively turn slashes into backslashes. */
3879 void
3880 unixtodos_filename (p)
3881 register char *p;
3883 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3885 *p += 'a' - 'A';
3886 p += 2;
3889 while (*p)
3891 if (*p == '/')
3892 *p = '\\';
3893 p++;
3897 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3900 getdefdir (drive, dst)
3901 int drive;
3902 char *dst;
3904 char in_path[4], *p = in_path, e = errno;
3906 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3907 if (drive != 0)
3909 *p++ = drive + 'A' - 1;
3910 *p++ = ':';
3913 *p++ = '.';
3914 *p = '\0';
3915 errno = 0;
3916 _fixpath (in_path, dst);
3917 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3918 it queries the LFN support, so ignore that error. */
3919 if ((errno && errno != ENOSYS) || *dst == '\0')
3920 return 0;
3922 msdos_downcase_filename (dst);
3924 errno = e;
3925 return 1;
3928 char *
3929 emacs_root_dir (void)
3931 static char root_dir[4];
3933 sprintf (root_dir, "%c:/", 'A' + getdisk ());
3934 root_dir[0] = tolower (root_dir[0]);
3935 return root_dir;
3938 /* Remove all CR's that are followed by a LF. */
3941 crlf_to_lf (n, buf)
3942 register int n;
3943 register unsigned char *buf;
3945 unsigned char *np = buf, *startp = buf, *endp = buf + n;
3947 if (n == 0)
3948 return n;
3949 while (buf < endp - 1)
3951 if (*buf == 0x0d)
3953 if (*(++buf) != 0x0a)
3954 *np++ = 0x0d;
3956 else
3957 *np++ = *buf++;
3959 if (buf < endp)
3960 *np++ = *buf++;
3961 return np - startp;
3964 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3965 0, 0, 0,
3966 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
3969 return (_USE_LFN ? Qt : Qnil);
3972 /* Convert alphabetic characters in a filename to lower-case. */
3974 void
3975 msdos_downcase_filename (p)
3976 register unsigned char *p;
3978 /* Always lower-case drive letters a-z, even if the filesystem
3979 preserves case in filenames.
3980 This is so MSDOS filenames could be compared by string comparison
3981 functions that are case-sensitive. Even case-preserving filesystems
3982 do not distinguish case in drive letters. */
3983 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3985 *p += 'a' - 'A';
3986 p += 2;
3989 /* Under LFN we expect to get pathnames in their true case. */
3990 if (NILP (Fmsdos_long_file_names ()))
3991 for ( ; *p; p++)
3992 if (*p >= 'A' && *p <= 'Z')
3993 *p += 'a' - 'A';
3996 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3997 1, 1, 0,
3998 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
3999 When long filenames are supported, doesn't change FILENAME.
4000 If FILENAME is not a string, returns nil.
4001 The argument object is never altered--the value is a copy. */)
4002 (filename)
4003 Lisp_Object filename;
4005 Lisp_Object tem;
4007 if (! STRINGP (filename))
4008 return Qnil;
4010 tem = Fcopy_sequence (filename);
4011 msdos_downcase_filename (SDATA (tem));
4012 return tem;
4015 /* The Emacs root directory as determined by init_environment. */
4017 static char emacsroot[MAXPATHLEN];
4019 char *
4020 rootrelativepath (rel)
4021 char *rel;
4023 static char result[MAXPATHLEN + 10];
4025 strcpy (result, emacsroot);
4026 strcat (result, "/");
4027 strcat (result, rel);
4028 return result;
4031 /* Define a lot of environment variables if not already defined. Don't
4032 remove anything unless you know what you're doing -- lots of code will
4033 break if one or more of these are missing. */
4035 void
4036 init_environment (argc, argv, skip_args)
4037 int argc;
4038 char **argv;
4039 int skip_args;
4041 char *s, *t, *root;
4042 int len, i;
4043 static const char * const tempdirs[] = {
4044 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4046 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4048 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4049 temporary files and assume "/tmp" if $TMPDIR is unset, which
4050 will break on DOS/Windows. Refuse to work if we cannot find
4051 a directory, not even "c:/", usable for that purpose. */
4052 for (i = 0; i < imax ; i++)
4054 const char *tmp = tempdirs[i];
4055 char buf[FILENAME_MAX];
4057 if (*tmp == '$')
4059 int tmp_len;
4061 tmp = getenv (tmp + 1);
4062 if (!tmp)
4063 continue;
4065 /* Some lusers set TMPDIR=e:, probably because some losing
4066 programs cannot handle multiple slashes if they use e:/.
4067 e: fails in `access' below, so we interpret e: as e:/. */
4068 tmp_len = strlen(tmp);
4069 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4071 strcpy(buf, tmp);
4072 buf[tmp_len++] = '/', buf[tmp_len] = 0;
4073 tmp = buf;
4077 /* Note that `access' can lie to us if the directory resides on a
4078 read-only filesystem, like CD-ROM or a write-protected floppy.
4079 The only way to be really sure is to actually create a file and
4080 see if it succeeds. But I think that's too much to ask. */
4081 if (tmp && access (tmp, D_OK) == 0)
4083 setenv ("TMPDIR", tmp, 1);
4084 break;
4087 if (i >= imax)
4088 cmd_error_internal
4089 (Fcons (Qerror,
4090 Fcons (build_string ("no usable temporary directories found!!"),
4091 Qnil)),
4092 "While setting TMPDIR: ");
4094 /* Note the startup time, so we know not to clear the screen if we
4095 exit immediately; see IT_reset_terminal_modes.
4096 (Yes, I know `clock' returns zero the first time it's called, but
4097 I do this anyway, in case some wiseguy changes that at some point.) */
4098 startup_time = clock ();
4100 /* Find our root from argv[0]. Assuming argv[0] is, say,
4101 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4102 root = alloca (MAXPATHLEN + 20);
4103 _fixpath (argv[0], root);
4104 msdos_downcase_filename (root);
4105 len = strlen (root);
4106 while (len > 0 && root[len] != '/' && root[len] != ':')
4107 len--;
4108 root[len] = '\0';
4109 if (len > 4
4110 && (strcmp (root + len - 4, "/bin") == 0
4111 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4112 root[len - 4] = '\0';
4113 else
4114 strcpy (root, "c:/emacs"); /* let's be defensive */
4115 len = strlen (root);
4116 strcpy (emacsroot, root);
4118 /* We default HOME to our root. */
4119 setenv ("HOME", root, 0);
4121 /* We default EMACSPATH to root + "/bin". */
4122 strcpy (root + len, "/bin");
4123 setenv ("EMACSPATH", root, 0);
4125 /* I don't expect anybody to ever use other terminals so the internal
4126 terminal is the default. */
4127 setenv ("TERM", "internal", 0);
4129 #ifdef HAVE_X_WINDOWS
4130 /* Emacs expects DISPLAY to be set. */
4131 setenv ("DISPLAY", "unix:0.0", 0);
4132 #endif
4134 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4135 downcase it and mirror the backslashes. */
4136 s = getenv ("COMSPEC");
4137 if (!s) s = "c:/command.com";
4138 t = alloca (strlen (s) + 1);
4139 strcpy (t, s);
4140 dostounix_filename (t);
4141 setenv ("SHELL", t, 0);
4143 /* PATH is also downcased and backslashes mirrored. */
4144 s = getenv ("PATH");
4145 if (!s) s = "";
4146 t = alloca (strlen (s) + 3);
4147 /* Current directory is always considered part of MsDos's path but it is
4148 not normally mentioned. Now it is. */
4149 strcat (strcpy (t, ".;"), s);
4150 dostounix_filename (t); /* Not a single file name, but this should work. */
4151 setenv ("PATH", t, 1);
4153 /* In some sense all dos users have root privileges, so... */
4154 setenv ("USER", "root", 0);
4155 setenv ("NAME", getenv ("USER"), 0);
4157 /* Time zone determined from country code. To make this possible, the
4158 country code may not span more than one time zone. In other words,
4159 in the USA, you lose. */
4160 if (!getenv ("TZ"))
4161 switch (dos_country_code)
4163 case 31: /* Belgium */
4164 case 32: /* The Netherlands */
4165 case 33: /* France */
4166 case 34: /* Spain */
4167 case 36: /* Hungary */
4168 case 38: /* Yugoslavia (or what's left of it?) */
4169 case 39: /* Italy */
4170 case 41: /* Switzerland */
4171 case 42: /* Tjekia */
4172 case 45: /* Denmark */
4173 case 46: /* Sweden */
4174 case 47: /* Norway */
4175 case 48: /* Poland */
4176 case 49: /* Germany */
4177 /* Daylight saving from last Sunday in March to last Sunday in
4178 September, both at 2AM. */
4179 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4180 break;
4181 case 44: /* United Kingdom */
4182 case 351: /* Portugal */
4183 case 354: /* Iceland */
4184 setenv ("TZ", "GMT+00", 0);
4185 break;
4186 case 81: /* Japan */
4187 case 82: /* Korea */
4188 setenv ("TZ", "JST-09", 0);
4189 break;
4190 case 90: /* Turkey */
4191 case 358: /* Finland */
4192 setenv ("TZ", "EET-02", 0);
4193 break;
4194 case 972: /* Israel */
4195 /* This is an approximation. (For exact rules, use the
4196 `zoneinfo/israel' file which comes with DJGPP, but you need
4197 to install it in `/usr/share/zoneinfo/' directory first.) */
4198 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4199 break;
4201 tzset ();
4206 static int break_stat; /* BREAK check mode status. */
4207 static int stdin_stat; /* stdin IOCTL status. */
4209 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4210 control chars by DOS. Determine the keyboard type. */
4213 dos_ttraw (struct tty_display_info *tty)
4215 union REGS inregs, outregs;
4216 static int first_time = 1;
4218 /* If we are called for the initial terminal, it's too early to do
4219 anything, and termscript isn't set up. */
4220 if (tty->terminal->type == output_initial)
4221 return;
4223 break_stat = getcbrk ();
4224 setcbrk (0);
4226 if (first_time)
4228 inregs.h.ah = 0xc0;
4229 int86 (0x15, &inregs, &outregs);
4230 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4232 have_mouse = 0;
4234 if (1
4235 #ifdef HAVE_X_WINDOWS
4236 && inhibit_window_system
4237 #endif
4240 inregs.x.ax = 0x0021;
4241 int86 (0x33, &inregs, &outregs);
4242 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4243 if (!have_mouse)
4245 /* Reportedly, the above doesn't work for some mouse drivers. There
4246 is an additional detection method that should work, but might be
4247 a little slower. Use that as an alternative. */
4248 inregs.x.ax = 0x0000;
4249 int86 (0x33, &inregs, &outregs);
4250 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4252 if (have_mouse)
4253 mouse_button_count = outregs.x.bx;
4255 #ifndef HAVE_X_WINDOWS
4256 /* Save the cursor shape used outside Emacs. */
4257 outside_cursor = _farpeekw (_dos_ds, 0x460);
4258 #endif
4261 first_time = 0;
4263 stdin_stat = setmode (fileno (stdin), O_BINARY);
4264 return (stdin_stat != -1);
4266 else
4267 return (setmode (fileno (stdin), O_BINARY) != -1);
4270 /* Restore status of standard input and Ctrl-C checking. */
4273 dos_ttcooked ()
4275 union REGS inregs, outregs;
4277 setcbrk (break_stat);
4278 mouse_off ();
4280 #ifndef HAVE_X_WINDOWS
4281 /* Restore the cursor shape we found on startup. */
4282 if (outside_cursor)
4284 inregs.h.ah = 1;
4285 inregs.x.cx = outside_cursor;
4286 int86 (0x10, &inregs, &outregs);
4288 #endif
4290 return (setmode (fileno (stdin), stdin_stat) != -1);
4294 /* Run command as specified by ARGV in directory DIR.
4295 The command is run with input from TEMPIN, output to
4296 file TEMPOUT and stderr to TEMPERR. */
4299 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4300 unsigned char **argv;
4301 const char *working_dir;
4302 int tempin, tempout, temperr;
4303 char **envv;
4305 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4306 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4307 int msshell, result = -1, inbak, outbak, errbak, x, y;
4308 Lisp_Object cmd;
4310 /* Get current directory as MSDOS cwd is not per-process. */
4311 getwd (oldwd);
4313 /* If argv[0] is the shell, it might come in any lettercase.
4314 Since `Fmember' is case-sensitive, we need to downcase
4315 argv[0], even if we are on case-preserving filesystems. */
4316 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4317 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4319 *pl = *pa++;
4320 if (*pl >= 'A' && *pl <= 'Z')
4321 *pl += 'a' - 'A';
4323 *pl = '\0';
4325 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4326 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4327 && !strcmp ("-c", argv[1]);
4328 if (msshell)
4330 saveargv1 = argv[1];
4331 saveargv2 = argv[2];
4332 argv[1] = "/c";
4333 /* We only need to mirror slashes if a DOS shell will be invoked
4334 not via `system' (which does the mirroring itself). Yes, that
4335 means DJGPP v1.x will lose here. */
4336 if (argv[2] && argv[3])
4338 char *p = alloca (strlen (argv[2]) + 1);
4340 strcpy (argv[2] = p, saveargv2);
4341 while (*p && isspace (*p))
4342 p++;
4343 while (*p)
4345 if (*p == '/')
4346 *p++ = '\\';
4347 else
4348 p++;
4353 chdir (working_dir);
4354 inbak = dup (0);
4355 outbak = dup (1);
4356 errbak = dup (2);
4357 if (inbak < 0 || outbak < 0 || errbak < 0)
4358 goto done; /* Allocation might fail due to lack of descriptors. */
4360 if (have_mouse > 0)
4361 mouse_get_xy (&x, &y);
4363 if (!noninteractive)
4364 dos_ttcooked (); /* do it here while 0 = stdin */
4366 dup2 (tempin, 0);
4367 dup2 (tempout, 1);
4368 dup2 (temperr, 2);
4370 if (msshell && !argv[3])
4372 /* MS-DOS native shells are too restrictive. For starters, they
4373 cannot grok commands longer than 126 characters. In DJGPP v2
4374 and later, `system' is much smarter, so we'll call it instead. */
4376 const char *cmnd;
4378 /* A shell gets a single argument--its full command
4379 line--whose original was saved in `saveargv2'. */
4381 /* Don't let them pass empty command lines to `system', since
4382 with some shells it will try to invoke an interactive shell,
4383 which will hang Emacs. */
4384 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4386 if (*cmnd)
4388 extern char **environ;
4389 char **save_env = environ;
4390 int save_system_flags = __system_flags;
4392 /* Request the most powerful version of `system'. We need
4393 all the help we can get to avoid calling stock DOS shells. */
4394 __system_flags = (__system_redirect
4395 | __system_use_shell
4396 | __system_allow_multiple_cmds
4397 | __system_allow_long_cmds
4398 | __system_handle_null_commands
4399 | __system_emulate_chdir);
4401 environ = envv;
4402 result = system (cmnd);
4403 __system_flags = save_system_flags;
4404 environ = save_env;
4406 else
4407 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4409 else
4410 result = spawnve (P_WAIT, argv[0], argv, envv);
4412 dup2 (inbak, 0);
4413 dup2 (outbak, 1);
4414 dup2 (errbak, 2);
4415 emacs_close (inbak);
4416 emacs_close (outbak);
4417 emacs_close (errbak);
4419 if (!noninteractive)
4420 dos_ttraw (CURTTY ());
4421 if (have_mouse > 0)
4423 mouse_init ();
4424 mouse_moveto (x, y);
4427 /* Some programs might change the meaning of the highest bit of the
4428 text attribute byte, so we get blinking characters instead of the
4429 bright background colors. Restore that. */
4430 if (!noninteractive)
4431 bright_bg ();
4433 done:
4434 chdir (oldwd);
4435 if (msshell)
4437 argv[1] = saveargv1;
4438 argv[2] = saveargv2;
4440 return result;
4443 void
4444 croak (badfunc)
4445 char *badfunc;
4447 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4448 reset_all_sys_modes ();
4449 exit (1);
4453 * A few unimplemented functions that we silently ignore.
4455 setpgrp () {return 0; }
4456 setpriority (x,y,z) int x,y,z; { return 0; }
4458 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4460 /* Augment DJGPP library POSIX signal functions. This is needed
4461 as of DJGPP v2.01, but might be in the library in later releases. */
4463 #include <libc/bss.h>
4465 /* A counter to know when to re-initialize the static sets. */
4466 static int sigprocmask_count = -1;
4468 /* Which signals are currently blocked (initially none). */
4469 static sigset_t current_mask;
4471 /* Which signals are pending (initially none). */
4472 static sigset_t msdos_pending_signals;
4474 /* Previous handlers to restore when the blocked signals are unblocked. */
4475 typedef void (*sighandler_t)(int);
4476 static sighandler_t prev_handlers[320];
4478 /* A signal handler which just records that a signal occurred
4479 (it will be raised later, if and when the signal is unblocked). */
4480 static void
4481 sig_suspender (signo)
4482 int signo;
4484 sigaddset (&msdos_pending_signals, signo);
4488 sigprocmask (how, new_set, old_set)
4489 int how;
4490 const sigset_t *new_set;
4491 sigset_t *old_set;
4493 int signo;
4494 sigset_t new_mask;
4496 /* If called for the first time, initialize. */
4497 if (sigprocmask_count != __bss_count)
4499 sigprocmask_count = __bss_count;
4500 sigemptyset (&msdos_pending_signals);
4501 sigemptyset (&current_mask);
4502 for (signo = 0; signo < 320; signo++)
4503 prev_handlers[signo] = SIG_ERR;
4506 if (old_set)
4507 *old_set = current_mask;
4509 if (new_set == 0)
4510 return 0;
4512 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4514 errno = EINVAL;
4515 return -1;
4518 sigemptyset (&new_mask);
4520 /* DJGPP supports upto 320 signals. */
4521 for (signo = 0; signo < 320; signo++)
4523 if (sigismember (&current_mask, signo))
4524 sigaddset (&new_mask, signo);
4525 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4527 sigaddset (&new_mask, signo);
4529 /* SIGKILL is silently ignored, as on other platforms. */
4530 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4531 prev_handlers[signo] = signal (signo, sig_suspender);
4533 if (( how == SIG_UNBLOCK
4534 && sigismember (&new_mask, signo)
4535 && sigismember (new_set, signo))
4536 || (how == SIG_SETMASK
4537 && sigismember (&new_mask, signo)
4538 && !sigismember (new_set, signo)))
4540 sigdelset (&new_mask, signo);
4541 if (prev_handlers[signo] != SIG_ERR)
4543 signal (signo, prev_handlers[signo]);
4544 prev_handlers[signo] = SIG_ERR;
4546 if (sigismember (&msdos_pending_signals, signo))
4548 sigdelset (&msdos_pending_signals, signo);
4549 raise (signo);
4553 current_mask = new_mask;
4554 return 0;
4557 #endif /* not __DJGPP_MINOR__ < 2 */
4559 #ifndef HAVE_SELECT
4560 #include "sysselect.h"
4562 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4563 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4564 ((long)(time).tv_sec < 0 \
4565 || ((time).tv_sec == 0 \
4566 && (long)(time).tv_usec <= 0))
4567 #endif
4569 /* This yields the rest of the current time slice to the task manager.
4570 It should be called by any code which knows that it has nothing
4571 useful to do except idle.
4573 I don't use __dpmi_yield here, since versions of library before 2.02
4574 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4575 on some versions of Windows 9X. */
4577 void
4578 dos_yield_time_slice (void)
4580 _go32_dpmi_registers r;
4582 r.x.ax = 0x1680;
4583 r.x.ss = r.x.sp = r.x.flags = 0;
4584 _go32_dpmi_simulate_int (0x2f, &r);
4585 if (r.h.al == 0x80)
4586 errno = ENOSYS;
4589 /* Only event queue is checked. */
4590 /* We don't have to call timer_check here
4591 because wait_reading_process_output takes care of that. */
4593 sys_select (nfds, rfds, wfds, efds, timeout)
4594 int nfds;
4595 SELECT_TYPE *rfds, *wfds, *efds;
4596 EMACS_TIME *timeout;
4598 int check_input;
4599 struct time t;
4601 check_input = 0;
4602 if (rfds)
4604 check_input = FD_ISSET (0, rfds);
4605 FD_ZERO (rfds);
4607 if (wfds)
4608 FD_ZERO (wfds);
4609 if (efds)
4610 FD_ZERO (efds);
4612 if (nfds != 1)
4613 abort ();
4615 /* If we are looking only for the terminal, with no timeout,
4616 just read it and wait -- that's more efficient. */
4617 if (!timeout)
4619 while (!detect_input_pending ())
4621 dos_yield_time_slice ();
4624 else
4626 EMACS_TIME clnow, cllast, cldiff;
4628 gettime (&t);
4629 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4631 while (!check_input || !detect_input_pending ())
4633 gettime (&t);
4634 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4635 EMACS_SUB_TIME (cldiff, clnow, cllast);
4637 /* When seconds wrap around, we assume that no more than
4638 1 minute passed since last `gettime'. */
4639 if (EMACS_TIME_NEG_P (cldiff))
4640 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4641 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4643 /* Stop when timeout value crosses zero. */
4644 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4645 return 0;
4646 cllast = clnow;
4647 dos_yield_time_slice ();
4651 FD_SET (0, rfds);
4652 return 1;
4654 #endif
4657 * Define overlaid functions:
4659 * chdir -> sys_chdir
4660 * tzset -> init_gettimeofday
4661 * abort -> dos_abort
4664 #ifdef chdir
4665 #undef chdir
4666 extern int chdir ();
4669 sys_chdir (path)
4670 const char* path;
4672 int len = strlen (path);
4673 char *tmp = (char *)path;
4675 if (*tmp && tmp[1] == ':')
4677 if (getdisk () != tolower (tmp[0]) - 'a')
4678 setdisk (tolower (tmp[0]) - 'a');
4679 tmp += 2; /* strip drive: KFS 1995-07-06 */
4680 len -= 2;
4683 if (len > 1 && (tmp[len - 1] == '/'))
4685 char *tmp1 = (char *) alloca (len + 1);
4686 strcpy (tmp1, tmp);
4687 tmp1[len - 1] = 0;
4688 tmp = tmp1;
4690 return chdir (tmp);
4692 #endif
4694 #ifdef tzset
4695 #undef tzset
4696 extern void tzset (void);
4698 void
4699 init_gettimeofday ()
4701 time_t ltm, gtm;
4702 struct tm *lstm;
4704 tzset ();
4705 ltm = gtm = time (NULL);
4706 ltm = mktime (lstm = localtime (&ltm));
4707 gtm = mktime (gmtime (&gtm));
4708 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4709 time_rec.tm_isdst = lstm->tm_isdst;
4710 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4712 #endif
4714 #ifdef abort
4715 #undef abort
4716 void
4717 dos_abort (file, line)
4718 char *file;
4719 int line;
4721 char buffer1[200], buffer2[400];
4722 int i, j;
4724 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4725 for (i = j = 0; buffer1[i]; i++) {
4726 buffer2[j++] = buffer1[i];
4727 buffer2[j++] = 0x70;
4729 dosmemput (buffer2, j, (int)ScreenPrimary);
4730 ScreenSetCursor (2, 0);
4731 abort ();
4733 #else
4734 void
4735 abort ()
4737 dos_ttcooked ();
4738 ScreenSetCursor (10, 0);
4739 cputs ("\r\n\nEmacs aborted!\r\n");
4740 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4741 if (screen_virtual_segment)
4742 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4743 /* Generate traceback, so we could tell whodunit. */
4744 signal (SIGINT, SIG_DFL);
4745 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4746 #else /* __DJGPP_MINOR__ >= 2 */
4747 raise (SIGABRT);
4748 #endif /* __DJGPP_MINOR__ >= 2 */
4749 exit (2);
4751 #endif
4753 /* The following variables are required so that cus-start.el won't
4754 complain about unbound variables. */
4755 #ifndef subprocesses
4756 /* Nonzero means delete a process right away if it exits (process.c). */
4757 static int delete_exited_processes;
4758 #endif
4760 syms_of_msdos ()
4762 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4763 staticpro (&recent_doskeys);
4765 #ifndef HAVE_X_WINDOWS
4767 /* The following two are from xfns.c: */
4768 Qreverse = intern ("reverse");
4769 staticpro (&Qreverse);
4771 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4772 doc: /* *Glyph to display instead of chars not supported by current codepage.
4773 This variable is used only by MS-DOS terminals. */);
4774 Vdos_unsupported_char_glyph = make_number ('\177');
4776 #endif
4777 #ifndef subprocesses
4778 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
4779 doc: /* *Non-nil means delete processes immediately when they exit.
4780 A value of nil means don't delete them until `list-processes' is run. */);
4781 delete_exited_processes = 0;
4782 #endif
4784 defsubr (&Srecent_doskeys);
4785 defsubr (&Smsdos_long_file_names);
4786 defsubr (&Smsdos_downcase_filename);
4787 defsubr (&Smsdos_remember_default_colors);
4788 defsubr (&Smsdos_set_mouse_buttons);
4791 #endif /* MSDOS */
4793 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
4794 (do not change this comment) */