(combine-run-hooks): New function.
[emacs.git] / src / msdos.c
blob0351b04c0277f04400024d0aa93c334fe7f8cbaa
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 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
128 static int mouse_visible;
130 static int mouse_last_x;
131 static int mouse_last_y;
133 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
134 static int mouse_button_count;
136 void
137 mouse_on ()
139 union REGS regs;
141 if (have_mouse > 0 && !mouse_visible)
143 if (termscript)
144 fprintf (termscript, "<M_ON>");
145 regs.x.ax = 0x0001;
146 int86 (0x33, &regs, &regs);
147 mouse_visible = 1;
151 void
152 mouse_off ()
154 union REGS regs;
156 if (have_mouse > 0 && mouse_visible)
158 if (termscript)
159 fprintf (termscript, "<M_OFF>");
160 regs.x.ax = 0x0002;
161 int86 (0x33, &regs, &regs);
162 mouse_visible = 0;
166 static void
167 mouse_get_xy (int *x, int *y)
169 union REGS regs;
171 regs.x.ax = 0x0003;
172 int86 (0x33, &regs, &regs);
173 *x = regs.x.cx / 8;
174 *y = regs.x.dx / 8;
177 void
178 mouse_moveto (x, y)
179 int x, y;
181 union REGS regs;
183 if (termscript)
184 fprintf (termscript, "<M_XY=%dx%d>", x, y);
185 regs.x.ax = 0x0004;
186 mouse_last_x = regs.x.cx = x * 8;
187 mouse_last_y = regs.x.dx = y * 8;
188 int86 (0x33, &regs, &regs);
191 static int
192 mouse_pressed (b, xp, yp)
193 int b, *xp, *yp;
195 union REGS regs;
197 if (b >= mouse_button_count)
198 return 0;
199 regs.x.ax = 0x0005;
200 regs.x.bx = mouse_button_translate[b];
201 int86 (0x33, &regs, &regs);
202 if (regs.x.bx)
203 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
204 return (regs.x.bx != 0);
207 static int
208 mouse_released (b, xp, yp)
209 int b, *xp, *yp;
211 union REGS regs;
213 if (b >= mouse_button_count)
214 return 0;
215 regs.x.ax = 0x0006;
216 regs.x.bx = mouse_button_translate[b];
217 int86 (0x33, &regs, &regs);
218 if (regs.x.bx)
219 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
220 return (regs.x.bx != 0);
223 static int
224 mouse_button_depressed (b, xp, yp)
225 int b, *xp, *yp;
227 union REGS regs;
229 if (b >= mouse_button_count)
230 return 0;
231 regs.x.ax = 0x0003;
232 int86 (0x33, &regs, &regs);
233 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
235 *xp = regs.x.cx / 8;
236 *yp = regs.x.dx / 8;
237 return 1;
239 return 0;
242 void
243 mouse_get_pos (f, insist, bar_window, part, x, y, time)
244 FRAME_PTR *f;
245 int insist;
246 Lisp_Object *bar_window, *x, *y;
247 enum scroll_bar_part *part;
248 unsigned long *time;
250 int ix, iy;
251 Lisp_Object frame, tail;
253 /* Clear the mouse-moved flag for every frame on this display. */
254 FOR_EACH_FRAME (tail, frame)
255 XFRAME (frame)->mouse_moved = 0;
257 *f = SELECTED_FRAME();
258 *bar_window = Qnil;
259 mouse_get_xy (&ix, &iy);
260 *time = event_timestamp ();
261 *x = make_number (mouse_last_x = ix);
262 *y = make_number (mouse_last_y = iy);
265 static void
266 mouse_check_moved ()
268 int x, y;
270 mouse_get_xy (&x, &y);
271 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
272 mouse_last_x = x;
273 mouse_last_y = y;
276 void
277 mouse_init ()
279 union REGS regs;
280 int b;
282 if (termscript)
283 fprintf (termscript, "<M_INIT>");
285 regs.x.ax = 0x0021;
286 int86 (0x33, &regs, &regs);
288 /* Reset the mouse last press/release info. It seems that Windows
289 doesn't do that automatically when function 21h is called, which
290 causes Emacs to ``remember'' the click that switched focus to the
291 window just before Emacs was started from that window. */
292 for (b = 0; b < mouse_button_count; b++)
294 int dummy_x, dummy_y;
296 (void) mouse_pressed (b, &dummy_x, &dummy_y);
297 (void) mouse_released (b, &dummy_x, &dummy_y);
300 regs.x.ax = 0x0007;
301 regs.x.cx = 0;
302 regs.x.dx = 8 * (ScreenCols () - 1);
303 int86 (0x33, &regs, &regs);
305 regs.x.ax = 0x0008;
306 regs.x.cx = 0;
307 regs.x.dx = 8 * (ScreenRows () - 1);
308 int86 (0x33, &regs, &regs);
310 mouse_moveto (0, 0);
311 mouse_visible = 0;
314 /* ------------------------- Screen control ----------------------
318 static int internal_terminal = 0;
320 #ifndef HAVE_X_WINDOWS
321 extern unsigned char ScreenAttrib;
322 static int screen_face;
323 static int highlight;
325 static int screen_size_X;
326 static int screen_size_Y;
327 static int screen_size;
329 static int current_pos_X;
330 static int current_pos_Y;
331 static int new_pos_X;
332 static int new_pos_Y;
334 static void *startup_screen_buffer;
335 static int startup_screen_size_X;
336 static int startup_screen_size_Y;
337 static int startup_pos_X;
338 static int startup_pos_Y;
339 static unsigned char startup_screen_attrib;
341 static clock_t startup_time;
343 static int term_setup_done;
345 static unsigned short outside_cursor;
347 /* Similar to the_only_frame. */
348 struct x_output the_only_x_display;
350 /* Support for DOS/V (allows Japanese characters to be displayed on
351 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
353 /* Holds the address of the text-mode screen buffer. */
354 static unsigned long screen_old_address = 0;
355 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
356 static unsigned short screen_virtual_segment = 0;
357 static unsigned short screen_virtual_offset = 0;
358 /* A flag to control how to display unibyte 8-bit characters. */
359 extern int unibyte_display_via_language_environment;
361 Lisp_Object Qbar;
363 #if __DJGPP__ > 1
364 /* Update the screen from a part of relocated DOS/V screen buffer which
365 begins at OFFSET and includes COUNT characters. */
366 static void
367 dosv_refresh_virtual_screen (int offset, int count)
369 __dpmi_regs regs;
371 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
372 return;
374 regs.h.ah = 0xff; /* update relocated screen */
375 regs.x.es = screen_virtual_segment;
376 regs.x.di = screen_virtual_offset + offset;
377 regs.x.cx = count;
378 __dpmi_int (0x10, &regs);
380 #endif
382 static void
383 dos_direct_output (y, x, buf, len)
384 int y;
385 int x;
386 char *buf;
387 int len;
389 int t0 = 2 * (x + y * screen_size_X);
390 int t = t0 + (int) ScreenPrimary;
391 int l0 = len;
393 #if (__DJGPP__ < 2)
394 while (--len >= 0) {
395 dosmemput (buf++, 1, t);
396 t += 2;
398 #else
399 /* This is faster. */
400 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
401 _farnspokeb (t, *buf);
403 if (screen_virtual_segment)
404 dosv_refresh_virtual_screen (t0, l0);
405 #endif
407 #endif
409 /* Flash the screen as a substitute for BEEPs. */
411 #if (__DJGPP__ < 2)
412 static void
413 do_visible_bell (xorattr)
414 unsigned char xorattr;
416 asm volatile
417 (" movb $1,%%dl
418 visible_bell_0:
419 movl _ScreenPrimary,%%eax
420 call dosmemsetup
421 movl %%eax,%%ebx
422 movl %1,%%ecx
423 movb %0,%%al
424 incl %%ebx
425 visible_bell_1:
426 xorb %%al,%%gs:(%%ebx)
427 addl $2,%%ebx
428 decl %%ecx
429 jne visible_bell_1
430 decb %%dl
431 jne visible_bell_3
432 visible_bell_2:
433 movzwl %%ax,%%eax
434 movzwl %%ax,%%eax
435 movzwl %%ax,%%eax
436 movzwl %%ax,%%eax
437 decw %%cx
438 jne visible_bell_2
439 jmp visible_bell_0
440 visible_bell_3:"
441 : /* no output */
442 : "m" (xorattr), "g" (screen_size)
443 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
446 static void
447 ScreenVisualBell (void)
449 /* This creates an xor-mask that will swap the default fore- and
450 background colors. */
451 do_visible_bell (((the_only_x_display.foreground_pixel
452 ^ the_only_x_display.background_pixel)
453 * 0x11) & 0x7f);
455 #endif
457 #ifndef HAVE_X_WINDOWS
459 static int blink_bit = -1; /* the state of the blink bit at startup */
461 /* Enable bright background colors. */
462 static void
463 bright_bg (void)
465 union REGS regs;
467 /* Remember the original state of the blink/bright-background bit.
468 It is stored at 0040:0065h in the BIOS data area. */
469 if (blink_bit == -1)
470 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
472 regs.h.bl = 0;
473 regs.x.ax = 0x1003;
474 int86 (0x10, &regs, &regs);
477 /* Disable bright background colors (and enable blinking) if we found
478 the video system in that state at startup. */
479 static void
480 maybe_enable_blinking (void)
482 if (blink_bit == 1)
484 union REGS regs;
486 regs.h.bl = 1;
487 regs.x.ax = 0x1003;
488 int86 (0x10, &regs, &regs);
492 /* Return non-zero if the system has a VGA adapter. */
493 static int
494 vga_installed (void)
496 union REGS regs;
498 regs.x.ax = 0x1a00;
499 int86 (0x10, &regs, &regs);
500 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
501 return 1;
502 return 0;
505 /* Set the screen dimensions so that it can show no less than
506 ROWS x COLS frame. */
508 void
509 dos_set_window_size (rows, cols)
510 int *rows, *cols;
512 char video_name[30];
513 Lisp_Object video_mode;
514 int video_mode_value;
515 int have_vga = 0;
516 union REGS regs;
517 int current_rows = ScreenRows (), current_cols = ScreenCols ();
519 if (*rows == current_rows && *cols == current_cols)
520 return;
522 mouse_off ();
523 have_vga = vga_installed ();
525 /* If the user specified a special video mode for these dimensions,
526 use that mode. */
527 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
528 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
529 Qnil))-> value;
531 if (INTEGERP (video_mode)
532 && (video_mode_value = XINT (video_mode)) > 0)
534 regs.x.ax = video_mode_value;
535 int86 (0x10, &regs, &regs);
537 if (have_mouse)
539 /* Must hardware-reset the mouse, or else it won't update
540 its notion of screen dimensions for some non-standard
541 video modes. This is *painfully* slow... */
542 regs.x.ax = 0;
543 int86 (0x33, &regs, &regs);
547 /* Find one of the dimensions supported by standard EGA/VGA
548 which gives us at least the required dimensions. */
550 #if __DJGPP__ > 1
552 else
554 static struct {
555 int rows;
556 int need_vga;
557 } std_dimension[] = {
558 {25, 0},
559 {28, 1},
560 {35, 0},
561 {40, 1},
562 {43, 0},
563 {50, 1}
565 int i = 0;
567 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
569 if (std_dimension[i].need_vga <= have_vga
570 && std_dimension[i].rows >= *rows)
572 if (std_dimension[i].rows != current_rows
573 || *cols != current_cols)
574 _set_screen_lines (std_dimension[i].rows);
575 break;
577 i++;
581 #else /* not __DJGPP__ > 1 */
583 else if (*rows <= 25)
585 if (current_rows != 25 || current_cols != 80)
587 regs.x.ax = 3;
588 int86 (0x10, &regs, &regs);
589 regs.x.ax = 0x1101;
590 regs.h.bl = 0;
591 int86 (0x10, &regs, &regs);
592 regs.x.ax = 0x1200;
593 regs.h.bl = 32;
594 int86 (0x10, &regs, &regs);
595 regs.x.ax = 3;
596 int86 (0x10, &regs, &regs);
599 else if (*rows <= 50)
600 if (have_vga && (current_rows != 50 || current_cols != 80)
601 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
603 regs.x.ax = 3;
604 int86 (0x10, &regs, &regs);
605 regs.x.ax = 0x1112;
606 regs.h.bl = 0;
607 int86 (0x10, &regs, &regs);
608 regs.x.ax = 0x1200;
609 regs.h.bl = 32;
610 int86 (0x10, &regs, &regs);
611 regs.x.ax = 0x0100;
612 regs.x.cx = 7;
613 int86 (0x10, &regs, &regs);
615 #endif /* not __DJGPP__ > 1 */
617 if (have_mouse)
619 mouse_init ();
620 mouse_on ();
623 /* Tell the caller what dimensions have been REALLY set. */
624 *rows = ScreenRows ();
625 *cols = ScreenCols ();
627 #if __DJGPP__ > 1
628 /* If the dimensions changed, the mouse highlight info is invalid. */
629 if (current_rows != *rows || current_cols != *cols)
631 struct frame *f = SELECTED_FRAME();
632 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
633 Lisp_Object window = dpyinfo->mouse_face_window;
635 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
637 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
638 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
639 dpyinfo->mouse_face_window = Qnil;
642 #endif
644 /* Enable bright background colors. */
645 bright_bg ();
647 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
648 be defensive anyway. */
649 if (screen_virtual_segment)
650 dosv_refresh_virtual_screen (0, *cols * *rows);
653 /* If we write a character in the position where the mouse is,
654 the mouse cursor may need to be refreshed. */
656 static void
657 mouse_off_maybe ()
659 int x, y;
661 if (!mouse_visible)
662 return;
664 mouse_get_xy (&x, &y);
665 if (y != new_pos_Y || x < new_pos_X)
666 return;
668 mouse_off ();
671 #define DEFAULT_CURSOR_START (-1)
672 #define DEFAULT_CURSOR_WIDTH (-1)
673 #define BOX_CURSOR_WIDTH (-32)
675 /* Set cursor to begin at scan line START_LINE in the character cell
676 and extend for WIDTH scan lines. Scan lines are counted from top
677 of the character cell, starting from zero. */
678 static void
679 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
681 #if __DJGPP__ > 1
682 unsigned desired_cursor;
683 __dpmi_regs regs;
684 int max_line, top_line, bot_line;
686 /* Avoid the costly BIOS call if F isn't the currently selected
687 frame. Allow for NULL as unconditionally meaning the selected
688 frame. */
689 if (f && f != SELECTED_FRAME())
690 return;
692 /* The character cell size in scan lines is stored at 40:85 in the
693 BIOS data area. */
694 max_line = _farpeekw (_dos_ds, 0x485) - 1;
695 switch (max_line)
697 default: /* this relies on CGA cursor emulation being ON! */
698 case 7:
699 bot_line = 7;
700 break;
701 case 9:
702 bot_line = 9;
703 break;
704 case 13:
705 bot_line = 12;
706 break;
707 case 15:
708 bot_line = 14;
709 break;
712 if (width < 0)
714 if (width == BOX_CURSOR_WIDTH)
716 top_line = 0;
717 bot_line = max_line;
719 else if (start_line != DEFAULT_CURSOR_START)
721 top_line = start_line;
722 bot_line = top_line - width - 1;
724 else if (width != DEFAULT_CURSOR_WIDTH)
726 top_line = 0;
727 bot_line = -1 - width;
729 else
730 top_line = bot_line + 1;
732 else if (width == 0)
734 /* [31, 0] seems to DTRT for all screen sizes. */
735 top_line = 31;
736 bot_line = 0;
738 else /* WIDTH is positive */
740 if (start_line != DEFAULT_CURSOR_START)
741 bot_line = start_line;
742 top_line = bot_line - (width - 1);
745 /* If the current cursor shape is already what they want, we are
746 history here. */
747 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
748 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
749 return;
751 regs.h.ah = 1;
752 regs.x.cx = desired_cursor;
753 __dpmi_int (0x10, &regs);
754 #endif /* __DJGPP__ > 1 */
757 static void
758 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
760 if (EQ (cursor_type, Qbar))
762 /* Just BAR means the normal EGA/VGA cursor. */
763 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
765 else if (CONSP (cursor_type) && EQ (XCAR (cursor_type), Qbar))
767 Lisp_Object bar_parms = XCDR (cursor_type);
768 int width;
770 if (INTEGERP (bar_parms))
772 /* Feature: negative WIDTH means cursor at the top
773 of the character cell, zero means invisible cursor. */
774 width = XINT (bar_parms);
775 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
776 width);
778 else if (CONSP (bar_parms)
779 && INTEGERP (XCAR (bar_parms))
780 && INTEGERP (XCDR (bar_parms)))
782 int start_line = XINT (XCDR (bar_parms));
784 width = XINT (XCAR (bar_parms));
785 msdos_set_cursor_shape (f, start_line, width);
788 else
789 /* Treat anything unknown as "box cursor". This includes nil, so
790 that a frame which doesn't specify a cursor type gets a box,
791 which is the default in Emacs. */
792 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
795 static void
796 IT_ring_bell (void)
798 if (visible_bell)
800 mouse_off ();
801 ScreenVisualBell ();
803 else
805 union REGS inregs, outregs;
806 inregs.h.ah = 2;
807 inregs.h.dl = 7;
808 intdos (&inregs, &outregs);
812 /* Given a face id FACE, extract the face parameters to be used for
813 display until the face changes. The face parameters (actually, its
814 color) are used to construct the video attribute byte for each
815 glyph during the construction of the buffer that is then blitted to
816 the video RAM. */
817 static void
818 IT_set_face (int face)
820 struct frame *sf = SELECTED_FRAME();
821 struct face *fp = FACE_FROM_ID (sf, face);
822 unsigned long fg, bg;
824 if (!fp)
826 fp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
827 /* The default face for the frame should always be realized and
828 cached. */
829 if (!fp)
830 abort ();
832 screen_face = face;
833 fg = fp->foreground;
834 bg = fp->background;
836 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
837 colors mean use the colors of the default face, except that if
838 highlight is on, invert the foreground and the background. Note
839 that we assume all 16 colors to be available for the background,
840 since Emacs switches on this mode (and loses the blinking
841 attribute) at startup. */
842 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
843 fg = FRAME_FOREGROUND_PIXEL (sf);
844 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
845 fg = FRAME_BACKGROUND_PIXEL (sf);
846 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
847 bg = FRAME_BACKGROUND_PIXEL (sf);
848 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
849 bg = FRAME_FOREGROUND_PIXEL (sf);
851 /* Make sure highlighted lines really stand out, come what may. */
852 if ((highlight || fp->tty_reverse_p)
853 && (fg == FRAME_FOREGROUND_PIXEL (sf)
854 && bg == FRAME_BACKGROUND_PIXEL (sf)))
856 unsigned long tem = fg;
858 fg = bg;
859 bg = tem;
861 if (termscript)
862 fprintf (termscript, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face,
863 highlight ? "H" : "", fp->foreground, fp->background, fg, bg);
864 if (fg >= 0 && fg < 16)
866 ScreenAttrib &= 0xf0;
867 ScreenAttrib |= fg;
869 if (bg >= 0 && bg < 16)
871 ScreenAttrib &= 0x0f;
872 ScreenAttrib |= ((bg & 0x0f) << 4);
876 Lisp_Object Vdos_unsupported_char_glyph;
878 static void
879 IT_write_glyphs (struct glyph *str, int str_len)
881 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
882 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
883 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
884 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
885 register int sl = str_len;
886 register int tlen = GLYPH_TABLE_LENGTH;
887 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
889 struct coding_system *coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
890 ? &terminal_coding
891 : &safe_terminal_coding);
892 struct frame *sf;
894 /* Do we need to consider conversion of unibyte characters to
895 multibyte? */
896 int convert_unibyte_characters
897 = (NILP (current_buffer->enable_multibyte_characters)
898 && unibyte_display_via_language_environment);
900 if (str_len <= 0) return;
902 screen_buf = screen_bp = alloca (str_len * 2);
903 screen_buf_end = screen_buf + str_len * 2;
904 sf = SELECTED_FRAME();
906 /* Since faces get cached and uncached behind our back, we can't
907 rely on their indices in the cache being consistent across
908 invocations. So always reset the screen face to the default
909 face of the frame, before writing glyphs, and let the glyphs
910 set the right face if it's different from the default. */
911 IT_set_face (DEFAULT_FACE_ID);
913 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
914 the tail. */
915 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
916 while (sl)
918 int cf, chlen, enclen;
919 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
920 unsigned ch;
922 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
923 only for the redisplay code to know how many columns does
924 this character occupy on the screen. Skip padding glyphs. */
925 if (CHAR_GLYPH_PADDING_P (*str))
927 str++;
928 sl--;
930 else
932 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
933 int glyph_not_in_table = 0;
935 if (g < 0 || g >= tlen)
937 /* This glyph doesn't have an entry in Vglyph_table. */
938 ch = str->u.ch;
939 glyph_not_in_table = 1;
941 else
943 /* This glyph has an entry in Vglyph_table, so process
944 any aliases before testing for simpleness. */
945 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
946 ch = FAST_GLYPH_CHAR (g);
949 /* Convert the character code to multibyte, if they
950 requested display via language environment. We only want
951 to convert unibyte characters to multibyte in unibyte
952 buffers! Otherwise, the 8-bit value in CH came from the
953 display table set up to display foreign characters. */
954 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
955 && (ch >= 0240
956 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
957 ch = unibyte_char_to_multibyte (ch);
959 /* Invalid characters are displayed with a special glyph. */
960 if (! CHAR_VALID_P (ch, 0))
962 g = !NILP (Vdos_unsupported_char_glyph)
963 ? Vdos_unsupported_char_glyph
964 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
965 ch = FAST_GLYPH_CHAR (g);
968 /* If the face of this glyph is different from the current
969 screen face, update the screen attribute byte. */
970 cf = FAST_GLYPH_FACE (g);
971 if (cf != screen_face)
972 IT_set_face (cf); /* handles invalid faces gracefully */
974 if (glyph_not_in_table || GLYPH_SIMPLE_P (tbase, tlen, g))
976 /* We generate the multi-byte form of CH in WORKBUF. */
977 chlen = CHAR_STRING (ch, workbuf);
978 buf = workbuf;
980 else
982 /* We have a string in Vglyph_table. */
983 chlen = GLYPH_LENGTH (tbase, g);
984 buf = GLYPH_STRING (tbase, g);
987 /* If the character is not multibyte, don't bother converting it. */
988 if (chlen == 1)
990 *conversion_buffer = (unsigned char)ch;
991 chlen = 0;
992 enclen = 1;
994 else
996 encode_coding (coding, buf, conversion_buffer, chlen,
997 conversion_buffer_size);
998 chlen -= coding->consumed;
999 enclen = coding->produced;
1001 /* Replace glyph codes that cannot be converted by
1002 terminal_coding with Vdos_unsupported_char_glyph. */
1003 if (*conversion_buffer == '?')
1005 char *cbp = conversion_buffer;
1007 while (cbp < conversion_buffer + enclen && *cbp == '?')
1008 *cbp++ = unsupported_char;
1009 if (unsupported_face != screen_face)
1010 IT_set_face (unsupported_face);
1014 if (enclen + chlen > screen_buf_end - screen_bp)
1016 /* The allocated buffer for screen writes is too small.
1017 Flush it and loop again without incrementing STR, so
1018 that the next loop will begin with the same glyph. */
1019 int nbytes = screen_bp - screen_buf;
1021 mouse_off_maybe ();
1022 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1023 if (screen_virtual_segment)
1024 dosv_refresh_virtual_screen (offset, nbytes / 2);
1025 new_pos_X += nbytes / 2;
1026 offset += nbytes;
1028 /* Prepare to reuse the same buffer again. */
1029 screen_bp = screen_buf;
1031 else
1033 /* There's enough place in the allocated buffer to add
1034 the encoding of this glyph. */
1036 /* First, copy the encoded bytes. */
1037 for (bp = conversion_buffer; enclen--; bp++)
1039 *screen_bp++ = (unsigned char)*bp;
1040 *screen_bp++ = ScreenAttrib;
1041 if (termscript)
1042 fputc (*bp, termscript);
1045 /* Now copy the bytes not consumed by the encoding. */
1046 if (chlen > 0)
1048 buf += coding->consumed;
1049 while (chlen--)
1051 if (termscript)
1052 fputc (*buf, termscript);
1053 *screen_bp++ = (unsigned char)*buf++;
1054 *screen_bp++ = ScreenAttrib;
1058 /* Update STR and its remaining length. */
1059 str++;
1060 sl--;
1065 /* Dump whatever is left in the screen buffer. */
1066 mouse_off_maybe ();
1067 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1068 if (screen_virtual_segment)
1069 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1070 new_pos_X += (screen_bp - screen_buf) / 2;
1072 /* We may have to output some codes to terminate the writing. */
1073 if (CODING_REQUIRE_FLUSHING (coding))
1075 coding->mode |= CODING_MODE_LAST_BLOCK;
1076 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
1077 if (coding->produced > 0)
1079 screen_buf = alloca (coding->produced * 2);
1080 for (screen_bp = screen_buf, bp = conversion_buffer;
1081 coding->produced--; bp++)
1083 *screen_bp++ = (unsigned char)*bp;
1084 *screen_bp++ = ScreenAttrib;
1085 if (termscript)
1086 fputc (*bp, termscript);
1088 offset += screen_bp - screen_buf;
1089 mouse_off_maybe ();
1090 dosmemput (screen_buf, screen_bp - screen_buf,
1091 (int)ScreenPrimary + offset);
1092 if (screen_virtual_segment)
1093 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1094 new_pos_X += (screen_bp - screen_buf) / 2;
1099 /************************************************************************
1100 Mouse Highlight (and friends..)
1101 ************************************************************************/
1103 /* This is used for debugging, to turn off note_mouse_highlight. */
1104 int disable_mouse_highlight;
1106 /* If a string, dos_rawgetc generates an event to display that string.
1107 (The display is done in keyboard.c:read_char.) */
1108 static Lisp_Object help_echo;
1109 static Lisp_Object previous_help_echo; /* a helper temporary variable */
1111 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1113 /* Set the mouse pointer shape according to whether it is in the
1114 area where the mouse highlight is in effect. */
1115 static void
1116 IT_set_mouse_pointer (int mode)
1118 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1119 many possibilities to change its shape, and the available
1120 functionality pretty much sucks (e.g., almost every reasonable
1121 shape will conceal the character it is on). Since the color of
1122 the pointer changes in the highlighted area, it is not clear to
1123 me whether anything else is required, anyway. */
1126 /* Display the active region described by mouse_face_*
1127 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1128 static void
1129 show_mouse_face (struct display_info *dpyinfo, int hl)
1131 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1132 struct frame *f = XFRAME (WINDOW_FRAME (w));
1133 int i;
1134 struct face *fp;
1137 /* If window is in the process of being destroyed, don't bother
1138 doing anything. */
1139 if (w->current_matrix == NULL)
1140 goto set_cursor_shape;
1142 /* Recognize when we are called to operate on rows that don't exist
1143 anymore. This can happen when a window is split. */
1144 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1145 goto set_cursor_shape;
1147 /* There's no sense to do anything if the mouse face isn't realized. */
1148 if (hl > 0)
1150 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1151 if (!fp)
1152 goto set_cursor_shape;
1155 /* Note that mouse_face_beg_row etc. are window relative. */
1156 for (i = dpyinfo->mouse_face_beg_row;
1157 i <= dpyinfo->mouse_face_end_row;
1158 i++)
1160 int start_hpos, end_hpos;
1161 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1163 /* Don't do anything if row doesn't have valid contents. */
1164 if (!row->enabled_p)
1165 continue;
1167 /* For all but the first row, the highlight starts at column 0. */
1168 if (i == dpyinfo->mouse_face_beg_row)
1169 start_hpos = dpyinfo->mouse_face_beg_col;
1170 else
1171 start_hpos = 0;
1173 if (i == dpyinfo->mouse_face_end_row)
1174 end_hpos = dpyinfo->mouse_face_end_col;
1175 else
1176 end_hpos = row->used[TEXT_AREA];
1178 if (end_hpos <= start_hpos)
1179 continue;
1180 if (hl > 0)
1182 int vpos = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1183 int kstart = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1184 int nglyphs = end_hpos - start_hpos;
1185 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1186 int start_offset = offset;
1188 if (termscript)
1189 fprintf (termscript, "\n<MH+ %d-%d:%d>",
1190 kstart, kstart + nglyphs - 1, vpos);
1192 mouse_off ();
1193 IT_set_face (dpyinfo->mouse_face_face_id);
1194 /* Since we are going to change only the _colors_ of the
1195 displayed text, there's no need to go through all the
1196 pain of generating and encoding the text from the glyphs.
1197 Instead, we simply poke the attribute byte of each
1198 affected position in video memory with the colors
1199 computed by IT_set_face! */
1200 _farsetsel (_dos_ds);
1201 while (nglyphs--)
1203 _farnspokeb (offset, ScreenAttrib);
1204 offset += 2;
1206 if (screen_virtual_segment)
1207 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1208 mouse_on ();
1210 else
1212 /* We are removing a previously-drawn mouse highlight. The
1213 safest way to do so is to redraw the glyphs anew, since
1214 all kinds of faces and display tables could have changed
1215 behind our back. */
1216 int nglyphs = end_hpos - start_hpos;
1217 int save_x = new_pos_X, save_y = new_pos_Y;
1219 if (end_hpos >= row->used[TEXT_AREA])
1220 nglyphs = row->used[TEXT_AREA] - start_hpos;
1222 /* IT_write_glyphs writes at cursor position, so we need to
1223 temporarily move cursor coordinates to the beginning of
1224 the highlight region. */
1225 new_pos_X = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1226 new_pos_Y = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1228 if (termscript)
1229 fprintf (termscript, "<MH- %d-%d:%d>",
1230 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1231 IT_write_glyphs (row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1232 if (termscript)
1233 fputs ("\n", termscript);
1234 new_pos_X = save_x;
1235 new_pos_Y = save_y;
1239 set_cursor_shape:
1241 /* Change the mouse pointer shape. */
1242 IT_set_mouse_pointer (hl);
1245 /* Clear out the mouse-highlighted active region.
1246 Redraw it un-highlighted first. */
1247 static void
1248 clear_mouse_face (struct display_info *dpyinfo)
1250 if (! NILP (dpyinfo->mouse_face_window))
1251 show_mouse_face (dpyinfo, 0);
1253 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1254 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1255 dpyinfo->mouse_face_window = Qnil;
1258 /* Find the glyph matrix position of buffer position POS in window W.
1259 *HPOS and *VPOS are set to the positions found. W's current glyphs
1260 must be up to date. If POS is above window start return (0, 0).
1261 If POS is after end of W, return end of last line in W. */
1262 static int
1263 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1265 int i;
1266 int lastcol;
1267 int maybe_next_line_p = 0;
1268 int line_start_position;
1269 int yb = window_text_bottom_y (w);
1270 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
1271 struct glyph_row *best_row = row;
1273 while (row->y < yb)
1275 if (row->used[TEXT_AREA])
1276 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1277 else
1278 line_start_position = 0;
1280 if (line_start_position > pos)
1281 break;
1282 /* If the position sought is the end of the buffer,
1283 don't include the blank lines at the bottom of the window. */
1284 else if (line_start_position == pos
1285 && pos == BUF_ZV (XBUFFER (w->buffer)))
1287 maybe_next_line_p = 1;
1288 break;
1290 else if (line_start_position > 0)
1291 best_row = row;
1293 ++row;
1296 /* Find the right column within BEST_ROW. */
1297 lastcol = 0;
1298 row = best_row;
1299 for (i = 0; i < row->used[TEXT_AREA]; i++)
1301 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1302 int charpos;
1304 charpos = glyph->charpos;
1305 if (charpos == pos)
1307 *hpos = i;
1308 *vpos = row->y;
1309 return 1;
1311 else if (charpos > pos)
1312 break;
1313 else if (charpos > 0)
1314 lastcol = i;
1317 /* If we're looking for the end of the buffer,
1318 and we didn't find it in the line we scanned,
1319 use the start of the following line. */
1320 if (maybe_next_line_p)
1322 ++row;
1323 lastcol = 0;
1326 *vpos = row->y;
1327 *hpos = lastcol + 1;
1328 return 0;
1331 /* Take proper action when mouse has moved to the mode or top line of
1332 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1333 mode line. X is relative to the start of the text display area of
1334 W, so the width of bitmap areas and scroll bars must be subtracted
1335 to get a position relative to the start of the mode line. */
1336 static void
1337 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1339 struct frame *f = XFRAME (w->frame);
1340 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1341 struct glyph_row *row;
1343 if (mode_line_p)
1344 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1345 else
1346 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1348 if (row->enabled_p)
1350 extern Lisp_Object Qhelp_echo;
1351 struct glyph *glyph, *end;
1352 Lisp_Object help, map;
1354 /* Find the glyph under X. */
1355 glyph = row->glyphs[TEXT_AREA]
1356 + x - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
1357 end = glyph + row->used[TEXT_AREA];
1358 if (glyph < end
1359 && STRINGP (glyph->object)
1360 && XSTRING (glyph->object)->intervals
1361 && glyph->charpos >= 0
1362 && glyph->charpos < XSTRING (glyph->object)->size)
1364 /* If we're on a string with `help-echo' text property,
1365 arrange for the help to be displayed. This is done by
1366 setting the global variable help_echo to the help string. */
1367 help = Fget_text_property (make_number (glyph->charpos),
1368 Qhelp_echo, glyph->object);
1369 if (STRINGP (help))
1370 help_echo = help;
1375 /* Take proper action when the mouse has moved to position X, Y on
1376 frame F as regards highlighting characters that have mouse-face
1377 properties. Also de-highlighting chars where the mouse was before.
1378 X and Y can be negative or out of range. */
1379 static void
1380 IT_note_mouse_highlight (struct frame *f, int x, int y)
1382 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1383 int portion;
1384 Lisp_Object window;
1385 struct window *w;
1387 /* When a menu is active, don't highlight because this looks odd. */
1388 if (mouse_preempted)
1389 return;
1391 if (disable_mouse_highlight
1392 || !f->glyphs_initialized_p)
1393 return;
1395 dpyinfo->mouse_face_mouse_x = x;
1396 dpyinfo->mouse_face_mouse_y = y;
1397 dpyinfo->mouse_face_mouse_frame = f;
1399 if (dpyinfo->mouse_face_defer)
1400 return;
1402 if (gc_in_progress)
1404 dpyinfo->mouse_face_deferred_gc = 1;
1405 return;
1408 /* Which window is that in? */
1409 window = window_from_coordinates (f, x, y, &portion, 0);
1411 /* If we were displaying active text in another window, clear that. */
1412 if (! EQ (window, dpyinfo->mouse_face_window))
1413 clear_mouse_face (dpyinfo);
1415 /* Not on a window -> return. */
1416 if (!WINDOWP (window))
1417 return;
1419 /* Convert to window-relative coordinates. */
1420 w = XWINDOW (window);
1421 x -= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1422 y -= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1424 if (portion == 1 || portion == 3)
1426 /* Mouse is on the mode or top line. */
1427 IT_note_mode_line_highlight (w, x, portion == 1);
1428 return;
1430 else
1431 IT_set_mouse_pointer (0);
1433 /* Are we in a window whose display is up to date?
1434 And verify the buffer's text has not changed. */
1435 if (/* Within text portion of the window. */
1436 portion == 0
1437 && EQ (w->window_end_valid, w->buffer)
1438 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1439 && (XFASTINT (w->last_overlay_modified)
1440 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1442 int pos, i, area;
1443 struct glyph_row *row;
1444 struct glyph *glyph;
1446 /* Find the glyph under X/Y. */
1447 glyph = NULL;
1448 if (y < w->current_matrix->nrows)
1450 row = MATRIX_ROW (w->current_matrix, y);
1451 if (row->enabled_p
1452 && row->displays_text_p
1453 && x < window_box_width (w, TEXT_AREA))
1455 glyph = row->glyphs[TEXT_AREA];
1456 if (x >= row->used[TEXT_AREA])
1457 glyph = NULL;
1458 else
1460 glyph += x;
1461 if (!BUFFERP (glyph->object))
1462 glyph = NULL;
1467 /* Clear mouse face if X/Y not over text. */
1468 if (glyph == NULL)
1470 clear_mouse_face (dpyinfo);
1471 return;
1474 if (!BUFFERP (glyph->object))
1475 abort ();
1476 pos = glyph->charpos;
1478 /* Check for mouse-face and help-echo. */
1480 extern Lisp_Object Qmouse_face;
1481 Lisp_Object mouse_face, overlay, position;
1482 Lisp_Object *overlay_vec;
1483 int len, noverlays;
1484 struct buffer *obuf;
1485 int obegv, ozv;
1487 /* If we get an out-of-range value, return now; avoid an error. */
1488 if (pos > BUF_Z (XBUFFER (w->buffer)))
1489 return;
1491 /* Make the window's buffer temporarily current for
1492 overlays_at and compute_char_face. */
1493 obuf = current_buffer;
1494 current_buffer = XBUFFER (w->buffer);
1495 obegv = BEGV;
1496 ozv = ZV;
1497 BEGV = BEG;
1498 ZV = Z;
1500 /* Is this char mouse-active or does it have help-echo? */
1501 XSETINT (position, pos);
1503 /* Put all the overlays we want in a vector in overlay_vec.
1504 Store the length in len. If there are more than 10, make
1505 enough space for all, and try again. */
1506 len = 10;
1507 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1508 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1509 if (noverlays > len)
1511 len = noverlays;
1512 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1513 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1516 noverlays = sort_overlays (overlay_vec, noverlays, w);
1518 /* Check mouse-face highlighting. */
1519 if (! (EQ (window, dpyinfo->mouse_face_window)
1520 && y >= dpyinfo->mouse_face_beg_row
1521 && y <= dpyinfo->mouse_face_end_row
1522 && (y > dpyinfo->mouse_face_beg_row
1523 || x >= dpyinfo->mouse_face_beg_col)
1524 && (y < dpyinfo->mouse_face_end_row
1525 || x < dpyinfo->mouse_face_end_col
1526 || dpyinfo->mouse_face_past_end)))
1528 /* Clear the display of the old active region, if any. */
1529 clear_mouse_face (dpyinfo);
1531 /* Find highest priority overlay that has a mouse-face prop. */
1532 overlay = Qnil;
1533 for (i = 0; i < noverlays; i++)
1535 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1536 if (!NILP (mouse_face))
1538 overlay = overlay_vec[i];
1539 break;
1543 /* If no overlay applies, get a text property. */
1544 if (NILP (overlay))
1545 mouse_face = Fget_text_property (position, Qmouse_face,
1546 w->buffer);
1548 /* Handle the overlay case. */
1549 if (! NILP (overlay))
1551 /* Find the range of text around this char that
1552 should be active. */
1553 Lisp_Object before, after;
1554 int ignore;
1556 before = Foverlay_start (overlay);
1557 after = Foverlay_end (overlay);
1558 /* Record this as the current active region. */
1559 fast_find_position (w, XFASTINT (before),
1560 &dpyinfo->mouse_face_beg_col,
1561 &dpyinfo->mouse_face_beg_row);
1562 dpyinfo->mouse_face_past_end
1563 = !fast_find_position (w, XFASTINT (after),
1564 &dpyinfo->mouse_face_end_col,
1565 &dpyinfo->mouse_face_end_row);
1566 dpyinfo->mouse_face_window = window;
1567 dpyinfo->mouse_face_face_id
1568 = face_at_buffer_position (w, pos, 0, 0,
1569 &ignore, pos + 1, 1);
1571 /* Display it as active. */
1572 show_mouse_face (dpyinfo, 1);
1574 /* Handle the text property case. */
1575 else if (! NILP (mouse_face))
1577 /* Find the range of text around this char that
1578 should be active. */
1579 Lisp_Object before, after, beginning, end;
1580 int ignore;
1582 beginning = Fmarker_position (w->start);
1583 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1584 - XFASTINT (w->window_end_pos)));
1585 before
1586 = Fprevious_single_property_change (make_number (pos + 1),
1587 Qmouse_face,
1588 w->buffer, beginning);
1589 after
1590 = Fnext_single_property_change (position, Qmouse_face,
1591 w->buffer, end);
1592 /* Record this as the current active region. */
1593 fast_find_position (w, XFASTINT (before),
1594 &dpyinfo->mouse_face_beg_col,
1595 &dpyinfo->mouse_face_beg_row);
1596 dpyinfo->mouse_face_past_end
1597 = !fast_find_position (w, XFASTINT (after),
1598 &dpyinfo->mouse_face_end_col,
1599 &dpyinfo->mouse_face_end_row);
1600 dpyinfo->mouse_face_window = window;
1601 dpyinfo->mouse_face_face_id
1602 = face_at_buffer_position (w, pos, 0, 0,
1603 &ignore, pos + 1, 1);
1605 /* Display it as active. */
1606 show_mouse_face (dpyinfo, 1);
1610 /* Look for a `help-echo' property. */
1612 Lisp_Object help;
1613 extern Lisp_Object Qhelp_echo;
1615 /* Check overlays first. */
1616 help = Qnil;
1617 for (i = 0; i < noverlays && !STRINGP (help); ++i)
1618 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
1620 /* Try text properties. */
1621 if (!STRINGP (help)
1622 && ((STRINGP (glyph->object)
1623 && glyph->charpos >= 0
1624 && glyph->charpos < XSTRING (glyph->object)->size)
1625 || (BUFFERP (glyph->object)
1626 && glyph->charpos >= BEGV
1627 && glyph->charpos < ZV)))
1628 help = Fget_text_property (make_number (glyph->charpos),
1629 Qhelp_echo, glyph->object);
1631 if (STRINGP (help))
1632 help_echo = help;
1635 BEGV = obegv;
1636 ZV = ozv;
1637 current_buffer = obuf;
1642 static void
1643 IT_clear_end_of_line (int first_unused)
1645 char *spaces, *sp;
1646 int i, j;
1647 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1648 extern int fatal_error_in_progress;
1650 if (new_pos_X >= first_unused || fatal_error_in_progress)
1651 return;
1653 IT_set_face (0);
1654 i = (j = first_unused - new_pos_X) * 2;
1655 if (termscript)
1656 fprintf (termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1657 spaces = sp = alloca (i);
1659 while (--j >= 0)
1661 *sp++ = ' ';
1662 *sp++ = ScreenAttrib;
1665 mouse_off_maybe ();
1666 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1667 if (screen_virtual_segment)
1668 dosv_refresh_virtual_screen (offset, i / 2);
1670 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1671 Let's follow their lead, in case someone relies on this. */
1672 new_pos_X = first_unused;
1675 static void
1676 IT_clear_screen (void)
1678 if (termscript)
1679 fprintf (termscript, "<CLR:SCR>");
1680 IT_set_face (0);
1681 mouse_off ();
1682 ScreenClear ();
1683 if (screen_virtual_segment)
1684 dosv_refresh_virtual_screen (0, screen_size);
1685 new_pos_X = new_pos_Y = 0;
1688 static void
1689 IT_clear_to_end (void)
1691 if (termscript)
1692 fprintf (termscript, "<CLR:EOS>");
1694 while (new_pos_Y < screen_size_Y) {
1695 new_pos_X = 0;
1696 IT_clear_end_of_line (screen_size_X);
1697 new_pos_Y++;
1701 static void
1702 IT_cursor_to (int y, int x)
1704 if (termscript)
1705 fprintf (termscript, "\n<XY=%dx%d>", x, y);
1706 new_pos_X = x;
1707 new_pos_Y = y;
1710 static int cursor_cleared;
1712 static void
1713 IT_display_cursor (int on)
1715 if (on && cursor_cleared)
1717 ScreenSetCursor (current_pos_Y, current_pos_X);
1718 cursor_cleared = 0;
1720 else if (!on && !cursor_cleared)
1722 ScreenSetCursor (-1, -1);
1723 cursor_cleared = 1;
1727 /* Emacs calls cursor-movement functions a lot when it updates the
1728 display (probably a legacy of old terminals where you cannot
1729 update a screen line without first moving the cursor there).
1730 However, cursor movement is expensive on MSDOS (it calls a slow
1731 BIOS function and requires 2 mode switches), while actual screen
1732 updates access the video memory directly and don't depend on
1733 cursor position. To avoid slowing down the redisplay, we cheat:
1734 all functions that move the cursor only set internal variables
1735 which record the cursor position, whereas the cursor is only
1736 moved to its final position whenever screen update is complete.
1738 `IT_cmgoto' is called from the keyboard reading loop and when the
1739 frame update is complete. This means that we are ready for user
1740 input, so we update the cursor position to show where the point is,
1741 and also make the mouse pointer visible.
1743 Special treatment is required when the cursor is in the echo area,
1744 to put the cursor at the end of the text displayed there. */
1746 static void
1747 IT_cmgoto (FRAME_PTR f)
1749 /* Only set the cursor to where it should be if the display is
1750 already in sync with the window contents. */
1751 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1753 /* FIXME: This needs to be rewritten for the new redisplay, or
1754 removed. */
1755 #if 0
1756 static int previous_pos_X = -1;
1758 update_cursor_pos = 1; /* temporary!!! */
1760 /* If the display is in sync, forget any previous knowledge about
1761 cursor position. This is primarily for unexpected events like
1762 C-g in the minibuffer. */
1763 if (update_cursor_pos && previous_pos_X >= 0)
1764 previous_pos_X = -1;
1765 /* If we are in the echo area, put the cursor at the
1766 end of the echo area message. */
1767 if (!update_cursor_pos
1768 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1770 int tem_X = current_pos_X, dummy;
1772 if (echo_area_glyphs)
1774 tem_X = echo_area_glyphs_length;
1775 /* Save current cursor position, to be restored after the
1776 echo area message is erased. Only remember one level
1777 of previous cursor position. */
1778 if (previous_pos_X == -1)
1779 ScreenGetCursor (&dummy, &previous_pos_X);
1781 else if (previous_pos_X >= 0)
1783 /* We wind up here after the echo area message is erased.
1784 Restore the cursor position we remembered above. */
1785 tem_X = previous_pos_X;
1786 previous_pos_X = -1;
1789 if (current_pos_X != tem_X)
1791 new_pos_X = tem_X;
1792 update_cursor_pos = 1;
1795 #endif
1797 if (update_cursor_pos
1798 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1800 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1801 if (termscript)
1802 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1805 /* Maybe cursor is invisible, so make it visible. */
1806 IT_display_cursor (1);
1808 /* Mouse pointer should be always visible if we are waiting for
1809 keyboard input. */
1810 if (!mouse_visible)
1811 mouse_on ();
1814 static void
1815 IT_reassert_line_highlight (int new, int vpos)
1817 highlight = new;
1820 static void
1821 IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1823 highlight = new_highlight;
1824 IT_cursor_to (vpos, 0);
1825 IT_clear_end_of_line (first_unused_hpos);
1828 static void
1829 IT_update_begin (struct frame *f)
1831 struct display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1833 highlight = 0;
1835 BLOCK_INPUT;
1837 if (f == display_info->mouse_face_mouse_frame)
1839 /* Don't do highlighting for mouse motion during the update. */
1840 display_info->mouse_face_defer = 1;
1842 /* If F needs to be redrawn, simply forget about any prior mouse
1843 highlighting. */
1844 if (FRAME_GARBAGED_P (f))
1845 display_info->mouse_face_window = Qnil;
1847 /* Can we tell that this update does not affect the window
1848 where the mouse highlight is? If so, no need to turn off.
1849 Likewise, don't do anything if the frame is garbaged;
1850 in that case, the frame's current matrix that we would use
1851 is all wrong, and we will redisplay that line anyway. */
1852 if (!NILP (display_info->mouse_face_window)
1853 && WINDOWP (display_info->mouse_face_window))
1855 struct window *w = XWINDOW (display_info->mouse_face_window);
1856 int i;
1858 /* If the mouse highlight is in the window that was deleted
1859 (e.g., if it was popped by completion), clear highlight
1860 unconditionally. */
1861 if (NILP (w->buffer))
1862 display_info->mouse_face_window = Qnil;
1863 else
1865 for (i = 0; i < w->desired_matrix->nrows; ++i)
1866 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
1867 break;
1870 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1871 clear_mouse_face (display_info);
1874 else if (!FRAME_LIVE_P (display_info->mouse_face_mouse_frame))
1876 /* If the frame with mouse highlight was deleted, invalidate the
1877 highlight info. */
1878 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1879 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1880 display_info->mouse_face_window = Qnil;
1881 display_info->mouse_face_deferred_gc = 0;
1882 display_info->mouse_face_mouse_frame = NULL;
1885 UNBLOCK_INPUT;
1888 static void
1889 IT_update_end (struct frame *f)
1891 highlight = 0;
1892 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
1895 Lisp_Object Qcursor_type;
1897 static void
1898 IT_frame_up_to_date (struct frame *f)
1900 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1902 if (dpyinfo->mouse_face_deferred_gc
1903 || f == dpyinfo->mouse_face_mouse_frame)
1905 BLOCK_INPUT;
1906 if (dpyinfo->mouse_face_mouse_frame)
1907 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1908 dpyinfo->mouse_face_mouse_x,
1909 dpyinfo->mouse_face_mouse_y);
1910 dpyinfo->mouse_face_deferred_gc = 0;
1911 UNBLOCK_INPUT;
1914 /* Set the cursor type to whatever they wanted. */
1915 IT_set_cursor_type (f, Fcdr (Fassq (Qcursor_type, f->param_alist)));
1917 IT_cmgoto (f); /* position cursor when update is done */
1920 /* Copy LEN glyphs displayed on a single line whose vertical position
1921 is YPOS, beginning at horizontal position XFROM to horizontal
1922 position XTO, by moving blocks in the video memory. Used by
1923 functions that insert and delete glyphs. */
1924 static void
1925 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1927 /* The offsets of source and destination relative to the
1928 conventional memorty selector. */
1929 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1930 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1932 if (from == to || len <= 0)
1933 return;
1935 _farsetsel (_dos_ds);
1937 /* The source and destination might overlap, so we need to move
1938 glyphs non-destructively. */
1939 if (from > to)
1941 for ( ; len; from += 2, to += 2, len--)
1942 _farnspokew (to, _farnspeekw (from));
1944 else
1946 from += (len - 1) * 2;
1947 to += (len - 1) * 2;
1948 for ( ; len; from -= 2, to -= 2, len--)
1949 _farnspokew (to, _farnspeekw (from));
1951 if (screen_virtual_segment)
1952 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1955 /* Insert and delete glyphs. */
1956 static void
1957 IT_insert_glyphs (start, len)
1958 register struct glyph *start;
1959 register int len;
1961 int shift_by_width = screen_size_X - (new_pos_X + len);
1963 /* Shift right the glyphs from the nominal cursor position to the
1964 end of this line. */
1965 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1967 /* Now write the glyphs to be inserted. */
1968 IT_write_glyphs (start, len);
1971 static void
1972 IT_delete_glyphs (n)
1973 register int n;
1975 abort ();
1978 /* set-window-configuration on window.c needs this. */
1979 void
1980 x_set_menu_bar_lines (f, value, oldval)
1981 struct frame *f;
1982 Lisp_Object value, oldval;
1984 set_menu_bar_lines (f, value, oldval);
1987 /* This was copied from xfns.c */
1989 Lisp_Object Qbackground_color;
1990 Lisp_Object Qforeground_color;
1991 Lisp_Object Qreverse;
1992 extern Lisp_Object Qtitle;
1994 /* IT_set_terminal_modes is called when emacs is started,
1995 resumed, and whenever the screen is redrawn! */
1997 static void
1998 IT_set_terminal_modes (void)
2000 if (termscript)
2001 fprintf (termscript, "\n<SET_TERM>");
2002 highlight = 0;
2004 screen_size_X = ScreenCols ();
2005 screen_size_Y = ScreenRows ();
2006 screen_size = screen_size_X * screen_size_Y;
2008 new_pos_X = new_pos_Y = 0;
2009 current_pos_X = current_pos_Y = -1;
2011 if (term_setup_done)
2012 return;
2013 term_setup_done = 1;
2015 startup_screen_size_X = screen_size_X;
2016 startup_screen_size_Y = screen_size_Y;
2017 startup_screen_attrib = ScreenAttrib;
2019 #if __DJGPP__ > 1
2020 /* Is DOS/V (or any other RSIS software which relocates
2021 the screen) installed? */
2023 unsigned short es_value;
2024 __dpmi_regs regs;
2026 regs.h.ah = 0xfe; /* get relocated screen address */
2027 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2028 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2029 else if (screen_old_address) /* already switched to Japanese mode once */
2030 regs.x.es = (screen_old_address >> 4) & 0xffff;
2031 else
2032 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2033 regs.x.di = 0;
2034 es_value = regs.x.es;
2035 __dpmi_int (0x10, &regs);
2037 if (regs.x.es != es_value)
2039 /* screen_old_address is only set if ScreenPrimary does NOT
2040 already point to the relocated buffer address returned by
2041 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2042 ScreenPrimary to that address at startup under DOS/V. */
2043 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2044 screen_old_address = ScreenPrimary;
2045 screen_virtual_segment = regs.x.es;
2046 screen_virtual_offset = regs.x.di;
2047 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2050 #endif /* __DJGPP__ > 1 */
2052 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2053 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2055 if (termscript)
2056 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2057 screen_size_X, screen_size_Y);
2059 bright_bg ();
2062 /* IT_reset_terminal_modes is called when emacs is
2063 suspended or killed. */
2065 static void
2066 IT_reset_terminal_modes (void)
2068 int display_row_start = (int) ScreenPrimary;
2069 int saved_row_len = startup_screen_size_X * 2;
2070 int update_row_len = ScreenCols () * 2;
2071 int current_rows = ScreenRows ();
2072 int to_next_row = update_row_len;
2073 unsigned char *saved_row = startup_screen_buffer;
2074 int cursor_pos_X = ScreenCols () - 1;
2075 int cursor_pos_Y = ScreenRows () - 1;
2077 if (termscript)
2078 fprintf (termscript, "\n<RESET_TERM>");
2080 highlight = 0;
2082 if (!term_setup_done)
2083 return;
2085 mouse_off ();
2087 /* Leave the video system in the same state as we found it,
2088 as far as the blink/bright-background bit is concerned. */
2089 maybe_enable_blinking ();
2091 /* We have a situation here.
2092 We cannot just do ScreenUpdate(startup_screen_buffer) because
2093 the luser could have changed screen dimensions inside Emacs
2094 and failed (or didn't want) to restore them before killing
2095 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2096 thus will happily use memory outside what was allocated for
2097 `startup_screen_buffer'.
2098 Thus we only restore as much as the current screen dimensions
2099 can hold, and clear the rest (if the saved screen is smaller than
2100 the current) with the color attribute saved at startup. The cursor
2101 is also restored within the visible dimensions. */
2103 ScreenAttrib = startup_screen_attrib;
2105 /* Don't restore the screen if we are exiting less than 2 seconds
2106 after startup: we might be crashing, and the screen might show
2107 some vital clues to what's wrong. */
2108 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2110 ScreenClear ();
2111 if (screen_virtual_segment)
2112 dosv_refresh_virtual_screen (0, screen_size);
2114 if (update_row_len > saved_row_len)
2115 update_row_len = saved_row_len;
2116 if (current_rows > startup_screen_size_Y)
2117 current_rows = startup_screen_size_Y;
2119 if (termscript)
2120 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2121 update_row_len / 2, current_rows);
2123 while (current_rows--)
2125 dosmemput (saved_row, update_row_len, display_row_start);
2126 if (screen_virtual_segment)
2127 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2128 update_row_len / 2);
2129 saved_row += saved_row_len;
2130 display_row_start += to_next_row;
2133 if (startup_pos_X < cursor_pos_X)
2134 cursor_pos_X = startup_pos_X;
2135 if (startup_pos_Y < cursor_pos_Y)
2136 cursor_pos_Y = startup_pos_Y;
2138 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2139 xfree (startup_screen_buffer);
2141 term_setup_done = 0;
2144 static void
2145 IT_set_terminal_window (int foo)
2149 /* Remember the screen colors of the curent frame, to serve as the
2150 default colors for newly-created frames. */
2152 static int initial_screen_colors[2];
2154 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2155 Smsdos_remember_default_colors, 1, 1, 0,
2156 "Remember the screen colors of the current frame.")
2157 (frame)
2158 Lisp_Object frame;
2160 int reverse;
2161 struct frame *f;
2163 CHECK_FRAME (frame, 0);
2164 f= XFRAME (frame);
2165 reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
2167 initial_screen_colors[0]
2168 = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
2169 initial_screen_colors[1]
2170 = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
2173 void
2174 IT_set_frame_parameters (f, alist)
2175 struct frame *f;
2176 Lisp_Object alist;
2178 Lisp_Object tail;
2179 int length = XINT (Flength (alist));
2180 int i, j;
2181 Lisp_Object *parms
2182 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2183 Lisp_Object *values
2184 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2185 /* Do we have to reverse the foreground and background colors? */
2186 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2187 int was_reverse = reverse;
2188 int redraw = 0, fg_set = 0, bg_set = 0;
2189 unsigned long orig_fg;
2190 unsigned long orig_bg;
2192 /* If we are creating a new frame, begin with the original screen colors
2193 used for the initial frame. */
2194 if (alist == Vdefault_frame_alist
2195 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2197 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2198 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2200 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2201 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2203 /* Extract parm names and values into those vectors. */
2204 i = 0;
2205 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2207 Lisp_Object elt;
2209 elt = Fcar (tail);
2210 parms[i] = Fcar (elt);
2211 CHECK_SYMBOL (parms[i], 1);
2212 values[i] = Fcdr (elt);
2213 i++;
2216 j = i;
2218 for (i = 0; i < j; i++)
2220 Lisp_Object prop = parms[i];
2221 Lisp_Object val = values[i];
2223 if (EQ (prop, Qreverse))
2224 reverse = EQ (val, Qt);
2227 if (termscript && reverse && !was_reverse)
2228 fprintf (termscript, "<INVERSE-VIDEO>\n");
2230 /* Now process the alist elements in reverse of specified order. */
2231 for (i--; i >= 0; i--)
2233 Lisp_Object prop = parms[i];
2234 Lisp_Object val = values[i];
2236 if (EQ (prop, Qforeground_color))
2238 unsigned long new_color = load_color (f, NULL, val, reverse
2239 ? LFACE_BACKGROUND_INDEX
2240 : LFACE_FOREGROUND_INDEX);
2241 if (new_color != FACE_TTY_DEFAULT_COLOR
2242 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2243 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2245 if (reverse)
2246 /* FIXME: should the fore-/background of the default
2247 face change here as well? */
2248 FRAME_BACKGROUND_PIXEL (f) = new_color;
2249 else
2250 FRAME_FOREGROUND_PIXEL (f) = new_color;
2251 redraw = 1;
2252 fg_set = 1;
2253 if (termscript)
2254 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
2257 else if (EQ (prop, Qbackground_color))
2259 unsigned long new_color = load_color (f, NULL, val, reverse
2260 ? LFACE_FOREGROUND_INDEX
2261 : LFACE_BACKGROUND_INDEX);
2262 if (new_color != FACE_TTY_DEFAULT_COLOR
2263 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2264 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2266 if (reverse)
2267 FRAME_FOREGROUND_PIXEL (f) = new_color;
2268 else
2269 FRAME_BACKGROUND_PIXEL (f) = new_color;
2270 redraw = 1;
2271 bg_set = 1;
2272 if (termscript)
2273 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
2276 else if (EQ (prop, Qtitle))
2278 x_set_title (f, val);
2279 if (termscript)
2280 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
2282 else if (EQ (prop, Qcursor_type))
2284 IT_set_cursor_type (f, val);
2285 if (termscript)
2286 fprintf (termscript, "<CTYPE: %s>\n",
2287 EQ (val, Qbar) || CONSP (val) && EQ (XCAR (val), Qbar)
2288 ? "bar" : "box");
2290 store_frame_param (f, prop, val);
2293 /* If they specified "reverse", but not the colors, we need to swap
2294 the current frame colors. */
2295 if (reverse && !was_reverse)
2297 if (!fg_set)
2299 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
2300 redraw = 1;
2302 if (!bg_set)
2304 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
2305 redraw = 1;
2309 if (redraw)
2311 face_change_count++; /* forces xdisp.c to recompute basic faces */
2312 if (f == SELECTED_FRAME())
2313 redraw_frame (f);
2317 extern void init_frame_faces (FRAME_PTR);
2319 #endif /* !HAVE_X_WINDOWS */
2322 /* Do we need the internal terminal? */
2324 void
2325 internal_terminal_init ()
2327 char *term = getenv ("TERM");
2328 char *colors;
2329 struct frame *sf = SELECTED_FRAME();
2331 #ifdef HAVE_X_WINDOWS
2332 if (!inhibit_window_system)
2333 return;
2334 #endif
2336 internal_terminal
2337 = (!noninteractive) && term && !strcmp (term, "internal");
2339 if (getenv ("EMACSTEST"))
2340 termscript = fopen (getenv ("EMACSTEST"), "wt");
2342 #ifndef HAVE_X_WINDOWS
2343 if (!internal_terminal || inhibit_window_system)
2345 sf->output_method = output_termcap;
2346 return;
2349 Vwindow_system = intern ("pc");
2350 Vwindow_system_version = make_number (1);
2351 sf->output_method = output_msdos_raw;
2353 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2354 screen_old_address = 0;
2356 /* Forget the stale screen colors as well. */
2357 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2359 bzero (&the_only_x_display, sizeof the_only_x_display);
2360 the_only_x_display.background_pixel = 7; /* White */
2361 the_only_x_display.foreground_pixel = 0; /* Black */
2362 bright_bg ();
2363 colors = getenv ("EMACSCOLORS");
2364 if (colors && strlen (colors) >= 2)
2366 /* The colors use 4 bits each (we enable bright background). */
2367 if (isdigit (colors[0]))
2368 colors[0] -= '0';
2369 else if (isxdigit (colors[0]))
2370 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2371 if (colors[0] >= 0 && colors[0] < 16)
2372 the_only_x_display.foreground_pixel = colors[0];
2373 if (isdigit (colors[1]))
2374 colors[1] -= '0';
2375 else if (isxdigit (colors[1]))
2376 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2377 if (colors[1] >= 0 && colors[1] < 16)
2378 the_only_x_display.background_pixel = colors[1];
2380 the_only_x_display.line_height = 1;
2381 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
2382 the_only_x_display.display_info.mouse_face_mouse_frame = NULL;
2383 the_only_x_display.display_info.mouse_face_deferred_gc = 0;
2384 the_only_x_display.display_info.mouse_face_beg_row =
2385 the_only_x_display.display_info.mouse_face_beg_col = -1;
2386 the_only_x_display.display_info.mouse_face_end_row =
2387 the_only_x_display.display_info.mouse_face_end_col = -1;
2388 the_only_x_display.display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2389 the_only_x_display.display_info.mouse_face_window = Qnil;
2390 the_only_x_display.display_info.mouse_face_mouse_x =
2391 the_only_x_display.display_info.mouse_face_mouse_y = 0;
2392 the_only_x_display.display_info.mouse_face_defer = 0;
2394 init_frame_faces (sf);
2396 ring_bell_hook = IT_ring_bell;
2397 insert_glyphs_hook = IT_insert_glyphs;
2398 delete_glyphs_hook = IT_delete_glyphs;
2399 write_glyphs_hook = IT_write_glyphs;
2400 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
2401 clear_to_end_hook = IT_clear_to_end;
2402 clear_end_of_line_hook = IT_clear_end_of_line;
2403 clear_frame_hook = IT_clear_screen;
2404 change_line_highlight_hook = IT_change_line_highlight;
2405 update_begin_hook = IT_update_begin;
2406 update_end_hook = IT_update_end;
2407 reassert_line_highlight_hook = IT_reassert_line_highlight;
2408 frame_up_to_date_hook = IT_frame_up_to_date;
2410 /* These hooks are called by term.c without being checked. */
2411 set_terminal_modes_hook = IT_set_terminal_modes;
2412 reset_terminal_modes_hook = IT_reset_terminal_modes;
2413 set_terminal_window_hook = IT_set_terminal_window;
2414 char_ins_del_ok = 0;
2415 #endif
2418 dos_get_saved_screen (screen, rows, cols)
2419 char **screen;
2420 int *rows;
2421 int *cols;
2423 #ifndef HAVE_X_WINDOWS
2424 *screen = startup_screen_buffer;
2425 *cols = startup_screen_size_X;
2426 *rows = startup_screen_size_Y;
2427 return *screen != (char *)0;
2428 #else
2429 return 0;
2430 #endif
2433 #ifndef HAVE_X_WINDOWS
2435 /* We are not X, but we can emulate it well enough for our needs... */
2436 void
2437 check_x (void)
2439 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2440 error ("Not running under a window system");
2443 #endif
2446 /* ----------------------- Keyboard control ----------------------
2448 * Keymaps reflect the following keyboard layout:
2450 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2451 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2452 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2453 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2454 * SPACE
2457 #define Ignore 0x0000
2458 #define Normal 0x0000 /* normal key - alt changes scan-code */
2459 #define FctKey 0x1000 /* func key if c == 0, else c */
2460 #define Special 0x2000 /* func key even if c != 0 */
2461 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2462 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2463 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2464 #define Grey 0x6000 /* Grey keypad key */
2466 #define Alt 0x0100 /* alt scan-code */
2467 #define Ctrl 0x0200 /* ctrl scan-code */
2468 #define Shift 0x0400 /* shift scan-code */
2470 static int extended_kbd; /* 101 (102) keyboard present. */
2472 struct kbd_translate {
2473 unsigned char sc;
2474 unsigned char ch;
2475 unsigned short code;
2478 struct dos_keyboard_map
2480 char *unshifted;
2481 char *shifted;
2482 char *alt_gr;
2483 struct kbd_translate *translate_table;
2487 static struct dos_keyboard_map us_keyboard = {
2488 /* 0 1 2 3 4 5 */
2489 /* 01234567890123456789012345678901234567890 12345678901234 */
2490 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2491 /* 0123456789012345678901234567890123456789 012345678901234 */
2492 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2493 0, /* no Alt-Gr key */
2494 0 /* no translate table */
2497 static struct dos_keyboard_map fr_keyboard = {
2498 /* 0 1 2 3 4 5 */
2499 /* 012 3456789012345678901234567890123456789012345678901234 */
2500 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2501 /* 0123456789012345678901234567890123456789012345678901234 */
2502 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2503 /* 01234567 89012345678901234567890123456789012345678901234 */
2504 " ~#{[|`\\^@]} Ï ",
2505 0 /* no translate table */
2509 * Italian keyboard support, country code 39.
2510 * '<' 56:3c*0000
2511 * '>' 56:3e*0000
2512 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2513 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2516 static struct kbd_translate it_kbd_translate_table[] = {
2517 { 0x56, 0x3c, Normal | 13 },
2518 { 0x56, 0x3e, Normal | 27 },
2519 { 0, 0, 0 }
2521 static struct dos_keyboard_map it_keyboard = {
2522 /* 0 1 2 3 4 5 */
2523 /* 0 123456789012345678901234567890123456789012345678901234 */
2524 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2525 /* 01 23456789012345678901234567890123456789012345678901234 */
2526 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2527 /* 0123456789012345678901234567890123456789012345678901234 */
2528 " {}~` [] @# ",
2529 it_kbd_translate_table
2532 static struct dos_keyboard_map dk_keyboard = {
2533 /* 0 1 2 3 4 5 */
2534 /* 0123456789012345678901234567890123456789012345678901234 */
2535 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2536 /* 01 23456789012345678901234567890123456789012345678901234 */
2537 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2538 /* 0123456789012345678901234567890123456789012345678901234 */
2539 " @œ$ {[]} | ",
2540 0 /* no translate table */
2543 static struct kbd_translate jp_kbd_translate_table[] = {
2544 { 0x73, 0x5c, Normal | 0 },
2545 { 0x73, 0x5f, Normal | 0 },
2546 { 0x73, 0x1c, Map | 0 },
2547 { 0x7d, 0x5c, Normal | 13 },
2548 { 0x7d, 0x7c, Normal | 13 },
2549 { 0x7d, 0x1c, Map | 13 },
2550 { 0, 0, 0 }
2552 static struct dos_keyboard_map jp_keyboard = {
2553 /* 0 1 2 3 4 5 */
2554 /* 0123456789012 345678901234567890123456789012345678901234 */
2555 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2556 /* 01 23456789012345678901234567890123456789012345678901234 */
2557 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2558 0, /* no Alt-Gr key */
2559 jp_kbd_translate_table
2562 static struct keyboard_layout_list
2564 int country_code;
2565 struct dos_keyboard_map *keyboard_map;
2566 } keyboard_layout_list[] =
2568 1, &us_keyboard,
2569 33, &fr_keyboard,
2570 39, &it_keyboard,
2571 45, &dk_keyboard,
2572 81, &jp_keyboard
2575 static struct dos_keyboard_map *keyboard;
2576 static int keyboard_map_all;
2577 static int international_keyboard;
2580 dos_set_keyboard (code, always)
2581 int code;
2582 int always;
2584 int i;
2585 _go32_dpmi_registers regs;
2587 /* See if Keyb.Com is installed (for international keyboard support).
2588 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2589 of Windows 9X! So don't do that! */
2590 regs.x.ax = 0xad80;
2591 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2592 _go32_dpmi_simulate_int (0x2f, &regs);
2593 if (regs.h.al == 0xff)
2594 international_keyboard = 1;
2596 /* Initialize to US settings, for countries that don't have their own. */
2597 keyboard = keyboard_layout_list[0].keyboard_map;
2598 keyboard_map_all = always;
2599 dos_keyboard_layout = 1;
2601 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2602 if (code == keyboard_layout_list[i].country_code)
2604 keyboard = keyboard_layout_list[i].keyboard_map;
2605 keyboard_map_all = always;
2606 dos_keyboard_layout = code;
2607 return 1;
2609 return 0;
2612 static struct
2614 unsigned char char_code; /* normal code */
2615 unsigned char meta_code; /* M- code */
2616 unsigned char keypad_code; /* keypad code */
2617 unsigned char editkey_code; /* edit key */
2618 } keypad_translate_map[] = {
2619 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2620 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2621 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2622 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2623 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2624 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2625 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2626 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2627 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2628 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2629 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2632 static struct
2634 unsigned char char_code; /* normal code */
2635 unsigned char keypad_code; /* keypad code */
2636 } grey_key_translate_map[] = {
2637 '/', 0xaf, /* kp-decimal */
2638 '*', 0xaa, /* kp-multiply */
2639 '-', 0xad, /* kp-subtract */
2640 '+', 0xab, /* kp-add */
2641 '\r', 0x8d /* kp-enter */
2644 static unsigned short
2645 ibmpc_translate_map[] =
2647 /* --------------- 00 to 0f --------------- */
2648 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2649 Alt | ModFct | 0x1b, /* Escape */
2650 Normal | 1, /* '1' */
2651 Normal | 2, /* '2' */
2652 Normal | 3, /* '3' */
2653 Normal | 4, /* '4' */
2654 Normal | 5, /* '5' */
2655 Normal | 6, /* '6' */
2656 Normal | 7, /* '7' */
2657 Normal | 8, /* '8' */
2658 Normal | 9, /* '9' */
2659 Normal | 10, /* '0' */
2660 Normal | 11, /* '-' */
2661 Normal | 12, /* '=' */
2662 Special | 0x08, /* Backspace */
2663 ModFct | 0x74, /* Tab/Backtab */
2665 /* --------------- 10 to 1f --------------- */
2666 Map | 15, /* 'q' */
2667 Map | 16, /* 'w' */
2668 Map | 17, /* 'e' */
2669 Map | 18, /* 'r' */
2670 Map | 19, /* 't' */
2671 Map | 20, /* 'y' */
2672 Map | 21, /* 'u' */
2673 Map | 22, /* 'i' */
2674 Map | 23, /* 'o' */
2675 Map | 24, /* 'p' */
2676 Map | 25, /* '[' */
2677 Map | 26, /* ']' */
2678 ModFct | 0x0d, /* Return */
2679 Ignore, /* Ctrl */
2680 Map | 30, /* 'a' */
2681 Map | 31, /* 's' */
2683 /* --------------- 20 to 2f --------------- */
2684 Map | 32, /* 'd' */
2685 Map | 33, /* 'f' */
2686 Map | 34, /* 'g' */
2687 Map | 35, /* 'h' */
2688 Map | 36, /* 'j' */
2689 Map | 37, /* 'k' */
2690 Map | 38, /* 'l' */
2691 Map | 39, /* ';' */
2692 Map | 40, /* '\'' */
2693 Map | 0, /* '`' */
2694 Ignore, /* Left shift */
2695 Map | 41, /* '\\' */
2696 Map | 45, /* 'z' */
2697 Map | 46, /* 'x' */
2698 Map | 47, /* 'c' */
2699 Map | 48, /* 'v' */
2701 /* --------------- 30 to 3f --------------- */
2702 Map | 49, /* 'b' */
2703 Map | 50, /* 'n' */
2704 Map | 51, /* 'm' */
2705 Map | 52, /* ',' */
2706 Map | 53, /* '.' */
2707 Map | 54, /* '/' */
2708 Ignore, /* Right shift */
2709 Grey | 1, /* Grey * */
2710 Ignore, /* Alt */
2711 Normal | 55, /* ' ' */
2712 Ignore, /* Caps Lock */
2713 FctKey | 0xbe, /* F1 */
2714 FctKey | 0xbf, /* F2 */
2715 FctKey | 0xc0, /* F3 */
2716 FctKey | 0xc1, /* F4 */
2717 FctKey | 0xc2, /* F5 */
2719 /* --------------- 40 to 4f --------------- */
2720 FctKey | 0xc3, /* F6 */
2721 FctKey | 0xc4, /* F7 */
2722 FctKey | 0xc5, /* F8 */
2723 FctKey | 0xc6, /* F9 */
2724 FctKey | 0xc7, /* F10 */
2725 Ignore, /* Num Lock */
2726 Ignore, /* Scroll Lock */
2727 KeyPad | 7, /* Home */
2728 KeyPad | 8, /* Up */
2729 KeyPad | 9, /* Page Up */
2730 Grey | 2, /* Grey - */
2731 KeyPad | 4, /* Left */
2732 KeyPad | 5, /* Keypad 5 */
2733 KeyPad | 6, /* Right */
2734 Grey | 3, /* Grey + */
2735 KeyPad | 1, /* End */
2737 /* --------------- 50 to 5f --------------- */
2738 KeyPad | 2, /* Down */
2739 KeyPad | 3, /* Page Down */
2740 KeyPad | 0, /* Insert */
2741 KeyPad | 10, /* Delete */
2742 Shift | FctKey | 0xbe, /* (Shift) F1 */
2743 Shift | FctKey | 0xbf, /* (Shift) F2 */
2744 Shift | FctKey | 0xc0, /* (Shift) F3 */
2745 Shift | FctKey | 0xc1, /* (Shift) F4 */
2746 Shift | FctKey | 0xc2, /* (Shift) F5 */
2747 Shift | FctKey | 0xc3, /* (Shift) F6 */
2748 Shift | FctKey | 0xc4, /* (Shift) F7 */
2749 Shift | FctKey | 0xc5, /* (Shift) F8 */
2750 Shift | FctKey | 0xc6, /* (Shift) F9 */
2751 Shift | FctKey | 0xc7, /* (Shift) F10 */
2752 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2753 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2755 /* --------------- 60 to 6f --------------- */
2756 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2757 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2758 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2759 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2760 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2761 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2762 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2763 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2764 Alt | FctKey | 0xbe, /* (Alt) F1 */
2765 Alt | FctKey | 0xbf, /* (Alt) F2 */
2766 Alt | FctKey | 0xc0, /* (Alt) F3 */
2767 Alt | FctKey | 0xc1, /* (Alt) F4 */
2768 Alt | FctKey | 0xc2, /* (Alt) F5 */
2769 Alt | FctKey | 0xc3, /* (Alt) F6 */
2770 Alt | FctKey | 0xc4, /* (Alt) F7 */
2771 Alt | FctKey | 0xc5, /* (Alt) F8 */
2773 /* --------------- 70 to 7f --------------- */
2774 Alt | FctKey | 0xc6, /* (Alt) F9 */
2775 Alt | FctKey | 0xc7, /* (Alt) F10 */
2776 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2777 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2778 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2779 Ctrl | KeyPad | 1, /* (Ctrl) End */
2780 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2781 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2782 Alt | Map | 1, /* '1' */
2783 Alt | Map | 2, /* '2' */
2784 Alt | Map | 3, /* '3' */
2785 Alt | Map | 4, /* '4' */
2786 Alt | Map | 5, /* '5' */
2787 Alt | Map | 6, /* '6' */
2788 Alt | Map | 7, /* '7' */
2789 Alt | Map | 8, /* '8' */
2791 /* --------------- 80 to 8f --------------- */
2792 Alt | Map | 9, /* '9' */
2793 Alt | Map | 10, /* '0' */
2794 Alt | Map | 11, /* '-' */
2795 Alt | Map | 12, /* '=' */
2796 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2797 FctKey | 0xc8, /* F11 */
2798 FctKey | 0xc9, /* F12 */
2799 Shift | FctKey | 0xc8, /* (Shift) F11 */
2800 Shift | FctKey | 0xc9, /* (Shift) F12 */
2801 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2802 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2803 Alt | FctKey | 0xc8, /* (Alt) F11 */
2804 Alt | FctKey | 0xc9, /* (Alt) F12 */
2805 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2806 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2807 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2809 /* --------------- 90 to 9f --------------- */
2810 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2811 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2812 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2813 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2814 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2815 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2816 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2817 Alt | FctKey | 0x50, /* (Alt) Home */
2818 Alt | FctKey | 0x52, /* (Alt) Up */
2819 Alt | FctKey | 0x55, /* (Alt) Page Up */
2820 Ignore, /* NO KEY */
2821 Alt | FctKey | 0x51, /* (Alt) Left */
2822 Ignore, /* NO KEY */
2823 Alt | FctKey | 0x53, /* (Alt) Right */
2824 Ignore, /* NO KEY */
2825 Alt | FctKey | 0x57, /* (Alt) End */
2827 /* --------------- a0 to af --------------- */
2828 Alt | KeyPad | 2, /* (Alt) Down */
2829 Alt | KeyPad | 3, /* (Alt) Page Down */
2830 Alt | KeyPad | 0, /* (Alt) Insert */
2831 Alt | KeyPad | 10, /* (Alt) Delete */
2832 Alt | Grey | 0, /* (Alt) Grey / */
2833 Alt | FctKey | 0x09, /* (Alt) Tab */
2834 Alt | Grey | 4 /* (Alt) Keypad Enter */
2837 /* These bit-positions corresponds to values returned by BIOS */
2838 #define SHIFT_P 0x0003 /* two bits! */
2839 #define CTRL_P 0x0004
2840 #define ALT_P 0x0008
2841 #define SCRLOCK_P 0x0010
2842 #define NUMLOCK_P 0x0020
2843 #define CAPSLOCK_P 0x0040
2844 #define ALT_GR_P 0x0800
2845 #define SUPER_P 0x4000 /* pseudo */
2846 #define HYPER_P 0x8000 /* pseudo */
2848 static int
2849 dos_get_modifiers (keymask)
2850 int *keymask;
2852 union REGS regs;
2853 int mask;
2854 int modifiers = 0;
2856 /* Calculate modifier bits */
2857 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2858 int86 (0x16, &regs, &regs);
2860 if (!extended_kbd)
2862 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2863 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2865 else
2867 mask = regs.h.al & (SHIFT_P |
2868 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2870 /* Do not break international keyboard support. */
2871 /* When Keyb.Com is loaded, the right Alt key is */
2872 /* used for accessing characters like { and } */
2873 if (regs.h.ah & 2) /* Left ALT pressed ? */
2874 mask |= ALT_P;
2876 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2878 mask |= ALT_GR_P;
2879 if (dos_hyper_key == 1)
2881 mask |= HYPER_P;
2882 modifiers |= hyper_modifier;
2884 else if (dos_super_key == 1)
2886 mask |= SUPER_P;
2887 modifiers |= super_modifier;
2889 else if (!international_keyboard)
2891 /* If Keyb.Com is NOT installed, let Right Alt behave
2892 like the Left Alt. */
2893 mask &= ~ALT_GR_P;
2894 mask |= ALT_P;
2898 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2899 mask |= CTRL_P;
2901 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2903 if (dos_hyper_key == 2)
2905 mask |= HYPER_P;
2906 modifiers |= hyper_modifier;
2908 else if (dos_super_key == 2)
2910 mask |= SUPER_P;
2911 modifiers |= super_modifier;
2913 else
2914 mask |= CTRL_P;
2918 if (mask & SHIFT_P)
2919 modifiers |= shift_modifier;
2920 if (mask & CTRL_P)
2921 modifiers |= ctrl_modifier;
2922 if (mask & ALT_P)
2923 modifiers |= meta_modifier;
2925 if (keymask)
2926 *keymask = mask;
2927 return modifiers;
2930 #define NUM_RECENT_DOSKEYS (100)
2931 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2932 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2933 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2935 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2936 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2937 Each input key receives two values in this vector: first the ASCII code,\n\
2938 and then the scan code.")
2941 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
2942 Lisp_Object val;
2944 if (total_doskeys < NUM_RECENT_DOSKEYS)
2945 return Fvector (total_doskeys, keys);
2946 else
2948 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2949 bcopy (keys + recent_doskeys_index,
2950 XVECTOR (val)->contents,
2951 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2952 bcopy (keys,
2953 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2954 recent_doskeys_index * sizeof (Lisp_Object));
2955 return val;
2959 /* Get a char from keyboard. Function keys are put into the event queue. */
2961 extern void kbd_buffer_store_event (struct input_event *);
2963 static int
2964 dos_rawgetc ()
2966 struct input_event event;
2967 union REGS regs;
2969 #ifndef HAVE_X_WINDOWS
2970 /* Maybe put the cursor where it should be. */
2971 IT_cmgoto (SELECTED_FRAME());
2972 #endif
2974 /* The following condition is equivalent to `kbhit ()', except that
2975 it uses the bios to do its job. This pleases DESQview/X. */
2976 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2977 int86 (0x16, &regs, &regs),
2978 (regs.x.flags & 0x40) == 0)
2980 union REGS regs;
2981 register unsigned char c;
2982 int sc, code = -1, mask, kp_mode;
2983 int modifiers;
2985 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2986 int86 (0x16, &regs, &regs);
2987 c = regs.h.al;
2988 sc = regs.h.ah;
2990 total_doskeys += 2;
2991 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2992 = make_number (c);
2993 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2994 recent_doskeys_index = 0;
2995 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2996 = make_number (sc);
2997 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2998 recent_doskeys_index = 0;
3000 modifiers = dos_get_modifiers (&mask);
3002 #ifndef HAVE_X_WINDOWS
3003 if (!NILP (Vdos_display_scancodes))
3005 char buf[11];
3006 sprintf (buf, "%02x:%02x*%04x",
3007 (unsigned) (sc&0xff), (unsigned) c, mask);
3008 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
3010 #endif
3012 if (sc == 0xe0)
3014 switch (c)
3016 case 10: /* Ctrl Grey Enter */
3017 code = Ctrl | Grey | 4;
3018 break;
3019 case 13: /* Grey Enter */
3020 code = Grey | 4;
3021 break;
3022 case '/': /* Grey / */
3023 code = Grey | 0;
3024 break;
3025 default:
3026 continue;
3028 c = 0;
3030 else
3032 /* Try the keyboard-private translation table first. */
3033 if (keyboard->translate_table)
3035 struct kbd_translate *p = keyboard->translate_table;
3037 while (p->sc)
3039 if (p->sc == sc && p->ch == c)
3041 code = p->code;
3042 break;
3044 p++;
3047 /* If the private table didn't translate it, use the general
3048 one. */
3049 if (code == -1)
3051 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3052 continue;
3053 if ((code = ibmpc_translate_map[sc]) == Ignore)
3054 continue;
3058 if (c == 0)
3060 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3061 Emacs is ready to read a key. Therefore, if they press
3062 `Alt-x' when Emacs is busy, by the time we get to
3063 `dos_get_modifiers', they might have already released the
3064 Alt key, and Emacs gets just `x', which is BAD.
3065 However, for keys with the `Map' property set, the ASCII
3066 code returns zero iff Alt is pressed. So, when we DON'T
3067 have to support international_keyboard, we don't have to
3068 distinguish between the left and right Alt keys, and we
3069 can set the META modifier for any keys with the `Map'
3070 property if they return zero ASCII code (c = 0). */
3071 if ( (code & Alt)
3072 || ( (code & 0xf000) == Map && !international_keyboard))
3073 modifiers |= meta_modifier;
3074 if (code & Ctrl)
3075 modifiers |= ctrl_modifier;
3076 if (code & Shift)
3077 modifiers |= shift_modifier;
3080 switch (code & 0xf000)
3082 case ModFct:
3083 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3084 return c;
3085 c = 0; /* Special */
3087 case FctKey:
3088 if (c != 0)
3089 return c;
3091 case Special:
3092 code |= 0xff00;
3093 break;
3095 case Normal:
3096 if (sc == 0)
3098 if (c == 0) /* ctrl-break */
3099 continue;
3100 return c; /* ALT-nnn */
3102 if (!keyboard_map_all)
3104 if (c != ' ')
3105 return c;
3106 code = c;
3107 break;
3110 case Map:
3111 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3112 if (!keyboard_map_all)
3113 return c;
3115 code &= 0xff;
3116 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3117 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3119 if (mask & SHIFT_P)
3121 code = keyboard->shifted[code];
3122 mask -= SHIFT_P;
3123 modifiers &= ~shift_modifier;
3125 else
3126 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3127 code = keyboard->alt_gr[code];
3128 else
3129 code = keyboard->unshifted[code];
3130 break;
3132 case KeyPad:
3133 code &= 0xff;
3134 if (c == 0xe0) /* edit key */
3135 kp_mode = 3;
3136 else
3137 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3138 kp_mode = dos_keypad_mode & 0x03;
3139 else
3140 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3142 switch (kp_mode)
3144 case 0:
3145 if (code == 10 && dos_decimal_point)
3146 return dos_decimal_point;
3147 return keypad_translate_map[code].char_code;
3149 case 1:
3150 code = 0xff00 | keypad_translate_map[code].keypad_code;
3151 break;
3153 case 2:
3154 code = keypad_translate_map[code].meta_code;
3155 modifiers = meta_modifier;
3156 break;
3158 case 3:
3159 code = 0xff00 | keypad_translate_map[code].editkey_code;
3160 break;
3162 break;
3164 case Grey:
3165 code &= 0xff;
3166 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3167 if (dos_keypad_mode & kp_mode)
3168 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3169 else
3170 code = grey_key_translate_map[code].char_code;
3171 break;
3174 make_event:
3175 if (code == 0)
3176 continue;
3178 if (code >= 0x100)
3179 event.kind = non_ascii_keystroke;
3180 else
3181 event.kind = ascii_keystroke;
3182 event.code = code;
3183 event.modifiers = modifiers;
3184 event.frame_or_window = selected_frame;
3185 event.timestamp = event_timestamp ();
3186 kbd_buffer_store_event (&event);
3189 if (have_mouse > 0 && !mouse_preempted)
3191 int but, press, x, y, ok;
3192 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3194 /* Check for mouse movement *before* buttons. */
3195 mouse_check_moved ();
3197 /* If the mouse moved from the spot of its last sighting, we
3198 might need to update mouse highlight. */
3199 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3201 previous_help_echo = help_echo;
3202 help_echo = Qnil;
3203 IT_note_mouse_highlight (SELECTED_FRAME(),
3204 mouse_last_x, mouse_last_y);
3205 /* If the contents of the global variable help_echo has
3206 changed, generate a HELP_EVENT. */
3207 if (STRINGP (help_echo) || STRINGP (previous_help_echo))
3209 event.kind = HELP_EVENT;
3210 event.frame_or_window = Fcons (selected_frame, help_echo);
3211 event.timestamp = event_timestamp ();
3212 kbd_buffer_store_event (&event);
3216 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3217 for (press = 0; press < 2; press++)
3219 int button_num = but;
3221 if (press)
3222 ok = mouse_pressed (but, &x, &y);
3223 else
3224 ok = mouse_released (but, &x, &y);
3225 if (ok)
3227 /* Allow a simultaneous press/release of Mouse-1 and
3228 Mouse-2 to simulate Mouse-3 on two-button mice. */
3229 if (mouse_button_count == 2 && but < 2)
3231 int x2, y2; /* don't clobber original coordinates */
3233 /* If only one button is pressed, wait 100 msec and
3234 check again. This way, Speedy Gonzales isn't
3235 punished, while the slow get their chance. */
3236 if (press && mouse_pressed (1-but, &x2, &y2)
3237 || !press && mouse_released (1-but, &x2, &y2))
3238 button_num = 2;
3239 else
3241 delay (100);
3242 if (press && mouse_pressed (1-but, &x2, &y2)
3243 || !press && mouse_released (1-but, &x2, &y2))
3244 button_num = 2;
3248 event.kind = mouse_click;
3249 event.code = button_num;
3250 event.modifiers = dos_get_modifiers (0)
3251 | (press ? down_modifier : up_modifier);
3252 event.x = x;
3253 event.y = y;
3254 event.frame_or_window = selected_frame;
3255 event.timestamp = event_timestamp ();
3256 kbd_buffer_store_event (&event);
3261 return -1;
3264 static int prev_get_char = -1;
3266 /* Return 1 if a key is ready to be read without suspending execution. */
3268 dos_keysns ()
3270 if (prev_get_char != -1)
3271 return 1;
3272 else
3273 return ((prev_get_char = dos_rawgetc ()) != -1);
3276 /* Read a key. Return -1 if no key is ready. */
3278 dos_keyread ()
3280 if (prev_get_char != -1)
3282 int c = prev_get_char;
3283 prev_get_char = -1;
3284 return c;
3286 else
3287 return dos_rawgetc ();
3290 #ifndef HAVE_X_WINDOWS
3291 /* See xterm.c for more info. */
3292 void
3293 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
3294 FRAME_PTR f;
3295 register int pix_x, pix_y;
3296 register int *x, *y;
3297 XRectangle *bounds;
3298 int noclip;
3300 if (bounds) abort ();
3302 /* Ignore clipping. */
3304 *x = pix_x;
3305 *y = pix_y;
3308 void
3309 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
3310 FRAME_PTR f;
3311 register int x, y;
3312 register int *pix_x, *pix_y;
3314 *pix_x = x;
3315 *pix_y = y;
3318 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3319 for now.
3321 Actually, I don't know the meaning of all the parameters of the functions
3322 here -- I only know how they are called by xmenu.c. I could of course
3323 grab the nearest Xlib manual (down the hall, second-to-last door on the
3324 left), but I don't think it's worth the effort. */
3326 static char *menu_help_message, *prev_menu_help_message;
3328 static XMenu *
3329 IT_menu_create ()
3331 XMenu *menu;
3333 menu = (XMenu *) xmalloc (sizeof (XMenu));
3334 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3335 return menu;
3338 /* Allocate some (more) memory for MENU ensuring that there is room for one
3339 for item. */
3341 static void
3342 IT_menu_make_room (XMenu *menu)
3344 if (menu->allocated == 0)
3346 int count = menu->allocated = 10;
3347 menu->text = (char **) xmalloc (count * sizeof (char *));
3348 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3349 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3350 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3352 else if (menu->allocated == menu->count)
3354 int count = menu->allocated = menu->allocated + 10;
3355 menu->text
3356 = (char **) xrealloc (menu->text, count * sizeof (char *));
3357 menu->submenu
3358 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3359 menu->panenumber
3360 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3361 menu->help_text
3362 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3366 /* Search the given menu structure for a given pane number. */
3368 static XMenu *
3369 IT_menu_search_pane (XMenu *menu, int pane)
3371 int i;
3372 XMenu *try;
3374 for (i = 0; i < menu->count; i++)
3375 if (menu->submenu[i])
3377 if (pane == menu->panenumber[i])
3378 return menu->submenu[i];
3379 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3380 return try;
3382 return (XMenu *) 0;
3385 /* Determine how much screen space a given menu needs. */
3387 static void
3388 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3390 int i, h2, w2, maxsubwidth, maxheight;
3392 maxsubwidth = 0;
3393 maxheight = menu->count;
3394 for (i = 0; i < menu->count; i++)
3396 if (menu->submenu[i])
3398 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3399 if (w2 > maxsubwidth) maxsubwidth = w2;
3400 if (i + h2 > maxheight) maxheight = i + h2;
3403 *width = menu->width + maxsubwidth;
3404 *height = maxheight;
3407 /* Display MENU at (X,Y) using FACES. */
3409 static void
3410 IT_menu_display (XMenu *menu, int y, int x, int *faces, int disp_help)
3412 int i, j, face, width;
3413 struct glyph *text, *p;
3414 char *q;
3415 int mx, my;
3416 int enabled, mousehere;
3417 int row, col;
3418 struct frame *sf = SELECTED_FRAME();
3420 menu_help_message = NULL;
3422 width = menu->width;
3423 text = (struct glyph *) xmalloc ((width + 2) * sizeof (struct glyph));
3424 ScreenGetCursor (&row, &col);
3425 mouse_get_xy (&mx, &my);
3426 IT_update_begin (sf);
3427 for (i = 0; i < menu->count; i++)
3429 int max_width = width + 2;
3431 IT_cursor_to (y + i, x);
3432 enabled
3433 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3434 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
3435 face = faces[enabled + mousehere * 2];
3436 if (disp_help && enabled + mousehere * 2 >= 2)
3437 menu_help_message = menu->help_text[i];
3438 p = text;
3439 SET_CHAR_GLYPH (*p, ' ', face, 0);
3440 p++;
3441 for (j = 0, q = menu->text[i]; *q; j++)
3443 if (*q > 26)
3445 SET_CHAR_GLYPH (*p, *q++, face, 0);
3446 p++;
3448 else /* make '^x' */
3450 SET_CHAR_GLYPH (*p, '^', face, 0);
3451 p++;
3452 j++;
3453 SET_CHAR_GLYPH (*p, *q++ + 64, face, 0);
3454 p++;
3457 /* Don't let the menu text overflow into the next screen row. */
3458 if (x + max_width > screen_size_X)
3460 max_width = screen_size_X - x;
3461 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3463 for (; j < max_width - 2; j++, p++)
3464 SET_CHAR_GLYPH (*p, ' ', face, 0);
3466 SET_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3467 p++;
3468 IT_write_glyphs (text, max_width);
3470 IT_update_end (sf);
3471 IT_cursor_to (row, col);
3472 xfree (text);
3475 /* --------------------------- X Menu emulation ---------------------- */
3477 /* Report availability of menus. */
3480 have_menus_p ()
3482 return 1;
3485 /* Create a brand new menu structure. */
3487 XMenu *
3488 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3490 return IT_menu_create ();
3493 /* Create a new pane and place it on the outer-most level. It is not
3494 clear that it should be placed out there, but I don't know what else
3495 to do. */
3498 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3500 int len;
3501 char *p;
3503 if (!enable)
3504 abort ();
3506 IT_menu_make_room (menu);
3507 menu->submenu[menu->count] = IT_menu_create ();
3508 menu->text[menu->count] = txt;
3509 menu->panenumber[menu->count] = ++menu->panecount;
3510 menu->help_text[menu->count] = NULL;
3511 menu->count++;
3513 /* Adjust length for possible control characters (which will
3514 be written as ^x). */
3515 for (len = strlen (txt), p = txt; *p; p++)
3516 if (*p < 27)
3517 len++;
3519 if (len > menu->width)
3520 menu->width = len;
3522 return menu->panecount;
3525 /* Create a new item in a menu pane. */
3528 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3529 int foo, char *txt, int enable, char *help_text)
3531 int len;
3532 char *p;
3534 if (pane)
3535 if (!(menu = IT_menu_search_pane (menu, pane)))
3536 return XM_FAILURE;
3537 IT_menu_make_room (menu);
3538 menu->submenu[menu->count] = (XMenu *) 0;
3539 menu->text[menu->count] = txt;
3540 menu->panenumber[menu->count] = enable;
3541 menu->help_text[menu->count] = help_text;
3542 menu->count++;
3544 /* Adjust length for possible control characters (which will
3545 be written as ^x). */
3546 for (len = strlen (txt), p = txt; *p; p++)
3547 if (*p < 27)
3548 len++;
3550 if (len > menu->width)
3551 menu->width = len;
3553 return XM_SUCCESS;
3556 /* Decide where the menu would be placed if requested at (X,Y). */
3558 void
3559 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3560 int *ulx, int *uly, int *width, int *height)
3562 IT_menu_calc_size (menu, width, height);
3563 *ulx = x + 1;
3564 *uly = y;
3565 *width += 2;
3568 struct IT_menu_state
3570 void *screen_behind;
3571 XMenu *menu;
3572 int pane;
3573 int x, y;
3577 /* Display menu, wait for user's response, and return that response. */
3580 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3581 int x0, int y0, unsigned ButtonMask, char **txt,
3582 void (*help_callback)(char *))
3584 struct IT_menu_state *state;
3585 int statecount;
3586 int x, y, i, b;
3587 int screensize;
3588 int faces[4];
3589 Lisp_Object selectface;
3590 int leave, result, onepane;
3591 int title_faces[4]; /* face to display the menu title */
3592 int buffers_num_deleted = 0;
3593 struct frame *sf = SELECTED_FRAME();
3595 /* Just in case we got here without a mouse present... */
3596 if (have_mouse <= 0)
3597 return XM_IA_SELECT;
3598 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3599 around the display. */
3600 if (x0 <= 0)
3601 x0 = 1;
3602 if (y0 <= 0)
3603 y0 = 1;
3605 /* We will process all the mouse events directly, so we had
3606 better prevented dos_rawgetc from stealing them from us. */
3607 mouse_preempted++;
3609 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3610 screensize = screen_size * 2;
3611 faces[0]
3612 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3613 0, DEFAULT_FACE_ID);
3614 faces[1]
3615 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3616 0, DEFAULT_FACE_ID);
3617 selectface = intern ("msdos-menu-select-face");
3618 faces[2] = lookup_derived_face (sf, selectface,
3619 0, faces[0]);
3620 faces[3] = lookup_derived_face (sf, selectface,
3621 0, faces[1]);
3623 /* Make sure the menu title is always displayed with
3624 `msdos-menu-active-face', no matter where the mouse pointer is. */
3625 for (i = 0; i < 4; i++)
3626 title_faces[i] = faces[3];
3628 statecount = 1;
3630 /* Don't let the title for the "Buffers" popup menu include a
3631 digit (which is ugly).
3633 This is a terrible kludge, but I think the "Buffers" case is
3634 the only one where the title includes a number, so it doesn't
3635 seem to be necessary to make this more general. */
3636 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3638 menu->text[0][7] = '\0';
3639 buffers_num_deleted = 1;
3641 state[0].menu = menu;
3642 mouse_off ();
3643 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3645 /* Turn off the cursor. Otherwise it shows through the menu
3646 panes, which is ugly. */
3647 IT_display_cursor (0);
3649 /* Display the menu title. */
3650 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces, 0);
3651 if (buffers_num_deleted)
3652 menu->text[0][7] = ' ';
3653 if ((onepane = menu->count == 1 && menu->submenu[0]))
3655 menu->width = menu->submenu[0]->width;
3656 state[0].menu = menu->submenu[0];
3658 else
3660 state[0].menu = menu;
3662 state[0].x = x0 - 1;
3663 state[0].y = y0;
3664 state[0].pane = onepane;
3666 mouse_last_x = -1; /* A hack that forces display. */
3667 leave = 0;
3668 while (!leave)
3670 if (!mouse_visible) mouse_on ();
3671 mouse_check_moved ();
3672 if (sf->mouse_moved)
3674 sf->mouse_moved = 0;
3675 result = XM_IA_SELECT;
3676 mouse_get_xy (&x, &y);
3677 for (i = 0; i < statecount; i++)
3678 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3680 int dy = y - state[i].y;
3681 if (0 <= dy && dy < state[i].menu->count)
3683 if (!state[i].menu->submenu[dy])
3684 if (state[i].menu->panenumber[dy])
3685 result = XM_SUCCESS;
3686 else
3687 result = XM_IA_SELECT;
3688 *pane = state[i].pane - 1;
3689 *selidx = dy;
3690 /* We hit some part of a menu, so drop extra menus that
3691 have been opened. That does not include an open and
3692 active submenu. */
3693 if (i != statecount - 2
3694 || state[i].menu->submenu[dy] != state[i+1].menu)
3695 while (i != statecount - 1)
3697 statecount--;
3698 mouse_off ();
3699 ScreenUpdate (state[statecount].screen_behind);
3700 if (screen_virtual_segment)
3701 dosv_refresh_virtual_screen (0, screen_size);
3702 xfree (state[statecount].screen_behind);
3704 if (i == statecount - 1 && state[i].menu->submenu[dy])
3706 IT_menu_display (state[i].menu,
3707 state[i].y,
3708 state[i].x,
3709 faces, 1);
3710 state[statecount].menu = state[i].menu->submenu[dy];
3711 state[statecount].pane = state[i].menu->panenumber[dy];
3712 mouse_off ();
3713 ScreenRetrieve (state[statecount].screen_behind
3714 = xmalloc (screensize));
3715 state[statecount].x
3716 = state[i].x + state[i].menu->width + 2;
3717 state[statecount].y = y;
3718 statecount++;
3722 IT_menu_display (state[statecount - 1].menu,
3723 state[statecount - 1].y,
3724 state[statecount - 1].x,
3725 faces, 1);
3727 else
3729 if ((menu_help_message || prev_menu_help_message)
3730 && menu_help_message != prev_menu_help_message)
3732 help_callback (menu_help_message);
3733 IT_display_cursor (0);
3734 prev_menu_help_message = menu_help_message;
3736 /* We are busy-waiting for the mouse to move, so let's be nice
3737 to other Windows applications by releasing our time slice. */
3738 __dpmi_yield ();
3740 for (b = 0; b < mouse_button_count && !leave; b++)
3742 /* Only leave if user both pressed and released the mouse, and in
3743 that order. This avoids popping down the menu pane unless
3744 the user is really done with it. */
3745 if (mouse_pressed (b, &x, &y))
3747 while (mouse_button_depressed (b, &x, &y))
3748 __dpmi_yield ();
3749 leave = 1;
3751 (void) mouse_released (b, &x, &y);
3755 mouse_off ();
3756 ScreenUpdate (state[0].screen_behind);
3757 if (screen_virtual_segment)
3758 dosv_refresh_virtual_screen (0, screen_size);
3759 message (0);
3760 while (statecount--)
3761 xfree (state[statecount].screen_behind);
3762 IT_display_cursor (1); /* turn cursor back on */
3763 /* Clean up any mouse events that are waiting inside Emacs event queue.
3764 These events are likely to be generated before the menu was even
3765 displayed, probably because the user pressed and released the button
3766 (which invoked the menu) too quickly. If we don't remove these events,
3767 Emacs will process them after we return and surprise the user. */
3768 discard_mouse_events ();
3769 /* Allow mouse events generation by dos_rawgetc. */
3770 mouse_preempted--;
3771 return result;
3774 /* Dispose of a menu. */
3776 void
3777 XMenuDestroy (Display *foo, XMenu *menu)
3779 int i;
3780 if (menu->allocated)
3782 for (i = 0; i < menu->count; i++)
3783 if (menu->submenu[i])
3784 XMenuDestroy (foo, menu->submenu[i]);
3785 xfree (menu->text);
3786 xfree (menu->submenu);
3787 xfree (menu->panenumber);
3788 xfree (menu->help_text);
3790 xfree (menu);
3791 menu_help_message = prev_menu_help_message = NULL;
3795 x_pixel_width (struct frame *f)
3797 return FRAME_WIDTH (f);
3801 x_pixel_height (struct frame *f)
3803 return FRAME_HEIGHT (f);
3805 #endif /* !HAVE_X_WINDOWS */
3807 /* ----------------------- DOS / UNIX conversion --------------------- */
3809 void msdos_downcase_filename (unsigned char *);
3811 /* Destructively turn backslashes into slashes. */
3813 void
3814 dostounix_filename (p)
3815 register char *p;
3817 msdos_downcase_filename (p);
3819 while (*p)
3821 if (*p == '\\')
3822 *p = '/';
3823 p++;
3827 /* Destructively turn slashes into backslashes. */
3829 void
3830 unixtodos_filename (p)
3831 register char *p;
3833 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3835 *p += 'a' - 'A';
3836 p += 2;
3839 while (*p)
3841 if (*p == '/')
3842 *p = '\\';
3843 p++;
3847 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3850 getdefdir (drive, dst)
3851 int drive;
3852 char *dst;
3854 char in_path[4], *p = in_path;
3855 int e = errno;
3857 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3858 if (drive != 0)
3860 *p++ = drive + 'A' - 1;
3861 *p++ = ':';
3864 *p++ = '.';
3865 *p = '\0';
3866 errno = 0;
3867 _fixpath (in_path, dst);
3868 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3869 it queries the LFN support, so ignore that error. */
3870 if ((errno && errno != ENOSYS) || *dst == '\0')
3871 return 0;
3873 msdos_downcase_filename (dst);
3875 errno = e;
3876 return 1;
3879 /* Remove all CR's that are followed by a LF. */
3882 crlf_to_lf (n, buf)
3883 register int n;
3884 register unsigned char *buf;
3886 unsigned char *np = buf;
3887 unsigned char *startp = buf;
3888 unsigned char *endp = buf + n;
3890 if (n == 0)
3891 return n;
3892 while (buf < endp - 1)
3894 if (*buf == 0x0d)
3896 if (*(++buf) != 0x0a)
3897 *np++ = 0x0d;
3899 else
3900 *np++ = *buf++;
3902 if (buf < endp)
3903 *np++ = *buf++;
3904 return np - startp;
3907 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
3909 /* In DJGPP v2.0, library `write' can call `malloc', which might
3910 cause relocation of the buffer whose address we get in ADDR.
3911 Here is a version of `write' that avoids calling `malloc',
3912 to serve us until such time as the library is fixed.
3913 Actually, what we define here is called `__write', because
3914 `write' is a stub that just jmp's to `__write' (to be
3915 POSIXLY-correct with respect to the global name-space). */
3917 #include <io.h> /* for _write */
3918 #include <libc/dosio.h> /* for __file_handle_modes[] */
3920 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
3922 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
3925 __write (int handle, const void *buffer, size_t count)
3927 if (count == 0)
3928 return 0;
3930 if(__file_handle_modes[handle] & O_BINARY)
3931 return _write (handle, buffer, count);
3932 else
3934 char *xbp = xbuf;
3935 const char *bp = buffer;
3936 int total_written = 0;
3937 int nmoved = 0, ncr = 0;
3939 while (count)
3941 /* The next test makes sure there's space for at least 2 more
3942 characters in xbuf[], so both CR and LF can be put there. */
3943 if (xbp < XBUF_END)
3945 if (*bp == '\n')
3947 ncr++;
3948 *xbp++ = '\r';
3950 *xbp++ = *bp++;
3951 nmoved++;
3952 count--;
3954 if (xbp >= XBUF_END || !count)
3956 size_t to_write = nmoved + ncr;
3957 int written = _write (handle, xbuf, to_write);
3959 if (written == -1)
3960 return -1;
3961 else
3962 total_written += nmoved; /* CRs aren't counted in ret value */
3964 /* If some, but not all were written (disk full?), return
3965 an estimate of the total written bytes not counting CRs. */
3966 if (written < to_write)
3967 return total_written - (to_write - written) * nmoved/to_write;
3969 nmoved = 0;
3970 ncr = 0;
3971 xbp = xbuf;
3974 return total_written;
3978 /* A low-level file-renaming function which works around Windows 95 bug.
3979 This is pulled directly out of DJGPP v2.01 library sources, and only
3980 used when you compile with DJGPP v2.0. */
3982 #include <io.h>
3984 int _rename(const char *old, const char *new)
3986 __dpmi_regs r;
3987 int olen = strlen(old) + 1;
3988 int i;
3989 int use_lfn = _USE_LFN;
3990 char tempfile[FILENAME_MAX];
3991 const char *orig = old;
3992 int lfn_fd = -1;
3994 r.x.dx = __tb_offset;
3995 r.x.di = __tb_offset + olen;
3996 r.x.ds = r.x.es = __tb_segment;
3998 if (use_lfn)
4000 /* Windows 95 bug: for some filenames, when you rename
4001 file -> file~ (as in Emacs, to leave a backup), the
4002 short 8+3 alias doesn't change, which effectively
4003 makes OLD and NEW the same file. We must rename
4004 through a temporary file to work around this. */
4006 char *pbase = 0, *p;
4007 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
4008 int idx = sizeof(try_char) - 1;
4010 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4011 might point to another drive, which will fail the DOS call. */
4012 strcpy(tempfile, old);
4013 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
4014 if (*p == '/' || *p == '\\' || *p == ':')
4015 pbase = p;
4016 if (pbase)
4017 pbase++;
4018 else
4019 pbase = tempfile;
4020 strcpy(pbase, "X$$djren$$.$$temp$$");
4024 if (idx <= 0)
4025 return -1;
4026 *pbase = try_char[--idx];
4027 } while (_chmod(tempfile, 0) != -1);
4029 r.x.ax = 0x7156;
4030 _put_path2(tempfile, olen);
4031 _put_path(old);
4032 __dpmi_int(0x21, &r);
4033 if (r.x.flags & 1)
4035 errno = __doserr_to_errno(r.x.ax);
4036 return -1;
4039 /* Now create a file with the original name. This will
4040 ensure that NEW will always have a 8+3 alias
4041 different from that of OLD. (Seems to be required
4042 when NameNumericTail in the Registry is set to 0.) */
4043 lfn_fd = _creat(old, 0);
4045 olen = strlen(tempfile) + 1;
4046 old = tempfile;
4047 r.x.di = __tb_offset + olen;
4050 for (i=0; i<2; i++)
4052 if(use_lfn)
4053 r.x.ax = 0x7156;
4054 else
4055 r.h.ah = 0x56;
4056 _put_path2(new, olen);
4057 _put_path(old);
4058 __dpmi_int(0x21, &r);
4059 if(r.x.flags & 1)
4061 if (r.x.ax == 5 && i == 0) /* access denied */
4062 remove(new); /* and try again */
4063 else
4065 errno = __doserr_to_errno(r.x.ax);
4067 /* Restore to original name if we renamed it to temporary. */
4068 if (use_lfn)
4070 if (lfn_fd != -1)
4072 _close (lfn_fd);
4073 remove (orig);
4075 _put_path2(orig, olen);
4076 _put_path(tempfile);
4077 r.x.ax = 0x7156;
4078 __dpmi_int(0x21, &r);
4080 return -1;
4083 else
4084 break;
4087 /* Success. Delete the file possibly created to work
4088 around the Windows 95 bug. */
4089 if (lfn_fd != -1)
4090 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
4091 return 0;
4094 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4096 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
4097 0, 0, 0,
4098 "Return non-nil if long file names are supported on MSDOS.")
4101 return (_USE_LFN ? Qt : Qnil);
4104 /* Convert alphabetic characters in a filename to lower-case. */
4106 void
4107 msdos_downcase_filename (p)
4108 register unsigned char *p;
4110 /* Always lower-case drive letters a-z, even if the filesystem
4111 preserves case in filenames.
4112 This is so MSDOS filenames could be compared by string comparison
4113 functions that are case-sensitive. Even case-preserving filesystems
4114 do not distinguish case in drive letters. */
4115 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4117 *p += 'a' - 'A';
4118 p += 2;
4121 /* Under LFN we expect to get pathnames in their true case. */
4122 if (NILP (Fmsdos_long_file_names ()))
4123 for ( ; *p; p++)
4124 if (*p >= 'A' && *p <= 'Z')
4125 *p += 'a' - 'A';
4128 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
4129 1, 1, 0,
4130 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4131 When long filenames are supported, doesn't change FILENAME.\n\
4132 If FILENAME is not a string, returns nil.\n\
4133 The argument object is never altered--the value is a copy.")
4134 (filename)
4135 Lisp_Object filename;
4137 Lisp_Object tem;
4139 if (! STRINGP (filename))
4140 return Qnil;
4142 tem = Fcopy_sequence (filename);
4143 msdos_downcase_filename (XSTRING (tem)->data);
4144 return tem;
4147 /* The Emacs root directory as determined by init_environment. */
4149 static char emacsroot[MAXPATHLEN];
4151 char *
4152 rootrelativepath (rel)
4153 char *rel;
4155 static char result[MAXPATHLEN + 10];
4157 strcpy (result, emacsroot);
4158 strcat (result, "/");
4159 strcat (result, rel);
4160 return result;
4163 /* Define a lot of environment variables if not already defined. Don't
4164 remove anything unless you know what you're doing -- lots of code will
4165 break if one or more of these are missing. */
4167 void
4168 init_environment (argc, argv, skip_args)
4169 int argc;
4170 char **argv;
4171 int skip_args;
4173 char *s, *t, *root;
4174 int len;
4175 static const char * const tempdirs[] = {
4176 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4178 int i;
4179 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4181 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4182 temporary files and assume "/tmp" if $TMPDIR is unset, which
4183 will break on DOS/Windows. Refuse to work if we cannot find
4184 a directory, not even "c:/", usable for that purpose. */
4185 for (i = 0; i < imax ; i++)
4187 const char *tmp = tempdirs[i];
4189 if (*tmp == '$')
4190 tmp = getenv (tmp + 1);
4191 /* Note that `access' can lie to us if the directory resides on a
4192 read-only filesystem, like CD-ROM or a write-protected floppy.
4193 The only way to be really sure is to actually create a file and
4194 see if it succeeds. But I think that's too much to ask. */
4195 if (tmp && access (tmp, D_OK) == 0)
4197 setenv ("TMPDIR", tmp, 1);
4198 break;
4201 if (i >= imax)
4202 cmd_error_internal
4203 (Fcons (Qerror,
4204 Fcons (build_string ("no usable temporary directories found!!"),
4205 Qnil)),
4206 "While setting TMPDIR: ");
4208 /* Note the startup time, so we know not to clear the screen if we
4209 exit immediately; see IT_reset_terminal_modes.
4210 (Yes, I know `clock' returns zero the first time it's called, but
4211 I do this anyway, in case some wiseguy changes that at some point.) */
4212 startup_time = clock ();
4214 /* Find our root from argv[0]. Assuming argv[0] is, say,
4215 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4216 root = alloca (MAXPATHLEN + 20);
4217 _fixpath (argv[0], root);
4218 msdos_downcase_filename (root);
4219 len = strlen (root);
4220 while (len > 0 && root[len] != '/' && root[len] != ':')
4221 len--;
4222 root[len] = '\0';
4223 if (len > 4
4224 && (strcmp (root + len - 4, "/bin") == 0
4225 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4226 root[len - 4] = '\0';
4227 else
4228 strcpy (root, "c:/emacs"); /* let's be defensive */
4229 len = strlen (root);
4230 strcpy (emacsroot, root);
4232 /* We default HOME to our root. */
4233 setenv ("HOME", root, 0);
4235 /* We default EMACSPATH to root + "/bin". */
4236 strcpy (root + len, "/bin");
4237 setenv ("EMACSPATH", root, 0);
4239 /* I don't expect anybody to ever use other terminals so the internal
4240 terminal is the default. */
4241 setenv ("TERM", "internal", 0);
4243 #ifdef HAVE_X_WINDOWS
4244 /* Emacs expects DISPLAY to be set. */
4245 setenv ("DISPLAY", "unix:0.0", 0);
4246 #endif
4248 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4249 downcase it and mirror the backslashes. */
4250 s = getenv ("COMSPEC");
4251 if (!s) s = "c:/command.com";
4252 t = alloca (strlen (s) + 1);
4253 strcpy (t, s);
4254 dostounix_filename (t);
4255 setenv ("SHELL", t, 0);
4257 /* PATH is also downcased and backslashes mirrored. */
4258 s = getenv ("PATH");
4259 if (!s) s = "";
4260 t = alloca (strlen (s) + 3);
4261 /* Current directory is always considered part of MsDos's path but it is
4262 not normally mentioned. Now it is. */
4263 strcat (strcpy (t, ".;"), s);
4264 dostounix_filename (t); /* Not a single file name, but this should work. */
4265 setenv ("PATH", t, 1);
4267 /* In some sense all dos users have root privileges, so... */
4268 setenv ("USER", "root", 0);
4269 setenv ("NAME", getenv ("USER"), 0);
4271 /* Time zone determined from country code. To make this possible, the
4272 country code may not span more than one time zone. In other words,
4273 in the USA, you lose. */
4274 if (!getenv ("TZ"))
4275 switch (dos_country_code)
4277 case 31: /* Belgium */
4278 case 32: /* The Netherlands */
4279 case 33: /* France */
4280 case 34: /* Spain */
4281 case 36: /* Hungary */
4282 case 38: /* Yugoslavia (or what's left of it?) */
4283 case 39: /* Italy */
4284 case 41: /* Switzerland */
4285 case 42: /* Tjekia */
4286 case 45: /* Denmark */
4287 case 46: /* Sweden */
4288 case 47: /* Norway */
4289 case 48: /* Poland */
4290 case 49: /* Germany */
4291 /* Daylight saving from last Sunday in March to last Sunday in
4292 September, both at 2AM. */
4293 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4294 break;
4295 case 44: /* United Kingdom */
4296 case 351: /* Portugal */
4297 case 354: /* Iceland */
4298 setenv ("TZ", "GMT+00", 0);
4299 break;
4300 case 81: /* Japan */
4301 case 82: /* Korea */
4302 setenv ("TZ", "JST-09", 0);
4303 break;
4304 case 90: /* Turkey */
4305 case 358: /* Finland */
4306 setenv ("TZ", "EET-02", 0);
4307 break;
4308 case 972: /* Israel */
4309 /* This is an approximation. (For exact rules, use the
4310 `zoneinfo/israel' file which comes with DJGPP, but you need
4311 to install it in `/usr/share/zoneinfo/' directory first.) */
4312 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4313 break;
4315 tzset ();
4320 static int break_stat; /* BREAK check mode status. */
4321 static int stdin_stat; /* stdin IOCTL status. */
4323 #if __DJGPP__ < 2
4325 /* These must be global. */
4326 static _go32_dpmi_seginfo ctrl_break_vector;
4327 static _go32_dpmi_registers ctrl_break_regs;
4328 static int ctrlbreakinstalled = 0;
4330 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4332 void
4333 ctrl_break_func (regs)
4334 _go32_dpmi_registers *regs;
4336 Vquit_flag = Qt;
4339 void
4340 install_ctrl_break_check ()
4342 if (!ctrlbreakinstalled)
4344 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4345 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4346 ctrlbreakinstalled = 1;
4347 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
4348 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
4349 &ctrl_break_regs);
4350 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
4354 #endif /* __DJGPP__ < 2 */
4356 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4357 control chars by DOS. Determine the keyboard type. */
4360 dos_ttraw ()
4362 union REGS inregs, outregs;
4363 static int first_time = 1;
4365 break_stat = getcbrk ();
4366 setcbrk (0);
4367 #if __DJGPP__ < 2
4368 install_ctrl_break_check ();
4369 #endif
4371 if (first_time)
4373 inregs.h.ah = 0xc0;
4374 int86 (0x15, &inregs, &outregs);
4375 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4377 have_mouse = 0;
4379 if (internal_terminal
4380 #ifdef HAVE_X_WINDOWS
4381 && inhibit_window_system
4382 #endif
4385 inregs.x.ax = 0x0021;
4386 int86 (0x33, &inregs, &outregs);
4387 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4388 if (!have_mouse)
4390 /* Reportedly, the above doesn't work for some mouse drivers. There
4391 is an additional detection method that should work, but might be
4392 a little slower. Use that as an alternative. */
4393 inregs.x.ax = 0x0000;
4394 int86 (0x33, &inregs, &outregs);
4395 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4398 if (have_mouse)
4400 have_mouse = 1; /* enable mouse */
4401 mouse_visible = 0;
4403 if (outregs.x.bx == 3)
4405 mouse_button_count = 3;
4406 mouse_button_translate[0] = 0; /* Left */
4407 mouse_button_translate[1] = 2; /* Middle */
4408 mouse_button_translate[2] = 1; /* Right */
4410 else
4412 mouse_button_count = 2;
4413 mouse_button_translate[0] = 0;
4414 mouse_button_translate[1] = 1;
4416 mouse_position_hook = &mouse_get_pos;
4417 mouse_init ();
4420 #ifndef HAVE_X_WINDOWS
4421 #if __DJGPP__ >= 2
4422 /* Save the cursor shape used outside Emacs. */
4423 outside_cursor = _farpeekw (_dos_ds, 0x460);
4424 #endif
4425 #endif
4428 first_time = 0;
4430 #if __DJGPP__ >= 2
4432 stdin_stat = setmode (fileno (stdin), O_BINARY);
4433 return (stdin_stat != -1);
4435 else
4436 return (setmode (fileno (stdin), O_BINARY) != -1);
4438 #else /* __DJGPP__ < 2 */
4442 /* I think it is wrong to overwrite `stdin_stat' every time
4443 but the first one this function is called, but I don't
4444 want to change the way it used to work in v1.x.--EZ */
4446 inregs.x.ax = 0x4400; /* Get IOCTL status. */
4447 inregs.x.bx = 0x00; /* 0 = stdin. */
4448 intdos (&inregs, &outregs);
4449 stdin_stat = outregs.h.dl;
4451 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
4452 inregs.x.ax = 0x4401; /* Set IOCTL status */
4453 intdos (&inregs, &outregs);
4454 return !outregs.x.cflag;
4456 #endif /* __DJGPP__ < 2 */
4459 /* Restore status of standard input and Ctrl-C checking. */
4462 dos_ttcooked ()
4464 union REGS inregs, outregs;
4466 setcbrk (break_stat);
4467 mouse_off ();
4469 #if __DJGPP__ >= 2
4471 #ifndef HAVE_X_WINDOWS
4472 /* Restore the cursor shape we found on startup. */
4473 if (outside_cursor)
4475 inregs.h.ah = 1;
4476 inregs.x.cx = outside_cursor;
4477 int86 (0x10, &inregs, &outregs);
4479 #endif
4481 return (setmode (fileno (stdin), stdin_stat) != -1);
4483 #else /* not __DJGPP__ >= 2 */
4485 inregs.x.ax = 0x4401; /* Set IOCTL status. */
4486 inregs.x.bx = 0x00; /* 0 = stdin. */
4487 inregs.x.dx = stdin_stat;
4488 intdos (&inregs, &outregs);
4489 return !outregs.x.cflag;
4491 #endif /* not __DJGPP__ >= 2 */
4495 /* Run command as specified by ARGV in directory DIR.
4496 The command is run with input from TEMPIN, output to
4497 file TEMPOUT and stderr to TEMPERR. */
4500 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4501 unsigned char **argv;
4502 const char *working_dir;
4503 int tempin, tempout, temperr;
4504 char **envv;
4506 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4507 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4508 int msshell, result = -1;
4509 int inbak, outbak, errbak;
4510 int x, y;
4511 Lisp_Object cmd;
4513 /* Get current directory as MSDOS cwd is not per-process. */
4514 getwd (oldwd);
4516 /* If argv[0] is the shell, it might come in any lettercase.
4517 Since `Fmember' is case-sensitive, we need to downcase
4518 argv[0], even if we are on case-preserving filesystems. */
4519 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4520 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4522 *pl = *pa++;
4523 if (*pl >= 'A' && *pl <= 'Z')
4524 *pl += 'a' - 'A';
4526 *pl = '\0';
4528 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4529 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4530 && !strcmp ("-c", argv[1]);
4531 if (msshell)
4533 saveargv1 = argv[1];
4534 saveargv2 = argv[2];
4535 argv[1] = "/c";
4536 if (argv[2])
4538 char *p = alloca (strlen (argv[2]) + 1);
4540 strcpy (argv[2] = p, saveargv2);
4541 while (*p && isspace (*p))
4542 p++;
4543 while (*p && !isspace (*p))
4544 if (*p == '/')
4545 *p++ = '\\';
4546 else
4547 p++;
4551 chdir (working_dir);
4552 inbak = dup (0);
4553 outbak = dup (1);
4554 errbak = dup (2);
4555 if (inbak < 0 || outbak < 0 || errbak < 0)
4556 goto done; /* Allocation might fail due to lack of descriptors. */
4558 if (have_mouse > 0)
4559 mouse_get_xy (&x, &y);
4561 dos_ttcooked (); /* do it here while 0 = stdin */
4563 dup2 (tempin, 0);
4564 dup2 (tempout, 1);
4565 dup2 (temperr, 2);
4567 #if __DJGPP__ > 1
4569 if (msshell && !argv[3])
4571 /* MS-DOS native shells are too restrictive. For starters, they
4572 cannot grok commands longer than 126 characters. In DJGPP v2
4573 and later, `system' is much smarter, so we'll call it instead. */
4575 const char *cmnd;
4577 /* A shell gets a single argument--its full command
4578 line--whose original was saved in `saveargv2'. */
4580 /* Don't let them pass empty command lines to `system', since
4581 with some shells it will try to invoke an interactive shell,
4582 which will hang Emacs. */
4583 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4585 if (*cmnd)
4587 extern char **environ;
4588 int save_system_flags = __system_flags;
4590 /* Request the most powerful version of `system'. We need
4591 all the help we can get to avoid calling stock DOS shells. */
4592 __system_flags = (__system_redirect
4593 | __system_use_shell
4594 | __system_allow_multiple_cmds
4595 | __system_allow_long_cmds
4596 | __system_handle_null_commands
4597 | __system_emulate_chdir);
4599 environ = envv;
4600 result = system (cmnd);
4601 __system_flags = save_system_flags;
4603 else
4604 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4606 else
4608 #endif /* __DJGPP__ > 1 */
4610 result = spawnve (P_WAIT, argv[0], argv, envv);
4612 dup2 (inbak, 0);
4613 dup2 (outbak, 1);
4614 dup2 (errbak, 2);
4615 emacs_close (inbak);
4616 emacs_close (outbak);
4617 emacs_close (errbak);
4619 dos_ttraw ();
4620 if (have_mouse > 0)
4622 mouse_init ();
4623 mouse_moveto (x, y);
4626 /* Some programs might change the meaning of the highest bit of the
4627 text attribute byte, so we get blinking characters instead of the
4628 bright background colors. Restore that. */
4629 bright_bg ();
4631 done:
4632 chdir (oldwd);
4633 if (msshell)
4635 argv[1] = saveargv1;
4636 argv[2] = saveargv2;
4638 return result;
4641 croak (badfunc)
4642 char *badfunc;
4644 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4645 reset_sys_modes ();
4646 exit (1);
4649 #if __DJGPP__ < 2
4651 /* ------------------------- Compatibility functions -------------------
4652 * gethostname
4653 * gettimeofday
4656 /* Hostnames for a pc are not really funny,
4657 but they are used in change log so we emulate the best we can. */
4659 gethostname (p, size)
4660 char *p;
4661 int size;
4663 char *q = egetenv ("HOSTNAME");
4665 if (!q) q = "pc";
4666 strcpy (p, q);
4667 return 0;
4670 /* When time zones are set from Ms-Dos too many C-libraries are playing
4671 tricks with time values. We solve this by defining our own version
4672 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4673 once and after each call to `tzset' with TZ changed. That is
4674 accomplished by aliasing tzset to init_gettimeofday. */
4676 static struct tm time_rec;
4679 gettimeofday (struct timeval *tp, struct timezone *tzp)
4681 if (tp)
4683 struct time t;
4684 struct tm tm;
4686 gettime (&t);
4687 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
4689 struct date d;
4690 getdate (&d);
4691 time_rec.tm_year = d.da_year - 1900;
4692 time_rec.tm_mon = d.da_mon - 1;
4693 time_rec.tm_mday = d.da_day;
4696 time_rec.tm_hour = t.ti_hour;
4697 time_rec.tm_min = t.ti_min;
4698 time_rec.tm_sec = t.ti_sec;
4700 tm = time_rec;
4701 tm.tm_gmtoff = dos_timezone_offset;
4703 tp->tv_sec = mktime (&tm); /* may modify tm */
4704 tp->tv_usec = t.ti_hund * (1000000 / 100);
4706 /* Ignore tzp; it's obsolescent. */
4707 return 0;
4710 #endif /* __DJGPP__ < 2 */
4713 * A list of unimplemented functions that we silently ignore.
4716 #if __DJGPP__ < 2
4717 unsigned alarm (s) unsigned s; {}
4718 fork () { return 0; }
4719 int kill (x, y) int x, y; { return -1; }
4720 nice (p) int p; {}
4721 void volatile pause () {}
4722 sigsetmask (x) int x; { return 0; }
4723 sigblock (mask) int mask; { return 0; }
4724 #endif
4726 void request_sigio (void) {}
4727 setpgrp () {return 0; }
4728 setpriority (x,y,z) int x,y,z; { return 0; }
4729 void unrequest_sigio (void) {}
4731 #if __DJGPP__ > 1
4733 #ifdef POSIX_SIGNALS
4735 /* Augment DJGPP library POSIX signal functions. This is needed
4736 as of DJGPP v2.01, but might be in the library in later releases. */
4738 #include <libc/bss.h>
4740 /* A counter to know when to re-initialize the static sets. */
4741 static int sigprocmask_count = -1;
4743 /* Which signals are currently blocked (initially none). */
4744 static sigset_t current_mask;
4746 /* Which signals are pending (initially none). */
4747 static sigset_t pending_signals;
4749 /* Previous handlers to restore when the blocked signals are unblocked. */
4750 typedef void (*sighandler_t)(int);
4751 static sighandler_t prev_handlers[320];
4753 /* A signal handler which just records that a signal occured
4754 (it will be raised later, if and when the signal is unblocked). */
4755 static void
4756 sig_suspender (signo)
4757 int signo;
4759 sigaddset (&pending_signals, signo);
4763 sigprocmask (how, new_set, old_set)
4764 int how;
4765 const sigset_t *new_set;
4766 sigset_t *old_set;
4768 int signo;
4769 sigset_t new_mask;
4771 /* If called for the first time, initialize. */
4772 if (sigprocmask_count != __bss_count)
4774 sigprocmask_count = __bss_count;
4775 sigemptyset (&pending_signals);
4776 sigemptyset (&current_mask);
4777 for (signo = 0; signo < 320; signo++)
4778 prev_handlers[signo] = SIG_ERR;
4781 if (old_set)
4782 *old_set = current_mask;
4784 if (new_set == 0)
4785 return 0;
4787 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4789 errno = EINVAL;
4790 return -1;
4793 sigemptyset (&new_mask);
4795 /* DJGPP supports upto 320 signals. */
4796 for (signo = 0; signo < 320; signo++)
4798 if (sigismember (&current_mask, signo))
4799 sigaddset (&new_mask, signo);
4800 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4802 sigaddset (&new_mask, signo);
4804 /* SIGKILL is silently ignored, as on other platforms. */
4805 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4806 prev_handlers[signo] = signal (signo, sig_suspender);
4808 if (( how == SIG_UNBLOCK
4809 && sigismember (&new_mask, signo)
4810 && sigismember (new_set, signo))
4811 || (how == SIG_SETMASK
4812 && sigismember (&new_mask, signo)
4813 && !sigismember (new_set, signo)))
4815 sigdelset (&new_mask, signo);
4816 if (prev_handlers[signo] != SIG_ERR)
4818 signal (signo, prev_handlers[signo]);
4819 prev_handlers[signo] = SIG_ERR;
4821 if (sigismember (&pending_signals, signo))
4823 sigdelset (&pending_signals, signo);
4824 raise (signo);
4828 current_mask = new_mask;
4829 return 0;
4832 #else /* not POSIX_SIGNALS */
4834 sigsetmask (x) int x; { return 0; }
4835 sigblock (mask) int mask; { return 0; }
4837 #endif /* not POSIX_SIGNALS */
4838 #endif /* __DJGPP__ > 1 */
4840 #ifndef HAVE_SELECT
4841 #include "sysselect.h"
4843 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4844 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4845 ((long)(time).tv_sec < 0 \
4846 || ((time).tv_sec == 0 \
4847 && (long)(time).tv_usec <= 0))
4848 #endif
4850 /* This yields the rest of the current time slice to the task manager.
4851 It should be called by any code which knows that it has nothing
4852 useful to do except idle.
4854 I don't use __dpmi_yield here, since versions of library before 2.02
4855 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4856 on some versions of Windows 9X. */
4858 void
4859 dos_yield_time_slice (void)
4861 _go32_dpmi_registers r;
4863 r.x.ax = 0x1680;
4864 r.x.ss = r.x.sp = r.x.flags = 0;
4865 _go32_dpmi_simulate_int (0x2f, &r);
4866 if (r.h.al == 0x80)
4867 errno = ENOSYS;
4870 /* Only event queue is checked. */
4871 /* We don't have to call timer_check here
4872 because wait_reading_process_input takes care of that. */
4874 sys_select (nfds, rfds, wfds, efds, timeout)
4875 int nfds;
4876 SELECT_TYPE *rfds, *wfds, *efds;
4877 EMACS_TIME *timeout;
4879 int check_input;
4880 struct time t;
4882 check_input = 0;
4883 if (rfds)
4885 check_input = FD_ISSET (0, rfds);
4886 FD_ZERO (rfds);
4888 if (wfds)
4889 FD_ZERO (wfds);
4890 if (efds)
4891 FD_ZERO (efds);
4893 if (nfds != 1)
4894 abort ();
4896 /* If we are looking only for the terminal, with no timeout,
4897 just read it and wait -- that's more efficient. */
4898 if (!timeout)
4900 while (!detect_input_pending ())
4902 dos_yield_time_slice ();
4905 else
4907 EMACS_TIME clnow, cllast, cldiff;
4909 gettime (&t);
4910 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4912 while (!check_input || !detect_input_pending ())
4914 gettime (&t);
4915 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4916 EMACS_SUB_TIME (cldiff, clnow, cllast);
4918 /* When seconds wrap around, we assume that no more than
4919 1 minute passed since last `gettime'. */
4920 if (EMACS_TIME_NEG_P (cldiff))
4921 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4922 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4924 /* Stop when timeout value crosses zero. */
4925 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4926 return 0;
4927 cllast = clnow;
4928 dos_yield_time_slice ();
4932 FD_SET (0, rfds);
4933 return 1;
4935 #endif
4938 * Define overlaid functions:
4940 * chdir -> sys_chdir
4941 * tzset -> init_gettimeofday
4942 * abort -> dos_abort
4945 #ifdef chdir
4946 #undef chdir
4947 extern int chdir ();
4950 sys_chdir (path)
4951 const char* path;
4953 int len = strlen (path);
4954 char *tmp = (char *)path;
4956 if (*tmp && tmp[1] == ':')
4958 if (getdisk () != tolower (tmp[0]) - 'a')
4959 setdisk (tolower (tmp[0]) - 'a');
4960 tmp += 2; /* strip drive: KFS 1995-07-06 */
4961 len -= 2;
4964 if (len > 1 && (tmp[len - 1] == '/'))
4966 char *tmp1 = (char *) alloca (len + 1);
4967 strcpy (tmp1, tmp);
4968 tmp1[len - 1] = 0;
4969 tmp = tmp1;
4971 return chdir (tmp);
4973 #endif
4975 #ifdef tzset
4976 #undef tzset
4977 extern void tzset (void);
4979 void
4980 init_gettimeofday ()
4982 time_t ltm, gtm;
4983 struct tm *lstm;
4985 tzset ();
4986 ltm = gtm = time (NULL);
4987 ltm = mktime (lstm = localtime (&ltm));
4988 gtm = mktime (gmtime (&gtm));
4989 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4990 time_rec.tm_isdst = lstm->tm_isdst;
4991 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4993 #endif
4995 #ifdef abort
4996 #undef abort
4997 void
4998 dos_abort (file, line)
4999 char *file;
5000 int line;
5002 char buffer1[200], buffer2[400];
5003 int i, j;
5005 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
5006 for (i = j = 0; buffer1[i]; i++) {
5007 buffer2[j++] = buffer1[i];
5008 buffer2[j++] = 0x70;
5010 dosmemput (buffer2, j, (int)ScreenPrimary);
5011 ScreenSetCursor (2, 0);
5012 abort ();
5014 #else
5015 void
5016 abort ()
5018 dos_ttcooked ();
5019 ScreenSetCursor (10, 0);
5020 cputs ("\r\n\nEmacs aborted!\r\n");
5021 #if __DJGPP__ > 1
5022 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5023 if (screen_virtual_segment)
5024 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
5025 /* Generate traceback, so we could tell whodunit. */
5026 signal (SIGINT, SIG_DFL);
5027 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5028 #else /* __DJGPP_MINOR__ >= 2 */
5029 raise (SIGABRT);
5030 #endif /* __DJGPP_MINOR__ >= 2 */
5031 #endif
5032 exit (2);
5034 #endif
5036 /* The following variables are required so that cus-start.el won't
5037 complain about unbound variables. */
5038 #ifndef HAVE_X_WINDOWS
5039 /* Search path for bitmap files (xfns.c). */
5040 Lisp_Object Vx_bitmap_file_path;
5041 int x_stretch_cursor_p;
5042 #endif
5043 #ifndef subprocesses
5044 /* Nonzero means delete a process right away if it exits (process.c). */
5045 static int delete_exited_processes;
5046 #endif
5048 syms_of_msdos ()
5050 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
5051 staticpro (&recent_doskeys);
5052 #ifndef HAVE_X_WINDOWS
5053 staticpro (&help_echo);
5054 help_echo = Qnil;
5055 staticpro (&previous_help_echo);
5056 previous_help_echo = Qnil;
5058 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
5059 "List of directories to search for bitmap files for X.");
5060 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
5062 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
5063 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5064 For example, if a block cursor is over a tab, it will be drawn as\n\
5065 wide as that tab on the display. (No effect on MS-DOS.)");
5066 x_stretch_cursor_p = 0;
5068 /* The following three are from xfns.c: */
5069 Qbackground_color = intern ("background-color");
5070 staticpro (&Qbackground_color);
5071 Qforeground_color = intern ("foreground-color");
5072 staticpro (&Qforeground_color);
5073 Qbar = intern ("bar");
5074 staticpro (&Qbar);
5075 Qcursor_type = intern ("cursor-type");
5076 staticpro (&Qcursor_type);
5077 Qreverse = intern ("reverse");
5078 staticpro (&Qreverse);
5080 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
5081 "*Glyph to display instead of chars not supported by current codepage.\n\
5083 This variable is used only by MSDOS terminals.");
5084 Vdos_unsupported_char_glyph = '\177';
5085 #endif
5086 #ifndef subprocesses
5087 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
5088 "*Non-nil means delete processes immediately when they exit.\n\
5089 nil means don't delete them until `list-processes' is run.");
5090 delete_exited_processes = 0;
5091 #endif
5093 defsubr (&Srecent_doskeys);
5094 defsubr (&Smsdos_long_file_names);
5095 defsubr (&Smsdos_downcase_filename);
5096 defsubr (&Smsdos_remember_default_colors);
5099 #endif /* MSDOS */