(IT_note_mode_line_highlight, IT_note_mouse_highlight):
[emacs.git] / src / msdos.c
blob3e6dbf236de88b25d6e01ea64fcb75581711f944
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
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 "lisp.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <dos.h>
36 #include <errno.h>
37 #include <string.h> /* for bzero and string functions */
38 #include <sys/stat.h> /* for _fixpath */
39 #include <unistd.h> /* for chdir, dup, dup2, etc. */
40 #if __DJGPP__ >= 2
41 #include <fcntl.h>
42 #include <io.h> /* for setmode */
43 #include <dpmi.h> /* for __dpmi_xxx stuff */
44 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
45 #include <libc/dosio.h> /* for _USE_LFN */
46 #include <conio.h> /* for cputs */
47 #endif
49 #include "msdos.h"
50 #include "systime.h"
51 #include "termhooks.h"
52 #include "termchar.h"
53 #include "dispextern.h"
54 #include "dosfns.h"
55 #include "termopts.h"
56 #include "charset.h"
57 #include "coding.h"
58 #include "disptab.h"
59 #include "frame.h"
60 #include "window.h"
61 #include "buffer.h"
62 #include "commands.h"
63 #include "blockinput.h"
64 #include <go32.h>
65 #include <pc.h>
66 #include <ctype.h>
67 /* #include <process.h> */
68 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
69 #define P_WAIT 1
71 #ifndef _USE_LFN
72 #define _USE_LFN 0
73 #endif
75 #ifndef _dos_ds
76 #define _dos_ds _go32_info_block.selector_for_linear_memory
77 #endif
79 #if __DJGPP__ > 1
81 #include <signal.h>
82 #include "syssignal.h"
84 #ifndef SYSTEM_MALLOC
86 #ifdef GNU_MALLOC
88 /* If other `malloc' than ours is used, force our `sbrk' behave like
89 Unix programs expect (resize memory blocks to keep them contiguous).
90 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
91 because that's what `gmalloc' expects to get. */
92 #include <crt0.h>
94 #ifdef REL_ALLOC
95 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
96 #else /* not REL_ALLOC */
97 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
98 #endif /* not REL_ALLOC */
99 #endif /* GNU_MALLOC */
101 #endif /* not SYSTEM_MALLOC */
102 #endif /* __DJGPP__ > 1 */
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 if (termscript)
148 fprintf (termscript, "<M_ON>");
149 regs.x.ax = 0x0001;
150 int86 (0x33, &regs, &regs);
151 mouse_visible = 1;
155 void
156 mouse_off ()
158 union REGS regs;
160 if (have_mouse > 0 && mouse_visible)
162 if (termscript)
163 fprintf (termscript, "<M_OFF>");
164 regs.x.ax = 0x0002;
165 int86 (0x33, &regs, &regs);
166 mouse_visible = 0;
170 static void
171 mouse_get_xy (int *x, int *y)
173 union REGS regs;
175 regs.x.ax = 0x0003;
176 int86 (0x33, &regs, &regs);
177 *x = regs.x.cx / 8;
178 *y = regs.x.dx / 8;
181 void
182 mouse_moveto (x, y)
183 int x, y;
185 union REGS regs;
187 if (termscript)
188 fprintf (termscript, "<M_XY=%dx%d>", x, y);
189 regs.x.ax = 0x0004;
190 mouse_last_x = regs.x.cx = x * 8;
191 mouse_last_y = regs.x.dx = y * 8;
192 int86 (0x33, &regs, &regs);
195 static int
196 mouse_pressed (b, xp, yp)
197 int b, *xp, *yp;
199 union REGS regs;
201 if (b >= mouse_button_count)
202 return 0;
203 regs.x.ax = 0x0005;
204 regs.x.bx = mouse_button_translate[b];
205 int86 (0x33, &regs, &regs);
206 if (regs.x.bx)
207 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
208 return (regs.x.bx != 0);
211 static int
212 mouse_released (b, xp, yp)
213 int b, *xp, *yp;
215 union REGS regs;
217 if (b >= mouse_button_count)
218 return 0;
219 regs.x.ax = 0x0006;
220 regs.x.bx = mouse_button_translate[b];
221 int86 (0x33, &regs, &regs);
222 if (regs.x.bx)
223 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
224 return (regs.x.bx != 0);
227 static int
228 mouse_button_depressed (b, xp, yp)
229 int b, *xp, *yp;
231 union REGS regs;
233 if (b >= mouse_button_count)
234 return 0;
235 regs.x.ax = 0x0003;
236 int86 (0x33, &regs, &regs);
237 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
239 *xp = regs.x.cx / 8;
240 *yp = regs.x.dx / 8;
241 return 1;
243 return 0;
246 void
247 mouse_get_pos (f, insist, bar_window, part, x, y, time)
248 FRAME_PTR *f;
249 int insist;
250 Lisp_Object *bar_window, *x, *y;
251 enum scroll_bar_part *part;
252 unsigned long *time;
254 int ix, iy;
255 Lisp_Object frame, tail;
257 /* Clear the mouse-moved flag for every frame on this display. */
258 FOR_EACH_FRAME (tail, frame)
259 XFRAME (frame)->mouse_moved = 0;
261 *f = SELECTED_FRAME();
262 *bar_window = Qnil;
263 mouse_get_xy (&ix, &iy);
264 *time = event_timestamp ();
265 *x = make_number (mouse_last_x = ix);
266 *y = make_number (mouse_last_y = iy);
269 static void
270 mouse_check_moved ()
272 int x, y;
274 mouse_get_xy (&x, &y);
275 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
276 mouse_last_x = x;
277 mouse_last_y = y;
280 void
281 mouse_init ()
283 union REGS regs;
284 int b;
286 if (termscript)
287 fprintf (termscript, "<M_INIT>");
289 regs.x.ax = 0x0021;
290 int86 (0x33, &regs, &regs);
292 /* Reset the mouse last press/release info. It seems that Windows
293 doesn't do that automatically when function 21h is called, which
294 causes Emacs to ``remember'' the click that switched focus to the
295 window just before Emacs was started from that window. */
296 for (b = 0; b < mouse_button_count; b++)
298 int dummy_x, dummy_y;
300 (void) mouse_pressed (b, &dummy_x, &dummy_y);
301 (void) mouse_released (b, &dummy_x, &dummy_y);
304 regs.x.ax = 0x0007;
305 regs.x.cx = 0;
306 regs.x.dx = 8 * (ScreenCols () - 1);
307 int86 (0x33, &regs, &regs);
309 regs.x.ax = 0x0008;
310 regs.x.cx = 0;
311 regs.x.dx = 8 * (ScreenRows () - 1);
312 int86 (0x33, &regs, &regs);
314 mouse_moveto (0, 0);
315 mouse_visible = 0;
318 /* ------------------------- Screen control ----------------------
322 static int internal_terminal = 0;
324 #ifndef HAVE_X_WINDOWS
325 extern unsigned char ScreenAttrib;
326 static int screen_face;
327 static int highlight;
329 static int screen_size_X;
330 static int screen_size_Y;
331 static int screen_size;
333 static int current_pos_X;
334 static int current_pos_Y;
335 static int new_pos_X;
336 static int new_pos_Y;
338 static void *startup_screen_buffer;
339 static int startup_screen_size_X;
340 static int startup_screen_size_Y;
341 static int startup_pos_X;
342 static int startup_pos_Y;
343 static unsigned char startup_screen_attrib;
345 static clock_t startup_time;
347 static int term_setup_done;
349 static unsigned short outside_cursor;
351 /* Similar to the_only_frame. */
352 struct x_output the_only_x_display;
354 /* Support for DOS/V (allows Japanese characters to be displayed on
355 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
357 /* Holds the address of the text-mode screen buffer. */
358 static unsigned long screen_old_address = 0;
359 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
360 static unsigned short screen_virtual_segment = 0;
361 static unsigned short screen_virtual_offset = 0;
362 /* A flag to control how to display unibyte 8-bit characters. */
363 extern int unibyte_display_via_language_environment;
365 Lisp_Object Qbar;
367 #if __DJGPP__ > 1
368 /* Update the screen from a part of relocated DOS/V screen buffer which
369 begins at OFFSET and includes COUNT characters. */
370 static void
371 dosv_refresh_virtual_screen (int offset, int count)
373 __dpmi_regs regs;
375 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
376 return;
378 regs.h.ah = 0xff; /* update relocated screen */
379 regs.x.es = screen_virtual_segment;
380 regs.x.di = screen_virtual_offset + offset;
381 regs.x.cx = count;
382 __dpmi_int (0x10, &regs);
384 #endif
386 static void
387 dos_direct_output (y, x, buf, len)
388 int y;
389 int x;
390 char *buf;
391 int len;
393 int t0 = 2 * (x + y * screen_size_X);
394 int t = t0 + (int) ScreenPrimary;
395 int l0 = len;
397 #if (__DJGPP__ < 2)
398 while (--len >= 0) {
399 dosmemput (buf++, 1, t);
400 t += 2;
402 #else
403 /* This is faster. */
404 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
405 _farnspokeb (t, *buf);
407 if (screen_virtual_segment)
408 dosv_refresh_virtual_screen (t0, l0);
409 #endif
411 #endif
413 /* Flash the screen as a substitute for BEEPs. */
415 #if (__DJGPP__ < 2)
416 static void
417 do_visible_bell (xorattr)
418 unsigned char xorattr;
420 asm volatile
421 (" movb $1,%%dl
422 visible_bell_0:
423 movl _ScreenPrimary,%%eax
424 call dosmemsetup
425 movl %%eax,%%ebx
426 movl %1,%%ecx
427 movb %0,%%al
428 incl %%ebx
429 visible_bell_1:
430 xorb %%al,%%gs:(%%ebx)
431 addl $2,%%ebx
432 decl %%ecx
433 jne visible_bell_1
434 decb %%dl
435 jne visible_bell_3
436 visible_bell_2:
437 movzwl %%ax,%%eax
438 movzwl %%ax,%%eax
439 movzwl %%ax,%%eax
440 movzwl %%ax,%%eax
441 decw %%cx
442 jne visible_bell_2
443 jmp visible_bell_0
444 visible_bell_3:"
445 : /* no output */
446 : "m" (xorattr), "g" (screen_size)
447 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
450 static void
451 ScreenVisualBell (void)
453 /* This creates an xor-mask that will swap the default fore- and
454 background colors. */
455 do_visible_bell (((the_only_x_display.foreground_pixel
456 ^ the_only_x_display.background_pixel)
457 * 0x11) & 0x7f);
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 Lisp_Object video_mode;
518 int video_mode_value;
519 int have_vga = 0;
520 union REGS regs;
521 int current_rows = ScreenRows (), current_cols = ScreenCols ();
523 if (*rows == current_rows && *cols == current_cols)
524 return;
526 mouse_off ();
527 have_vga = vga_installed ();
529 /* If the user specified a special video mode for these dimensions,
530 use that mode. */
531 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
532 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
533 Qnil))-> value;
535 if (INTEGERP (video_mode)
536 && (video_mode_value = XINT (video_mode)) > 0)
538 regs.x.ax = video_mode_value;
539 int86 (0x10, &regs, &regs);
541 if (have_mouse)
543 /* Must hardware-reset the mouse, or else it won't update
544 its notion of screen dimensions for some non-standard
545 video modes. This is *painfully* slow... */
546 regs.x.ax = 0;
547 int86 (0x33, &regs, &regs);
551 /* Find one of the dimensions supported by standard EGA/VGA
552 which gives us at least the required dimensions. */
554 #if __DJGPP__ > 1
556 else
558 static struct {
559 int rows;
560 int need_vga;
561 } std_dimension[] = {
562 {25, 0},
563 {28, 1},
564 {35, 0},
565 {40, 1},
566 {43, 0},
567 {50, 1}
569 int i = 0;
571 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
573 if (std_dimension[i].need_vga <= have_vga
574 && std_dimension[i].rows >= *rows)
576 if (std_dimension[i].rows != current_rows
577 || *cols != current_cols)
578 _set_screen_lines (std_dimension[i].rows);
579 break;
581 i++;
585 #else /* not __DJGPP__ > 1 */
587 else if (*rows <= 25)
589 if (current_rows != 25 || current_cols != 80)
591 regs.x.ax = 3;
592 int86 (0x10, &regs, &regs);
593 regs.x.ax = 0x1101;
594 regs.h.bl = 0;
595 int86 (0x10, &regs, &regs);
596 regs.x.ax = 0x1200;
597 regs.h.bl = 32;
598 int86 (0x10, &regs, &regs);
599 regs.x.ax = 3;
600 int86 (0x10, &regs, &regs);
603 else if (*rows <= 50)
604 if (have_vga && (current_rows != 50 || current_cols != 80)
605 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
607 regs.x.ax = 3;
608 int86 (0x10, &regs, &regs);
609 regs.x.ax = 0x1112;
610 regs.h.bl = 0;
611 int86 (0x10, &regs, &regs);
612 regs.x.ax = 0x1200;
613 regs.h.bl = 32;
614 int86 (0x10, &regs, &regs);
615 regs.x.ax = 0x0100;
616 regs.x.cx = 7;
617 int86 (0x10, &regs, &regs);
619 #endif /* not __DJGPP__ > 1 */
621 if (have_mouse)
623 mouse_init ();
624 mouse_on ();
627 /* Tell the caller what dimensions have been REALLY set. */
628 *rows = ScreenRows ();
629 *cols = ScreenCols ();
631 #if __DJGPP__ > 1
632 /* If the dimensions changed, the mouse highlight info is invalid. */
633 if (current_rows != *rows || current_cols != *cols)
635 struct frame *f = SELECTED_FRAME();
636 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
637 Lisp_Object window = dpyinfo->mouse_face_window;
639 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
641 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
642 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
643 dpyinfo->mouse_face_window = Qnil;
646 #endif
648 /* Enable bright background colors. */
649 bright_bg ();
651 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
652 be defensive anyway. */
653 if (screen_virtual_segment)
654 dosv_refresh_virtual_screen (0, *cols * *rows);
657 /* If we write a character in the position where the mouse is,
658 the mouse cursor may need to be refreshed. */
660 static void
661 mouse_off_maybe ()
663 int x, y;
665 if (!mouse_visible)
666 return;
668 mouse_get_xy (&x, &y);
669 if (y != new_pos_Y || x < new_pos_X)
670 return;
672 mouse_off ();
675 #define DEFAULT_CURSOR_START (-1)
676 #define DEFAULT_CURSOR_WIDTH (-1)
677 #define BOX_CURSOR_WIDTH (-32)
679 /* Set cursor to begin at scan line START_LINE in the character cell
680 and extend for WIDTH scan lines. Scan lines are counted from top
681 of the character cell, starting from zero. */
682 static void
683 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
685 #if __DJGPP__ > 1
686 unsigned desired_cursor;
687 __dpmi_regs regs;
688 int max_line, top_line, bot_line;
690 /* Avoid the costly BIOS call if F isn't the currently selected
691 frame. Allow for NULL as unconditionally meaning the selected
692 frame. */
693 if (f && f != SELECTED_FRAME())
694 return;
696 /* The character cell size in scan lines is stored at 40:85 in the
697 BIOS data area. */
698 max_line = _farpeekw (_dos_ds, 0x485) - 1;
699 switch (max_line)
701 default: /* this relies on CGA cursor emulation being ON! */
702 case 7:
703 bot_line = 7;
704 break;
705 case 9:
706 bot_line = 9;
707 break;
708 case 13:
709 bot_line = 12;
710 break;
711 case 15:
712 bot_line = 14;
713 break;
716 if (width < 0)
718 if (width == BOX_CURSOR_WIDTH)
720 top_line = 0;
721 bot_line = max_line;
723 else if (start_line != DEFAULT_CURSOR_START)
725 top_line = start_line;
726 bot_line = top_line - width - 1;
728 else if (width != DEFAULT_CURSOR_WIDTH)
730 top_line = 0;
731 bot_line = -1 - width;
733 else
734 top_line = bot_line + 1;
736 else if (width == 0)
738 /* [31, 0] seems to DTRT for all screen sizes. */
739 top_line = 31;
740 bot_line = 0;
742 else /* WIDTH is positive */
744 if (start_line != DEFAULT_CURSOR_START)
745 bot_line = start_line;
746 top_line = bot_line - (width - 1);
749 /* If the current cursor shape is already what they want, we are
750 history here. */
751 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
752 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
753 return;
755 regs.h.ah = 1;
756 regs.x.cx = desired_cursor;
757 __dpmi_int (0x10, &regs);
758 #endif /* __DJGPP__ > 1 */
761 static void
762 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
764 if (EQ (cursor_type, Qbar))
766 /* Just BAR means the normal EGA/VGA cursor. */
767 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
769 else if (CONSP (cursor_type) && EQ (XCAR (cursor_type), Qbar))
771 Lisp_Object bar_parms = XCDR (cursor_type);
772 int width;
774 if (INTEGERP (bar_parms))
776 /* Feature: negative WIDTH means cursor at the top
777 of the character cell, zero means invisible cursor. */
778 width = XINT (bar_parms);
779 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
780 width);
782 else if (CONSP (bar_parms)
783 && INTEGERP (XCAR (bar_parms))
784 && INTEGERP (XCDR (bar_parms)))
786 int start_line = XINT (XCDR (bar_parms));
788 width = XINT (XCAR (bar_parms));
789 msdos_set_cursor_shape (f, start_line, width);
792 else
793 /* Treat anything unknown as "box cursor". This includes nil, so
794 that a frame which doesn't specify a cursor type gets a box,
795 which is the default in Emacs. */
796 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
799 static void
800 IT_ring_bell (void)
802 if (visible_bell)
804 mouse_off ();
805 ScreenVisualBell ();
807 else
809 union REGS inregs, outregs;
810 inregs.h.ah = 2;
811 inregs.h.dl = 7;
812 intdos (&inregs, &outregs);
816 /* Given a face id FACE, extract the face parameters to be used for
817 display until the face changes. The face parameters (actually, its
818 color) are used to construct the video attribute byte for each
819 glyph during the construction of the buffer that is then blitted to
820 the video RAM. */
821 static void
822 IT_set_face (int face)
824 struct frame *sf = SELECTED_FRAME();
825 struct face *fp = FACE_FROM_ID (sf, face);
826 unsigned long fg, bg;
828 if (!fp)
830 fp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
831 /* The default face for the frame should always be realized and
832 cached. */
833 if (!fp)
834 abort ();
836 screen_face = face;
837 fg = fp->foreground;
838 bg = fp->background;
840 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
841 colors mean use the colors of the default face, except that if
842 highlight is on, invert the foreground and the background. Note
843 that we assume all 16 colors to be available for the background,
844 since Emacs switches on this mode (and loses the blinking
845 attribute) at startup. */
846 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
847 fg = FRAME_FOREGROUND_PIXEL (sf);
848 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
849 fg = FRAME_BACKGROUND_PIXEL (sf);
850 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
851 bg = FRAME_BACKGROUND_PIXEL (sf);
852 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
853 bg = FRAME_FOREGROUND_PIXEL (sf);
855 /* Make sure highlighted lines really stand out, come what may. */
856 if ((highlight || fp->tty_reverse_p)
857 && (fg == FRAME_FOREGROUND_PIXEL (sf)
858 && bg == FRAME_BACKGROUND_PIXEL (sf)))
860 unsigned long tem = fg;
862 fg = bg;
863 bg = tem;
865 if (termscript)
866 fprintf (termscript, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face,
867 highlight ? "H" : "", fp->foreground, fp->background, fg, bg);
868 if (fg >= 0 && fg < 16)
870 ScreenAttrib &= 0xf0;
871 ScreenAttrib |= fg;
873 if (bg >= 0 && bg < 16)
875 ScreenAttrib &= 0x0f;
876 ScreenAttrib |= ((bg & 0x0f) << 4);
880 Lisp_Object Vdos_unsupported_char_glyph;
882 static void
883 IT_write_glyphs (struct glyph *str, int str_len)
885 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
886 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
887 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
888 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
889 register int sl = str_len;
890 register int tlen = GLYPH_TABLE_LENGTH;
891 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
893 /* If terminal_coding does any conversion, use it, otherwise use
894 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
895 because it always returns 1 if terminal_coding.src_multibyte is 1. */
896 struct coding_system *coding =
897 (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
898 ? &terminal_coding
899 : &safe_terminal_coding);
900 struct frame *sf;
902 /* Do we need to consider conversion of unibyte characters to
903 multibyte? */
904 int convert_unibyte_characters
905 = (NILP (current_buffer->enable_multibyte_characters)
906 && unibyte_display_via_language_environment);
908 if (str_len <= 0) return;
910 screen_buf = screen_bp = alloca (str_len * 2);
911 screen_buf_end = screen_buf + str_len * 2;
912 sf = SELECTED_FRAME();
914 /* Since faces get cached and uncached behind our back, we can't
915 rely on their indices in the cache being consistent across
916 invocations. So always reset the screen face to the default
917 face of the frame, before writing glyphs, and let the glyphs
918 set the right face if it's different from the default. */
919 IT_set_face (DEFAULT_FACE_ID);
921 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
922 the tail. */
923 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
924 while (sl)
926 int cf, chlen, enclen;
927 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
928 unsigned ch;
930 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
931 only for the redisplay code to know how many columns does
932 this character occupy on the screen. Skip padding glyphs. */
933 if (CHAR_GLYPH_PADDING_P (*str))
935 str++;
936 sl--;
938 else
940 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
941 int glyph_not_in_table = 0;
943 if (g < 0 || g >= tlen)
945 /* This glyph doesn't have an entry in Vglyph_table. */
946 ch = str->u.ch;
947 glyph_not_in_table = 1;
949 else
951 /* This glyph has an entry in Vglyph_table, so process
952 any aliases before testing for simpleness. */
953 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
954 ch = FAST_GLYPH_CHAR (g);
957 /* Convert the character code to multibyte, if they
958 requested display via language environment. We only want
959 to convert unibyte characters to multibyte in unibyte
960 buffers! Otherwise, the 8-bit value in CH came from the
961 display table set up to display foreign characters. */
962 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
963 && (ch >= 0240
964 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
965 ch = unibyte_char_to_multibyte (ch);
967 /* Invalid characters are displayed with a special glyph. */
968 if (! CHAR_VALID_P (ch, 0))
970 g = !NILP (Vdos_unsupported_char_glyph)
971 ? Vdos_unsupported_char_glyph
972 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
973 ch = FAST_GLYPH_CHAR (g);
976 /* If the face of this glyph is different from the current
977 screen face, update the screen attribute byte. */
978 cf = FAST_GLYPH_FACE (g);
979 if (cf != screen_face)
980 IT_set_face (cf); /* handles invalid faces gracefully */
982 if (glyph_not_in_table || GLYPH_SIMPLE_P (tbase, tlen, g))
984 /* We generate the multi-byte form of CH in WORKBUF. */
985 chlen = CHAR_STRING (ch, workbuf);
986 buf = workbuf;
988 else
990 /* We have a string in Vglyph_table. */
991 chlen = GLYPH_LENGTH (tbase, g);
992 buf = GLYPH_STRING (tbase, g);
995 /* If the character is not multibyte, don't bother converting it. */
996 if (chlen == 1)
998 *conversion_buffer = (unsigned char)ch;
999 chlen = 0;
1000 enclen = 1;
1002 else
1004 coding->src_multibyte = 1;
1005 encode_coding (coding, buf, conversion_buffer, chlen,
1006 conversion_buffer_size);
1007 chlen -= coding->consumed;
1008 enclen = coding->produced;
1010 /* Replace glyph codes that cannot be converted by
1011 terminal_coding with Vdos_unsupported_char_glyph. */
1012 if (*conversion_buffer == '?')
1014 char *cbp = conversion_buffer;
1016 while (cbp < conversion_buffer + enclen && *cbp == '?')
1017 *cbp++ = unsupported_char;
1018 if (unsupported_face != screen_face)
1019 IT_set_face (unsupported_face);
1023 if (enclen + chlen > screen_buf_end - screen_bp)
1025 /* The allocated buffer for screen writes is too small.
1026 Flush it and loop again without incrementing STR, so
1027 that the next loop will begin with the same glyph. */
1028 int nbytes = screen_bp - screen_buf;
1030 mouse_off_maybe ();
1031 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1032 if (screen_virtual_segment)
1033 dosv_refresh_virtual_screen (offset, nbytes / 2);
1034 new_pos_X += nbytes / 2;
1035 offset += nbytes;
1037 /* Prepare to reuse the same buffer again. */
1038 screen_bp = screen_buf;
1040 else
1042 /* There's enough place in the allocated buffer to add
1043 the encoding of this glyph. */
1045 /* First, copy the encoded bytes. */
1046 for (bp = conversion_buffer; enclen--; bp++)
1048 *screen_bp++ = (unsigned char)*bp;
1049 *screen_bp++ = ScreenAttrib;
1050 if (termscript)
1051 fputc (*bp, termscript);
1054 /* Now copy the bytes not consumed by the encoding. */
1055 if (chlen > 0)
1057 buf += coding->consumed;
1058 while (chlen--)
1060 if (termscript)
1061 fputc (*buf, termscript);
1062 *screen_bp++ = (unsigned char)*buf++;
1063 *screen_bp++ = ScreenAttrib;
1067 /* Update STR and its remaining length. */
1068 str++;
1069 sl--;
1074 /* Dump whatever is left in the screen buffer. */
1075 mouse_off_maybe ();
1076 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1077 if (screen_virtual_segment)
1078 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1079 new_pos_X += (screen_bp - screen_buf) / 2;
1081 /* We may have to output some codes to terminate the writing. */
1082 if (CODING_REQUIRE_FLUSHING (coding))
1084 coding->mode |= CODING_MODE_LAST_BLOCK;
1085 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
1086 if (coding->produced > 0)
1088 screen_buf = alloca (coding->produced * 2);
1089 for (screen_bp = screen_buf, bp = conversion_buffer;
1090 coding->produced--; bp++)
1092 *screen_bp++ = (unsigned char)*bp;
1093 *screen_bp++ = ScreenAttrib;
1094 if (termscript)
1095 fputc (*bp, termscript);
1097 offset += screen_bp - screen_buf;
1098 mouse_off_maybe ();
1099 dosmemput (screen_buf, screen_bp - screen_buf,
1100 (int)ScreenPrimary + offset);
1101 if (screen_virtual_segment)
1102 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1103 new_pos_X += (screen_bp - screen_buf) / 2;
1108 /************************************************************************
1109 Mouse Highlight (and friends..)
1110 ************************************************************************/
1112 /* This is used for debugging, to turn off note_mouse_highlight. */
1113 int disable_mouse_highlight;
1115 /* If non-nil, dos_rawgetc generates an event to display that string.
1116 (The display is done in keyboard.c:read_char, by calling
1117 show_help_echo.) */
1118 static Lisp_Object help_echo;
1119 static Lisp_Object previous_help_echo; /* a helper temporary variable */
1121 /* These record the window, the object and the position where the help
1122 echo string was generated. */
1123 static Lisp_Object help_echo_window;
1124 static Lisp_Object help_echo_object;
1125 static int help_echo_pos;
1127 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1129 /* Set the mouse pointer shape according to whether it is in the
1130 area where the mouse highlight is in effect. */
1131 static void
1132 IT_set_mouse_pointer (int mode)
1134 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1135 many possibilities to change its shape, and the available
1136 functionality pretty much sucks (e.g., almost every reasonable
1137 shape will conceal the character it is on). Since the color of
1138 the pointer changes in the highlighted area, it is not clear to
1139 me whether anything else is required, anyway. */
1142 /* Display the active region described by mouse_face_*
1143 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1144 static void
1145 show_mouse_face (struct display_info *dpyinfo, int hl)
1147 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1148 struct frame *f = XFRAME (WINDOW_FRAME (w));
1149 int i;
1150 struct face *fp;
1153 /* If window is in the process of being destroyed, don't bother
1154 doing anything. */
1155 if (w->current_matrix == NULL)
1156 goto set_cursor_shape;
1158 /* Recognize when we are called to operate on rows that don't exist
1159 anymore. This can happen when a window is split. */
1160 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1161 goto set_cursor_shape;
1163 /* There's no sense to do anything if the mouse face isn't realized. */
1164 if (hl > 0)
1166 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1167 if (!fp)
1168 goto set_cursor_shape;
1171 /* Note that mouse_face_beg_row etc. are window relative. */
1172 for (i = dpyinfo->mouse_face_beg_row;
1173 i <= dpyinfo->mouse_face_end_row;
1174 i++)
1176 int start_hpos, end_hpos;
1177 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1179 /* Don't do anything if row doesn't have valid contents. */
1180 if (!row->enabled_p)
1181 continue;
1183 /* For all but the first row, the highlight starts at column 0. */
1184 if (i == dpyinfo->mouse_face_beg_row)
1185 start_hpos = dpyinfo->mouse_face_beg_col;
1186 else
1187 start_hpos = 0;
1189 if (i == dpyinfo->mouse_face_end_row)
1190 end_hpos = dpyinfo->mouse_face_end_col;
1191 else
1192 end_hpos = row->used[TEXT_AREA];
1194 if (end_hpos <= start_hpos)
1195 continue;
1196 /* Record that some glyphs of this row are displayed in
1197 mouse-face. */
1198 row->mouse_face_p = hl > 0;
1199 if (hl > 0)
1201 int vpos = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1202 int kstart = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1203 int nglyphs = end_hpos - start_hpos;
1204 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1205 int start_offset = offset;
1207 if (termscript)
1208 fprintf (termscript, "\n<MH+ %d-%d:%d>",
1209 kstart, kstart + nglyphs - 1, vpos);
1211 mouse_off ();
1212 IT_set_face (dpyinfo->mouse_face_face_id);
1213 /* Since we are going to change only the _colors_ of the
1214 displayed text, there's no need to go through all the
1215 pain of generating and encoding the text from the glyphs.
1216 Instead, we simply poke the attribute byte of each
1217 affected position in video memory with the colors
1218 computed by IT_set_face! */
1219 _farsetsel (_dos_ds);
1220 while (nglyphs--)
1222 _farnspokeb (offset, ScreenAttrib);
1223 offset += 2;
1225 if (screen_virtual_segment)
1226 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1227 mouse_on ();
1229 else
1231 /* We are removing a previously-drawn mouse highlight. The
1232 safest way to do so is to redraw the glyphs anew, since
1233 all kinds of faces and display tables could have changed
1234 behind our back. */
1235 int nglyphs = end_hpos - start_hpos;
1236 int save_x = new_pos_X, save_y = new_pos_Y;
1238 if (end_hpos >= row->used[TEXT_AREA])
1239 nglyphs = row->used[TEXT_AREA] - start_hpos;
1241 /* IT_write_glyphs writes at cursor position, so we need to
1242 temporarily move cursor coordinates to the beginning of
1243 the highlight region. */
1244 new_pos_X = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1245 new_pos_Y = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1247 if (termscript)
1248 fprintf (termscript, "<MH- %d-%d:%d>",
1249 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1250 IT_write_glyphs (row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1251 if (termscript)
1252 fputs ("\n", termscript);
1253 new_pos_X = save_x;
1254 new_pos_Y = save_y;
1258 set_cursor_shape:
1260 /* Change the mouse pointer shape. */
1261 IT_set_mouse_pointer (hl);
1264 /* Clear out the mouse-highlighted active region.
1265 Redraw it un-highlighted first. */
1266 static void
1267 clear_mouse_face (struct display_info *dpyinfo)
1269 if (! NILP (dpyinfo->mouse_face_window))
1270 show_mouse_face (dpyinfo, 0);
1272 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1273 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1274 dpyinfo->mouse_face_window = Qnil;
1277 /* Find the glyph matrix position of buffer position POS in window W.
1278 *HPOS and *VPOS are set to the positions found. W's current glyphs
1279 must be up to date. If POS is above window start return (0, 0).
1280 If POS is after end of W, return end of last line in W. */
1281 static int
1282 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1284 int i;
1285 int lastcol;
1286 int maybe_next_line_p = 0;
1287 int line_start_position;
1288 int yb = window_text_bottom_y (w);
1289 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
1290 struct glyph_row *best_row = row;
1292 while (row->y < yb)
1294 if (row->used[TEXT_AREA])
1295 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1296 else
1297 line_start_position = 0;
1299 if (line_start_position > pos)
1300 break;
1301 /* If the position sought is the end of the buffer,
1302 don't include the blank lines at the bottom of the window. */
1303 else if (line_start_position == pos
1304 && pos == BUF_ZV (XBUFFER (w->buffer)))
1306 maybe_next_line_p = 1;
1307 break;
1309 else if (line_start_position > 0)
1310 best_row = row;
1312 ++row;
1315 /* Find the right column within BEST_ROW. */
1316 lastcol = 0;
1317 row = best_row;
1318 for (i = 0; i < row->used[TEXT_AREA]; i++)
1320 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1321 int charpos;
1323 charpos = glyph->charpos;
1324 if (charpos == pos)
1326 *hpos = i;
1327 *vpos = row->y;
1328 return 1;
1330 else if (charpos > pos)
1331 break;
1332 else if (charpos > 0)
1333 lastcol = i;
1336 /* If we're looking for the end of the buffer,
1337 and we didn't find it in the line we scanned,
1338 use the start of the following line. */
1339 if (maybe_next_line_p)
1341 ++row;
1342 lastcol = 0;
1345 *vpos = row->y;
1346 *hpos = lastcol + 1;
1347 return 0;
1350 /* Take proper action when mouse has moved to the mode or top line of
1351 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1352 mode line. X is relative to the start of the text display area of
1353 W, so the width of bitmap areas and scroll bars must be subtracted
1354 to get a position relative to the start of the mode line. */
1355 static void
1356 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1358 struct frame *f = XFRAME (w->frame);
1359 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1360 struct glyph_row *row;
1362 if (mode_line_p)
1363 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1364 else
1365 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1367 if (row->enabled_p)
1369 extern Lisp_Object Qhelp_echo;
1370 struct glyph *glyph, *end;
1371 Lisp_Object help, map;
1373 /* Find the glyph under X. */
1374 glyph = row->glyphs[TEXT_AREA]
1375 + x - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
1376 end = glyph + row->used[TEXT_AREA];
1377 if (glyph < end
1378 && STRINGP (glyph->object)
1379 && XSTRING (glyph->object)->intervals
1380 && glyph->charpos >= 0
1381 && glyph->charpos < XSTRING (glyph->object)->size)
1383 /* If we're on a string with `help-echo' text property,
1384 arrange for the help to be displayed. This is done by
1385 setting the global variable help_echo to the help string. */
1386 help = Fget_text_property (make_number (glyph->charpos),
1387 Qhelp_echo, glyph->object);
1388 if (!NILP (help))
1390 help_echo = help;
1391 XSETWINDOW (help_echo_window, w);
1392 help_echo_object = glyph->object;
1393 help_echo_pos = glyph->charpos;
1399 /* Take proper action when the mouse has moved to position X, Y on
1400 frame F as regards highlighting characters that have mouse-face
1401 properties. Also de-highlighting chars where the mouse was before.
1402 X and Y can be negative or out of range. */
1403 static void
1404 IT_note_mouse_highlight (struct frame *f, int x, int y)
1406 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1407 int portion;
1408 Lisp_Object window;
1409 struct window *w;
1411 /* When a menu is active, don't highlight because this looks odd. */
1412 if (mouse_preempted)
1413 return;
1415 if (disable_mouse_highlight
1416 || !f->glyphs_initialized_p)
1417 return;
1419 dpyinfo->mouse_face_mouse_x = x;
1420 dpyinfo->mouse_face_mouse_y = y;
1421 dpyinfo->mouse_face_mouse_frame = f;
1423 if (dpyinfo->mouse_face_defer)
1424 return;
1426 if (gc_in_progress)
1428 dpyinfo->mouse_face_deferred_gc = 1;
1429 return;
1432 /* Which window is that in? */
1433 window = window_from_coordinates (f, x, y, &portion, 0);
1435 /* If we were displaying active text in another window, clear that. */
1436 if (! EQ (window, dpyinfo->mouse_face_window))
1437 clear_mouse_face (dpyinfo);
1439 /* Not on a window -> return. */
1440 if (!WINDOWP (window))
1441 return;
1443 /* Convert to window-relative coordinates. */
1444 w = XWINDOW (window);
1445 x -= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1446 y -= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1448 if (portion == 1 || portion == 3)
1450 /* Mouse is on the mode or top line. */
1451 IT_note_mode_line_highlight (w, x, portion == 1);
1452 return;
1454 else
1455 IT_set_mouse_pointer (0);
1457 /* Are we in a window whose display is up to date?
1458 And verify the buffer's text has not changed. */
1459 if (/* Within text portion of the window. */
1460 portion == 0
1461 && EQ (w->window_end_valid, w->buffer)
1462 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1463 && (XFASTINT (w->last_overlay_modified)
1464 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1466 int pos, i, area;
1467 struct glyph_row *row;
1468 struct glyph *glyph;
1470 /* Find the glyph under X/Y. */
1471 glyph = NULL;
1472 if (y < w->current_matrix->nrows)
1474 row = MATRIX_ROW (w->current_matrix, y);
1475 if (row->enabled_p
1476 && row->displays_text_p
1477 && x < window_box_width (w, TEXT_AREA))
1479 glyph = row->glyphs[TEXT_AREA];
1480 if (x >= row->used[TEXT_AREA])
1481 glyph = NULL;
1482 else
1484 glyph += x;
1485 if (!BUFFERP (glyph->object))
1486 glyph = NULL;
1491 /* Clear mouse face if X/Y not over text. */
1492 if (glyph == NULL)
1494 clear_mouse_face (dpyinfo);
1495 return;
1498 if (!BUFFERP (glyph->object))
1499 abort ();
1500 pos = glyph->charpos;
1502 /* Check for mouse-face and help-echo. */
1504 extern Lisp_Object Qmouse_face;
1505 Lisp_Object mouse_face, overlay, position;
1506 Lisp_Object *overlay_vec;
1507 int len, noverlays;
1508 struct buffer *obuf;
1509 int obegv, ozv;
1511 /* If we get an out-of-range value, return now; avoid an error. */
1512 if (pos > BUF_Z (XBUFFER (w->buffer)))
1513 return;
1515 /* Make the window's buffer temporarily current for
1516 overlays_at and compute_char_face. */
1517 obuf = current_buffer;
1518 current_buffer = XBUFFER (w->buffer);
1519 obegv = BEGV;
1520 ozv = ZV;
1521 BEGV = BEG;
1522 ZV = Z;
1524 /* Is this char mouse-active or does it have help-echo? */
1525 XSETINT (position, pos);
1527 /* Put all the overlays we want in a vector in overlay_vec.
1528 Store the length in len. If there are more than 10, make
1529 enough space for all, and try again. */
1530 len = 10;
1531 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1532 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1533 if (noverlays > len)
1535 len = noverlays;
1536 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1537 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1540 noverlays = sort_overlays (overlay_vec, noverlays, w);
1542 /* Check mouse-face highlighting. */
1543 if (! (EQ (window, dpyinfo->mouse_face_window)
1544 && y >= dpyinfo->mouse_face_beg_row
1545 && y <= dpyinfo->mouse_face_end_row
1546 && (y > dpyinfo->mouse_face_beg_row
1547 || x >= dpyinfo->mouse_face_beg_col)
1548 && (y < dpyinfo->mouse_face_end_row
1549 || x < dpyinfo->mouse_face_end_col
1550 || dpyinfo->mouse_face_past_end)))
1552 /* Clear the display of the old active region, if any. */
1553 clear_mouse_face (dpyinfo);
1555 /* Find highest priority overlay that has a mouse-face prop. */
1556 overlay = Qnil;
1557 for (i = 0; i < noverlays; i++)
1559 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1560 if (!NILP (mouse_face))
1562 overlay = overlay_vec[i];
1563 break;
1567 /* If no overlay applies, get a text property. */
1568 if (NILP (overlay))
1569 mouse_face = Fget_text_property (position, Qmouse_face,
1570 w->buffer);
1572 /* Handle the overlay case. */
1573 if (! NILP (overlay))
1575 /* Find the range of text around this char that
1576 should be active. */
1577 Lisp_Object before, after;
1578 int ignore;
1580 before = Foverlay_start (overlay);
1581 after = Foverlay_end (overlay);
1582 /* Record this as the current active region. */
1583 fast_find_position (w, XFASTINT (before),
1584 &dpyinfo->mouse_face_beg_col,
1585 &dpyinfo->mouse_face_beg_row);
1586 dpyinfo->mouse_face_past_end
1587 = !fast_find_position (w, XFASTINT (after),
1588 &dpyinfo->mouse_face_end_col,
1589 &dpyinfo->mouse_face_end_row);
1590 dpyinfo->mouse_face_window = window;
1591 dpyinfo->mouse_face_face_id
1592 = face_at_buffer_position (w, pos, 0, 0,
1593 &ignore, pos + 1, 1);
1595 /* Display it as active. */
1596 show_mouse_face (dpyinfo, 1);
1598 /* Handle the text property case. */
1599 else if (! NILP (mouse_face))
1601 /* Find the range of text around this char that
1602 should be active. */
1603 Lisp_Object before, after, beginning, end;
1604 int ignore;
1606 beginning = Fmarker_position (w->start);
1607 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1608 - XFASTINT (w->window_end_pos)));
1609 before
1610 = Fprevious_single_property_change (make_number (pos + 1),
1611 Qmouse_face,
1612 w->buffer, beginning);
1613 after
1614 = Fnext_single_property_change (position, Qmouse_face,
1615 w->buffer, end);
1616 /* Record this as the current active region. */
1617 fast_find_position (w, XFASTINT (before),
1618 &dpyinfo->mouse_face_beg_col,
1619 &dpyinfo->mouse_face_beg_row);
1620 dpyinfo->mouse_face_past_end
1621 = !fast_find_position (w, XFASTINT (after),
1622 &dpyinfo->mouse_face_end_col,
1623 &dpyinfo->mouse_face_end_row);
1624 dpyinfo->mouse_face_window = window;
1625 dpyinfo->mouse_face_face_id
1626 = face_at_buffer_position (w, pos, 0, 0,
1627 &ignore, pos + 1, 1);
1629 /* Display it as active. */
1630 show_mouse_face (dpyinfo, 1);
1634 /* Look for a `help-echo' property. */
1636 Lisp_Object help;
1637 extern Lisp_Object Qhelp_echo;
1639 /* Check overlays first. */
1640 help = Qnil;
1641 for (i = 0; i < noverlays && NILP (help); ++i)
1642 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
1644 if (!NILP (help))
1646 help_echo = help;
1647 help_echo_window = window;
1648 help_echo_object = w->buffer;
1649 help_echo_pos = pos;
1651 /* Try text properties. */
1652 else if (NILP (help)
1653 && ((STRINGP (glyph->object)
1654 && glyph->charpos >= 0
1655 && glyph->charpos < XSTRING (glyph->object)->size)
1656 || (BUFFERP (glyph->object)
1657 && glyph->charpos >= BEGV
1658 && glyph->charpos < ZV)))
1660 help = Fget_text_property (make_number (glyph->charpos),
1661 Qhelp_echo, glyph->object);
1662 if (!NILP (help))
1664 help_echo = help;
1665 help_echo_window = window;
1666 help_echo_object = glyph->object;
1667 help_echo_pos = glyph->charpos;
1672 BEGV = obegv;
1673 ZV = ozv;
1674 current_buffer = obuf;
1679 static void
1680 IT_clear_end_of_line (int first_unused)
1682 char *spaces, *sp;
1683 int i, j;
1684 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1685 extern int fatal_error_in_progress;
1687 if (new_pos_X >= first_unused || fatal_error_in_progress)
1688 return;
1690 IT_set_face (0);
1691 i = (j = first_unused - new_pos_X) * 2;
1692 if (termscript)
1693 fprintf (termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1694 spaces = sp = alloca (i);
1696 while (--j >= 0)
1698 *sp++ = ' ';
1699 *sp++ = ScreenAttrib;
1702 mouse_off_maybe ();
1703 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1704 if (screen_virtual_segment)
1705 dosv_refresh_virtual_screen (offset, i / 2);
1707 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1708 Let's follow their lead, in case someone relies on this. */
1709 new_pos_X = first_unused;
1712 static void
1713 IT_clear_screen (void)
1715 if (termscript)
1716 fprintf (termscript, "<CLR:SCR>");
1717 IT_set_face (0);
1718 mouse_off ();
1719 ScreenClear ();
1720 if (screen_virtual_segment)
1721 dosv_refresh_virtual_screen (0, screen_size);
1722 new_pos_X = new_pos_Y = 0;
1725 static void
1726 IT_clear_to_end (void)
1728 if (termscript)
1729 fprintf (termscript, "<CLR:EOS>");
1731 while (new_pos_Y < screen_size_Y) {
1732 new_pos_X = 0;
1733 IT_clear_end_of_line (screen_size_X);
1734 new_pos_Y++;
1738 static void
1739 IT_cursor_to (int y, int x)
1741 if (termscript)
1742 fprintf (termscript, "\n<XY=%dx%d>", x, y);
1743 new_pos_X = x;
1744 new_pos_Y = y;
1747 static int cursor_cleared;
1749 static void
1750 IT_display_cursor (int on)
1752 if (on && cursor_cleared)
1754 ScreenSetCursor (current_pos_Y, current_pos_X);
1755 cursor_cleared = 0;
1757 else if (!on && !cursor_cleared)
1759 ScreenSetCursor (-1, -1);
1760 cursor_cleared = 1;
1764 /* Emacs calls cursor-movement functions a lot when it updates the
1765 display (probably a legacy of old terminals where you cannot
1766 update a screen line without first moving the cursor there).
1767 However, cursor movement is expensive on MSDOS (it calls a slow
1768 BIOS function and requires 2 mode switches), while actual screen
1769 updates access the video memory directly and don't depend on
1770 cursor position. To avoid slowing down the redisplay, we cheat:
1771 all functions that move the cursor only set internal variables
1772 which record the cursor position, whereas the cursor is only
1773 moved to its final position whenever screen update is complete.
1775 `IT_cmgoto' is called from the keyboard reading loop and when the
1776 frame update is complete. This means that we are ready for user
1777 input, so we update the cursor position to show where the point is,
1778 and also make the mouse pointer visible.
1780 Special treatment is required when the cursor is in the echo area,
1781 to put the cursor at the end of the text displayed there. */
1783 static void
1784 IT_cmgoto (FRAME_PTR f)
1786 /* Only set the cursor to where it should be if the display is
1787 already in sync with the window contents. */
1788 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1790 /* FIXME: This needs to be rewritten for the new redisplay, or
1791 removed. */
1792 #if 0
1793 static int previous_pos_X = -1;
1795 update_cursor_pos = 1; /* temporary!!! */
1797 /* If the display is in sync, forget any previous knowledge about
1798 cursor position. This is primarily for unexpected events like
1799 C-g in the minibuffer. */
1800 if (update_cursor_pos && previous_pos_X >= 0)
1801 previous_pos_X = -1;
1802 /* If we are in the echo area, put the cursor at the
1803 end of the echo area message. */
1804 if (!update_cursor_pos
1805 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1807 int tem_X = current_pos_X, dummy;
1809 if (echo_area_glyphs)
1811 tem_X = echo_area_glyphs_length;
1812 /* Save current cursor position, to be restored after the
1813 echo area message is erased. Only remember one level
1814 of previous cursor position. */
1815 if (previous_pos_X == -1)
1816 ScreenGetCursor (&dummy, &previous_pos_X);
1818 else if (previous_pos_X >= 0)
1820 /* We wind up here after the echo area message is erased.
1821 Restore the cursor position we remembered above. */
1822 tem_X = previous_pos_X;
1823 previous_pos_X = -1;
1826 if (current_pos_X != tem_X)
1828 new_pos_X = tem_X;
1829 update_cursor_pos = 1;
1832 #endif
1834 if (update_cursor_pos
1835 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1837 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1838 if (termscript)
1839 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1842 /* Maybe cursor is invisible, so make it visible. */
1843 IT_display_cursor (1);
1845 /* Mouse pointer should be always visible if we are waiting for
1846 keyboard input. */
1847 if (!mouse_visible)
1848 mouse_on ();
1851 static void
1852 IT_reassert_line_highlight (int new, int vpos)
1854 highlight = new;
1857 static void
1858 IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1860 highlight = new_highlight;
1861 IT_cursor_to (vpos, 0);
1862 IT_clear_end_of_line (first_unused_hpos);
1865 static void
1866 IT_update_begin (struct frame *f)
1868 struct display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1870 highlight = 0;
1872 BLOCK_INPUT;
1874 if (f == display_info->mouse_face_mouse_frame)
1876 /* Don't do highlighting for mouse motion during the update. */
1877 display_info->mouse_face_defer = 1;
1879 /* If F needs to be redrawn, simply forget about any prior mouse
1880 highlighting. */
1881 if (FRAME_GARBAGED_P (f))
1882 display_info->mouse_face_window = Qnil;
1884 /* Can we tell that this update does not affect the window
1885 where the mouse highlight is? If so, no need to turn off.
1886 Likewise, don't do anything if none of the enabled rows
1887 contains glyphs highlighted in mouse face. */
1888 if (!NILP (display_info->mouse_face_window)
1889 && WINDOWP (display_info->mouse_face_window))
1891 struct window *w = XWINDOW (display_info->mouse_face_window);
1892 int i;
1894 /* If the mouse highlight is in the window that was deleted
1895 (e.g., if it was popped by completion), clear highlight
1896 unconditionally. */
1897 if (NILP (w->buffer))
1898 display_info->mouse_face_window = Qnil;
1899 else
1901 for (i = 0; i < w->desired_matrix->nrows; ++i)
1902 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1903 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1904 break;
1907 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1908 clear_mouse_face (display_info);
1911 else if (!FRAME_LIVE_P (display_info->mouse_face_mouse_frame))
1913 /* If the frame with mouse highlight was deleted, invalidate the
1914 highlight info. */
1915 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1916 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1917 display_info->mouse_face_window = Qnil;
1918 display_info->mouse_face_deferred_gc = 0;
1919 display_info->mouse_face_mouse_frame = NULL;
1922 UNBLOCK_INPUT;
1925 static void
1926 IT_update_end (struct frame *f)
1928 highlight = 0;
1929 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
1932 Lisp_Object Qcursor_type;
1934 static void
1935 IT_frame_up_to_date (struct frame *f)
1937 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1938 Lisp_Object new_cursor, frame_desired_cursor;
1939 struct window *sw;
1941 if (dpyinfo->mouse_face_deferred_gc
1942 || f == dpyinfo->mouse_face_mouse_frame)
1944 BLOCK_INPUT;
1945 if (dpyinfo->mouse_face_mouse_frame)
1946 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1947 dpyinfo->mouse_face_mouse_x,
1948 dpyinfo->mouse_face_mouse_y);
1949 dpyinfo->mouse_face_deferred_gc = 0;
1950 UNBLOCK_INPUT;
1953 /* Set the cursor type to whatever they wanted. In a minibuffer
1954 window, we want the cursor to appear only if we are reading input
1955 from this window, and we want the cursor to be taken from the
1956 frame parameters. For the selected window, we use either its
1957 buffer-local value or the value from the frame parameters if the
1958 buffer doesn't define its local value for the cursor type. */
1959 sw = XWINDOW (f->selected_window);
1960 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1961 if (cursor_in_echo_area
1962 && FRAME_HAS_MINIBUF_P (f)
1963 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1964 && sw == XWINDOW (echo_area_window))
1965 new_cursor = frame_desired_cursor;
1966 else
1968 struct buffer *b = XBUFFER (sw->buffer);
1970 if (EQ (b->cursor_type, Qt))
1971 new_cursor = frame_desired_cursor;
1972 else if (NILP (b->cursor_type)) /* nil means no cursor */
1973 new_cursor = Fcons (Qbar, make_number (0));
1974 else
1975 new_cursor = b->cursor_type;
1978 IT_set_cursor_type (f, new_cursor);
1980 IT_cmgoto (f); /* position cursor when update is done */
1983 /* Copy LEN glyphs displayed on a single line whose vertical position
1984 is YPOS, beginning at horizontal position XFROM to horizontal
1985 position XTO, by moving blocks in the video memory. Used by
1986 functions that insert and delete glyphs. */
1987 static void
1988 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1990 /* The offsets of source and destination relative to the
1991 conventional memorty selector. */
1992 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1993 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1995 if (from == to || len <= 0)
1996 return;
1998 _farsetsel (_dos_ds);
2000 /* The source and destination might overlap, so we need to move
2001 glyphs non-destructively. */
2002 if (from > to)
2004 for ( ; len; from += 2, to += 2, len--)
2005 _farnspokew (to, _farnspeekw (from));
2007 else
2009 from += (len - 1) * 2;
2010 to += (len - 1) * 2;
2011 for ( ; len; from -= 2, to -= 2, len--)
2012 _farnspokew (to, _farnspeekw (from));
2014 if (screen_virtual_segment)
2015 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
2018 /* Insert and delete glyphs. */
2019 static void
2020 IT_insert_glyphs (start, len)
2021 register struct glyph *start;
2022 register int len;
2024 int shift_by_width = screen_size_X - (new_pos_X + len);
2026 /* Shift right the glyphs from the nominal cursor position to the
2027 end of this line. */
2028 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
2030 /* Now write the glyphs to be inserted. */
2031 IT_write_glyphs (start, len);
2034 static void
2035 IT_delete_glyphs (n)
2036 register int n;
2038 abort ();
2041 /* set-window-configuration on window.c needs this. */
2042 void
2043 x_set_menu_bar_lines (f, value, oldval)
2044 struct frame *f;
2045 Lisp_Object value, oldval;
2047 set_menu_bar_lines (f, value, oldval);
2050 /* This was copied from xfns.c */
2052 Lisp_Object Qbackground_color;
2053 Lisp_Object Qforeground_color;
2054 Lisp_Object Qreverse;
2055 extern Lisp_Object Qtitle;
2057 /* IT_set_terminal_modes is called when emacs is started,
2058 resumed, and whenever the screen is redrawn! */
2060 static void
2061 IT_set_terminal_modes (void)
2063 if (termscript)
2064 fprintf (termscript, "\n<SET_TERM>");
2065 highlight = 0;
2067 screen_size_X = ScreenCols ();
2068 screen_size_Y = ScreenRows ();
2069 screen_size = screen_size_X * screen_size_Y;
2071 new_pos_X = new_pos_Y = 0;
2072 current_pos_X = current_pos_Y = -1;
2074 if (term_setup_done)
2075 return;
2076 term_setup_done = 1;
2078 startup_screen_size_X = screen_size_X;
2079 startup_screen_size_Y = screen_size_Y;
2080 startup_screen_attrib = ScreenAttrib;
2082 #if __DJGPP__ > 1
2083 /* Is DOS/V (or any other RSIS software which relocates
2084 the screen) installed? */
2086 unsigned short es_value;
2087 __dpmi_regs regs;
2089 regs.h.ah = 0xfe; /* get relocated screen address */
2090 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2091 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2092 else if (screen_old_address) /* already switched to Japanese mode once */
2093 regs.x.es = (screen_old_address >> 4) & 0xffff;
2094 else
2095 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2096 regs.x.di = 0;
2097 es_value = regs.x.es;
2098 __dpmi_int (0x10, &regs);
2100 if (regs.x.es != es_value)
2102 /* screen_old_address is only set if ScreenPrimary does NOT
2103 already point to the relocated buffer address returned by
2104 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2105 ScreenPrimary to that address at startup under DOS/V. */
2106 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2107 screen_old_address = ScreenPrimary;
2108 screen_virtual_segment = regs.x.es;
2109 screen_virtual_offset = regs.x.di;
2110 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2113 #endif /* __DJGPP__ > 1 */
2115 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2116 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2118 if (termscript)
2119 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2120 screen_size_X, screen_size_Y);
2122 bright_bg ();
2125 /* IT_reset_terminal_modes is called when emacs is
2126 suspended or killed. */
2128 static void
2129 IT_reset_terminal_modes (void)
2131 int display_row_start = (int) ScreenPrimary;
2132 int saved_row_len = startup_screen_size_X * 2;
2133 int update_row_len = ScreenCols () * 2;
2134 int current_rows = ScreenRows ();
2135 int to_next_row = update_row_len;
2136 unsigned char *saved_row = startup_screen_buffer;
2137 int cursor_pos_X = ScreenCols () - 1;
2138 int cursor_pos_Y = ScreenRows () - 1;
2140 if (termscript)
2141 fprintf (termscript, "\n<RESET_TERM>");
2143 highlight = 0;
2145 if (!term_setup_done)
2146 return;
2148 mouse_off ();
2150 /* Leave the video system in the same state as we found it,
2151 as far as the blink/bright-background bit is concerned. */
2152 maybe_enable_blinking ();
2154 /* We have a situation here.
2155 We cannot just do ScreenUpdate(startup_screen_buffer) because
2156 the luser could have changed screen dimensions inside Emacs
2157 and failed (or didn't want) to restore them before killing
2158 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2159 thus will happily use memory outside what was allocated for
2160 `startup_screen_buffer'.
2161 Thus we only restore as much as the current screen dimensions
2162 can hold, and clear the rest (if the saved screen is smaller than
2163 the current) with the color attribute saved at startup. The cursor
2164 is also restored within the visible dimensions. */
2166 ScreenAttrib = startup_screen_attrib;
2168 /* Don't restore the screen if we are exiting less than 2 seconds
2169 after startup: we might be crashing, and the screen might show
2170 some vital clues to what's wrong. */
2171 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2173 ScreenClear ();
2174 if (screen_virtual_segment)
2175 dosv_refresh_virtual_screen (0, screen_size);
2177 if (update_row_len > saved_row_len)
2178 update_row_len = saved_row_len;
2179 if (current_rows > startup_screen_size_Y)
2180 current_rows = startup_screen_size_Y;
2182 if (termscript)
2183 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2184 update_row_len / 2, current_rows);
2186 while (current_rows--)
2188 dosmemput (saved_row, update_row_len, display_row_start);
2189 if (screen_virtual_segment)
2190 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2191 update_row_len / 2);
2192 saved_row += saved_row_len;
2193 display_row_start += to_next_row;
2196 if (startup_pos_X < cursor_pos_X)
2197 cursor_pos_X = startup_pos_X;
2198 if (startup_pos_Y < cursor_pos_Y)
2199 cursor_pos_Y = startup_pos_Y;
2201 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2202 xfree (startup_screen_buffer);
2204 term_setup_done = 0;
2207 static void
2208 IT_set_terminal_window (int foo)
2212 /* Remember the screen colors of the curent frame, to serve as the
2213 default colors for newly-created frames. */
2215 static int initial_screen_colors[2];
2217 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2218 Smsdos_remember_default_colors, 1, 1, 0,
2219 "Remember the screen colors of the current frame.")
2220 (frame)
2221 Lisp_Object frame;
2223 int reverse;
2224 struct frame *f;
2226 CHECK_FRAME (frame, 0);
2227 f= XFRAME (frame);
2228 reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
2230 initial_screen_colors[0]
2231 = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
2232 initial_screen_colors[1]
2233 = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
2236 void
2237 IT_set_frame_parameters (f, alist)
2238 struct frame *f;
2239 Lisp_Object alist;
2241 Lisp_Object tail;
2242 int length = XINT (Flength (alist));
2243 int i, j;
2244 Lisp_Object *parms
2245 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2246 Lisp_Object *values
2247 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2248 /* Do we have to reverse the foreground and background colors? */
2249 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2250 int was_reverse = reverse;
2251 int redraw = 0, fg_set = 0, bg_set = 0;
2252 unsigned long orig_fg;
2253 unsigned long orig_bg;
2255 /* If we are creating a new frame, begin with the original screen colors
2256 used for the initial frame. */
2257 if (alist == Vdefault_frame_alist
2258 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2260 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2261 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2263 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2264 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2266 /* Extract parm names and values into those vectors. */
2267 i = 0;
2268 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2270 Lisp_Object elt;
2272 elt = Fcar (tail);
2273 parms[i] = Fcar (elt);
2274 CHECK_SYMBOL (parms[i], 1);
2275 values[i] = Fcdr (elt);
2276 i++;
2279 j = i;
2281 for (i = 0; i < j; i++)
2283 Lisp_Object prop = parms[i];
2284 Lisp_Object val = values[i];
2286 if (EQ (prop, Qreverse))
2287 reverse = EQ (val, Qt);
2290 if (termscript && reverse && !was_reverse)
2291 fprintf (termscript, "<INVERSE-VIDEO>\n");
2293 /* Now process the alist elements in reverse of specified order. */
2294 for (i--; i >= 0; i--)
2296 Lisp_Object prop = parms[i];
2297 Lisp_Object val = values[i];
2299 if (EQ (prop, Qforeground_color))
2301 unsigned long new_color = load_color (f, NULL, val, reverse
2302 ? LFACE_BACKGROUND_INDEX
2303 : LFACE_FOREGROUND_INDEX);
2304 if (new_color != FACE_TTY_DEFAULT_COLOR
2305 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2306 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2308 if (reverse)
2309 /* FIXME: should the fore-/background of the default
2310 face change here as well? */
2311 FRAME_BACKGROUND_PIXEL (f) = new_color;
2312 else
2313 FRAME_FOREGROUND_PIXEL (f) = new_color;
2314 redraw = 1;
2315 fg_set = 1;
2316 if (termscript)
2317 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
2320 else if (EQ (prop, Qbackground_color))
2322 unsigned long new_color = load_color (f, NULL, val, reverse
2323 ? LFACE_FOREGROUND_INDEX
2324 : LFACE_BACKGROUND_INDEX);
2325 if (new_color != FACE_TTY_DEFAULT_COLOR
2326 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2327 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2329 if (reverse)
2330 FRAME_FOREGROUND_PIXEL (f) = new_color;
2331 else
2332 FRAME_BACKGROUND_PIXEL (f) = new_color;
2333 redraw = 1;
2334 bg_set = 1;
2335 if (termscript)
2336 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
2339 else if (EQ (prop, Qtitle))
2341 x_set_title (f, val);
2342 if (termscript)
2343 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
2345 else if (EQ (prop, Qcursor_type))
2347 IT_set_cursor_type (f, val);
2348 if (termscript)
2349 fprintf (termscript, "<CTYPE: %s>\n",
2350 EQ (val, Qbar) || CONSP (val) && EQ (XCAR (val), Qbar)
2351 ? "bar" : "box");
2353 store_frame_param (f, prop, val);
2356 /* If they specified "reverse", but not the colors, we need to swap
2357 the current frame colors. */
2358 if (reverse && !was_reverse)
2360 if (!fg_set)
2362 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
2363 redraw = 1;
2365 if (!bg_set)
2367 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
2368 redraw = 1;
2372 if (redraw)
2374 face_change_count++; /* forces xdisp.c to recompute basic faces */
2375 if (f == SELECTED_FRAME())
2376 redraw_frame (f);
2380 extern void init_frame_faces (FRAME_PTR);
2382 #endif /* !HAVE_X_WINDOWS */
2385 /* Do we need the internal terminal? */
2387 void
2388 internal_terminal_init ()
2390 char *term = getenv ("TERM");
2391 char *colors;
2392 struct frame *sf = SELECTED_FRAME();
2394 #ifdef HAVE_X_WINDOWS
2395 if (!inhibit_window_system)
2396 return;
2397 #endif
2399 internal_terminal
2400 = (!noninteractive) && term && !strcmp (term, "internal");
2402 if (getenv ("EMACSTEST"))
2403 termscript = fopen (getenv ("EMACSTEST"), "wt");
2405 #ifndef HAVE_X_WINDOWS
2406 if (!internal_terminal || inhibit_window_system)
2408 sf->output_method = output_termcap;
2409 return;
2412 Vwindow_system = intern ("pc");
2413 Vwindow_system_version = make_number (1);
2414 sf->output_method = output_msdos_raw;
2416 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2417 screen_old_address = 0;
2419 /* Forget the stale screen colors as well. */
2420 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2422 bzero (&the_only_x_display, sizeof the_only_x_display);
2423 the_only_x_display.background_pixel = 7; /* White */
2424 the_only_x_display.foreground_pixel = 0; /* Black */
2425 bright_bg ();
2426 colors = getenv ("EMACSCOLORS");
2427 if (colors && strlen (colors) >= 2)
2429 /* The colors use 4 bits each (we enable bright background). */
2430 if (isdigit (colors[0]))
2431 colors[0] -= '0';
2432 else if (isxdigit (colors[0]))
2433 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2434 if (colors[0] >= 0 && colors[0] < 16)
2435 the_only_x_display.foreground_pixel = colors[0];
2436 if (isdigit (colors[1]))
2437 colors[1] -= '0';
2438 else if (isxdigit (colors[1]))
2439 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2440 if (colors[1] >= 0 && colors[1] < 16)
2441 the_only_x_display.background_pixel = colors[1];
2443 the_only_x_display.line_height = 1;
2444 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
2445 the_only_x_display.display_info.mouse_face_mouse_frame = NULL;
2446 the_only_x_display.display_info.mouse_face_deferred_gc = 0;
2447 the_only_x_display.display_info.mouse_face_beg_row =
2448 the_only_x_display.display_info.mouse_face_beg_col = -1;
2449 the_only_x_display.display_info.mouse_face_end_row =
2450 the_only_x_display.display_info.mouse_face_end_col = -1;
2451 the_only_x_display.display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2452 the_only_x_display.display_info.mouse_face_window = Qnil;
2453 the_only_x_display.display_info.mouse_face_mouse_x =
2454 the_only_x_display.display_info.mouse_face_mouse_y = 0;
2455 the_only_x_display.display_info.mouse_face_defer = 0;
2457 init_frame_faces (sf);
2459 ring_bell_hook = IT_ring_bell;
2460 insert_glyphs_hook = IT_insert_glyphs;
2461 delete_glyphs_hook = IT_delete_glyphs;
2462 write_glyphs_hook = IT_write_glyphs;
2463 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
2464 clear_to_end_hook = IT_clear_to_end;
2465 clear_end_of_line_hook = IT_clear_end_of_line;
2466 clear_frame_hook = IT_clear_screen;
2467 change_line_highlight_hook = IT_change_line_highlight;
2468 update_begin_hook = IT_update_begin;
2469 update_end_hook = IT_update_end;
2470 reassert_line_highlight_hook = IT_reassert_line_highlight;
2471 frame_up_to_date_hook = IT_frame_up_to_date;
2473 /* These hooks are called by term.c without being checked. */
2474 set_terminal_modes_hook = IT_set_terminal_modes;
2475 reset_terminal_modes_hook = IT_reset_terminal_modes;
2476 set_terminal_window_hook = IT_set_terminal_window;
2477 char_ins_del_ok = 0;
2478 #endif
2481 dos_get_saved_screen (screen, rows, cols)
2482 char **screen;
2483 int *rows;
2484 int *cols;
2486 #ifndef HAVE_X_WINDOWS
2487 *screen = startup_screen_buffer;
2488 *cols = startup_screen_size_X;
2489 *rows = startup_screen_size_Y;
2490 return *screen != (char *)0;
2491 #else
2492 return 0;
2493 #endif
2496 #ifndef HAVE_X_WINDOWS
2498 /* We are not X, but we can emulate it well enough for our needs... */
2499 void
2500 check_x (void)
2502 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2503 error ("Not running under a window system");
2506 #endif
2509 /* ----------------------- Keyboard control ----------------------
2511 * Keymaps reflect the following keyboard layout:
2513 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2514 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2515 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2516 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2517 * SPACE
2520 #define Ignore 0x0000
2521 #define Normal 0x0000 /* normal key - alt changes scan-code */
2522 #define FctKey 0x1000 /* func key if c == 0, else c */
2523 #define Special 0x2000 /* func key even if c != 0 */
2524 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2525 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2526 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2527 #define Grey 0x6000 /* Grey keypad key */
2529 #define Alt 0x0100 /* alt scan-code */
2530 #define Ctrl 0x0200 /* ctrl scan-code */
2531 #define Shift 0x0400 /* shift scan-code */
2533 static int extended_kbd; /* 101 (102) keyboard present. */
2535 struct kbd_translate {
2536 unsigned char sc;
2537 unsigned char ch;
2538 unsigned short code;
2541 struct dos_keyboard_map
2543 char *unshifted;
2544 char *shifted;
2545 char *alt_gr;
2546 struct kbd_translate *translate_table;
2550 static struct dos_keyboard_map us_keyboard = {
2551 /* 0 1 2 3 4 5 */
2552 /* 01234567890123456789012345678901234567890 12345678901234 */
2553 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2554 /* 0123456789012345678901234567890123456789 012345678901234 */
2555 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2556 0, /* no Alt-Gr key */
2557 0 /* no translate table */
2560 static struct dos_keyboard_map fr_keyboard = {
2561 /* 0 1 2 3 4 5 */
2562 /* 012 3456789012345678901234567890123456789012345678901234 */
2563 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2564 /* 0123456789012345678901234567890123456789012345678901234 */
2565 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2566 /* 01234567 89012345678901234567890123456789012345678901234 */
2567 " ~#{[|`\\^@]} Ï ",
2568 0 /* no translate table */
2572 * Italian keyboard support, country code 39.
2573 * '<' 56:3c*0000
2574 * '>' 56:3e*0000
2575 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2576 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2579 static struct kbd_translate it_kbd_translate_table[] = {
2580 { 0x56, 0x3c, Normal | 13 },
2581 { 0x56, 0x3e, Normal | 27 },
2582 { 0, 0, 0 }
2584 static struct dos_keyboard_map it_keyboard = {
2585 /* 0 1 2 3 4 5 */
2586 /* 0 123456789012345678901234567890123456789012345678901234 */
2587 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2588 /* 01 23456789012345678901234567890123456789012345678901234 */
2589 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2590 /* 0123456789012345678901234567890123456789012345678901234 */
2591 " {}~` [] @# ",
2592 it_kbd_translate_table
2595 static struct dos_keyboard_map dk_keyboard = {
2596 /* 0 1 2 3 4 5 */
2597 /* 0123456789012345678901234567890123456789012345678901234 */
2598 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2599 /* 01 23456789012345678901234567890123456789012345678901234 */
2600 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2601 /* 0123456789012345678901234567890123456789012345678901234 */
2602 " @œ$ {[]} | ",
2603 0 /* no translate table */
2606 static struct kbd_translate jp_kbd_translate_table[] = {
2607 { 0x73, 0x5c, Normal | 0 },
2608 { 0x73, 0x5f, Normal | 0 },
2609 { 0x73, 0x1c, Map | 0 },
2610 { 0x7d, 0x5c, Normal | 13 },
2611 { 0x7d, 0x7c, Normal | 13 },
2612 { 0x7d, 0x1c, Map | 13 },
2613 { 0, 0, 0 }
2615 static struct dos_keyboard_map jp_keyboard = {
2616 /* 0 1 2 3 4 5 */
2617 /* 0123456789012 345678901234567890123456789012345678901234 */
2618 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2619 /* 01 23456789012345678901234567890123456789012345678901234 */
2620 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2621 0, /* no Alt-Gr key */
2622 jp_kbd_translate_table
2625 static struct keyboard_layout_list
2627 int country_code;
2628 struct dos_keyboard_map *keyboard_map;
2629 } keyboard_layout_list[] =
2631 1, &us_keyboard,
2632 33, &fr_keyboard,
2633 39, &it_keyboard,
2634 45, &dk_keyboard,
2635 81, &jp_keyboard
2638 static struct dos_keyboard_map *keyboard;
2639 static int keyboard_map_all;
2640 static int international_keyboard;
2643 dos_set_keyboard (code, always)
2644 int code;
2645 int always;
2647 int i;
2648 _go32_dpmi_registers regs;
2650 /* See if Keyb.Com is installed (for international keyboard support).
2651 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2652 of Windows 9X! So don't do that! */
2653 regs.x.ax = 0xad80;
2654 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2655 _go32_dpmi_simulate_int (0x2f, &regs);
2656 if (regs.h.al == 0xff)
2657 international_keyboard = 1;
2659 /* Initialize to US settings, for countries that don't have their own. */
2660 keyboard = keyboard_layout_list[0].keyboard_map;
2661 keyboard_map_all = always;
2662 dos_keyboard_layout = 1;
2664 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2665 if (code == keyboard_layout_list[i].country_code)
2667 keyboard = keyboard_layout_list[i].keyboard_map;
2668 keyboard_map_all = always;
2669 dos_keyboard_layout = code;
2670 return 1;
2672 return 0;
2675 static struct
2677 unsigned char char_code; /* normal code */
2678 unsigned char meta_code; /* M- code */
2679 unsigned char keypad_code; /* keypad code */
2680 unsigned char editkey_code; /* edit key */
2681 } keypad_translate_map[] = {
2682 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2683 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2684 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2685 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2686 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2687 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2688 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2689 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2690 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2691 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2692 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2695 static struct
2697 unsigned char char_code; /* normal code */
2698 unsigned char keypad_code; /* keypad code */
2699 } grey_key_translate_map[] = {
2700 '/', 0xaf, /* kp-decimal */
2701 '*', 0xaa, /* kp-multiply */
2702 '-', 0xad, /* kp-subtract */
2703 '+', 0xab, /* kp-add */
2704 '\r', 0x8d /* kp-enter */
2707 static unsigned short
2708 ibmpc_translate_map[] =
2710 /* --------------- 00 to 0f --------------- */
2711 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2712 Alt | ModFct | 0x1b, /* Escape */
2713 Normal | 1, /* '1' */
2714 Normal | 2, /* '2' */
2715 Normal | 3, /* '3' */
2716 Normal | 4, /* '4' */
2717 Normal | 5, /* '5' */
2718 Normal | 6, /* '6' */
2719 Normal | 7, /* '7' */
2720 Normal | 8, /* '8' */
2721 Normal | 9, /* '9' */
2722 Normal | 10, /* '0' */
2723 Normal | 11, /* '-' */
2724 Normal | 12, /* '=' */
2725 Special | 0x08, /* Backspace */
2726 ModFct | 0x74, /* Tab/Backtab */
2728 /* --------------- 10 to 1f --------------- */
2729 Map | 15, /* 'q' */
2730 Map | 16, /* 'w' */
2731 Map | 17, /* 'e' */
2732 Map | 18, /* 'r' */
2733 Map | 19, /* 't' */
2734 Map | 20, /* 'y' */
2735 Map | 21, /* 'u' */
2736 Map | 22, /* 'i' */
2737 Map | 23, /* 'o' */
2738 Map | 24, /* 'p' */
2739 Map | 25, /* '[' */
2740 Map | 26, /* ']' */
2741 ModFct | 0x0d, /* Return */
2742 Ignore, /* Ctrl */
2743 Map | 30, /* 'a' */
2744 Map | 31, /* 's' */
2746 /* --------------- 20 to 2f --------------- */
2747 Map | 32, /* 'd' */
2748 Map | 33, /* 'f' */
2749 Map | 34, /* 'g' */
2750 Map | 35, /* 'h' */
2751 Map | 36, /* 'j' */
2752 Map | 37, /* 'k' */
2753 Map | 38, /* 'l' */
2754 Map | 39, /* ';' */
2755 Map | 40, /* '\'' */
2756 Map | 0, /* '`' */
2757 Ignore, /* Left shift */
2758 Map | 41, /* '\\' */
2759 Map | 45, /* 'z' */
2760 Map | 46, /* 'x' */
2761 Map | 47, /* 'c' */
2762 Map | 48, /* 'v' */
2764 /* --------------- 30 to 3f --------------- */
2765 Map | 49, /* 'b' */
2766 Map | 50, /* 'n' */
2767 Map | 51, /* 'm' */
2768 Map | 52, /* ',' */
2769 Map | 53, /* '.' */
2770 Map | 54, /* '/' */
2771 Ignore, /* Right shift */
2772 Grey | 1, /* Grey * */
2773 Ignore, /* Alt */
2774 Normal | 55, /* ' ' */
2775 Ignore, /* Caps Lock */
2776 FctKey | 0xbe, /* F1 */
2777 FctKey | 0xbf, /* F2 */
2778 FctKey | 0xc0, /* F3 */
2779 FctKey | 0xc1, /* F4 */
2780 FctKey | 0xc2, /* F5 */
2782 /* --------------- 40 to 4f --------------- */
2783 FctKey | 0xc3, /* F6 */
2784 FctKey | 0xc4, /* F7 */
2785 FctKey | 0xc5, /* F8 */
2786 FctKey | 0xc6, /* F9 */
2787 FctKey | 0xc7, /* F10 */
2788 Ignore, /* Num Lock */
2789 Ignore, /* Scroll Lock */
2790 KeyPad | 7, /* Home */
2791 KeyPad | 8, /* Up */
2792 KeyPad | 9, /* Page Up */
2793 Grey | 2, /* Grey - */
2794 KeyPad | 4, /* Left */
2795 KeyPad | 5, /* Keypad 5 */
2796 KeyPad | 6, /* Right */
2797 Grey | 3, /* Grey + */
2798 KeyPad | 1, /* End */
2800 /* --------------- 50 to 5f --------------- */
2801 KeyPad | 2, /* Down */
2802 KeyPad | 3, /* Page Down */
2803 KeyPad | 0, /* Insert */
2804 KeyPad | 10, /* Delete */
2805 Shift | FctKey | 0xbe, /* (Shift) F1 */
2806 Shift | FctKey | 0xbf, /* (Shift) F2 */
2807 Shift | FctKey | 0xc0, /* (Shift) F3 */
2808 Shift | FctKey | 0xc1, /* (Shift) F4 */
2809 Shift | FctKey | 0xc2, /* (Shift) F5 */
2810 Shift | FctKey | 0xc3, /* (Shift) F6 */
2811 Shift | FctKey | 0xc4, /* (Shift) F7 */
2812 Shift | FctKey | 0xc5, /* (Shift) F8 */
2813 Shift | FctKey | 0xc6, /* (Shift) F9 */
2814 Shift | FctKey | 0xc7, /* (Shift) F10 */
2815 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2816 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2818 /* --------------- 60 to 6f --------------- */
2819 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2820 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2821 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2822 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2823 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2824 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2825 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2826 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2827 Alt | FctKey | 0xbe, /* (Alt) F1 */
2828 Alt | FctKey | 0xbf, /* (Alt) F2 */
2829 Alt | FctKey | 0xc0, /* (Alt) F3 */
2830 Alt | FctKey | 0xc1, /* (Alt) F4 */
2831 Alt | FctKey | 0xc2, /* (Alt) F5 */
2832 Alt | FctKey | 0xc3, /* (Alt) F6 */
2833 Alt | FctKey | 0xc4, /* (Alt) F7 */
2834 Alt | FctKey | 0xc5, /* (Alt) F8 */
2836 /* --------------- 70 to 7f --------------- */
2837 Alt | FctKey | 0xc6, /* (Alt) F9 */
2838 Alt | FctKey | 0xc7, /* (Alt) F10 */
2839 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2840 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2841 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2842 Ctrl | KeyPad | 1, /* (Ctrl) End */
2843 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2844 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2845 Alt | Map | 1, /* '1' */
2846 Alt | Map | 2, /* '2' */
2847 Alt | Map | 3, /* '3' */
2848 Alt | Map | 4, /* '4' */
2849 Alt | Map | 5, /* '5' */
2850 Alt | Map | 6, /* '6' */
2851 Alt | Map | 7, /* '7' */
2852 Alt | Map | 8, /* '8' */
2854 /* --------------- 80 to 8f --------------- */
2855 Alt | Map | 9, /* '9' */
2856 Alt | Map | 10, /* '0' */
2857 Alt | Map | 11, /* '-' */
2858 Alt | Map | 12, /* '=' */
2859 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2860 FctKey | 0xc8, /* F11 */
2861 FctKey | 0xc9, /* F12 */
2862 Shift | FctKey | 0xc8, /* (Shift) F11 */
2863 Shift | FctKey | 0xc9, /* (Shift) F12 */
2864 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2865 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2866 Alt | FctKey | 0xc8, /* (Alt) F11 */
2867 Alt | FctKey | 0xc9, /* (Alt) F12 */
2868 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2869 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2870 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2872 /* --------------- 90 to 9f --------------- */
2873 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2874 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2875 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2876 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2877 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2878 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2879 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2880 Alt | FctKey | 0x50, /* (Alt) Home */
2881 Alt | FctKey | 0x52, /* (Alt) Up */
2882 Alt | FctKey | 0x55, /* (Alt) Page Up */
2883 Ignore, /* NO KEY */
2884 Alt | FctKey | 0x51, /* (Alt) Left */
2885 Ignore, /* NO KEY */
2886 Alt | FctKey | 0x53, /* (Alt) Right */
2887 Ignore, /* NO KEY */
2888 Alt | FctKey | 0x57, /* (Alt) End */
2890 /* --------------- a0 to af --------------- */
2891 Alt | KeyPad | 2, /* (Alt) Down */
2892 Alt | KeyPad | 3, /* (Alt) Page Down */
2893 Alt | KeyPad | 0, /* (Alt) Insert */
2894 Alt | KeyPad | 10, /* (Alt) Delete */
2895 Alt | Grey | 0, /* (Alt) Grey / */
2896 Alt | FctKey | 0x09, /* (Alt) Tab */
2897 Alt | Grey | 4 /* (Alt) Keypad Enter */
2900 /* These bit-positions corresponds to values returned by BIOS */
2901 #define SHIFT_P 0x0003 /* two bits! */
2902 #define CTRL_P 0x0004
2903 #define ALT_P 0x0008
2904 #define SCRLOCK_P 0x0010
2905 #define NUMLOCK_P 0x0020
2906 #define CAPSLOCK_P 0x0040
2907 #define ALT_GR_P 0x0800
2908 #define SUPER_P 0x4000 /* pseudo */
2909 #define HYPER_P 0x8000 /* pseudo */
2911 static int
2912 dos_get_modifiers (keymask)
2913 int *keymask;
2915 union REGS regs;
2916 int mask;
2917 int modifiers = 0;
2919 /* Calculate modifier bits */
2920 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2921 int86 (0x16, &regs, &regs);
2923 if (!extended_kbd)
2925 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2926 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2928 else
2930 mask = regs.h.al & (SHIFT_P |
2931 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2933 /* Do not break international keyboard support. */
2934 /* When Keyb.Com is loaded, the right Alt key is */
2935 /* used for accessing characters like { and } */
2936 if (regs.h.ah & 2) /* Left ALT pressed ? */
2937 mask |= ALT_P;
2939 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2941 mask |= ALT_GR_P;
2942 if (dos_hyper_key == 1)
2944 mask |= HYPER_P;
2945 modifiers |= hyper_modifier;
2947 else if (dos_super_key == 1)
2949 mask |= SUPER_P;
2950 modifiers |= super_modifier;
2952 else if (!international_keyboard)
2954 /* If Keyb.Com is NOT installed, let Right Alt behave
2955 like the Left Alt. */
2956 mask &= ~ALT_GR_P;
2957 mask |= ALT_P;
2961 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2962 mask |= CTRL_P;
2964 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2966 if (dos_hyper_key == 2)
2968 mask |= HYPER_P;
2969 modifiers |= hyper_modifier;
2971 else if (dos_super_key == 2)
2973 mask |= SUPER_P;
2974 modifiers |= super_modifier;
2976 else
2977 mask |= CTRL_P;
2981 if (mask & SHIFT_P)
2982 modifiers |= shift_modifier;
2983 if (mask & CTRL_P)
2984 modifiers |= ctrl_modifier;
2985 if (mask & ALT_P)
2986 modifiers |= meta_modifier;
2988 if (keymask)
2989 *keymask = mask;
2990 return modifiers;
2993 #define NUM_RECENT_DOSKEYS (100)
2994 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2995 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2996 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2998 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2999 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
3000 Each input key receives two values in this vector: first the ASCII code,\n\
3001 and then the scan code.")
3004 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
3005 Lisp_Object val;
3007 if (total_doskeys < NUM_RECENT_DOSKEYS)
3008 return Fvector (total_doskeys, keys);
3009 else
3011 val = Fvector (NUM_RECENT_DOSKEYS, keys);
3012 bcopy (keys + recent_doskeys_index,
3013 XVECTOR (val)->contents,
3014 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
3015 bcopy (keys,
3016 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
3017 recent_doskeys_index * sizeof (Lisp_Object));
3018 return val;
3022 /* Get a char from keyboard. Function keys are put into the event queue. */
3024 extern void kbd_buffer_store_event (struct input_event *);
3026 static int
3027 dos_rawgetc ()
3029 struct input_event event;
3030 union REGS regs;
3032 #ifndef HAVE_X_WINDOWS
3033 /* Maybe put the cursor where it should be. */
3034 IT_cmgoto (SELECTED_FRAME());
3035 #endif
3037 /* The following condition is equivalent to `kbhit ()', except that
3038 it uses the bios to do its job. This pleases DESQview/X. */
3039 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
3040 int86 (0x16, &regs, &regs),
3041 (regs.x.flags & 0x40) == 0)
3043 union REGS regs;
3044 register unsigned char c;
3045 int sc, code = -1, mask, kp_mode;
3046 int modifiers;
3048 regs.h.ah = extended_kbd ? 0x10 : 0x00;
3049 int86 (0x16, &regs, &regs);
3050 c = regs.h.al;
3051 sc = regs.h.ah;
3053 total_doskeys += 2;
3054 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3055 = make_number (c);
3056 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3057 recent_doskeys_index = 0;
3058 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3059 = make_number (sc);
3060 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3061 recent_doskeys_index = 0;
3063 modifiers = dos_get_modifiers (&mask);
3065 #ifndef HAVE_X_WINDOWS
3066 if (!NILP (Vdos_display_scancodes))
3068 char buf[11];
3069 sprintf (buf, "%02x:%02x*%04x",
3070 (unsigned) (sc&0xff), (unsigned) c, mask);
3071 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
3073 #endif
3075 if (sc == 0xe0)
3077 switch (c)
3079 case 10: /* Ctrl Grey Enter */
3080 code = Ctrl | Grey | 4;
3081 break;
3082 case 13: /* Grey Enter */
3083 code = Grey | 4;
3084 break;
3085 case '/': /* Grey / */
3086 code = Grey | 0;
3087 break;
3088 default:
3089 continue;
3091 c = 0;
3093 else
3095 /* Try the keyboard-private translation table first. */
3096 if (keyboard->translate_table)
3098 struct kbd_translate *p = keyboard->translate_table;
3100 while (p->sc)
3102 if (p->sc == sc && p->ch == c)
3104 code = p->code;
3105 break;
3107 p++;
3110 /* If the private table didn't translate it, use the general
3111 one. */
3112 if (code == -1)
3114 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3115 continue;
3116 if ((code = ibmpc_translate_map[sc]) == Ignore)
3117 continue;
3121 if (c == 0)
3123 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3124 Emacs is ready to read a key. Therefore, if they press
3125 `Alt-x' when Emacs is busy, by the time we get to
3126 `dos_get_modifiers', they might have already released the
3127 Alt key, and Emacs gets just `x', which is BAD.
3128 However, for keys with the `Map' property set, the ASCII
3129 code returns zero iff Alt is pressed. So, when we DON'T
3130 have to support international_keyboard, we don't have to
3131 distinguish between the left and right Alt keys, and we
3132 can set the META modifier for any keys with the `Map'
3133 property if they return zero ASCII code (c = 0). */
3134 if ( (code & Alt)
3135 || ( (code & 0xf000) == Map && !international_keyboard))
3136 modifiers |= meta_modifier;
3137 if (code & Ctrl)
3138 modifiers |= ctrl_modifier;
3139 if (code & Shift)
3140 modifiers |= shift_modifier;
3143 switch (code & 0xf000)
3145 case ModFct:
3146 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3147 return c;
3148 c = 0; /* Special */
3150 case FctKey:
3151 if (c != 0)
3152 return c;
3154 case Special:
3155 code |= 0xff00;
3156 break;
3158 case Normal:
3159 if (sc == 0)
3161 if (c == 0) /* ctrl-break */
3162 continue;
3163 return c; /* ALT-nnn */
3165 if (!keyboard_map_all)
3167 if (c != ' ')
3168 return c;
3169 code = c;
3170 break;
3173 case Map:
3174 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3175 if (!keyboard_map_all)
3176 return c;
3178 code &= 0xff;
3179 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3180 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3182 if (mask & SHIFT_P)
3184 code = keyboard->shifted[code];
3185 mask -= SHIFT_P;
3186 modifiers &= ~shift_modifier;
3188 else
3189 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3190 code = keyboard->alt_gr[code];
3191 else
3192 code = keyboard->unshifted[code];
3193 break;
3195 case KeyPad:
3196 code &= 0xff;
3197 if (c == 0xe0) /* edit key */
3198 kp_mode = 3;
3199 else
3200 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3201 kp_mode = dos_keypad_mode & 0x03;
3202 else
3203 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3205 switch (kp_mode)
3207 case 0:
3208 if (code == 10 && dos_decimal_point)
3209 return dos_decimal_point;
3210 return keypad_translate_map[code].char_code;
3212 case 1:
3213 code = 0xff00 | keypad_translate_map[code].keypad_code;
3214 break;
3216 case 2:
3217 code = keypad_translate_map[code].meta_code;
3218 modifiers = meta_modifier;
3219 break;
3221 case 3:
3222 code = 0xff00 | keypad_translate_map[code].editkey_code;
3223 break;
3225 break;
3227 case Grey:
3228 code &= 0xff;
3229 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3230 if (dos_keypad_mode & kp_mode)
3231 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3232 else
3233 code = grey_key_translate_map[code].char_code;
3234 break;
3237 make_event:
3238 if (code == 0)
3239 continue;
3241 if (code >= 0x100)
3242 event.kind = non_ascii_keystroke;
3243 else
3244 event.kind = ascii_keystroke;
3245 event.code = code;
3246 event.modifiers = modifiers;
3247 event.frame_or_window = selected_frame;
3248 event.arg = Qnil;
3249 event.timestamp = event_timestamp ();
3250 kbd_buffer_store_event (&event);
3253 if (have_mouse > 0 && !mouse_preempted)
3255 int but, press, x, y, ok;
3256 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3258 /* Check for mouse movement *before* buttons. */
3259 mouse_check_moved ();
3261 /* If the mouse moved from the spot of its last sighting, we
3262 might need to update mouse highlight. */
3263 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3265 previous_help_echo = help_echo;
3266 help_echo = help_echo_object = help_echo_window = Qnil;
3267 help_echo_pos = -1;
3268 IT_note_mouse_highlight (SELECTED_FRAME(),
3269 mouse_last_x, mouse_last_y);
3270 /* If the contents of the global variable help_echo has
3271 changed, generate a HELP_EVENT. */
3272 if (!NILP (help_echo) || !NILP (previous_help_echo))
3274 /* HELP_EVENT takes 2 events in the event loop. */
3275 event.kind = HELP_EVENT;
3276 event.frame_or_window = selected_frame;
3277 event.arg = help_echo_object;
3278 event.x = make_number (help_echo_pos);
3279 event.timestamp = event_timestamp ();
3280 event.code = 0;
3281 kbd_buffer_store_event (&event);
3282 if (WINDOWP (help_echo_window))
3283 event.frame_or_window = help_echo_window;
3284 event.arg = help_echo;
3285 event.code = 1;
3286 kbd_buffer_store_event (&event);
3290 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3291 for (press = 0; press < 2; press++)
3293 int button_num = but;
3295 if (press)
3296 ok = mouse_pressed (but, &x, &y);
3297 else
3298 ok = mouse_released (but, &x, &y);
3299 if (ok)
3301 /* Allow a simultaneous press/release of Mouse-1 and
3302 Mouse-2 to simulate Mouse-3 on two-button mice. */
3303 if (mouse_button_count == 2 && but < 2)
3305 int x2, y2; /* don't clobber original coordinates */
3307 /* If only one button is pressed, wait 100 msec and
3308 check again. This way, Speedy Gonzales isn't
3309 punished, while the slow get their chance. */
3310 if (press && mouse_pressed (1-but, &x2, &y2)
3311 || !press && mouse_released (1-but, &x2, &y2))
3312 button_num = 2;
3313 else
3315 delay (100);
3316 if (press && mouse_pressed (1-but, &x2, &y2)
3317 || !press && mouse_released (1-but, &x2, &y2))
3318 button_num = 2;
3322 event.kind = mouse_click;
3323 event.code = button_num;
3324 event.modifiers = dos_get_modifiers (0)
3325 | (press ? down_modifier : up_modifier);
3326 event.x = x;
3327 event.y = y;
3328 event.frame_or_window = selected_frame;
3329 event.arg = Qnil;
3330 event.timestamp = event_timestamp ();
3331 kbd_buffer_store_event (&event);
3336 return -1;
3339 static int prev_get_char = -1;
3341 /* Return 1 if a key is ready to be read without suspending execution. */
3343 dos_keysns ()
3345 if (prev_get_char != -1)
3346 return 1;
3347 else
3348 return ((prev_get_char = dos_rawgetc ()) != -1);
3351 /* Read a key. Return -1 if no key is ready. */
3353 dos_keyread ()
3355 if (prev_get_char != -1)
3357 int c = prev_get_char;
3358 prev_get_char = -1;
3359 return c;
3361 else
3362 return dos_rawgetc ();
3365 #ifndef HAVE_X_WINDOWS
3366 /* See xterm.c for more info. */
3367 void
3368 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
3369 FRAME_PTR f;
3370 register int pix_x, pix_y;
3371 register int *x, *y;
3372 XRectangle *bounds;
3373 int noclip;
3375 if (bounds) abort ();
3377 /* Ignore clipping. */
3379 *x = pix_x;
3380 *y = pix_y;
3383 void
3384 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
3385 FRAME_PTR f;
3386 register int x, y;
3387 register int *pix_x, *pix_y;
3389 *pix_x = x;
3390 *pix_y = y;
3393 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3394 for now.
3396 Actually, I don't know the meaning of all the parameters of the functions
3397 here -- I only know how they are called by xmenu.c. I could of course
3398 grab the nearest Xlib manual (down the hall, second-to-last door on the
3399 left), but I don't think it's worth the effort. */
3401 /* These hold text of the current and the previous menu help messages. */
3402 static char *menu_help_message, *prev_menu_help_message;
3403 /* Pane number and item number of the menu item which generated the
3404 last menu help message. */
3405 static int menu_help_paneno, menu_help_itemno;
3407 static XMenu *
3408 IT_menu_create ()
3410 XMenu *menu;
3412 menu = (XMenu *) xmalloc (sizeof (XMenu));
3413 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3414 return menu;
3417 /* Allocate some (more) memory for MENU ensuring that there is room for one
3418 for item. */
3420 static void
3421 IT_menu_make_room (XMenu *menu)
3423 if (menu->allocated == 0)
3425 int count = menu->allocated = 10;
3426 menu->text = (char **) xmalloc (count * sizeof (char *));
3427 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3428 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3429 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3431 else if (menu->allocated == menu->count)
3433 int count = menu->allocated = menu->allocated + 10;
3434 menu->text
3435 = (char **) xrealloc (menu->text, count * sizeof (char *));
3436 menu->submenu
3437 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3438 menu->panenumber
3439 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3440 menu->help_text
3441 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3445 /* Search the given menu structure for a given pane number. */
3447 static XMenu *
3448 IT_menu_search_pane (XMenu *menu, int pane)
3450 int i;
3451 XMenu *try;
3453 for (i = 0; i < menu->count; i++)
3454 if (menu->submenu[i])
3456 if (pane == menu->panenumber[i])
3457 return menu->submenu[i];
3458 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3459 return try;
3461 return (XMenu *) 0;
3464 /* Determine how much screen space a given menu needs. */
3466 static void
3467 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3469 int i, h2, w2, maxsubwidth, maxheight;
3471 maxsubwidth = 0;
3472 maxheight = menu->count;
3473 for (i = 0; i < menu->count; i++)
3475 if (menu->submenu[i])
3477 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3478 if (w2 > maxsubwidth) maxsubwidth = w2;
3479 if (i + h2 > maxheight) maxheight = i + h2;
3482 *width = menu->width + maxsubwidth;
3483 *height = maxheight;
3486 /* Display MENU at (X,Y) using FACES. */
3488 static void
3489 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3491 int i, j, face, width;
3492 struct glyph *text, *p;
3493 char *q;
3494 int mx, my;
3495 int enabled, mousehere;
3496 int row, col;
3497 struct frame *sf = SELECTED_FRAME();
3499 menu_help_message = NULL;
3501 width = menu->width;
3502 text = (struct glyph *) xmalloc ((width + 2) * sizeof (struct glyph));
3503 ScreenGetCursor (&row, &col);
3504 mouse_get_xy (&mx, &my);
3505 IT_update_begin (sf);
3506 for (i = 0; i < menu->count; i++)
3508 int max_width = width + 2;
3510 IT_cursor_to (y + i, x);
3511 enabled
3512 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3513 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
3514 face = faces[enabled + mousehere * 2];
3515 /* The following if clause means that we display the menu help
3516 strings even if the menu item is currently disabled. */
3517 if (disp_help && enabled + mousehere * 2 >= 2)
3519 menu_help_message = menu->help_text[i];
3520 menu_help_paneno = pn - 1;
3521 menu_help_itemno = i;
3523 p = text;
3524 SET_CHAR_GLYPH (*p, ' ', face, 0);
3525 p++;
3526 for (j = 0, q = menu->text[i]; *q; j++)
3528 if (*q > 26)
3530 SET_CHAR_GLYPH (*p, *q++, face, 0);
3531 p++;
3533 else /* make '^x' */
3535 SET_CHAR_GLYPH (*p, '^', face, 0);
3536 p++;
3537 j++;
3538 SET_CHAR_GLYPH (*p, *q++ + 64, face, 0);
3539 p++;
3542 /* Don't let the menu text overflow into the next screen row. */
3543 if (x + max_width > screen_size_X)
3545 max_width = screen_size_X - x;
3546 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3548 for (; j < max_width - 2; j++, p++)
3549 SET_CHAR_GLYPH (*p, ' ', face, 0);
3551 SET_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3552 p++;
3553 IT_write_glyphs (text, max_width);
3555 IT_update_end (sf);
3556 IT_cursor_to (row, col);
3557 xfree (text);
3560 /* --------------------------- X Menu emulation ---------------------- */
3562 /* Report availability of menus. */
3565 have_menus_p ()
3567 return 1;
3570 /* Create a brand new menu structure. */
3572 XMenu *
3573 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3575 return IT_menu_create ();
3578 /* Create a new pane and place it on the outer-most level. It is not
3579 clear that it should be placed out there, but I don't know what else
3580 to do. */
3583 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3585 int len;
3586 char *p;
3588 if (!enable)
3589 abort ();
3591 IT_menu_make_room (menu);
3592 menu->submenu[menu->count] = IT_menu_create ();
3593 menu->text[menu->count] = txt;
3594 menu->panenumber[menu->count] = ++menu->panecount;
3595 menu->help_text[menu->count] = NULL;
3596 menu->count++;
3598 /* Adjust length for possible control characters (which will
3599 be written as ^x). */
3600 for (len = strlen (txt), p = txt; *p; p++)
3601 if (*p < 27)
3602 len++;
3604 if (len > menu->width)
3605 menu->width = len;
3607 return menu->panecount;
3610 /* Create a new item in a menu pane. */
3613 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3614 int foo, char *txt, int enable, char *help_text)
3616 int len;
3617 char *p;
3619 if (pane)
3620 if (!(menu = IT_menu_search_pane (menu, pane)))
3621 return XM_FAILURE;
3622 IT_menu_make_room (menu);
3623 menu->submenu[menu->count] = (XMenu *) 0;
3624 menu->text[menu->count] = txt;
3625 menu->panenumber[menu->count] = enable;
3626 menu->help_text[menu->count] = help_text;
3627 menu->count++;
3629 /* Adjust length for possible control characters (which will
3630 be written as ^x). */
3631 for (len = strlen (txt), p = txt; *p; p++)
3632 if (*p < 27)
3633 len++;
3635 if (len > menu->width)
3636 menu->width = len;
3638 return XM_SUCCESS;
3641 /* Decide where the menu would be placed if requested at (X,Y). */
3643 void
3644 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3645 int *ulx, int *uly, int *width, int *height)
3647 IT_menu_calc_size (menu, width, height);
3648 *ulx = x + 1;
3649 *uly = y;
3650 *width += 2;
3653 struct IT_menu_state
3655 void *screen_behind;
3656 XMenu *menu;
3657 int pane;
3658 int x, y;
3662 /* Display menu, wait for user's response, and return that response. */
3665 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3666 int x0, int y0, unsigned ButtonMask, char **txt,
3667 void (*help_callback)(char *, int, int))
3669 struct IT_menu_state *state;
3670 int statecount;
3671 int x, y, i, b;
3672 int screensize;
3673 int faces[4];
3674 Lisp_Object selectface;
3675 int leave, result, onepane;
3676 int title_faces[4]; /* face to display the menu title */
3677 int buffers_num_deleted = 0;
3678 struct frame *sf = SELECTED_FRAME();
3679 Lisp_Object saved_echo_area_message;
3681 /* Just in case we got here without a mouse present... */
3682 if (have_mouse <= 0)
3683 return XM_IA_SELECT;
3684 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3685 around the display. */
3686 if (x0 <= 0)
3687 x0 = 1;
3688 if (y0 <= 0)
3689 y0 = 1;
3691 /* We will process all the mouse events directly, so we had
3692 better prevent dos_rawgetc from stealing them from us. */
3693 mouse_preempted++;
3695 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3696 screensize = screen_size * 2;
3697 faces[0]
3698 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3699 0, DEFAULT_FACE_ID);
3700 faces[1]
3701 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3702 0, DEFAULT_FACE_ID);
3703 selectface = intern ("msdos-menu-select-face");
3704 faces[2] = lookup_derived_face (sf, selectface,
3705 0, faces[0]);
3706 faces[3] = lookup_derived_face (sf, selectface,
3707 0, faces[1]);
3709 /* Make sure the menu title is always displayed with
3710 `msdos-menu-active-face', no matter where the mouse pointer is. */
3711 for (i = 0; i < 4; i++)
3712 title_faces[i] = faces[3];
3714 statecount = 1;
3716 /* Don't let the title for the "Buffers" popup menu include a
3717 digit (which is ugly).
3719 This is a terrible kludge, but I think the "Buffers" case is
3720 the only one where the title includes a number, so it doesn't
3721 seem to be necessary to make this more general. */
3722 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3724 menu->text[0][7] = '\0';
3725 buffers_num_deleted = 1;
3728 /* We need to save the current echo area message, so that we could
3729 restore it below, before we exit. See the commentary below,
3730 before the call to message_with_string. */
3731 saved_echo_area_message = Fcurrent_message ();
3732 state[0].menu = menu;
3733 mouse_off ();
3734 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3736 /* Turn off the cursor. Otherwise it shows through the menu
3737 panes, which is ugly. */
3738 IT_display_cursor (0);
3740 /* Display the menu title. */
3741 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3742 if (buffers_num_deleted)
3743 menu->text[0][7] = ' ';
3744 if ((onepane = menu->count == 1 && menu->submenu[0]))
3746 menu->width = menu->submenu[0]->width;
3747 state[0].menu = menu->submenu[0];
3749 else
3751 state[0].menu = menu;
3753 state[0].x = x0 - 1;
3754 state[0].y = y0;
3755 state[0].pane = onepane;
3757 mouse_last_x = -1; /* A hack that forces display. */
3758 leave = 0;
3759 while (!leave)
3761 if (!mouse_visible) mouse_on ();
3762 mouse_check_moved ();
3763 if (sf->mouse_moved)
3765 sf->mouse_moved = 0;
3766 result = XM_IA_SELECT;
3767 mouse_get_xy (&x, &y);
3768 for (i = 0; i < statecount; i++)
3769 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3771 int dy = y - state[i].y;
3772 if (0 <= dy && dy < state[i].menu->count)
3774 if (!state[i].menu->submenu[dy])
3775 if (state[i].menu->panenumber[dy])
3776 result = XM_SUCCESS;
3777 else
3778 result = XM_IA_SELECT;
3779 *pane = state[i].pane - 1;
3780 *selidx = dy;
3781 /* We hit some part of a menu, so drop extra menus that
3782 have been opened. That does not include an open and
3783 active submenu. */
3784 if (i != statecount - 2
3785 || state[i].menu->submenu[dy] != state[i+1].menu)
3786 while (i != statecount - 1)
3788 statecount--;
3789 mouse_off ();
3790 ScreenUpdate (state[statecount].screen_behind);
3791 if (screen_virtual_segment)
3792 dosv_refresh_virtual_screen (0, screen_size);
3793 xfree (state[statecount].screen_behind);
3795 if (i == statecount - 1 && state[i].menu->submenu[dy])
3797 IT_menu_display (state[i].menu,
3798 state[i].y,
3799 state[i].x,
3800 state[i].pane,
3801 faces, 1);
3802 state[statecount].menu = state[i].menu->submenu[dy];
3803 state[statecount].pane = state[i].menu->panenumber[dy];
3804 mouse_off ();
3805 ScreenRetrieve (state[statecount].screen_behind
3806 = xmalloc (screensize));
3807 state[statecount].x
3808 = state[i].x + state[i].menu->width + 2;
3809 state[statecount].y = y;
3810 statecount++;
3814 IT_menu_display (state[statecount - 1].menu,
3815 state[statecount - 1].y,
3816 state[statecount - 1].x,
3817 state[statecount - 1].pane,
3818 faces, 1);
3820 else
3822 if ((menu_help_message || prev_menu_help_message)
3823 && menu_help_message != prev_menu_help_message)
3825 help_callback (menu_help_message,
3826 menu_help_paneno, menu_help_itemno);
3827 IT_display_cursor (0);
3828 prev_menu_help_message = menu_help_message;
3830 /* We are busy-waiting for the mouse to move, so let's be nice
3831 to other Windows applications by releasing our time slice. */
3832 __dpmi_yield ();
3834 for (b = 0; b < mouse_button_count && !leave; b++)
3836 /* Only leave if user both pressed and released the mouse, and in
3837 that order. This avoids popping down the menu pane unless
3838 the user is really done with it. */
3839 if (mouse_pressed (b, &x, &y))
3841 while (mouse_button_depressed (b, &x, &y))
3842 __dpmi_yield ();
3843 leave = 1;
3845 (void) mouse_released (b, &x, &y);
3849 mouse_off ();
3850 ScreenUpdate (state[0].screen_behind);
3851 if (screen_virtual_segment)
3852 dosv_refresh_virtual_screen (0, screen_size);
3854 /* We have a situation here. ScreenUpdate has just restored the
3855 screen contents as it was before we started drawing this menu.
3856 That includes any echo area message that could have been
3857 displayed back then. (In reality, that echo area message will
3858 almost always be the ``keystroke echo'' that echoes the sequence
3859 of menu items chosen by the user.) However, if the menu had some
3860 help messages, then displaying those messages caused Emacs to
3861 forget about the original echo area message. So when
3862 ScreenUpdate restored it, it created a discrepancy between the
3863 actual screen contents and what Emacs internal data structures
3864 know about it.
3866 To avoid this conflict, we force Emacs to restore the original
3867 echo area message as we found it when we entered this function.
3868 The irony of this is that we then erase the restored message
3869 right away, so the only purpose of restoring it is so that
3870 erasing it works correctly... */
3871 if (! NILP (saved_echo_area_message))
3872 message_with_string ("%s", saved_echo_area_message, 0);
3873 message (0);
3874 while (statecount--)
3875 xfree (state[statecount].screen_behind);
3876 IT_display_cursor (1); /* turn cursor back on */
3877 /* Clean up any mouse events that are waiting inside Emacs event queue.
3878 These events are likely to be generated before the menu was even
3879 displayed, probably because the user pressed and released the button
3880 (which invoked the menu) too quickly. If we don't remove these events,
3881 Emacs will process them after we return and surprise the user. */
3882 discard_mouse_events ();
3883 /* Allow mouse events generation by dos_rawgetc. */
3884 mouse_preempted--;
3885 return result;
3888 /* Dispose of a menu. */
3890 void
3891 XMenuDestroy (Display *foo, XMenu *menu)
3893 int i;
3894 if (menu->allocated)
3896 for (i = 0; i < menu->count; i++)
3897 if (menu->submenu[i])
3898 XMenuDestroy (foo, menu->submenu[i]);
3899 xfree (menu->text);
3900 xfree (menu->submenu);
3901 xfree (menu->panenumber);
3902 xfree (menu->help_text);
3904 xfree (menu);
3905 menu_help_message = prev_menu_help_message = NULL;
3909 x_pixel_width (struct frame *f)
3911 return FRAME_WIDTH (f);
3915 x_pixel_height (struct frame *f)
3917 return FRAME_HEIGHT (f);
3919 #endif /* !HAVE_X_WINDOWS */
3921 /* ----------------------- DOS / UNIX conversion --------------------- */
3923 void msdos_downcase_filename (unsigned char *);
3925 /* Destructively turn backslashes into slashes. */
3927 void
3928 dostounix_filename (p)
3929 register char *p;
3931 msdos_downcase_filename (p);
3933 while (*p)
3935 if (*p == '\\')
3936 *p = '/';
3937 p++;
3941 /* Destructively turn slashes into backslashes. */
3943 void
3944 unixtodos_filename (p)
3945 register char *p;
3947 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3949 *p += 'a' - 'A';
3950 p += 2;
3953 while (*p)
3955 if (*p == '/')
3956 *p = '\\';
3957 p++;
3961 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3964 getdefdir (drive, dst)
3965 int drive;
3966 char *dst;
3968 char in_path[4], *p = in_path;
3969 int e = errno;
3971 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3972 if (drive != 0)
3974 *p++ = drive + 'A' - 1;
3975 *p++ = ':';
3978 *p++ = '.';
3979 *p = '\0';
3980 errno = 0;
3981 _fixpath (in_path, dst);
3982 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3983 it queries the LFN support, so ignore that error. */
3984 if ((errno && errno != ENOSYS) || *dst == '\0')
3985 return 0;
3987 msdos_downcase_filename (dst);
3989 errno = e;
3990 return 1;
3993 /* Remove all CR's that are followed by a LF. */
3996 crlf_to_lf (n, buf)
3997 register int n;
3998 register unsigned char *buf;
4000 unsigned char *np = buf;
4001 unsigned char *startp = buf;
4002 unsigned char *endp = buf + n;
4004 if (n == 0)
4005 return n;
4006 while (buf < endp - 1)
4008 if (*buf == 0x0d)
4010 if (*(++buf) != 0x0a)
4011 *np++ = 0x0d;
4013 else
4014 *np++ = *buf++;
4016 if (buf < endp)
4017 *np++ = *buf++;
4018 return np - startp;
4021 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4023 /* In DJGPP v2.0, library `write' can call `malloc', which might
4024 cause relocation of the buffer whose address we get in ADDR.
4025 Here is a version of `write' that avoids calling `malloc',
4026 to serve us until such time as the library is fixed.
4027 Actually, what we define here is called `__write', because
4028 `write' is a stub that just jmp's to `__write' (to be
4029 POSIXLY-correct with respect to the global name-space). */
4031 #include <io.h> /* for _write */
4032 #include <libc/dosio.h> /* for __file_handle_modes[] */
4034 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
4036 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4039 __write (int handle, const void *buffer, size_t count)
4041 if (count == 0)
4042 return 0;
4044 if(__file_handle_modes[handle] & O_BINARY)
4045 return _write (handle, buffer, count);
4046 else
4048 char *xbp = xbuf;
4049 const char *bp = buffer;
4050 int total_written = 0;
4051 int nmoved = 0, ncr = 0;
4053 while (count)
4055 /* The next test makes sure there's space for at least 2 more
4056 characters in xbuf[], so both CR and LF can be put there. */
4057 if (xbp < XBUF_END)
4059 if (*bp == '\n')
4061 ncr++;
4062 *xbp++ = '\r';
4064 *xbp++ = *bp++;
4065 nmoved++;
4066 count--;
4068 if (xbp >= XBUF_END || !count)
4070 size_t to_write = nmoved + ncr;
4071 int written = _write (handle, xbuf, to_write);
4073 if (written == -1)
4074 return -1;
4075 else
4076 total_written += nmoved; /* CRs aren't counted in ret value */
4078 /* If some, but not all were written (disk full?), return
4079 an estimate of the total written bytes not counting CRs. */
4080 if (written < to_write)
4081 return total_written - (to_write - written) * nmoved/to_write;
4083 nmoved = 0;
4084 ncr = 0;
4085 xbp = xbuf;
4088 return total_written;
4092 /* A low-level file-renaming function which works around Windows 95 bug.
4093 This is pulled directly out of DJGPP v2.01 library sources, and only
4094 used when you compile with DJGPP v2.0. */
4096 #include <io.h>
4098 int _rename(const char *old, const char *new)
4100 __dpmi_regs r;
4101 int olen = strlen(old) + 1;
4102 int i;
4103 int use_lfn = _USE_LFN;
4104 char tempfile[FILENAME_MAX];
4105 const char *orig = old;
4106 int lfn_fd = -1;
4108 r.x.dx = __tb_offset;
4109 r.x.di = __tb_offset + olen;
4110 r.x.ds = r.x.es = __tb_segment;
4112 if (use_lfn)
4114 /* Windows 95 bug: for some filenames, when you rename
4115 file -> file~ (as in Emacs, to leave a backup), the
4116 short 8+3 alias doesn't change, which effectively
4117 makes OLD and NEW the same file. We must rename
4118 through a temporary file to work around this. */
4120 char *pbase = 0, *p;
4121 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
4122 int idx = sizeof(try_char) - 1;
4124 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4125 might point to another drive, which will fail the DOS call. */
4126 strcpy(tempfile, old);
4127 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
4128 if (*p == '/' || *p == '\\' || *p == ':')
4129 pbase = p;
4130 if (pbase)
4131 pbase++;
4132 else
4133 pbase = tempfile;
4134 strcpy(pbase, "X$$djren$$.$$temp$$");
4138 if (idx <= 0)
4139 return -1;
4140 *pbase = try_char[--idx];
4141 } while (_chmod(tempfile, 0) != -1);
4143 r.x.ax = 0x7156;
4144 _put_path2(tempfile, olen);
4145 _put_path(old);
4146 __dpmi_int(0x21, &r);
4147 if (r.x.flags & 1)
4149 errno = __doserr_to_errno(r.x.ax);
4150 return -1;
4153 /* Now create a file with the original name. This will
4154 ensure that NEW will always have a 8+3 alias
4155 different from that of OLD. (Seems to be required
4156 when NameNumericTail in the Registry is set to 0.) */
4157 lfn_fd = _creat(old, 0);
4159 olen = strlen(tempfile) + 1;
4160 old = tempfile;
4161 r.x.di = __tb_offset + olen;
4164 for (i=0; i<2; i++)
4166 if(use_lfn)
4167 r.x.ax = 0x7156;
4168 else
4169 r.h.ah = 0x56;
4170 _put_path2(new, olen);
4171 _put_path(old);
4172 __dpmi_int(0x21, &r);
4173 if(r.x.flags & 1)
4175 if (r.x.ax == 5 && i == 0) /* access denied */
4176 remove(new); /* and try again */
4177 else
4179 errno = __doserr_to_errno(r.x.ax);
4181 /* Restore to original name if we renamed it to temporary. */
4182 if (use_lfn)
4184 if (lfn_fd != -1)
4186 _close (lfn_fd);
4187 remove (orig);
4189 _put_path2(orig, olen);
4190 _put_path(tempfile);
4191 r.x.ax = 0x7156;
4192 __dpmi_int(0x21, &r);
4194 return -1;
4197 else
4198 break;
4201 /* Success. Delete the file possibly created to work
4202 around the Windows 95 bug. */
4203 if (lfn_fd != -1)
4204 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
4205 return 0;
4208 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4210 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
4211 0, 0, 0,
4212 "Return non-nil if long file names are supported on MSDOS.")
4215 return (_USE_LFN ? Qt : Qnil);
4218 /* Convert alphabetic characters in a filename to lower-case. */
4220 void
4221 msdos_downcase_filename (p)
4222 register unsigned char *p;
4224 /* Always lower-case drive letters a-z, even if the filesystem
4225 preserves case in filenames.
4226 This is so MSDOS filenames could be compared by string comparison
4227 functions that are case-sensitive. Even case-preserving filesystems
4228 do not distinguish case in drive letters. */
4229 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4231 *p += 'a' - 'A';
4232 p += 2;
4235 /* Under LFN we expect to get pathnames in their true case. */
4236 if (NILP (Fmsdos_long_file_names ()))
4237 for ( ; *p; p++)
4238 if (*p >= 'A' && *p <= 'Z')
4239 *p += 'a' - 'A';
4242 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
4243 1, 1, 0,
4244 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4245 When long filenames are supported, doesn't change FILENAME.\n\
4246 If FILENAME is not a string, returns nil.\n\
4247 The argument object is never altered--the value is a copy.")
4248 (filename)
4249 Lisp_Object filename;
4251 Lisp_Object tem;
4253 if (! STRINGP (filename))
4254 return Qnil;
4256 tem = Fcopy_sequence (filename);
4257 msdos_downcase_filename (XSTRING (tem)->data);
4258 return tem;
4261 /* The Emacs root directory as determined by init_environment. */
4263 static char emacsroot[MAXPATHLEN];
4265 char *
4266 rootrelativepath (rel)
4267 char *rel;
4269 static char result[MAXPATHLEN + 10];
4271 strcpy (result, emacsroot);
4272 strcat (result, "/");
4273 strcat (result, rel);
4274 return result;
4277 /* Define a lot of environment variables if not already defined. Don't
4278 remove anything unless you know what you're doing -- lots of code will
4279 break if one or more of these are missing. */
4281 void
4282 init_environment (argc, argv, skip_args)
4283 int argc;
4284 char **argv;
4285 int skip_args;
4287 char *s, *t, *root;
4288 int len;
4289 static const char * const tempdirs[] = {
4290 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4292 int i;
4293 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4295 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4296 temporary files and assume "/tmp" if $TMPDIR is unset, which
4297 will break on DOS/Windows. Refuse to work if we cannot find
4298 a directory, not even "c:/", usable for that purpose. */
4299 for (i = 0; i < imax ; i++)
4301 const char *tmp = tempdirs[i];
4303 if (*tmp == '$')
4304 tmp = getenv (tmp + 1);
4305 /* Note that `access' can lie to us if the directory resides on a
4306 read-only filesystem, like CD-ROM or a write-protected floppy.
4307 The only way to be really sure is to actually create a file and
4308 see if it succeeds. But I think that's too much to ask. */
4309 if (tmp && access (tmp, D_OK) == 0)
4311 setenv ("TMPDIR", tmp, 1);
4312 break;
4315 if (i >= imax)
4316 cmd_error_internal
4317 (Fcons (Qerror,
4318 Fcons (build_string ("no usable temporary directories found!!"),
4319 Qnil)),
4320 "While setting TMPDIR: ");
4322 /* Note the startup time, so we know not to clear the screen if we
4323 exit immediately; see IT_reset_terminal_modes.
4324 (Yes, I know `clock' returns zero the first time it's called, but
4325 I do this anyway, in case some wiseguy changes that at some point.) */
4326 startup_time = clock ();
4328 /* Find our root from argv[0]. Assuming argv[0] is, say,
4329 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4330 root = alloca (MAXPATHLEN + 20);
4331 _fixpath (argv[0], root);
4332 msdos_downcase_filename (root);
4333 len = strlen (root);
4334 while (len > 0 && root[len] != '/' && root[len] != ':')
4335 len--;
4336 root[len] = '\0';
4337 if (len > 4
4338 && (strcmp (root + len - 4, "/bin") == 0
4339 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4340 root[len - 4] = '\0';
4341 else
4342 strcpy (root, "c:/emacs"); /* let's be defensive */
4343 len = strlen (root);
4344 strcpy (emacsroot, root);
4346 /* We default HOME to our root. */
4347 setenv ("HOME", root, 0);
4349 /* We default EMACSPATH to root + "/bin". */
4350 strcpy (root + len, "/bin");
4351 setenv ("EMACSPATH", root, 0);
4353 /* I don't expect anybody to ever use other terminals so the internal
4354 terminal is the default. */
4355 setenv ("TERM", "internal", 0);
4357 #ifdef HAVE_X_WINDOWS
4358 /* Emacs expects DISPLAY to be set. */
4359 setenv ("DISPLAY", "unix:0.0", 0);
4360 #endif
4362 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4363 downcase it and mirror the backslashes. */
4364 s = getenv ("COMSPEC");
4365 if (!s) s = "c:/command.com";
4366 t = alloca (strlen (s) + 1);
4367 strcpy (t, s);
4368 dostounix_filename (t);
4369 setenv ("SHELL", t, 0);
4371 /* PATH is also downcased and backslashes mirrored. */
4372 s = getenv ("PATH");
4373 if (!s) s = "";
4374 t = alloca (strlen (s) + 3);
4375 /* Current directory is always considered part of MsDos's path but it is
4376 not normally mentioned. Now it is. */
4377 strcat (strcpy (t, ".;"), s);
4378 dostounix_filename (t); /* Not a single file name, but this should work. */
4379 setenv ("PATH", t, 1);
4381 /* In some sense all dos users have root privileges, so... */
4382 setenv ("USER", "root", 0);
4383 setenv ("NAME", getenv ("USER"), 0);
4385 /* Time zone determined from country code. To make this possible, the
4386 country code may not span more than one time zone. In other words,
4387 in the USA, you lose. */
4388 if (!getenv ("TZ"))
4389 switch (dos_country_code)
4391 case 31: /* Belgium */
4392 case 32: /* The Netherlands */
4393 case 33: /* France */
4394 case 34: /* Spain */
4395 case 36: /* Hungary */
4396 case 38: /* Yugoslavia (or what's left of it?) */
4397 case 39: /* Italy */
4398 case 41: /* Switzerland */
4399 case 42: /* Tjekia */
4400 case 45: /* Denmark */
4401 case 46: /* Sweden */
4402 case 47: /* Norway */
4403 case 48: /* Poland */
4404 case 49: /* Germany */
4405 /* Daylight saving from last Sunday in March to last Sunday in
4406 September, both at 2AM. */
4407 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4408 break;
4409 case 44: /* United Kingdom */
4410 case 351: /* Portugal */
4411 case 354: /* Iceland */
4412 setenv ("TZ", "GMT+00", 0);
4413 break;
4414 case 81: /* Japan */
4415 case 82: /* Korea */
4416 setenv ("TZ", "JST-09", 0);
4417 break;
4418 case 90: /* Turkey */
4419 case 358: /* Finland */
4420 setenv ("TZ", "EET-02", 0);
4421 break;
4422 case 972: /* Israel */
4423 /* This is an approximation. (For exact rules, use the
4424 `zoneinfo/israel' file which comes with DJGPP, but you need
4425 to install it in `/usr/share/zoneinfo/' directory first.) */
4426 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4427 break;
4429 tzset ();
4434 static int break_stat; /* BREAK check mode status. */
4435 static int stdin_stat; /* stdin IOCTL status. */
4437 #if __DJGPP__ < 2
4439 /* These must be global. */
4440 static _go32_dpmi_seginfo ctrl_break_vector;
4441 static _go32_dpmi_registers ctrl_break_regs;
4442 static int ctrlbreakinstalled = 0;
4444 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4446 void
4447 ctrl_break_func (regs)
4448 _go32_dpmi_registers *regs;
4450 Vquit_flag = Qt;
4453 void
4454 install_ctrl_break_check ()
4456 if (!ctrlbreakinstalled)
4458 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4459 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4460 ctrlbreakinstalled = 1;
4461 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
4462 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
4463 &ctrl_break_regs);
4464 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
4468 #endif /* __DJGPP__ < 2 */
4470 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4471 control chars by DOS. Determine the keyboard type. */
4474 dos_ttraw ()
4476 union REGS inregs, outregs;
4477 static int first_time = 1;
4479 break_stat = getcbrk ();
4480 setcbrk (0);
4481 #if __DJGPP__ < 2
4482 install_ctrl_break_check ();
4483 #endif
4485 if (first_time)
4487 inregs.h.ah = 0xc0;
4488 int86 (0x15, &inregs, &outregs);
4489 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4491 have_mouse = 0;
4493 if (internal_terminal
4494 #ifdef HAVE_X_WINDOWS
4495 && inhibit_window_system
4496 #endif
4499 inregs.x.ax = 0x0021;
4500 int86 (0x33, &inregs, &outregs);
4501 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4502 if (!have_mouse)
4504 /* Reportedly, the above doesn't work for some mouse drivers. There
4505 is an additional detection method that should work, but might be
4506 a little slower. Use that as an alternative. */
4507 inregs.x.ax = 0x0000;
4508 int86 (0x33, &inregs, &outregs);
4509 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4512 if (have_mouse)
4514 have_mouse = 1; /* enable mouse */
4515 mouse_visible = 0;
4517 if (outregs.x.bx == 3)
4519 mouse_button_count = 3;
4520 mouse_button_translate[0] = 0; /* Left */
4521 mouse_button_translate[1] = 2; /* Middle */
4522 mouse_button_translate[2] = 1; /* Right */
4524 else
4526 mouse_button_count = 2;
4527 mouse_button_translate[0] = 0;
4528 mouse_button_translate[1] = 1;
4530 mouse_position_hook = &mouse_get_pos;
4531 mouse_init ();
4534 #ifndef HAVE_X_WINDOWS
4535 #if __DJGPP__ >= 2
4536 /* Save the cursor shape used outside Emacs. */
4537 outside_cursor = _farpeekw (_dos_ds, 0x460);
4538 #endif
4539 #endif
4542 first_time = 0;
4544 #if __DJGPP__ >= 2
4546 stdin_stat = setmode (fileno (stdin), O_BINARY);
4547 return (stdin_stat != -1);
4549 else
4550 return (setmode (fileno (stdin), O_BINARY) != -1);
4552 #else /* __DJGPP__ < 2 */
4556 /* I think it is wrong to overwrite `stdin_stat' every time
4557 but the first one this function is called, but I don't
4558 want to change the way it used to work in v1.x.--EZ */
4560 inregs.x.ax = 0x4400; /* Get IOCTL status. */
4561 inregs.x.bx = 0x00; /* 0 = stdin. */
4562 intdos (&inregs, &outregs);
4563 stdin_stat = outregs.h.dl;
4565 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
4566 inregs.x.ax = 0x4401; /* Set IOCTL status */
4567 intdos (&inregs, &outregs);
4568 return !outregs.x.cflag;
4570 #endif /* __DJGPP__ < 2 */
4573 /* Restore status of standard input and Ctrl-C checking. */
4576 dos_ttcooked ()
4578 union REGS inregs, outregs;
4580 setcbrk (break_stat);
4581 mouse_off ();
4583 #if __DJGPP__ >= 2
4585 #ifndef HAVE_X_WINDOWS
4586 /* Restore the cursor shape we found on startup. */
4587 if (outside_cursor)
4589 inregs.h.ah = 1;
4590 inregs.x.cx = outside_cursor;
4591 int86 (0x10, &inregs, &outregs);
4593 #endif
4595 return (setmode (fileno (stdin), stdin_stat) != -1);
4597 #else /* not __DJGPP__ >= 2 */
4599 inregs.x.ax = 0x4401; /* Set IOCTL status. */
4600 inregs.x.bx = 0x00; /* 0 = stdin. */
4601 inregs.x.dx = stdin_stat;
4602 intdos (&inregs, &outregs);
4603 return !outregs.x.cflag;
4605 #endif /* not __DJGPP__ >= 2 */
4609 /* Run command as specified by ARGV in directory DIR.
4610 The command is run with input from TEMPIN, output to
4611 file TEMPOUT and stderr to TEMPERR. */
4614 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4615 unsigned char **argv;
4616 const char *working_dir;
4617 int tempin, tempout, temperr;
4618 char **envv;
4620 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4621 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4622 int msshell, result = -1;
4623 int inbak, outbak, errbak;
4624 int x, y;
4625 Lisp_Object cmd;
4627 /* Get current directory as MSDOS cwd is not per-process. */
4628 getwd (oldwd);
4630 /* If argv[0] is the shell, it might come in any lettercase.
4631 Since `Fmember' is case-sensitive, we need to downcase
4632 argv[0], even if we are on case-preserving filesystems. */
4633 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4634 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4636 *pl = *pa++;
4637 if (*pl >= 'A' && *pl <= 'Z')
4638 *pl += 'a' - 'A';
4640 *pl = '\0';
4642 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4643 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4644 && !strcmp ("-c", argv[1]);
4645 if (msshell)
4647 saveargv1 = argv[1];
4648 saveargv2 = argv[2];
4649 argv[1] = "/c";
4650 if (argv[2])
4652 char *p = alloca (strlen (argv[2]) + 1);
4654 strcpy (argv[2] = p, saveargv2);
4655 while (*p && isspace (*p))
4656 p++;
4657 while (*p && !isspace (*p))
4658 if (*p == '/')
4659 *p++ = '\\';
4660 else
4661 p++;
4665 chdir (working_dir);
4666 inbak = dup (0);
4667 outbak = dup (1);
4668 errbak = dup (2);
4669 if (inbak < 0 || outbak < 0 || errbak < 0)
4670 goto done; /* Allocation might fail due to lack of descriptors. */
4672 if (have_mouse > 0)
4673 mouse_get_xy (&x, &y);
4675 dos_ttcooked (); /* do it here while 0 = stdin */
4677 dup2 (tempin, 0);
4678 dup2 (tempout, 1);
4679 dup2 (temperr, 2);
4681 #if __DJGPP__ > 1
4683 if (msshell && !argv[3])
4685 /* MS-DOS native shells are too restrictive. For starters, they
4686 cannot grok commands longer than 126 characters. In DJGPP v2
4687 and later, `system' is much smarter, so we'll call it instead. */
4689 const char *cmnd;
4691 /* A shell gets a single argument--its full command
4692 line--whose original was saved in `saveargv2'. */
4694 /* Don't let them pass empty command lines to `system', since
4695 with some shells it will try to invoke an interactive shell,
4696 which will hang Emacs. */
4697 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4699 if (*cmnd)
4701 extern char **environ;
4702 int save_system_flags = __system_flags;
4704 /* Request the most powerful version of `system'. We need
4705 all the help we can get to avoid calling stock DOS shells. */
4706 __system_flags = (__system_redirect
4707 | __system_use_shell
4708 | __system_allow_multiple_cmds
4709 | __system_allow_long_cmds
4710 | __system_handle_null_commands
4711 | __system_emulate_chdir);
4713 environ = envv;
4714 result = system (cmnd);
4715 __system_flags = save_system_flags;
4717 else
4718 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4720 else
4722 #endif /* __DJGPP__ > 1 */
4724 result = spawnve (P_WAIT, argv[0], argv, envv);
4726 dup2 (inbak, 0);
4727 dup2 (outbak, 1);
4728 dup2 (errbak, 2);
4729 emacs_close (inbak);
4730 emacs_close (outbak);
4731 emacs_close (errbak);
4733 dos_ttraw ();
4734 if (have_mouse > 0)
4736 mouse_init ();
4737 mouse_moveto (x, y);
4740 /* Some programs might change the meaning of the highest bit of the
4741 text attribute byte, so we get blinking characters instead of the
4742 bright background colors. Restore that. */
4743 bright_bg ();
4745 done:
4746 chdir (oldwd);
4747 if (msshell)
4749 argv[1] = saveargv1;
4750 argv[2] = saveargv2;
4752 return result;
4755 croak (badfunc)
4756 char *badfunc;
4758 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4759 reset_sys_modes ();
4760 exit (1);
4763 #if __DJGPP__ < 2
4765 /* ------------------------- Compatibility functions -------------------
4766 * gethostname
4767 * gettimeofday
4770 /* Hostnames for a pc are not really funny,
4771 but they are used in change log so we emulate the best we can. */
4773 gethostname (p, size)
4774 char *p;
4775 int size;
4777 char *q = egetenv ("HOSTNAME");
4779 if (!q) q = "pc";
4780 strcpy (p, q);
4781 return 0;
4784 /* When time zones are set from Ms-Dos too many C-libraries are playing
4785 tricks with time values. We solve this by defining our own version
4786 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4787 once and after each call to `tzset' with TZ changed. That is
4788 accomplished by aliasing tzset to init_gettimeofday. */
4790 static struct tm time_rec;
4793 gettimeofday (struct timeval *tp, struct timezone *tzp)
4795 if (tp)
4797 struct time t;
4798 struct tm tm;
4800 gettime (&t);
4801 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
4803 struct date d;
4804 getdate (&d);
4805 time_rec.tm_year = d.da_year - 1900;
4806 time_rec.tm_mon = d.da_mon - 1;
4807 time_rec.tm_mday = d.da_day;
4810 time_rec.tm_hour = t.ti_hour;
4811 time_rec.tm_min = t.ti_min;
4812 time_rec.tm_sec = t.ti_sec;
4814 tm = time_rec;
4815 tm.tm_gmtoff = dos_timezone_offset;
4817 tp->tv_sec = mktime (&tm); /* may modify tm */
4818 tp->tv_usec = t.ti_hund * (1000000 / 100);
4820 /* Ignore tzp; it's obsolescent. */
4821 return 0;
4824 #endif /* __DJGPP__ < 2 */
4827 * A list of unimplemented functions that we silently ignore.
4830 #if __DJGPP__ < 2
4831 unsigned alarm (s) unsigned s; {}
4832 fork () { return 0; }
4833 int kill (x, y) int x, y; { return -1; }
4834 nice (p) int p; {}
4835 void volatile pause () {}
4836 sigsetmask (x) int x; { return 0; }
4837 sigblock (mask) int mask; { return 0; }
4838 #endif
4840 void request_sigio (void) {}
4841 setpgrp () {return 0; }
4842 setpriority (x,y,z) int x,y,z; { return 0; }
4843 void unrequest_sigio (void) {}
4845 #if __DJGPP__ > 1
4847 #ifdef POSIX_SIGNALS
4849 /* Augment DJGPP library POSIX signal functions. This is needed
4850 as of DJGPP v2.01, but might be in the library in later releases. */
4852 #include <libc/bss.h>
4854 /* A counter to know when to re-initialize the static sets. */
4855 static int sigprocmask_count = -1;
4857 /* Which signals are currently blocked (initially none). */
4858 static sigset_t current_mask;
4860 /* Which signals are pending (initially none). */
4861 static sigset_t pending_signals;
4863 /* Previous handlers to restore when the blocked signals are unblocked. */
4864 typedef void (*sighandler_t)(int);
4865 static sighandler_t prev_handlers[320];
4867 /* A signal handler which just records that a signal occured
4868 (it will be raised later, if and when the signal is unblocked). */
4869 static void
4870 sig_suspender (signo)
4871 int signo;
4873 sigaddset (&pending_signals, signo);
4877 sigprocmask (how, new_set, old_set)
4878 int how;
4879 const sigset_t *new_set;
4880 sigset_t *old_set;
4882 int signo;
4883 sigset_t new_mask;
4885 /* If called for the first time, initialize. */
4886 if (sigprocmask_count != __bss_count)
4888 sigprocmask_count = __bss_count;
4889 sigemptyset (&pending_signals);
4890 sigemptyset (&current_mask);
4891 for (signo = 0; signo < 320; signo++)
4892 prev_handlers[signo] = SIG_ERR;
4895 if (old_set)
4896 *old_set = current_mask;
4898 if (new_set == 0)
4899 return 0;
4901 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4903 errno = EINVAL;
4904 return -1;
4907 sigemptyset (&new_mask);
4909 /* DJGPP supports upto 320 signals. */
4910 for (signo = 0; signo < 320; signo++)
4912 if (sigismember (&current_mask, signo))
4913 sigaddset (&new_mask, signo);
4914 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4916 sigaddset (&new_mask, signo);
4918 /* SIGKILL is silently ignored, as on other platforms. */
4919 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4920 prev_handlers[signo] = signal (signo, sig_suspender);
4922 if (( how == SIG_UNBLOCK
4923 && sigismember (&new_mask, signo)
4924 && sigismember (new_set, signo))
4925 || (how == SIG_SETMASK
4926 && sigismember (&new_mask, signo)
4927 && !sigismember (new_set, signo)))
4929 sigdelset (&new_mask, signo);
4930 if (prev_handlers[signo] != SIG_ERR)
4932 signal (signo, prev_handlers[signo]);
4933 prev_handlers[signo] = SIG_ERR;
4935 if (sigismember (&pending_signals, signo))
4937 sigdelset (&pending_signals, signo);
4938 raise (signo);
4942 current_mask = new_mask;
4943 return 0;
4946 #else /* not POSIX_SIGNALS */
4948 sigsetmask (x) int x; { return 0; }
4949 sigblock (mask) int mask; { return 0; }
4951 #endif /* not POSIX_SIGNALS */
4952 #endif /* __DJGPP__ > 1 */
4954 #ifndef HAVE_SELECT
4955 #include "sysselect.h"
4957 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4958 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4959 ((long)(time).tv_sec < 0 \
4960 || ((time).tv_sec == 0 \
4961 && (long)(time).tv_usec <= 0))
4962 #endif
4964 /* This yields the rest of the current time slice to the task manager.
4965 It should be called by any code which knows that it has nothing
4966 useful to do except idle.
4968 I don't use __dpmi_yield here, since versions of library before 2.02
4969 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4970 on some versions of Windows 9X. */
4972 void
4973 dos_yield_time_slice (void)
4975 _go32_dpmi_registers r;
4977 r.x.ax = 0x1680;
4978 r.x.ss = r.x.sp = r.x.flags = 0;
4979 _go32_dpmi_simulate_int (0x2f, &r);
4980 if (r.h.al == 0x80)
4981 errno = ENOSYS;
4984 /* Only event queue is checked. */
4985 /* We don't have to call timer_check here
4986 because wait_reading_process_input takes care of that. */
4988 sys_select (nfds, rfds, wfds, efds, timeout)
4989 int nfds;
4990 SELECT_TYPE *rfds, *wfds, *efds;
4991 EMACS_TIME *timeout;
4993 int check_input;
4994 struct time t;
4996 check_input = 0;
4997 if (rfds)
4999 check_input = FD_ISSET (0, rfds);
5000 FD_ZERO (rfds);
5002 if (wfds)
5003 FD_ZERO (wfds);
5004 if (efds)
5005 FD_ZERO (efds);
5007 if (nfds != 1)
5008 abort ();
5010 /* If we are looking only for the terminal, with no timeout,
5011 just read it and wait -- that's more efficient. */
5012 if (!timeout)
5014 while (!detect_input_pending ())
5016 dos_yield_time_slice ();
5019 else
5021 EMACS_TIME clnow, cllast, cldiff;
5023 gettime (&t);
5024 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
5026 while (!check_input || !detect_input_pending ())
5028 gettime (&t);
5029 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
5030 EMACS_SUB_TIME (cldiff, clnow, cllast);
5032 /* When seconds wrap around, we assume that no more than
5033 1 minute passed since last `gettime'. */
5034 if (EMACS_TIME_NEG_P (cldiff))
5035 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
5036 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
5038 /* Stop when timeout value crosses zero. */
5039 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
5040 return 0;
5041 cllast = clnow;
5042 dos_yield_time_slice ();
5046 FD_SET (0, rfds);
5047 return 1;
5049 #endif
5052 * Define overlaid functions:
5054 * chdir -> sys_chdir
5055 * tzset -> init_gettimeofday
5056 * abort -> dos_abort
5059 #ifdef chdir
5060 #undef chdir
5061 extern int chdir ();
5064 sys_chdir (path)
5065 const char* path;
5067 int len = strlen (path);
5068 char *tmp = (char *)path;
5070 if (*tmp && tmp[1] == ':')
5072 if (getdisk () != tolower (tmp[0]) - 'a')
5073 setdisk (tolower (tmp[0]) - 'a');
5074 tmp += 2; /* strip drive: KFS 1995-07-06 */
5075 len -= 2;
5078 if (len > 1 && (tmp[len - 1] == '/'))
5080 char *tmp1 = (char *) alloca (len + 1);
5081 strcpy (tmp1, tmp);
5082 tmp1[len - 1] = 0;
5083 tmp = tmp1;
5085 return chdir (tmp);
5087 #endif
5089 #ifdef tzset
5090 #undef tzset
5091 extern void tzset (void);
5093 void
5094 init_gettimeofday ()
5096 time_t ltm, gtm;
5097 struct tm *lstm;
5099 tzset ();
5100 ltm = gtm = time (NULL);
5101 ltm = mktime (lstm = localtime (&ltm));
5102 gtm = mktime (gmtime (&gtm));
5103 time_rec.tm_hour = 99; /* force gettimeofday to get date */
5104 time_rec.tm_isdst = lstm->tm_isdst;
5105 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
5107 #endif
5109 #ifdef abort
5110 #undef abort
5111 void
5112 dos_abort (file, line)
5113 char *file;
5114 int line;
5116 char buffer1[200], buffer2[400];
5117 int i, j;
5119 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
5120 for (i = j = 0; buffer1[i]; i++) {
5121 buffer2[j++] = buffer1[i];
5122 buffer2[j++] = 0x70;
5124 dosmemput (buffer2, j, (int)ScreenPrimary);
5125 ScreenSetCursor (2, 0);
5126 abort ();
5128 #else
5129 void
5130 abort ()
5132 dos_ttcooked ();
5133 ScreenSetCursor (10, 0);
5134 cputs ("\r\n\nEmacs aborted!\r\n");
5135 #if __DJGPP__ > 1
5136 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5137 if (screen_virtual_segment)
5138 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
5139 /* Generate traceback, so we could tell whodunit. */
5140 signal (SIGINT, SIG_DFL);
5141 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5142 #else /* __DJGPP_MINOR__ >= 2 */
5143 raise (SIGABRT);
5144 #endif /* __DJGPP_MINOR__ >= 2 */
5145 #endif
5146 exit (2);
5148 #endif
5150 /* The following variables are required so that cus-start.el won't
5151 complain about unbound variables. */
5152 #ifndef HAVE_X_WINDOWS
5153 /* Search path for bitmap files (xfns.c). */
5154 Lisp_Object Vx_bitmap_file_path;
5155 int x_stretch_cursor_p;
5156 #endif
5157 #ifndef subprocesses
5158 /* Nonzero means delete a process right away if it exits (process.c). */
5159 static int delete_exited_processes;
5160 #endif
5162 syms_of_msdos ()
5164 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
5165 staticpro (&recent_doskeys);
5166 #ifndef HAVE_X_WINDOWS
5167 help_echo = Qnil;
5168 staticpro (&help_echo);
5169 help_echo_object = Qnil;
5170 staticpro (&help_echo_object);
5171 help_echo_window = Qnil;
5172 staticpro (&help_echo_window);
5173 previous_help_echo = Qnil;
5174 staticpro (&previous_help_echo);
5175 help_echo_pos = -1;
5177 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
5178 "List of directories to search for bitmap files for X.");
5179 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
5181 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
5182 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5183 For example, if a block cursor is over a tab, it will be drawn as\n\
5184 wide as that tab on the display. (No effect on MS-DOS.)");
5185 x_stretch_cursor_p = 0;
5187 /* The following three are from xfns.c: */
5188 Qbackground_color = intern ("background-color");
5189 staticpro (&Qbackground_color);
5190 Qforeground_color = intern ("foreground-color");
5191 staticpro (&Qforeground_color);
5192 Qbar = intern ("bar");
5193 staticpro (&Qbar);
5194 Qcursor_type = intern ("cursor-type");
5195 staticpro (&Qcursor_type);
5196 Qreverse = intern ("reverse");
5197 staticpro (&Qreverse);
5199 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
5200 "*Glyph to display instead of chars not supported by current codepage.\n\
5202 This variable is used only by MSDOS terminals.");
5203 Vdos_unsupported_char_glyph = '\177';
5204 #endif
5205 #ifndef subprocesses
5206 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
5207 "*Non-nil means delete processes immediately when they exit.\n\
5208 nil means don't delete them until `list-processes' is run.");
5209 delete_exited_processes = 0;
5210 #endif
5212 defsubr (&Srecent_doskeys);
5213 defsubr (&Smsdos_long_file_names);
5214 defsubr (&Smsdos_downcase_filename);
5215 defsubr (&Smsdos_remember_default_colors);
5218 #endif /* MSDOS */