Fix showing the complete tip the first time, bug #2423.
[emacs.git] / src / msdos.c
blob6cde7cd6ebc301460d6f47eeba788aede0aee82d
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 = XSYMBOL (Fintern_soft (build_string (video_name),
532 Qnil))-> value;
534 if (INTEGERP (video_mode)
535 && (video_mode_value = XINT (video_mode)) > 0)
537 regs.x.ax = video_mode_value;
538 int86 (0x10, &regs, &regs);
540 if (have_mouse)
542 /* Must hardware-reset the mouse, or else it won't update
543 its notion of screen dimensions for some non-standard
544 video modes. This is *painfully* slow... */
545 regs.x.ax = 0;
546 int86 (0x33, &regs, &regs);
550 /* Find one of the dimensions supported by standard EGA/VGA
551 which gives us at least the required dimensions. */
552 else
554 static struct {
555 int rows, need_vga;
556 } std_dimension[] = {
557 {25, 0},
558 {28, 1},
559 {35, 0},
560 {40, 1},
561 {43, 0},
562 {50, 1}
564 int i = 0;
566 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
568 if (std_dimension[i].need_vga <= have_vga
569 && std_dimension[i].rows >= *rows)
571 if (std_dimension[i].rows != current_rows
572 || *cols != current_cols)
573 _set_screen_lines (std_dimension[i].rows);
574 break;
576 i++;
581 if (have_mouse)
583 mouse_init ();
584 mouse_on ();
587 /* Tell the caller what dimensions have been REALLY set. */
588 *rows = ScreenRows ();
589 *cols = ScreenCols ();
591 /* Update Emacs' notion of screen dimensions. */
592 screen_size_X = *cols;
593 screen_size_Y = *rows;
594 screen_size = *cols * *rows;
596 /* If the dimensions changed, the mouse highlight info is invalid. */
597 if (current_rows != *rows || current_cols != *cols)
599 struct frame *f = SELECTED_FRAME();
600 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
601 Lisp_Object window = dpyinfo->mouse_face_window;
603 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
605 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
606 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
607 dpyinfo->mouse_face_window = Qnil;
611 /* Enable bright background colors. */
612 bright_bg ();
614 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
615 be defensive anyway. */
616 if (screen_virtual_segment)
617 dosv_refresh_virtual_screen (0, *cols * *rows);
620 /* If we write a character in the position where the mouse is,
621 the mouse cursor may need to be refreshed. */
623 static void
624 mouse_off_maybe ()
626 int x, y;
628 if (!mouse_visible)
629 return;
631 mouse_get_xy (&x, &y);
632 if (y != new_pos_Y || x < new_pos_X)
633 return;
635 mouse_off ();
638 #define DEFAULT_CURSOR_START (-1)
639 #define DEFAULT_CURSOR_WIDTH (-1)
640 #define BOX_CURSOR_WIDTH (-32)
642 /* Set cursor to begin at scan line START_LINE in the character cell
643 and extend for WIDTH scan lines. Scan lines are counted from top
644 of the character cell, starting from zero. */
645 static void
646 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
648 unsigned desired_cursor;
649 __dpmi_regs regs;
650 int max_line, top_line, bot_line;
651 struct tty_display_info *tty = FRAME_TTY (f);
653 /* Avoid the costly BIOS call if F isn't the currently selected
654 frame. Allow for NULL as unconditionally meaning the selected
655 frame. */
656 if (f && f != SELECTED_FRAME())
657 return;
659 if (tty->termscript)
660 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
662 /* The character cell size in scan lines is stored at 40:85 in the
663 BIOS data area. */
664 max_line = _farpeekw (_dos_ds, 0x485) - 1;
665 switch (max_line)
667 default: /* this relies on CGA cursor emulation being ON! */
668 case 7:
669 bot_line = 7;
670 break;
671 case 9:
672 bot_line = 9;
673 break;
674 case 13:
675 bot_line = 12;
676 break;
677 case 15:
678 bot_line = 14;
679 break;
682 if (width < 0)
684 if (width == BOX_CURSOR_WIDTH)
686 top_line = 0;
687 bot_line = max_line;
689 else if (start_line != DEFAULT_CURSOR_START)
691 top_line = start_line;
692 bot_line = top_line - width - 1;
694 else if (width != DEFAULT_CURSOR_WIDTH)
696 top_line = 0;
697 bot_line = -1 - width;
699 else
700 top_line = bot_line + 1;
702 else if (width == 0)
704 /* [31, 0] seems to DTRT for all screen sizes. */
705 top_line = 31;
706 bot_line = 0;
708 else /* WIDTH is positive */
710 if (start_line != DEFAULT_CURSOR_START)
711 bot_line = start_line;
712 top_line = bot_line - (width - 1);
715 /* If the current cursor shape is already what they want, we are
716 history here. */
717 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
718 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
719 return;
721 regs.h.ah = 1;
722 regs.x.cx = desired_cursor;
723 __dpmi_int (0x10, &regs);
726 static void
727 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
729 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
731 /* Just BAR means the normal EGA/VGA cursor. */
732 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
734 else if (CONSP (cursor_type)
735 && (EQ (XCAR (cursor_type), Qbar)
736 || EQ (XCAR (cursor_type), Qhbar)))
738 Lisp_Object bar_parms = XCDR (cursor_type);
739 int width;
741 if (INTEGERP (bar_parms))
743 /* Feature: negative WIDTH means cursor at the top
744 of the character cell, zero means invisible cursor. */
745 width = XINT (bar_parms);
746 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
747 width);
749 else if (CONSP (bar_parms)
750 && INTEGERP (XCAR (bar_parms))
751 && INTEGERP (XCDR (bar_parms)))
753 int start_line = XINT (XCDR (bar_parms));
755 width = XINT (XCAR (bar_parms));
756 msdos_set_cursor_shape (f, start_line, width);
759 else
761 /* Treat anything unknown as "box cursor". This includes nil, so
762 that a frame which doesn't specify a cursor type gets a box,
763 which is the default in Emacs. */
764 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
768 static void
769 IT_ring_bell (struct frame *f)
771 if (visible_bell)
773 mouse_off ();
774 ScreenVisualBell ();
776 else
778 union REGS inregs, outregs;
779 inregs.h.ah = 2;
780 inregs.h.dl = 7;
781 intdos (&inregs, &outregs);
785 /* Given a face id FACE, extract the face parameters to be used for
786 display until the face changes. The face parameters (actually, its
787 color) are used to construct the video attribute byte for each
788 glyph during the construction of the buffer that is then blitted to
789 the video RAM. */
790 static void
791 IT_set_face (int face)
793 struct frame *sf = SELECTED_FRAME();
794 struct face *fp = FACE_FROM_ID (sf, face);
795 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
796 unsigned long fg, bg, dflt_fg, dflt_bg;
797 struct tty_display_info *tty = FRAME_TTY (sf);
799 if (!fp)
801 fp = dfp;
802 /* The default face for the frame should always be realized and
803 cached. */
804 if (!fp)
805 abort ();
807 screen_face = face;
808 fg = fp->foreground;
809 bg = fp->background;
810 dflt_fg = dfp->foreground;
811 dflt_bg = dfp->background;
813 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
814 mean use the colors of the default face. Note that we assume all
815 16 colors to be available for the background, since Emacs switches
816 on this mode (and loses the blinking attribute) at startup. */
817 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
818 fg = FRAME_FOREGROUND_PIXEL (sf);
819 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
820 fg = FRAME_BACKGROUND_PIXEL (sf);
821 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
822 bg = FRAME_BACKGROUND_PIXEL (sf);
823 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
824 bg = FRAME_FOREGROUND_PIXEL (sf);
826 /* Make sure highlighted lines really stand out, come what may. */
827 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
829 unsigned long tem = fg;
831 fg = bg;
832 bg = tem;
834 /* If the user requested inverse video, obey. */
835 if (inverse_video)
837 unsigned long tem2 = fg;
839 fg = bg;
840 bg = tem2;
842 if (tty->termscript)
843 fprintf (tty->termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
844 fp->foreground, fp->background, fg, bg);
845 if (fg >= 0 && fg < 16)
847 ScreenAttrib &= 0xf0;
848 ScreenAttrib |= fg;
850 if (bg >= 0 && bg < 16)
852 ScreenAttrib &= 0x0f;
853 ScreenAttrib |= ((bg & 0x0f) << 4);
857 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
858 width of a DOS display in any known text mode. We multiply by 2 to
859 accomodate the screen attribute byte. */
860 #define MAX_SCREEN_BUF 160*2
862 Lisp_Object Vdos_unsupported_char_glyph;
863 extern unsigned char *encode_terminal_code (struct glyph *, int,
864 struct coding_system *);
865 static void
866 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
868 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
869 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
870 register int sl = str_len;
871 struct tty_display_info *tty = FRAME_TTY (f);
872 struct frame *sf;
873 unsigned char *conversion_buffer;
875 /* Do we need to consider conversion of unibyte characters to
876 multibyte? */
877 int convert_unibyte_characters
878 = (NILP (current_buffer->enable_multibyte_characters)
879 && unibyte_display_via_language_environment);
881 /* If terminal_coding does any conversion, use it, otherwise use
882 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
883 because it always returns 1 if terminal_coding.src_multibyte is 1. */
884 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
886 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
887 coding = &safe_terminal_coding;
889 if (str_len <= 0) return;
891 sf = SELECTED_FRAME();
893 /* Since faces get cached and uncached behind our back, we can't
894 rely on their indices in the cache being consistent across
895 invocations. So always reset the screen face to the default
896 face of the frame, before writing glyphs, and let the glyphs
897 set the right face if it's different from the default. */
898 IT_set_face (DEFAULT_FACE_ID);
900 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
901 the tail. */
902 coding->mode &= ~CODING_MODE_LAST_BLOCK;
903 screen_bp = &screen_buf[0];
904 while (sl > 0)
906 int cf;
907 int n;
909 /* If the face of this glyph is different from the current
910 screen face, update the screen attribute byte. */
911 cf = str->face_id;
912 if (cf != screen_face)
913 IT_set_face (cf); /* handles invalid faces gracefully */
915 /* Identify a run of glyphs with the same face. */
916 for (n = 1; n < sl; ++n)
917 if (str[n].face_id != cf)
918 break;
920 if (n >= sl)
921 /* This is the last glyph. */
922 coding->mode |= CODING_MODE_LAST_BLOCK;
924 conversion_buffer = encode_terminal_code (str, n, coding);
925 if (coding->produced > 0)
927 /* Copy the encoded bytes to the screen buffer. */
928 for (bp = conversion_buffer; coding->produced--; bp++)
930 /* Paranoia: discard bytes that would overrun the end of
931 the screen buffer. */
932 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
934 *screen_bp++ = (unsigned char)*bp;
935 *screen_bp++ = ScreenAttrib;
937 if (tty->termscript)
938 fputc (*bp, tty->termscript);
941 /* Update STR and its remaining length. */
942 str += n;
943 sl -= n;
946 /* Dump whatever we have in the screen buffer. */
947 mouse_off_maybe ();
948 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
949 if (screen_virtual_segment)
950 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
951 new_pos_X += (screen_bp - screen_buf) / 2;
954 /************************************************************************
955 Mouse Highlight (and friends..)
956 ************************************************************************/
958 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
959 static Lisp_Object last_mouse_window;
961 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
963 /* Set the mouse pointer shape according to whether it is in the
964 area where the mouse highlight is in effect. */
965 static void
966 IT_set_mouse_pointer (int mode)
968 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
969 many possibilities to change its shape, and the available
970 functionality pretty much sucks (e.g., almost every reasonable
971 shape will conceal the character it is on). Since the color of
972 the pointer changes in the highlighted area, it is not clear to
973 me whether anything else is required, anyway. */
976 /* Display the active region described by mouse_face_*
977 in its mouse-face if HL > 0, in its normal face if HL = 0. */
978 static void
979 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
981 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
982 struct frame *f = XFRAME (WINDOW_FRAME (w));
983 int i;
984 struct face *fp;
985 struct tty_display_info *tty = FRAME_TTY (f);
988 /* If window is in the process of being destroyed, don't bother
989 doing anything. */
990 if (w->current_matrix == NULL)
991 goto set_cursor_shape;
993 /* Recognize when we are called to operate on rows that don't exist
994 anymore. This can happen when a window is split. */
995 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
996 goto set_cursor_shape;
998 /* There's no sense to do anything if the mouse face isn't realized. */
999 if (hl > 0)
1001 if (dpyinfo->mouse_face_hidden)
1002 goto set_cursor_shape;
1004 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1005 if (!fp)
1006 goto set_cursor_shape;
1009 /* Note that mouse_face_beg_row etc. are window relative. */
1010 for (i = dpyinfo->mouse_face_beg_row;
1011 i <= dpyinfo->mouse_face_end_row;
1012 i++)
1014 int start_hpos, end_hpos;
1015 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1017 /* Don't do anything if row doesn't have valid contents. */
1018 if (!row->enabled_p)
1019 continue;
1021 /* For all but the first row, the highlight starts at column 0. */
1022 if (i == dpyinfo->mouse_face_beg_row)
1023 start_hpos = dpyinfo->mouse_face_beg_col;
1024 else
1025 start_hpos = 0;
1027 if (i == dpyinfo->mouse_face_end_row)
1028 end_hpos = dpyinfo->mouse_face_end_col;
1029 else
1030 end_hpos = row->used[TEXT_AREA];
1032 if (end_hpos <= start_hpos)
1033 continue;
1034 /* Record that some glyphs of this row are displayed in
1035 mouse-face. */
1036 row->mouse_face_p = hl > 0;
1037 if (hl > 0)
1039 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1040 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1041 int nglyphs = end_hpos - start_hpos;
1042 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1043 int start_offset = offset;
1045 if (tty->termscript)
1046 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1047 kstart, kstart + nglyphs - 1, vpos);
1049 mouse_off ();
1050 IT_set_face (dpyinfo->mouse_face_face_id);
1051 /* Since we are going to change only the _colors_ of the
1052 displayed text, there's no need to go through all the
1053 pain of generating and encoding the text from the glyphs.
1054 Instead, we simply poke the attribute byte of each
1055 affected position in video memory with the colors
1056 computed by IT_set_face! */
1057 _farsetsel (_dos_ds);
1058 while (nglyphs--)
1060 _farnspokeb (offset, ScreenAttrib);
1061 offset += 2;
1063 if (screen_virtual_segment)
1064 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1065 mouse_on ();
1067 else
1069 /* We are removing a previously-drawn mouse highlight. The
1070 safest way to do so is to redraw the glyphs anew, since
1071 all kinds of faces and display tables could have changed
1072 behind our back. */
1073 int nglyphs = end_hpos - start_hpos;
1074 int save_x = new_pos_X, save_y = new_pos_Y;
1076 if (end_hpos >= row->used[TEXT_AREA])
1077 nglyphs = row->used[TEXT_AREA] - start_hpos;
1079 /* IT_write_glyphs writes at cursor position, so we need to
1080 temporarily move cursor coordinates to the beginning of
1081 the highlight region. */
1082 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1083 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1085 if (tty->termscript)
1086 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1087 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1088 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1089 if (tty->termscript)
1090 fputs ("\n", tty->termscript);
1091 new_pos_X = save_x;
1092 new_pos_Y = save_y;
1096 set_cursor_shape:
1097 /* Change the mouse pointer shape. */
1098 IT_set_mouse_pointer (hl);
1101 /* Clear out the mouse-highlighted active region.
1102 Redraw it un-highlighted first. */
1103 static void
1104 clear_mouse_face (struct tty_display_info *dpyinfo)
1106 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1107 show_mouse_face (dpyinfo, 0);
1109 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1110 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1111 dpyinfo->mouse_face_window = Qnil;
1114 /* Find the glyph matrix position of buffer position POS in window W.
1115 *HPOS and *VPOS are set to the positions found. W's current glyphs
1116 must be up to date. If POS is above window start return (0, 0).
1117 If POS is after end of W, return end of last line in W. */
1118 static int
1119 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1121 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1122 int yb = window_text_bottom_y (w);
1123 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1125 while (row->y < yb)
1127 if (row->used[TEXT_AREA])
1128 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1129 else
1130 line_start_position = 0;
1132 if (line_start_position > pos)
1133 break;
1134 /* If the position sought is the end of the buffer,
1135 don't include the blank lines at the bottom of the window. */
1136 else if (line_start_position == pos
1137 && pos == BUF_ZV (XBUFFER (w->buffer)))
1139 maybe_next_line_p = 1;
1140 break;
1142 else if (line_start_position > 0)
1143 best_row = row;
1145 /* Don't overstep the last matrix row, lest we get into the
1146 never-never land... */
1147 if (row->y + 1 >= yb)
1148 break;
1150 ++row;
1153 /* Find the right column within BEST_ROW. */
1154 lastcol = 0;
1155 row = best_row;
1156 for (i = 0; i < row->used[TEXT_AREA]; i++)
1158 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1159 int charpos;
1161 charpos = glyph->charpos;
1162 if (charpos == pos)
1164 *hpos = i;
1165 *vpos = row->y;
1166 return 1;
1168 else if (charpos > pos)
1169 break;
1170 else if (charpos > 0)
1171 lastcol = i;
1174 /* If we're looking for the end of the buffer,
1175 and we didn't find it in the line we scanned,
1176 use the start of the following line. */
1177 if (maybe_next_line_p)
1179 ++row;
1180 lastcol = 0;
1183 *vpos = row->y;
1184 *hpos = lastcol + 1;
1185 return 0;
1188 /* Take proper action when mouse has moved to the mode or top line of
1189 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1190 mode line. X is relative to the start of the text display area of
1191 W, so the width of fringes and scroll bars must be subtracted
1192 to get a position relative to the start of the mode line. */
1193 static void
1194 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1196 struct frame *f = XFRAME (w->frame);
1197 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1198 struct glyph_row *row;
1200 if (mode_line_p)
1201 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1202 else
1203 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1205 if (row->enabled_p)
1207 extern Lisp_Object Qhelp_echo;
1208 struct glyph *glyph, *end;
1209 Lisp_Object help, map;
1211 /* Find the glyph under X. */
1212 glyph = (row->glyphs[TEXT_AREA]
1214 /* in case someone implements scroll bars some day... */
1215 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1216 end = glyph + row->used[TEXT_AREA];
1217 if (glyph < end
1218 && STRINGP (glyph->object)
1219 && STRING_INTERVALS (glyph->object)
1220 && glyph->charpos >= 0
1221 && glyph->charpos < SCHARS (glyph->object))
1223 /* If we're on a string with `help-echo' text property,
1224 arrange for the help to be displayed. This is done by
1225 setting the global variable help_echo to the help string. */
1226 help = Fget_text_property (make_number (glyph->charpos),
1227 Qhelp_echo, glyph->object);
1228 if (!NILP (help))
1230 help_echo_string = help;
1231 XSETWINDOW (help_echo_window, w);
1232 help_echo_object = glyph->object;
1233 help_echo_pos = glyph->charpos;
1239 /* Take proper action when the mouse has moved to position X, Y on
1240 frame F as regards highlighting characters that have mouse-face
1241 properties. Also de-highlighting chars where the mouse was before.
1242 X and Y can be negative or out of range. */
1243 static void
1244 IT_note_mouse_highlight (struct frame *f, int x, int y)
1246 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1247 enum window_part part = ON_NOTHING;
1248 Lisp_Object window;
1249 struct window *w;
1251 /* When a menu is active, don't highlight because this looks odd. */
1252 if (mouse_preempted)
1253 return;
1255 if (NILP (Vmouse_highlight)
1256 || !f->glyphs_initialized_p)
1257 return;
1259 dpyinfo->mouse_face_mouse_x = x;
1260 dpyinfo->mouse_face_mouse_y = y;
1261 dpyinfo->mouse_face_mouse_frame = f;
1263 if (dpyinfo->mouse_face_defer)
1264 return;
1266 if (gc_in_progress)
1268 dpyinfo->mouse_face_deferred_gc = 1;
1269 return;
1272 /* Which window is that in? */
1273 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1275 /* If we were displaying active text in another window, clear that. */
1276 if (! EQ (window, dpyinfo->mouse_face_window))
1277 clear_mouse_face (dpyinfo);
1279 /* Not on a window -> return. */
1280 if (!WINDOWP (window))
1281 return;
1283 /* Convert to window-relative coordinates. */
1284 w = XWINDOW (window);
1286 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1288 /* Mouse is on the mode or top line. */
1289 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1290 return;
1293 IT_set_mouse_pointer (0);
1295 /* Are we in a window whose display is up to date?
1296 And verify the buffer's text has not changed. */
1297 if (part == ON_TEXT
1298 && EQ (w->window_end_valid, w->buffer)
1299 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1300 && (XFASTINT (w->last_overlay_modified)
1301 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1303 int pos, i, nrows = w->current_matrix->nrows;
1304 struct glyph_row *row;
1305 struct glyph *glyph;
1307 /* Find the glyph under X/Y. */
1308 glyph = NULL;
1309 if (y >= 0 && y < nrows)
1311 row = MATRIX_ROW (w->current_matrix, y);
1312 /* Give up if some row before the one we are looking for is
1313 not enabled. */
1314 for (i = 0; i <= y; i++)
1315 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1316 break;
1317 if (i > y /* all rows upto and including the one at Y are enabled */
1318 && row->displays_text_p
1319 && x < window_box_width (w, TEXT_AREA))
1321 glyph = row->glyphs[TEXT_AREA];
1322 if (x >= row->used[TEXT_AREA])
1323 glyph = NULL;
1324 else
1326 glyph += x;
1327 if (!BUFFERP (glyph->object))
1328 glyph = NULL;
1333 /* Clear mouse face if X/Y not over text. */
1334 if (glyph == NULL)
1336 clear_mouse_face (dpyinfo);
1337 return;
1340 if (!BUFFERP (glyph->object))
1341 abort ();
1342 pos = glyph->charpos;
1344 /* Check for mouse-face and help-echo. */
1346 extern Lisp_Object Qmouse_face;
1347 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1348 int noverlays, obegv, ozv;
1349 struct buffer *obuf;
1351 /* If we get an out-of-range value, return now; avoid an error. */
1352 if (pos > BUF_Z (XBUFFER (w->buffer)))
1353 return;
1355 /* Make the window's buffer temporarily current for
1356 overlays_at and compute_char_face. */
1357 obuf = current_buffer;
1358 current_buffer = XBUFFER (w->buffer);
1359 obegv = BEGV;
1360 ozv = ZV;
1361 BEGV = BEG;
1362 ZV = Z;
1364 /* Is this char mouse-active or does it have help-echo? */
1365 XSETINT (position, pos);
1367 /* Put all the overlays we want in a vector in overlay_vec. */
1368 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1369 /* Sort overlays into increasing priority order. */
1370 noverlays = sort_overlays (overlay_vec, noverlays, w);
1372 /* Check mouse-face highlighting. */
1373 if (! (EQ (window, dpyinfo->mouse_face_window)
1374 && y >= dpyinfo->mouse_face_beg_row
1375 && y <= dpyinfo->mouse_face_end_row
1376 && (y > dpyinfo->mouse_face_beg_row
1377 || x >= dpyinfo->mouse_face_beg_col)
1378 && (y < dpyinfo->mouse_face_end_row
1379 || x < dpyinfo->mouse_face_end_col
1380 || dpyinfo->mouse_face_past_end)))
1382 /* Clear the display of the old active region, if any. */
1383 clear_mouse_face (dpyinfo);
1385 /* Find highest priority overlay that has a mouse-face prop. */
1386 overlay = Qnil;
1387 for (i = noverlays - 1; i >= 0; --i)
1389 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1390 if (!NILP (mouse_face))
1392 overlay = overlay_vec[i];
1393 break;
1397 /* If no overlay applies, get a text property. */
1398 if (NILP (overlay))
1399 mouse_face = Fget_text_property (position, Qmouse_face,
1400 w->buffer);
1402 /* Handle the overlay case. */
1403 if (! NILP (overlay))
1405 /* Find the range of text around this char that
1406 should be active. */
1407 Lisp_Object before, after;
1408 EMACS_INT ignore;
1410 before = Foverlay_start (overlay);
1411 after = Foverlay_end (overlay);
1412 /* Record this as the current active region. */
1413 fast_find_position (w, XFASTINT (before),
1414 &dpyinfo->mouse_face_beg_col,
1415 &dpyinfo->mouse_face_beg_row);
1416 dpyinfo->mouse_face_past_end
1417 = !fast_find_position (w, XFASTINT (after),
1418 &dpyinfo->mouse_face_end_col,
1419 &dpyinfo->mouse_face_end_row);
1420 dpyinfo->mouse_face_window = window;
1421 dpyinfo->mouse_face_face_id
1422 = face_at_buffer_position (w, pos, 0, 0,
1423 &ignore, pos + 1,
1424 !dpyinfo->mouse_face_hidden,
1425 -1);
1427 /* Display it as active. */
1428 show_mouse_face (dpyinfo, 1);
1430 /* Handle the text property case. */
1431 else if (! NILP (mouse_face))
1433 /* Find the range of text around this char that
1434 should be active. */
1435 Lisp_Object before, after, beginning, end;
1436 EMACS_INT ignore;
1438 beginning = Fmarker_position (w->start);
1439 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1440 - XFASTINT (w->window_end_pos)));
1441 before
1442 = Fprevious_single_property_change (make_number (pos + 1),
1443 Qmouse_face,
1444 w->buffer, beginning);
1445 after
1446 = Fnext_single_property_change (position, Qmouse_face,
1447 w->buffer, end);
1448 /* Record this as the current active region. */
1449 fast_find_position (w, XFASTINT (before),
1450 &dpyinfo->mouse_face_beg_col,
1451 &dpyinfo->mouse_face_beg_row);
1452 dpyinfo->mouse_face_past_end
1453 = !fast_find_position (w, XFASTINT (after),
1454 &dpyinfo->mouse_face_end_col,
1455 &dpyinfo->mouse_face_end_row);
1456 dpyinfo->mouse_face_window = window;
1457 dpyinfo->mouse_face_face_id
1458 = face_at_buffer_position (w, pos, 0, 0,
1459 &ignore, pos + 1,
1460 !dpyinfo->mouse_face_hidden,
1461 -1);
1463 /* Display it as active. */
1464 show_mouse_face (dpyinfo, 1);
1468 /* Look for a `help-echo' property. */
1470 Lisp_Object help;
1471 extern Lisp_Object Qhelp_echo;
1473 /* Check overlays first. */
1474 help = Qnil;
1475 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1477 overlay = overlay_vec[i];
1478 help = Foverlay_get (overlay, Qhelp_echo);
1481 if (!NILP (help))
1483 help_echo_string = help;
1484 help_echo_window = window;
1485 help_echo_object = overlay;
1486 help_echo_pos = pos;
1488 /* Try text properties. */
1489 else if (NILP (help)
1490 && ((STRINGP (glyph->object)
1491 && glyph->charpos >= 0
1492 && glyph->charpos < SCHARS (glyph->object))
1493 || (BUFFERP (glyph->object)
1494 && glyph->charpos >= BEGV
1495 && glyph->charpos < ZV)))
1497 help = Fget_text_property (make_number (glyph->charpos),
1498 Qhelp_echo, glyph->object);
1499 if (!NILP (help))
1501 help_echo_string = help;
1502 help_echo_window = window;
1503 help_echo_object = glyph->object;
1504 help_echo_pos = glyph->charpos;
1509 BEGV = obegv;
1510 ZV = ozv;
1511 current_buffer = obuf;
1516 static void
1517 IT_clear_end_of_line (struct frame *f, int first_unused)
1519 char *spaces, *sp;
1520 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1521 extern int fatal_error_in_progress;
1522 struct tty_display_info *tty = FRAME_TTY (f);
1524 if (new_pos_X >= first_unused || fatal_error_in_progress)
1525 return;
1527 IT_set_face (0);
1528 i = (j = first_unused - new_pos_X) * 2;
1529 if (tty->termscript)
1530 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1531 spaces = sp = alloca (i);
1533 while (--j >= 0)
1535 *sp++ = ' ';
1536 *sp++ = ScreenAttrib;
1539 mouse_off_maybe ();
1540 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1541 if (screen_virtual_segment)
1542 dosv_refresh_virtual_screen (offset, i / 2);
1544 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1545 Let's follow their lead, in case someone relies on this. */
1546 new_pos_X = first_unused;
1549 static void
1550 IT_clear_screen (struct frame *f)
1552 struct tty_display_info *tty = FRAME_TTY (f);
1554 if (tty->termscript)
1555 fprintf (tty->termscript, "<CLR:SCR>");
1556 /* We are sometimes called (from clear_garbaged_frames) when a new
1557 frame is being created, but its faces are not yet realized. In
1558 such a case we cannot call IT_set_face, since it will fail to find
1559 any valid faces and will abort. Instead, use the initial screen
1560 colors; that should mimic what a Unix tty does, which simply clears
1561 the screen with whatever default colors are in use. */
1562 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1563 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1564 else
1565 IT_set_face (0);
1566 mouse_off ();
1567 ScreenClear ();
1568 if (screen_virtual_segment)
1569 dosv_refresh_virtual_screen (0, screen_size);
1570 new_pos_X = new_pos_Y = 0;
1573 static void
1574 IT_clear_to_end (struct frame *f)
1576 struct tty_display_info *tty = FRAME_TTY (f);
1578 if (tty->termscript)
1579 fprintf (tty->termscript, "<CLR:EOS>");
1581 while (new_pos_Y < screen_size_Y) {
1582 new_pos_X = 0;
1583 IT_clear_end_of_line (f, screen_size_X);
1584 new_pos_Y++;
1588 static void
1589 IT_cursor_to (struct frame *f, int y, int x)
1591 struct tty_display_info *tty = FRAME_TTY (f);
1593 if (tty->termscript)
1594 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1595 new_pos_X = x;
1596 new_pos_Y = y;
1599 static int cursor_cleared;
1601 static void
1602 IT_display_cursor (int on)
1604 struct tty_display_info *tty = CURTTY ();
1606 if (on && cursor_cleared)
1608 ScreenSetCursor (current_pos_Y, current_pos_X);
1609 cursor_cleared = 0;
1610 if (tty->termscript)
1611 fprintf (tty->termscript, "\nCURSOR ON");
1613 else if (!on && !cursor_cleared)
1615 ScreenSetCursor (-1, -1);
1616 cursor_cleared = 1;
1617 if (tty->termscript)
1618 fprintf (tty->termscript, "\nCURSOR OFF");
1622 /* Emacs calls cursor-movement functions a lot when it updates the
1623 display (probably a legacy of old terminals where you cannot
1624 update a screen line without first moving the cursor there).
1625 However, cursor movement is expensive on MSDOS (it calls a slow
1626 BIOS function and requires 2 mode switches), while actual screen
1627 updates access the video memory directly and don't depend on
1628 cursor position. To avoid slowing down the redisplay, we cheat:
1629 all functions that move the cursor only set internal variables
1630 which record the cursor position, whereas the cursor is only
1631 moved to its final position whenever screen update is complete.
1633 `IT_cmgoto' is called from the keyboard reading loop and when the
1634 frame update is complete. This means that we are ready for user
1635 input, so we update the cursor position to show where the point is,
1636 and also make the mouse pointer visible.
1638 Special treatment is required when the cursor is in the echo area,
1639 to put the cursor at the end of the text displayed there. */
1641 static void
1642 IT_cmgoto (FRAME_PTR f)
1644 /* Only set the cursor to where it should be if the display is
1645 already in sync with the window contents. */
1646 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1647 struct tty_display_info *tty = FRAME_TTY (f);
1649 /* FIXME: This needs to be rewritten for the new redisplay, or
1650 removed. */
1651 #if 0
1652 static int previous_pos_X = -1;
1654 update_cursor_pos = 1; /* temporary!!! */
1656 /* If the display is in sync, forget any previous knowledge about
1657 cursor position. This is primarily for unexpected events like
1658 C-g in the minibuffer. */
1659 if (update_cursor_pos && previous_pos_X >= 0)
1660 previous_pos_X = -1;
1661 /* If we are in the echo area, put the cursor at the
1662 end of the echo area message. */
1663 if (!update_cursor_pos
1664 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1666 int tem_X = current_pos_X, dummy;
1668 if (echo_area_glyphs)
1670 tem_X = echo_area_glyphs_length;
1671 /* Save current cursor position, to be restored after the
1672 echo area message is erased. Only remember one level
1673 of previous cursor position. */
1674 if (previous_pos_X == -1)
1675 ScreenGetCursor (&dummy, &previous_pos_X);
1677 else if (previous_pos_X >= 0)
1679 /* We wind up here after the echo area message is erased.
1680 Restore the cursor position we remembered above. */
1681 tem_X = previous_pos_X;
1682 previous_pos_X = -1;
1685 if (current_pos_X != tem_X)
1687 new_pos_X = tem_X;
1688 update_cursor_pos = 1;
1691 #endif
1693 if (update_cursor_pos
1694 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1696 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1697 if (tty->termscript)
1698 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1701 /* Maybe cursor is invisible, so make it visible. */
1702 IT_display_cursor (1);
1704 /* Mouse pointer should be always visible if we are waiting for
1705 keyboard input. */
1706 if (!mouse_visible)
1707 mouse_on ();
1710 static void
1711 IT_update_begin (struct frame *f)
1713 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1714 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1716 if (display_info->termscript)
1717 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1719 BLOCK_INPUT;
1721 if (f && f == mouse_face_frame)
1723 /* Don't do highlighting for mouse motion during the update. */
1724 display_info->mouse_face_defer = 1;
1726 /* If F needs to be redrawn, simply forget about any prior mouse
1727 highlighting. */
1728 if (FRAME_GARBAGED_P (f))
1729 display_info->mouse_face_window = Qnil;
1731 /* Can we tell that this update does not affect the window
1732 where the mouse highlight is? If so, no need to turn off.
1733 Likewise, don't do anything if none of the enabled rows
1734 contains glyphs highlighted in mouse face. */
1735 if (!NILP (display_info->mouse_face_window)
1736 && WINDOWP (display_info->mouse_face_window))
1738 struct window *w = XWINDOW (display_info->mouse_face_window);
1739 int i;
1741 /* If the mouse highlight is in the window that was deleted
1742 (e.g., if it was popped by completion), clear highlight
1743 unconditionally. */
1744 if (NILP (w->buffer))
1745 display_info->mouse_face_window = Qnil;
1746 else
1748 for (i = 0; i < w->desired_matrix->nrows; ++i)
1749 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1750 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1751 break;
1754 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1755 clear_mouse_face (display_info);
1758 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1760 /* If the frame with mouse highlight was deleted, invalidate the
1761 highlight info. */
1762 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1763 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1764 display_info->mouse_face_window = Qnil;
1765 display_info->mouse_face_deferred_gc = 0;
1766 display_info->mouse_face_mouse_frame = NULL;
1769 UNBLOCK_INPUT;
1772 static void
1773 IT_update_end (struct frame *f)
1775 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1777 if (dpyinfo->termscript)
1778 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1779 dpyinfo->mouse_face_defer = 0;
1782 static void
1783 IT_frame_up_to_date (struct frame *f)
1785 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1786 Lisp_Object new_cursor, frame_desired_cursor;
1787 struct window *sw;
1789 if (dpyinfo->mouse_face_deferred_gc
1790 || (f && f == dpyinfo->mouse_face_mouse_frame))
1792 BLOCK_INPUT;
1793 if (dpyinfo->mouse_face_mouse_frame)
1794 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1795 dpyinfo->mouse_face_mouse_x,
1796 dpyinfo->mouse_face_mouse_y);
1797 dpyinfo->mouse_face_deferred_gc = 0;
1798 UNBLOCK_INPUT;
1801 /* Set the cursor type to whatever they wanted. In a minibuffer
1802 window, we want the cursor to appear only if we are reading input
1803 from this window, and we want the cursor to be taken from the
1804 frame parameters. For the selected window, we use either its
1805 buffer-local value or the value from the frame parameters if the
1806 buffer doesn't define its local value for the cursor type. */
1807 sw = XWINDOW (f->selected_window);
1808 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1809 if (cursor_in_echo_area
1810 && FRAME_HAS_MINIBUF_P (f)
1811 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1812 && sw == XWINDOW (echo_area_window))
1813 new_cursor = frame_desired_cursor;
1814 else
1816 struct buffer *b = XBUFFER (sw->buffer);
1818 if (EQ (b->cursor_type, Qt))
1819 new_cursor = frame_desired_cursor;
1820 else if (NILP (b->cursor_type)) /* nil means no cursor */
1821 new_cursor = Fcons (Qbar, make_number (0));
1822 else
1823 new_cursor = b->cursor_type;
1826 IT_set_cursor_type (f, new_cursor);
1828 IT_cmgoto (f); /* position cursor when update is done */
1831 /* Copy LEN glyphs displayed on a single line whose vertical position
1832 is YPOS, beginning at horizontal position XFROM to horizontal
1833 position XTO, by moving blocks in the video memory. Used by
1834 functions that insert and delete glyphs. */
1835 static void
1836 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1838 /* The offsets of source and destination relative to the
1839 conventional memorty selector. */
1840 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1841 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1843 if (from == to || len <= 0)
1844 return;
1846 _farsetsel (_dos_ds);
1848 /* The source and destination might overlap, so we need to move
1849 glyphs non-destructively. */
1850 if (from > to)
1852 for ( ; len; from += 2, to += 2, len--)
1853 _farnspokew (to, _farnspeekw (from));
1855 else
1857 from += (len - 1) * 2;
1858 to += (len - 1) * 2;
1859 for ( ; len; from -= 2, to -= 2, len--)
1860 _farnspokew (to, _farnspeekw (from));
1862 if (screen_virtual_segment)
1863 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1866 /* Insert and delete glyphs. */
1867 static void
1868 IT_insert_glyphs (f, start, len)
1869 struct frame *f;
1870 register struct glyph *start;
1871 register int len;
1873 int shift_by_width = screen_size_X - (new_pos_X + len);
1875 /* Shift right the glyphs from the nominal cursor position to the
1876 end of this line. */
1877 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1879 /* Now write the glyphs to be inserted. */
1880 IT_write_glyphs (f, start, len);
1883 static void
1884 IT_delete_glyphs (f, n)
1885 struct frame *f;
1886 register int n;
1888 abort ();
1891 /* set-window-configuration on window.c needs this. */
1892 void
1893 x_set_menu_bar_lines (f, value, oldval)
1894 struct frame *f;
1895 Lisp_Object value, oldval;
1897 set_menu_bar_lines (f, value, oldval);
1900 /* This was copied from xfaces.c */
1902 extern Lisp_Object Qbackground_color;
1903 extern Lisp_Object Qforeground_color;
1904 Lisp_Object Qreverse;
1905 extern Lisp_Object Qtitle;
1907 /* IT_set_terminal_modes is called when emacs is started,
1908 resumed, and whenever the screen is redrawn! */
1910 static void
1911 IT_set_terminal_modes (struct terminal *term)
1913 struct tty_display_info *tty;
1915 /* If called with initial terminal, it's too early to do anything
1916 useful. */
1917 if (term->type == output_initial)
1918 return;
1920 tty = term->display_info.tty;
1922 if (tty->termscript)
1923 fprintf (tty->termscript, "\n<SET_TERM>");
1925 screen_size_X = ScreenCols ();
1926 screen_size_Y = ScreenRows ();
1927 screen_size = screen_size_X * screen_size_Y;
1929 new_pos_X = new_pos_Y = 0;
1930 current_pos_X = current_pos_Y = -1;
1932 if (term_setup_done)
1933 return;
1934 term_setup_done = 1;
1936 startup_screen_size_X = screen_size_X;
1937 startup_screen_size_Y = screen_size_Y;
1938 startup_screen_attrib = ScreenAttrib;
1940 /* Is DOS/V (or any other RSIS software which relocates
1941 the screen) installed? */
1943 unsigned short es_value;
1944 __dpmi_regs regs;
1946 regs.h.ah = 0xfe; /* get relocated screen address */
1947 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1948 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1949 else if (screen_old_address) /* already switched to Japanese mode once */
1950 regs.x.es = (screen_old_address >> 4) & 0xffff;
1951 else
1952 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1953 regs.x.di = 0;
1954 es_value = regs.x.es;
1955 __dpmi_int (0x10, &regs);
1957 if (regs.x.es != es_value)
1959 /* screen_old_address is only set if ScreenPrimary does NOT
1960 already point to the relocated buffer address returned by
1961 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1962 ScreenPrimary to that address at startup under DOS/V. */
1963 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1964 screen_old_address = ScreenPrimary;
1965 screen_virtual_segment = regs.x.es;
1966 screen_virtual_offset = regs.x.di;
1967 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1971 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1972 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1974 bright_bg ();
1977 /* IT_reset_terminal_modes is called when emacs is
1978 suspended or killed. */
1980 static void
1981 IT_reset_terminal_modes (struct terminal *term)
1983 int display_row_start = (int) ScreenPrimary;
1984 int saved_row_len = startup_screen_size_X * 2;
1985 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1986 int to_next_row = update_row_len;
1987 unsigned char *saved_row = startup_screen_buffer;
1988 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1989 struct tty_display_info *tty = term->display_info.tty;
1991 if (tty->termscript)
1992 fprintf (tty->termscript, "\n<RESET_TERM>");
1994 if (!term_setup_done)
1995 return;
1997 mouse_off ();
1999 /* Leave the video system in the same state as we found it,
2000 as far as the blink/bright-background bit is concerned. */
2001 maybe_enable_blinking ();
2003 /* We have a situation here.
2004 We cannot just do ScreenUpdate(startup_screen_buffer) because
2005 the luser could have changed screen dimensions inside Emacs
2006 and failed (or didn't want) to restore them before killing
2007 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2008 thus will happily use memory outside what was allocated for
2009 `startup_screen_buffer'.
2010 Thus we only restore as much as the current screen dimensions
2011 can hold, and clear the rest (if the saved screen is smaller than
2012 the current) with the color attribute saved at startup. The cursor
2013 is also restored within the visible dimensions. */
2015 ScreenAttrib = startup_screen_attrib;
2017 /* Don't restore the screen if we are exiting less than 2 seconds
2018 after startup: we might be crashing, and the screen might show
2019 some vital clues to what's wrong. */
2020 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2022 ScreenClear ();
2023 if (screen_virtual_segment)
2024 dosv_refresh_virtual_screen (0, screen_size);
2026 if (update_row_len > saved_row_len)
2027 update_row_len = saved_row_len;
2028 if (current_rows > startup_screen_size_Y)
2029 current_rows = startup_screen_size_Y;
2031 if (tty->termscript)
2032 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2033 update_row_len / 2, current_rows);
2035 while (current_rows--)
2037 dosmemput (saved_row, update_row_len, display_row_start);
2038 if (screen_virtual_segment)
2039 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2040 update_row_len / 2);
2041 saved_row += saved_row_len;
2042 display_row_start += to_next_row;
2045 if (startup_pos_X < cursor_pos_X)
2046 cursor_pos_X = startup_pos_X;
2047 if (startup_pos_Y < cursor_pos_Y)
2048 cursor_pos_Y = startup_pos_Y;
2050 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2051 xfree (startup_screen_buffer);
2052 startup_screen_buffer = NULL;
2054 term_setup_done = 0;
2057 static void
2058 IT_set_terminal_window (struct frame *f, int foo)
2062 /* Remember the screen colors of the curent frame, to serve as the
2063 default colors for newly-created frames. */
2064 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2065 Smsdos_remember_default_colors, 1, 1, 0,
2066 doc: /* Remember the screen colors of the current frame. */)
2067 (frame)
2068 Lisp_Object frame;
2070 struct frame *f;
2072 CHECK_FRAME (frame);
2073 f = XFRAME (frame);
2075 /* This function is called after applying default-frame-alist to the
2076 initial frame. At that time, if reverse-colors option was
2077 specified in default-frame-alist, it was already applied, and
2078 frame colors are reversed. */
2079 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2080 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2083 void
2084 IT_set_frame_parameters (f, alist)
2085 struct frame *f;
2086 Lisp_Object alist;
2088 Lisp_Object tail;
2089 int i, j, length = XINT (Flength (alist));
2090 Lisp_Object *parms
2091 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2092 Lisp_Object *values
2093 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2094 /* Do we have to reverse the foreground and background colors? */
2095 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2096 int need_to_reverse, was_reverse = reverse;
2097 int redraw = 0, fg_set = 0, bg_set = 0;
2098 unsigned long orig_fg, orig_bg;
2099 Lisp_Object frame_bg, frame_fg;
2100 extern Lisp_Object Qdefault, QCforeground, QCbackground;
2101 struct tty_display_info *tty = FRAME_TTY (f);
2103 /* If we are creating a new frame, begin with the original screen colors
2104 used for the initial frame. */
2105 if (EQ (alist, Vdefault_frame_alist)
2106 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2108 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2109 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2110 init_frame_faces (f);
2112 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2113 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2114 frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2115 frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2116 /* frame_fg and frame_bg could be nil if, for example,
2117 f->param_alist is nil, e.g. if we are called from
2118 Fmake_terminal_frame. */
2119 if (NILP (frame_fg))
2120 frame_fg = build_string (unspecified_fg);
2121 if (NILP (frame_bg))
2122 frame_bg = build_string (unspecified_bg);
2124 /* Extract parm names and values into those vectors. */
2125 i = 0;
2126 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2128 Lisp_Object elt;
2130 elt = Fcar (tail);
2131 parms[i] = Fcar (elt);
2132 CHECK_SYMBOL (parms[i]);
2133 values[i] = Fcdr (elt);
2134 i++;
2137 j = i;
2139 for (i = 0; i < j; i++)
2141 Lisp_Object prop, val;
2143 prop = parms[i];
2144 val = values[i];
2146 if (EQ (prop, Qreverse))
2147 reverse = EQ (val, Qt);
2150 need_to_reverse = reverse && !was_reverse;
2151 if (tty->termscript && need_to_reverse)
2152 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2154 /* Now process the alist elements in reverse of specified order. */
2155 for (i--; i >= 0; i--)
2157 Lisp_Object prop, val, frame;
2159 prop = parms[i];
2160 val = values[i];
2162 if (EQ (prop, Qforeground_color))
2164 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2165 ? LFACE_BACKGROUND_INDEX
2166 : LFACE_FOREGROUND_INDEX);
2167 if (new_color != FACE_TTY_DEFAULT_COLOR
2168 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2169 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2171 FRAME_FOREGROUND_PIXEL (f) = new_color;
2172 /* Make sure the foreground of the default face for this
2173 frame is changed as well. */
2174 XSETFRAME (frame, f);
2175 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2176 val, frame);
2177 fg_set = 1;
2178 redraw = 1;
2179 if (tty->termscript)
2180 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2183 else if (EQ (prop, Qbackground_color))
2185 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2186 ? LFACE_FOREGROUND_INDEX
2187 : LFACE_BACKGROUND_INDEX);
2188 if (new_color != FACE_TTY_DEFAULT_COLOR
2189 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2190 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2192 FRAME_BACKGROUND_PIXEL (f) = new_color;
2193 /* Make sure the background of the default face for this
2194 frame is changed as well. */
2195 XSETFRAME (frame, f);
2196 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2197 val, frame);
2198 bg_set = 1;
2199 redraw = 1;
2200 if (tty->termscript)
2201 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2204 else if (EQ (prop, Qtitle))
2206 x_set_title (f, val);
2207 if (tty->termscript)
2208 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2210 else if (EQ (prop, Qcursor_type))
2212 IT_set_cursor_type (f, val);
2213 if (tty->termscript)
2214 fprintf (tty->termscript, "<CTYPE: %s>\n",
2215 EQ (val, Qbar) || EQ (val, Qhbar)
2216 || CONSP (val) && (EQ (XCAR (val), Qbar)
2217 || EQ (XCAR (val), Qhbar))
2218 ? "bar" : "box");
2220 else if (EQ (prop, Qtty_type))
2222 internal_terminal_init ();
2223 if (tty->termscript)
2224 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2225 SBYTES (val), SDATA (val));
2227 store_frame_param (f, prop, val);
2230 /* If they specified "reverse", but not the colors, we need to swap
2231 the current frame colors. */
2232 if (need_to_reverse)
2234 Lisp_Object frame;
2236 if (!fg_set)
2238 XSETFRAME (frame, f);
2239 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2240 tty_color_name (f, orig_bg),
2241 frame);
2242 redraw = 1;
2244 if (!bg_set)
2246 XSETFRAME (frame, f);
2247 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2248 tty_color_name (f, orig_fg),
2249 frame);
2250 redraw = 1;
2254 if (redraw)
2256 face_change_count++; /* forces xdisp.c to recompute basic faces */
2257 if (f == SELECTED_FRAME())
2258 redraw_frame (f);
2262 extern void init_frame_faces (FRAME_PTR);
2264 #endif /* !HAVE_X_WINDOWS */
2267 /* Do we need the internal terminal? */
2269 void
2270 internal_terminal_init ()
2272 static int init_needed = 1;
2273 char *term = getenv ("TERM"), *colors;
2274 struct frame *sf = SELECTED_FRAME();
2275 struct tty_display_info *tty;
2277 #ifdef HAVE_X_WINDOWS
2278 if (!inhibit_window_system)
2279 return;
2280 #endif
2282 /* If this is the initial terminal, we are done here. */
2283 if (sf->output_method == output_initial)
2284 return;
2286 internal_terminal
2287 = (!noninteractive) && term && !strcmp (term, "internal");
2289 #ifndef HAVE_X_WINDOWS
2290 if (!internal_terminal || inhibit_window_system)
2292 sf->output_method = output_termcap;
2293 return;
2296 tty = FRAME_TTY (sf);
2297 current_kboard->Vwindow_system = Qpc;
2298 sf->output_method = output_msdos_raw;
2299 if (init_needed)
2301 if (!tty->termscript && getenv ("EMACSTEST"))
2302 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2303 if (tty->termscript)
2305 time_t now = time (NULL);
2306 struct tm *tnow = localtime (&now);
2307 char tbuf[100];
2309 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2310 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2311 fprintf (tty->termscript, "=====================\n\n");
2314 Vinitial_window_system = Qpc;
2315 Vwindow_system_version = make_number (23); /* RE Emacs version */
2316 tty->terminal->type = output_msdos_raw;
2318 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2319 address. */
2320 screen_old_address = 0;
2322 /* Forget the stale screen colors as well. */
2323 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2325 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2326 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2327 bright_bg ();
2328 colors = getenv ("EMACSCOLORS");
2329 if (colors && strlen (colors) >= 2)
2331 /* The colors use 4 bits each (we enable bright background). */
2332 if (isdigit (colors[0]))
2333 colors[0] -= '0';
2334 else if (isxdigit (colors[0]))
2335 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2336 if (colors[0] >= 0 && colors[0] < 16)
2337 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2338 if (isdigit (colors[1]))
2339 colors[1] -= '0';
2340 else if (isxdigit (colors[1]))
2341 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2342 if (colors[1] >= 0 && colors[1] < 16)
2343 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2345 the_only_display_info.mouse_face_mouse_frame = NULL;
2346 the_only_display_info.mouse_face_deferred_gc = 0;
2347 the_only_display_info.mouse_face_beg_row =
2348 the_only_display_info.mouse_face_beg_col = -1;
2349 the_only_display_info.mouse_face_end_row =
2350 the_only_display_info.mouse_face_end_col = -1;
2351 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2352 the_only_display_info.mouse_face_window = Qnil;
2353 the_only_display_info.mouse_face_mouse_x =
2354 the_only_display_info.mouse_face_mouse_y = 0;
2355 the_only_display_info.mouse_face_defer = 0;
2356 the_only_display_info.mouse_face_hidden = 0;
2358 if (have_mouse) /* detected in dos_ttraw, which see */
2360 have_mouse = 1; /* enable mouse */
2361 mouse_visible = 0;
2362 mouse_setup_buttons (mouse_button_count);
2363 tty->terminal->mouse_position_hook = &mouse_get_pos;
2364 mouse_init ();
2367 if (tty->termscript && screen_size)
2368 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2369 screen_size_X, screen_size_Y);
2371 init_frame_faces (sf);
2372 init_needed = 0;
2374 #endif
2377 void
2378 initialize_msdos_display (struct terminal *term)
2380 term->rif = 0; /* we don't support window-based display */
2381 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2382 term->clear_to_end_hook = IT_clear_to_end;
2383 term->clear_frame_hook = IT_clear_screen;
2384 term->clear_end_of_line_hook = IT_clear_end_of_line;
2385 term->ins_del_lines_hook = 0;
2386 term->insert_glyphs_hook = IT_insert_glyphs;
2387 term->write_glyphs_hook = IT_write_glyphs;
2388 term->delete_glyphs_hook = IT_delete_glyphs;
2389 term->ring_bell_hook = IT_ring_bell;
2390 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2391 term->set_terminal_modes_hook = IT_set_terminal_modes;
2392 term->set_terminal_window_hook = IT_set_terminal_window;
2393 term->update_begin_hook = IT_update_begin;
2394 term->update_end_hook = IT_update_end;
2395 term->frame_up_to_date_hook = IT_frame_up_to_date;
2396 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2397 term->frame_rehighlight_hook = 0;
2398 term->frame_raise_lower_hook = 0;
2399 term->set_vertical_scroll_bar_hook = 0;
2400 term->condemn_scroll_bars_hook = 0;
2401 term->redeem_scroll_bar_hook = 0;
2402 term->judge_scroll_bars_hook = 0;
2403 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2406 dos_get_saved_screen (screen, rows, cols)
2407 char **screen;
2408 int *rows;
2409 int *cols;
2411 #ifndef HAVE_X_WINDOWS
2412 *screen = startup_screen_buffer;
2413 *cols = startup_screen_size_X;
2414 *rows = startup_screen_size_Y;
2415 return *screen != (char *)0;
2416 #else
2417 return 0;
2418 #endif
2421 #ifndef HAVE_X_WINDOWS
2423 /* We are not X, but we can emulate it well enough for our needs... */
2424 void
2425 check_x (void)
2427 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2428 error ("Not running under a window system");
2431 #endif
2434 /* ----------------------- Keyboard control ----------------------
2436 * Keymaps reflect the following keyboard layout:
2438 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2439 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2440 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2441 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2442 * SPACE
2445 #define Ignore 0x0000
2446 #define Normal 0x0000 /* normal key - alt changes scan-code */
2447 #define FctKey 0x1000 /* func key if c == 0, else c */
2448 #define Special 0x2000 /* func key even if c != 0 */
2449 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2450 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2451 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2452 #define Grey 0x6000 /* Grey keypad key */
2454 #define Alt 0x0100 /* alt scan-code */
2455 #define Ctrl 0x0200 /* ctrl scan-code */
2456 #define Shift 0x0400 /* shift scan-code */
2458 static int extended_kbd; /* 101 (102) keyboard present. */
2460 struct kbd_translate {
2461 unsigned char sc;
2462 unsigned char ch;
2463 unsigned short code;
2466 struct dos_keyboard_map
2468 char *unshifted;
2469 char *shifted;
2470 char *alt_gr;
2471 struct kbd_translate *translate_table;
2475 static struct dos_keyboard_map us_keyboard = {
2476 /* 0 1 2 3 4 5 */
2477 /* 01234567890123456789012345678901234567890 12345678901234 */
2478 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2479 /* 0123456789012345678901234567890123456789 012345678901234 */
2480 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2481 0, /* no Alt-Gr key */
2482 0 /* no translate table */
2485 static struct dos_keyboard_map fr_keyboard = {
2486 /* 0 1 2 3 4 5 */
2487 /* 012 3456789012345678901234567890123456789012345678901234 */
2488 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2489 /* 0123456789012345678901234567890123456789012345678901234 */
2490 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2491 /* 01234567 89012345678901234567890123456789012345678901234 */
2492 " ~#{[|`\\^@]} Ï ",
2493 0 /* no translate table */
2497 * Italian keyboard support, country code 39.
2498 * '<' 56:3c*0000
2499 * '>' 56:3e*0000
2500 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2501 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2504 static struct kbd_translate it_kbd_translate_table[] = {
2505 { 0x56, 0x3c, Normal | 13 },
2506 { 0x56, 0x3e, Normal | 27 },
2507 { 0, 0, 0 }
2509 static struct dos_keyboard_map it_keyboard = {
2510 /* 0 1 2 3 4 5 */
2511 /* 0 123456789012345678901234567890123456789012345678901234 */
2512 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2513 /* 01 23456789012345678901234567890123456789012345678901234 */
2514 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2515 /* 0123456789012345678901234567890123456789012345678901234 */
2516 " {}~` [] @# ",
2517 it_kbd_translate_table
2520 static struct dos_keyboard_map dk_keyboard = {
2521 /* 0 1 2 3 4 5 */
2522 /* 0123456789012345678901234567890123456789012345678901234 */
2523 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2524 /* 01 23456789012345678901234567890123456789012345678901234 */
2525 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2526 /* 0123456789012345678901234567890123456789012345678901234 */
2527 " @œ$ {[]} | ",
2528 0 /* no translate table */
2531 static struct kbd_translate jp_kbd_translate_table[] = {
2532 { 0x73, 0x5c, Normal | 0 },
2533 { 0x73, 0x5f, Normal | 0 },
2534 { 0x73, 0x1c, Map | 0 },
2535 { 0x7d, 0x5c, Normal | 13 },
2536 { 0x7d, 0x7c, Normal | 13 },
2537 { 0x7d, 0x1c, Map | 13 },
2538 { 0, 0, 0 }
2540 static struct dos_keyboard_map jp_keyboard = {
2541 /* 0 1 2 3 4 5 */
2542 /* 0123456789012 345678901234567890123456789012345678901234 */
2543 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2544 /* 01 23456789012345678901234567890123456789012345678901234 */
2545 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2546 0, /* no Alt-Gr key */
2547 jp_kbd_translate_table
2550 static struct keyboard_layout_list
2552 int country_code;
2553 struct dos_keyboard_map *keyboard_map;
2554 } keyboard_layout_list[] =
2556 1, &us_keyboard,
2557 33, &fr_keyboard,
2558 39, &it_keyboard,
2559 45, &dk_keyboard,
2560 81, &jp_keyboard
2563 static struct dos_keyboard_map *keyboard;
2564 static int keyboard_map_all;
2565 static int international_keyboard;
2568 dos_set_keyboard (code, always)
2569 int code;
2570 int always;
2572 int i;
2573 _go32_dpmi_registers regs;
2575 /* See if Keyb.Com is installed (for international keyboard support).
2576 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2577 of Windows 9X! So don't do that! */
2578 regs.x.ax = 0xad80;
2579 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2580 _go32_dpmi_simulate_int (0x2f, &regs);
2581 if (regs.h.al == 0xff)
2582 international_keyboard = 1;
2584 /* Initialize to US settings, for countries that don't have their own. */
2585 keyboard = keyboard_layout_list[0].keyboard_map;
2586 keyboard_map_all = always;
2587 dos_keyboard_layout = 1;
2589 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2590 if (code == keyboard_layout_list[i].country_code)
2592 keyboard = keyboard_layout_list[i].keyboard_map;
2593 keyboard_map_all = always;
2594 dos_keyboard_layout = code;
2595 return 1;
2597 return 0;
2600 static struct
2602 unsigned char char_code; /* normal code */
2603 unsigned char meta_code; /* M- code */
2604 unsigned char keypad_code; /* keypad code */
2605 unsigned char editkey_code; /* edit key */
2606 } keypad_translate_map[] = {
2607 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2608 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2609 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2610 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2611 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2612 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2613 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2614 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2615 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2616 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2617 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2620 static struct
2622 unsigned char char_code; /* normal code */
2623 unsigned char keypad_code; /* keypad code */
2624 } grey_key_translate_map[] = {
2625 '/', 0xaf, /* kp-decimal */
2626 '*', 0xaa, /* kp-multiply */
2627 '-', 0xad, /* kp-subtract */
2628 '+', 0xab, /* kp-add */
2629 '\r', 0x8d /* kp-enter */
2632 static unsigned short
2633 ibmpc_translate_map[] =
2635 /* --------------- 00 to 0f --------------- */
2636 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2637 Alt | ModFct | 0x1b, /* Escape */
2638 Normal | 1, /* '1' */
2639 Normal | 2, /* '2' */
2640 Normal | 3, /* '3' */
2641 Normal | 4, /* '4' */
2642 Normal | 5, /* '5' */
2643 Normal | 6, /* '6' */
2644 Normal | 7, /* '7' */
2645 Normal | 8, /* '8' */
2646 Normal | 9, /* '9' */
2647 Normal | 10, /* '0' */
2648 Normal | 11, /* '-' */
2649 Normal | 12, /* '=' */
2650 Special | 0x08, /* Backspace */
2651 ModFct | 0x74, /* Tab/Backtab */
2653 /* --------------- 10 to 1f --------------- */
2654 Map | 15, /* 'q' */
2655 Map | 16, /* 'w' */
2656 Map | 17, /* 'e' */
2657 Map | 18, /* 'r' */
2658 Map | 19, /* 't' */
2659 Map | 20, /* 'y' */
2660 Map | 21, /* 'u' */
2661 Map | 22, /* 'i' */
2662 Map | 23, /* 'o' */
2663 Map | 24, /* 'p' */
2664 Map | 25, /* '[' */
2665 Map | 26, /* ']' */
2666 ModFct | 0x0d, /* Return */
2667 Ignore, /* Ctrl */
2668 Map | 30, /* 'a' */
2669 Map | 31, /* 's' */
2671 /* --------------- 20 to 2f --------------- */
2672 Map | 32, /* 'd' */
2673 Map | 33, /* 'f' */
2674 Map | 34, /* 'g' */
2675 Map | 35, /* 'h' */
2676 Map | 36, /* 'j' */
2677 Map | 37, /* 'k' */
2678 Map | 38, /* 'l' */
2679 Map | 39, /* ';' */
2680 Map | 40, /* '\'' */
2681 Map | 0, /* '`' */
2682 Ignore, /* Left shift */
2683 Map | 41, /* '\\' */
2684 Map | 45, /* 'z' */
2685 Map | 46, /* 'x' */
2686 Map | 47, /* 'c' */
2687 Map | 48, /* 'v' */
2689 /* --------------- 30 to 3f --------------- */
2690 Map | 49, /* 'b' */
2691 Map | 50, /* 'n' */
2692 Map | 51, /* 'm' */
2693 Map | 52, /* ',' */
2694 Map | 53, /* '.' */
2695 Map | 54, /* '/' */
2696 Ignore, /* Right shift */
2697 Grey | 1, /* Grey * */
2698 Ignore, /* Alt */
2699 Normal | 55, /* ' ' */
2700 Ignore, /* Caps Lock */
2701 FctKey | 0xbe, /* F1 */
2702 FctKey | 0xbf, /* F2 */
2703 FctKey | 0xc0, /* F3 */
2704 FctKey | 0xc1, /* F4 */
2705 FctKey | 0xc2, /* F5 */
2707 /* --------------- 40 to 4f --------------- */
2708 FctKey | 0xc3, /* F6 */
2709 FctKey | 0xc4, /* F7 */
2710 FctKey | 0xc5, /* F8 */
2711 FctKey | 0xc6, /* F9 */
2712 FctKey | 0xc7, /* F10 */
2713 Ignore, /* Num Lock */
2714 Ignore, /* Scroll Lock */
2715 KeyPad | 7, /* Home */
2716 KeyPad | 8, /* Up */
2717 KeyPad | 9, /* Page Up */
2718 Grey | 2, /* Grey - */
2719 KeyPad | 4, /* Left */
2720 KeyPad | 5, /* Keypad 5 */
2721 KeyPad | 6, /* Right */
2722 Grey | 3, /* Grey + */
2723 KeyPad | 1, /* End */
2725 /* --------------- 50 to 5f --------------- */
2726 KeyPad | 2, /* Down */
2727 KeyPad | 3, /* Page Down */
2728 KeyPad | 0, /* Insert */
2729 KeyPad | 10, /* Delete */
2730 Shift | FctKey | 0xbe, /* (Shift) F1 */
2731 Shift | FctKey | 0xbf, /* (Shift) F2 */
2732 Shift | FctKey | 0xc0, /* (Shift) F3 */
2733 Shift | FctKey | 0xc1, /* (Shift) F4 */
2734 Shift | FctKey | 0xc2, /* (Shift) F5 */
2735 Shift | FctKey | 0xc3, /* (Shift) F6 */
2736 Shift | FctKey | 0xc4, /* (Shift) F7 */
2737 Shift | FctKey | 0xc5, /* (Shift) F8 */
2738 Shift | FctKey | 0xc6, /* (Shift) F9 */
2739 Shift | FctKey | 0xc7, /* (Shift) F10 */
2740 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2741 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2743 /* --------------- 60 to 6f --------------- */
2744 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2745 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2746 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2747 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2748 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2749 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2750 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2751 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2752 Alt | FctKey | 0xbe, /* (Alt) F1 */
2753 Alt | FctKey | 0xbf, /* (Alt) F2 */
2754 Alt | FctKey | 0xc0, /* (Alt) F3 */
2755 Alt | FctKey | 0xc1, /* (Alt) F4 */
2756 Alt | FctKey | 0xc2, /* (Alt) F5 */
2757 Alt | FctKey | 0xc3, /* (Alt) F6 */
2758 Alt | FctKey | 0xc4, /* (Alt) F7 */
2759 Alt | FctKey | 0xc5, /* (Alt) F8 */
2761 /* --------------- 70 to 7f --------------- */
2762 Alt | FctKey | 0xc6, /* (Alt) F9 */
2763 Alt | FctKey | 0xc7, /* (Alt) F10 */
2764 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2765 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2766 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2767 Ctrl | KeyPad | 1, /* (Ctrl) End */
2768 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2769 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2770 Alt | Map | 1, /* '1' */
2771 Alt | Map | 2, /* '2' */
2772 Alt | Map | 3, /* '3' */
2773 Alt | Map | 4, /* '4' */
2774 Alt | Map | 5, /* '5' */
2775 Alt | Map | 6, /* '6' */
2776 Alt | Map | 7, /* '7' */
2777 Alt | Map | 8, /* '8' */
2779 /* --------------- 80 to 8f --------------- */
2780 Alt | Map | 9, /* '9' */
2781 Alt | Map | 10, /* '0' */
2782 Alt | Map | 11, /* '-' */
2783 Alt | Map | 12, /* '=' */
2784 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2785 FctKey | 0xc8, /* F11 */
2786 FctKey | 0xc9, /* F12 */
2787 Shift | FctKey | 0xc8, /* (Shift) F11 */
2788 Shift | FctKey | 0xc9, /* (Shift) F12 */
2789 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2790 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2791 Alt | FctKey | 0xc8, /* (Alt) F11 */
2792 Alt | FctKey | 0xc9, /* (Alt) F12 */
2793 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2794 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2795 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2797 /* --------------- 90 to 9f --------------- */
2798 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2799 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2800 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2801 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2802 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2803 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2804 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2805 Alt | FctKey | 0x50, /* (Alt) Home */
2806 Alt | FctKey | 0x52, /* (Alt) Up */
2807 Alt | FctKey | 0x55, /* (Alt) Page Up */
2808 Ignore, /* NO KEY */
2809 Alt | FctKey | 0x51, /* (Alt) Left */
2810 Ignore, /* NO KEY */
2811 Alt | FctKey | 0x53, /* (Alt) Right */
2812 Ignore, /* NO KEY */
2813 Alt | FctKey | 0x57, /* (Alt) End */
2815 /* --------------- a0 to af --------------- */
2816 Alt | KeyPad | 2, /* (Alt) Down */
2817 Alt | KeyPad | 3, /* (Alt) Page Down */
2818 Alt | KeyPad | 0, /* (Alt) Insert */
2819 Alt | KeyPad | 10, /* (Alt) Delete */
2820 Alt | Grey | 0, /* (Alt) Grey / */
2821 Alt | FctKey | 0x09, /* (Alt) Tab */
2822 Alt | Grey | 4 /* (Alt) Keypad Enter */
2825 /* These bit-positions corresponds to values returned by BIOS */
2826 #define SHIFT_P 0x0003 /* two bits! */
2827 #define CTRL_P 0x0004
2828 #define ALT_P 0x0008
2829 #define SCRLOCK_P 0x0010
2830 #define NUMLOCK_P 0x0020
2831 #define CAPSLOCK_P 0x0040
2832 #define ALT_GR_P 0x0800
2833 #define SUPER_P 0x4000 /* pseudo */
2834 #define HYPER_P 0x8000 /* pseudo */
2836 static int
2837 dos_get_modifiers (keymask)
2838 int *keymask;
2840 union REGS regs;
2841 int mask, modifiers = 0;
2843 /* Calculate modifier bits */
2844 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2845 int86 (0x16, &regs, &regs);
2847 if (!extended_kbd)
2849 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2850 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2852 else
2854 mask = regs.h.al & (SHIFT_P |
2855 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2857 /* Do not break international keyboard support. */
2858 /* When Keyb.Com is loaded, the right Alt key is */
2859 /* used for accessing characters like { and } */
2860 if (regs.h.ah & 2) /* Left ALT pressed ? */
2861 mask |= ALT_P;
2863 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2865 mask |= ALT_GR_P;
2866 if (dos_hyper_key == 1)
2868 mask |= HYPER_P;
2869 modifiers |= hyper_modifier;
2871 else if (dos_super_key == 1)
2873 mask |= SUPER_P;
2874 modifiers |= super_modifier;
2876 else if (!international_keyboard)
2878 /* If Keyb.Com is NOT installed, let Right Alt behave
2879 like the Left Alt. */
2880 mask &= ~ALT_GR_P;
2881 mask |= ALT_P;
2885 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2886 mask |= CTRL_P;
2888 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2890 if (dos_hyper_key == 2)
2892 mask |= HYPER_P;
2893 modifiers |= hyper_modifier;
2895 else if (dos_super_key == 2)
2897 mask |= SUPER_P;
2898 modifiers |= super_modifier;
2900 else
2901 mask |= CTRL_P;
2905 if (mask & SHIFT_P)
2906 modifiers |= shift_modifier;
2907 if (mask & CTRL_P)
2908 modifiers |= ctrl_modifier;
2909 if (mask & ALT_P)
2910 modifiers |= meta_modifier;
2912 if (keymask)
2913 *keymask = mask;
2914 return modifiers;
2917 #define NUM_RECENT_DOSKEYS (100)
2918 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2919 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2920 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2922 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2923 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2924 Each input key receives two values in this vector: first the ASCII code,
2925 and then the scan code. */)
2928 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2930 if (total_doskeys < NUM_RECENT_DOSKEYS)
2931 return Fvector (total_doskeys, keys);
2932 else
2934 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2935 bcopy (keys + recent_doskeys_index,
2936 XVECTOR (val)->contents,
2937 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2938 bcopy (keys,
2939 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2940 recent_doskeys_index * sizeof (Lisp_Object));
2941 return val;
2945 /* Get a char from keyboard. Function keys are put into the event queue. */
2946 static int
2947 dos_rawgetc ()
2949 struct input_event event;
2950 union REGS regs;
2951 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
2952 EVENT_INIT (event);
2954 #ifndef HAVE_X_WINDOWS
2955 /* Maybe put the cursor where it should be. */
2956 IT_cmgoto (SELECTED_FRAME());
2957 #endif
2959 /* The following condition is equivalent to `kbhit ()', except that
2960 it uses the bios to do its job. This pleases DESQview/X. */
2961 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2962 int86 (0x16, &regs, &regs),
2963 (regs.x.flags & 0x40) == 0)
2965 union REGS regs;
2966 register unsigned char c;
2967 int modifiers, sc, code = -1, mask, kp_mode;
2969 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2970 int86 (0x16, &regs, &regs);
2971 c = regs.h.al;
2972 sc = regs.h.ah;
2974 total_doskeys += 2;
2975 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2976 = make_number (c);
2977 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2978 recent_doskeys_index = 0;
2979 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2980 = make_number (sc);
2981 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2982 recent_doskeys_index = 0;
2984 modifiers = dos_get_modifiers (&mask);
2986 #ifndef HAVE_X_WINDOWS
2987 if (!NILP (Vdos_display_scancodes))
2989 char buf[11];
2990 sprintf (buf, "%02x:%02x*%04x",
2991 (unsigned) (sc&0xff), (unsigned) c, mask);
2992 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2994 #endif
2996 if (sc == 0xe0)
2998 switch (c)
3000 case 10: /* Ctrl Grey Enter */
3001 code = Ctrl | Grey | 4;
3002 break;
3003 case 13: /* Grey Enter */
3004 code = Grey | 4;
3005 break;
3006 case '/': /* Grey / */
3007 code = Grey | 0;
3008 break;
3009 default:
3010 continue;
3012 c = 0;
3014 else
3016 /* Try the keyboard-private translation table first. */
3017 if (keyboard->translate_table)
3019 struct kbd_translate *p = keyboard->translate_table;
3021 while (p->sc)
3023 if (p->sc == sc && p->ch == c)
3025 code = p->code;
3026 break;
3028 p++;
3031 /* If the private table didn't translate it, use the general
3032 one. */
3033 if (code == -1)
3035 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3036 continue;
3037 if ((code = ibmpc_translate_map[sc]) == Ignore)
3038 continue;
3042 if (c == 0)
3044 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3045 Emacs is ready to read a key. Therefore, if they press
3046 `Alt-x' when Emacs is busy, by the time we get to
3047 `dos_get_modifiers', they might have already released the
3048 Alt key, and Emacs gets just `x', which is BAD.
3049 However, for keys with the `Map' property set, the ASCII
3050 code returns zero only if Alt is pressed. So, when we DON'T
3051 have to support international_keyboard, we don't have to
3052 distinguish between the left and right Alt keys, and we
3053 can set the META modifier for any keys with the `Map'
3054 property if they return zero ASCII code (c = 0). */
3055 if ( (code & Alt)
3056 || ( (code & 0xf000) == Map && !international_keyboard))
3057 modifiers |= meta_modifier;
3058 if (code & Ctrl)
3059 modifiers |= ctrl_modifier;
3060 if (code & Shift)
3061 modifiers |= shift_modifier;
3064 switch (code & 0xf000)
3066 case ModFct:
3067 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3068 return c;
3069 c = 0; /* Special */
3071 case FctKey:
3072 if (c != 0)
3073 return c;
3075 case Special:
3076 code |= 0xff00;
3077 break;
3079 case Normal:
3080 if (sc == 0)
3082 if (c == 0) /* ctrl-break */
3083 continue;
3084 return c; /* ALT-nnn */
3086 if (!keyboard_map_all)
3088 if (c != ' ')
3089 return c;
3090 code = c;
3091 break;
3094 case Map:
3095 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3096 if (!keyboard_map_all)
3097 return c;
3099 code &= 0xff;
3100 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3101 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3103 if (mask & SHIFT_P)
3105 code = keyboard->shifted[code];
3106 mask -= SHIFT_P;
3107 modifiers &= ~shift_modifier;
3109 else
3110 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3111 code = keyboard->alt_gr[code];
3112 else
3113 code = keyboard->unshifted[code];
3114 break;
3116 case KeyPad:
3117 code &= 0xff;
3118 if (c == 0xe0) /* edit key */
3119 kp_mode = 3;
3120 else
3121 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3122 kp_mode = dos_keypad_mode & 0x03;
3123 else
3124 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3126 switch (kp_mode)
3128 case 0:
3129 if (code == 10 && dos_decimal_point)
3130 return dos_decimal_point;
3131 return keypad_translate_map[code].char_code;
3133 case 1:
3134 code = 0xff00 | keypad_translate_map[code].keypad_code;
3135 break;
3137 case 2:
3138 code = keypad_translate_map[code].meta_code;
3139 modifiers = meta_modifier;
3140 break;
3142 case 3:
3143 code = 0xff00 | keypad_translate_map[code].editkey_code;
3144 break;
3146 break;
3148 case Grey:
3149 code &= 0xff;
3150 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3151 if (dos_keypad_mode & kp_mode)
3152 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3153 else
3154 code = grey_key_translate_map[code].char_code;
3155 break;
3158 make_event:
3159 if (code == 0)
3160 continue;
3162 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3164 clear_mouse_face (dpyinfo);
3165 dpyinfo->mouse_face_hidden = 1;
3168 if (code >= 0x100)
3169 event.kind = NON_ASCII_KEYSTROKE_EVENT;
3170 else
3171 event.kind = ASCII_KEYSTROKE_EVENT;
3172 event.code = code;
3173 event.modifiers = modifiers;
3174 event.frame_or_window = selected_frame;
3175 event.arg = Qnil;
3176 event.timestamp = event_timestamp ();
3177 kbd_buffer_store_event (&event);
3180 if (have_mouse > 0 && !mouse_preempted)
3182 int but, press, x, y, ok;
3183 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3184 Lisp_Object mouse_window = Qnil;
3186 /* Check for mouse movement *before* buttons. */
3187 mouse_check_moved ();
3189 /* If the mouse moved from the spot of its last sighting, we
3190 might need to update mouse highlight. */
3191 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3193 if (dpyinfo->mouse_face_hidden)
3195 dpyinfo->mouse_face_hidden = 0;
3196 clear_mouse_face (dpyinfo);
3199 /* Generate SELECT_WINDOW_EVENTs when needed. */
3200 if (!NILP (Vmouse_autoselect_window))
3202 mouse_window = window_from_coordinates (SELECTED_FRAME(),
3203 mouse_last_x,
3204 mouse_last_y,
3205 0, 0, 0, 0);
3206 /* A window will be selected only when it is not
3207 selected now, and the last mouse movement event was
3208 not in it. A minibuffer window will be selected iff
3209 it is active. */
3210 if (WINDOWP (mouse_window)
3211 && !EQ (mouse_window, last_mouse_window)
3212 && !EQ (mouse_window, selected_window))
3214 event.kind = SELECT_WINDOW_EVENT;
3215 event.frame_or_window = mouse_window;
3216 event.arg = Qnil;
3217 event.timestamp = event_timestamp ();
3218 kbd_buffer_store_event (&event);
3220 last_mouse_window = mouse_window;
3222 else
3223 last_mouse_window = Qnil;
3225 previous_help_echo_string = help_echo_string;
3226 help_echo_string = help_echo_object = help_echo_window = Qnil;
3227 help_echo_pos = -1;
3228 IT_note_mouse_highlight (SELECTED_FRAME(),
3229 mouse_last_x, mouse_last_y);
3230 /* If the contents of the global variable help_echo has
3231 changed, generate a HELP_EVENT. */
3232 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3234 event.kind = HELP_EVENT;
3235 event.frame_or_window = selected_frame;
3236 event.arg = help_echo_object;
3237 event.x = WINDOWP (help_echo_window)
3238 ? help_echo_window : selected_frame;
3239 event.y = help_echo_string;
3240 event.timestamp = event_timestamp ();
3241 event.code = help_echo_pos;
3242 kbd_buffer_store_event (&event);
3246 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3247 for (press = 0; press < 2; press++)
3249 int button_num = but;
3251 if (press)
3252 ok = mouse_pressed (but, &x, &y);
3253 else
3254 ok = mouse_released (but, &x, &y);
3255 if (ok)
3257 /* Allow a simultaneous press/release of Mouse-1 and
3258 Mouse-2 to simulate Mouse-3 on two-button mice. */
3259 if (mouse_button_count == 2 && but < 2)
3261 int x2, y2; /* don't clobber original coordinates */
3263 /* If only one button is pressed, wait 100 msec and
3264 check again. This way, Speedy Gonzales isn't
3265 punished, while the slow get their chance. */
3266 if (press && mouse_pressed (1-but, &x2, &y2)
3267 || !press && mouse_released (1-but, &x2, &y2))
3268 button_num = 2;
3269 else
3271 delay (100);
3272 if (press && mouse_pressed (1-but, &x2, &y2)
3273 || !press && mouse_released (1-but, &x2, &y2))
3274 button_num = 2;
3278 event.kind = MOUSE_CLICK_EVENT;
3279 event.code = button_num;
3280 event.modifiers = dos_get_modifiers (0)
3281 | (press ? down_modifier : up_modifier);
3282 event.x = make_number (x);
3283 event.y = make_number (y);
3284 event.frame_or_window = selected_frame;
3285 event.arg = Qnil;
3286 event.timestamp = event_timestamp ();
3287 kbd_buffer_store_event (&event);
3292 return -1;
3295 static int prev_get_char = -1;
3297 /* Return 1 if a key is ready to be read without suspending execution. */
3299 dos_keysns ()
3301 if (prev_get_char != -1)
3302 return 1;
3303 else
3304 return ((prev_get_char = dos_rawgetc ()) != -1);
3307 /* Read a key. Return -1 if no key is ready. */
3309 dos_keyread ()
3311 if (prev_get_char != -1)
3313 int c = prev_get_char;
3314 prev_get_char = -1;
3315 return c;
3317 else
3318 return dos_rawgetc ();
3321 #ifndef HAVE_X_WINDOWS
3323 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3324 for now.
3326 Actually, I don't know the meaning of all the parameters of the functions
3327 here -- I only know how they are called by xmenu.c. I could of course
3328 grab the nearest Xlib manual (down the hall, second-to-last door on the
3329 left), but I don't think it's worth the effort. */
3331 /* These hold text of the current and the previous menu help messages. */
3332 static char *menu_help_message, *prev_menu_help_message;
3333 /* Pane number and item number of the menu item which generated the
3334 last menu help message. */
3335 static int menu_help_paneno, menu_help_itemno;
3337 static XMenu *
3338 IT_menu_create ()
3340 XMenu *menu;
3342 menu = (XMenu *) xmalloc (sizeof (XMenu));
3343 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3344 return menu;
3347 /* Allocate some (more) memory for MENU ensuring that there is room for one
3348 for item. */
3350 static void
3351 IT_menu_make_room (XMenu *menu)
3353 if (menu->allocated == 0)
3355 int count = menu->allocated = 10;
3356 menu->text = (char **) xmalloc (count * sizeof (char *));
3357 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3358 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3359 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3361 else if (menu->allocated == menu->count)
3363 int count = menu->allocated = menu->allocated + 10;
3364 menu->text
3365 = (char **) xrealloc (menu->text, count * sizeof (char *));
3366 menu->submenu
3367 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3368 menu->panenumber
3369 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3370 menu->help_text
3371 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3375 /* Search the given menu structure for a given pane number. */
3377 static XMenu *
3378 IT_menu_search_pane (XMenu *menu, int pane)
3380 int i;
3381 XMenu *try;
3383 for (i = 0; i < menu->count; i++)
3384 if (menu->submenu[i])
3386 if (pane == menu->panenumber[i])
3387 return menu->submenu[i];
3388 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3389 return try;
3391 return (XMenu *) 0;
3394 /* Determine how much screen space a given menu needs. */
3396 static void
3397 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3399 int i, h2, w2, maxsubwidth, maxheight;
3401 maxsubwidth = 0;
3402 maxheight = menu->count;
3403 for (i = 0; i < menu->count; i++)
3405 if (menu->submenu[i])
3407 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3408 if (w2 > maxsubwidth) maxsubwidth = w2;
3409 if (i + h2 > maxheight) maxheight = i + h2;
3412 *width = menu->width + maxsubwidth;
3413 *height = maxheight;
3416 /* Display MENU at (X,Y) using FACES. */
3418 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3419 do \
3421 (GLYPH).type = CHAR_GLYPH; \
3422 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3423 (GLYPH).charpos = -1; \
3425 while (0)
3427 static void
3428 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3430 int i, j, face, width, mx, my, enabled, mousehere, row, col;
3431 struct glyph *text, *p;
3432 const unsigned char *q;
3433 struct frame *sf = SELECTED_FRAME();
3435 menu_help_message = NULL;
3437 width = menu->width;
3438 /* We multiply width by 2 to account for possible control characters.
3439 FIXME: cater to non-ASCII characters in menus. */
3440 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3441 ScreenGetCursor (&row, &col);
3442 mouse_get_xy (&mx, &my);
3443 IT_update_begin (sf);
3444 for (i = 0; i < menu->count; i++)
3446 int max_width = width + 2;
3448 IT_cursor_to (sf, y + i, x);
3449 enabled
3450 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3451 mousehere = (y + i == my && x <= mx && mx < x + max_width);
3452 face = faces[enabled + mousehere * 2];
3453 /* The following if clause means that we display the menu help
3454 strings even if the menu item is currently disabled. */
3455 if (disp_help && enabled + mousehere * 2 >= 2)
3457 menu_help_message = menu->help_text[i];
3458 menu_help_paneno = pn - 1;
3459 menu_help_itemno = i;
3461 p = text;
3462 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3463 p++;
3464 for (j = 0, q = menu->text[i]; *q; j++)
3466 unsigned c = STRING_CHAR_ADVANCE (q);
3468 if (c > 26)
3470 BUILD_CHAR_GLYPH (*p, c, face, 0);
3471 p++;
3473 else /* make '^x' */
3475 BUILD_CHAR_GLYPH (*p, '^', face, 0);
3476 p++;
3477 j++;
3478 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3479 p++;
3482 /* Don't let the menu text overflow into the next screen row. */
3483 if (x + max_width > screen_size_X)
3485 max_width = screen_size_X - x;
3486 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3488 for (; j < max_width - 2; j++, p++)
3489 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3491 /* 16 is the character code of a character that on DOS terminal
3492 produces a nice-looking right-pointing arrow glyph. */
3493 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3494 p++;
3495 IT_write_glyphs (sf, text, max_width);
3497 IT_update_end (sf);
3498 IT_cursor_to (sf, row, col);
3499 xfree (text);
3502 /* --------------------------- X Menu emulation ---------------------- */
3504 /* Report availability of menus. */
3507 have_menus_p () { return 1; }
3509 /* Create a brand new menu structure. */
3511 XMenu *
3512 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3514 return IT_menu_create ();
3517 /* Create a new pane and place it on the outer-most level. It is not
3518 clear that it should be placed out there, but I don't know what else
3519 to do. */
3522 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3524 int len;
3525 char *p;
3527 if (!enable)
3528 abort ();
3530 IT_menu_make_room (menu);
3531 menu->submenu[menu->count] = IT_menu_create ();
3532 menu->text[menu->count] = txt;
3533 menu->panenumber[menu->count] = ++menu->panecount;
3534 menu->help_text[menu->count] = NULL;
3535 menu->count++;
3537 /* Adjust length for possible control characters (which will
3538 be written as ^x). */
3539 for (len = strlen (txt), p = txt; *p; p++)
3540 if (*p < 27)
3541 len++;
3543 if (len > menu->width)
3544 menu->width = len;
3546 return menu->panecount;
3549 /* Create a new item in a menu pane. */
3552 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3553 int foo, char *txt, int enable, char *help_text)
3555 int len;
3556 char *p;
3558 if (pane)
3559 if (!(menu = IT_menu_search_pane (menu, pane)))
3560 return XM_FAILURE;
3561 IT_menu_make_room (menu);
3562 menu->submenu[menu->count] = (XMenu *) 0;
3563 menu->text[menu->count] = txt;
3564 menu->panenumber[menu->count] = enable;
3565 menu->help_text[menu->count] = help_text;
3566 menu->count++;
3568 /* Adjust length for possible control characters (which will
3569 be written as ^x). */
3570 for (len = strlen (txt), p = txt; *p; p++)
3571 if (*p < 27)
3572 len++;
3574 if (len > menu->width)
3575 menu->width = len;
3577 return XM_SUCCESS;
3580 /* Decide where the menu would be placed if requested at (X,Y). */
3582 void
3583 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3584 int *ulx, int *uly, int *width, int *height)
3586 IT_menu_calc_size (menu, width, height);
3587 *ulx = x + 1;
3588 *uly = y;
3589 *width += 2;
3592 struct IT_menu_state
3594 void *screen_behind;
3595 XMenu *menu;
3596 int pane;
3597 int x, y;
3601 /* Display menu, wait for user's response, and return that response. */
3604 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3605 int x0, int y0, unsigned ButtonMask, char **txt,
3606 void (*help_callback)(char *, int, int))
3608 struct IT_menu_state *state;
3609 int statecount, x, y, i, b, screensize, leave, result, onepane;
3610 int title_faces[4]; /* face to display the menu title */
3611 int faces[4], buffers_num_deleted = 0;
3612 struct frame *sf = SELECTED_FRAME();
3613 Lisp_Object saved_echo_area_message, selectface;
3615 /* Just in case we got here without a mouse present... */
3616 if (have_mouse <= 0)
3617 return XM_IA_SELECT;
3618 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3619 around the display. */
3620 if (x0 <= 0)
3621 x0 = 1;
3622 if (y0 <= 0)
3623 y0 = 1;
3625 /* We will process all the mouse events directly, so we had
3626 better prevent dos_rawgetc from stealing them from us. */
3627 mouse_preempted++;
3629 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3630 screensize = screen_size * 2;
3631 faces[0]
3632 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3633 DEFAULT_FACE_ID, 1);
3634 faces[1]
3635 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3636 DEFAULT_FACE_ID, 1);
3637 selectface = intern ("msdos-menu-select-face");
3638 faces[2] = lookup_derived_face (sf, selectface,
3639 faces[0], 1);
3640 faces[3] = lookup_derived_face (sf, selectface,
3641 faces[1], 1);
3643 /* Make sure the menu title is always displayed with
3644 `msdos-menu-active-face', no matter where the mouse pointer is. */
3645 for (i = 0; i < 4; i++)
3646 title_faces[i] = faces[3];
3648 statecount = 1;
3650 /* Don't let the title for the "Buffers" popup menu include a
3651 digit (which is ugly).
3653 This is a terrible kludge, but I think the "Buffers" case is
3654 the only one where the title includes a number, so it doesn't
3655 seem to be necessary to make this more general. */
3656 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3658 menu->text[0][7] = '\0';
3659 buffers_num_deleted = 1;
3662 /* We need to save the current echo area message, so that we could
3663 restore it below, before we exit. See the commentary below,
3664 before the call to message_with_string. */
3665 saved_echo_area_message = Fcurrent_message ();
3666 state[0].menu = menu;
3667 mouse_off ();
3668 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3670 /* Turn off the cursor. Otherwise it shows through the menu
3671 panes, which is ugly. */
3672 IT_display_cursor (0);
3674 /* Display the menu title. */
3675 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3676 if (buffers_num_deleted)
3677 menu->text[0][7] = ' ';
3678 if ((onepane = menu->count == 1 && menu->submenu[0]))
3680 menu->width = menu->submenu[0]->width;
3681 state[0].menu = menu->submenu[0];
3683 else
3685 state[0].menu = menu;
3687 state[0].x = x0 - 1;
3688 state[0].y = y0;
3689 state[0].pane = onepane;
3691 mouse_last_x = -1; /* A hack that forces display. */
3692 leave = 0;
3693 while (!leave)
3695 if (!mouse_visible) mouse_on ();
3696 mouse_check_moved ();
3697 if (sf->mouse_moved)
3699 sf->mouse_moved = 0;
3700 result = XM_IA_SELECT;
3701 mouse_get_xy (&x, &y);
3702 for (i = 0; i < statecount; i++)
3703 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3705 int dy = y - state[i].y;
3706 if (0 <= dy && dy < state[i].menu->count)
3708 if (!state[i].menu->submenu[dy])
3709 if (state[i].menu->panenumber[dy])
3710 result = XM_SUCCESS;
3711 else
3712 result = XM_IA_SELECT;
3713 *pane = state[i].pane - 1;
3714 *selidx = dy;
3715 /* We hit some part of a menu, so drop extra menus that
3716 have been opened. That does not include an open and
3717 active submenu. */
3718 if (i != statecount - 2
3719 || state[i].menu->submenu[dy] != state[i+1].menu)
3720 while (i != statecount - 1)
3722 statecount--;
3723 mouse_off ();
3724 ScreenUpdate (state[statecount].screen_behind);
3725 if (screen_virtual_segment)
3726 dosv_refresh_virtual_screen (0, screen_size);
3727 xfree (state[statecount].screen_behind);
3729 if (i == statecount - 1 && state[i].menu->submenu[dy])
3731 IT_menu_display (state[i].menu,
3732 state[i].y,
3733 state[i].x,
3734 state[i].pane,
3735 faces, 1);
3736 state[statecount].menu = state[i].menu->submenu[dy];
3737 state[statecount].pane = state[i].menu->panenumber[dy];
3738 mouse_off ();
3739 ScreenRetrieve (state[statecount].screen_behind
3740 = xmalloc (screensize));
3741 state[statecount].x
3742 = state[i].x + state[i].menu->width + 2;
3743 state[statecount].y = y;
3744 statecount++;
3748 IT_menu_display (state[statecount - 1].menu,
3749 state[statecount - 1].y,
3750 state[statecount - 1].x,
3751 state[statecount - 1].pane,
3752 faces, 1);
3754 else
3756 if ((menu_help_message || prev_menu_help_message)
3757 && menu_help_message != prev_menu_help_message)
3759 help_callback (menu_help_message,
3760 menu_help_paneno, menu_help_itemno);
3761 IT_display_cursor (0);
3762 prev_menu_help_message = menu_help_message;
3764 /* We are busy-waiting for the mouse to move, so let's be nice
3765 to other Windows applications by releasing our time slice. */
3766 __dpmi_yield ();
3768 for (b = 0; b < mouse_button_count && !leave; b++)
3770 /* Only leave if user both pressed and released the mouse, and in
3771 that order. This avoids popping down the menu pane unless
3772 the user is really done with it. */
3773 if (mouse_pressed (b, &x, &y))
3775 while (mouse_button_depressed (b, &x, &y))
3776 __dpmi_yield ();
3777 leave = 1;
3779 (void) mouse_released (b, &x, &y);
3783 mouse_off ();
3784 ScreenUpdate (state[0].screen_behind);
3785 if (screen_virtual_segment)
3786 dosv_refresh_virtual_screen (0, screen_size);
3788 /* We have a situation here. ScreenUpdate has just restored the
3789 screen contents as it was before we started drawing this menu.
3790 That includes any echo area message that could have been
3791 displayed back then. (In reality, that echo area message will
3792 almost always be the ``keystroke echo'' that echoes the sequence
3793 of menu items chosen by the user.) However, if the menu had some
3794 help messages, then displaying those messages caused Emacs to
3795 forget about the original echo area message. So when
3796 ScreenUpdate restored it, it created a discrepancy between the
3797 actual screen contents and what Emacs internal data structures
3798 know about it.
3800 To avoid this conflict, we force Emacs to restore the original
3801 echo area message as we found it when we entered this function.
3802 The irony of this is that we then erase the restored message
3803 right away, so the only purpose of restoring it is so that
3804 erasing it works correctly... */
3805 if (! NILP (saved_echo_area_message))
3806 message_with_string ("%s", saved_echo_area_message, 0);
3807 message (0);
3808 while (statecount--)
3809 xfree (state[statecount].screen_behind);
3810 IT_display_cursor (1); /* turn cursor back on */
3811 /* Clean up any mouse events that are waiting inside Emacs event queue.
3812 These events are likely to be generated before the menu was even
3813 displayed, probably because the user pressed and released the button
3814 (which invoked the menu) too quickly. If we don't remove these events,
3815 Emacs will process them after we return and surprise the user. */
3816 discard_mouse_events ();
3817 mouse_clear_clicks ();
3818 if (!kbd_buffer_events_waiting (1))
3819 clear_input_pending ();
3820 /* Allow mouse events generation by dos_rawgetc. */
3821 mouse_preempted--;
3822 return result;
3825 /* Dispose of a menu. */
3827 void
3828 XMenuDestroy (Display *foo, XMenu *menu)
3830 int i;
3831 if (menu->allocated)
3833 for (i = 0; i < menu->count; i++)
3834 if (menu->submenu[i])
3835 XMenuDestroy (foo, menu->submenu[i]);
3836 xfree (menu->text);
3837 xfree (menu->submenu);
3838 xfree (menu->panenumber);
3839 xfree (menu->help_text);
3841 xfree (menu);
3842 menu_help_message = prev_menu_help_message = NULL;
3846 x_pixel_width (struct frame *f)
3848 return FRAME_COLS (f);
3852 x_pixel_height (struct frame *f)
3854 return FRAME_LINES (f);
3856 #endif /* !HAVE_X_WINDOWS */
3858 /* ----------------------- DOS / UNIX conversion --------------------- */
3860 void msdos_downcase_filename (unsigned char *);
3862 /* Destructively turn backslashes into slashes. */
3864 void
3865 dostounix_filename (p)
3866 register char *p;
3868 msdos_downcase_filename (p);
3870 while (*p)
3872 if (*p == '\\')
3873 *p = '/';
3874 p++;
3878 /* Destructively turn slashes into backslashes. */
3880 void
3881 unixtodos_filename (p)
3882 register char *p;
3884 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3886 *p += 'a' - 'A';
3887 p += 2;
3890 while (*p)
3892 if (*p == '/')
3893 *p = '\\';
3894 p++;
3898 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3901 getdefdir (drive, dst)
3902 int drive;
3903 char *dst;
3905 char in_path[4], *p = in_path, e = errno;
3907 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3908 if (drive != 0)
3910 *p++ = drive + 'A' - 1;
3911 *p++ = ':';
3914 *p++ = '.';
3915 *p = '\0';
3916 errno = 0;
3917 _fixpath (in_path, dst);
3918 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3919 it queries the LFN support, so ignore that error. */
3920 if ((errno && errno != ENOSYS) || *dst == '\0')
3921 return 0;
3923 msdos_downcase_filename (dst);
3925 errno = e;
3926 return 1;
3929 char *
3930 emacs_root_dir (void)
3932 static char root_dir[4];
3934 sprintf (root_dir, "%c:/", 'A' + getdisk ());
3935 root_dir[0] = tolower (root_dir[0]);
3936 return root_dir;
3939 /* Remove all CR's that are followed by a LF. */
3942 crlf_to_lf (n, buf)
3943 register int n;
3944 register unsigned char *buf;
3946 unsigned char *np = buf, *startp = buf, *endp = buf + n;
3948 if (n == 0)
3949 return n;
3950 while (buf < endp - 1)
3952 if (*buf == 0x0d)
3954 if (*(++buf) != 0x0a)
3955 *np++ = 0x0d;
3957 else
3958 *np++ = *buf++;
3960 if (buf < endp)
3961 *np++ = *buf++;
3962 return np - startp;
3965 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3966 0, 0, 0,
3967 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
3970 return (_USE_LFN ? Qt : Qnil);
3973 /* Convert alphabetic characters in a filename to lower-case. */
3975 void
3976 msdos_downcase_filename (p)
3977 register unsigned char *p;
3979 /* Always lower-case drive letters a-z, even if the filesystem
3980 preserves case in filenames.
3981 This is so MSDOS filenames could be compared by string comparison
3982 functions that are case-sensitive. Even case-preserving filesystems
3983 do not distinguish case in drive letters. */
3984 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3986 *p += 'a' - 'A';
3987 p += 2;
3990 /* Under LFN we expect to get pathnames in their true case. */
3991 if (NILP (Fmsdos_long_file_names ()))
3992 for ( ; *p; p++)
3993 if (*p >= 'A' && *p <= 'Z')
3994 *p += 'a' - 'A';
3997 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3998 1, 1, 0,
3999 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
4000 When long filenames are supported, doesn't change FILENAME.
4001 If FILENAME is not a string, returns nil.
4002 The argument object is never altered--the value is a copy. */)
4003 (filename)
4004 Lisp_Object filename;
4006 Lisp_Object tem;
4008 if (! STRINGP (filename))
4009 return Qnil;
4011 tem = Fcopy_sequence (filename);
4012 msdos_downcase_filename (SDATA (tem));
4013 return tem;
4016 /* The Emacs root directory as determined by init_environment. */
4018 static char emacsroot[MAXPATHLEN];
4020 char *
4021 rootrelativepath (rel)
4022 char *rel;
4024 static char result[MAXPATHLEN + 10];
4026 strcpy (result, emacsroot);
4027 strcat (result, "/");
4028 strcat (result, rel);
4029 return result;
4032 /* Define a lot of environment variables if not already defined. Don't
4033 remove anything unless you know what you're doing -- lots of code will
4034 break if one or more of these are missing. */
4036 void
4037 init_environment (argc, argv, skip_args)
4038 int argc;
4039 char **argv;
4040 int skip_args;
4042 char *s, *t, *root;
4043 int len, i;
4044 static const char * const tempdirs[] = {
4045 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4047 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4049 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4050 temporary files and assume "/tmp" if $TMPDIR is unset, which
4051 will break on DOS/Windows. Refuse to work if we cannot find
4052 a directory, not even "c:/", usable for that purpose. */
4053 for (i = 0; i < imax ; i++)
4055 const char *tmp = tempdirs[i];
4056 char buf[FILENAME_MAX];
4058 if (*tmp == '$')
4060 int tmp_len;
4062 tmp = getenv (tmp + 1);
4063 if (!tmp)
4064 continue;
4066 /* Some lusers set TMPDIR=e:, probably because some losing
4067 programs cannot handle multiple slashes if they use e:/.
4068 e: fails in `access' below, so we interpret e: as e:/. */
4069 tmp_len = strlen(tmp);
4070 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4072 strcpy(buf, tmp);
4073 buf[tmp_len++] = '/', buf[tmp_len] = 0;
4074 tmp = buf;
4078 /* Note that `access' can lie to us if the directory resides on a
4079 read-only filesystem, like CD-ROM or a write-protected floppy.
4080 The only way to be really sure is to actually create a file and
4081 see if it succeeds. But I think that's too much to ask. */
4082 if (tmp && access (tmp, D_OK) == 0)
4084 setenv ("TMPDIR", tmp, 1);
4085 break;
4088 if (i >= imax)
4089 cmd_error_internal
4090 (Fcons (Qerror,
4091 Fcons (build_string ("no usable temporary directories found!!"),
4092 Qnil)),
4093 "While setting TMPDIR: ");
4095 /* Note the startup time, so we know not to clear the screen if we
4096 exit immediately; see IT_reset_terminal_modes.
4097 (Yes, I know `clock' returns zero the first time it's called, but
4098 I do this anyway, in case some wiseguy changes that at some point.) */
4099 startup_time = clock ();
4101 /* Find our root from argv[0]. Assuming argv[0] is, say,
4102 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4103 root = alloca (MAXPATHLEN + 20);
4104 _fixpath (argv[0], root);
4105 msdos_downcase_filename (root);
4106 len = strlen (root);
4107 while (len > 0 && root[len] != '/' && root[len] != ':')
4108 len--;
4109 root[len] = '\0';
4110 if (len > 4
4111 && (strcmp (root + len - 4, "/bin") == 0
4112 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4113 root[len - 4] = '\0';
4114 else
4115 strcpy (root, "c:/emacs"); /* let's be defensive */
4116 len = strlen (root);
4117 strcpy (emacsroot, root);
4119 /* We default HOME to our root. */
4120 setenv ("HOME", root, 0);
4122 /* We default EMACSPATH to root + "/bin". */
4123 strcpy (root + len, "/bin");
4124 setenv ("EMACSPATH", root, 0);
4126 /* I don't expect anybody to ever use other terminals so the internal
4127 terminal is the default. */
4128 setenv ("TERM", "internal", 0);
4130 #ifdef HAVE_X_WINDOWS
4131 /* Emacs expects DISPLAY to be set. */
4132 setenv ("DISPLAY", "unix:0.0", 0);
4133 #endif
4135 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4136 downcase it and mirror the backslashes. */
4137 s = getenv ("COMSPEC");
4138 if (!s) s = "c:/command.com";
4139 t = alloca (strlen (s) + 1);
4140 strcpy (t, s);
4141 dostounix_filename (t);
4142 setenv ("SHELL", t, 0);
4144 /* PATH is also downcased and backslashes mirrored. */
4145 s = getenv ("PATH");
4146 if (!s) s = "";
4147 t = alloca (strlen (s) + 3);
4148 /* Current directory is always considered part of MsDos's path but it is
4149 not normally mentioned. Now it is. */
4150 strcat (strcpy (t, ".;"), s);
4151 dostounix_filename (t); /* Not a single file name, but this should work. */
4152 setenv ("PATH", t, 1);
4154 /* In some sense all dos users have root privileges, so... */
4155 setenv ("USER", "root", 0);
4156 setenv ("NAME", getenv ("USER"), 0);
4158 /* Time zone determined from country code. To make this possible, the
4159 country code may not span more than one time zone. In other words,
4160 in the USA, you lose. */
4161 if (!getenv ("TZ"))
4162 switch (dos_country_code)
4164 case 31: /* Belgium */
4165 case 32: /* The Netherlands */
4166 case 33: /* France */
4167 case 34: /* Spain */
4168 case 36: /* Hungary */
4169 case 38: /* Yugoslavia (or what's left of it?) */
4170 case 39: /* Italy */
4171 case 41: /* Switzerland */
4172 case 42: /* Tjekia */
4173 case 45: /* Denmark */
4174 case 46: /* Sweden */
4175 case 47: /* Norway */
4176 case 48: /* Poland */
4177 case 49: /* Germany */
4178 /* Daylight saving from last Sunday in March to last Sunday in
4179 September, both at 2AM. */
4180 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4181 break;
4182 case 44: /* United Kingdom */
4183 case 351: /* Portugal */
4184 case 354: /* Iceland */
4185 setenv ("TZ", "GMT+00", 0);
4186 break;
4187 case 81: /* Japan */
4188 case 82: /* Korea */
4189 setenv ("TZ", "JST-09", 0);
4190 break;
4191 case 90: /* Turkey */
4192 case 358: /* Finland */
4193 setenv ("TZ", "EET-02", 0);
4194 break;
4195 case 972: /* Israel */
4196 /* This is an approximation. (For exact rules, use the
4197 `zoneinfo/israel' file which comes with DJGPP, but you need
4198 to install it in `/usr/share/zoneinfo/' directory first.) */
4199 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4200 break;
4202 tzset ();
4207 static int break_stat; /* BREAK check mode status. */
4208 static int stdin_stat; /* stdin IOCTL status. */
4210 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4211 control chars by DOS. Determine the keyboard type. */
4214 dos_ttraw (struct tty_display_info *tty)
4216 union REGS inregs, outregs;
4217 static int first_time = 1;
4219 /* If we are called for the initial terminal, it's too early to do
4220 anything, and termscript isn't set up. */
4221 if (tty->terminal->type == output_initial)
4222 return;
4224 break_stat = getcbrk ();
4225 setcbrk (0);
4227 if (first_time)
4229 inregs.h.ah = 0xc0;
4230 int86 (0x15, &inregs, &outregs);
4231 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4233 have_mouse = 0;
4235 if (1
4236 #ifdef HAVE_X_WINDOWS
4237 && inhibit_window_system
4238 #endif
4241 inregs.x.ax = 0x0021;
4242 int86 (0x33, &inregs, &outregs);
4243 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4244 if (!have_mouse)
4246 /* Reportedly, the above doesn't work for some mouse drivers. There
4247 is an additional detection method that should work, but might be
4248 a little slower. Use that as an alternative. */
4249 inregs.x.ax = 0x0000;
4250 int86 (0x33, &inregs, &outregs);
4251 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4253 if (have_mouse)
4254 mouse_button_count = outregs.x.bx;
4256 #ifndef HAVE_X_WINDOWS
4257 /* Save the cursor shape used outside Emacs. */
4258 outside_cursor = _farpeekw (_dos_ds, 0x460);
4259 #endif
4262 first_time = 0;
4264 stdin_stat = setmode (fileno (stdin), O_BINARY);
4265 return (stdin_stat != -1);
4267 else
4268 return (setmode (fileno (stdin), O_BINARY) != -1);
4271 /* Restore status of standard input and Ctrl-C checking. */
4274 dos_ttcooked ()
4276 union REGS inregs, outregs;
4278 setcbrk (break_stat);
4279 mouse_off ();
4281 #ifndef HAVE_X_WINDOWS
4282 /* Restore the cursor shape we found on startup. */
4283 if (outside_cursor)
4285 inregs.h.ah = 1;
4286 inregs.x.cx = outside_cursor;
4287 int86 (0x10, &inregs, &outregs);
4289 #endif
4291 return (setmode (fileno (stdin), stdin_stat) != -1);
4295 /* Run command as specified by ARGV in directory DIR.
4296 The command is run with input from TEMPIN, output to
4297 file TEMPOUT and stderr to TEMPERR. */
4300 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4301 unsigned char **argv;
4302 const char *working_dir;
4303 int tempin, tempout, temperr;
4304 char **envv;
4306 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4307 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4308 int msshell, result = -1, inbak, outbak, errbak, x, y;
4309 Lisp_Object cmd;
4311 /* Get current directory as MSDOS cwd is not per-process. */
4312 getwd (oldwd);
4314 /* If argv[0] is the shell, it might come in any lettercase.
4315 Since `Fmember' is case-sensitive, we need to downcase
4316 argv[0], even if we are on case-preserving filesystems. */
4317 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4318 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4320 *pl = *pa++;
4321 if (*pl >= 'A' && *pl <= 'Z')
4322 *pl += 'a' - 'A';
4324 *pl = '\0';
4326 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4327 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4328 && !strcmp ("-c", argv[1]);
4329 if (msshell)
4331 saveargv1 = argv[1];
4332 saveargv2 = argv[2];
4333 argv[1] = "/c";
4334 /* We only need to mirror slashes if a DOS shell will be invoked
4335 not via `system' (which does the mirroring itself). Yes, that
4336 means DJGPP v1.x will lose here. */
4337 if (argv[2] && argv[3])
4339 char *p = alloca (strlen (argv[2]) + 1);
4341 strcpy (argv[2] = p, saveargv2);
4342 while (*p && isspace (*p))
4343 p++;
4344 while (*p)
4346 if (*p == '/')
4347 *p++ = '\\';
4348 else
4349 p++;
4354 chdir (working_dir);
4355 inbak = dup (0);
4356 outbak = dup (1);
4357 errbak = dup (2);
4358 if (inbak < 0 || outbak < 0 || errbak < 0)
4359 goto done; /* Allocation might fail due to lack of descriptors. */
4361 if (have_mouse > 0)
4362 mouse_get_xy (&x, &y);
4364 if (!noninteractive)
4365 dos_ttcooked (); /* do it here while 0 = stdin */
4367 dup2 (tempin, 0);
4368 dup2 (tempout, 1);
4369 dup2 (temperr, 2);
4371 if (msshell && !argv[3])
4373 /* MS-DOS native shells are too restrictive. For starters, they
4374 cannot grok commands longer than 126 characters. In DJGPP v2
4375 and later, `system' is much smarter, so we'll call it instead. */
4377 const char *cmnd;
4379 /* A shell gets a single argument--its full command
4380 line--whose original was saved in `saveargv2'. */
4382 /* Don't let them pass empty command lines to `system', since
4383 with some shells it will try to invoke an interactive shell,
4384 which will hang Emacs. */
4385 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4387 if (*cmnd)
4389 extern char **environ;
4390 char **save_env = environ;
4391 int save_system_flags = __system_flags;
4393 /* Request the most powerful version of `system'. We need
4394 all the help we can get to avoid calling stock DOS shells. */
4395 __system_flags = (__system_redirect
4396 | __system_use_shell
4397 | __system_allow_multiple_cmds
4398 | __system_allow_long_cmds
4399 | __system_handle_null_commands
4400 | __system_emulate_chdir);
4402 environ = envv;
4403 result = system (cmnd);
4404 __system_flags = save_system_flags;
4405 environ = save_env;
4407 else
4408 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4410 else
4411 result = spawnve (P_WAIT, argv[0], argv, envv);
4413 dup2 (inbak, 0);
4414 dup2 (outbak, 1);
4415 dup2 (errbak, 2);
4416 emacs_close (inbak);
4417 emacs_close (outbak);
4418 emacs_close (errbak);
4420 if (!noninteractive)
4421 dos_ttraw (CURTTY ());
4422 if (have_mouse > 0)
4424 mouse_init ();
4425 mouse_moveto (x, y);
4428 /* Some programs might change the meaning of the highest bit of the
4429 text attribute byte, so we get blinking characters instead of the
4430 bright background colors. Restore that. */
4431 if (!noninteractive)
4432 bright_bg ();
4434 done:
4435 chdir (oldwd);
4436 if (msshell)
4438 argv[1] = saveargv1;
4439 argv[2] = saveargv2;
4441 return result;
4444 void
4445 croak (badfunc)
4446 char *badfunc;
4448 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4449 reset_all_sys_modes ();
4450 exit (1);
4454 * A few unimplemented functions that we silently ignore.
4456 setpgrp () {return 0; }
4457 setpriority (x,y,z) int x,y,z; { return 0; }
4459 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4461 #ifdef POSIX_SIGNALS
4463 /* Augment DJGPP library POSIX signal functions. This is needed
4464 as of DJGPP v2.01, but might be in the library in later releases. */
4466 #include <libc/bss.h>
4468 /* A counter to know when to re-initialize the static sets. */
4469 static int sigprocmask_count = -1;
4471 /* Which signals are currently blocked (initially none). */
4472 static sigset_t current_mask;
4474 /* Which signals are pending (initially none). */
4475 static sigset_t msdos_pending_signals;
4477 /* Previous handlers to restore when the blocked signals are unblocked. */
4478 typedef void (*sighandler_t)(int);
4479 static sighandler_t prev_handlers[320];
4481 /* A signal handler which just records that a signal occurred
4482 (it will be raised later, if and when the signal is unblocked). */
4483 static void
4484 sig_suspender (signo)
4485 int signo;
4487 sigaddset (&msdos_pending_signals, signo);
4491 sigprocmask (how, new_set, old_set)
4492 int how;
4493 const sigset_t *new_set;
4494 sigset_t *old_set;
4496 int signo;
4497 sigset_t new_mask;
4499 /* If called for the first time, initialize. */
4500 if (sigprocmask_count != __bss_count)
4502 sigprocmask_count = __bss_count;
4503 sigemptyset (&msdos_pending_signals);
4504 sigemptyset (&current_mask);
4505 for (signo = 0; signo < 320; signo++)
4506 prev_handlers[signo] = SIG_ERR;
4509 if (old_set)
4510 *old_set = current_mask;
4512 if (new_set == 0)
4513 return 0;
4515 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4517 errno = EINVAL;
4518 return -1;
4521 sigemptyset (&new_mask);
4523 /* DJGPP supports upto 320 signals. */
4524 for (signo = 0; signo < 320; signo++)
4526 if (sigismember (&current_mask, signo))
4527 sigaddset (&new_mask, signo);
4528 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4530 sigaddset (&new_mask, signo);
4532 /* SIGKILL is silently ignored, as on other platforms. */
4533 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4534 prev_handlers[signo] = signal (signo, sig_suspender);
4536 if (( how == SIG_UNBLOCK
4537 && sigismember (&new_mask, signo)
4538 && sigismember (new_set, signo))
4539 || (how == SIG_SETMASK
4540 && sigismember (&new_mask, signo)
4541 && !sigismember (new_set, signo)))
4543 sigdelset (&new_mask, signo);
4544 if (prev_handlers[signo] != SIG_ERR)
4546 signal (signo, prev_handlers[signo]);
4547 prev_handlers[signo] = SIG_ERR;
4549 if (sigismember (&msdos_pending_signals, signo))
4551 sigdelset (&msdos_pending_signals, signo);
4552 raise (signo);
4556 current_mask = new_mask;
4557 return 0;
4560 #else /* not POSIX_SIGNALS */
4562 sigsetmask (x) int x; { return 0; }
4563 sigblock (mask) int mask; { return 0; }
4565 #endif /* not POSIX_SIGNALS */
4566 #endif /* not __DJGPP_MINOR__ < 2 */
4568 #ifndef HAVE_SELECT
4569 #include "sysselect.h"
4571 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4572 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4573 ((long)(time).tv_sec < 0 \
4574 || ((time).tv_sec == 0 \
4575 && (long)(time).tv_usec <= 0))
4576 #endif
4578 /* This yields the rest of the current time slice to the task manager.
4579 It should be called by any code which knows that it has nothing
4580 useful to do except idle.
4582 I don't use __dpmi_yield here, since versions of library before 2.02
4583 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4584 on some versions of Windows 9X. */
4586 void
4587 dos_yield_time_slice (void)
4589 _go32_dpmi_registers r;
4591 r.x.ax = 0x1680;
4592 r.x.ss = r.x.sp = r.x.flags = 0;
4593 _go32_dpmi_simulate_int (0x2f, &r);
4594 if (r.h.al == 0x80)
4595 errno = ENOSYS;
4598 /* Only event queue is checked. */
4599 /* We don't have to call timer_check here
4600 because wait_reading_process_output takes care of that. */
4602 sys_select (nfds, rfds, wfds, efds, timeout)
4603 int nfds;
4604 SELECT_TYPE *rfds, *wfds, *efds;
4605 EMACS_TIME *timeout;
4607 int check_input;
4608 struct time t;
4610 check_input = 0;
4611 if (rfds)
4613 check_input = FD_ISSET (0, rfds);
4614 FD_ZERO (rfds);
4616 if (wfds)
4617 FD_ZERO (wfds);
4618 if (efds)
4619 FD_ZERO (efds);
4621 if (nfds != 1)
4622 abort ();
4624 /* If we are looking only for the terminal, with no timeout,
4625 just read it and wait -- that's more efficient. */
4626 if (!timeout)
4628 while (!detect_input_pending ())
4630 dos_yield_time_slice ();
4633 else
4635 EMACS_TIME clnow, cllast, cldiff;
4637 gettime (&t);
4638 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4640 while (!check_input || !detect_input_pending ())
4642 gettime (&t);
4643 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4644 EMACS_SUB_TIME (cldiff, clnow, cllast);
4646 /* When seconds wrap around, we assume that no more than
4647 1 minute passed since last `gettime'. */
4648 if (EMACS_TIME_NEG_P (cldiff))
4649 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4650 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4652 /* Stop when timeout value crosses zero. */
4653 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4654 return 0;
4655 cllast = clnow;
4656 dos_yield_time_slice ();
4660 FD_SET (0, rfds);
4661 return 1;
4663 #endif
4666 * Define overlaid functions:
4668 * chdir -> sys_chdir
4669 * tzset -> init_gettimeofday
4670 * abort -> dos_abort
4673 #ifdef chdir
4674 #undef chdir
4675 extern int chdir ();
4678 sys_chdir (path)
4679 const char* path;
4681 int len = strlen (path);
4682 char *tmp = (char *)path;
4684 if (*tmp && tmp[1] == ':')
4686 if (getdisk () != tolower (tmp[0]) - 'a')
4687 setdisk (tolower (tmp[0]) - 'a');
4688 tmp += 2; /* strip drive: KFS 1995-07-06 */
4689 len -= 2;
4692 if (len > 1 && (tmp[len - 1] == '/'))
4694 char *tmp1 = (char *) alloca (len + 1);
4695 strcpy (tmp1, tmp);
4696 tmp1[len - 1] = 0;
4697 tmp = tmp1;
4699 return chdir (tmp);
4701 #endif
4703 #ifdef tzset
4704 #undef tzset
4705 extern void tzset (void);
4707 void
4708 init_gettimeofday ()
4710 time_t ltm, gtm;
4711 struct tm *lstm;
4713 tzset ();
4714 ltm = gtm = time (NULL);
4715 ltm = mktime (lstm = localtime (&ltm));
4716 gtm = mktime (gmtime (&gtm));
4717 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4718 time_rec.tm_isdst = lstm->tm_isdst;
4719 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4721 #endif
4723 #ifdef abort
4724 #undef abort
4725 void
4726 dos_abort (file, line)
4727 char *file;
4728 int line;
4730 char buffer1[200], buffer2[400];
4731 int i, j;
4733 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4734 for (i = j = 0; buffer1[i]; i++) {
4735 buffer2[j++] = buffer1[i];
4736 buffer2[j++] = 0x70;
4738 dosmemput (buffer2, j, (int)ScreenPrimary);
4739 ScreenSetCursor (2, 0);
4740 abort ();
4742 #else
4743 void
4744 abort ()
4746 dos_ttcooked ();
4747 ScreenSetCursor (10, 0);
4748 cputs ("\r\n\nEmacs aborted!\r\n");
4749 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4750 if (screen_virtual_segment)
4751 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4752 /* Generate traceback, so we could tell whodunit. */
4753 signal (SIGINT, SIG_DFL);
4754 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4755 #else /* __DJGPP_MINOR__ >= 2 */
4756 raise (SIGABRT);
4757 #endif /* __DJGPP_MINOR__ >= 2 */
4758 exit (2);
4760 #endif
4762 /* The following variables are required so that cus-start.el won't
4763 complain about unbound variables. */
4764 #ifndef subprocesses
4765 /* Nonzero means delete a process right away if it exits (process.c). */
4766 static int delete_exited_processes;
4767 #endif
4769 syms_of_msdos ()
4771 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4772 staticpro (&recent_doskeys);
4774 #ifndef HAVE_X_WINDOWS
4776 /* The following two are from xfns.c: */
4777 Qreverse = intern ("reverse");
4778 staticpro (&Qreverse);
4780 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4781 doc: /* *Glyph to display instead of chars not supported by current codepage.
4782 This variable is used only by MS-DOS terminals. */);
4783 Vdos_unsupported_char_glyph = make_number ('\177');
4785 #endif
4786 #ifndef subprocesses
4787 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
4788 doc: /* *Non-nil means delete processes immediately when they exit.
4789 A value of nil means don't delete them until `list-processes' is run. */);
4790 delete_exited_processes = 0;
4791 #endif
4793 defsubr (&Srecent_doskeys);
4794 defsubr (&Smsdos_long_file_names);
4795 defsubr (&Smsdos_downcase_filename);
4796 defsubr (&Smsdos_remember_default_colors);
4797 defsubr (&Smsdos_set_mouse_buttons);
4800 #endif /* MSDOS */
4802 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
4803 (do not change this comment) */