* customize.texi (Composite Types): Move alist/plist from Simple Types (Bug#7545).
[emacs.git] / src / msdos.c
blobc176680bf9db377543290c2367cdb254fc9a4495
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26 #include <config.h>
28 #ifdef MSDOS
29 #include <setjmp.h>
30 #include "lisp.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <sys/param.h>
35 #include <sys/time.h>
36 #include <dos.h>
37 #include <errno.h>
38 #include <string.h> /* for bzero and string functions */
39 #include <sys/stat.h> /* for _fixpath */
40 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #include <dir.h> /* for getdisk */
42 #if __DJGPP__ >= 2
43 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
44 #include <fcntl.h>
45 #include <io.h> /* for setmode */
46 #include <dpmi.h> /* for __dpmi_xxx stuff */
47 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
48 #include <libc/dosio.h> /* for _USE_LFN */
49 #include <conio.h> /* for cputs */
50 #endif
52 #include "msdos.h"
53 #include "systime.h"
54 #include "frame.h"
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "dispextern.h"
58 #include "dosfns.h"
59 #include "termopts.h"
60 #include "character.h"
61 #include "coding.h"
62 #include "disptab.h"
63 #include "window.h"
64 #include "buffer.h"
65 #include "commands.h"
66 #include "blockinput.h"
67 #include "keyboard.h"
68 #include "intervals.h"
69 #include <go32.h>
70 #include <pc.h>
71 #include <ctype.h>
72 /* #include <process.h> */
73 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
74 #define P_WAIT 1
76 #ifndef _USE_LFN
77 #define _USE_LFN 0
78 #endif
80 #ifndef _dos_ds
81 #define _dos_ds _go32_info_block.selector_for_linear_memory
82 #endif
84 #if __DJGPP__ > 1
86 #include <signal.h>
87 #include "syssignal.h"
89 #ifndef SYSTEM_MALLOC
91 #ifdef GNU_MALLOC
93 /* If other `malloc' than ours is used, force our `sbrk' behave like
94 Unix programs expect (resize memory blocks to keep them contiguous).
95 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
96 because that's what `gmalloc' expects to get. */
97 #include <crt0.h>
99 #ifdef REL_ALLOC
100 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
101 #else /* not REL_ALLOC */
102 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
103 #endif /* not REL_ALLOC */
104 #endif /* GNU_MALLOC */
106 #endif /* not SYSTEM_MALLOC */
107 #endif /* __DJGPP__ > 1 */
109 static unsigned long
110 event_timestamp ()
112 struct time t;
113 unsigned long s;
115 gettime (&t);
116 s = t.ti_min;
117 s *= 60;
118 s += t.ti_sec;
119 s *= 1000;
120 s += t.ti_hund * 10;
122 return s;
126 /* ------------------------ Mouse control ---------------------------
128 * Coordinates are in screen positions and zero based.
129 * Mouse buttons are numbered from left to right and also zero based.
132 /* This used to be in termhooks.h, but mainstream Emacs code no longer
133 uses it, and it was removed... */
134 #define NUM_MOUSE_BUTTONS (5)
136 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
137 static int mouse_visible;
139 static int mouse_last_x;
140 static int mouse_last_y;
142 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
143 static int mouse_button_count;
145 void
146 mouse_on ()
148 union REGS regs;
150 if (have_mouse > 0 && !mouse_visible)
152 struct tty_display_info *tty = CURTTY ();
154 if (tty->termscript)
155 fprintf (tty->termscript, "<M_ON>");
156 regs.x.ax = 0x0001;
157 int86 (0x33, &regs, &regs);
158 mouse_visible = 1;
162 void
163 mouse_off ()
165 union REGS regs;
167 if (have_mouse > 0 && mouse_visible)
169 struct tty_display_info *tty = CURTTY ();
171 if (tty->termscript)
172 fprintf (tty->termscript, "<M_OFF>");
173 regs.x.ax = 0x0002;
174 int86 (0x33, &regs, &regs);
175 mouse_visible = 0;
179 static void
180 mouse_setup_buttons (int n_buttons)
182 if (n_buttons == 3)
184 mouse_button_count = 3;
185 mouse_button_translate[0] = 0; /* Left */
186 mouse_button_translate[1] = 2; /* Middle */
187 mouse_button_translate[2] = 1; /* Right */
189 else /* two, what else? */
191 mouse_button_count = 2;
192 mouse_button_translate[0] = 0;
193 mouse_button_translate[1] = 1;
197 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
198 1, 1, "NSet number of mouse buttons to: ",
199 doc: /* Set the number of mouse buttons to use by Emacs.
200 This is useful with mice that report the number of buttons inconsistently,
201 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
202 them. This happens with wheeled mice on Windows 9X, for example. */)
203 (nbuttons)
204 Lisp_Object nbuttons;
206 int n;
208 CHECK_NUMBER (nbuttons);
209 n = XINT (nbuttons);
210 if (n < 2 || n > 3)
211 xsignal2 (Qargs_out_of_range,
212 build_string ("only 2 or 3 mouse buttons are supported"),
213 nbuttons);
214 mouse_setup_buttons (n);
215 return Qnil;
218 static void
219 mouse_get_xy (int *x, int *y)
221 union REGS regs;
223 regs.x.ax = 0x0003;
224 int86 (0x33, &regs, &regs);
225 *x = regs.x.cx / 8;
226 *y = regs.x.dx / 8;
229 void
230 mouse_moveto (x, y)
231 int x, y;
233 union REGS regs;
234 struct tty_display_info *tty = CURTTY ();
236 if (tty->termscript)
237 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
238 regs.x.ax = 0x0004;
239 mouse_last_x = regs.x.cx = x * 8;
240 mouse_last_y = regs.x.dx = y * 8;
241 int86 (0x33, &regs, &regs);
244 static int
245 mouse_pressed (b, xp, yp)
246 int b, *xp, *yp;
248 union REGS regs;
250 if (b >= mouse_button_count)
251 return 0;
252 regs.x.ax = 0x0005;
253 regs.x.bx = mouse_button_translate[b];
254 int86 (0x33, &regs, &regs);
255 if (regs.x.bx)
256 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
257 return (regs.x.bx != 0);
260 static int
261 mouse_released (b, xp, yp)
262 int b, *xp, *yp;
264 union REGS regs;
266 if (b >= mouse_button_count)
267 return 0;
268 regs.x.ax = 0x0006;
269 regs.x.bx = mouse_button_translate[b];
270 int86 (0x33, &regs, &regs);
271 if (regs.x.bx)
272 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
273 return (regs.x.bx != 0);
276 static int
277 mouse_button_depressed (b, xp, yp)
278 int b, *xp, *yp;
280 union REGS regs;
282 if (b >= mouse_button_count)
283 return 0;
284 regs.x.ax = 0x0003;
285 int86 (0x33, &regs, &regs);
286 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
288 *xp = regs.x.cx / 8;
289 *yp = regs.x.dx / 8;
290 return 1;
292 return 0;
295 void
296 mouse_get_pos (f, insist, bar_window, part, x, y, time)
297 FRAME_PTR *f;
298 int insist;
299 Lisp_Object *bar_window, *x, *y;
300 enum scroll_bar_part *part;
301 unsigned long *time;
303 int ix, iy;
304 Lisp_Object frame, tail;
306 /* Clear the mouse-moved flag for every frame on this display. */
307 FOR_EACH_FRAME (tail, frame)
308 XFRAME (frame)->mouse_moved = 0;
310 *f = SELECTED_FRAME();
311 *bar_window = Qnil;
312 mouse_get_xy (&ix, &iy);
313 *time = event_timestamp ();
314 *x = make_number (mouse_last_x = ix);
315 *y = make_number (mouse_last_y = iy);
318 static void
319 mouse_check_moved ()
321 int x, y;
323 mouse_get_xy (&x, &y);
324 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
325 mouse_last_x = x;
326 mouse_last_y = y;
329 /* Force the mouse driver to ``forget'' about any button clicks until
330 now. */
331 static void
332 mouse_clear_clicks (void)
334 int b;
336 for (b = 0; b < mouse_button_count; b++)
338 int dummy_x, dummy_y;
340 (void) mouse_pressed (b, &dummy_x, &dummy_y);
341 (void) mouse_released (b, &dummy_x, &dummy_y);
345 void
346 mouse_init ()
348 union REGS regs;
349 struct tty_display_info *tty = CURTTY ();
351 if (tty->termscript)
352 fprintf (tty->termscript, "<M_INIT>");
354 regs.x.ax = 0x0021;
355 int86 (0x33, &regs, &regs);
357 /* Reset the mouse last press/release info. It seems that Windows
358 doesn't do that automatically when function 21h is called, which
359 causes Emacs to ``remember'' the click that switched focus to the
360 window just before Emacs was started from that window. */
361 mouse_clear_clicks ();
363 regs.x.ax = 0x0007;
364 regs.x.cx = 0;
365 regs.x.dx = 8 * (ScreenCols () - 1);
366 int86 (0x33, &regs, &regs);
368 regs.x.ax = 0x0008;
369 regs.x.cx = 0;
370 regs.x.dx = 8 * (ScreenRows () - 1);
371 int86 (0x33, &regs, &regs);
373 mouse_moveto (0, 0);
374 mouse_visible = 0;
377 /* ------------------------- Screen control ----------------------
381 static int internal_terminal = 0;
383 #ifndef HAVE_X_WINDOWS
384 extern unsigned char ScreenAttrib;
385 static int screen_face;
387 static int screen_size_X;
388 static int screen_size_Y;
389 static int screen_size;
391 static int current_pos_X;
392 static int current_pos_Y;
393 static int new_pos_X;
394 static int new_pos_Y;
396 static void *startup_screen_buffer;
397 static int startup_screen_size_X;
398 static int startup_screen_size_Y;
399 static int startup_pos_X;
400 static int startup_pos_Y;
401 static unsigned char startup_screen_attrib;
403 static clock_t startup_time;
405 static int term_setup_done;
407 static unsigned short outside_cursor;
409 /* Similar to the_only_frame. */
410 struct tty_display_info the_only_display_info;
412 /* Support for DOS/V (allows Japanese characters to be displayed on
413 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
415 /* Holds the address of the text-mode screen buffer. */
416 static unsigned long screen_old_address = 0;
417 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
418 static unsigned short screen_virtual_segment = 0;
419 static unsigned short screen_virtual_offset = 0;
420 /* A flag to control how to display unibyte 8-bit characters. */
421 extern int unibyte_display_via_language_environment;
423 extern Lisp_Object Qcursor_type;
424 extern Lisp_Object Qbar, Qhbar;
426 /* The screen colors of the current frame, which serve as the default
427 colors for newly-created frames. */
428 static int initial_screen_colors[2];
430 #if __DJGPP__ > 1
431 /* Update the screen from a part of relocated DOS/V screen buffer which
432 begins at OFFSET and includes COUNT characters. */
433 static void
434 dosv_refresh_virtual_screen (int offset, int count)
436 __dpmi_regs regs;
438 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
439 return;
441 regs.h.ah = 0xff; /* update relocated screen */
442 regs.x.es = screen_virtual_segment;
443 regs.x.di = screen_virtual_offset + offset;
444 regs.x.cx = count;
445 __dpmi_int (0x10, &regs);
447 #endif
449 static void
450 dos_direct_output (y, x, buf, len)
451 int x, y;
452 char *buf;
453 int len;
455 int t0 = 2 * (x + y * screen_size_X);
456 int t = t0 + (int) ScreenPrimary;
457 int l0 = len;
459 #if (__DJGPP__ < 2)
460 while (--len >= 0) {
461 dosmemput (buf++, 1, t);
462 t += 2;
464 #else
465 /* This is faster. */
466 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
467 _farnspokeb (t, *buf);
469 if (screen_virtual_segment)
470 dosv_refresh_virtual_screen (t0, l0);
471 #endif
473 #endif
475 /* Flash the screen as a substitute for BEEPs. */
477 #if (__DJGPP__ < 2)
478 static void
479 do_visible_bell (xorattr)
480 unsigned char xorattr;
482 asm volatile
483 (" movb $1,%%dl \n\
484 visible_bell_0: \n\
485 movl _ScreenPrimary,%%eax \n\
486 call dosmemsetup \n\
487 movl %%eax,%%ebx \n\
488 movl %1,%%ecx \n\
489 movb %0,%%al \n\
490 incl %%ebx \n\
491 visible_bell_1: \n\
492 xorb %%al,%%gs:(%%ebx) \n\
493 addl $2,%%ebx \n\
494 decl %%ecx \n\
495 jne visible_bell_1 \n\
496 decb %%dl \n\
497 jne visible_bell_3 \n\
498 visible_bell_2: \n\
499 movzwl %%ax,%%eax \n\
500 movzwl %%ax,%%eax \n\
501 movzwl %%ax,%%eax \n\
502 movzwl %%ax,%%eax \n\
503 decw %%cx \n\
504 jne visible_bell_2 \n\
505 jmp visible_bell_0 \n\
506 visible_bell_3:"
507 : /* no output */
508 : "m" (xorattr), "g" (screen_size)
509 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
512 static void
513 ScreenVisualBell (void)
515 /* This creates an xor-mask that will swap the default fore- and
516 background colors. */
517 do_visible_bell (((FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ())
518 ^ FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()))
519 * 0x11) & 0x7f);
521 #endif
523 #ifndef HAVE_X_WINDOWS
525 static int blink_bit = -1; /* the state of the blink bit at startup */
527 /* Enable bright background colors. */
528 static void
529 bright_bg (void)
531 union REGS regs;
533 /* Remember the original state of the blink/bright-background bit.
534 It is stored at 0040:0065h in the BIOS data area. */
535 if (blink_bit == -1)
536 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
538 regs.h.bl = 0;
539 regs.x.ax = 0x1003;
540 int86 (0x10, &regs, &regs);
543 /* Disable bright background colors (and enable blinking) if we found
544 the video system in that state at startup. */
545 static void
546 maybe_enable_blinking (void)
548 if (blink_bit == 1)
550 union REGS regs;
552 regs.h.bl = 1;
553 regs.x.ax = 0x1003;
554 int86 (0x10, &regs, &regs);
558 /* Return non-zero if the system has a VGA adapter. */
559 static int
560 vga_installed (void)
562 union REGS regs;
564 regs.x.ax = 0x1a00;
565 int86 (0x10, &regs, &regs);
566 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
567 return 1;
568 return 0;
571 /* Set the screen dimensions so that it can show no less than
572 ROWS x COLS frame. */
574 void
575 dos_set_window_size (rows, cols)
576 int *rows, *cols;
578 char video_name[30];
579 union REGS regs;
580 Lisp_Object video_mode;
581 int video_mode_value, have_vga = 0;
582 int current_rows = ScreenRows (), current_cols = ScreenCols ();
584 if (*rows == current_rows && *cols == current_cols)
585 return;
587 mouse_off ();
588 have_vga = vga_installed ();
590 /* If the user specified a special video mode for these dimensions,
591 use that mode. */
592 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
593 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
594 Qnil))-> value;
596 if (INTEGERP (video_mode)
597 && (video_mode_value = XINT (video_mode)) > 0)
599 regs.x.ax = video_mode_value;
600 int86 (0x10, &regs, &regs);
602 if (have_mouse)
604 /* Must hardware-reset the mouse, or else it won't update
605 its notion of screen dimensions for some non-standard
606 video modes. This is *painfully* slow... */
607 regs.x.ax = 0;
608 int86 (0x33, &regs, &regs);
612 /* Find one of the dimensions supported by standard EGA/VGA
613 which gives us at least the required dimensions. */
615 #if __DJGPP__ > 1
617 else
619 static struct {
620 int rows, need_vga;
621 } std_dimension[] = {
622 {25, 0},
623 {28, 1},
624 {35, 0},
625 {40, 1},
626 {43, 0},
627 {50, 1}
629 int i = 0;
631 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
633 if (std_dimension[i].need_vga <= have_vga
634 && std_dimension[i].rows >= *rows)
636 if (std_dimension[i].rows != current_rows
637 || *cols != current_cols)
638 _set_screen_lines (std_dimension[i].rows);
639 break;
641 i++;
645 #else /* not __DJGPP__ > 1 */
647 else if (*rows <= 25)
649 if (current_rows != 25 || current_cols != 80)
651 regs.x.ax = 3;
652 int86 (0x10, &regs, &regs);
653 regs.x.ax = 0x1101;
654 regs.h.bl = 0;
655 int86 (0x10, &regs, &regs);
656 regs.x.ax = 0x1200;
657 regs.h.bl = 32;
658 int86 (0x10, &regs, &regs);
659 regs.x.ax = 3;
660 int86 (0x10, &regs, &regs);
663 else if (*rows <= 50)
664 if (have_vga && (current_rows != 50 || current_cols != 80)
665 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
667 regs.x.ax = 3;
668 int86 (0x10, &regs, &regs);
669 regs.x.ax = 0x1112;
670 regs.h.bl = 0;
671 int86 (0x10, &regs, &regs);
672 regs.x.ax = 0x1200;
673 regs.h.bl = 32;
674 int86 (0x10, &regs, &regs);
675 regs.x.ax = 0x0100;
676 regs.x.cx = 7;
677 int86 (0x10, &regs, &regs);
679 #endif /* not __DJGPP__ > 1 */
681 if (have_mouse)
683 mouse_init ();
684 mouse_on ();
687 /* Tell the caller what dimensions have been REALLY set. */
688 *rows = ScreenRows ();
689 *cols = ScreenCols ();
691 /* Update Emacs' notion of screen dimensions. */
692 screen_size_X = *cols;
693 screen_size_Y = *rows;
694 screen_size = *cols * *rows;
696 #if __DJGPP__ > 1
697 /* If the dimensions changed, the mouse highlight info is invalid. */
698 if (current_rows != *rows || current_cols != *cols)
700 struct frame *f = SELECTED_FRAME();
701 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
702 Lisp_Object window = dpyinfo->mouse_face_window;
704 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
706 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
707 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
708 dpyinfo->mouse_face_window = Qnil;
711 #endif
713 /* Enable bright background colors. */
714 bright_bg ();
716 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
717 be defensive anyway. */
718 if (screen_virtual_segment)
719 dosv_refresh_virtual_screen (0, *cols * *rows);
722 /* If we write a character in the position where the mouse is,
723 the mouse cursor may need to be refreshed. */
725 static void
726 mouse_off_maybe ()
728 int x, y;
730 if (!mouse_visible)
731 return;
733 mouse_get_xy (&x, &y);
734 if (y != new_pos_Y || x < new_pos_X)
735 return;
737 mouse_off ();
740 #define DEFAULT_CURSOR_START (-1)
741 #define DEFAULT_CURSOR_WIDTH (-1)
742 #define BOX_CURSOR_WIDTH (-32)
744 /* Set cursor to begin at scan line START_LINE in the character cell
745 and extend for WIDTH scan lines. Scan lines are counted from top
746 of the character cell, starting from zero. */
747 static void
748 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
750 #if __DJGPP__ > 1
751 unsigned desired_cursor;
752 __dpmi_regs regs;
753 int max_line, top_line, bot_line;
754 struct tty_display_info *tty = FRAME_TTY (f);
756 /* Avoid the costly BIOS call if F isn't the currently selected
757 frame. Allow for NULL as unconditionally meaning the selected
758 frame. */
759 if (f && f != SELECTED_FRAME())
760 return;
762 if (tty->termscript)
763 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
765 /* The character cell size in scan lines is stored at 40:85 in the
766 BIOS data area. */
767 max_line = _farpeekw (_dos_ds, 0x485) - 1;
768 switch (max_line)
770 default: /* this relies on CGA cursor emulation being ON! */
771 case 7:
772 bot_line = 7;
773 break;
774 case 9:
775 bot_line = 9;
776 break;
777 case 13:
778 bot_line = 12;
779 break;
780 case 15:
781 bot_line = 14;
782 break;
785 if (width < 0)
787 if (width == BOX_CURSOR_WIDTH)
789 top_line = 0;
790 bot_line = max_line;
792 else if (start_line != DEFAULT_CURSOR_START)
794 top_line = start_line;
795 bot_line = top_line - width - 1;
797 else if (width != DEFAULT_CURSOR_WIDTH)
799 top_line = 0;
800 bot_line = -1 - width;
802 else
803 top_line = bot_line + 1;
805 else if (width == 0)
807 /* [31, 0] seems to DTRT for all screen sizes. */
808 top_line = 31;
809 bot_line = 0;
811 else /* WIDTH is positive */
813 if (start_line != DEFAULT_CURSOR_START)
814 bot_line = start_line;
815 top_line = bot_line - (width - 1);
818 /* If the current cursor shape is already what they want, we are
819 history here. */
820 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
821 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
822 return;
824 regs.h.ah = 1;
825 regs.x.cx = desired_cursor;
826 __dpmi_int (0x10, &regs);
827 #endif /* __DJGPP__ > 1 */
830 static void
831 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
833 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
835 /* Just BAR means the normal EGA/VGA cursor. */
836 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
838 else if (CONSP (cursor_type)
839 && (EQ (XCAR (cursor_type), Qbar)
840 || EQ (XCAR (cursor_type), Qhbar)))
842 Lisp_Object bar_parms = XCDR (cursor_type);
843 int width;
845 if (INTEGERP (bar_parms))
847 /* Feature: negative WIDTH means cursor at the top
848 of the character cell, zero means invisible cursor. */
849 width = XINT (bar_parms);
850 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
851 width);
853 else if (CONSP (bar_parms)
854 && INTEGERP (XCAR (bar_parms))
855 && INTEGERP (XCDR (bar_parms)))
857 int start_line = XINT (XCDR (bar_parms));
859 width = XINT (XCAR (bar_parms));
860 msdos_set_cursor_shape (f, start_line, width);
863 else
865 /* Treat anything unknown as "box cursor". This includes nil, so
866 that a frame which doesn't specify a cursor type gets a box,
867 which is the default in Emacs. */
868 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
872 static void
873 IT_ring_bell (struct frame *f)
875 if (visible_bell)
877 mouse_off ();
878 ScreenVisualBell ();
880 else
882 union REGS inregs, outregs;
883 inregs.h.ah = 2;
884 inregs.h.dl = 7;
885 intdos (&inregs, &outregs);
889 /* Given a face id FACE, extract the face parameters to be used for
890 display until the face changes. The face parameters (actually, its
891 color) are used to construct the video attribute byte for each
892 glyph during the construction of the buffer that is then blitted to
893 the video RAM. */
894 static void
895 IT_set_face (int face)
897 struct frame *sf = SELECTED_FRAME();
898 struct face *fp = FACE_FROM_ID (sf, face);
899 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
900 unsigned long fg, bg, dflt_fg, dflt_bg;
901 struct tty_display_info *tty = FRAME_TTY (sf);
903 if (!fp)
905 fp = dfp;
906 /* The default face for the frame should always be realized and
907 cached. */
908 if (!fp)
909 abort ();
911 screen_face = face;
912 fg = fp->foreground;
913 bg = fp->background;
914 dflt_fg = dfp->foreground;
915 dflt_bg = dfp->background;
917 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
918 mean use the colors of the default face. Note that we assume all
919 16 colors to be available for the background, since Emacs switches
920 on this mode (and loses the blinking attribute) at startup. */
921 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
922 fg = FRAME_FOREGROUND_PIXEL (sf);
923 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
924 fg = FRAME_BACKGROUND_PIXEL (sf);
925 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
926 bg = FRAME_BACKGROUND_PIXEL (sf);
927 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
928 bg = FRAME_FOREGROUND_PIXEL (sf);
930 /* Make sure highlighted lines really stand out, come what may. */
931 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
933 unsigned long tem = fg;
935 fg = bg;
936 bg = tem;
938 /* If the user requested inverse video, obey. */
939 if (inverse_video)
941 unsigned long tem2 = fg;
943 fg = bg;
944 bg = tem2;
946 if (tty->termscript)
947 fprintf (tty->termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
948 fp->foreground, fp->background, fg, bg);
949 if (fg >= 0 && fg < 16)
951 ScreenAttrib &= 0xf0;
952 ScreenAttrib |= fg;
954 if (bg >= 0 && bg < 16)
956 ScreenAttrib &= 0x0f;
957 ScreenAttrib |= ((bg & 0x0f) << 4);
961 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
962 width of a DOS display in any known text mode. We multiply by 2 to
963 accommodate the screen attribute byte. */
964 #define MAX_SCREEN_BUF 160*2
966 Lisp_Object Vdos_unsupported_char_glyph;
967 extern unsigned char *encode_terminal_code (struct glyph *, int,
968 struct coding_system *);
969 static void
970 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
972 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
973 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
974 register int sl = str_len;
975 struct tty_display_info *tty = FRAME_TTY (f);
976 struct frame *sf;
977 unsigned char *conversion_buffer;
979 /* Do we need to consider conversion of unibyte characters to
980 multibyte? */
981 int convert_unibyte_characters
982 = (NILP (current_buffer->enable_multibyte_characters)
983 && unibyte_display_via_language_environment);
985 /* If terminal_coding does any conversion, use it, otherwise use
986 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
987 because it always returns 1 if terminal_coding.src_multibyte is 1. */
988 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
990 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
991 coding = &safe_terminal_coding;
993 if (str_len <= 0) return;
995 sf = SELECTED_FRAME();
997 /* Since faces get cached and uncached behind our back, we can't
998 rely on their indices in the cache being consistent across
999 invocations. So always reset the screen face to the default
1000 face of the frame, before writing glyphs, and let the glyphs
1001 set the right face if it's different from the default. */
1002 IT_set_face (DEFAULT_FACE_ID);
1004 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1005 the tail. */
1006 coding->mode &= ~CODING_MODE_LAST_BLOCK;
1007 screen_bp = &screen_buf[0];
1008 while (sl > 0)
1010 int cf;
1011 int n;
1013 /* If the face of this glyph is different from the current
1014 screen face, update the screen attribute byte. */
1015 cf = str->face_id;
1016 if (cf != screen_face)
1017 IT_set_face (cf); /* handles invalid faces gracefully */
1019 /* Identify a run of glyphs with the same face. */
1020 for (n = 1; n < sl; ++n)
1021 if (str[n].face_id != cf)
1022 break;
1024 if (n >= sl)
1025 /* This is the last glyph. */
1026 coding->mode |= CODING_MODE_LAST_BLOCK;
1028 conversion_buffer = encode_terminal_code (str, n, coding);
1029 if (coding->produced > 0)
1031 /* Copy the encoded bytes to the screen buffer. */
1032 for (bp = conversion_buffer; coding->produced--; bp++)
1034 /* Paranoia: discard bytes that would overrun the end of
1035 the screen buffer. */
1036 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
1038 *screen_bp++ = (unsigned char)*bp;
1039 *screen_bp++ = ScreenAttrib;
1041 if (tty->termscript)
1042 fputc (*bp, tty->termscript);
1045 /* Update STR and its remaining length. */
1046 str += n;
1047 sl -= n;
1050 /* Dump whatever we have in the screen buffer. */
1051 mouse_off_maybe ();
1052 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1053 if (screen_virtual_segment)
1054 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1055 new_pos_X += (screen_bp - screen_buf) / 2;
1058 /************************************************************************
1059 Mouse Highlight (and friends..)
1060 ************************************************************************/
1062 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1063 static Lisp_Object last_mouse_window;
1065 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1067 /* Set the mouse pointer shape according to whether it is in the
1068 area where the mouse highlight is in effect. */
1069 static void
1070 IT_set_mouse_pointer (int mode)
1072 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1073 many possibilities to change its shape, and the available
1074 functionality pretty much sucks (e.g., almost every reasonable
1075 shape will conceal the character it is on). Since the color of
1076 the pointer changes in the highlighted area, it is not clear to
1077 me whether anything else is required, anyway. */
1080 /* Display the active region described by mouse_face_*
1081 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1082 static void
1083 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
1085 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1086 struct frame *f = XFRAME (WINDOW_FRAME (w));
1087 int i;
1088 struct face *fp;
1089 struct tty_display_info *tty = FRAME_TTY (f);
1092 /* If window is in the process of being destroyed, don't bother
1093 doing anything. */
1094 if (w->current_matrix == NULL)
1095 goto set_cursor_shape;
1097 /* Recognize when we are called to operate on rows that don't exist
1098 anymore. This can happen when a window is split. */
1099 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1100 goto set_cursor_shape;
1102 /* There's no sense to do anything if the mouse face isn't realized. */
1103 if (hl > 0)
1105 if (dpyinfo->mouse_face_hidden)
1106 goto set_cursor_shape;
1108 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1109 if (!fp)
1110 goto set_cursor_shape;
1113 /* Note that mouse_face_beg_row etc. are window relative. */
1114 for (i = dpyinfo->mouse_face_beg_row;
1115 i <= dpyinfo->mouse_face_end_row;
1116 i++)
1118 int start_hpos, end_hpos;
1119 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1121 /* Don't do anything if row doesn't have valid contents. */
1122 if (!row->enabled_p)
1123 continue;
1125 /* For all but the first row, the highlight starts at column 0. */
1126 if (i == dpyinfo->mouse_face_beg_row)
1127 start_hpos = dpyinfo->mouse_face_beg_col;
1128 else
1129 start_hpos = 0;
1131 if (i == dpyinfo->mouse_face_end_row)
1132 end_hpos = dpyinfo->mouse_face_end_col;
1133 else
1134 end_hpos = row->used[TEXT_AREA];
1136 if (end_hpos <= start_hpos)
1137 continue;
1138 /* Record that some glyphs of this row are displayed in
1139 mouse-face. */
1140 row->mouse_face_p = hl > 0;
1141 if (hl > 0)
1143 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1144 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1145 int nglyphs = end_hpos - start_hpos;
1146 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1147 int start_offset = offset;
1149 if (tty->termscript)
1150 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1151 kstart, kstart + nglyphs - 1, vpos);
1153 mouse_off ();
1154 IT_set_face (dpyinfo->mouse_face_face_id);
1155 /* Since we are going to change only the _colors_ of the
1156 displayed text, there's no need to go through all the
1157 pain of generating and encoding the text from the glyphs.
1158 Instead, we simply poke the attribute byte of each
1159 affected position in video memory with the colors
1160 computed by IT_set_face! */
1161 _farsetsel (_dos_ds);
1162 while (nglyphs--)
1164 _farnspokeb (offset, ScreenAttrib);
1165 offset += 2;
1167 if (screen_virtual_segment)
1168 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1169 mouse_on ();
1171 else
1173 /* We are removing a previously-drawn mouse highlight. The
1174 safest way to do so is to redraw the glyphs anew, since
1175 all kinds of faces and display tables could have changed
1176 behind our back. */
1177 int nglyphs = end_hpos - start_hpos;
1178 int save_x = new_pos_X, save_y = new_pos_Y;
1180 if (end_hpos >= row->used[TEXT_AREA])
1181 nglyphs = row->used[TEXT_AREA] - start_hpos;
1183 /* IT_write_glyphs writes at cursor position, so we need to
1184 temporarily move cursor coordinates to the beginning of
1185 the highlight region. */
1186 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1187 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1189 if (tty->termscript)
1190 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1191 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1192 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1193 if (tty->termscript)
1194 fputs ("\n", tty->termscript);
1195 new_pos_X = save_x;
1196 new_pos_Y = save_y;
1200 set_cursor_shape:
1201 /* Change the mouse pointer shape. */
1202 IT_set_mouse_pointer (hl);
1205 /* Clear out the mouse-highlighted active region.
1206 Redraw it un-highlighted first. */
1207 static void
1208 clear_mouse_face (struct tty_display_info *dpyinfo)
1210 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1211 show_mouse_face (dpyinfo, 0);
1213 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1214 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1215 dpyinfo->mouse_face_window = Qnil;
1218 /* Find the glyph matrix position of buffer position POS in window W.
1219 *HPOS and *VPOS are set to the positions found. W's current glyphs
1220 must be up to date. If POS is above window start return (0, 0).
1221 If POS is after end of W, return end of last line in W. */
1222 static int
1223 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1225 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1226 int yb = window_text_bottom_y (w);
1227 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1229 while (row->y < yb)
1231 if (row->used[TEXT_AREA])
1232 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1233 else
1234 line_start_position = 0;
1236 if (line_start_position > pos)
1237 break;
1238 /* If the position sought is the end of the buffer,
1239 don't include the blank lines at the bottom of the window. */
1240 else if (line_start_position == pos
1241 && pos == BUF_ZV (XBUFFER (w->buffer)))
1243 maybe_next_line_p = 1;
1244 break;
1246 else if (line_start_position > 0)
1247 best_row = row;
1249 /* Don't overstep the last matrix row, lest we get into the
1250 never-never land... */
1251 if (row->y + 1 >= yb)
1252 break;
1254 ++row;
1257 /* Find the right column within BEST_ROW. */
1258 lastcol = 0;
1259 row = best_row;
1260 for (i = 0; i < row->used[TEXT_AREA]; i++)
1262 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1263 int charpos;
1265 charpos = glyph->charpos;
1266 if (charpos == pos)
1268 *hpos = i;
1269 *vpos = row->y;
1270 return 1;
1272 else if (charpos > pos)
1273 break;
1274 else if (charpos > 0)
1275 lastcol = i;
1278 /* If we're looking for the end of the buffer,
1279 and we didn't find it in the line we scanned,
1280 use the start of the following line. */
1281 if (maybe_next_line_p)
1283 ++row;
1284 lastcol = 0;
1287 *vpos = row->y;
1288 *hpos = lastcol + 1;
1289 return 0;
1292 /* Take proper action when mouse has moved to the mode or top line of
1293 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1294 mode line. X is relative to the start of the text display area of
1295 W, so the width of fringes and scroll bars must be subtracted
1296 to get a position relative to the start of the mode line. */
1297 static void
1298 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1300 struct frame *f = XFRAME (w->frame);
1301 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1302 struct glyph_row *row;
1304 if (mode_line_p)
1305 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1306 else
1307 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1309 if (row->enabled_p)
1311 extern Lisp_Object Qhelp_echo;
1312 struct glyph *glyph, *end;
1313 Lisp_Object help, map;
1315 /* Find the glyph under X. */
1316 glyph = (row->glyphs[TEXT_AREA]
1318 /* in case someone implements scroll bars some day... */
1319 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1320 end = glyph + row->used[TEXT_AREA];
1321 if (glyph < end
1322 && STRINGP (glyph->object)
1323 && STRING_INTERVALS (glyph->object)
1324 && glyph->charpos >= 0
1325 && glyph->charpos < SCHARS (glyph->object))
1327 /* If we're on a string with `help-echo' text property,
1328 arrange for the help to be displayed. This is done by
1329 setting the global variable help_echo to the help string. */
1330 help = Fget_text_property (make_number (glyph->charpos),
1331 Qhelp_echo, glyph->object);
1332 if (!NILP (help))
1334 help_echo_string = help;
1335 XSETWINDOW (help_echo_window, w);
1336 help_echo_object = glyph->object;
1337 help_echo_pos = glyph->charpos;
1343 /* Take proper action when the mouse has moved to position X, Y on
1344 frame F as regards highlighting characters that have mouse-face
1345 properties. Also de-highlighting chars where the mouse was before.
1346 X and Y can be negative or out of range. */
1347 static void
1348 IT_note_mouse_highlight (struct frame *f, int x, int y)
1350 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1351 enum window_part part = ON_NOTHING;
1352 Lisp_Object window;
1353 struct window *w;
1355 /* When a menu is active, don't highlight because this looks odd. */
1356 if (mouse_preempted)
1357 return;
1359 if (NILP (Vmouse_highlight)
1360 || !f->glyphs_initialized_p)
1361 return;
1363 dpyinfo->mouse_face_mouse_x = x;
1364 dpyinfo->mouse_face_mouse_y = y;
1365 dpyinfo->mouse_face_mouse_frame = f;
1367 if (dpyinfo->mouse_face_defer)
1368 return;
1370 if (gc_in_progress)
1372 dpyinfo->mouse_face_deferred_gc = 1;
1373 return;
1376 /* Which window is that in? */
1377 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1379 /* If we were displaying active text in another window, clear that. */
1380 if (! EQ (window, dpyinfo->mouse_face_window))
1381 clear_mouse_face (dpyinfo);
1383 /* Not on a window -> return. */
1384 if (!WINDOWP (window))
1385 return;
1387 /* Convert to window-relative coordinates. */
1388 w = XWINDOW (window);
1390 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1392 /* Mouse is on the mode or top line. */
1393 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1394 return;
1397 IT_set_mouse_pointer (0);
1399 /* Are we in a window whose display is up to date?
1400 And verify the buffer's text has not changed. */
1401 if (part == ON_TEXT
1402 && EQ (w->window_end_valid, w->buffer)
1403 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1404 && (XFASTINT (w->last_overlay_modified)
1405 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1407 int pos, i, nrows = w->current_matrix->nrows;
1408 struct glyph_row *row;
1409 struct glyph *glyph;
1411 /* Find the glyph under X/Y. */
1412 glyph = NULL;
1413 if (y >= 0 && y < nrows)
1415 row = MATRIX_ROW (w->current_matrix, y);
1416 /* Give up if some row before the one we are looking for is
1417 not enabled. */
1418 for (i = 0; i <= y; i++)
1419 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1420 break;
1421 if (i > y /* all rows upto and including the one at Y are enabled */
1422 && row->displays_text_p
1423 && x < window_box_width (w, TEXT_AREA))
1425 glyph = row->glyphs[TEXT_AREA];
1426 if (x >= row->used[TEXT_AREA])
1427 glyph = NULL;
1428 else
1430 glyph += x;
1431 if (!BUFFERP (glyph->object))
1432 glyph = NULL;
1437 /* Clear mouse face if X/Y not over text. */
1438 if (glyph == NULL)
1440 clear_mouse_face (dpyinfo);
1441 return;
1444 if (!BUFFERP (glyph->object))
1445 abort ();
1446 pos = glyph->charpos;
1448 /* Check for mouse-face and help-echo. */
1450 extern Lisp_Object Qmouse_face;
1451 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1452 int noverlays, obegv, ozv;
1453 struct buffer *obuf;
1455 /* If we get an out-of-range value, return now; avoid an error. */
1456 if (pos > BUF_Z (XBUFFER (w->buffer)))
1457 return;
1459 /* Make the window's buffer temporarily current for
1460 overlays_at and compute_char_face. */
1461 obuf = current_buffer;
1462 current_buffer = XBUFFER (w->buffer);
1463 obegv = BEGV;
1464 ozv = ZV;
1465 BEGV = BEG;
1466 ZV = Z;
1468 /* Is this char mouse-active or does it have help-echo? */
1469 XSETINT (position, pos);
1471 /* Put all the overlays we want in a vector in overlay_vec. */
1472 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1473 /* Sort overlays into increasing priority order. */
1474 noverlays = sort_overlays (overlay_vec, noverlays, w);
1476 /* Check mouse-face highlighting. */
1477 if (! (EQ (window, dpyinfo->mouse_face_window)
1478 && y >= dpyinfo->mouse_face_beg_row
1479 && y <= dpyinfo->mouse_face_end_row
1480 && (y > dpyinfo->mouse_face_beg_row
1481 || x >= dpyinfo->mouse_face_beg_col)
1482 && (y < dpyinfo->mouse_face_end_row
1483 || x < dpyinfo->mouse_face_end_col
1484 || dpyinfo->mouse_face_past_end)))
1486 /* Clear the display of the old active region, if any. */
1487 clear_mouse_face (dpyinfo);
1489 /* Find highest priority overlay that has a mouse-face prop. */
1490 overlay = Qnil;
1491 for (i = noverlays - 1; i >= 0; --i)
1493 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1494 if (!NILP (mouse_face))
1496 overlay = overlay_vec[i];
1497 break;
1501 /* If no overlay applies, get a text property. */
1502 if (NILP (overlay))
1503 mouse_face = Fget_text_property (position, Qmouse_face,
1504 w->buffer);
1506 /* Handle the overlay case. */
1507 if (! NILP (overlay))
1509 /* Find the range of text around this char that
1510 should be active. */
1511 Lisp_Object before, after;
1512 EMACS_INT ignore;
1514 before = Foverlay_start (overlay);
1515 after = Foverlay_end (overlay);
1516 /* Record this as the current active region. */
1517 fast_find_position (w, XFASTINT (before),
1518 &dpyinfo->mouse_face_beg_col,
1519 &dpyinfo->mouse_face_beg_row);
1520 dpyinfo->mouse_face_past_end
1521 = !fast_find_position (w, XFASTINT (after),
1522 &dpyinfo->mouse_face_end_col,
1523 &dpyinfo->mouse_face_end_row);
1524 dpyinfo->mouse_face_window = window;
1525 dpyinfo->mouse_face_face_id
1526 = face_at_buffer_position (w, pos, 0, 0,
1527 &ignore, pos + 1,
1528 !dpyinfo->mouse_face_hidden,
1529 -1);
1531 /* Display it as active. */
1532 show_mouse_face (dpyinfo, 1);
1534 /* Handle the text property case. */
1535 else if (! NILP (mouse_face))
1537 /* Find the range of text around this char that
1538 should be active. */
1539 Lisp_Object before, after, beginning, end;
1540 EMACS_INT ignore;
1542 beginning = Fmarker_position (w->start);
1543 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1544 - XFASTINT (w->window_end_pos)));
1545 before
1546 = Fprevious_single_property_change (make_number (pos + 1),
1547 Qmouse_face,
1548 w->buffer, beginning);
1549 after
1550 = Fnext_single_property_change (position, Qmouse_face,
1551 w->buffer, end);
1552 /* Record this as the current active region. */
1553 fast_find_position (w, XFASTINT (before),
1554 &dpyinfo->mouse_face_beg_col,
1555 &dpyinfo->mouse_face_beg_row);
1556 dpyinfo->mouse_face_past_end
1557 = !fast_find_position (w, XFASTINT (after),
1558 &dpyinfo->mouse_face_end_col,
1559 &dpyinfo->mouse_face_end_row);
1560 dpyinfo->mouse_face_window = window;
1561 dpyinfo->mouse_face_face_id
1562 = face_at_buffer_position (w, pos, 0, 0,
1563 &ignore, pos + 1,
1564 !dpyinfo->mouse_face_hidden,
1565 -1);
1567 /* Display it as active. */
1568 show_mouse_face (dpyinfo, 1);
1572 /* Look for a `help-echo' property. */
1574 Lisp_Object help;
1575 extern Lisp_Object Qhelp_echo;
1577 /* Check overlays first. */
1578 help = Qnil;
1579 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1581 overlay = overlay_vec[i];
1582 help = Foverlay_get (overlay, Qhelp_echo);
1585 if (!NILP (help))
1587 help_echo_string = help;
1588 help_echo_window = window;
1589 help_echo_object = overlay;
1590 help_echo_pos = pos;
1592 /* Try text properties. */
1593 else if (NILP (help)
1594 && ((STRINGP (glyph->object)
1595 && glyph->charpos >= 0
1596 && glyph->charpos < SCHARS (glyph->object))
1597 || (BUFFERP (glyph->object)
1598 && glyph->charpos >= BEGV
1599 && glyph->charpos < ZV)))
1601 help = Fget_text_property (make_number (glyph->charpos),
1602 Qhelp_echo, glyph->object);
1603 if (!NILP (help))
1605 help_echo_string = help;
1606 help_echo_window = window;
1607 help_echo_object = glyph->object;
1608 help_echo_pos = glyph->charpos;
1613 BEGV = obegv;
1614 ZV = ozv;
1615 current_buffer = obuf;
1620 static void
1621 IT_clear_end_of_line (struct frame *f, int first_unused)
1623 char *spaces, *sp;
1624 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1625 extern int fatal_error_in_progress;
1626 struct tty_display_info *tty = FRAME_TTY (f);
1628 if (new_pos_X >= first_unused || fatal_error_in_progress)
1629 return;
1631 IT_set_face (0);
1632 i = (j = first_unused - new_pos_X) * 2;
1633 if (tty->termscript)
1634 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1635 spaces = sp = alloca (i);
1637 while (--j >= 0)
1639 *sp++ = ' ';
1640 *sp++ = ScreenAttrib;
1643 mouse_off_maybe ();
1644 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1645 if (screen_virtual_segment)
1646 dosv_refresh_virtual_screen (offset, i / 2);
1648 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1649 Let's follow their lead, in case someone relies on this. */
1650 new_pos_X = first_unused;
1653 static void
1654 IT_clear_screen (struct frame *f)
1656 struct tty_display_info *tty = FRAME_TTY (f);
1658 if (tty->termscript)
1659 fprintf (tty->termscript, "<CLR:SCR>");
1660 /* We are sometimes called (from clear_garbaged_frames) when a new
1661 frame is being created, but its faces are not yet realized. In
1662 such a case we cannot call IT_set_face, since it will fail to find
1663 any valid faces and will abort. Instead, use the initial screen
1664 colors; that should mimic what a Unix tty does, which simply clears
1665 the screen with whatever default colors are in use. */
1666 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1667 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1668 else
1669 IT_set_face (0);
1670 mouse_off ();
1671 ScreenClear ();
1672 if (screen_virtual_segment)
1673 dosv_refresh_virtual_screen (0, screen_size);
1674 new_pos_X = new_pos_Y = 0;
1677 static void
1678 IT_clear_to_end (struct frame *f)
1680 struct tty_display_info *tty = FRAME_TTY (f);
1682 if (tty->termscript)
1683 fprintf (tty->termscript, "<CLR:EOS>");
1685 while (new_pos_Y < screen_size_Y) {
1686 new_pos_X = 0;
1687 IT_clear_end_of_line (f, screen_size_X);
1688 new_pos_Y++;
1692 static void
1693 IT_cursor_to (struct frame *f, int y, int x)
1695 struct tty_display_info *tty = FRAME_TTY (f);
1697 if (tty->termscript)
1698 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1699 new_pos_X = x;
1700 new_pos_Y = y;
1703 static int cursor_cleared;
1705 static void
1706 IT_display_cursor (int on)
1708 struct tty_display_info *tty = CURTTY ();
1710 if (on && cursor_cleared)
1712 ScreenSetCursor (current_pos_Y, current_pos_X);
1713 cursor_cleared = 0;
1714 if (tty->termscript)
1715 fprintf (tty->termscript, "\nCURSOR ON");
1717 else if (!on && !cursor_cleared)
1719 ScreenSetCursor (-1, -1);
1720 cursor_cleared = 1;
1721 if (tty->termscript)
1722 fprintf (tty->termscript, "\nCURSOR OFF");
1726 /* Emacs calls cursor-movement functions a lot when it updates the
1727 display (probably a legacy of old terminals where you cannot
1728 update a screen line without first moving the cursor there).
1729 However, cursor movement is expensive on MSDOS (it calls a slow
1730 BIOS function and requires 2 mode switches), while actual screen
1731 updates access the video memory directly and don't depend on
1732 cursor position. To avoid slowing down the redisplay, we cheat:
1733 all functions that move the cursor only set internal variables
1734 which record the cursor position, whereas the cursor is only
1735 moved to its final position whenever screen update is complete.
1737 `IT_cmgoto' is called from the keyboard reading loop and when the
1738 frame update is complete. This means that we are ready for user
1739 input, so we update the cursor position to show where the point is,
1740 and also make the mouse pointer visible.
1742 Special treatment is required when the cursor is in the echo area,
1743 to put the cursor at the end of the text displayed there. */
1745 static void
1746 IT_cmgoto (FRAME_PTR f)
1748 /* Only set the cursor to where it should be if the display is
1749 already in sync with the window contents. */
1750 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1751 struct tty_display_info *tty = FRAME_TTY (f);
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 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= 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 (tty->termscript)
1802 fprintf (tty->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_update_begin (struct frame *f)
1817 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1818 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1820 if (display_info->termscript)
1821 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1823 BLOCK_INPUT;
1825 if (f && f == mouse_face_frame)
1827 /* Don't do highlighting for mouse motion during the update. */
1828 display_info->mouse_face_defer = 1;
1830 /* If F needs to be redrawn, simply forget about any prior mouse
1831 highlighting. */
1832 if (FRAME_GARBAGED_P (f))
1833 display_info->mouse_face_window = Qnil;
1835 /* Can we tell that this update does not affect the window
1836 where the mouse highlight is? If so, no need to turn off.
1837 Likewise, don't do anything if none of the enabled rows
1838 contains glyphs highlighted in mouse face. */
1839 if (!NILP (display_info->mouse_face_window)
1840 && WINDOWP (display_info->mouse_face_window))
1842 struct window *w = XWINDOW (display_info->mouse_face_window);
1843 int i;
1845 /* If the mouse highlight is in the window that was deleted
1846 (e.g., if it was popped by completion), clear highlight
1847 unconditionally. */
1848 if (NILP (w->buffer))
1849 display_info->mouse_face_window = Qnil;
1850 else
1852 for (i = 0; i < w->desired_matrix->nrows; ++i)
1853 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1854 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1855 break;
1858 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1859 clear_mouse_face (display_info);
1862 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1864 /* If the frame with mouse highlight was deleted, invalidate the
1865 highlight info. */
1866 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1867 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1868 display_info->mouse_face_window = Qnil;
1869 display_info->mouse_face_deferred_gc = 0;
1870 display_info->mouse_face_mouse_frame = NULL;
1873 UNBLOCK_INPUT;
1876 static void
1877 IT_update_end (struct frame *f)
1879 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1881 if (dpyinfo->termscript)
1882 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1883 dpyinfo->mouse_face_defer = 0;
1886 static void
1887 IT_frame_up_to_date (struct frame *f)
1889 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1890 Lisp_Object new_cursor, frame_desired_cursor;
1891 struct window *sw;
1893 if (dpyinfo->mouse_face_deferred_gc
1894 || (f && f == dpyinfo->mouse_face_mouse_frame))
1896 BLOCK_INPUT;
1897 if (dpyinfo->mouse_face_mouse_frame)
1898 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1899 dpyinfo->mouse_face_mouse_x,
1900 dpyinfo->mouse_face_mouse_y);
1901 dpyinfo->mouse_face_deferred_gc = 0;
1902 UNBLOCK_INPUT;
1905 /* Set the cursor type to whatever they wanted. In a minibuffer
1906 window, we want the cursor to appear only if we are reading input
1907 from this window, and we want the cursor to be taken from the
1908 frame parameters. For the selected window, we use either its
1909 buffer-local value or the value from the frame parameters if the
1910 buffer doesn't define its local value for the cursor type. */
1911 sw = XWINDOW (f->selected_window);
1912 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1913 if (cursor_in_echo_area
1914 && FRAME_HAS_MINIBUF_P (f)
1915 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1916 && sw == XWINDOW (echo_area_window))
1917 new_cursor = frame_desired_cursor;
1918 else
1920 struct buffer *b = XBUFFER (sw->buffer);
1922 if (EQ (b->cursor_type, Qt))
1923 new_cursor = frame_desired_cursor;
1924 else if (NILP (b->cursor_type)) /* nil means no cursor */
1925 new_cursor = Fcons (Qbar, make_number (0));
1926 else
1927 new_cursor = b->cursor_type;
1930 IT_set_cursor_type (f, new_cursor);
1932 IT_cmgoto (f); /* position cursor when update is done */
1935 /* Copy LEN glyphs displayed on a single line whose vertical position
1936 is YPOS, beginning at horizontal position XFROM to horizontal
1937 position XTO, by moving blocks in the video memory. Used by
1938 functions that insert and delete glyphs. */
1939 static void
1940 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1942 /* The offsets of source and destination relative to the
1943 conventional memorty selector. */
1944 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1945 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1947 if (from == to || len <= 0)
1948 return;
1950 _farsetsel (_dos_ds);
1952 /* The source and destination might overlap, so we need to move
1953 glyphs non-destructively. */
1954 if (from > to)
1956 for ( ; len; from += 2, to += 2, len--)
1957 _farnspokew (to, _farnspeekw (from));
1959 else
1961 from += (len - 1) * 2;
1962 to += (len - 1) * 2;
1963 for ( ; len; from -= 2, to -= 2, len--)
1964 _farnspokew (to, _farnspeekw (from));
1966 if (screen_virtual_segment)
1967 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1970 /* Insert and delete glyphs. */
1971 static void
1972 IT_insert_glyphs (f, start, len)
1973 struct frame *f;
1974 register struct glyph *start;
1975 register int len;
1977 int shift_by_width = screen_size_X - (new_pos_X + len);
1979 /* Shift right the glyphs from the nominal cursor position to the
1980 end of this line. */
1981 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1983 /* Now write the glyphs to be inserted. */
1984 IT_write_glyphs (f, start, len);
1987 static void
1988 IT_delete_glyphs (f, n)
1989 struct frame *f;
1990 register int n;
1992 abort ();
1995 /* set-window-configuration on window.c needs this. */
1996 void
1997 x_set_menu_bar_lines (f, value, oldval)
1998 struct frame *f;
1999 Lisp_Object value, oldval;
2001 set_menu_bar_lines (f, value, oldval);
2004 /* This was copied from xfaces.c */
2006 extern Lisp_Object Qbackground_color;
2007 extern Lisp_Object Qforeground_color;
2008 Lisp_Object Qreverse;
2009 extern Lisp_Object Qtitle;
2011 /* IT_set_terminal_modes is called when emacs is started,
2012 resumed, and whenever the screen is redrawn! */
2014 static void
2015 IT_set_terminal_modes (struct terminal *term)
2017 struct tty_display_info *tty;
2019 /* If called with initial terminal, it's too early to do anything
2020 useful. */
2021 if (term->type == output_initial)
2022 return;
2024 tty = term->display_info.tty;
2026 if (tty->termscript)
2027 fprintf (tty->termscript, "\n<SET_TERM>");
2029 screen_size_X = ScreenCols ();
2030 screen_size_Y = ScreenRows ();
2031 screen_size = screen_size_X * screen_size_Y;
2033 new_pos_X = new_pos_Y = 0;
2034 current_pos_X = current_pos_Y = -1;
2036 if (term_setup_done)
2037 return;
2038 term_setup_done = 1;
2040 startup_screen_size_X = screen_size_X;
2041 startup_screen_size_Y = screen_size_Y;
2042 startup_screen_attrib = ScreenAttrib;
2044 #if __DJGPP__ > 1
2045 /* Is DOS/V (or any other RSIS software which relocates
2046 the screen) installed? */
2048 unsigned short es_value;
2049 __dpmi_regs regs;
2051 regs.h.ah = 0xfe; /* get relocated screen address */
2052 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2053 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2054 else if (screen_old_address) /* already switched to Japanese mode once */
2055 regs.x.es = (screen_old_address >> 4) & 0xffff;
2056 else
2057 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2058 regs.x.di = 0;
2059 es_value = regs.x.es;
2060 __dpmi_int (0x10, &regs);
2062 if (regs.x.es != es_value)
2064 /* screen_old_address is only set if ScreenPrimary does NOT
2065 already point to the relocated buffer address returned by
2066 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2067 ScreenPrimary to that address at startup under DOS/V. */
2068 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2069 screen_old_address = ScreenPrimary;
2070 screen_virtual_segment = regs.x.es;
2071 screen_virtual_offset = regs.x.di;
2072 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2075 #endif /* __DJGPP__ > 1 */
2077 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2078 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2080 bright_bg ();
2083 /* IT_reset_terminal_modes is called when emacs is
2084 suspended or killed. */
2086 static void
2087 IT_reset_terminal_modes (struct terminal *term)
2089 int display_row_start = (int) ScreenPrimary;
2090 int saved_row_len = startup_screen_size_X * 2;
2091 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
2092 int to_next_row = update_row_len;
2093 unsigned char *saved_row = startup_screen_buffer;
2094 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
2095 struct tty_display_info *tty = term->display_info.tty;
2097 if (tty->termscript)
2098 fprintf (tty->termscript, "\n<RESET_TERM>");
2100 if (!term_setup_done)
2101 return;
2103 mouse_off ();
2105 /* Leave the video system in the same state as we found it,
2106 as far as the blink/bright-background bit is concerned. */
2107 maybe_enable_blinking ();
2109 /* We have a situation here.
2110 We cannot just do ScreenUpdate(startup_screen_buffer) because
2111 the luser could have changed screen dimensions inside Emacs
2112 and failed (or didn't want) to restore them before killing
2113 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2114 thus will happily use memory outside what was allocated for
2115 `startup_screen_buffer'.
2116 Thus we only restore as much as the current screen dimensions
2117 can hold, and clear the rest (if the saved screen is smaller than
2118 the current) with the color attribute saved at startup. The cursor
2119 is also restored within the visible dimensions. */
2121 ScreenAttrib = startup_screen_attrib;
2123 /* Don't restore the screen if we are exiting less than 2 seconds
2124 after startup: we might be crashing, and the screen might show
2125 some vital clues to what's wrong. */
2126 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2128 ScreenClear ();
2129 if (screen_virtual_segment)
2130 dosv_refresh_virtual_screen (0, screen_size);
2132 if (update_row_len > saved_row_len)
2133 update_row_len = saved_row_len;
2134 if (current_rows > startup_screen_size_Y)
2135 current_rows = startup_screen_size_Y;
2137 if (tty->termscript)
2138 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2139 update_row_len / 2, current_rows);
2141 while (current_rows--)
2143 dosmemput (saved_row, update_row_len, display_row_start);
2144 if (screen_virtual_segment)
2145 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2146 update_row_len / 2);
2147 saved_row += saved_row_len;
2148 display_row_start += to_next_row;
2151 if (startup_pos_X < cursor_pos_X)
2152 cursor_pos_X = startup_pos_X;
2153 if (startup_pos_Y < cursor_pos_Y)
2154 cursor_pos_Y = startup_pos_Y;
2156 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2157 xfree (startup_screen_buffer);
2158 startup_screen_buffer = NULL;
2160 term_setup_done = 0;
2163 static void
2164 IT_set_terminal_window (struct frame *f, int foo)
2168 /* Remember the screen colors of the curent frame, to serve as the
2169 default colors for newly-created frames. */
2170 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2171 Smsdos_remember_default_colors, 1, 1, 0,
2172 doc: /* Remember the screen colors of the current frame. */)
2173 (frame)
2174 Lisp_Object frame;
2176 struct frame *f;
2178 CHECK_FRAME (frame);
2179 f = XFRAME (frame);
2181 /* This function is called after applying default-frame-alist to the
2182 initial frame. At that time, if reverse-colors option was
2183 specified in default-frame-alist, it was already applied, and
2184 frame colors are reversed. */
2185 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2186 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2189 void
2190 IT_set_frame_parameters (f, alist)
2191 struct frame *f;
2192 Lisp_Object alist;
2194 Lisp_Object tail;
2195 int i, j, length = XINT (Flength (alist));
2196 Lisp_Object *parms
2197 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2198 Lisp_Object *values
2199 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2200 /* Do we have to reverse the foreground and background colors? */
2201 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2202 int need_to_reverse, was_reverse = reverse;
2203 int redraw = 0, fg_set = 0, bg_set = 0;
2204 unsigned long orig_fg, orig_bg;
2205 Lisp_Object frame_bg, frame_fg;
2206 extern Lisp_Object Qdefault, QCforeground, QCbackground;
2207 struct tty_display_info *tty = FRAME_TTY (f);
2209 /* If we are creating a new frame, begin with the original screen colors
2210 used for the initial frame. */
2211 if (EQ (alist, Vdefault_frame_alist)
2212 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2214 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2215 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2216 init_frame_faces (f);
2218 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2219 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2220 frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2221 frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2222 /* frame_fg and frame_bg could be nil if, for example,
2223 f->param_alist is nil, e.g. if we are called from
2224 Fmake_terminal_frame. */
2225 if (NILP (frame_fg))
2226 frame_fg = build_string (unspecified_fg);
2227 if (NILP (frame_bg))
2228 frame_bg = build_string (unspecified_bg);
2230 /* Extract parm names and values into those vectors. */
2231 i = 0;
2232 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2234 Lisp_Object elt;
2236 elt = Fcar (tail);
2237 parms[i] = Fcar (elt);
2238 CHECK_SYMBOL (parms[i]);
2239 values[i] = Fcdr (elt);
2240 i++;
2243 j = i;
2245 for (i = 0; i < j; i++)
2247 Lisp_Object prop, val;
2249 prop = parms[i];
2250 val = values[i];
2252 if (EQ (prop, Qreverse))
2253 reverse = EQ (val, Qt);
2256 need_to_reverse = reverse && !was_reverse;
2257 if (tty->termscript && need_to_reverse)
2258 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2260 /* Now process the alist elements in reverse of specified order. */
2261 for (i--; i >= 0; i--)
2263 Lisp_Object prop, val, frame;
2265 prop = parms[i];
2266 val = values[i];
2268 if (EQ (prop, Qforeground_color))
2270 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2271 ? LFACE_BACKGROUND_INDEX
2272 : LFACE_FOREGROUND_INDEX);
2273 if (new_color != FACE_TTY_DEFAULT_COLOR
2274 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2275 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2277 FRAME_FOREGROUND_PIXEL (f) = new_color;
2278 /* Make sure the foreground of the default face for this
2279 frame is changed as well. */
2280 XSETFRAME (frame, f);
2281 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2282 val, frame);
2283 fg_set = 1;
2284 redraw = 1;
2285 if (tty->termscript)
2286 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2289 else if (EQ (prop, Qbackground_color))
2291 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2292 ? LFACE_FOREGROUND_INDEX
2293 : LFACE_BACKGROUND_INDEX);
2294 if (new_color != FACE_TTY_DEFAULT_COLOR
2295 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2296 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2298 FRAME_BACKGROUND_PIXEL (f) = new_color;
2299 /* Make sure the background of the default face for this
2300 frame is changed as well. */
2301 XSETFRAME (frame, f);
2302 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2303 val, frame);
2304 bg_set = 1;
2305 redraw = 1;
2306 if (tty->termscript)
2307 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2310 else if (EQ (prop, Qtitle))
2312 x_set_title (f, val);
2313 if (tty->termscript)
2314 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2316 else if (EQ (prop, Qcursor_type))
2318 IT_set_cursor_type (f, val);
2319 if (tty->termscript)
2320 fprintf (tty->termscript, "<CTYPE: %s>\n",
2321 EQ (val, Qbar) || EQ (val, Qhbar)
2322 || CONSP (val) && (EQ (XCAR (val), Qbar)
2323 || EQ (XCAR (val), Qhbar))
2324 ? "bar" : "box");
2326 else if (EQ (prop, Qtty_type))
2328 internal_terminal_init ();
2329 if (tty->termscript)
2330 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2331 SBYTES (val), SDATA (val));
2333 store_frame_param (f, prop, val);
2336 /* If they specified "reverse", but not the colors, we need to swap
2337 the current frame colors. */
2338 if (need_to_reverse)
2340 Lisp_Object frame;
2342 if (!fg_set)
2344 XSETFRAME (frame, f);
2345 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2346 tty_color_name (f, orig_bg),
2347 frame);
2348 redraw = 1;
2350 if (!bg_set)
2352 XSETFRAME (frame, f);
2353 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2354 tty_color_name (f, orig_fg),
2355 frame);
2356 redraw = 1;
2360 if (redraw)
2362 face_change_count++; /* forces xdisp.c to recompute basic faces */
2363 if (f == SELECTED_FRAME())
2364 redraw_frame (f);
2368 extern void init_frame_faces (FRAME_PTR);
2370 #endif /* !HAVE_X_WINDOWS */
2373 /* Do we need the internal terminal? */
2375 void
2376 internal_terminal_init ()
2378 static int init_needed = 1;
2379 char *term = getenv ("TERM"), *colors;
2380 struct frame *sf = SELECTED_FRAME();
2381 struct tty_display_info *tty;
2383 #ifdef HAVE_X_WINDOWS
2384 if (!inhibit_window_system)
2385 return;
2386 #endif
2388 /* If this is the initial terminal, we are done here. */
2389 if (sf->output_method == output_initial)
2390 return;
2392 internal_terminal
2393 = (!noninteractive) && term && !strcmp (term, "internal");
2395 #ifndef HAVE_X_WINDOWS
2396 if (!internal_terminal || inhibit_window_system)
2398 sf->output_method = output_termcap;
2399 return;
2402 tty = FRAME_TTY (sf);
2403 current_kboard->Vwindow_system = Qpc;
2404 sf->output_method = output_msdos_raw;
2405 if (init_needed)
2407 if (!tty->termscript && getenv ("EMACSTEST"))
2408 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2409 if (tty->termscript)
2411 time_t now = time (NULL);
2412 struct tm *tnow = localtime (&now);
2413 char tbuf[100];
2415 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2416 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2417 fprintf (tty->termscript, "=====================\n\n");
2420 Vinitial_window_system = Qpc;
2421 Vwindow_system_version = make_number (23); /* RE Emacs version */
2422 tty->terminal->type = output_msdos_raw;
2424 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2425 address. */
2426 screen_old_address = 0;
2428 /* Forget the stale screen colors as well. */
2429 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2431 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2432 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2433 bright_bg ();
2434 colors = getenv ("EMACSCOLORS");
2435 if (colors && strlen (colors) >= 2)
2437 /* The colors use 4 bits each (we enable bright background). */
2438 if (isdigit (colors[0]))
2439 colors[0] -= '0';
2440 else if (isxdigit (colors[0]))
2441 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2442 if (colors[0] >= 0 && colors[0] < 16)
2443 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2444 if (isdigit (colors[1]))
2445 colors[1] -= '0';
2446 else if (isxdigit (colors[1]))
2447 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2448 if (colors[1] >= 0 && colors[1] < 16)
2449 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2451 the_only_display_info.mouse_face_mouse_frame = NULL;
2452 the_only_display_info.mouse_face_deferred_gc = 0;
2453 the_only_display_info.mouse_face_beg_row =
2454 the_only_display_info.mouse_face_beg_col = -1;
2455 the_only_display_info.mouse_face_end_row =
2456 the_only_display_info.mouse_face_end_col = -1;
2457 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2458 the_only_display_info.mouse_face_window = Qnil;
2459 the_only_display_info.mouse_face_mouse_x =
2460 the_only_display_info.mouse_face_mouse_y = 0;
2461 the_only_display_info.mouse_face_defer = 0;
2462 the_only_display_info.mouse_face_hidden = 0;
2464 if (have_mouse) /* detected in dos_ttraw, which see */
2466 have_mouse = 1; /* enable mouse */
2467 mouse_visible = 0;
2468 mouse_setup_buttons (mouse_button_count);
2469 tty->terminal->mouse_position_hook = &mouse_get_pos;
2470 mouse_init ();
2473 if (tty->termscript && screen_size)
2474 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2475 screen_size_X, screen_size_Y);
2477 init_frame_faces (sf);
2478 init_needed = 0;
2480 #endif
2483 void
2484 initialize_msdos_display (struct terminal *term)
2486 term->rif = 0; /* we don't support window-based display */
2487 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2488 term->clear_to_end_hook = IT_clear_to_end;
2489 term->clear_frame_hook = IT_clear_screen;
2490 term->clear_end_of_line_hook = IT_clear_end_of_line;
2491 term->ins_del_lines_hook = 0;
2492 term->insert_glyphs_hook = IT_insert_glyphs;
2493 term->write_glyphs_hook = IT_write_glyphs;
2494 term->delete_glyphs_hook = IT_delete_glyphs;
2495 term->ring_bell_hook = IT_ring_bell;
2496 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2497 term->set_terminal_modes_hook = IT_set_terminal_modes;
2498 term->set_terminal_window_hook = IT_set_terminal_window;
2499 term->update_begin_hook = IT_update_begin;
2500 term->update_end_hook = IT_update_end;
2501 term->frame_up_to_date_hook = IT_frame_up_to_date;
2502 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2503 term->frame_rehighlight_hook = 0;
2504 term->frame_raise_lower_hook = 0;
2505 term->set_vertical_scroll_bar_hook = 0;
2506 term->condemn_scroll_bars_hook = 0;
2507 term->redeem_scroll_bar_hook = 0;
2508 term->judge_scroll_bars_hook = 0;
2509 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2512 dos_get_saved_screen (screen, rows, cols)
2513 char **screen;
2514 int *rows;
2515 int *cols;
2517 #ifndef HAVE_X_WINDOWS
2518 *screen = startup_screen_buffer;
2519 *cols = startup_screen_size_X;
2520 *rows = startup_screen_size_Y;
2521 return *screen != (char *)0;
2522 #else
2523 return 0;
2524 #endif
2527 #ifndef HAVE_X_WINDOWS
2529 /* We are not X, but we can emulate it well enough for our needs... */
2530 void
2531 check_x (void)
2533 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2534 error ("Not running under a window system");
2537 #endif
2540 /* ----------------------- Keyboard control ----------------------
2542 * Keymaps reflect the following keyboard layout:
2544 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2545 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2546 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2547 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2548 * SPACE
2551 #define Ignore 0x0000
2552 #define Normal 0x0000 /* normal key - alt changes scan-code */
2553 #define FctKey 0x1000 /* func key if c == 0, else c */
2554 #define Special 0x2000 /* func key even if c != 0 */
2555 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2556 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2557 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2558 #define Grey 0x6000 /* Grey keypad key */
2560 #define Alt 0x0100 /* alt scan-code */
2561 #define Ctrl 0x0200 /* ctrl scan-code */
2562 #define Shift 0x0400 /* shift scan-code */
2564 static int extended_kbd; /* 101 (102) keyboard present. */
2566 struct kbd_translate {
2567 unsigned char sc;
2568 unsigned char ch;
2569 unsigned short code;
2572 struct dos_keyboard_map
2574 char *unshifted;
2575 char *shifted;
2576 char *alt_gr;
2577 struct kbd_translate *translate_table;
2581 static struct dos_keyboard_map us_keyboard = {
2582 /* 0 1 2 3 4 5 */
2583 /* 01234567890123456789012345678901234567890 12345678901234 */
2584 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2585 /* 0123456789012345678901234567890123456789 012345678901234 */
2586 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2587 0, /* no Alt-Gr key */
2588 0 /* no translate table */
2591 static struct dos_keyboard_map fr_keyboard = {
2592 /* 0 1 2 3 4 5 */
2593 /* 012 3456789012345678901234567890123456789012345678901234 */
2594 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2595 /* 0123456789012345678901234567890123456789012345678901234 */
2596 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2597 /* 01234567 89012345678901234567890123456789012345678901234 */
2598 " ~#{[|`\\^@]} Ï ",
2599 0 /* no translate table */
2603 * Italian keyboard support, country code 39.
2604 * '<' 56:3c*0000
2605 * '>' 56:3e*0000
2606 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2607 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2610 static struct kbd_translate it_kbd_translate_table[] = {
2611 { 0x56, 0x3c, Normal | 13 },
2612 { 0x56, 0x3e, Normal | 27 },
2613 { 0, 0, 0 }
2615 static struct dos_keyboard_map it_keyboard = {
2616 /* 0 1 2 3 4 5 */
2617 /* 0 123456789012345678901234567890123456789012345678901234 */
2618 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2619 /* 01 23456789012345678901234567890123456789012345678901234 */
2620 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2621 /* 0123456789012345678901234567890123456789012345678901234 */
2622 " {}~` [] @# ",
2623 it_kbd_translate_table
2626 static struct dos_keyboard_map dk_keyboard = {
2627 /* 0 1 2 3 4 5 */
2628 /* 0123456789012345678901234567890123456789012345678901234 */
2629 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2630 /* 01 23456789012345678901234567890123456789012345678901234 */
2631 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2632 /* 0123456789012345678901234567890123456789012345678901234 */
2633 " @œ$ {[]} | ",
2634 0 /* no translate table */
2637 static struct kbd_translate jp_kbd_translate_table[] = {
2638 { 0x73, 0x5c, Normal | 0 },
2639 { 0x73, 0x5f, Normal | 0 },
2640 { 0x73, 0x1c, Map | 0 },
2641 { 0x7d, 0x5c, Normal | 13 },
2642 { 0x7d, 0x7c, Normal | 13 },
2643 { 0x7d, 0x1c, Map | 13 },
2644 { 0, 0, 0 }
2646 static struct dos_keyboard_map jp_keyboard = {
2647 /* 0 1 2 3 4 5 */
2648 /* 0123456789012 345678901234567890123456789012345678901234 */
2649 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2650 /* 01 23456789012345678901234567890123456789012345678901234 */
2651 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2652 0, /* no Alt-Gr key */
2653 jp_kbd_translate_table
2656 static struct keyboard_layout_list
2658 int country_code;
2659 struct dos_keyboard_map *keyboard_map;
2660 } keyboard_layout_list[] =
2662 1, &us_keyboard,
2663 33, &fr_keyboard,
2664 39, &it_keyboard,
2665 45, &dk_keyboard,
2666 81, &jp_keyboard
2669 static struct dos_keyboard_map *keyboard;
2670 static int keyboard_map_all;
2671 static int international_keyboard;
2674 dos_set_keyboard (code, always)
2675 int code;
2676 int always;
2678 int i;
2679 _go32_dpmi_registers regs;
2681 /* See if Keyb.Com is installed (for international keyboard support).
2682 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2683 of Windows 9X! So don't do that! */
2684 regs.x.ax = 0xad80;
2685 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2686 _go32_dpmi_simulate_int (0x2f, &regs);
2687 if (regs.h.al == 0xff)
2688 international_keyboard = 1;
2690 /* Initialize to US settings, for countries that don't have their own. */
2691 keyboard = keyboard_layout_list[0].keyboard_map;
2692 keyboard_map_all = always;
2693 dos_keyboard_layout = 1;
2695 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2696 if (code == keyboard_layout_list[i].country_code)
2698 keyboard = keyboard_layout_list[i].keyboard_map;
2699 keyboard_map_all = always;
2700 dos_keyboard_layout = code;
2701 return 1;
2703 return 0;
2706 static struct
2708 unsigned char char_code; /* normal code */
2709 unsigned char meta_code; /* M- code */
2710 unsigned char keypad_code; /* keypad code */
2711 unsigned char editkey_code; /* edit key */
2712 } keypad_translate_map[] = {
2713 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2714 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2715 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2716 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2717 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2718 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2719 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2720 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2721 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2722 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2723 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2726 static struct
2728 unsigned char char_code; /* normal code */
2729 unsigned char keypad_code; /* keypad code */
2730 } grey_key_translate_map[] = {
2731 '/', 0xaf, /* kp-decimal */
2732 '*', 0xaa, /* kp-multiply */
2733 '-', 0xad, /* kp-subtract */
2734 '+', 0xab, /* kp-add */
2735 '\r', 0x8d /* kp-enter */
2738 static unsigned short
2739 ibmpc_translate_map[] =
2741 /* --------------- 00 to 0f --------------- */
2742 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2743 Alt | ModFct | 0x1b, /* Escape */
2744 Normal | 1, /* '1' */
2745 Normal | 2, /* '2' */
2746 Normal | 3, /* '3' */
2747 Normal | 4, /* '4' */
2748 Normal | 5, /* '5' */
2749 Normal | 6, /* '6' */
2750 Normal | 7, /* '7' */
2751 Normal | 8, /* '8' */
2752 Normal | 9, /* '9' */
2753 Normal | 10, /* '0' */
2754 Normal | 11, /* '-' */
2755 Normal | 12, /* '=' */
2756 Special | 0x08, /* Backspace */
2757 ModFct | 0x74, /* Tab/Backtab */
2759 /* --------------- 10 to 1f --------------- */
2760 Map | 15, /* 'q' */
2761 Map | 16, /* 'w' */
2762 Map | 17, /* 'e' */
2763 Map | 18, /* 'r' */
2764 Map | 19, /* 't' */
2765 Map | 20, /* 'y' */
2766 Map | 21, /* 'u' */
2767 Map | 22, /* 'i' */
2768 Map | 23, /* 'o' */
2769 Map | 24, /* 'p' */
2770 Map | 25, /* '[' */
2771 Map | 26, /* ']' */
2772 ModFct | 0x0d, /* Return */
2773 Ignore, /* Ctrl */
2774 Map | 30, /* 'a' */
2775 Map | 31, /* 's' */
2777 /* --------------- 20 to 2f --------------- */
2778 Map | 32, /* 'd' */
2779 Map | 33, /* 'f' */
2780 Map | 34, /* 'g' */
2781 Map | 35, /* 'h' */
2782 Map | 36, /* 'j' */
2783 Map | 37, /* 'k' */
2784 Map | 38, /* 'l' */
2785 Map | 39, /* ';' */
2786 Map | 40, /* '\'' */
2787 Map | 0, /* '`' */
2788 Ignore, /* Left shift */
2789 Map | 41, /* '\\' */
2790 Map | 45, /* 'z' */
2791 Map | 46, /* 'x' */
2792 Map | 47, /* 'c' */
2793 Map | 48, /* 'v' */
2795 /* --------------- 30 to 3f --------------- */
2796 Map | 49, /* 'b' */
2797 Map | 50, /* 'n' */
2798 Map | 51, /* 'm' */
2799 Map | 52, /* ',' */
2800 Map | 53, /* '.' */
2801 Map | 54, /* '/' */
2802 Ignore, /* Right shift */
2803 Grey | 1, /* Grey * */
2804 Ignore, /* Alt */
2805 Normal | 55, /* ' ' */
2806 Ignore, /* Caps Lock */
2807 FctKey | 0xbe, /* F1 */
2808 FctKey | 0xbf, /* F2 */
2809 FctKey | 0xc0, /* F3 */
2810 FctKey | 0xc1, /* F4 */
2811 FctKey | 0xc2, /* F5 */
2813 /* --------------- 40 to 4f --------------- */
2814 FctKey | 0xc3, /* F6 */
2815 FctKey | 0xc4, /* F7 */
2816 FctKey | 0xc5, /* F8 */
2817 FctKey | 0xc6, /* F9 */
2818 FctKey | 0xc7, /* F10 */
2819 Ignore, /* Num Lock */
2820 Ignore, /* Scroll Lock */
2821 KeyPad | 7, /* Home */
2822 KeyPad | 8, /* Up */
2823 KeyPad | 9, /* Page Up */
2824 Grey | 2, /* Grey - */
2825 KeyPad | 4, /* Left */
2826 KeyPad | 5, /* Keypad 5 */
2827 KeyPad | 6, /* Right */
2828 Grey | 3, /* Grey + */
2829 KeyPad | 1, /* End */
2831 /* --------------- 50 to 5f --------------- */
2832 KeyPad | 2, /* Down */
2833 KeyPad | 3, /* Page Down */
2834 KeyPad | 0, /* Insert */
2835 KeyPad | 10, /* Delete */
2836 Shift | FctKey | 0xbe, /* (Shift) F1 */
2837 Shift | FctKey | 0xbf, /* (Shift) F2 */
2838 Shift | FctKey | 0xc0, /* (Shift) F3 */
2839 Shift | FctKey | 0xc1, /* (Shift) F4 */
2840 Shift | FctKey | 0xc2, /* (Shift) F5 */
2841 Shift | FctKey | 0xc3, /* (Shift) F6 */
2842 Shift | FctKey | 0xc4, /* (Shift) F7 */
2843 Shift | FctKey | 0xc5, /* (Shift) F8 */
2844 Shift | FctKey | 0xc6, /* (Shift) F9 */
2845 Shift | FctKey | 0xc7, /* (Shift) F10 */
2846 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2847 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2849 /* --------------- 60 to 6f --------------- */
2850 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2851 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2852 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2853 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2854 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2855 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2856 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2857 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2858 Alt | FctKey | 0xbe, /* (Alt) F1 */
2859 Alt | FctKey | 0xbf, /* (Alt) F2 */
2860 Alt | FctKey | 0xc0, /* (Alt) F3 */
2861 Alt | FctKey | 0xc1, /* (Alt) F4 */
2862 Alt | FctKey | 0xc2, /* (Alt) F5 */
2863 Alt | FctKey | 0xc3, /* (Alt) F6 */
2864 Alt | FctKey | 0xc4, /* (Alt) F7 */
2865 Alt | FctKey | 0xc5, /* (Alt) F8 */
2867 /* --------------- 70 to 7f --------------- */
2868 Alt | FctKey | 0xc6, /* (Alt) F9 */
2869 Alt | FctKey | 0xc7, /* (Alt) F10 */
2870 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2871 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2872 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2873 Ctrl | KeyPad | 1, /* (Ctrl) End */
2874 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2875 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2876 Alt | Map | 1, /* '1' */
2877 Alt | Map | 2, /* '2' */
2878 Alt | Map | 3, /* '3' */
2879 Alt | Map | 4, /* '4' */
2880 Alt | Map | 5, /* '5' */
2881 Alt | Map | 6, /* '6' */
2882 Alt | Map | 7, /* '7' */
2883 Alt | Map | 8, /* '8' */
2885 /* --------------- 80 to 8f --------------- */
2886 Alt | Map | 9, /* '9' */
2887 Alt | Map | 10, /* '0' */
2888 Alt | Map | 11, /* '-' */
2889 Alt | Map | 12, /* '=' */
2890 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2891 FctKey | 0xc8, /* F11 */
2892 FctKey | 0xc9, /* F12 */
2893 Shift | FctKey | 0xc8, /* (Shift) F11 */
2894 Shift | FctKey | 0xc9, /* (Shift) F12 */
2895 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2896 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2897 Alt | FctKey | 0xc8, /* (Alt) F11 */
2898 Alt | FctKey | 0xc9, /* (Alt) F12 */
2899 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2900 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2901 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2903 /* --------------- 90 to 9f --------------- */
2904 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2905 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2906 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2907 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2908 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2909 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2910 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2911 Alt | FctKey | 0x50, /* (Alt) Home */
2912 Alt | FctKey | 0x52, /* (Alt) Up */
2913 Alt | FctKey | 0x55, /* (Alt) Page Up */
2914 Ignore, /* NO KEY */
2915 Alt | FctKey | 0x51, /* (Alt) Left */
2916 Ignore, /* NO KEY */
2917 Alt | FctKey | 0x53, /* (Alt) Right */
2918 Ignore, /* NO KEY */
2919 Alt | FctKey | 0x57, /* (Alt) End */
2921 /* --------------- a0 to af --------------- */
2922 Alt | KeyPad | 2, /* (Alt) Down */
2923 Alt | KeyPad | 3, /* (Alt) Page Down */
2924 Alt | KeyPad | 0, /* (Alt) Insert */
2925 Alt | KeyPad | 10, /* (Alt) Delete */
2926 Alt | Grey | 0, /* (Alt) Grey / */
2927 Alt | FctKey | 0x09, /* (Alt) Tab */
2928 Alt | Grey | 4 /* (Alt) Keypad Enter */
2931 /* These bit-positions corresponds to values returned by BIOS */
2932 #define SHIFT_P 0x0003 /* two bits! */
2933 #define CTRL_P 0x0004
2934 #define ALT_P 0x0008
2935 #define SCRLOCK_P 0x0010
2936 #define NUMLOCK_P 0x0020
2937 #define CAPSLOCK_P 0x0040
2938 #define ALT_GR_P 0x0800
2939 #define SUPER_P 0x4000 /* pseudo */
2940 #define HYPER_P 0x8000 /* pseudo */
2942 static int
2943 dos_get_modifiers (keymask)
2944 int *keymask;
2946 union REGS regs;
2947 int mask, modifiers = 0;
2949 /* Calculate modifier bits */
2950 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2951 int86 (0x16, &regs, &regs);
2953 if (!extended_kbd)
2955 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2956 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2958 else
2960 mask = regs.h.al & (SHIFT_P |
2961 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2963 /* Do not break international keyboard support. */
2964 /* When Keyb.Com is loaded, the right Alt key is */
2965 /* used for accessing characters like { and } */
2966 if (regs.h.ah & 2) /* Left ALT pressed ? */
2967 mask |= ALT_P;
2969 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2971 mask |= ALT_GR_P;
2972 if (dos_hyper_key == 1)
2974 mask |= HYPER_P;
2975 modifiers |= hyper_modifier;
2977 else if (dos_super_key == 1)
2979 mask |= SUPER_P;
2980 modifiers |= super_modifier;
2982 else if (!international_keyboard)
2984 /* If Keyb.Com is NOT installed, let Right Alt behave
2985 like the Left Alt. */
2986 mask &= ~ALT_GR_P;
2987 mask |= ALT_P;
2991 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2992 mask |= CTRL_P;
2994 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2996 if (dos_hyper_key == 2)
2998 mask |= HYPER_P;
2999 modifiers |= hyper_modifier;
3001 else if (dos_super_key == 2)
3003 mask |= SUPER_P;
3004 modifiers |= super_modifier;
3006 else
3007 mask |= CTRL_P;
3011 if (mask & SHIFT_P)
3012 modifiers |= shift_modifier;
3013 if (mask & CTRL_P)
3014 modifiers |= ctrl_modifier;
3015 if (mask & ALT_P)
3016 modifiers |= meta_modifier;
3018 if (keymask)
3019 *keymask = mask;
3020 return modifiers;
3023 #define NUM_RECENT_DOSKEYS (100)
3024 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
3025 int total_doskeys; /* Total number of elements stored into recent_doskeys */
3026 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
3028 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
3029 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3030 Each input key receives two values in this vector: first the ASCII code,
3031 and then the scan code. */)
3034 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
3036 if (total_doskeys < NUM_RECENT_DOSKEYS)
3037 return Fvector (total_doskeys, keys);
3038 else
3040 val = Fvector (NUM_RECENT_DOSKEYS, keys);
3041 bcopy (keys + recent_doskeys_index,
3042 XVECTOR (val)->contents,
3043 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
3044 bcopy (keys,
3045 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
3046 recent_doskeys_index * sizeof (Lisp_Object));
3047 return val;
3051 /* Get a char from keyboard. Function keys are put into the event queue. */
3052 static int
3053 dos_rawgetc ()
3055 struct input_event event;
3056 union REGS regs;
3057 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3058 EVENT_INIT (event);
3060 #ifndef HAVE_X_WINDOWS
3061 /* Maybe put the cursor where it should be. */
3062 IT_cmgoto (SELECTED_FRAME());
3063 #endif
3065 /* The following condition is equivalent to `kbhit ()', except that
3066 it uses the bios to do its job. This pleases DESQview/X. */
3067 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
3068 int86 (0x16, &regs, &regs),
3069 (regs.x.flags & 0x40) == 0)
3071 union REGS regs;
3072 register unsigned char c;
3073 int modifiers, sc, code = -1, mask, kp_mode;
3075 regs.h.ah = extended_kbd ? 0x10 : 0x00;
3076 int86 (0x16, &regs, &regs);
3077 c = regs.h.al;
3078 sc = regs.h.ah;
3080 total_doskeys += 2;
3081 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3082 = make_number (c);
3083 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3084 recent_doskeys_index = 0;
3085 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3086 = make_number (sc);
3087 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3088 recent_doskeys_index = 0;
3090 modifiers = dos_get_modifiers (&mask);
3092 #ifndef HAVE_X_WINDOWS
3093 if (!NILP (Vdos_display_scancodes))
3095 char buf[11];
3096 sprintf (buf, "%02x:%02x*%04x",
3097 (unsigned) (sc&0xff), (unsigned) c, mask);
3098 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
3100 #endif
3102 if (sc == 0xe0)
3104 switch (c)
3106 case 10: /* Ctrl Grey Enter */
3107 code = Ctrl | Grey | 4;
3108 break;
3109 case 13: /* Grey Enter */
3110 code = Grey | 4;
3111 break;
3112 case '/': /* Grey / */
3113 code = Grey | 0;
3114 break;
3115 default:
3116 continue;
3118 c = 0;
3120 else
3122 /* Try the keyboard-private translation table first. */
3123 if (keyboard->translate_table)
3125 struct kbd_translate *p = keyboard->translate_table;
3127 while (p->sc)
3129 if (p->sc == sc && p->ch == c)
3131 code = p->code;
3132 break;
3134 p++;
3137 /* If the private table didn't translate it, use the general
3138 one. */
3139 if (code == -1)
3141 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3142 continue;
3143 if ((code = ibmpc_translate_map[sc]) == Ignore)
3144 continue;
3148 if (c == 0)
3150 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3151 Emacs is ready to read a key. Therefore, if they press
3152 `Alt-x' when Emacs is busy, by the time we get to
3153 `dos_get_modifiers', they might have already released the
3154 Alt key, and Emacs gets just `x', which is BAD.
3155 However, for keys with the `Map' property set, the ASCII
3156 code returns zero only if Alt is pressed. So, when we DON'T
3157 have to support international_keyboard, we don't have to
3158 distinguish between the left and right Alt keys, and we
3159 can set the META modifier for any keys with the `Map'
3160 property if they return zero ASCII code (c = 0). */
3161 if ( (code & Alt)
3162 || ( (code & 0xf000) == Map && !international_keyboard))
3163 modifiers |= meta_modifier;
3164 if (code & Ctrl)
3165 modifiers |= ctrl_modifier;
3166 if (code & Shift)
3167 modifiers |= shift_modifier;
3170 switch (code & 0xf000)
3172 case ModFct:
3173 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3174 return c;
3175 c = 0; /* Special */
3177 case FctKey:
3178 if (c != 0)
3179 return c;
3181 case Special:
3182 code |= 0xff00;
3183 break;
3185 case Normal:
3186 if (sc == 0)
3188 if (c == 0) /* ctrl-break */
3189 continue;
3190 return c; /* ALT-nnn */
3192 if (!keyboard_map_all)
3194 if (c != ' ')
3195 return c;
3196 code = c;
3197 break;
3200 case Map:
3201 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3202 if (!keyboard_map_all)
3203 return c;
3205 code &= 0xff;
3206 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3207 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3209 if (mask & SHIFT_P)
3211 code = keyboard->shifted[code];
3212 mask -= SHIFT_P;
3213 modifiers &= ~shift_modifier;
3215 else
3216 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3217 code = keyboard->alt_gr[code];
3218 else
3219 code = keyboard->unshifted[code];
3220 break;
3222 case KeyPad:
3223 code &= 0xff;
3224 if (c == 0xe0) /* edit key */
3225 kp_mode = 3;
3226 else
3227 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3228 kp_mode = dos_keypad_mode & 0x03;
3229 else
3230 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3232 switch (kp_mode)
3234 case 0:
3235 if (code == 10 && dos_decimal_point)
3236 return dos_decimal_point;
3237 return keypad_translate_map[code].char_code;
3239 case 1:
3240 code = 0xff00 | keypad_translate_map[code].keypad_code;
3241 break;
3243 case 2:
3244 code = keypad_translate_map[code].meta_code;
3245 modifiers = meta_modifier;
3246 break;
3248 case 3:
3249 code = 0xff00 | keypad_translate_map[code].editkey_code;
3250 break;
3252 break;
3254 case Grey:
3255 code &= 0xff;
3256 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3257 if (dos_keypad_mode & kp_mode)
3258 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3259 else
3260 code = grey_key_translate_map[code].char_code;
3261 break;
3264 make_event:
3265 if (code == 0)
3266 continue;
3268 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3270 clear_mouse_face (dpyinfo);
3271 dpyinfo->mouse_face_hidden = 1;
3274 if (code >= 0x100)
3275 event.kind = NON_ASCII_KEYSTROKE_EVENT;
3276 else
3277 event.kind = ASCII_KEYSTROKE_EVENT;
3278 event.code = code;
3279 event.modifiers = modifiers;
3280 event.frame_or_window = selected_frame;
3281 event.arg = Qnil;
3282 event.timestamp = event_timestamp ();
3283 kbd_buffer_store_event (&event);
3286 if (have_mouse > 0 && !mouse_preempted)
3288 int but, press, x, y, ok;
3289 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3290 Lisp_Object mouse_window = Qnil;
3292 /* Check for mouse movement *before* buttons. */
3293 mouse_check_moved ();
3295 /* If the mouse moved from the spot of its last sighting, we
3296 might need to update mouse highlight. */
3297 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3299 if (dpyinfo->mouse_face_hidden)
3301 dpyinfo->mouse_face_hidden = 0;
3302 clear_mouse_face (dpyinfo);
3305 /* Generate SELECT_WINDOW_EVENTs when needed. */
3306 if (!NILP (Vmouse_autoselect_window))
3308 mouse_window = window_from_coordinates (SELECTED_FRAME(),
3309 mouse_last_x,
3310 mouse_last_y,
3311 0, 0, 0, 0);
3312 /* A window will be selected only when it is not
3313 selected now, and the last mouse movement event was
3314 not in it. A minibuffer window will be selected iff
3315 it is active. */
3316 if (WINDOWP (mouse_window)
3317 && !EQ (mouse_window, last_mouse_window)
3318 && !EQ (mouse_window, selected_window))
3320 event.kind = SELECT_WINDOW_EVENT;
3321 event.frame_or_window = mouse_window;
3322 event.arg = Qnil;
3323 event.timestamp = event_timestamp ();
3324 kbd_buffer_store_event (&event);
3326 last_mouse_window = mouse_window;
3328 else
3329 last_mouse_window = Qnil;
3331 previous_help_echo_string = help_echo_string;
3332 help_echo_string = help_echo_object = help_echo_window = Qnil;
3333 help_echo_pos = -1;
3334 IT_note_mouse_highlight (SELECTED_FRAME(),
3335 mouse_last_x, mouse_last_y);
3336 /* If the contents of the global variable help_echo has
3337 changed, generate a HELP_EVENT. */
3338 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3340 event.kind = HELP_EVENT;
3341 event.frame_or_window = selected_frame;
3342 event.arg = help_echo_object;
3343 event.x = WINDOWP (help_echo_window)
3344 ? help_echo_window : selected_frame;
3345 event.y = help_echo_string;
3346 event.timestamp = event_timestamp ();
3347 event.code = help_echo_pos;
3348 kbd_buffer_store_event (&event);
3352 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3353 for (press = 0; press < 2; press++)
3355 int button_num = but;
3357 if (press)
3358 ok = mouse_pressed (but, &x, &y);
3359 else
3360 ok = mouse_released (but, &x, &y);
3361 if (ok)
3363 /* Allow a simultaneous press/release of Mouse-1 and
3364 Mouse-2 to simulate Mouse-3 on two-button mice. */
3365 if (mouse_button_count == 2 && but < 2)
3367 int x2, y2; /* don't clobber original coordinates */
3369 /* If only one button is pressed, wait 100 msec and
3370 check again. This way, Speedy Gonzales isn't
3371 punished, while the slow get their chance. */
3372 if (press && mouse_pressed (1-but, &x2, &y2)
3373 || !press && mouse_released (1-but, &x2, &y2))
3374 button_num = 2;
3375 else
3377 delay (100);
3378 if (press && mouse_pressed (1-but, &x2, &y2)
3379 || !press && mouse_released (1-but, &x2, &y2))
3380 button_num = 2;
3384 event.kind = MOUSE_CLICK_EVENT;
3385 event.code = button_num;
3386 event.modifiers = dos_get_modifiers (0)
3387 | (press ? down_modifier : up_modifier);
3388 event.x = make_number (x);
3389 event.y = make_number (y);
3390 event.frame_or_window = selected_frame;
3391 event.arg = Qnil;
3392 event.timestamp = event_timestamp ();
3393 kbd_buffer_store_event (&event);
3398 return -1;
3401 static int prev_get_char = -1;
3403 /* Return 1 if a key is ready to be read without suspending execution. */
3405 dos_keysns ()
3407 if (prev_get_char != -1)
3408 return 1;
3409 else
3410 return ((prev_get_char = dos_rawgetc ()) != -1);
3413 /* Read a key. Return -1 if no key is ready. */
3415 dos_keyread ()
3417 if (prev_get_char != -1)
3419 int c = prev_get_char;
3420 prev_get_char = -1;
3421 return c;
3423 else
3424 return dos_rawgetc ();
3427 #ifndef HAVE_X_WINDOWS
3429 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3430 for now.
3432 Actually, I don't know the meaning of all the parameters of the functions
3433 here -- I only know how they are called by xmenu.c. I could of course
3434 grab the nearest Xlib manual (down the hall, second-to-last door on the
3435 left), but I don't think it's worth the effort. */
3437 /* These hold text of the current and the previous menu help messages. */
3438 static char *menu_help_message, *prev_menu_help_message;
3439 /* Pane number and item number of the menu item which generated the
3440 last menu help message. */
3441 static int menu_help_paneno, menu_help_itemno;
3443 static XMenu *
3444 IT_menu_create ()
3446 XMenu *menu;
3448 menu = (XMenu *) xmalloc (sizeof (XMenu));
3449 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3450 return menu;
3453 /* Allocate some (more) memory for MENU ensuring that there is room for one
3454 for item. */
3456 static void
3457 IT_menu_make_room (XMenu *menu)
3459 if (menu->allocated == 0)
3461 int count = menu->allocated = 10;
3462 menu->text = (char **) xmalloc (count * sizeof (char *));
3463 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3464 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3465 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3467 else if (menu->allocated == menu->count)
3469 int count = menu->allocated = menu->allocated + 10;
3470 menu->text
3471 = (char **) xrealloc (menu->text, count * sizeof (char *));
3472 menu->submenu
3473 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3474 menu->panenumber
3475 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3476 menu->help_text
3477 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3481 /* Search the given menu structure for a given pane number. */
3483 static XMenu *
3484 IT_menu_search_pane (XMenu *menu, int pane)
3486 int i;
3487 XMenu *try;
3489 for (i = 0; i < menu->count; i++)
3490 if (menu->submenu[i])
3492 if (pane == menu->panenumber[i])
3493 return menu->submenu[i];
3494 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3495 return try;
3497 return (XMenu *) 0;
3500 /* Determine how much screen space a given menu needs. */
3502 static void
3503 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3505 int i, h2, w2, maxsubwidth, maxheight;
3507 maxsubwidth = 0;
3508 maxheight = menu->count;
3509 for (i = 0; i < menu->count; i++)
3511 if (menu->submenu[i])
3513 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3514 if (w2 > maxsubwidth) maxsubwidth = w2;
3515 if (i + h2 > maxheight) maxheight = i + h2;
3518 *width = menu->width + maxsubwidth;
3519 *height = maxheight;
3522 /* Display MENU at (X,Y) using FACES. */
3524 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3525 do \
3527 (GLYPH).type = CHAR_GLYPH; \
3528 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3529 (GLYPH).charpos = -1; \
3531 while (0)
3533 static void
3534 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3536 int i, j, face, width, mx, my, enabled, mousehere, row, col;
3537 struct glyph *text, *p;
3538 const unsigned char *q;
3539 struct frame *sf = SELECTED_FRAME();
3541 menu_help_message = NULL;
3543 width = menu->width;
3544 /* We multiply width by 2 to account for possible control characters.
3545 FIXME: cater to non-ASCII characters in menus. */
3546 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3547 ScreenGetCursor (&row, &col);
3548 mouse_get_xy (&mx, &my);
3549 IT_update_begin (sf);
3550 for (i = 0; i < menu->count; i++)
3552 int max_width = width + 2;
3554 IT_cursor_to (sf, y + i, x);
3555 enabled
3556 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3557 mousehere = (y + i == my && x <= mx && mx < x + max_width);
3558 face = faces[enabled + mousehere * 2];
3559 /* The following if clause means that we display the menu help
3560 strings even if the menu item is currently disabled. */
3561 if (disp_help && enabled + mousehere * 2 >= 2)
3563 menu_help_message = menu->help_text[i];
3564 menu_help_paneno = pn - 1;
3565 menu_help_itemno = i;
3567 p = text;
3568 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3569 p++;
3570 for (j = 0, q = menu->text[i]; *q; j++)
3572 unsigned c = STRING_CHAR_ADVANCE (q);
3574 if (c > 26)
3576 BUILD_CHAR_GLYPH (*p, c, face, 0);
3577 p++;
3579 else /* make '^x' */
3581 BUILD_CHAR_GLYPH (*p, '^', face, 0);
3582 p++;
3583 j++;
3584 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3585 p++;
3588 /* Don't let the menu text overflow into the next screen row. */
3589 if (x + max_width > screen_size_X)
3591 max_width = screen_size_X - x;
3592 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3594 for (; j < max_width - 2; j++, p++)
3595 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3597 /* 16 is the character code of a character that on DOS terminal
3598 produces a nice-looking right-pointing arrow glyph. */
3599 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3600 p++;
3601 IT_write_glyphs (sf, text, max_width);
3603 IT_update_end (sf);
3604 IT_cursor_to (sf, row, col);
3605 xfree (text);
3608 /* --------------------------- X Menu emulation ---------------------- */
3610 /* Report availability of menus. */
3613 have_menus_p () { return 1; }
3615 /* Create a brand new menu structure. */
3617 XMenu *
3618 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3620 return IT_menu_create ();
3623 /* Create a new pane and place it on the outer-most level. It is not
3624 clear that it should be placed out there, but I don't know what else
3625 to do. */
3628 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3630 int len;
3631 char *p;
3633 if (!enable)
3634 abort ();
3636 IT_menu_make_room (menu);
3637 menu->submenu[menu->count] = IT_menu_create ();
3638 menu->text[menu->count] = txt;
3639 menu->panenumber[menu->count] = ++menu->panecount;
3640 menu->help_text[menu->count] = NULL;
3641 menu->count++;
3643 /* Adjust length for possible control characters (which will
3644 be written as ^x). */
3645 for (len = strlen (txt), p = txt; *p; p++)
3646 if (*p < 27)
3647 len++;
3649 if (len > menu->width)
3650 menu->width = len;
3652 return menu->panecount;
3655 /* Create a new item in a menu pane. */
3658 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3659 int foo, char *txt, int enable, char *help_text)
3661 int len;
3662 char *p;
3664 if (pane)
3665 if (!(menu = IT_menu_search_pane (menu, pane)))
3666 return XM_FAILURE;
3667 IT_menu_make_room (menu);
3668 menu->submenu[menu->count] = (XMenu *) 0;
3669 menu->text[menu->count] = txt;
3670 menu->panenumber[menu->count] = enable;
3671 menu->help_text[menu->count] = help_text;
3672 menu->count++;
3674 /* Adjust length for possible control characters (which will
3675 be written as ^x). */
3676 for (len = strlen (txt), p = txt; *p; p++)
3677 if (*p < 27)
3678 len++;
3680 if (len > menu->width)
3681 menu->width = len;
3683 return XM_SUCCESS;
3686 /* Decide where the menu would be placed if requested at (X,Y). */
3688 void
3689 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3690 int *ulx, int *uly, int *width, int *height)
3692 IT_menu_calc_size (menu, width, height);
3693 *ulx = x + 1;
3694 *uly = y;
3695 *width += 2;
3698 struct IT_menu_state
3700 void *screen_behind;
3701 XMenu *menu;
3702 int pane;
3703 int x, y;
3707 /* Display menu, wait for user's response, and return that response. */
3710 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3711 int x0, int y0, unsigned ButtonMask, char **txt,
3712 void (*help_callback)(char *, int, int))
3714 struct IT_menu_state *state;
3715 int statecount, x, y, i, b, screensize, leave, result, onepane;
3716 int title_faces[4]; /* face to display the menu title */
3717 int faces[4], buffers_num_deleted = 0;
3718 struct frame *sf = SELECTED_FRAME();
3719 Lisp_Object saved_echo_area_message, selectface;
3721 /* Just in case we got here without a mouse present... */
3722 if (have_mouse <= 0)
3723 return XM_IA_SELECT;
3724 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3725 around the display. */
3726 if (x0 <= 0)
3727 x0 = 1;
3728 if (y0 <= 0)
3729 y0 = 1;
3731 /* We will process all the mouse events directly, so we had
3732 better prevent dos_rawgetc from stealing them from us. */
3733 mouse_preempted++;
3735 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3736 screensize = screen_size * 2;
3737 faces[0]
3738 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3739 DEFAULT_FACE_ID, 1);
3740 faces[1]
3741 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3742 DEFAULT_FACE_ID, 1);
3743 selectface = intern ("msdos-menu-select-face");
3744 faces[2] = lookup_derived_face (sf, selectface,
3745 faces[0], 1);
3746 faces[3] = lookup_derived_face (sf, selectface,
3747 faces[1], 1);
3749 /* Make sure the menu title is always displayed with
3750 `msdos-menu-active-face', no matter where the mouse pointer is. */
3751 for (i = 0; i < 4; i++)
3752 title_faces[i] = faces[3];
3754 statecount = 1;
3756 /* Don't let the title for the "Buffers" popup menu include a
3757 digit (which is ugly).
3759 This is a terrible kludge, but I think the "Buffers" case is
3760 the only one where the title includes a number, so it doesn't
3761 seem to be necessary to make this more general. */
3762 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3764 menu->text[0][7] = '\0';
3765 buffers_num_deleted = 1;
3768 /* We need to save the current echo area message, so that we could
3769 restore it below, before we exit. See the commentary below,
3770 before the call to message_with_string. */
3771 saved_echo_area_message = Fcurrent_message ();
3772 state[0].menu = menu;
3773 mouse_off ();
3774 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3776 /* Turn off the cursor. Otherwise it shows through the menu
3777 panes, which is ugly. */
3778 IT_display_cursor (0);
3780 /* Display the menu title. */
3781 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3782 if (buffers_num_deleted)
3783 menu->text[0][7] = ' ';
3784 if ((onepane = menu->count == 1 && menu->submenu[0]))
3786 menu->width = menu->submenu[0]->width;
3787 state[0].menu = menu->submenu[0];
3789 else
3791 state[0].menu = menu;
3793 state[0].x = x0 - 1;
3794 state[0].y = y0;
3795 state[0].pane = onepane;
3797 mouse_last_x = -1; /* A hack that forces display. */
3798 leave = 0;
3799 while (!leave)
3801 if (!mouse_visible) mouse_on ();
3802 mouse_check_moved ();
3803 if (sf->mouse_moved)
3805 sf->mouse_moved = 0;
3806 result = XM_IA_SELECT;
3807 mouse_get_xy (&x, &y);
3808 for (i = 0; i < statecount; i++)
3809 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3811 int dy = y - state[i].y;
3812 if (0 <= dy && dy < state[i].menu->count)
3814 if (!state[i].menu->submenu[dy])
3815 if (state[i].menu->panenumber[dy])
3816 result = XM_SUCCESS;
3817 else
3818 result = XM_IA_SELECT;
3819 *pane = state[i].pane - 1;
3820 *selidx = dy;
3821 /* We hit some part of a menu, so drop extra menus that
3822 have been opened. That does not include an open and
3823 active submenu. */
3824 if (i != statecount - 2
3825 || state[i].menu->submenu[dy] != state[i+1].menu)
3826 while (i != statecount - 1)
3828 statecount--;
3829 mouse_off ();
3830 ScreenUpdate (state[statecount].screen_behind);
3831 if (screen_virtual_segment)
3832 dosv_refresh_virtual_screen (0, screen_size);
3833 xfree (state[statecount].screen_behind);
3835 if (i == statecount - 1 && state[i].menu->submenu[dy])
3837 IT_menu_display (state[i].menu,
3838 state[i].y,
3839 state[i].x,
3840 state[i].pane,
3841 faces, 1);
3842 state[statecount].menu = state[i].menu->submenu[dy];
3843 state[statecount].pane = state[i].menu->panenumber[dy];
3844 mouse_off ();
3845 ScreenRetrieve (state[statecount].screen_behind
3846 = xmalloc (screensize));
3847 state[statecount].x
3848 = state[i].x + state[i].menu->width + 2;
3849 state[statecount].y = y;
3850 statecount++;
3854 IT_menu_display (state[statecount - 1].menu,
3855 state[statecount - 1].y,
3856 state[statecount - 1].x,
3857 state[statecount - 1].pane,
3858 faces, 1);
3860 else
3862 if ((menu_help_message || prev_menu_help_message)
3863 && menu_help_message != prev_menu_help_message)
3865 help_callback (menu_help_message,
3866 menu_help_paneno, menu_help_itemno);
3867 IT_display_cursor (0);
3868 prev_menu_help_message = menu_help_message;
3870 /* We are busy-waiting for the mouse to move, so let's be nice
3871 to other Windows applications by releasing our time slice. */
3872 __dpmi_yield ();
3874 for (b = 0; b < mouse_button_count && !leave; b++)
3876 /* Only leave if user both pressed and released the mouse, and in
3877 that order. This avoids popping down the menu pane unless
3878 the user is really done with it. */
3879 if (mouse_pressed (b, &x, &y))
3881 while (mouse_button_depressed (b, &x, &y))
3882 __dpmi_yield ();
3883 leave = 1;
3885 (void) mouse_released (b, &x, &y);
3889 mouse_off ();
3890 ScreenUpdate (state[0].screen_behind);
3891 if (screen_virtual_segment)
3892 dosv_refresh_virtual_screen (0, screen_size);
3894 /* We have a situation here. ScreenUpdate has just restored the
3895 screen contents as it was before we started drawing this menu.
3896 That includes any echo area message that could have been
3897 displayed back then. (In reality, that echo area message will
3898 almost always be the ``keystroke echo'' that echoes the sequence
3899 of menu items chosen by the user.) However, if the menu had some
3900 help messages, then displaying those messages caused Emacs to
3901 forget about the original echo area message. So when
3902 ScreenUpdate restored it, it created a discrepancy between the
3903 actual screen contents and what Emacs internal data structures
3904 know about it.
3906 To avoid this conflict, we force Emacs to restore the original
3907 echo area message as we found it when we entered this function.
3908 The irony of this is that we then erase the restored message
3909 right away, so the only purpose of restoring it is so that
3910 erasing it works correctly... */
3911 if (! NILP (saved_echo_area_message))
3912 message_with_string ("%s", saved_echo_area_message, 0);
3913 message (0);
3914 while (statecount--)
3915 xfree (state[statecount].screen_behind);
3916 IT_display_cursor (1); /* turn cursor back on */
3917 /* Clean up any mouse events that are waiting inside Emacs event queue.
3918 These events are likely to be generated before the menu was even
3919 displayed, probably because the user pressed and released the button
3920 (which invoked the menu) too quickly. If we don't remove these events,
3921 Emacs will process them after we return and surprise the user. */
3922 discard_mouse_events ();
3923 mouse_clear_clicks ();
3924 if (!kbd_buffer_events_waiting (1))
3925 clear_input_pending ();
3926 /* Allow mouse events generation by dos_rawgetc. */
3927 mouse_preempted--;
3928 return result;
3931 /* Dispose of a menu. */
3933 void
3934 XMenuDestroy (Display *foo, XMenu *menu)
3936 int i;
3937 if (menu->allocated)
3939 for (i = 0; i < menu->count; i++)
3940 if (menu->submenu[i])
3941 XMenuDestroy (foo, menu->submenu[i]);
3942 xfree (menu->text);
3943 xfree (menu->submenu);
3944 xfree (menu->panenumber);
3945 xfree (menu->help_text);
3947 xfree (menu);
3948 menu_help_message = prev_menu_help_message = NULL;
3952 x_pixel_width (struct frame *f)
3954 return FRAME_COLS (f);
3958 x_pixel_height (struct frame *f)
3960 return FRAME_LINES (f);
3962 #endif /* !HAVE_X_WINDOWS */
3964 /* ----------------------- DOS / UNIX conversion --------------------- */
3966 void msdos_downcase_filename (unsigned char *);
3968 /* Destructively turn backslashes into slashes. */
3970 void
3971 dostounix_filename (p)
3972 register char *p;
3974 msdos_downcase_filename (p);
3976 while (*p)
3978 if (*p == '\\')
3979 *p = '/';
3980 p++;
3984 /* Destructively turn slashes into backslashes. */
3986 void
3987 unixtodos_filename (p)
3988 register char *p;
3990 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3992 *p += 'a' - 'A';
3993 p += 2;
3996 while (*p)
3998 if (*p == '/')
3999 *p = '\\';
4000 p++;
4004 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4007 getdefdir (drive, dst)
4008 int drive;
4009 char *dst;
4011 char in_path[4], *p = in_path, e = errno;
4013 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4014 if (drive != 0)
4016 *p++ = drive + 'A' - 1;
4017 *p++ = ':';
4020 *p++ = '.';
4021 *p = '\0';
4022 errno = 0;
4023 _fixpath (in_path, dst);
4024 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4025 it queries the LFN support, so ignore that error. */
4026 if ((errno && errno != ENOSYS) || *dst == '\0')
4027 return 0;
4029 msdos_downcase_filename (dst);
4031 errno = e;
4032 return 1;
4035 char *
4036 emacs_root_dir (void)
4038 static char root_dir[4];
4040 sprintf (root_dir, "%c:/", 'A' + getdisk ());
4041 root_dir[0] = tolower (root_dir[0]);
4042 return root_dir;
4045 /* Remove all CR's that are followed by a LF. */
4048 crlf_to_lf (n, buf)
4049 register int n;
4050 register unsigned char *buf;
4052 unsigned char *np = buf, *startp = buf, *endp = buf + n;
4054 if (n == 0)
4055 return n;
4056 while (buf < endp - 1)
4058 if (*buf == 0x0d)
4060 if (*(++buf) != 0x0a)
4061 *np++ = 0x0d;
4063 else
4064 *np++ = *buf++;
4066 if (buf < endp)
4067 *np++ = *buf++;
4068 return np - startp;
4071 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4073 /* In DJGPP v2.0, library `write' can call `malloc', which might
4074 cause relocation of the buffer whose address we get in ADDR.
4075 Here is a version of `write' that avoids calling `malloc',
4076 to serve us until such time as the library is fixed.
4077 Actually, what we define here is called `__write', because
4078 `write' is a stub that just jmp's to `__write' (to be
4079 POSIXLY-correct with respect to the global name-space). */
4081 #include <io.h> /* for _write */
4082 #include <libc/dosio.h> /* for __file_handle_modes[] */
4084 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
4086 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4089 __write (int handle, const void *buffer, size_t count)
4091 if (count == 0)
4092 return 0;
4094 if(__file_handle_modes[handle] & O_BINARY)
4095 return _write (handle, buffer, count);
4096 else
4098 char *xbp = xbuf;
4099 const char *bp = buffer;
4100 int total_written = 0;
4101 int nmoved = 0, ncr = 0;
4103 while (count)
4105 /* The next test makes sure there's space for at least 2 more
4106 characters in xbuf[], so both CR and LF can be put there. */
4107 if (xbp < XBUF_END)
4109 if (*bp == '\n')
4111 ncr++;
4112 *xbp++ = '\r';
4114 *xbp++ = *bp++;
4115 nmoved++;
4116 count--;
4118 if (xbp >= XBUF_END || !count)
4120 size_t to_write = nmoved + ncr;
4121 int written = _write (handle, xbuf, to_write);
4123 if (written == -1)
4124 return -1;
4125 else
4126 total_written += nmoved; /* CRs aren't counted in ret value */
4128 /* If some, but not all were written (disk full?), return
4129 an estimate of the total written bytes not counting CRs. */
4130 if (written < to_write)
4131 return total_written - (to_write - written) * nmoved/to_write;
4133 nmoved = 0;
4134 ncr = 0;
4135 xbp = xbuf;
4138 return total_written;
4142 /* A low-level file-renaming function which works around Windows 95 bug.
4143 This is pulled directly out of DJGPP v2.01 library sources, and only
4144 used when you compile with DJGPP v2.0. */
4146 #include <io.h>
4148 int _rename(const char *old, const char *new)
4150 __dpmi_regs r;
4151 int olen = strlen(old) + 1;
4152 int i;
4153 int use_lfn = _USE_LFN;
4154 char tempfile[FILENAME_MAX];
4155 const char *orig = old;
4156 int lfn_fd = -1;
4158 r.x.dx = __tb_offset;
4159 r.x.di = __tb_offset + olen;
4160 r.x.ds = r.x.es = __tb_segment;
4162 if (use_lfn)
4164 /* Windows 95 bug: for some filenames, when you rename
4165 file -> file~ (as in Emacs, to leave a backup), the
4166 short 8+3 alias doesn't change, which effectively
4167 makes OLD and NEW the same file. We must rename
4168 through a temporary file to work around this. */
4170 char *pbase = 0, *p;
4171 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
4172 int idx = sizeof(try_char) - 1;
4174 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4175 might point to another drive, which will fail the DOS call. */
4176 strcpy(tempfile, old);
4177 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
4178 if (*p == '/' || *p == '\\' || *p == ':')
4179 pbase = p;
4180 if (pbase)
4181 pbase++;
4182 else
4183 pbase = tempfile;
4184 strcpy(pbase, "X$$djren$$.$$temp$$");
4188 if (idx <= 0)
4189 return -1;
4190 *pbase = try_char[--idx];
4191 } while (_chmod(tempfile, 0) != -1);
4193 r.x.ax = 0x7156;
4194 _put_path2(tempfile, olen);
4195 _put_path(old);
4196 __dpmi_int(0x21, &r);
4197 if (r.x.flags & 1)
4199 errno = __doserr_to_errno(r.x.ax);
4200 return -1;
4203 /* Now create a file with the original name. This will
4204 ensure that NEW will always have a 8+3 alias
4205 different from that of OLD. (Seems to be required
4206 when NameNumericTail in the Registry is set to 0.) */
4207 lfn_fd = _creat(old, 0);
4209 olen = strlen(tempfile) + 1;
4210 old = tempfile;
4211 r.x.di = __tb_offset + olen;
4214 for (i=0; i<2; i++)
4216 if(use_lfn)
4217 r.x.ax = 0x7156;
4218 else
4219 r.h.ah = 0x56;
4220 _put_path2(new, olen);
4221 _put_path(old);
4222 __dpmi_int(0x21, &r);
4223 if(r.x.flags & 1)
4225 if (r.x.ax == 5 && i == 0) /* access denied */
4226 remove(new); /* and try again */
4227 else
4229 errno = __doserr_to_errno(r.x.ax);
4231 /* Restore to original name if we renamed it to temporary. */
4232 if (use_lfn)
4234 if (lfn_fd != -1)
4236 _close (lfn_fd);
4237 remove (orig);
4239 _put_path2(orig, olen);
4240 _put_path(tempfile);
4241 r.x.ax = 0x7156;
4242 __dpmi_int(0x21, &r);
4244 return -1;
4247 else
4248 break;
4251 /* Success. Delete the file possibly created to work
4252 around the Windows 95 bug. */
4253 if (lfn_fd != -1)
4254 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
4255 return 0;
4258 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4260 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
4261 0, 0, 0,
4262 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
4265 return (_USE_LFN ? Qt : Qnil);
4268 /* Convert alphabetic characters in a filename to lower-case. */
4270 void
4271 msdos_downcase_filename (p)
4272 register unsigned char *p;
4274 /* Always lower-case drive letters a-z, even if the filesystem
4275 preserves case in filenames.
4276 This is so MSDOS filenames could be compared by string comparison
4277 functions that are case-sensitive. Even case-preserving filesystems
4278 do not distinguish case in drive letters. */
4279 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4281 *p += 'a' - 'A';
4282 p += 2;
4285 /* Under LFN we expect to get pathnames in their true case. */
4286 if (NILP (Fmsdos_long_file_names ()))
4287 for ( ; *p; p++)
4288 if (*p >= 'A' && *p <= 'Z')
4289 *p += 'a' - 'A';
4292 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
4293 1, 1, 0,
4294 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
4295 When long filenames are supported, doesn't change FILENAME.
4296 If FILENAME is not a string, returns nil.
4297 The argument object is never altered--the value is a copy. */)
4298 (filename)
4299 Lisp_Object filename;
4301 Lisp_Object tem;
4303 if (! STRINGP (filename))
4304 return Qnil;
4306 tem = Fcopy_sequence (filename);
4307 msdos_downcase_filename (SDATA (tem));
4308 return tem;
4311 /* The Emacs root directory as determined by init_environment. */
4313 static char emacsroot[MAXPATHLEN];
4315 char *
4316 rootrelativepath (rel)
4317 char *rel;
4319 static char result[MAXPATHLEN + 10];
4321 strcpy (result, emacsroot);
4322 strcat (result, "/");
4323 strcat (result, rel);
4324 return result;
4327 /* Define a lot of environment variables if not already defined. Don't
4328 remove anything unless you know what you're doing -- lots of code will
4329 break if one or more of these are missing. */
4331 void
4332 init_environment (argc, argv, skip_args)
4333 int argc;
4334 char **argv;
4335 int skip_args;
4337 char *s, *t, *root;
4338 int len, i;
4339 static const char * const tempdirs[] = {
4340 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4342 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4344 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4345 temporary files and assume "/tmp" if $TMPDIR is unset, which
4346 will break on DOS/Windows. Refuse to work if we cannot find
4347 a directory, not even "c:/", usable for that purpose. */
4348 for (i = 0; i < imax ; i++)
4350 const char *tmp = tempdirs[i];
4351 char buf[FILENAME_MAX];
4353 if (*tmp == '$')
4355 int tmp_len;
4357 tmp = getenv (tmp + 1);
4358 if (!tmp)
4359 continue;
4361 /* Some lusers set TMPDIR=e:, probably because some losing
4362 programs cannot handle multiple slashes if they use e:/.
4363 e: fails in `access' below, so we interpret e: as e:/. */
4364 tmp_len = strlen(tmp);
4365 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4367 strcpy(buf, tmp);
4368 buf[tmp_len++] = '/', buf[tmp_len] = 0;
4369 tmp = buf;
4373 /* Note that `access' can lie to us if the directory resides on a
4374 read-only filesystem, like CD-ROM or a write-protected floppy.
4375 The only way to be really sure is to actually create a file and
4376 see if it succeeds. But I think that's too much to ask. */
4377 if (tmp && access (tmp, D_OK) == 0)
4379 setenv ("TMPDIR", tmp, 1);
4380 break;
4383 if (i >= imax)
4384 cmd_error_internal
4385 (Fcons (Qerror,
4386 Fcons (build_string ("no usable temporary directories found!!"),
4387 Qnil)),
4388 "While setting TMPDIR: ");
4390 /* Note the startup time, so we know not to clear the screen if we
4391 exit immediately; see IT_reset_terminal_modes.
4392 (Yes, I know `clock' returns zero the first time it's called, but
4393 I do this anyway, in case some wiseguy changes that at some point.) */
4394 startup_time = clock ();
4396 /* Find our root from argv[0]. Assuming argv[0] is, say,
4397 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4398 root = alloca (MAXPATHLEN + 20);
4399 _fixpath (argv[0], root);
4400 msdos_downcase_filename (root);
4401 len = strlen (root);
4402 while (len > 0 && root[len] != '/' && root[len] != ':')
4403 len--;
4404 root[len] = '\0';
4405 if (len > 4
4406 && (strcmp (root + len - 4, "/bin") == 0
4407 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4408 root[len - 4] = '\0';
4409 else
4410 strcpy (root, "c:/emacs"); /* let's be defensive */
4411 len = strlen (root);
4412 strcpy (emacsroot, root);
4414 /* We default HOME to our root. */
4415 setenv ("HOME", root, 0);
4417 /* We default EMACSPATH to root + "/bin". */
4418 strcpy (root + len, "/bin");
4419 setenv ("EMACSPATH", root, 0);
4421 /* I don't expect anybody to ever use other terminals so the internal
4422 terminal is the default. */
4423 setenv ("TERM", "internal", 0);
4425 #ifdef HAVE_X_WINDOWS
4426 /* Emacs expects DISPLAY to be set. */
4427 setenv ("DISPLAY", "unix:0.0", 0);
4428 #endif
4430 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4431 downcase it and mirror the backslashes. */
4432 s = getenv ("COMSPEC");
4433 if (!s) s = "c:/command.com";
4434 t = alloca (strlen (s) + 1);
4435 strcpy (t, s);
4436 dostounix_filename (t);
4437 setenv ("SHELL", t, 0);
4439 /* PATH is also downcased and backslashes mirrored. */
4440 s = getenv ("PATH");
4441 if (!s) s = "";
4442 t = alloca (strlen (s) + 3);
4443 /* Current directory is always considered part of MsDos's path but it is
4444 not normally mentioned. Now it is. */
4445 strcat (strcpy (t, ".;"), s);
4446 dostounix_filename (t); /* Not a single file name, but this should work. */
4447 setenv ("PATH", t, 1);
4449 /* In some sense all dos users have root privileges, so... */
4450 setenv ("USER", "root", 0);
4451 setenv ("NAME", getenv ("USER"), 0);
4453 /* Time zone determined from country code. To make this possible, the
4454 country code may not span more than one time zone. In other words,
4455 in the USA, you lose. */
4456 if (!getenv ("TZ"))
4457 switch (dos_country_code)
4459 case 31: /* Belgium */
4460 case 32: /* The Netherlands */
4461 case 33: /* France */
4462 case 34: /* Spain */
4463 case 36: /* Hungary */
4464 case 38: /* Yugoslavia (or what's left of it?) */
4465 case 39: /* Italy */
4466 case 41: /* Switzerland */
4467 case 42: /* Tjekia */
4468 case 45: /* Denmark */
4469 case 46: /* Sweden */
4470 case 47: /* Norway */
4471 case 48: /* Poland */
4472 case 49: /* Germany */
4473 /* Daylight saving from last Sunday in March to last Sunday in
4474 September, both at 2AM. */
4475 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4476 break;
4477 case 44: /* United Kingdom */
4478 case 351: /* Portugal */
4479 case 354: /* Iceland */
4480 setenv ("TZ", "GMT+00", 0);
4481 break;
4482 case 81: /* Japan */
4483 case 82: /* Korea */
4484 setenv ("TZ", "JST-09", 0);
4485 break;
4486 case 90: /* Turkey */
4487 case 358: /* Finland */
4488 setenv ("TZ", "EET-02", 0);
4489 break;
4490 case 972: /* Israel */
4491 /* This is an approximation. (For exact rules, use the
4492 `zoneinfo/israel' file which comes with DJGPP, but you need
4493 to install it in `/usr/share/zoneinfo/' directory first.) */
4494 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4495 break;
4497 tzset ();
4502 static int break_stat; /* BREAK check mode status. */
4503 static int stdin_stat; /* stdin IOCTL status. */
4505 #if __DJGPP__ < 2
4507 /* These must be global. */
4508 static _go32_dpmi_seginfo ctrl_break_vector;
4509 static _go32_dpmi_registers ctrl_break_regs;
4510 static int ctrlbreakinstalled = 0;
4512 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4514 void
4515 ctrl_break_func (regs)
4516 _go32_dpmi_registers *regs;
4518 Vquit_flag = Qt;
4521 void
4522 install_ctrl_break_check ()
4524 if (!ctrlbreakinstalled)
4526 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4527 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4528 ctrlbreakinstalled = 1;
4529 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
4530 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
4531 &ctrl_break_regs);
4532 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
4536 #endif /* __DJGPP__ < 2 */
4538 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4539 control chars by DOS. Determine the keyboard type. */
4542 dos_ttraw (struct tty_display_info *tty)
4544 union REGS inregs, outregs;
4545 static int first_time = 1;
4547 /* If we are called for the initial terminal, it's too early to do
4548 anything, and termscript isn't set up. */
4549 if (tty->terminal->type == output_initial)
4550 return;
4552 break_stat = getcbrk ();
4553 setcbrk (0);
4554 #if __DJGPP__ < 2
4555 install_ctrl_break_check ();
4556 #endif
4558 if (first_time)
4560 inregs.h.ah = 0xc0;
4561 int86 (0x15, &inregs, &outregs);
4562 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4564 have_mouse = 0;
4566 if (1
4567 #ifdef HAVE_X_WINDOWS
4568 && inhibit_window_system
4569 #endif
4572 inregs.x.ax = 0x0021;
4573 int86 (0x33, &inregs, &outregs);
4574 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4575 if (!have_mouse)
4577 /* Reportedly, the above doesn't work for some mouse drivers. There
4578 is an additional detection method that should work, but might be
4579 a little slower. Use that as an alternative. */
4580 inregs.x.ax = 0x0000;
4581 int86 (0x33, &inregs, &outregs);
4582 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4584 if (have_mouse)
4585 mouse_button_count = outregs.x.bx;
4587 #ifndef HAVE_X_WINDOWS
4588 #if __DJGPP__ >= 2
4589 /* Save the cursor shape used outside Emacs. */
4590 outside_cursor = _farpeekw (_dos_ds, 0x460);
4591 #endif
4592 #endif
4595 first_time = 0;
4597 #if __DJGPP__ >= 2
4599 stdin_stat = setmode (fileno (stdin), O_BINARY);
4600 return (stdin_stat != -1);
4602 else
4603 return (setmode (fileno (stdin), O_BINARY) != -1);
4605 #else /* __DJGPP__ < 2 */
4609 /* I think it is wrong to overwrite `stdin_stat' every time
4610 but the first one this function is called, but I don't
4611 want to change the way it used to work in v1.x.--EZ */
4613 inregs.x.ax = 0x4400; /* Get IOCTL status. */
4614 inregs.x.bx = 0x00; /* 0 = stdin. */
4615 intdos (&inregs, &outregs);
4616 stdin_stat = outregs.h.dl;
4618 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
4619 inregs.x.ax = 0x4401; /* Set IOCTL status */
4620 intdos (&inregs, &outregs);
4621 return !outregs.x.cflag;
4623 #endif /* __DJGPP__ < 2 */
4626 /* Restore status of standard input and Ctrl-C checking. */
4629 dos_ttcooked ()
4631 union REGS inregs, outregs;
4633 setcbrk (break_stat);
4634 mouse_off ();
4636 #if __DJGPP__ >= 2
4638 #ifndef HAVE_X_WINDOWS
4639 /* Restore the cursor shape we found on startup. */
4640 if (outside_cursor)
4642 inregs.h.ah = 1;
4643 inregs.x.cx = outside_cursor;
4644 int86 (0x10, &inregs, &outregs);
4646 #endif
4648 return (setmode (fileno (stdin), stdin_stat) != -1);
4650 #else /* not __DJGPP__ >= 2 */
4652 inregs.x.ax = 0x4401; /* Set IOCTL status. */
4653 inregs.x.bx = 0x00; /* 0 = stdin. */
4654 inregs.x.dx = stdin_stat;
4655 intdos (&inregs, &outregs);
4656 return !outregs.x.cflag;
4658 #endif /* not __DJGPP__ >= 2 */
4662 /* Run command as specified by ARGV in directory DIR.
4663 The command is run with input from TEMPIN, output to
4664 file TEMPOUT and stderr to TEMPERR. */
4667 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4668 unsigned char **argv;
4669 const char *working_dir;
4670 int tempin, tempout, temperr;
4671 char **envv;
4673 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4674 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4675 int msshell, result = -1, inbak, outbak, errbak, x, y;
4676 Lisp_Object cmd;
4678 /* Get current directory as MSDOS cwd is not per-process. */
4679 getwd (oldwd);
4681 /* If argv[0] is the shell, it might come in any lettercase.
4682 Since `Fmember' is case-sensitive, we need to downcase
4683 argv[0], even if we are on case-preserving filesystems. */
4684 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4685 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4687 *pl = *pa++;
4688 if (*pl >= 'A' && *pl <= 'Z')
4689 *pl += 'a' - 'A';
4691 *pl = '\0';
4693 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4694 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4695 && !strcmp ("-c", argv[1]);
4696 if (msshell)
4698 saveargv1 = argv[1];
4699 saveargv2 = argv[2];
4700 argv[1] = "/c";
4701 /* We only need to mirror slashes if a DOS shell will be invoked
4702 not via `system' (which does the mirroring itself). Yes, that
4703 means DJGPP v1.x will lose here. */
4704 if (argv[2] && argv[3])
4706 char *p = alloca (strlen (argv[2]) + 1);
4708 strcpy (argv[2] = p, saveargv2);
4709 while (*p && isspace (*p))
4710 p++;
4711 while (*p)
4713 if (*p == '/')
4714 *p++ = '\\';
4715 else
4716 p++;
4721 chdir (working_dir);
4722 inbak = dup (0);
4723 outbak = dup (1);
4724 errbak = dup (2);
4725 if (inbak < 0 || outbak < 0 || errbak < 0)
4726 goto done; /* Allocation might fail due to lack of descriptors. */
4728 if (have_mouse > 0)
4729 mouse_get_xy (&x, &y);
4731 if (!noninteractive)
4732 dos_ttcooked (); /* do it here while 0 = stdin */
4734 dup2 (tempin, 0);
4735 dup2 (tempout, 1);
4736 dup2 (temperr, 2);
4738 #if __DJGPP__ > 1
4740 if (msshell && !argv[3])
4742 /* MS-DOS native shells are too restrictive. For starters, they
4743 cannot grok commands longer than 126 characters. In DJGPP v2
4744 and later, `system' is much smarter, so we'll call it instead. */
4746 const char *cmnd;
4748 /* A shell gets a single argument--its full command
4749 line--whose original was saved in `saveargv2'. */
4751 /* Don't let them pass empty command lines to `system', since
4752 with some shells it will try to invoke an interactive shell,
4753 which will hang Emacs. */
4754 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4756 if (*cmnd)
4758 extern char **environ;
4759 char **save_env = environ;
4760 int save_system_flags = __system_flags;
4762 /* Request the most powerful version of `system'. We need
4763 all the help we can get to avoid calling stock DOS shells. */
4764 __system_flags = (__system_redirect
4765 | __system_use_shell
4766 | __system_allow_multiple_cmds
4767 | __system_allow_long_cmds
4768 | __system_handle_null_commands
4769 | __system_emulate_chdir);
4771 environ = envv;
4772 result = system (cmnd);
4773 __system_flags = save_system_flags;
4774 environ = save_env;
4776 else
4777 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4779 else
4781 #endif /* __DJGPP__ > 1 */
4783 result = spawnve (P_WAIT, argv[0], argv, envv);
4785 dup2 (inbak, 0);
4786 dup2 (outbak, 1);
4787 dup2 (errbak, 2);
4788 emacs_close (inbak);
4789 emacs_close (outbak);
4790 emacs_close (errbak);
4792 if (!noninteractive)
4793 dos_ttraw (CURTTY ());
4794 if (have_mouse > 0)
4796 mouse_init ();
4797 mouse_moveto (x, y);
4800 /* Some programs might change the meaning of the highest bit of the
4801 text attribute byte, so we get blinking characters instead of the
4802 bright background colors. Restore that. */
4803 if (!noninteractive)
4804 bright_bg ();
4806 done:
4807 chdir (oldwd);
4808 if (msshell)
4810 argv[1] = saveargv1;
4811 argv[2] = saveargv2;
4813 return result;
4816 void
4817 croak (badfunc)
4818 char *badfunc;
4820 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4821 reset_all_sys_modes ();
4822 exit (1);
4825 #if __DJGPP__ < 2
4827 /* ------------------------- Compatibility functions -------------------
4828 * gethostname
4829 * gettimeofday
4832 /* Hostnames for a pc are not really funny,
4833 but they are used in change log so we emulate the best we can. */
4835 gethostname (p, size)
4836 char *p;
4837 int size;
4839 char *q = egetenv ("HOSTNAME");
4841 if (!q) q = "pc";
4842 strcpy (p, q);
4843 return 0;
4846 /* When time zones are set from Ms-Dos too many C-libraries are playing
4847 tricks with time values. We solve this by defining our own version
4848 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4849 once and after each call to `tzset' with TZ changed. That is
4850 accomplished by aliasing tzset to init_gettimeofday. */
4852 static struct tm time_rec;
4855 gettimeofday (struct timeval *tp, struct timezone *tzp)
4857 if (tp)
4859 struct time t;
4860 struct tm tm;
4862 gettime (&t);
4863 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
4865 struct date d;
4866 getdate (&d);
4867 time_rec.tm_year = d.da_year - 1900;
4868 time_rec.tm_mon = d.da_mon - 1;
4869 time_rec.tm_mday = d.da_day;
4872 time_rec.tm_hour = t.ti_hour;
4873 time_rec.tm_min = t.ti_min;
4874 time_rec.tm_sec = t.ti_sec;
4876 tm = time_rec;
4877 tm.tm_gmtoff = dos_timezone_offset;
4879 tp->tv_sec = mktime (&tm); /* may modify tm */
4880 tp->tv_usec = t.ti_hund * (1000000 / 100);
4882 /* Ignore tzp; it's obsolescent. */
4883 return 0;
4886 #endif /* __DJGPP__ < 2 */
4889 * A list of unimplemented functions that we silently ignore.
4892 #if __DJGPP__ < 2
4893 unsigned alarm (s) unsigned s; {}
4894 fork () { return 0; }
4895 int kill (x, y) int x, y; { return -1; }
4896 nice (p) int p; {}
4897 void volatile pause () {}
4898 sigsetmask (x) int x; { return 0; }
4899 sigblock (mask) int mask; { return 0; }
4900 #endif
4902 setpgrp () {return 0; }
4903 setpriority (x,y,z) int x,y,z; { return 0; }
4905 #if __DJGPP__ > 1
4906 #if __DJGPP_MINOR__ < 2
4908 #ifdef POSIX_SIGNALS
4910 /* Augment DJGPP library POSIX signal functions. This is needed
4911 as of DJGPP v2.01, but might be in the library in later releases. */
4913 #include <libc/bss.h>
4915 /* A counter to know when to re-initialize the static sets. */
4916 static int sigprocmask_count = -1;
4918 /* Which signals are currently blocked (initially none). */
4919 static sigset_t current_mask;
4921 /* Which signals are pending (initially none). */
4922 static sigset_t msdos_pending_signals;
4924 /* Previous handlers to restore when the blocked signals are unblocked. */
4925 typedef void (*sighandler_t)(int);
4926 static sighandler_t prev_handlers[320];
4928 /* A signal handler which just records that a signal occurred
4929 (it will be raised later, if and when the signal is unblocked). */
4930 static void
4931 sig_suspender (signo)
4932 int signo;
4934 sigaddset (&msdos_pending_signals, signo);
4938 sigprocmask (how, new_set, old_set)
4939 int how;
4940 const sigset_t *new_set;
4941 sigset_t *old_set;
4943 int signo;
4944 sigset_t new_mask;
4946 /* If called for the first time, initialize. */
4947 if (sigprocmask_count != __bss_count)
4949 sigprocmask_count = __bss_count;
4950 sigemptyset (&msdos_pending_signals);
4951 sigemptyset (&current_mask);
4952 for (signo = 0; signo < 320; signo++)
4953 prev_handlers[signo] = SIG_ERR;
4956 if (old_set)
4957 *old_set = current_mask;
4959 if (new_set == 0)
4960 return 0;
4962 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4964 errno = EINVAL;
4965 return -1;
4968 sigemptyset (&new_mask);
4970 /* DJGPP supports upto 320 signals. */
4971 for (signo = 0; signo < 320; signo++)
4973 if (sigismember (&current_mask, signo))
4974 sigaddset (&new_mask, signo);
4975 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4977 sigaddset (&new_mask, signo);
4979 /* SIGKILL is silently ignored, as on other platforms. */
4980 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4981 prev_handlers[signo] = signal (signo, sig_suspender);
4983 if (( how == SIG_UNBLOCK
4984 && sigismember (&new_mask, signo)
4985 && sigismember (new_set, signo))
4986 || (how == SIG_SETMASK
4987 && sigismember (&new_mask, signo)
4988 && !sigismember (new_set, signo)))
4990 sigdelset (&new_mask, signo);
4991 if (prev_handlers[signo] != SIG_ERR)
4993 signal (signo, prev_handlers[signo]);
4994 prev_handlers[signo] = SIG_ERR;
4996 if (sigismember (&msdos_pending_signals, signo))
4998 sigdelset (&msdos_pending_signals, signo);
4999 raise (signo);
5003 current_mask = new_mask;
5004 return 0;
5007 #else /* not POSIX_SIGNALS */
5009 sigsetmask (x) int x; { return 0; }
5010 sigblock (mask) int mask; { return 0; }
5012 #endif /* not POSIX_SIGNALS */
5013 #endif /* not __DJGPP_MINOR__ < 2 */
5014 #endif /* __DJGPP__ > 1 */
5016 #ifndef HAVE_SELECT
5017 #include "sysselect.h"
5019 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5020 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5021 ((long)(time).tv_sec < 0 \
5022 || ((time).tv_sec == 0 \
5023 && (long)(time).tv_usec <= 0))
5024 #endif
5026 /* This yields the rest of the current time slice to the task manager.
5027 It should be called by any code which knows that it has nothing
5028 useful to do except idle.
5030 I don't use __dpmi_yield here, since versions of library before 2.02
5031 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5032 on some versions of Windows 9X. */
5034 void
5035 dos_yield_time_slice (void)
5037 _go32_dpmi_registers r;
5039 r.x.ax = 0x1680;
5040 r.x.ss = r.x.sp = r.x.flags = 0;
5041 _go32_dpmi_simulate_int (0x2f, &r);
5042 if (r.h.al == 0x80)
5043 errno = ENOSYS;
5046 /* Only event queue is checked. */
5047 /* We don't have to call timer_check here
5048 because wait_reading_process_output takes care of that. */
5050 sys_select (nfds, rfds, wfds, efds, timeout)
5051 int nfds;
5052 SELECT_TYPE *rfds, *wfds, *efds;
5053 EMACS_TIME *timeout;
5055 int check_input;
5056 struct time t;
5058 check_input = 0;
5059 if (rfds)
5061 check_input = FD_ISSET (0, rfds);
5062 FD_ZERO (rfds);
5064 if (wfds)
5065 FD_ZERO (wfds);
5066 if (efds)
5067 FD_ZERO (efds);
5069 if (nfds != 1)
5070 abort ();
5072 /* If we are looking only for the terminal, with no timeout,
5073 just read it and wait -- that's more efficient. */
5074 if (!timeout)
5076 while (!detect_input_pending ())
5078 dos_yield_time_slice ();
5081 else
5083 EMACS_TIME clnow, cllast, cldiff;
5085 gettime (&t);
5086 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
5088 while (!check_input || !detect_input_pending ())
5090 gettime (&t);
5091 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
5092 EMACS_SUB_TIME (cldiff, clnow, cllast);
5094 /* When seconds wrap around, we assume that no more than
5095 1 minute passed since last `gettime'. */
5096 if (EMACS_TIME_NEG_P (cldiff))
5097 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
5098 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
5100 /* Stop when timeout value crosses zero. */
5101 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
5102 return 0;
5103 cllast = clnow;
5104 dos_yield_time_slice ();
5108 FD_SET (0, rfds);
5109 return 1;
5111 #endif
5114 * Define overlaid functions:
5116 * chdir -> sys_chdir
5117 * tzset -> init_gettimeofday
5118 * abort -> dos_abort
5121 #ifdef chdir
5122 #undef chdir
5123 extern int chdir ();
5126 sys_chdir (path)
5127 const char* path;
5129 int len = strlen (path);
5130 char *tmp = (char *)path;
5132 if (*tmp && tmp[1] == ':')
5134 if (getdisk () != tolower (tmp[0]) - 'a')
5135 setdisk (tolower (tmp[0]) - 'a');
5136 tmp += 2; /* strip drive: KFS 1995-07-06 */
5137 len -= 2;
5140 if (len > 1 && (tmp[len - 1] == '/'))
5142 char *tmp1 = (char *) alloca (len + 1);
5143 strcpy (tmp1, tmp);
5144 tmp1[len - 1] = 0;
5145 tmp = tmp1;
5147 return chdir (tmp);
5149 #endif
5151 #ifdef tzset
5152 #undef tzset
5153 extern void tzset (void);
5155 void
5156 init_gettimeofday ()
5158 time_t ltm, gtm;
5159 struct tm *lstm;
5161 tzset ();
5162 ltm = gtm = time (NULL);
5163 ltm = mktime (lstm = localtime (&ltm));
5164 gtm = mktime (gmtime (&gtm));
5165 time_rec.tm_hour = 99; /* force gettimeofday to get date */
5166 time_rec.tm_isdst = lstm->tm_isdst;
5167 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
5169 #endif
5171 #ifdef abort
5172 #undef abort
5173 void
5174 dos_abort (file, line)
5175 char *file;
5176 int line;
5178 char buffer1[200], buffer2[400];
5179 int i, j;
5181 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
5182 for (i = j = 0; buffer1[i]; i++) {
5183 buffer2[j++] = buffer1[i];
5184 buffer2[j++] = 0x70;
5186 dosmemput (buffer2, j, (int)ScreenPrimary);
5187 ScreenSetCursor (2, 0);
5188 abort ();
5190 #else
5191 void
5192 abort ()
5194 dos_ttcooked ();
5195 ScreenSetCursor (10, 0);
5196 cputs ("\r\n\nEmacs aborted!\r\n");
5197 #if __DJGPP__ > 1
5198 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5199 if (screen_virtual_segment)
5200 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
5201 /* Generate traceback, so we could tell whodunit. */
5202 signal (SIGINT, SIG_DFL);
5203 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5204 #else /* __DJGPP_MINOR__ >= 2 */
5205 raise (SIGABRT);
5206 #endif /* __DJGPP_MINOR__ >= 2 */
5207 #endif
5208 exit (2);
5210 #endif
5212 /* The following variables are required so that cus-start.el won't
5213 complain about unbound variables. */
5214 #ifndef subprocesses
5215 /* Nonzero means delete a process right away if it exits (process.c). */
5216 static int delete_exited_processes;
5217 #endif
5219 syms_of_msdos ()
5221 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
5222 staticpro (&recent_doskeys);
5224 #ifndef HAVE_X_WINDOWS
5226 /* The following two are from xfns.c: */
5227 Qreverse = intern ("reverse");
5228 staticpro (&Qreverse);
5230 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
5231 doc: /* *Glyph to display instead of chars not supported by current codepage.
5232 This variable is used only by MS-DOS terminals. */);
5233 Vdos_unsupported_char_glyph = make_number ('\177');
5235 #endif
5236 #ifndef subprocesses
5237 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
5238 doc: /* *Non-nil means delete processes immediately when they exit.
5239 A value of nil means don't delete them until `list-processes' is run. */);
5240 delete_exited_processes = 0;
5241 #endif
5243 defsubr (&Srecent_doskeys);
5244 defsubr (&Smsdos_long_file_names);
5245 defsubr (&Smsdos_downcase_filename);
5246 defsubr (&Smsdos_remember_default_colors);
5247 defsubr (&Smsdos_set_mouse_buttons);
5250 #endif /* MSDOS */
5252 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5253 (do not change this comment) */