* keyboard.c (Fset_input_meta_mode): Doc fix.
[emacs.git] / src / msdos.c
blob6397539574e7d6aeb9d8af83a173f32024286198
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
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 "lisp.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <dos.h>
36 #include <errno.h>
37 #include <string.h> /* for bzero and string functions */
38 #include <sys/stat.h> /* for _fixpath */
39 #include <unistd.h> /* for chdir, dup, dup2, etc. */
40 #include <dir.h> /* for getdisk */
41 #if __DJGPP__ >= 2
42 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
43 #include <fcntl.h>
44 #include <io.h> /* for setmode */
45 #include <dpmi.h> /* for __dpmi_xxx stuff */
46 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
47 #include <libc/dosio.h> /* for _USE_LFN */
48 #include <conio.h> /* for cputs */
49 #endif
51 #include "msdos.h"
52 #include "systime.h"
53 #include "frame.h"
54 #include "termhooks.h"
55 #include "termchar.h"
56 #include "dispextern.h"
57 #include "dosfns.h"
58 #include "termopts.h"
59 #include "character.h"
60 #include "coding.h"
61 #include "disptab.h"
62 #include "window.h"
63 #include "buffer.h"
64 #include "commands.h"
65 #include "blockinput.h"
66 #include "keyboard.h"
67 #include "intervals.h"
68 #include <go32.h>
69 #include <pc.h>
70 #include <ctype.h>
71 /* #include <process.h> */
72 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
73 #define P_WAIT 1
75 #ifndef _USE_LFN
76 #define _USE_LFN 0
77 #endif
79 #ifndef _dos_ds
80 #define _dos_ds _go32_info_block.selector_for_linear_memory
81 #endif
83 #if __DJGPP__ > 1
85 #include <signal.h>
86 #include "syssignal.h"
88 #ifndef SYSTEM_MALLOC
90 #ifdef GNU_MALLOC
92 /* If other `malloc' than ours is used, force our `sbrk' behave like
93 Unix programs expect (resize memory blocks to keep them contiguous).
94 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
95 because that's what `gmalloc' expects to get. */
96 #include <crt0.h>
98 #ifdef REL_ALLOC
99 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
100 #else /* not REL_ALLOC */
101 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
102 #endif /* not REL_ALLOC */
103 #endif /* GNU_MALLOC */
105 #endif /* not SYSTEM_MALLOC */
106 #endif /* __DJGPP__ > 1 */
108 static unsigned long
109 event_timestamp ()
111 struct time t;
112 unsigned long s;
114 gettime (&t);
115 s = t.ti_min;
116 s *= 60;
117 s += t.ti_sec;
118 s *= 1000;
119 s += t.ti_hund * 10;
121 return s;
125 /* ------------------------ Mouse control ---------------------------
127 * Coordinates are in screen positions and zero based.
128 * Mouse buttons are numbered from left to right and also zero based.
131 /* This used to be in termhooks.h, but mainstream Emacs code no longer
132 uses it, and it was removed... */
133 #define NUM_MOUSE_BUTTONS (5)
135 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
136 static int mouse_visible;
138 static int mouse_last_x;
139 static int mouse_last_y;
141 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
142 static int mouse_button_count;
144 void
145 mouse_on ()
147 union REGS regs;
149 if (have_mouse > 0 && !mouse_visible)
151 struct tty_display_info *tty = CURTTY ();
153 if (tty->termscript)
154 fprintf (tty->termscript, "<M_ON>");
155 regs.x.ax = 0x0001;
156 int86 (0x33, &regs, &regs);
157 mouse_visible = 1;
161 void
162 mouse_off ()
164 union REGS regs;
166 if (have_mouse > 0 && mouse_visible)
168 struct tty_display_info *tty = CURTTY ();
170 if (tty->termscript)
171 fprintf (tty->termscript, "<M_OFF>");
172 regs.x.ax = 0x0002;
173 int86 (0x33, &regs, &regs);
174 mouse_visible = 0;
178 static void
179 mouse_setup_buttons (int n_buttons)
181 if (n_buttons == 3)
183 mouse_button_count = 3;
184 mouse_button_translate[0] = 0; /* Left */
185 mouse_button_translate[1] = 2; /* Middle */
186 mouse_button_translate[2] = 1; /* Right */
188 else /* two, what else? */
190 mouse_button_count = 2;
191 mouse_button_translate[0] = 0;
192 mouse_button_translate[1] = 1;
196 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
197 1, 1, "NSet number of mouse buttons to: ",
198 doc: /* Set the number of mouse buttons to use by Emacs.
199 This is useful with mice that report the number of buttons inconsistently,
200 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
201 them. This happens with wheeled mice on Windows 9X, for example. */)
202 (nbuttons)
203 Lisp_Object nbuttons;
205 int n;
207 CHECK_NUMBER (nbuttons);
208 n = XINT (nbuttons);
209 if (n < 2 || n > 3)
210 xsignal2 (Qargs_out_of_range,
211 build_string ("only 2 or 3 mouse buttons are supported"),
212 nbuttons);
213 mouse_setup_buttons (n);
214 return Qnil;
217 static void
218 mouse_get_xy (int *x, int *y)
220 union REGS regs;
222 regs.x.ax = 0x0003;
223 int86 (0x33, &regs, &regs);
224 *x = regs.x.cx / 8;
225 *y = regs.x.dx / 8;
228 void
229 mouse_moveto (x, y)
230 int x, y;
232 union REGS regs;
233 struct tty_display_info *tty = CURTTY ();
235 if (tty->termscript)
236 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
237 regs.x.ax = 0x0004;
238 mouse_last_x = regs.x.cx = x * 8;
239 mouse_last_y = regs.x.dx = y * 8;
240 int86 (0x33, &regs, &regs);
243 static int
244 mouse_pressed (b, xp, yp)
245 int b, *xp, *yp;
247 union REGS regs;
249 if (b >= mouse_button_count)
250 return 0;
251 regs.x.ax = 0x0005;
252 regs.x.bx = mouse_button_translate[b];
253 int86 (0x33, &regs, &regs);
254 if (regs.x.bx)
255 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
256 return (regs.x.bx != 0);
259 static int
260 mouse_released (b, xp, yp)
261 int b, *xp, *yp;
263 union REGS regs;
265 if (b >= mouse_button_count)
266 return 0;
267 regs.x.ax = 0x0006;
268 regs.x.bx = mouse_button_translate[b];
269 int86 (0x33, &regs, &regs);
270 if (regs.x.bx)
271 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
272 return (regs.x.bx != 0);
275 static int
276 mouse_button_depressed (b, xp, yp)
277 int b, *xp, *yp;
279 union REGS regs;
281 if (b >= mouse_button_count)
282 return 0;
283 regs.x.ax = 0x0003;
284 int86 (0x33, &regs, &regs);
285 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
287 *xp = regs.x.cx / 8;
288 *yp = regs.x.dx / 8;
289 return 1;
291 return 0;
294 void
295 mouse_get_pos (f, insist, bar_window, part, x, y, time)
296 FRAME_PTR *f;
297 int insist;
298 Lisp_Object *bar_window, *x, *y;
299 enum scroll_bar_part *part;
300 unsigned long *time;
302 int ix, iy;
303 Lisp_Object frame, tail;
305 /* Clear the mouse-moved flag for every frame on this display. */
306 FOR_EACH_FRAME (tail, frame)
307 XFRAME (frame)->mouse_moved = 0;
309 *f = SELECTED_FRAME();
310 *bar_window = Qnil;
311 mouse_get_xy (&ix, &iy);
312 *time = event_timestamp ();
313 *x = make_number (mouse_last_x = ix);
314 *y = make_number (mouse_last_y = iy);
317 static void
318 mouse_check_moved ()
320 int x, y;
322 mouse_get_xy (&x, &y);
323 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
324 mouse_last_x = x;
325 mouse_last_y = y;
328 /* Force the mouse driver to ``forget'' about any button clicks until
329 now. */
330 static void
331 mouse_clear_clicks (void)
333 int b;
335 for (b = 0; b < mouse_button_count; b++)
337 int dummy_x, dummy_y;
339 (void) mouse_pressed (b, &dummy_x, &dummy_y);
340 (void) mouse_released (b, &dummy_x, &dummy_y);
344 void
345 mouse_init ()
347 union REGS regs;
348 struct tty_display_info *tty = CURTTY ();
350 if (tty->termscript)
351 fprintf (tty->termscript, "<M_INIT>");
353 regs.x.ax = 0x0021;
354 int86 (0x33, &regs, &regs);
356 /* Reset the mouse last press/release info. It seems that Windows
357 doesn't do that automatically when function 21h is called, which
358 causes Emacs to ``remember'' the click that switched focus to the
359 window just before Emacs was started from that window. */
360 mouse_clear_clicks ();
362 regs.x.ax = 0x0007;
363 regs.x.cx = 0;
364 regs.x.dx = 8 * (ScreenCols () - 1);
365 int86 (0x33, &regs, &regs);
367 regs.x.ax = 0x0008;
368 regs.x.cx = 0;
369 regs.x.dx = 8 * (ScreenRows () - 1);
370 int86 (0x33, &regs, &regs);
372 mouse_moveto (0, 0);
373 mouse_visible = 0;
376 /* ------------------------- Screen control ----------------------
380 static int internal_terminal = 0;
382 #ifndef HAVE_X_WINDOWS
383 extern unsigned char ScreenAttrib;
384 static int screen_face;
386 static int screen_size_X;
387 static int screen_size_Y;
388 static int screen_size;
390 static int current_pos_X;
391 static int current_pos_Y;
392 static int new_pos_X;
393 static int new_pos_Y;
395 static void *startup_screen_buffer;
396 static int startup_screen_size_X;
397 static int startup_screen_size_Y;
398 static int startup_pos_X;
399 static int startup_pos_Y;
400 static unsigned char startup_screen_attrib;
402 static clock_t startup_time;
404 static int term_setup_done;
406 static unsigned short outside_cursor;
408 /* Similar to the_only_frame. */
409 struct tty_display_info the_only_display_info;
411 /* Support for DOS/V (allows Japanese characters to be displayed on
412 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
414 /* Holds the address of the text-mode screen buffer. */
415 static unsigned long screen_old_address = 0;
416 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
417 static unsigned short screen_virtual_segment = 0;
418 static unsigned short screen_virtual_offset = 0;
419 /* A flag to control how to display unibyte 8-bit characters. */
420 extern int unibyte_display_via_language_environment;
422 extern Lisp_Object Qcursor_type;
423 extern Lisp_Object Qbar, Qhbar;
425 /* The screen colors of the current frame, which serve as the default
426 colors for newly-created frames. */
427 static int initial_screen_colors[2];
429 #if __DJGPP__ > 1
430 /* Update the screen from a part of relocated DOS/V screen buffer which
431 begins at OFFSET and includes COUNT characters. */
432 static void
433 dosv_refresh_virtual_screen (int offset, int count)
435 __dpmi_regs regs;
437 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
438 return;
440 regs.h.ah = 0xff; /* update relocated screen */
441 regs.x.es = screen_virtual_segment;
442 regs.x.di = screen_virtual_offset + offset;
443 regs.x.cx = count;
444 __dpmi_int (0x10, &regs);
446 #endif
448 static void
449 dos_direct_output (y, x, buf, len)
450 int x, y;
451 char *buf;
452 int len;
454 int t0 = 2 * (x + y * screen_size_X);
455 int t = t0 + (int) ScreenPrimary;
456 int l0 = len;
458 #if (__DJGPP__ < 2)
459 while (--len >= 0) {
460 dosmemput (buf++, 1, t);
461 t += 2;
463 #else
464 /* This is faster. */
465 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
466 _farnspokeb (t, *buf);
468 if (screen_virtual_segment)
469 dosv_refresh_virtual_screen (t0, l0);
470 #endif
472 #endif
474 /* Flash the screen as a substitute for BEEPs. */
476 #if (__DJGPP__ < 2)
477 static void
478 do_visible_bell (xorattr)
479 unsigned char xorattr;
481 asm volatile
482 (" movb $1,%%dl \n\
483 visible_bell_0: \n\
484 movl _ScreenPrimary,%%eax \n\
485 call dosmemsetup \n\
486 movl %%eax,%%ebx \n\
487 movl %1,%%ecx \n\
488 movb %0,%%al \n\
489 incl %%ebx \n\
490 visible_bell_1: \n\
491 xorb %%al,%%gs:(%%ebx) \n\
492 addl $2,%%ebx \n\
493 decl %%ecx \n\
494 jne visible_bell_1 \n\
495 decb %%dl \n\
496 jne visible_bell_3 \n\
497 visible_bell_2: \n\
498 movzwl %%ax,%%eax \n\
499 movzwl %%ax,%%eax \n\
500 movzwl %%ax,%%eax \n\
501 movzwl %%ax,%%eax \n\
502 decw %%cx \n\
503 jne visible_bell_2 \n\
504 jmp visible_bell_0 \n\
505 visible_bell_3:"
506 : /* no output */
507 : "m" (xorattr), "g" (screen_size)
508 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
511 static void
512 ScreenVisualBell (void)
514 /* This creates an xor-mask that will swap the default fore- and
515 background colors. */
516 do_visible_bell (((FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ())
517 ^ FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()))
518 * 0x11) & 0x7f);
520 #endif
522 #ifndef HAVE_X_WINDOWS
524 static int blink_bit = -1; /* the state of the blink bit at startup */
526 /* Enable bright background colors. */
527 static void
528 bright_bg (void)
530 union REGS regs;
532 /* Remember the original state of the blink/bright-background bit.
533 It is stored at 0040:0065h in the BIOS data area. */
534 if (blink_bit == -1)
535 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
537 regs.h.bl = 0;
538 regs.x.ax = 0x1003;
539 int86 (0x10, &regs, &regs);
542 /* Disable bright background colors (and enable blinking) if we found
543 the video system in that state at startup. */
544 static void
545 maybe_enable_blinking (void)
547 if (blink_bit == 1)
549 union REGS regs;
551 regs.h.bl = 1;
552 regs.x.ax = 0x1003;
553 int86 (0x10, &regs, &regs);
557 /* Return non-zero if the system has a VGA adapter. */
558 static int
559 vga_installed (void)
561 union REGS regs;
563 regs.x.ax = 0x1a00;
564 int86 (0x10, &regs, &regs);
565 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
566 return 1;
567 return 0;
570 /* Set the screen dimensions so that it can show no less than
571 ROWS x COLS frame. */
573 void
574 dos_set_window_size (rows, cols)
575 int *rows, *cols;
577 char video_name[30];
578 union REGS regs;
579 Lisp_Object video_mode;
580 int video_mode_value, have_vga = 0;
581 int current_rows = ScreenRows (), current_cols = ScreenCols ();
583 if (*rows == current_rows && *cols == current_cols)
584 return;
586 mouse_off ();
587 have_vga = vga_installed ();
589 /* If the user specified a special video mode for these dimensions,
590 use that mode. */
591 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
592 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
593 Qnil))-> value;
595 if (INTEGERP (video_mode)
596 && (video_mode_value = XINT (video_mode)) > 0)
598 regs.x.ax = video_mode_value;
599 int86 (0x10, &regs, &regs);
601 if (have_mouse)
603 /* Must hardware-reset the mouse, or else it won't update
604 its notion of screen dimensions for some non-standard
605 video modes. This is *painfully* slow... */
606 regs.x.ax = 0;
607 int86 (0x33, &regs, &regs);
611 /* Find one of the dimensions supported by standard EGA/VGA
612 which gives us at least the required dimensions. */
614 #if __DJGPP__ > 1
616 else
618 static struct {
619 int rows, need_vga;
620 } std_dimension[] = {
621 {25, 0},
622 {28, 1},
623 {35, 0},
624 {40, 1},
625 {43, 0},
626 {50, 1}
628 int i = 0;
630 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
632 if (std_dimension[i].need_vga <= have_vga
633 && std_dimension[i].rows >= *rows)
635 if (std_dimension[i].rows != current_rows
636 || *cols != current_cols)
637 _set_screen_lines (std_dimension[i].rows);
638 break;
640 i++;
644 #else /* not __DJGPP__ > 1 */
646 else if (*rows <= 25)
648 if (current_rows != 25 || current_cols != 80)
650 regs.x.ax = 3;
651 int86 (0x10, &regs, &regs);
652 regs.x.ax = 0x1101;
653 regs.h.bl = 0;
654 int86 (0x10, &regs, &regs);
655 regs.x.ax = 0x1200;
656 regs.h.bl = 32;
657 int86 (0x10, &regs, &regs);
658 regs.x.ax = 3;
659 int86 (0x10, &regs, &regs);
662 else if (*rows <= 50)
663 if (have_vga && (current_rows != 50 || current_cols != 80)
664 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
666 regs.x.ax = 3;
667 int86 (0x10, &regs, &regs);
668 regs.x.ax = 0x1112;
669 regs.h.bl = 0;
670 int86 (0x10, &regs, &regs);
671 regs.x.ax = 0x1200;
672 regs.h.bl = 32;
673 int86 (0x10, &regs, &regs);
674 regs.x.ax = 0x0100;
675 regs.x.cx = 7;
676 int86 (0x10, &regs, &regs);
678 #endif /* not __DJGPP__ > 1 */
680 if (have_mouse)
682 mouse_init ();
683 mouse_on ();
686 /* Tell the caller what dimensions have been REALLY set. */
687 *rows = ScreenRows ();
688 *cols = ScreenCols ();
690 /* Update Emacs' notion of screen dimensions. */
691 screen_size_X = *cols;
692 screen_size_Y = *rows;
693 screen_size = *cols * *rows;
695 #if __DJGPP__ > 1
696 /* If the dimensions changed, the mouse highlight info is invalid. */
697 if (current_rows != *rows || current_cols != *cols)
699 struct frame *f = SELECTED_FRAME();
700 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
701 Lisp_Object window = dpyinfo->mouse_face_window;
703 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
705 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
706 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
707 dpyinfo->mouse_face_window = Qnil;
710 #endif
712 /* Enable bright background colors. */
713 bright_bg ();
715 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
716 be defensive anyway. */
717 if (screen_virtual_segment)
718 dosv_refresh_virtual_screen (0, *cols * *rows);
721 /* If we write a character in the position where the mouse is,
722 the mouse cursor may need to be refreshed. */
724 static void
725 mouse_off_maybe ()
727 int x, y;
729 if (!mouse_visible)
730 return;
732 mouse_get_xy (&x, &y);
733 if (y != new_pos_Y || x < new_pos_X)
734 return;
736 mouse_off ();
739 #define DEFAULT_CURSOR_START (-1)
740 #define DEFAULT_CURSOR_WIDTH (-1)
741 #define BOX_CURSOR_WIDTH (-32)
743 /* Set cursor to begin at scan line START_LINE in the character cell
744 and extend for WIDTH scan lines. Scan lines are counted from top
745 of the character cell, starting from zero. */
746 static void
747 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
749 #if __DJGPP__ > 1
750 unsigned desired_cursor;
751 __dpmi_regs regs;
752 int max_line, top_line, bot_line;
753 struct tty_display_info *tty = FRAME_TTY (f);
755 /* Avoid the costly BIOS call if F isn't the currently selected
756 frame. Allow for NULL as unconditionally meaning the selected
757 frame. */
758 if (f && f != SELECTED_FRAME())
759 return;
761 if (tty->termscript)
762 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
764 /* The character cell size in scan lines is stored at 40:85 in the
765 BIOS data area. */
766 max_line = _farpeekw (_dos_ds, 0x485) - 1;
767 switch (max_line)
769 default: /* this relies on CGA cursor emulation being ON! */
770 case 7:
771 bot_line = 7;
772 break;
773 case 9:
774 bot_line = 9;
775 break;
776 case 13:
777 bot_line = 12;
778 break;
779 case 15:
780 bot_line = 14;
781 break;
784 if (width < 0)
786 if (width == BOX_CURSOR_WIDTH)
788 top_line = 0;
789 bot_line = max_line;
791 else if (start_line != DEFAULT_CURSOR_START)
793 top_line = start_line;
794 bot_line = top_line - width - 1;
796 else if (width != DEFAULT_CURSOR_WIDTH)
798 top_line = 0;
799 bot_line = -1 - width;
801 else
802 top_line = bot_line + 1;
804 else if (width == 0)
806 /* [31, 0] seems to DTRT for all screen sizes. */
807 top_line = 31;
808 bot_line = 0;
810 else /* WIDTH is positive */
812 if (start_line != DEFAULT_CURSOR_START)
813 bot_line = start_line;
814 top_line = bot_line - (width - 1);
817 /* If the current cursor shape is already what they want, we are
818 history here. */
819 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
820 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
821 return;
823 regs.h.ah = 1;
824 regs.x.cx = desired_cursor;
825 __dpmi_int (0x10, &regs);
826 #endif /* __DJGPP__ > 1 */
829 static void
830 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
832 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
834 /* Just BAR means the normal EGA/VGA cursor. */
835 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
837 else if (CONSP (cursor_type)
838 && (EQ (XCAR (cursor_type), Qbar)
839 || EQ (XCAR (cursor_type), Qhbar)))
841 Lisp_Object bar_parms = XCDR (cursor_type);
842 int width;
844 if (INTEGERP (bar_parms))
846 /* Feature: negative WIDTH means cursor at the top
847 of the character cell, zero means invisible cursor. */
848 width = XINT (bar_parms);
849 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
850 width);
852 else if (CONSP (bar_parms)
853 && INTEGERP (XCAR (bar_parms))
854 && INTEGERP (XCDR (bar_parms)))
856 int start_line = XINT (XCDR (bar_parms));
858 width = XINT (XCAR (bar_parms));
859 msdos_set_cursor_shape (f, start_line, width);
862 else
864 /* Treat anything unknown as "box cursor". This includes nil, so
865 that a frame which doesn't specify a cursor type gets a box,
866 which is the default in Emacs. */
867 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
871 static void
872 IT_ring_bell (struct frame *f)
874 if (visible_bell)
876 mouse_off ();
877 ScreenVisualBell ();
879 else
881 union REGS inregs, outregs;
882 inregs.h.ah = 2;
883 inregs.h.dl = 7;
884 intdos (&inregs, &outregs);
888 /* Given a face id FACE, extract the face parameters to be used for
889 display until the face changes. The face parameters (actually, its
890 color) are used to construct the video attribute byte for each
891 glyph during the construction of the buffer that is then blitted to
892 the video RAM. */
893 static void
894 IT_set_face (int face)
896 struct frame *sf = SELECTED_FRAME();
897 struct face *fp = FACE_FROM_ID (sf, face);
898 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
899 unsigned long fg, bg, dflt_fg, dflt_bg;
900 struct tty_display_info *tty = FRAME_TTY (sf);
902 if (!fp)
904 fp = dfp;
905 /* The default face for the frame should always be realized and
906 cached. */
907 if (!fp)
908 abort ();
910 screen_face = face;
911 fg = fp->foreground;
912 bg = fp->background;
913 dflt_fg = dfp->foreground;
914 dflt_bg = dfp->background;
916 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
917 mean use the colors of the default face. Note that we assume all
918 16 colors to be available for the background, since Emacs switches
919 on this mode (and loses the blinking attribute) at startup. */
920 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
921 fg = FRAME_FOREGROUND_PIXEL (sf);
922 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
923 fg = FRAME_BACKGROUND_PIXEL (sf);
924 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
925 bg = FRAME_BACKGROUND_PIXEL (sf);
926 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
927 bg = FRAME_FOREGROUND_PIXEL (sf);
929 /* Make sure highlighted lines really stand out, come what may. */
930 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
932 unsigned long tem = fg;
934 fg = bg;
935 bg = tem;
937 /* If the user requested inverse video, obey. */
938 if (inverse_video)
940 unsigned long tem2 = fg;
942 fg = bg;
943 bg = tem2;
945 if (tty->termscript)
946 fprintf (tty->termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
947 fp->foreground, fp->background, fg, bg);
948 if (fg >= 0 && fg < 16)
950 ScreenAttrib &= 0xf0;
951 ScreenAttrib |= fg;
953 if (bg >= 0 && bg < 16)
955 ScreenAttrib &= 0x0f;
956 ScreenAttrib |= ((bg & 0x0f) << 4);
960 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
961 width of a DOS display in any known text mode. We multiply by 2 to
962 accomodate the screen attribute byte. */
963 #define MAX_SCREEN_BUF 160*2
965 Lisp_Object Vdos_unsupported_char_glyph;
966 extern unsigned char *encode_terminal_code (struct glyph *, int,
967 struct coding_system *);
968 static void
969 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
971 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
972 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
973 register int sl = str_len;
974 struct tty_display_info *tty = FRAME_TTY (f);
975 struct frame *sf;
976 unsigned char *conversion_buffer;
978 /* Do we need to consider conversion of unibyte characters to
979 multibyte? */
980 int convert_unibyte_characters
981 = (NILP (current_buffer->enable_multibyte_characters)
982 && unibyte_display_via_language_environment);
984 /* If terminal_coding does any conversion, use it, otherwise use
985 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
986 because it always returns 1 if terminal_coding.src_multibyte is 1. */
987 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
989 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
990 coding = &safe_terminal_coding;
992 if (str_len <= 0) return;
994 sf = SELECTED_FRAME();
996 /* Since faces get cached and uncached behind our back, we can't
997 rely on their indices in the cache being consistent across
998 invocations. So always reset the screen face to the default
999 face of the frame, before writing glyphs, and let the glyphs
1000 set the right face if it's different from the default. */
1001 IT_set_face (DEFAULT_FACE_ID);
1003 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1004 the tail. */
1005 coding->mode &= ~CODING_MODE_LAST_BLOCK;
1006 screen_bp = &screen_buf[0];
1007 while (sl > 0)
1009 int cf;
1010 int n;
1012 /* If the face of this glyph is different from the current
1013 screen face, update the screen attribute byte. */
1014 cf = str->face_id;
1015 if (cf != screen_face)
1016 IT_set_face (cf); /* handles invalid faces gracefully */
1018 /* Identify a run of glyphs with the same face. */
1019 for (n = 1; n < sl; ++n)
1020 if (str[n].face_id != cf)
1021 break;
1023 if (n >= sl)
1024 /* This is the last glyph. */
1025 coding->mode |= CODING_MODE_LAST_BLOCK;
1027 conversion_buffer = encode_terminal_code (str, n, coding);
1028 if (coding->produced > 0)
1030 /* Copy the encoded bytes to the screen buffer. */
1031 for (bp = conversion_buffer; coding->produced--; bp++)
1033 /* Paranoia: discard bytes that would overrun the end of
1034 the screen buffer. */
1035 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
1037 *screen_bp++ = (unsigned char)*bp;
1038 *screen_bp++ = ScreenAttrib;
1040 if (tty->termscript)
1041 fputc (*bp, tty->termscript);
1044 /* Update STR and its remaining length. */
1045 str += n;
1046 sl -= n;
1049 /* Dump whatever we have in the screen buffer. */
1050 mouse_off_maybe ();
1051 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1052 if (screen_virtual_segment)
1053 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1054 new_pos_X += (screen_bp - screen_buf) / 2;
1057 /************************************************************************
1058 Mouse Highlight (and friends..)
1059 ************************************************************************/
1061 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1062 static Lisp_Object last_mouse_window;
1064 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1066 /* Set the mouse pointer shape according to whether it is in the
1067 area where the mouse highlight is in effect. */
1068 static void
1069 IT_set_mouse_pointer (int mode)
1071 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1072 many possibilities to change its shape, and the available
1073 functionality pretty much sucks (e.g., almost every reasonable
1074 shape will conceal the character it is on). Since the color of
1075 the pointer changes in the highlighted area, it is not clear to
1076 me whether anything else is required, anyway. */
1079 /* Display the active region described by mouse_face_*
1080 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1081 static void
1082 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
1084 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1085 struct frame *f = XFRAME (WINDOW_FRAME (w));
1086 int i;
1087 struct face *fp;
1088 struct tty_display_info *tty = FRAME_TTY (f);
1091 /* If window is in the process of being destroyed, don't bother
1092 doing anything. */
1093 if (w->current_matrix == NULL)
1094 goto set_cursor_shape;
1096 /* Recognize when we are called to operate on rows that don't exist
1097 anymore. This can happen when a window is split. */
1098 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1099 goto set_cursor_shape;
1101 /* There's no sense to do anything if the mouse face isn't realized. */
1102 if (hl > 0)
1104 if (dpyinfo->mouse_face_hidden)
1105 goto set_cursor_shape;
1107 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1108 if (!fp)
1109 goto set_cursor_shape;
1112 /* Note that mouse_face_beg_row etc. are window relative. */
1113 for (i = dpyinfo->mouse_face_beg_row;
1114 i <= dpyinfo->mouse_face_end_row;
1115 i++)
1117 int start_hpos, end_hpos;
1118 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1120 /* Don't do anything if row doesn't have valid contents. */
1121 if (!row->enabled_p)
1122 continue;
1124 /* For all but the first row, the highlight starts at column 0. */
1125 if (i == dpyinfo->mouse_face_beg_row)
1126 start_hpos = dpyinfo->mouse_face_beg_col;
1127 else
1128 start_hpos = 0;
1130 if (i == dpyinfo->mouse_face_end_row)
1131 end_hpos = dpyinfo->mouse_face_end_col;
1132 else
1133 end_hpos = row->used[TEXT_AREA];
1135 if (end_hpos <= start_hpos)
1136 continue;
1137 /* Record that some glyphs of this row are displayed in
1138 mouse-face. */
1139 row->mouse_face_p = hl > 0;
1140 if (hl > 0)
1142 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1143 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1144 int nglyphs = end_hpos - start_hpos;
1145 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1146 int start_offset = offset;
1148 if (tty->termscript)
1149 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1150 kstart, kstart + nglyphs - 1, vpos);
1152 mouse_off ();
1153 IT_set_face (dpyinfo->mouse_face_face_id);
1154 /* Since we are going to change only the _colors_ of the
1155 displayed text, there's no need to go through all the
1156 pain of generating and encoding the text from the glyphs.
1157 Instead, we simply poke the attribute byte of each
1158 affected position in video memory with the colors
1159 computed by IT_set_face! */
1160 _farsetsel (_dos_ds);
1161 while (nglyphs--)
1163 _farnspokeb (offset, ScreenAttrib);
1164 offset += 2;
1166 if (screen_virtual_segment)
1167 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1168 mouse_on ();
1170 else
1172 /* We are removing a previously-drawn mouse highlight. The
1173 safest way to do so is to redraw the glyphs anew, since
1174 all kinds of faces and display tables could have changed
1175 behind our back. */
1176 int nglyphs = end_hpos - start_hpos;
1177 int save_x = new_pos_X, save_y = new_pos_Y;
1179 if (end_hpos >= row->used[TEXT_AREA])
1180 nglyphs = row->used[TEXT_AREA] - start_hpos;
1182 /* IT_write_glyphs writes at cursor position, so we need to
1183 temporarily move cursor coordinates to the beginning of
1184 the highlight region. */
1185 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1186 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1188 if (tty->termscript)
1189 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1190 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1191 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1192 if (tty->termscript)
1193 fputs ("\n", tty->termscript);
1194 new_pos_X = save_x;
1195 new_pos_Y = save_y;
1199 set_cursor_shape:
1200 /* Change the mouse pointer shape. */
1201 IT_set_mouse_pointer (hl);
1204 /* Clear out the mouse-highlighted active region.
1205 Redraw it un-highlighted first. */
1206 static void
1207 clear_mouse_face (struct tty_display_info *dpyinfo)
1209 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1210 show_mouse_face (dpyinfo, 0);
1212 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1213 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1214 dpyinfo->mouse_face_window = Qnil;
1217 /* Find the glyph matrix position of buffer position POS in window W.
1218 *HPOS and *VPOS are set to the positions found. W's current glyphs
1219 must be up to date. If POS is above window start return (0, 0).
1220 If POS is after end of W, return end of last line in W. */
1221 static int
1222 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1224 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1225 int yb = window_text_bottom_y (w);
1226 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1228 while (row->y < yb)
1230 if (row->used[TEXT_AREA])
1231 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1232 else
1233 line_start_position = 0;
1235 if (line_start_position > pos)
1236 break;
1237 /* If the position sought is the end of the buffer,
1238 don't include the blank lines at the bottom of the window. */
1239 else if (line_start_position == pos
1240 && pos == BUF_ZV (XBUFFER (w->buffer)))
1242 maybe_next_line_p = 1;
1243 break;
1245 else if (line_start_position > 0)
1246 best_row = row;
1248 /* Don't overstep the last matrix row, lest we get into the
1249 never-never land... */
1250 if (row->y + 1 >= yb)
1251 break;
1253 ++row;
1256 /* Find the right column within BEST_ROW. */
1257 lastcol = 0;
1258 row = best_row;
1259 for (i = 0; i < row->used[TEXT_AREA]; i++)
1261 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1262 int charpos;
1264 charpos = glyph->charpos;
1265 if (charpos == pos)
1267 *hpos = i;
1268 *vpos = row->y;
1269 return 1;
1271 else if (charpos > pos)
1272 break;
1273 else if (charpos > 0)
1274 lastcol = i;
1277 /* If we're looking for the end of the buffer,
1278 and we didn't find it in the line we scanned,
1279 use the start of the following line. */
1280 if (maybe_next_line_p)
1282 ++row;
1283 lastcol = 0;
1286 *vpos = row->y;
1287 *hpos = lastcol + 1;
1288 return 0;
1291 /* Take proper action when mouse has moved to the mode or top line of
1292 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1293 mode line. X is relative to the start of the text display area of
1294 W, so the width of fringes and scroll bars must be subtracted
1295 to get a position relative to the start of the mode line. */
1296 static void
1297 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1299 struct frame *f = XFRAME (w->frame);
1300 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1301 struct glyph_row *row;
1303 if (mode_line_p)
1304 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1305 else
1306 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1308 if (row->enabled_p)
1310 extern Lisp_Object Qhelp_echo;
1311 struct glyph *glyph, *end;
1312 Lisp_Object help, map;
1314 /* Find the glyph under X. */
1315 glyph = (row->glyphs[TEXT_AREA]
1317 /* in case someone implements scroll bars some day... */
1318 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1319 end = glyph + row->used[TEXT_AREA];
1320 if (glyph < end
1321 && STRINGP (glyph->object)
1322 && STRING_INTERVALS (glyph->object)
1323 && glyph->charpos >= 0
1324 && glyph->charpos < SCHARS (glyph->object))
1326 /* If we're on a string with `help-echo' text property,
1327 arrange for the help to be displayed. This is done by
1328 setting the global variable help_echo to the help string. */
1329 help = Fget_text_property (make_number (glyph->charpos),
1330 Qhelp_echo, glyph->object);
1331 if (!NILP (help))
1333 help_echo_string = help;
1334 XSETWINDOW (help_echo_window, w);
1335 help_echo_object = glyph->object;
1336 help_echo_pos = glyph->charpos;
1342 /* Take proper action when the mouse has moved to position X, Y on
1343 frame F as regards highlighting characters that have mouse-face
1344 properties. Also de-highlighting chars where the mouse was before.
1345 X and Y can be negative or out of range. */
1346 static void
1347 IT_note_mouse_highlight (struct frame *f, int x, int y)
1349 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1350 enum window_part part = ON_NOTHING;
1351 Lisp_Object window;
1352 struct window *w;
1354 /* When a menu is active, don't highlight because this looks odd. */
1355 if (mouse_preempted)
1356 return;
1358 if (NILP (Vmouse_highlight)
1359 || !f->glyphs_initialized_p)
1360 return;
1362 dpyinfo->mouse_face_mouse_x = x;
1363 dpyinfo->mouse_face_mouse_y = y;
1364 dpyinfo->mouse_face_mouse_frame = f;
1366 if (dpyinfo->mouse_face_defer)
1367 return;
1369 if (gc_in_progress)
1371 dpyinfo->mouse_face_deferred_gc = 1;
1372 return;
1375 /* Which window is that in? */
1376 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1378 /* If we were displaying active text in another window, clear that. */
1379 if (! EQ (window, dpyinfo->mouse_face_window))
1380 clear_mouse_face (dpyinfo);
1382 /* Not on a window -> return. */
1383 if (!WINDOWP (window))
1384 return;
1386 /* Convert to window-relative coordinates. */
1387 w = XWINDOW (window);
1389 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1391 /* Mouse is on the mode or top line. */
1392 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1393 return;
1396 IT_set_mouse_pointer (0);
1398 /* Are we in a window whose display is up to date?
1399 And verify the buffer's text has not changed. */
1400 if (part == ON_TEXT
1401 && EQ (w->window_end_valid, w->buffer)
1402 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1403 && (XFASTINT (w->last_overlay_modified)
1404 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1406 int pos, i, nrows = w->current_matrix->nrows;
1407 struct glyph_row *row;
1408 struct glyph *glyph;
1410 /* Find the glyph under X/Y. */
1411 glyph = NULL;
1412 if (y >= 0 && y < nrows)
1414 row = MATRIX_ROW (w->current_matrix, y);
1415 /* Give up if some row before the one we are looking for is
1416 not enabled. */
1417 for (i = 0; i <= y; i++)
1418 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1419 break;
1420 if (i > y /* all rows upto and including the one at Y are enabled */
1421 && row->displays_text_p
1422 && x < window_box_width (w, TEXT_AREA))
1424 glyph = row->glyphs[TEXT_AREA];
1425 if (x >= row->used[TEXT_AREA])
1426 glyph = NULL;
1427 else
1429 glyph += x;
1430 if (!BUFFERP (glyph->object))
1431 glyph = NULL;
1436 /* Clear mouse face if X/Y not over text. */
1437 if (glyph == NULL)
1439 clear_mouse_face (dpyinfo);
1440 return;
1443 if (!BUFFERP (glyph->object))
1444 abort ();
1445 pos = glyph->charpos;
1447 /* Check for mouse-face and help-echo. */
1449 extern Lisp_Object Qmouse_face;
1450 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1451 int noverlays, obegv, ozv;
1452 struct buffer *obuf;
1454 /* If we get an out-of-range value, return now; avoid an error. */
1455 if (pos > BUF_Z (XBUFFER (w->buffer)))
1456 return;
1458 /* Make the window's buffer temporarily current for
1459 overlays_at and compute_char_face. */
1460 obuf = current_buffer;
1461 current_buffer = XBUFFER (w->buffer);
1462 obegv = BEGV;
1463 ozv = ZV;
1464 BEGV = BEG;
1465 ZV = Z;
1467 /* Is this char mouse-active or does it have help-echo? */
1468 XSETINT (position, pos);
1470 /* Put all the overlays we want in a vector in overlay_vec. */
1471 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1472 /* Sort overlays into increasing priority order. */
1473 noverlays = sort_overlays (overlay_vec, noverlays, w);
1475 /* Check mouse-face highlighting. */
1476 if (! (EQ (window, dpyinfo->mouse_face_window)
1477 && y >= dpyinfo->mouse_face_beg_row
1478 && y <= dpyinfo->mouse_face_end_row
1479 && (y > dpyinfo->mouse_face_beg_row
1480 || x >= dpyinfo->mouse_face_beg_col)
1481 && (y < dpyinfo->mouse_face_end_row
1482 || x < dpyinfo->mouse_face_end_col
1483 || dpyinfo->mouse_face_past_end)))
1485 /* Clear the display of the old active region, if any. */
1486 clear_mouse_face (dpyinfo);
1488 /* Find highest priority overlay that has a mouse-face prop. */
1489 overlay = Qnil;
1490 for (i = noverlays - 1; i >= 0; --i)
1492 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1493 if (!NILP (mouse_face))
1495 overlay = overlay_vec[i];
1496 break;
1500 /* If no overlay applies, get a text property. */
1501 if (NILP (overlay))
1502 mouse_face = Fget_text_property (position, Qmouse_face,
1503 w->buffer);
1505 /* Handle the overlay case. */
1506 if (! NILP (overlay))
1508 /* Find the range of text around this char that
1509 should be active. */
1510 Lisp_Object before, after;
1511 EMACS_INT ignore;
1513 before = Foverlay_start (overlay);
1514 after = Foverlay_end (overlay);
1515 /* Record this as the current active region. */
1516 fast_find_position (w, XFASTINT (before),
1517 &dpyinfo->mouse_face_beg_col,
1518 &dpyinfo->mouse_face_beg_row);
1519 dpyinfo->mouse_face_past_end
1520 = !fast_find_position (w, XFASTINT (after),
1521 &dpyinfo->mouse_face_end_col,
1522 &dpyinfo->mouse_face_end_row);
1523 dpyinfo->mouse_face_window = window;
1524 dpyinfo->mouse_face_face_id
1525 = face_at_buffer_position (w, pos, 0, 0,
1526 &ignore, pos + 1,
1527 !dpyinfo->mouse_face_hidden);
1529 /* Display it as active. */
1530 show_mouse_face (dpyinfo, 1);
1532 /* Handle the text property case. */
1533 else if (! NILP (mouse_face))
1535 /* Find the range of text around this char that
1536 should be active. */
1537 Lisp_Object before, after, beginning, end;
1538 EMACS_INT ignore;
1540 beginning = Fmarker_position (w->start);
1541 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1542 - XFASTINT (w->window_end_pos)));
1543 before
1544 = Fprevious_single_property_change (make_number (pos + 1),
1545 Qmouse_face,
1546 w->buffer, beginning);
1547 after
1548 = Fnext_single_property_change (position, Qmouse_face,
1549 w->buffer, end);
1550 /* Record this as the current active region. */
1551 fast_find_position (w, XFASTINT (before),
1552 &dpyinfo->mouse_face_beg_col,
1553 &dpyinfo->mouse_face_beg_row);
1554 dpyinfo->mouse_face_past_end
1555 = !fast_find_position (w, XFASTINT (after),
1556 &dpyinfo->mouse_face_end_col,
1557 &dpyinfo->mouse_face_end_row);
1558 dpyinfo->mouse_face_window = window;
1559 dpyinfo->mouse_face_face_id
1560 = face_at_buffer_position (w, pos, 0, 0,
1561 &ignore, pos + 1,
1562 !dpyinfo->mouse_face_hidden);
1564 /* Display it as active. */
1565 show_mouse_face (dpyinfo, 1);
1569 /* Look for a `help-echo' property. */
1571 Lisp_Object help;
1572 extern Lisp_Object Qhelp_echo;
1574 /* Check overlays first. */
1575 help = Qnil;
1576 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1578 overlay = overlay_vec[i];
1579 help = Foverlay_get (overlay, Qhelp_echo);
1582 if (!NILP (help))
1584 help_echo_string = help;
1585 help_echo_window = window;
1586 help_echo_object = overlay;
1587 help_echo_pos = pos;
1589 /* Try text properties. */
1590 else if (NILP (help)
1591 && ((STRINGP (glyph->object)
1592 && glyph->charpos >= 0
1593 && glyph->charpos < SCHARS (glyph->object))
1594 || (BUFFERP (glyph->object)
1595 && glyph->charpos >= BEGV
1596 && glyph->charpos < ZV)))
1598 help = Fget_text_property (make_number (glyph->charpos),
1599 Qhelp_echo, glyph->object);
1600 if (!NILP (help))
1602 help_echo_string = help;
1603 help_echo_window = window;
1604 help_echo_object = glyph->object;
1605 help_echo_pos = glyph->charpos;
1610 BEGV = obegv;
1611 ZV = ozv;
1612 current_buffer = obuf;
1617 static void
1618 IT_clear_end_of_line (struct frame *f, int first_unused)
1620 char *spaces, *sp;
1621 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1622 extern int fatal_error_in_progress;
1623 struct tty_display_info *tty = FRAME_TTY (f);
1625 if (new_pos_X >= first_unused || fatal_error_in_progress)
1626 return;
1628 IT_set_face (0);
1629 i = (j = first_unused - new_pos_X) * 2;
1630 if (tty->termscript)
1631 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1632 spaces = sp = alloca (i);
1634 while (--j >= 0)
1636 *sp++ = ' ';
1637 *sp++ = ScreenAttrib;
1640 mouse_off_maybe ();
1641 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1642 if (screen_virtual_segment)
1643 dosv_refresh_virtual_screen (offset, i / 2);
1645 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1646 Let's follow their lead, in case someone relies on this. */
1647 new_pos_X = first_unused;
1650 static void
1651 IT_clear_screen (struct frame *f)
1653 struct tty_display_info *tty = FRAME_TTY (f);
1655 if (tty->termscript)
1656 fprintf (tty->termscript, "<CLR:SCR>");
1657 /* We are sometimes called (from clear_garbaged_frames) when a new
1658 frame is being created, but its faces are not yet realized. In
1659 such a case we cannot call IT_set_face, since it will fail to find
1660 any valid faces and will abort. Instead, use the initial screen
1661 colors; that should mimic what a Unix tty does, which simply clears
1662 the screen with whatever default colors are in use. */
1663 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1664 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1665 else
1666 IT_set_face (0);
1667 mouse_off ();
1668 ScreenClear ();
1669 if (screen_virtual_segment)
1670 dosv_refresh_virtual_screen (0, screen_size);
1671 new_pos_X = new_pos_Y = 0;
1674 static void
1675 IT_clear_to_end (struct frame *f)
1677 struct tty_display_info *tty = FRAME_TTY (f);
1679 if (tty->termscript)
1680 fprintf (tty->termscript, "<CLR:EOS>");
1682 while (new_pos_Y < screen_size_Y) {
1683 new_pos_X = 0;
1684 IT_clear_end_of_line (f, screen_size_X);
1685 new_pos_Y++;
1689 static void
1690 IT_cursor_to (struct frame *f, int y, int x)
1692 struct tty_display_info *tty = FRAME_TTY (f);
1694 if (tty->termscript)
1695 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1696 new_pos_X = x;
1697 new_pos_Y = y;
1700 static int cursor_cleared;
1702 static void
1703 IT_display_cursor (int on)
1705 struct tty_display_info *tty = CURTTY ();
1707 if (on && cursor_cleared)
1709 ScreenSetCursor (current_pos_Y, current_pos_X);
1710 cursor_cleared = 0;
1711 if (tty->termscript)
1712 fprintf (tty->termscript, "\nCURSOR ON");
1714 else if (!on && !cursor_cleared)
1716 ScreenSetCursor (-1, -1);
1717 cursor_cleared = 1;
1718 if (tty->termscript)
1719 fprintf (tty->termscript, "\nCURSOR OFF");
1723 /* Emacs calls cursor-movement functions a lot when it updates the
1724 display (probably a legacy of old terminals where you cannot
1725 update a screen line without first moving the cursor there).
1726 However, cursor movement is expensive on MSDOS (it calls a slow
1727 BIOS function and requires 2 mode switches), while actual screen
1728 updates access the video memory directly and don't depend on
1729 cursor position. To avoid slowing down the redisplay, we cheat:
1730 all functions that move the cursor only set internal variables
1731 which record the cursor position, whereas the cursor is only
1732 moved to its final position whenever screen update is complete.
1734 `IT_cmgoto' is called from the keyboard reading loop and when the
1735 frame update is complete. This means that we are ready for user
1736 input, so we update the cursor position to show where the point is,
1737 and also make the mouse pointer visible.
1739 Special treatment is required when the cursor is in the echo area,
1740 to put the cursor at the end of the text displayed there. */
1742 static void
1743 IT_cmgoto (FRAME_PTR f)
1745 /* Only set the cursor to where it should be if the display is
1746 already in sync with the window contents. */
1747 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1748 struct tty_display_info *tty = FRAME_TTY (f);
1750 /* FIXME: This needs to be rewritten for the new redisplay, or
1751 removed. */
1752 #if 0
1753 static int previous_pos_X = -1;
1755 update_cursor_pos = 1; /* temporary!!! */
1757 /* If the display is in sync, forget any previous knowledge about
1758 cursor position. This is primarily for unexpected events like
1759 C-g in the minibuffer. */
1760 if (update_cursor_pos && previous_pos_X >= 0)
1761 previous_pos_X = -1;
1762 /* If we are in the echo area, put the cursor at the
1763 end of the echo area message. */
1764 if (!update_cursor_pos
1765 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1767 int tem_X = current_pos_X, dummy;
1769 if (echo_area_glyphs)
1771 tem_X = echo_area_glyphs_length;
1772 /* Save current cursor position, to be restored after the
1773 echo area message is erased. Only remember one level
1774 of previous cursor position. */
1775 if (previous_pos_X == -1)
1776 ScreenGetCursor (&dummy, &previous_pos_X);
1778 else if (previous_pos_X >= 0)
1780 /* We wind up here after the echo area message is erased.
1781 Restore the cursor position we remembered above. */
1782 tem_X = previous_pos_X;
1783 previous_pos_X = -1;
1786 if (current_pos_X != tem_X)
1788 new_pos_X = tem_X;
1789 update_cursor_pos = 1;
1792 #endif
1794 if (update_cursor_pos
1795 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1797 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1798 if (tty->termscript)
1799 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1802 /* Maybe cursor is invisible, so make it visible. */
1803 IT_display_cursor (1);
1805 /* Mouse pointer should be always visible if we are waiting for
1806 keyboard input. */
1807 if (!mouse_visible)
1808 mouse_on ();
1811 static void
1812 IT_update_begin (struct frame *f)
1814 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1815 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1817 if (display_info->termscript)
1818 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1820 BLOCK_INPUT;
1822 if (f && f == mouse_face_frame)
1824 /* Don't do highlighting for mouse motion during the update. */
1825 display_info->mouse_face_defer = 1;
1827 /* If F needs to be redrawn, simply forget about any prior mouse
1828 highlighting. */
1829 if (FRAME_GARBAGED_P (f))
1830 display_info->mouse_face_window = Qnil;
1832 /* Can we tell that this update does not affect the window
1833 where the mouse highlight is? If so, no need to turn off.
1834 Likewise, don't do anything if none of the enabled rows
1835 contains glyphs highlighted in mouse face. */
1836 if (!NILP (display_info->mouse_face_window)
1837 && WINDOWP (display_info->mouse_face_window))
1839 struct window *w = XWINDOW (display_info->mouse_face_window);
1840 int i;
1842 /* If the mouse highlight is in the window that was deleted
1843 (e.g., if it was popped by completion), clear highlight
1844 unconditionally. */
1845 if (NILP (w->buffer))
1846 display_info->mouse_face_window = Qnil;
1847 else
1849 for (i = 0; i < w->desired_matrix->nrows; ++i)
1850 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1851 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1852 break;
1855 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1856 clear_mouse_face (display_info);
1859 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1861 /* If the frame with mouse highlight was deleted, invalidate the
1862 highlight info. */
1863 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1864 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1865 display_info->mouse_face_window = Qnil;
1866 display_info->mouse_face_deferred_gc = 0;
1867 display_info->mouse_face_mouse_frame = NULL;
1870 UNBLOCK_INPUT;
1873 static void
1874 IT_update_end (struct frame *f)
1876 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1878 if (dpyinfo->termscript)
1879 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1880 dpyinfo->mouse_face_defer = 0;
1883 static void
1884 IT_frame_up_to_date (struct frame *f)
1886 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1887 Lisp_Object new_cursor, frame_desired_cursor;
1888 struct window *sw;
1890 if (dpyinfo->mouse_face_deferred_gc
1891 || (f && f == dpyinfo->mouse_face_mouse_frame))
1893 BLOCK_INPUT;
1894 if (dpyinfo->mouse_face_mouse_frame)
1895 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1896 dpyinfo->mouse_face_mouse_x,
1897 dpyinfo->mouse_face_mouse_y);
1898 dpyinfo->mouse_face_deferred_gc = 0;
1899 UNBLOCK_INPUT;
1902 /* Set the cursor type to whatever they wanted. In a minibuffer
1903 window, we want the cursor to appear only if we are reading input
1904 from this window, and we want the cursor to be taken from the
1905 frame parameters. For the selected window, we use either its
1906 buffer-local value or the value from the frame parameters if the
1907 buffer doesn't define its local value for the cursor type. */
1908 sw = XWINDOW (f->selected_window);
1909 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1910 if (cursor_in_echo_area
1911 && FRAME_HAS_MINIBUF_P (f)
1912 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1913 && sw == XWINDOW (echo_area_window))
1914 new_cursor = frame_desired_cursor;
1915 else
1917 struct buffer *b = XBUFFER (sw->buffer);
1919 if (EQ (b->cursor_type, Qt))
1920 new_cursor = frame_desired_cursor;
1921 else if (NILP (b->cursor_type)) /* nil means no cursor */
1922 new_cursor = Fcons (Qbar, make_number (0));
1923 else
1924 new_cursor = b->cursor_type;
1927 IT_set_cursor_type (f, new_cursor);
1929 IT_cmgoto (f); /* position cursor when update is done */
1932 /* Copy LEN glyphs displayed on a single line whose vertical position
1933 is YPOS, beginning at horizontal position XFROM to horizontal
1934 position XTO, by moving blocks in the video memory. Used by
1935 functions that insert and delete glyphs. */
1936 static void
1937 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1939 /* The offsets of source and destination relative to the
1940 conventional memorty selector. */
1941 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1942 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1944 if (from == to || len <= 0)
1945 return;
1947 _farsetsel (_dos_ds);
1949 /* The source and destination might overlap, so we need to move
1950 glyphs non-destructively. */
1951 if (from > to)
1953 for ( ; len; from += 2, to += 2, len--)
1954 _farnspokew (to, _farnspeekw (from));
1956 else
1958 from += (len - 1) * 2;
1959 to += (len - 1) * 2;
1960 for ( ; len; from -= 2, to -= 2, len--)
1961 _farnspokew (to, _farnspeekw (from));
1963 if (screen_virtual_segment)
1964 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1967 /* Insert and delete glyphs. */
1968 static void
1969 IT_insert_glyphs (f, start, len)
1970 struct frame *f;
1971 register struct glyph *start;
1972 register int len;
1974 int shift_by_width = screen_size_X - (new_pos_X + len);
1976 /* Shift right the glyphs from the nominal cursor position to the
1977 end of this line. */
1978 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1980 /* Now write the glyphs to be inserted. */
1981 IT_write_glyphs (f, start, len);
1984 static void
1985 IT_delete_glyphs (f, n)
1986 struct frame *f;
1987 register int n;
1989 abort ();
1992 /* set-window-configuration on window.c needs this. */
1993 void
1994 x_set_menu_bar_lines (f, value, oldval)
1995 struct frame *f;
1996 Lisp_Object value, oldval;
1998 set_menu_bar_lines (f, value, oldval);
2001 /* This was copied from xfaces.c */
2003 extern Lisp_Object Qbackground_color;
2004 extern Lisp_Object Qforeground_color;
2005 Lisp_Object Qreverse;
2006 extern Lisp_Object Qtitle;
2008 /* IT_set_terminal_modes is called when emacs is started,
2009 resumed, and whenever the screen is redrawn! */
2011 static void
2012 IT_set_terminal_modes (struct terminal *term)
2014 struct tty_display_info *tty;
2016 /* If called with initial terminal, it's too early to do anything
2017 useful. */
2018 if (term->type == output_initial)
2019 return;
2021 tty = term->display_info.tty;
2023 if (tty->termscript)
2024 fprintf (tty->termscript, "\n<SET_TERM>");
2026 screen_size_X = ScreenCols ();
2027 screen_size_Y = ScreenRows ();
2028 screen_size = screen_size_X * screen_size_Y;
2030 new_pos_X = new_pos_Y = 0;
2031 current_pos_X = current_pos_Y = -1;
2033 if (term_setup_done)
2034 return;
2035 term_setup_done = 1;
2037 startup_screen_size_X = screen_size_X;
2038 startup_screen_size_Y = screen_size_Y;
2039 startup_screen_attrib = ScreenAttrib;
2041 #if __DJGPP__ > 1
2042 /* Is DOS/V (or any other RSIS software which relocates
2043 the screen) installed? */
2045 unsigned short es_value;
2046 __dpmi_regs regs;
2048 regs.h.ah = 0xfe; /* get relocated screen address */
2049 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2050 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2051 else if (screen_old_address) /* already switched to Japanese mode once */
2052 regs.x.es = (screen_old_address >> 4) & 0xffff;
2053 else
2054 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2055 regs.x.di = 0;
2056 es_value = regs.x.es;
2057 __dpmi_int (0x10, &regs);
2059 if (regs.x.es != es_value)
2061 /* screen_old_address is only set if ScreenPrimary does NOT
2062 already point to the relocated buffer address returned by
2063 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2064 ScreenPrimary to that address at startup under DOS/V. */
2065 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2066 screen_old_address = ScreenPrimary;
2067 screen_virtual_segment = regs.x.es;
2068 screen_virtual_offset = regs.x.di;
2069 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2072 #endif /* __DJGPP__ > 1 */
2074 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2075 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2077 bright_bg ();
2080 /* IT_reset_terminal_modes is called when emacs is
2081 suspended or killed. */
2083 static void
2084 IT_reset_terminal_modes (struct terminal *term)
2086 int display_row_start = (int) ScreenPrimary;
2087 int saved_row_len = startup_screen_size_X * 2;
2088 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
2089 int to_next_row = update_row_len;
2090 unsigned char *saved_row = startup_screen_buffer;
2091 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
2092 struct tty_display_info *tty = term->display_info.tty;
2094 if (tty->termscript)
2095 fprintf (tty->termscript, "\n<RESET_TERM>");
2097 if (!term_setup_done)
2098 return;
2100 mouse_off ();
2102 /* Leave the video system in the same state as we found it,
2103 as far as the blink/bright-background bit is concerned. */
2104 maybe_enable_blinking ();
2106 /* We have a situation here.
2107 We cannot just do ScreenUpdate(startup_screen_buffer) because
2108 the luser could have changed screen dimensions inside Emacs
2109 and failed (or didn't want) to restore them before killing
2110 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2111 thus will happily use memory outside what was allocated for
2112 `startup_screen_buffer'.
2113 Thus we only restore as much as the current screen dimensions
2114 can hold, and clear the rest (if the saved screen is smaller than
2115 the current) with the color attribute saved at startup. The cursor
2116 is also restored within the visible dimensions. */
2118 ScreenAttrib = startup_screen_attrib;
2120 /* Don't restore the screen if we are exiting less than 2 seconds
2121 after startup: we might be crashing, and the screen might show
2122 some vital clues to what's wrong. */
2123 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2125 ScreenClear ();
2126 if (screen_virtual_segment)
2127 dosv_refresh_virtual_screen (0, screen_size);
2129 if (update_row_len > saved_row_len)
2130 update_row_len = saved_row_len;
2131 if (current_rows > startup_screen_size_Y)
2132 current_rows = startup_screen_size_Y;
2134 if (tty->termscript)
2135 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2136 update_row_len / 2, current_rows);
2138 while (current_rows--)
2140 dosmemput (saved_row, update_row_len, display_row_start);
2141 if (screen_virtual_segment)
2142 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2143 update_row_len / 2);
2144 saved_row += saved_row_len;
2145 display_row_start += to_next_row;
2148 if (startup_pos_X < cursor_pos_X)
2149 cursor_pos_X = startup_pos_X;
2150 if (startup_pos_Y < cursor_pos_Y)
2151 cursor_pos_Y = startup_pos_Y;
2153 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2154 xfree (startup_screen_buffer);
2155 startup_screen_buffer = NULL;
2157 term_setup_done = 0;
2160 static void
2161 IT_set_terminal_window (struct frame *f, int foo)
2165 /* Remember the screen colors of the curent frame, to serve as the
2166 default colors for newly-created frames. */
2167 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2168 Smsdos_remember_default_colors, 1, 1, 0,
2169 doc: /* Remember the screen colors of the current frame. */)
2170 (frame)
2171 Lisp_Object frame;
2173 struct frame *f;
2175 CHECK_FRAME (frame);
2176 f = XFRAME (frame);
2178 /* This function is called after applying default-frame-alist to the
2179 initial frame. At that time, if reverse-colors option was
2180 specified in default-frame-alist, it was already applied, and
2181 frame colors are reversed. */
2182 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2183 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2186 void
2187 IT_set_frame_parameters (f, alist)
2188 struct frame *f;
2189 Lisp_Object alist;
2191 Lisp_Object tail;
2192 int i, j, length = XINT (Flength (alist));
2193 Lisp_Object *parms
2194 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2195 Lisp_Object *values
2196 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2197 /* Do we have to reverse the foreground and background colors? */
2198 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2199 int need_to_reverse, was_reverse = reverse;
2200 int redraw = 0, fg_set = 0, bg_set = 0;
2201 unsigned long orig_fg, orig_bg;
2202 Lisp_Object frame_bg, frame_fg;
2203 extern Lisp_Object Qdefault, QCforeground, QCbackground;
2204 struct tty_display_info *tty = FRAME_TTY (f);
2206 /* If we are creating a new frame, begin with the original screen colors
2207 used for the initial frame. */
2208 if (EQ (alist, Vdefault_frame_alist)
2209 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2211 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2212 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2213 init_frame_faces (f);
2215 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2216 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2217 frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2218 frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2219 /* frame_fg and frame_bg could be nil if, for example,
2220 f->param_alist is nil, e.g. if we are called from
2221 Fmake_terminal_frame. */
2222 if (NILP (frame_fg))
2223 frame_fg = build_string (unspecified_fg);
2224 if (NILP (frame_bg))
2225 frame_bg = build_string (unspecified_bg);
2227 /* Extract parm names and values into those vectors. */
2228 i = 0;
2229 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2231 Lisp_Object elt;
2233 elt = Fcar (tail);
2234 parms[i] = Fcar (elt);
2235 CHECK_SYMBOL (parms[i]);
2236 values[i] = Fcdr (elt);
2237 i++;
2240 j = i;
2242 for (i = 0; i < j; i++)
2244 Lisp_Object prop, val;
2246 prop = parms[i];
2247 val = values[i];
2249 if (EQ (prop, Qreverse))
2250 reverse = EQ (val, Qt);
2253 need_to_reverse = reverse && !was_reverse;
2254 if (tty->termscript && need_to_reverse)
2255 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2257 /* Now process the alist elements in reverse of specified order. */
2258 for (i--; i >= 0; i--)
2260 Lisp_Object prop, val, frame;
2262 prop = parms[i];
2263 val = values[i];
2265 if (EQ (prop, Qforeground_color))
2267 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2268 ? LFACE_BACKGROUND_INDEX
2269 : LFACE_FOREGROUND_INDEX);
2270 if (new_color != FACE_TTY_DEFAULT_COLOR
2271 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2272 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2274 FRAME_FOREGROUND_PIXEL (f) = new_color;
2275 /* Make sure the foreground of the default face for this
2276 frame is changed as well. */
2277 XSETFRAME (frame, f);
2278 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2279 val, frame);
2280 fg_set = 1;
2281 redraw = 1;
2282 if (tty->termscript)
2283 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2286 else if (EQ (prop, Qbackground_color))
2288 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2289 ? LFACE_FOREGROUND_INDEX
2290 : LFACE_BACKGROUND_INDEX);
2291 if (new_color != FACE_TTY_DEFAULT_COLOR
2292 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2293 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2295 FRAME_BACKGROUND_PIXEL (f) = new_color;
2296 /* Make sure the background of the default face for this
2297 frame is changed as well. */
2298 XSETFRAME (frame, f);
2299 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2300 val, frame);
2301 bg_set = 1;
2302 redraw = 1;
2303 if (tty->termscript)
2304 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2307 else if (EQ (prop, Qtitle))
2309 x_set_title (f, val);
2310 if (tty->termscript)
2311 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2313 else if (EQ (prop, Qcursor_type))
2315 IT_set_cursor_type (f, val);
2316 if (tty->termscript)
2317 fprintf (tty->termscript, "<CTYPE: %s>\n",
2318 EQ (val, Qbar) || EQ (val, Qhbar)
2319 || CONSP (val) && (EQ (XCAR (val), Qbar)
2320 || EQ (XCAR (val), Qhbar))
2321 ? "bar" : "box");
2323 else if (EQ (prop, Qtty_type))
2325 internal_terminal_init ();
2326 if (tty->termscript)
2327 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2328 SBYTES (val), SDATA (val));
2330 store_frame_param (f, prop, val);
2333 /* If they specified "reverse", but not the colors, we need to swap
2334 the current frame colors. */
2335 if (need_to_reverse)
2337 Lisp_Object frame;
2339 if (!fg_set)
2341 XSETFRAME (frame, f);
2342 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2343 tty_color_name (f, orig_bg),
2344 frame);
2345 redraw = 1;
2347 if (!bg_set)
2349 XSETFRAME (frame, f);
2350 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2351 tty_color_name (f, orig_fg),
2352 frame);
2353 redraw = 1;
2357 if (redraw)
2359 face_change_count++; /* forces xdisp.c to recompute basic faces */
2360 if (f == SELECTED_FRAME())
2361 redraw_frame (f);
2365 extern void init_frame_faces (FRAME_PTR);
2367 #endif /* !HAVE_X_WINDOWS */
2370 /* Do we need the internal terminal? */
2372 void
2373 internal_terminal_init ()
2375 static int init_needed = 1;
2376 char *term = getenv ("TERM"), *colors;
2377 struct frame *sf = SELECTED_FRAME();
2378 struct tty_display_info *tty;
2380 #ifdef HAVE_X_WINDOWS
2381 if (!inhibit_window_system)
2382 return;
2383 #endif
2385 /* If this is the initial terminal, we are done here. */
2386 if (sf->output_method == output_initial)
2387 return;
2389 internal_terminal
2390 = (!noninteractive) && term && !strcmp (term, "internal");
2392 #ifndef HAVE_X_WINDOWS
2393 if (!internal_terminal || inhibit_window_system)
2395 sf->output_method = output_termcap;
2396 return;
2399 tty = FRAME_TTY (sf);
2400 current_kboard->Vwindow_system = Qpc;
2401 sf->output_method = output_msdos_raw;
2402 if (init_needed)
2404 if (!tty->termscript && getenv ("EMACSTEST"))
2405 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2406 if (tty->termscript)
2408 time_t now = time (NULL);
2409 struct tm *tnow = localtime (&now);
2410 char tbuf[100];
2412 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2413 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2414 fprintf (tty->termscript, "=====================\n\n");
2417 Vinitial_window_system = Qpc;
2418 Vwindow_system_version = make_number (23); /* RE Emacs version */
2419 tty->terminal->type = output_msdos_raw;
2421 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2422 address. */
2423 screen_old_address = 0;
2425 /* Forget the stale screen colors as well. */
2426 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2428 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2429 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2430 bright_bg ();
2431 colors = getenv ("EMACSCOLORS");
2432 if (colors && strlen (colors) >= 2)
2434 /* The colors use 4 bits each (we enable bright background). */
2435 if (isdigit (colors[0]))
2436 colors[0] -= '0';
2437 else if (isxdigit (colors[0]))
2438 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2439 if (colors[0] >= 0 && colors[0] < 16)
2440 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2441 if (isdigit (colors[1]))
2442 colors[1] -= '0';
2443 else if (isxdigit (colors[1]))
2444 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2445 if (colors[1] >= 0 && colors[1] < 16)
2446 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2448 the_only_display_info.mouse_face_mouse_frame = NULL;
2449 the_only_display_info.mouse_face_deferred_gc = 0;
2450 the_only_display_info.mouse_face_beg_row =
2451 the_only_display_info.mouse_face_beg_col = -1;
2452 the_only_display_info.mouse_face_end_row =
2453 the_only_display_info.mouse_face_end_col = -1;
2454 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2455 the_only_display_info.mouse_face_window = Qnil;
2456 the_only_display_info.mouse_face_mouse_x =
2457 the_only_display_info.mouse_face_mouse_y = 0;
2458 the_only_display_info.mouse_face_defer = 0;
2459 the_only_display_info.mouse_face_hidden = 0;
2461 if (have_mouse) /* detected in dos_ttraw, which see */
2463 have_mouse = 1; /* enable mouse */
2464 mouse_visible = 0;
2465 mouse_setup_buttons (mouse_button_count);
2466 tty->terminal->mouse_position_hook = &mouse_get_pos;
2467 mouse_init ();
2470 if (tty->termscript && screen_size)
2471 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2472 screen_size_X, screen_size_Y);
2474 init_frame_faces (sf);
2475 init_needed = 0;
2477 #endif
2480 void
2481 initialize_msdos_display (struct terminal *term)
2483 term->rif = 0; /* we don't support window-based display */
2484 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2485 term->clear_to_end_hook = IT_clear_to_end;
2486 term->clear_frame_hook = IT_clear_screen;
2487 term->clear_end_of_line_hook = IT_clear_end_of_line;
2488 term->ins_del_lines_hook = 0;
2489 term->insert_glyphs_hook = IT_insert_glyphs;
2490 term->write_glyphs_hook = IT_write_glyphs;
2491 term->delete_glyphs_hook = IT_delete_glyphs;
2492 term->ring_bell_hook = IT_ring_bell;
2493 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2494 term->set_terminal_modes_hook = IT_set_terminal_modes;
2495 term->set_terminal_window_hook = IT_set_terminal_window;
2496 term->update_begin_hook = IT_update_begin;
2497 term->update_end_hook = IT_update_end;
2498 term->frame_up_to_date_hook = IT_frame_up_to_date;
2499 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2500 term->frame_rehighlight_hook = 0;
2501 term->frame_raise_lower_hook = 0;
2502 term->set_vertical_scroll_bar_hook = 0;
2503 term->condemn_scroll_bars_hook = 0;
2504 term->redeem_scroll_bar_hook = 0;
2505 term->judge_scroll_bars_hook = 0;
2506 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2509 dos_get_saved_screen (screen, rows, cols)
2510 char **screen;
2511 int *rows;
2512 int *cols;
2514 #ifndef HAVE_X_WINDOWS
2515 *screen = startup_screen_buffer;
2516 *cols = startup_screen_size_X;
2517 *rows = startup_screen_size_Y;
2518 return *screen != (char *)0;
2519 #else
2520 return 0;
2521 #endif
2524 #ifndef HAVE_X_WINDOWS
2526 /* We are not X, but we can emulate it well enough for our needs... */
2527 void
2528 check_x (void)
2530 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2531 error ("Not running under a window system");
2534 #endif
2537 /* ----------------------- Keyboard control ----------------------
2539 * Keymaps reflect the following keyboard layout:
2541 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2542 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2543 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2544 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2545 * SPACE
2548 #define Ignore 0x0000
2549 #define Normal 0x0000 /* normal key - alt changes scan-code */
2550 #define FctKey 0x1000 /* func key if c == 0, else c */
2551 #define Special 0x2000 /* func key even if c != 0 */
2552 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2553 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2554 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2555 #define Grey 0x6000 /* Grey keypad key */
2557 #define Alt 0x0100 /* alt scan-code */
2558 #define Ctrl 0x0200 /* ctrl scan-code */
2559 #define Shift 0x0400 /* shift scan-code */
2561 static int extended_kbd; /* 101 (102) keyboard present. */
2563 struct kbd_translate {
2564 unsigned char sc;
2565 unsigned char ch;
2566 unsigned short code;
2569 struct dos_keyboard_map
2571 char *unshifted;
2572 char *shifted;
2573 char *alt_gr;
2574 struct kbd_translate *translate_table;
2578 static struct dos_keyboard_map us_keyboard = {
2579 /* 0 1 2 3 4 5 */
2580 /* 01234567890123456789012345678901234567890 12345678901234 */
2581 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2582 /* 0123456789012345678901234567890123456789 012345678901234 */
2583 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2584 0, /* no Alt-Gr key */
2585 0 /* no translate table */
2588 static struct dos_keyboard_map fr_keyboard = {
2589 /* 0 1 2 3 4 5 */
2590 /* 012 3456789012345678901234567890123456789012345678901234 */
2591 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2592 /* 0123456789012345678901234567890123456789012345678901234 */
2593 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2594 /* 01234567 89012345678901234567890123456789012345678901234 */
2595 " ~#{[|`\\^@]} Ï ",
2596 0 /* no translate table */
2600 * Italian keyboard support, country code 39.
2601 * '<' 56:3c*0000
2602 * '>' 56:3e*0000
2603 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2604 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2607 static struct kbd_translate it_kbd_translate_table[] = {
2608 { 0x56, 0x3c, Normal | 13 },
2609 { 0x56, 0x3e, Normal | 27 },
2610 { 0, 0, 0 }
2612 static struct dos_keyboard_map it_keyboard = {
2613 /* 0 1 2 3 4 5 */
2614 /* 0 123456789012345678901234567890123456789012345678901234 */
2615 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2616 /* 01 23456789012345678901234567890123456789012345678901234 */
2617 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2618 /* 0123456789012345678901234567890123456789012345678901234 */
2619 " {}~` [] @# ",
2620 it_kbd_translate_table
2623 static struct dos_keyboard_map dk_keyboard = {
2624 /* 0 1 2 3 4 5 */
2625 /* 0123456789012345678901234567890123456789012345678901234 */
2626 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2627 /* 01 23456789012345678901234567890123456789012345678901234 */
2628 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2629 /* 0123456789012345678901234567890123456789012345678901234 */
2630 " @œ$ {[]} | ",
2631 0 /* no translate table */
2634 static struct kbd_translate jp_kbd_translate_table[] = {
2635 { 0x73, 0x5c, Normal | 0 },
2636 { 0x73, 0x5f, Normal | 0 },
2637 { 0x73, 0x1c, Map | 0 },
2638 { 0x7d, 0x5c, Normal | 13 },
2639 { 0x7d, 0x7c, Normal | 13 },
2640 { 0x7d, 0x1c, Map | 13 },
2641 { 0, 0, 0 }
2643 static struct dos_keyboard_map jp_keyboard = {
2644 /* 0 1 2 3 4 5 */
2645 /* 0123456789012 345678901234567890123456789012345678901234 */
2646 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2647 /* 01 23456789012345678901234567890123456789012345678901234 */
2648 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2649 0, /* no Alt-Gr key */
2650 jp_kbd_translate_table
2653 static struct keyboard_layout_list
2655 int country_code;
2656 struct dos_keyboard_map *keyboard_map;
2657 } keyboard_layout_list[] =
2659 1, &us_keyboard,
2660 33, &fr_keyboard,
2661 39, &it_keyboard,
2662 45, &dk_keyboard,
2663 81, &jp_keyboard
2666 static struct dos_keyboard_map *keyboard;
2667 static int keyboard_map_all;
2668 static int international_keyboard;
2671 dos_set_keyboard (code, always)
2672 int code;
2673 int always;
2675 int i;
2676 _go32_dpmi_registers regs;
2678 /* See if Keyb.Com is installed (for international keyboard support).
2679 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2680 of Windows 9X! So don't do that! */
2681 regs.x.ax = 0xad80;
2682 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2683 _go32_dpmi_simulate_int (0x2f, &regs);
2684 if (regs.h.al == 0xff)
2685 international_keyboard = 1;
2687 /* Initialize to US settings, for countries that don't have their own. */
2688 keyboard = keyboard_layout_list[0].keyboard_map;
2689 keyboard_map_all = always;
2690 dos_keyboard_layout = 1;
2692 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2693 if (code == keyboard_layout_list[i].country_code)
2695 keyboard = keyboard_layout_list[i].keyboard_map;
2696 keyboard_map_all = always;
2697 dos_keyboard_layout = code;
2698 return 1;
2700 return 0;
2703 static struct
2705 unsigned char char_code; /* normal code */
2706 unsigned char meta_code; /* M- code */
2707 unsigned char keypad_code; /* keypad code */
2708 unsigned char editkey_code; /* edit key */
2709 } keypad_translate_map[] = {
2710 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2711 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2712 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2713 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2714 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2715 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2716 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2717 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2718 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2719 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2720 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2723 static struct
2725 unsigned char char_code; /* normal code */
2726 unsigned char keypad_code; /* keypad code */
2727 } grey_key_translate_map[] = {
2728 '/', 0xaf, /* kp-decimal */
2729 '*', 0xaa, /* kp-multiply */
2730 '-', 0xad, /* kp-subtract */
2731 '+', 0xab, /* kp-add */
2732 '\r', 0x8d /* kp-enter */
2735 static unsigned short
2736 ibmpc_translate_map[] =
2738 /* --------------- 00 to 0f --------------- */
2739 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2740 Alt | ModFct | 0x1b, /* Escape */
2741 Normal | 1, /* '1' */
2742 Normal | 2, /* '2' */
2743 Normal | 3, /* '3' */
2744 Normal | 4, /* '4' */
2745 Normal | 5, /* '5' */
2746 Normal | 6, /* '6' */
2747 Normal | 7, /* '7' */
2748 Normal | 8, /* '8' */
2749 Normal | 9, /* '9' */
2750 Normal | 10, /* '0' */
2751 Normal | 11, /* '-' */
2752 Normal | 12, /* '=' */
2753 Special | 0x08, /* Backspace */
2754 ModFct | 0x74, /* Tab/Backtab */
2756 /* --------------- 10 to 1f --------------- */
2757 Map | 15, /* 'q' */
2758 Map | 16, /* 'w' */
2759 Map | 17, /* 'e' */
2760 Map | 18, /* 'r' */
2761 Map | 19, /* 't' */
2762 Map | 20, /* 'y' */
2763 Map | 21, /* 'u' */
2764 Map | 22, /* 'i' */
2765 Map | 23, /* 'o' */
2766 Map | 24, /* 'p' */
2767 Map | 25, /* '[' */
2768 Map | 26, /* ']' */
2769 ModFct | 0x0d, /* Return */
2770 Ignore, /* Ctrl */
2771 Map | 30, /* 'a' */
2772 Map | 31, /* 's' */
2774 /* --------------- 20 to 2f --------------- */
2775 Map | 32, /* 'd' */
2776 Map | 33, /* 'f' */
2777 Map | 34, /* 'g' */
2778 Map | 35, /* 'h' */
2779 Map | 36, /* 'j' */
2780 Map | 37, /* 'k' */
2781 Map | 38, /* 'l' */
2782 Map | 39, /* ';' */
2783 Map | 40, /* '\'' */
2784 Map | 0, /* '`' */
2785 Ignore, /* Left shift */
2786 Map | 41, /* '\\' */
2787 Map | 45, /* 'z' */
2788 Map | 46, /* 'x' */
2789 Map | 47, /* 'c' */
2790 Map | 48, /* 'v' */
2792 /* --------------- 30 to 3f --------------- */
2793 Map | 49, /* 'b' */
2794 Map | 50, /* 'n' */
2795 Map | 51, /* 'm' */
2796 Map | 52, /* ',' */
2797 Map | 53, /* '.' */
2798 Map | 54, /* '/' */
2799 Ignore, /* Right shift */
2800 Grey | 1, /* Grey * */
2801 Ignore, /* Alt */
2802 Normal | 55, /* ' ' */
2803 Ignore, /* Caps Lock */
2804 FctKey | 0xbe, /* F1 */
2805 FctKey | 0xbf, /* F2 */
2806 FctKey | 0xc0, /* F3 */
2807 FctKey | 0xc1, /* F4 */
2808 FctKey | 0xc2, /* F5 */
2810 /* --------------- 40 to 4f --------------- */
2811 FctKey | 0xc3, /* F6 */
2812 FctKey | 0xc4, /* F7 */
2813 FctKey | 0xc5, /* F8 */
2814 FctKey | 0xc6, /* F9 */
2815 FctKey | 0xc7, /* F10 */
2816 Ignore, /* Num Lock */
2817 Ignore, /* Scroll Lock */
2818 KeyPad | 7, /* Home */
2819 KeyPad | 8, /* Up */
2820 KeyPad | 9, /* Page Up */
2821 Grey | 2, /* Grey - */
2822 KeyPad | 4, /* Left */
2823 KeyPad | 5, /* Keypad 5 */
2824 KeyPad | 6, /* Right */
2825 Grey | 3, /* Grey + */
2826 KeyPad | 1, /* End */
2828 /* --------------- 50 to 5f --------------- */
2829 KeyPad | 2, /* Down */
2830 KeyPad | 3, /* Page Down */
2831 KeyPad | 0, /* Insert */
2832 KeyPad | 10, /* Delete */
2833 Shift | FctKey | 0xbe, /* (Shift) F1 */
2834 Shift | FctKey | 0xbf, /* (Shift) F2 */
2835 Shift | FctKey | 0xc0, /* (Shift) F3 */
2836 Shift | FctKey | 0xc1, /* (Shift) F4 */
2837 Shift | FctKey | 0xc2, /* (Shift) F5 */
2838 Shift | FctKey | 0xc3, /* (Shift) F6 */
2839 Shift | FctKey | 0xc4, /* (Shift) F7 */
2840 Shift | FctKey | 0xc5, /* (Shift) F8 */
2841 Shift | FctKey | 0xc6, /* (Shift) F9 */
2842 Shift | FctKey | 0xc7, /* (Shift) F10 */
2843 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2844 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2846 /* --------------- 60 to 6f --------------- */
2847 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2848 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2849 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2850 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2851 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2852 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2853 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2854 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2855 Alt | FctKey | 0xbe, /* (Alt) F1 */
2856 Alt | FctKey | 0xbf, /* (Alt) F2 */
2857 Alt | FctKey | 0xc0, /* (Alt) F3 */
2858 Alt | FctKey | 0xc1, /* (Alt) F4 */
2859 Alt | FctKey | 0xc2, /* (Alt) F5 */
2860 Alt | FctKey | 0xc3, /* (Alt) F6 */
2861 Alt | FctKey | 0xc4, /* (Alt) F7 */
2862 Alt | FctKey | 0xc5, /* (Alt) F8 */
2864 /* --------------- 70 to 7f --------------- */
2865 Alt | FctKey | 0xc6, /* (Alt) F9 */
2866 Alt | FctKey | 0xc7, /* (Alt) F10 */
2867 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2868 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2869 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2870 Ctrl | KeyPad | 1, /* (Ctrl) End */
2871 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2872 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2873 Alt | Map | 1, /* '1' */
2874 Alt | Map | 2, /* '2' */
2875 Alt | Map | 3, /* '3' */
2876 Alt | Map | 4, /* '4' */
2877 Alt | Map | 5, /* '5' */
2878 Alt | Map | 6, /* '6' */
2879 Alt | Map | 7, /* '7' */
2880 Alt | Map | 8, /* '8' */
2882 /* --------------- 80 to 8f --------------- */
2883 Alt | Map | 9, /* '9' */
2884 Alt | Map | 10, /* '0' */
2885 Alt | Map | 11, /* '-' */
2886 Alt | Map | 12, /* '=' */
2887 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2888 FctKey | 0xc8, /* F11 */
2889 FctKey | 0xc9, /* F12 */
2890 Shift | FctKey | 0xc8, /* (Shift) F11 */
2891 Shift | FctKey | 0xc9, /* (Shift) F12 */
2892 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2893 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2894 Alt | FctKey | 0xc8, /* (Alt) F11 */
2895 Alt | FctKey | 0xc9, /* (Alt) F12 */
2896 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2897 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2898 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2900 /* --------------- 90 to 9f --------------- */
2901 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2902 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2903 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2904 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2905 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2906 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2907 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2908 Alt | FctKey | 0x50, /* (Alt) Home */
2909 Alt | FctKey | 0x52, /* (Alt) Up */
2910 Alt | FctKey | 0x55, /* (Alt) Page Up */
2911 Ignore, /* NO KEY */
2912 Alt | FctKey | 0x51, /* (Alt) Left */
2913 Ignore, /* NO KEY */
2914 Alt | FctKey | 0x53, /* (Alt) Right */
2915 Ignore, /* NO KEY */
2916 Alt | FctKey | 0x57, /* (Alt) End */
2918 /* --------------- a0 to af --------------- */
2919 Alt | KeyPad | 2, /* (Alt) Down */
2920 Alt | KeyPad | 3, /* (Alt) Page Down */
2921 Alt | KeyPad | 0, /* (Alt) Insert */
2922 Alt | KeyPad | 10, /* (Alt) Delete */
2923 Alt | Grey | 0, /* (Alt) Grey / */
2924 Alt | FctKey | 0x09, /* (Alt) Tab */
2925 Alt | Grey | 4 /* (Alt) Keypad Enter */
2928 /* These bit-positions corresponds to values returned by BIOS */
2929 #define SHIFT_P 0x0003 /* two bits! */
2930 #define CTRL_P 0x0004
2931 #define ALT_P 0x0008
2932 #define SCRLOCK_P 0x0010
2933 #define NUMLOCK_P 0x0020
2934 #define CAPSLOCK_P 0x0040
2935 #define ALT_GR_P 0x0800
2936 #define SUPER_P 0x4000 /* pseudo */
2937 #define HYPER_P 0x8000 /* pseudo */
2939 static int
2940 dos_get_modifiers (keymask)
2941 int *keymask;
2943 union REGS regs;
2944 int mask, modifiers = 0;
2946 /* Calculate modifier bits */
2947 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2948 int86 (0x16, &regs, &regs);
2950 if (!extended_kbd)
2952 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2953 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2955 else
2957 mask = regs.h.al & (SHIFT_P |
2958 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2960 /* Do not break international keyboard support. */
2961 /* When Keyb.Com is loaded, the right Alt key is */
2962 /* used for accessing characters like { and } */
2963 if (regs.h.ah & 2) /* Left ALT pressed ? */
2964 mask |= ALT_P;
2966 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2968 mask |= ALT_GR_P;
2969 if (dos_hyper_key == 1)
2971 mask |= HYPER_P;
2972 modifiers |= hyper_modifier;
2974 else if (dos_super_key == 1)
2976 mask |= SUPER_P;
2977 modifiers |= super_modifier;
2979 else if (!international_keyboard)
2981 /* If Keyb.Com is NOT installed, let Right Alt behave
2982 like the Left Alt. */
2983 mask &= ~ALT_GR_P;
2984 mask |= ALT_P;
2988 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2989 mask |= CTRL_P;
2991 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2993 if (dos_hyper_key == 2)
2995 mask |= HYPER_P;
2996 modifiers |= hyper_modifier;
2998 else if (dos_super_key == 2)
3000 mask |= SUPER_P;
3001 modifiers |= super_modifier;
3003 else
3004 mask |= CTRL_P;
3008 if (mask & SHIFT_P)
3009 modifiers |= shift_modifier;
3010 if (mask & CTRL_P)
3011 modifiers |= ctrl_modifier;
3012 if (mask & ALT_P)
3013 modifiers |= meta_modifier;
3015 if (keymask)
3016 *keymask = mask;
3017 return modifiers;
3020 #define NUM_RECENT_DOSKEYS (100)
3021 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
3022 int total_doskeys; /* Total number of elements stored into recent_doskeys */
3023 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
3025 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
3026 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3027 Each input key receives two values in this vector: first the ASCII code,
3028 and then the scan code. */)
3031 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
3033 if (total_doskeys < NUM_RECENT_DOSKEYS)
3034 return Fvector (total_doskeys, keys);
3035 else
3037 val = Fvector (NUM_RECENT_DOSKEYS, keys);
3038 bcopy (keys + recent_doskeys_index,
3039 XVECTOR (val)->contents,
3040 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
3041 bcopy (keys,
3042 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
3043 recent_doskeys_index * sizeof (Lisp_Object));
3044 return val;
3048 /* Get a char from keyboard. Function keys are put into the event queue. */
3049 static int
3050 dos_rawgetc ()
3052 struct input_event event;
3053 union REGS regs;
3054 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3055 EVENT_INIT (event);
3057 #ifndef HAVE_X_WINDOWS
3058 /* Maybe put the cursor where it should be. */
3059 IT_cmgoto (SELECTED_FRAME());
3060 #endif
3062 /* The following condition is equivalent to `kbhit ()', except that
3063 it uses the bios to do its job. This pleases DESQview/X. */
3064 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
3065 int86 (0x16, &regs, &regs),
3066 (regs.x.flags & 0x40) == 0)
3068 union REGS regs;
3069 register unsigned char c;
3070 int modifiers, sc, code = -1, mask, kp_mode;
3072 regs.h.ah = extended_kbd ? 0x10 : 0x00;
3073 int86 (0x16, &regs, &regs);
3074 c = regs.h.al;
3075 sc = regs.h.ah;
3077 total_doskeys += 2;
3078 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3079 = make_number (c);
3080 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3081 recent_doskeys_index = 0;
3082 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3083 = make_number (sc);
3084 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3085 recent_doskeys_index = 0;
3087 modifiers = dos_get_modifiers (&mask);
3089 #ifndef HAVE_X_WINDOWS
3090 if (!NILP (Vdos_display_scancodes))
3092 char buf[11];
3093 sprintf (buf, "%02x:%02x*%04x",
3094 (unsigned) (sc&0xff), (unsigned) c, mask);
3095 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
3097 #endif
3099 if (sc == 0xe0)
3101 switch (c)
3103 case 10: /* Ctrl Grey Enter */
3104 code = Ctrl | Grey | 4;
3105 break;
3106 case 13: /* Grey Enter */
3107 code = Grey | 4;
3108 break;
3109 case '/': /* Grey / */
3110 code = Grey | 0;
3111 break;
3112 default:
3113 continue;
3115 c = 0;
3117 else
3119 /* Try the keyboard-private translation table first. */
3120 if (keyboard->translate_table)
3122 struct kbd_translate *p = keyboard->translate_table;
3124 while (p->sc)
3126 if (p->sc == sc && p->ch == c)
3128 code = p->code;
3129 break;
3131 p++;
3134 /* If the private table didn't translate it, use the general
3135 one. */
3136 if (code == -1)
3138 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3139 continue;
3140 if ((code = ibmpc_translate_map[sc]) == Ignore)
3141 continue;
3145 if (c == 0)
3147 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3148 Emacs is ready to read a key. Therefore, if they press
3149 `Alt-x' when Emacs is busy, by the time we get to
3150 `dos_get_modifiers', they might have already released the
3151 Alt key, and Emacs gets just `x', which is BAD.
3152 However, for keys with the `Map' property set, the ASCII
3153 code returns zero only if Alt is pressed. So, when we DON'T
3154 have to support international_keyboard, we don't have to
3155 distinguish between the left and right Alt keys, and we
3156 can set the META modifier for any keys with the `Map'
3157 property if they return zero ASCII code (c = 0). */
3158 if ( (code & Alt)
3159 || ( (code & 0xf000) == Map && !international_keyboard))
3160 modifiers |= meta_modifier;
3161 if (code & Ctrl)
3162 modifiers |= ctrl_modifier;
3163 if (code & Shift)
3164 modifiers |= shift_modifier;
3167 switch (code & 0xf000)
3169 case ModFct:
3170 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3171 return c;
3172 c = 0; /* Special */
3174 case FctKey:
3175 if (c != 0)
3176 return c;
3178 case Special:
3179 code |= 0xff00;
3180 break;
3182 case Normal:
3183 if (sc == 0)
3185 if (c == 0) /* ctrl-break */
3186 continue;
3187 return c; /* ALT-nnn */
3189 if (!keyboard_map_all)
3191 if (c != ' ')
3192 return c;
3193 code = c;
3194 break;
3197 case Map:
3198 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3199 if (!keyboard_map_all)
3200 return c;
3202 code &= 0xff;
3203 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3204 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3206 if (mask & SHIFT_P)
3208 code = keyboard->shifted[code];
3209 mask -= SHIFT_P;
3210 modifiers &= ~shift_modifier;
3212 else
3213 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3214 code = keyboard->alt_gr[code];
3215 else
3216 code = keyboard->unshifted[code];
3217 break;
3219 case KeyPad:
3220 code &= 0xff;
3221 if (c == 0xe0) /* edit key */
3222 kp_mode = 3;
3223 else
3224 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3225 kp_mode = dos_keypad_mode & 0x03;
3226 else
3227 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3229 switch (kp_mode)
3231 case 0:
3232 if (code == 10 && dos_decimal_point)
3233 return dos_decimal_point;
3234 return keypad_translate_map[code].char_code;
3236 case 1:
3237 code = 0xff00 | keypad_translate_map[code].keypad_code;
3238 break;
3240 case 2:
3241 code = keypad_translate_map[code].meta_code;
3242 modifiers = meta_modifier;
3243 break;
3245 case 3:
3246 code = 0xff00 | keypad_translate_map[code].editkey_code;
3247 break;
3249 break;
3251 case Grey:
3252 code &= 0xff;
3253 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3254 if (dos_keypad_mode & kp_mode)
3255 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3256 else
3257 code = grey_key_translate_map[code].char_code;
3258 break;
3261 make_event:
3262 if (code == 0)
3263 continue;
3265 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3267 clear_mouse_face (dpyinfo);
3268 dpyinfo->mouse_face_hidden = 1;
3271 if (code >= 0x100)
3272 event.kind = NON_ASCII_KEYSTROKE_EVENT;
3273 else
3274 event.kind = ASCII_KEYSTROKE_EVENT;
3275 event.code = code;
3276 event.modifiers = modifiers;
3277 event.frame_or_window = selected_frame;
3278 event.arg = Qnil;
3279 event.timestamp = event_timestamp ();
3280 kbd_buffer_store_event (&event);
3283 if (have_mouse > 0 && !mouse_preempted)
3285 int but, press, x, y, ok;
3286 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3287 Lisp_Object mouse_window = Qnil;
3289 /* Check for mouse movement *before* buttons. */
3290 mouse_check_moved ();
3292 /* If the mouse moved from the spot of its last sighting, we
3293 might need to update mouse highlight. */
3294 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3296 if (dpyinfo->mouse_face_hidden)
3298 dpyinfo->mouse_face_hidden = 0;
3299 clear_mouse_face (dpyinfo);
3302 /* Generate SELECT_WINDOW_EVENTs when needed. */
3303 if (!NILP (Vmouse_autoselect_window))
3305 mouse_window = window_from_coordinates (SELECTED_FRAME(),
3306 mouse_last_x,
3307 mouse_last_y,
3308 0, 0, 0, 0);
3309 /* A window will be selected only when it is not
3310 selected now, and the last mouse movement event was
3311 not in it. A minibuffer window will be selected iff
3312 it is active. */
3313 if (WINDOWP (mouse_window)
3314 && !EQ (mouse_window, last_mouse_window)
3315 && !EQ (mouse_window, selected_window))
3317 event.kind = SELECT_WINDOW_EVENT;
3318 event.frame_or_window = mouse_window;
3319 event.arg = Qnil;
3320 event.timestamp = event_timestamp ();
3321 kbd_buffer_store_event (&event);
3323 last_mouse_window = mouse_window;
3325 else
3326 last_mouse_window = Qnil;
3328 previous_help_echo_string = help_echo_string;
3329 help_echo_string = help_echo_object = help_echo_window = Qnil;
3330 help_echo_pos = -1;
3331 IT_note_mouse_highlight (SELECTED_FRAME(),
3332 mouse_last_x, mouse_last_y);
3333 /* If the contents of the global variable help_echo has
3334 changed, generate a HELP_EVENT. */
3335 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3337 event.kind = HELP_EVENT;
3338 event.frame_or_window = selected_frame;
3339 event.arg = help_echo_object;
3340 event.x = WINDOWP (help_echo_window)
3341 ? help_echo_window : selected_frame;
3342 event.y = help_echo_string;
3343 event.timestamp = event_timestamp ();
3344 event.code = help_echo_pos;
3345 kbd_buffer_store_event (&event);
3349 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3350 for (press = 0; press < 2; press++)
3352 int button_num = but;
3354 if (press)
3355 ok = mouse_pressed (but, &x, &y);
3356 else
3357 ok = mouse_released (but, &x, &y);
3358 if (ok)
3360 /* Allow a simultaneous press/release of Mouse-1 and
3361 Mouse-2 to simulate Mouse-3 on two-button mice. */
3362 if (mouse_button_count == 2 && but < 2)
3364 int x2, y2; /* don't clobber original coordinates */
3366 /* If only one button is pressed, wait 100 msec and
3367 check again. This way, Speedy Gonzales isn't
3368 punished, while the slow get their chance. */
3369 if (press && mouse_pressed (1-but, &x2, &y2)
3370 || !press && mouse_released (1-but, &x2, &y2))
3371 button_num = 2;
3372 else
3374 delay (100);
3375 if (press && mouse_pressed (1-but, &x2, &y2)
3376 || !press && mouse_released (1-but, &x2, &y2))
3377 button_num = 2;
3381 event.kind = MOUSE_CLICK_EVENT;
3382 event.code = button_num;
3383 event.modifiers = dos_get_modifiers (0)
3384 | (press ? down_modifier : up_modifier);
3385 event.x = make_number (x);
3386 event.y = make_number (y);
3387 event.frame_or_window = selected_frame;
3388 event.arg = Qnil;
3389 event.timestamp = event_timestamp ();
3390 kbd_buffer_store_event (&event);
3395 return -1;
3398 static int prev_get_char = -1;
3400 /* Return 1 if a key is ready to be read without suspending execution. */
3402 dos_keysns ()
3404 if (prev_get_char != -1)
3405 return 1;
3406 else
3407 return ((prev_get_char = dos_rawgetc ()) != -1);
3410 /* Read a key. Return -1 if no key is ready. */
3412 dos_keyread ()
3414 if (prev_get_char != -1)
3416 int c = prev_get_char;
3417 prev_get_char = -1;
3418 return c;
3420 else
3421 return dos_rawgetc ();
3424 #ifndef HAVE_X_WINDOWS
3426 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3427 for now.
3429 Actually, I don't know the meaning of all the parameters of the functions
3430 here -- I only know how they are called by xmenu.c. I could of course
3431 grab the nearest Xlib manual (down the hall, second-to-last door on the
3432 left), but I don't think it's worth the effort. */
3434 /* These hold text of the current and the previous menu help messages. */
3435 static char *menu_help_message, *prev_menu_help_message;
3436 /* Pane number and item number of the menu item which generated the
3437 last menu help message. */
3438 static int menu_help_paneno, menu_help_itemno;
3440 static XMenu *
3441 IT_menu_create ()
3443 XMenu *menu;
3445 menu = (XMenu *) xmalloc (sizeof (XMenu));
3446 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3447 return menu;
3450 /* Allocate some (more) memory for MENU ensuring that there is room for one
3451 for item. */
3453 static void
3454 IT_menu_make_room (XMenu *menu)
3456 if (menu->allocated == 0)
3458 int count = menu->allocated = 10;
3459 menu->text = (char **) xmalloc (count * sizeof (char *));
3460 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3461 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3462 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3464 else if (menu->allocated == menu->count)
3466 int count = menu->allocated = menu->allocated + 10;
3467 menu->text
3468 = (char **) xrealloc (menu->text, count * sizeof (char *));
3469 menu->submenu
3470 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3471 menu->panenumber
3472 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3473 menu->help_text
3474 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3478 /* Search the given menu structure for a given pane number. */
3480 static XMenu *
3481 IT_menu_search_pane (XMenu *menu, int pane)
3483 int i;
3484 XMenu *try;
3486 for (i = 0; i < menu->count; i++)
3487 if (menu->submenu[i])
3489 if (pane == menu->panenumber[i])
3490 return menu->submenu[i];
3491 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3492 return try;
3494 return (XMenu *) 0;
3497 /* Determine how much screen space a given menu needs. */
3499 static void
3500 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3502 int i, h2, w2, maxsubwidth, maxheight;
3504 maxsubwidth = 0;
3505 maxheight = menu->count;
3506 for (i = 0; i < menu->count; i++)
3508 if (menu->submenu[i])
3510 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3511 if (w2 > maxsubwidth) maxsubwidth = w2;
3512 if (i + h2 > maxheight) maxheight = i + h2;
3515 *width = menu->width + maxsubwidth;
3516 *height = maxheight;
3519 /* Display MENU at (X,Y) using FACES. */
3521 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3522 do \
3524 (GLYPH).type = CHAR_GLYPH; \
3525 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3526 (GLYPH).charpos = -1; \
3528 while (0)
3530 static void
3531 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3533 int i, j, face, width, mx, my, enabled, mousehere, row, col;
3534 struct glyph *text, *p;
3535 const unsigned char *q;
3536 struct frame *sf = SELECTED_FRAME();
3538 menu_help_message = NULL;
3540 width = menu->width;
3541 /* We multiply width by 2 to account for possible control characters.
3542 FIXME: cater to non-ASCII characters in menus. */
3543 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3544 ScreenGetCursor (&row, &col);
3545 mouse_get_xy (&mx, &my);
3546 IT_update_begin (sf);
3547 for (i = 0; i < menu->count; i++)
3549 int max_width = width + 2;
3551 IT_cursor_to (sf, y + i, x);
3552 enabled
3553 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3554 mousehere = (y + i == my && x <= mx && mx < x + max_width);
3555 face = faces[enabled + mousehere * 2];
3556 /* The following if clause means that we display the menu help
3557 strings even if the menu item is currently disabled. */
3558 if (disp_help && enabled + mousehere * 2 >= 2)
3560 menu_help_message = menu->help_text[i];
3561 menu_help_paneno = pn - 1;
3562 menu_help_itemno = i;
3564 p = text;
3565 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3566 p++;
3567 for (j = 0, q = menu->text[i]; *q; j++)
3569 unsigned c = STRING_CHAR_ADVANCE (q);
3571 if (c > 26)
3573 BUILD_CHAR_GLYPH (*p, c, face, 0);
3574 p++;
3576 else /* make '^x' */
3578 BUILD_CHAR_GLYPH (*p, '^', face, 0);
3579 p++;
3580 j++;
3581 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3582 p++;
3585 /* Don't let the menu text overflow into the next screen row. */
3586 if (x + max_width > screen_size_X)
3588 max_width = screen_size_X - x;
3589 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3591 for (; j < max_width - 2; j++, p++)
3592 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3594 /* 16 is the character code of a character that on DOS terminal
3595 produces a nice-looking right-pointing arrow glyph. */
3596 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3597 p++;
3598 IT_write_glyphs (sf, text, max_width);
3600 IT_update_end (sf);
3601 IT_cursor_to (sf, row, col);
3602 xfree (text);
3605 /* --------------------------- X Menu emulation ---------------------- */
3607 /* Report availability of menus. */
3610 have_menus_p () { return 1; }
3612 /* Create a brand new menu structure. */
3614 XMenu *
3615 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3617 return IT_menu_create ();
3620 /* Create a new pane and place it on the outer-most level. It is not
3621 clear that it should be placed out there, but I don't know what else
3622 to do. */
3625 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3627 int len;
3628 char *p;
3630 if (!enable)
3631 abort ();
3633 IT_menu_make_room (menu);
3634 menu->submenu[menu->count] = IT_menu_create ();
3635 menu->text[menu->count] = txt;
3636 menu->panenumber[menu->count] = ++menu->panecount;
3637 menu->help_text[menu->count] = NULL;
3638 menu->count++;
3640 /* Adjust length for possible control characters (which will
3641 be written as ^x). */
3642 for (len = strlen (txt), p = txt; *p; p++)
3643 if (*p < 27)
3644 len++;
3646 if (len > menu->width)
3647 menu->width = len;
3649 return menu->panecount;
3652 /* Create a new item in a menu pane. */
3655 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3656 int foo, char *txt, int enable, char *help_text)
3658 int len;
3659 char *p;
3661 if (pane)
3662 if (!(menu = IT_menu_search_pane (menu, pane)))
3663 return XM_FAILURE;
3664 IT_menu_make_room (menu);
3665 menu->submenu[menu->count] = (XMenu *) 0;
3666 menu->text[menu->count] = txt;
3667 menu->panenumber[menu->count] = enable;
3668 menu->help_text[menu->count] = help_text;
3669 menu->count++;
3671 /* Adjust length for possible control characters (which will
3672 be written as ^x). */
3673 for (len = strlen (txt), p = txt; *p; p++)
3674 if (*p < 27)
3675 len++;
3677 if (len > menu->width)
3678 menu->width = len;
3680 return XM_SUCCESS;
3683 /* Decide where the menu would be placed if requested at (X,Y). */
3685 void
3686 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3687 int *ulx, int *uly, int *width, int *height)
3689 IT_menu_calc_size (menu, width, height);
3690 *ulx = x + 1;
3691 *uly = y;
3692 *width += 2;
3695 struct IT_menu_state
3697 void *screen_behind;
3698 XMenu *menu;
3699 int pane;
3700 int x, y;
3704 /* Display menu, wait for user's response, and return that response. */
3707 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3708 int x0, int y0, unsigned ButtonMask, char **txt,
3709 void (*help_callback)(char *, int, int))
3711 struct IT_menu_state *state;
3712 int statecount, x, y, i, b, screensize, leave, result, onepane;
3713 int title_faces[4]; /* face to display the menu title */
3714 int faces[4], buffers_num_deleted = 0;
3715 struct frame *sf = SELECTED_FRAME();
3716 Lisp_Object saved_echo_area_message, selectface;
3718 /* Just in case we got here without a mouse present... */
3719 if (have_mouse <= 0)
3720 return XM_IA_SELECT;
3721 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3722 around the display. */
3723 if (x0 <= 0)
3724 x0 = 1;
3725 if (y0 <= 0)
3726 y0 = 1;
3728 /* We will process all the mouse events directly, so we had
3729 better prevent dos_rawgetc from stealing them from us. */
3730 mouse_preempted++;
3732 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3733 screensize = screen_size * 2;
3734 faces[0]
3735 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3736 DEFAULT_FACE_ID, 1);
3737 faces[1]
3738 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3739 DEFAULT_FACE_ID, 1);
3740 selectface = intern ("msdos-menu-select-face");
3741 faces[2] = lookup_derived_face (sf, selectface,
3742 faces[0], 1);
3743 faces[3] = lookup_derived_face (sf, selectface,
3744 faces[1], 1);
3746 /* Make sure the menu title is always displayed with
3747 `msdos-menu-active-face', no matter where the mouse pointer is. */
3748 for (i = 0; i < 4; i++)
3749 title_faces[i] = faces[3];
3751 statecount = 1;
3753 /* Don't let the title for the "Buffers" popup menu include a
3754 digit (which is ugly).
3756 This is a terrible kludge, but I think the "Buffers" case is
3757 the only one where the title includes a number, so it doesn't
3758 seem to be necessary to make this more general. */
3759 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3761 menu->text[0][7] = '\0';
3762 buffers_num_deleted = 1;
3765 /* We need to save the current echo area message, so that we could
3766 restore it below, before we exit. See the commentary below,
3767 before the call to message_with_string. */
3768 saved_echo_area_message = Fcurrent_message ();
3769 state[0].menu = menu;
3770 mouse_off ();
3771 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3773 /* Turn off the cursor. Otherwise it shows through the menu
3774 panes, which is ugly. */
3775 IT_display_cursor (0);
3777 /* Display the menu title. */
3778 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3779 if (buffers_num_deleted)
3780 menu->text[0][7] = ' ';
3781 if ((onepane = menu->count == 1 && menu->submenu[0]))
3783 menu->width = menu->submenu[0]->width;
3784 state[0].menu = menu->submenu[0];
3786 else
3788 state[0].menu = menu;
3790 state[0].x = x0 - 1;
3791 state[0].y = y0;
3792 state[0].pane = onepane;
3794 mouse_last_x = -1; /* A hack that forces display. */
3795 leave = 0;
3796 while (!leave)
3798 if (!mouse_visible) mouse_on ();
3799 mouse_check_moved ();
3800 if (sf->mouse_moved)
3802 sf->mouse_moved = 0;
3803 result = XM_IA_SELECT;
3804 mouse_get_xy (&x, &y);
3805 for (i = 0; i < statecount; i++)
3806 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3808 int dy = y - state[i].y;
3809 if (0 <= dy && dy < state[i].menu->count)
3811 if (!state[i].menu->submenu[dy])
3812 if (state[i].menu->panenumber[dy])
3813 result = XM_SUCCESS;
3814 else
3815 result = XM_IA_SELECT;
3816 *pane = state[i].pane - 1;
3817 *selidx = dy;
3818 /* We hit some part of a menu, so drop extra menus that
3819 have been opened. That does not include an open and
3820 active submenu. */
3821 if (i != statecount - 2
3822 || state[i].menu->submenu[dy] != state[i+1].menu)
3823 while (i != statecount - 1)
3825 statecount--;
3826 mouse_off ();
3827 ScreenUpdate (state[statecount].screen_behind);
3828 if (screen_virtual_segment)
3829 dosv_refresh_virtual_screen (0, screen_size);
3830 xfree (state[statecount].screen_behind);
3832 if (i == statecount - 1 && state[i].menu->submenu[dy])
3834 IT_menu_display (state[i].menu,
3835 state[i].y,
3836 state[i].x,
3837 state[i].pane,
3838 faces, 1);
3839 state[statecount].menu = state[i].menu->submenu[dy];
3840 state[statecount].pane = state[i].menu->panenumber[dy];
3841 mouse_off ();
3842 ScreenRetrieve (state[statecount].screen_behind
3843 = xmalloc (screensize));
3844 state[statecount].x
3845 = state[i].x + state[i].menu->width + 2;
3846 state[statecount].y = y;
3847 statecount++;
3851 IT_menu_display (state[statecount - 1].menu,
3852 state[statecount - 1].y,
3853 state[statecount - 1].x,
3854 state[statecount - 1].pane,
3855 faces, 1);
3857 else
3859 if ((menu_help_message || prev_menu_help_message)
3860 && menu_help_message != prev_menu_help_message)
3862 help_callback (menu_help_message,
3863 menu_help_paneno, menu_help_itemno);
3864 IT_display_cursor (0);
3865 prev_menu_help_message = menu_help_message;
3867 /* We are busy-waiting for the mouse to move, so let's be nice
3868 to other Windows applications by releasing our time slice. */
3869 __dpmi_yield ();
3871 for (b = 0; b < mouse_button_count && !leave; b++)
3873 /* Only leave if user both pressed and released the mouse, and in
3874 that order. This avoids popping down the menu pane unless
3875 the user is really done with it. */
3876 if (mouse_pressed (b, &x, &y))
3878 while (mouse_button_depressed (b, &x, &y))
3879 __dpmi_yield ();
3880 leave = 1;
3882 (void) mouse_released (b, &x, &y);
3886 mouse_off ();
3887 ScreenUpdate (state[0].screen_behind);
3888 if (screen_virtual_segment)
3889 dosv_refresh_virtual_screen (0, screen_size);
3891 /* We have a situation here. ScreenUpdate has just restored the
3892 screen contents as it was before we started drawing this menu.
3893 That includes any echo area message that could have been
3894 displayed back then. (In reality, that echo area message will
3895 almost always be the ``keystroke echo'' that echoes the sequence
3896 of menu items chosen by the user.) However, if the menu had some
3897 help messages, then displaying those messages caused Emacs to
3898 forget about the original echo area message. So when
3899 ScreenUpdate restored it, it created a discrepancy between the
3900 actual screen contents and what Emacs internal data structures
3901 know about it.
3903 To avoid this conflict, we force Emacs to restore the original
3904 echo area message as we found it when we entered this function.
3905 The irony of this is that we then erase the restored message
3906 right away, so the only purpose of restoring it is so that
3907 erasing it works correctly... */
3908 if (! NILP (saved_echo_area_message))
3909 message_with_string ("%s", saved_echo_area_message, 0);
3910 message (0);
3911 while (statecount--)
3912 xfree (state[statecount].screen_behind);
3913 IT_display_cursor (1); /* turn cursor back on */
3914 /* Clean up any mouse events that are waiting inside Emacs event queue.
3915 These events are likely to be generated before the menu was even
3916 displayed, probably because the user pressed and released the button
3917 (which invoked the menu) too quickly. If we don't remove these events,
3918 Emacs will process them after we return and surprise the user. */
3919 discard_mouse_events ();
3920 mouse_clear_clicks ();
3921 if (!kbd_buffer_events_waiting (1))
3922 clear_input_pending ();
3923 /* Allow mouse events generation by dos_rawgetc. */
3924 mouse_preempted--;
3925 return result;
3928 /* Dispose of a menu. */
3930 void
3931 XMenuDestroy (Display *foo, XMenu *menu)
3933 int i;
3934 if (menu->allocated)
3936 for (i = 0; i < menu->count; i++)
3937 if (menu->submenu[i])
3938 XMenuDestroy (foo, menu->submenu[i]);
3939 xfree (menu->text);
3940 xfree (menu->submenu);
3941 xfree (menu->panenumber);
3942 xfree (menu->help_text);
3944 xfree (menu);
3945 menu_help_message = prev_menu_help_message = NULL;
3949 x_pixel_width (struct frame *f)
3951 return FRAME_COLS (f);
3955 x_pixel_height (struct frame *f)
3957 return FRAME_LINES (f);
3959 #endif /* !HAVE_X_WINDOWS */
3961 /* ----------------------- DOS / UNIX conversion --------------------- */
3963 void msdos_downcase_filename (unsigned char *);
3965 /* Destructively turn backslashes into slashes. */
3967 void
3968 dostounix_filename (p)
3969 register char *p;
3971 msdos_downcase_filename (p);
3973 while (*p)
3975 if (*p == '\\')
3976 *p = '/';
3977 p++;
3981 /* Destructively turn slashes into backslashes. */
3983 void
3984 unixtodos_filename (p)
3985 register char *p;
3987 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3989 *p += 'a' - 'A';
3990 p += 2;
3993 while (*p)
3995 if (*p == '/')
3996 *p = '\\';
3997 p++;
4001 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4004 getdefdir (drive, dst)
4005 int drive;
4006 char *dst;
4008 char in_path[4], *p = in_path, e = errno;
4010 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4011 if (drive != 0)
4013 *p++ = drive + 'A' - 1;
4014 *p++ = ':';
4017 *p++ = '.';
4018 *p = '\0';
4019 errno = 0;
4020 _fixpath (in_path, dst);
4021 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4022 it queries the LFN support, so ignore that error. */
4023 if ((errno && errno != ENOSYS) || *dst == '\0')
4024 return 0;
4026 msdos_downcase_filename (dst);
4028 errno = e;
4029 return 1;
4032 char *
4033 emacs_root_dir (void)
4035 static char root_dir[4];
4037 sprintf (root_dir, "%c:/", 'A' + getdisk ());
4038 root_dir[0] = tolower (root_dir[0]);
4039 return root_dir;
4042 /* Remove all CR's that are followed by a LF. */
4045 crlf_to_lf (n, buf)
4046 register int n;
4047 register unsigned char *buf;
4049 unsigned char *np = buf, *startp = buf, *endp = buf + n;
4051 if (n == 0)
4052 return n;
4053 while (buf < endp - 1)
4055 if (*buf == 0x0d)
4057 if (*(++buf) != 0x0a)
4058 *np++ = 0x0d;
4060 else
4061 *np++ = *buf++;
4063 if (buf < endp)
4064 *np++ = *buf++;
4065 return np - startp;
4068 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4070 /* In DJGPP v2.0, library `write' can call `malloc', which might
4071 cause relocation of the buffer whose address we get in ADDR.
4072 Here is a version of `write' that avoids calling `malloc',
4073 to serve us until such time as the library is fixed.
4074 Actually, what we define here is called `__write', because
4075 `write' is a stub that just jmp's to `__write' (to be
4076 POSIXLY-correct with respect to the global name-space). */
4078 #include <io.h> /* for _write */
4079 #include <libc/dosio.h> /* for __file_handle_modes[] */
4081 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
4083 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4086 __write (int handle, const void *buffer, size_t count)
4088 if (count == 0)
4089 return 0;
4091 if(__file_handle_modes[handle] & O_BINARY)
4092 return _write (handle, buffer, count);
4093 else
4095 char *xbp = xbuf;
4096 const char *bp = buffer;
4097 int total_written = 0;
4098 int nmoved = 0, ncr = 0;
4100 while (count)
4102 /* The next test makes sure there's space for at least 2 more
4103 characters in xbuf[], so both CR and LF can be put there. */
4104 if (xbp < XBUF_END)
4106 if (*bp == '\n')
4108 ncr++;
4109 *xbp++ = '\r';
4111 *xbp++ = *bp++;
4112 nmoved++;
4113 count--;
4115 if (xbp >= XBUF_END || !count)
4117 size_t to_write = nmoved + ncr;
4118 int written = _write (handle, xbuf, to_write);
4120 if (written == -1)
4121 return -1;
4122 else
4123 total_written += nmoved; /* CRs aren't counted in ret value */
4125 /* If some, but not all were written (disk full?), return
4126 an estimate of the total written bytes not counting CRs. */
4127 if (written < to_write)
4128 return total_written - (to_write - written) * nmoved/to_write;
4130 nmoved = 0;
4131 ncr = 0;
4132 xbp = xbuf;
4135 return total_written;
4139 /* A low-level file-renaming function which works around Windows 95 bug.
4140 This is pulled directly out of DJGPP v2.01 library sources, and only
4141 used when you compile with DJGPP v2.0. */
4143 #include <io.h>
4145 int _rename(const char *old, const char *new)
4147 __dpmi_regs r;
4148 int olen = strlen(old) + 1;
4149 int i;
4150 int use_lfn = _USE_LFN;
4151 char tempfile[FILENAME_MAX];
4152 const char *orig = old;
4153 int lfn_fd = -1;
4155 r.x.dx = __tb_offset;
4156 r.x.di = __tb_offset + olen;
4157 r.x.ds = r.x.es = __tb_segment;
4159 if (use_lfn)
4161 /* Windows 95 bug: for some filenames, when you rename
4162 file -> file~ (as in Emacs, to leave a backup), the
4163 short 8+3 alias doesn't change, which effectively
4164 makes OLD and NEW the same file. We must rename
4165 through a temporary file to work around this. */
4167 char *pbase = 0, *p;
4168 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
4169 int idx = sizeof(try_char) - 1;
4171 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4172 might point to another drive, which will fail the DOS call. */
4173 strcpy(tempfile, old);
4174 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
4175 if (*p == '/' || *p == '\\' || *p == ':')
4176 pbase = p;
4177 if (pbase)
4178 pbase++;
4179 else
4180 pbase = tempfile;
4181 strcpy(pbase, "X$$djren$$.$$temp$$");
4185 if (idx <= 0)
4186 return -1;
4187 *pbase = try_char[--idx];
4188 } while (_chmod(tempfile, 0) != -1);
4190 r.x.ax = 0x7156;
4191 _put_path2(tempfile, olen);
4192 _put_path(old);
4193 __dpmi_int(0x21, &r);
4194 if (r.x.flags & 1)
4196 errno = __doserr_to_errno(r.x.ax);
4197 return -1;
4200 /* Now create a file with the original name. This will
4201 ensure that NEW will always have a 8+3 alias
4202 different from that of OLD. (Seems to be required
4203 when NameNumericTail in the Registry is set to 0.) */
4204 lfn_fd = _creat(old, 0);
4206 olen = strlen(tempfile) + 1;
4207 old = tempfile;
4208 r.x.di = __tb_offset + olen;
4211 for (i=0; i<2; i++)
4213 if(use_lfn)
4214 r.x.ax = 0x7156;
4215 else
4216 r.h.ah = 0x56;
4217 _put_path2(new, olen);
4218 _put_path(old);
4219 __dpmi_int(0x21, &r);
4220 if(r.x.flags & 1)
4222 if (r.x.ax == 5 && i == 0) /* access denied */
4223 remove(new); /* and try again */
4224 else
4226 errno = __doserr_to_errno(r.x.ax);
4228 /* Restore to original name if we renamed it to temporary. */
4229 if (use_lfn)
4231 if (lfn_fd != -1)
4233 _close (lfn_fd);
4234 remove (orig);
4236 _put_path2(orig, olen);
4237 _put_path(tempfile);
4238 r.x.ax = 0x7156;
4239 __dpmi_int(0x21, &r);
4241 return -1;
4244 else
4245 break;
4248 /* Success. Delete the file possibly created to work
4249 around the Windows 95 bug. */
4250 if (lfn_fd != -1)
4251 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
4252 return 0;
4255 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4257 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
4258 0, 0, 0,
4259 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
4262 return (_USE_LFN ? Qt : Qnil);
4265 /* Convert alphabetic characters in a filename to lower-case. */
4267 void
4268 msdos_downcase_filename (p)
4269 register unsigned char *p;
4271 /* Always lower-case drive letters a-z, even if the filesystem
4272 preserves case in filenames.
4273 This is so MSDOS filenames could be compared by string comparison
4274 functions that are case-sensitive. Even case-preserving filesystems
4275 do not distinguish case in drive letters. */
4276 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4278 *p += 'a' - 'A';
4279 p += 2;
4282 /* Under LFN we expect to get pathnames in their true case. */
4283 if (NILP (Fmsdos_long_file_names ()))
4284 for ( ; *p; p++)
4285 if (*p >= 'A' && *p <= 'Z')
4286 *p += 'a' - 'A';
4289 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
4290 1, 1, 0,
4291 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
4292 When long filenames are supported, doesn't change FILENAME.
4293 If FILENAME is not a string, returns nil.
4294 The argument object is never altered--the value is a copy. */)
4295 (filename)
4296 Lisp_Object filename;
4298 Lisp_Object tem;
4300 if (! STRINGP (filename))
4301 return Qnil;
4303 tem = Fcopy_sequence (filename);
4304 msdos_downcase_filename (SDATA (tem));
4305 return tem;
4308 /* The Emacs root directory as determined by init_environment. */
4310 static char emacsroot[MAXPATHLEN];
4312 char *
4313 rootrelativepath (rel)
4314 char *rel;
4316 static char result[MAXPATHLEN + 10];
4318 strcpy (result, emacsroot);
4319 strcat (result, "/");
4320 strcat (result, rel);
4321 return result;
4324 /* Define a lot of environment variables if not already defined. Don't
4325 remove anything unless you know what you're doing -- lots of code will
4326 break if one or more of these are missing. */
4328 void
4329 init_environment (argc, argv, skip_args)
4330 int argc;
4331 char **argv;
4332 int skip_args;
4334 char *s, *t, *root;
4335 int len, i;
4336 static const char * const tempdirs[] = {
4337 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4339 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4341 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4342 temporary files and assume "/tmp" if $TMPDIR is unset, which
4343 will break on DOS/Windows. Refuse to work if we cannot find
4344 a directory, not even "c:/", usable for that purpose. */
4345 for (i = 0; i < imax ; i++)
4347 const char *tmp = tempdirs[i];
4348 char buf[FILENAME_MAX];
4350 if (*tmp == '$')
4352 int tmp_len;
4354 tmp = getenv (tmp + 1);
4355 if (!tmp)
4356 continue;
4358 /* Some lusers set TMPDIR=e:, probably because some losing
4359 programs cannot handle multiple slashes if they use e:/.
4360 e: fails in `access' below, so we interpret e: as e:/. */
4361 tmp_len = strlen(tmp);
4362 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4364 strcpy(buf, tmp);
4365 buf[tmp_len++] = '/', buf[tmp_len] = 0;
4366 tmp = buf;
4370 /* Note that `access' can lie to us if the directory resides on a
4371 read-only filesystem, like CD-ROM or a write-protected floppy.
4372 The only way to be really sure is to actually create a file and
4373 see if it succeeds. But I think that's too much to ask. */
4374 if (tmp && access (tmp, D_OK) == 0)
4376 setenv ("TMPDIR", tmp, 1);
4377 break;
4380 if (i >= imax)
4381 cmd_error_internal
4382 (Fcons (Qerror,
4383 Fcons (build_string ("no usable temporary directories found!!"),
4384 Qnil)),
4385 "While setting TMPDIR: ");
4387 /* Note the startup time, so we know not to clear the screen if we
4388 exit immediately; see IT_reset_terminal_modes.
4389 (Yes, I know `clock' returns zero the first time it's called, but
4390 I do this anyway, in case some wiseguy changes that at some point.) */
4391 startup_time = clock ();
4393 /* Find our root from argv[0]. Assuming argv[0] is, say,
4394 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4395 root = alloca (MAXPATHLEN + 20);
4396 _fixpath (argv[0], root);
4397 msdos_downcase_filename (root);
4398 len = strlen (root);
4399 while (len > 0 && root[len] != '/' && root[len] != ':')
4400 len--;
4401 root[len] = '\0';
4402 if (len > 4
4403 && (strcmp (root + len - 4, "/bin") == 0
4404 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4405 root[len - 4] = '\0';
4406 else
4407 strcpy (root, "c:/emacs"); /* let's be defensive */
4408 len = strlen (root);
4409 strcpy (emacsroot, root);
4411 /* We default HOME to our root. */
4412 setenv ("HOME", root, 0);
4414 /* We default EMACSPATH to root + "/bin". */
4415 strcpy (root + len, "/bin");
4416 setenv ("EMACSPATH", root, 0);
4418 /* I don't expect anybody to ever use other terminals so the internal
4419 terminal is the default. */
4420 setenv ("TERM", "internal", 0);
4422 #ifdef HAVE_X_WINDOWS
4423 /* Emacs expects DISPLAY to be set. */
4424 setenv ("DISPLAY", "unix:0.0", 0);
4425 #endif
4427 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4428 downcase it and mirror the backslashes. */
4429 s = getenv ("COMSPEC");
4430 if (!s) s = "c:/command.com";
4431 t = alloca (strlen (s) + 1);
4432 strcpy (t, s);
4433 dostounix_filename (t);
4434 setenv ("SHELL", t, 0);
4436 /* PATH is also downcased and backslashes mirrored. */
4437 s = getenv ("PATH");
4438 if (!s) s = "";
4439 t = alloca (strlen (s) + 3);
4440 /* Current directory is always considered part of MsDos's path but it is
4441 not normally mentioned. Now it is. */
4442 strcat (strcpy (t, ".;"), s);
4443 dostounix_filename (t); /* Not a single file name, but this should work. */
4444 setenv ("PATH", t, 1);
4446 /* In some sense all dos users have root privileges, so... */
4447 setenv ("USER", "root", 0);
4448 setenv ("NAME", getenv ("USER"), 0);
4450 /* Time zone determined from country code. To make this possible, the
4451 country code may not span more than one time zone. In other words,
4452 in the USA, you lose. */
4453 if (!getenv ("TZ"))
4454 switch (dos_country_code)
4456 case 31: /* Belgium */
4457 case 32: /* The Netherlands */
4458 case 33: /* France */
4459 case 34: /* Spain */
4460 case 36: /* Hungary */
4461 case 38: /* Yugoslavia (or what's left of it?) */
4462 case 39: /* Italy */
4463 case 41: /* Switzerland */
4464 case 42: /* Tjekia */
4465 case 45: /* Denmark */
4466 case 46: /* Sweden */
4467 case 47: /* Norway */
4468 case 48: /* Poland */
4469 case 49: /* Germany */
4470 /* Daylight saving from last Sunday in March to last Sunday in
4471 September, both at 2AM. */
4472 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4473 break;
4474 case 44: /* United Kingdom */
4475 case 351: /* Portugal */
4476 case 354: /* Iceland */
4477 setenv ("TZ", "GMT+00", 0);
4478 break;
4479 case 81: /* Japan */
4480 case 82: /* Korea */
4481 setenv ("TZ", "JST-09", 0);
4482 break;
4483 case 90: /* Turkey */
4484 case 358: /* Finland */
4485 setenv ("TZ", "EET-02", 0);
4486 break;
4487 case 972: /* Israel */
4488 /* This is an approximation. (For exact rules, use the
4489 `zoneinfo/israel' file which comes with DJGPP, but you need
4490 to install it in `/usr/share/zoneinfo/' directory first.) */
4491 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4492 break;
4494 tzset ();
4499 static int break_stat; /* BREAK check mode status. */
4500 static int stdin_stat; /* stdin IOCTL status. */
4502 #if __DJGPP__ < 2
4504 /* These must be global. */
4505 static _go32_dpmi_seginfo ctrl_break_vector;
4506 static _go32_dpmi_registers ctrl_break_regs;
4507 static int ctrlbreakinstalled = 0;
4509 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4511 void
4512 ctrl_break_func (regs)
4513 _go32_dpmi_registers *regs;
4515 Vquit_flag = Qt;
4518 void
4519 install_ctrl_break_check ()
4521 if (!ctrlbreakinstalled)
4523 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4524 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4525 ctrlbreakinstalled = 1;
4526 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
4527 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
4528 &ctrl_break_regs);
4529 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
4533 #endif /* __DJGPP__ < 2 */
4535 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4536 control chars by DOS. Determine the keyboard type. */
4539 dos_ttraw (struct tty_display_info *tty)
4541 union REGS inregs, outregs;
4542 static int first_time = 1;
4544 /* If we are called for the initial terminal, it's too early to do
4545 anything, and termscript isn't set up. */
4546 if (tty->terminal->type == output_initial)
4547 return;
4549 break_stat = getcbrk ();
4550 setcbrk (0);
4551 #if __DJGPP__ < 2
4552 install_ctrl_break_check ();
4553 #endif
4555 if (first_time)
4557 inregs.h.ah = 0xc0;
4558 int86 (0x15, &inregs, &outregs);
4559 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4561 have_mouse = 0;
4563 if (1
4564 #ifdef HAVE_X_WINDOWS
4565 && inhibit_window_system
4566 #endif
4569 inregs.x.ax = 0x0021;
4570 int86 (0x33, &inregs, &outregs);
4571 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4572 if (!have_mouse)
4574 /* Reportedly, the above doesn't work for some mouse drivers. There
4575 is an additional detection method that should work, but might be
4576 a little slower. Use that as an alternative. */
4577 inregs.x.ax = 0x0000;
4578 int86 (0x33, &inregs, &outregs);
4579 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4581 if (have_mouse)
4582 mouse_button_count = outregs.x.bx;
4584 #ifndef HAVE_X_WINDOWS
4585 #if __DJGPP__ >= 2
4586 /* Save the cursor shape used outside Emacs. */
4587 outside_cursor = _farpeekw (_dos_ds, 0x460);
4588 #endif
4589 #endif
4592 first_time = 0;
4594 #if __DJGPP__ >= 2
4596 stdin_stat = setmode (fileno (stdin), O_BINARY);
4597 return (stdin_stat != -1);
4599 else
4600 return (setmode (fileno (stdin), O_BINARY) != -1);
4602 #else /* __DJGPP__ < 2 */
4606 /* I think it is wrong to overwrite `stdin_stat' every time
4607 but the first one this function is called, but I don't
4608 want to change the way it used to work in v1.x.--EZ */
4610 inregs.x.ax = 0x4400; /* Get IOCTL status. */
4611 inregs.x.bx = 0x00; /* 0 = stdin. */
4612 intdos (&inregs, &outregs);
4613 stdin_stat = outregs.h.dl;
4615 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
4616 inregs.x.ax = 0x4401; /* Set IOCTL status */
4617 intdos (&inregs, &outregs);
4618 return !outregs.x.cflag;
4620 #endif /* __DJGPP__ < 2 */
4623 /* Restore status of standard input and Ctrl-C checking. */
4626 dos_ttcooked ()
4628 union REGS inregs, outregs;
4630 setcbrk (break_stat);
4631 mouse_off ();
4633 #if __DJGPP__ >= 2
4635 #ifndef HAVE_X_WINDOWS
4636 /* Restore the cursor shape we found on startup. */
4637 if (outside_cursor)
4639 inregs.h.ah = 1;
4640 inregs.x.cx = outside_cursor;
4641 int86 (0x10, &inregs, &outregs);
4643 #endif
4645 return (setmode (fileno (stdin), stdin_stat) != -1);
4647 #else /* not __DJGPP__ >= 2 */
4649 inregs.x.ax = 0x4401; /* Set IOCTL status. */
4650 inregs.x.bx = 0x00; /* 0 = stdin. */
4651 inregs.x.dx = stdin_stat;
4652 intdos (&inregs, &outregs);
4653 return !outregs.x.cflag;
4655 #endif /* not __DJGPP__ >= 2 */
4659 /* Run command as specified by ARGV in directory DIR.
4660 The command is run with input from TEMPIN, output to
4661 file TEMPOUT and stderr to TEMPERR. */
4664 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4665 unsigned char **argv;
4666 const char *working_dir;
4667 int tempin, tempout, temperr;
4668 char **envv;
4670 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4671 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4672 int msshell, result = -1, inbak, outbak, errbak, x, y;
4673 Lisp_Object cmd;
4675 /* Get current directory as MSDOS cwd is not per-process. */
4676 getwd (oldwd);
4678 /* If argv[0] is the shell, it might come in any lettercase.
4679 Since `Fmember' is case-sensitive, we need to downcase
4680 argv[0], even if we are on case-preserving filesystems. */
4681 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4682 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4684 *pl = *pa++;
4685 if (*pl >= 'A' && *pl <= 'Z')
4686 *pl += 'a' - 'A';
4688 *pl = '\0';
4690 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4691 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4692 && !strcmp ("-c", argv[1]);
4693 if (msshell)
4695 saveargv1 = argv[1];
4696 saveargv2 = argv[2];
4697 argv[1] = "/c";
4698 /* We only need to mirror slashes if a DOS shell will be invoked
4699 not via `system' (which does the mirroring itself). Yes, that
4700 means DJGPP v1.x will lose here. */
4701 if (argv[2] && argv[3])
4703 char *p = alloca (strlen (argv[2]) + 1);
4705 strcpy (argv[2] = p, saveargv2);
4706 while (*p && isspace (*p))
4707 p++;
4708 while (*p)
4710 if (*p == '/')
4711 *p++ = '\\';
4712 else
4713 p++;
4718 chdir (working_dir);
4719 inbak = dup (0);
4720 outbak = dup (1);
4721 errbak = dup (2);
4722 if (inbak < 0 || outbak < 0 || errbak < 0)
4723 goto done; /* Allocation might fail due to lack of descriptors. */
4725 if (have_mouse > 0)
4726 mouse_get_xy (&x, &y);
4728 if (!noninteractive)
4729 dos_ttcooked (); /* do it here while 0 = stdin */
4731 dup2 (tempin, 0);
4732 dup2 (tempout, 1);
4733 dup2 (temperr, 2);
4735 #if __DJGPP__ > 1
4737 if (msshell && !argv[3])
4739 /* MS-DOS native shells are too restrictive. For starters, they
4740 cannot grok commands longer than 126 characters. In DJGPP v2
4741 and later, `system' is much smarter, so we'll call it instead. */
4743 const char *cmnd;
4745 /* A shell gets a single argument--its full command
4746 line--whose original was saved in `saveargv2'. */
4748 /* Don't let them pass empty command lines to `system', since
4749 with some shells it will try to invoke an interactive shell,
4750 which will hang Emacs. */
4751 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4753 if (*cmnd)
4755 extern char **environ;
4756 char **save_env = environ;
4757 int save_system_flags = __system_flags;
4759 /* Request the most powerful version of `system'. We need
4760 all the help we can get to avoid calling stock DOS shells. */
4761 __system_flags = (__system_redirect
4762 | __system_use_shell
4763 | __system_allow_multiple_cmds
4764 | __system_allow_long_cmds
4765 | __system_handle_null_commands
4766 | __system_emulate_chdir);
4768 environ = envv;
4769 result = system (cmnd);
4770 __system_flags = save_system_flags;
4771 environ = save_env;
4773 else
4774 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4776 else
4778 #endif /* __DJGPP__ > 1 */
4780 result = spawnve (P_WAIT, argv[0], argv, envv);
4782 dup2 (inbak, 0);
4783 dup2 (outbak, 1);
4784 dup2 (errbak, 2);
4785 emacs_close (inbak);
4786 emacs_close (outbak);
4787 emacs_close (errbak);
4789 if (!noninteractive)
4790 dos_ttraw (CURTTY ());
4791 if (have_mouse > 0)
4793 mouse_init ();
4794 mouse_moveto (x, y);
4797 /* Some programs might change the meaning of the highest bit of the
4798 text attribute byte, so we get blinking characters instead of the
4799 bright background colors. Restore that. */
4800 if (!noninteractive)
4801 bright_bg ();
4803 done:
4804 chdir (oldwd);
4805 if (msshell)
4807 argv[1] = saveargv1;
4808 argv[2] = saveargv2;
4810 return result;
4813 void
4814 croak (badfunc)
4815 char *badfunc;
4817 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4818 reset_all_sys_modes ();
4819 exit (1);
4822 #if __DJGPP__ < 2
4824 /* ------------------------- Compatibility functions -------------------
4825 * gethostname
4826 * gettimeofday
4829 /* Hostnames for a pc are not really funny,
4830 but they are used in change log so we emulate the best we can. */
4832 gethostname (p, size)
4833 char *p;
4834 int size;
4836 char *q = egetenv ("HOSTNAME");
4838 if (!q) q = "pc";
4839 strcpy (p, q);
4840 return 0;
4843 /* When time zones are set from Ms-Dos too many C-libraries are playing
4844 tricks with time values. We solve this by defining our own version
4845 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4846 once and after each call to `tzset' with TZ changed. That is
4847 accomplished by aliasing tzset to init_gettimeofday. */
4849 static struct tm time_rec;
4852 gettimeofday (struct timeval *tp, struct timezone *tzp)
4854 if (tp)
4856 struct time t;
4857 struct tm tm;
4859 gettime (&t);
4860 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
4862 struct date d;
4863 getdate (&d);
4864 time_rec.tm_year = d.da_year - 1900;
4865 time_rec.tm_mon = d.da_mon - 1;
4866 time_rec.tm_mday = d.da_day;
4869 time_rec.tm_hour = t.ti_hour;
4870 time_rec.tm_min = t.ti_min;
4871 time_rec.tm_sec = t.ti_sec;
4873 tm = time_rec;
4874 tm.tm_gmtoff = dos_timezone_offset;
4876 tp->tv_sec = mktime (&tm); /* may modify tm */
4877 tp->tv_usec = t.ti_hund * (1000000 / 100);
4879 /* Ignore tzp; it's obsolescent. */
4880 return 0;
4883 #endif /* __DJGPP__ < 2 */
4886 * A list of unimplemented functions that we silently ignore.
4889 #if __DJGPP__ < 2
4890 unsigned alarm (s) unsigned s; {}
4891 fork () { return 0; }
4892 int kill (x, y) int x, y; { return -1; }
4893 nice (p) int p; {}
4894 void volatile pause () {}
4895 sigsetmask (x) int x; { return 0; }
4896 sigblock (mask) int mask; { return 0; }
4897 #endif
4899 setpgrp () {return 0; }
4900 setpriority (x,y,z) int x,y,z; { return 0; }
4902 #if __DJGPP__ > 1
4903 #if __DJGPP_MINOR__ < 2
4905 #ifdef POSIX_SIGNALS
4907 /* Augment DJGPP library POSIX signal functions. This is needed
4908 as of DJGPP v2.01, but might be in the library in later releases. */
4910 #include <libc/bss.h>
4912 /* A counter to know when to re-initialize the static sets. */
4913 static int sigprocmask_count = -1;
4915 /* Which signals are currently blocked (initially none). */
4916 static sigset_t current_mask;
4918 /* Which signals are pending (initially none). */
4919 static sigset_t msdos_pending_signals;
4921 /* Previous handlers to restore when the blocked signals are unblocked. */
4922 typedef void (*sighandler_t)(int);
4923 static sighandler_t prev_handlers[320];
4925 /* A signal handler which just records that a signal occurred
4926 (it will be raised later, if and when the signal is unblocked). */
4927 static void
4928 sig_suspender (signo)
4929 int signo;
4931 sigaddset (&msdos_pending_signals, signo);
4935 sigprocmask (how, new_set, old_set)
4936 int how;
4937 const sigset_t *new_set;
4938 sigset_t *old_set;
4940 int signo;
4941 sigset_t new_mask;
4943 /* If called for the first time, initialize. */
4944 if (sigprocmask_count != __bss_count)
4946 sigprocmask_count = __bss_count;
4947 sigemptyset (&msdos_pending_signals);
4948 sigemptyset (&current_mask);
4949 for (signo = 0; signo < 320; signo++)
4950 prev_handlers[signo] = SIG_ERR;
4953 if (old_set)
4954 *old_set = current_mask;
4956 if (new_set == 0)
4957 return 0;
4959 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4961 errno = EINVAL;
4962 return -1;
4965 sigemptyset (&new_mask);
4967 /* DJGPP supports upto 320 signals. */
4968 for (signo = 0; signo < 320; signo++)
4970 if (sigismember (&current_mask, signo))
4971 sigaddset (&new_mask, signo);
4972 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4974 sigaddset (&new_mask, signo);
4976 /* SIGKILL is silently ignored, as on other platforms. */
4977 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4978 prev_handlers[signo] = signal (signo, sig_suspender);
4980 if (( how == SIG_UNBLOCK
4981 && sigismember (&new_mask, signo)
4982 && sigismember (new_set, signo))
4983 || (how == SIG_SETMASK
4984 && sigismember (&new_mask, signo)
4985 && !sigismember (new_set, signo)))
4987 sigdelset (&new_mask, signo);
4988 if (prev_handlers[signo] != SIG_ERR)
4990 signal (signo, prev_handlers[signo]);
4991 prev_handlers[signo] = SIG_ERR;
4993 if (sigismember (&msdos_pending_signals, signo))
4995 sigdelset (&msdos_pending_signals, signo);
4996 raise (signo);
5000 current_mask = new_mask;
5001 return 0;
5004 #else /* not POSIX_SIGNALS */
5006 sigsetmask (x) int x; { return 0; }
5007 sigblock (mask) int mask; { return 0; }
5009 #endif /* not POSIX_SIGNALS */
5010 #endif /* not __DJGPP_MINOR__ < 2 */
5011 #endif /* __DJGPP__ > 1 */
5013 #ifndef HAVE_SELECT
5014 #include "sysselect.h"
5016 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5017 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5018 ((long)(time).tv_sec < 0 \
5019 || ((time).tv_sec == 0 \
5020 && (long)(time).tv_usec <= 0))
5021 #endif
5023 /* This yields the rest of the current time slice to the task manager.
5024 It should be called by any code which knows that it has nothing
5025 useful to do except idle.
5027 I don't use __dpmi_yield here, since versions of library before 2.02
5028 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5029 on some versions of Windows 9X. */
5031 void
5032 dos_yield_time_slice (void)
5034 _go32_dpmi_registers r;
5036 r.x.ax = 0x1680;
5037 r.x.ss = r.x.sp = r.x.flags = 0;
5038 _go32_dpmi_simulate_int (0x2f, &r);
5039 if (r.h.al == 0x80)
5040 errno = ENOSYS;
5043 /* Only event queue is checked. */
5044 /* We don't have to call timer_check here
5045 because wait_reading_process_output takes care of that. */
5047 sys_select (nfds, rfds, wfds, efds, timeout)
5048 int nfds;
5049 SELECT_TYPE *rfds, *wfds, *efds;
5050 EMACS_TIME *timeout;
5052 int check_input;
5053 struct time t;
5055 check_input = 0;
5056 if (rfds)
5058 check_input = FD_ISSET (0, rfds);
5059 FD_ZERO (rfds);
5061 if (wfds)
5062 FD_ZERO (wfds);
5063 if (efds)
5064 FD_ZERO (efds);
5066 if (nfds != 1)
5067 abort ();
5069 /* If we are looking only for the terminal, with no timeout,
5070 just read it and wait -- that's more efficient. */
5071 if (!timeout)
5073 while (!detect_input_pending ())
5075 dos_yield_time_slice ();
5078 else
5080 EMACS_TIME clnow, cllast, cldiff;
5082 gettime (&t);
5083 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
5085 while (!check_input || !detect_input_pending ())
5087 gettime (&t);
5088 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
5089 EMACS_SUB_TIME (cldiff, clnow, cllast);
5091 /* When seconds wrap around, we assume that no more than
5092 1 minute passed since last `gettime'. */
5093 if (EMACS_TIME_NEG_P (cldiff))
5094 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
5095 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
5097 /* Stop when timeout value crosses zero. */
5098 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
5099 return 0;
5100 cllast = clnow;
5101 dos_yield_time_slice ();
5105 FD_SET (0, rfds);
5106 return 1;
5108 #endif
5111 * Define overlaid functions:
5113 * chdir -> sys_chdir
5114 * tzset -> init_gettimeofday
5115 * abort -> dos_abort
5118 #ifdef chdir
5119 #undef chdir
5120 extern int chdir ();
5123 sys_chdir (path)
5124 const char* path;
5126 int len = strlen (path);
5127 char *tmp = (char *)path;
5129 if (*tmp && tmp[1] == ':')
5131 if (getdisk () != tolower (tmp[0]) - 'a')
5132 setdisk (tolower (tmp[0]) - 'a');
5133 tmp += 2; /* strip drive: KFS 1995-07-06 */
5134 len -= 2;
5137 if (len > 1 && (tmp[len - 1] == '/'))
5139 char *tmp1 = (char *) alloca (len + 1);
5140 strcpy (tmp1, tmp);
5141 tmp1[len - 1] = 0;
5142 tmp = tmp1;
5144 return chdir (tmp);
5146 #endif
5148 #ifdef tzset
5149 #undef tzset
5150 extern void tzset (void);
5152 void
5153 init_gettimeofday ()
5155 time_t ltm, gtm;
5156 struct tm *lstm;
5158 tzset ();
5159 ltm = gtm = time (NULL);
5160 ltm = mktime (lstm = localtime (&ltm));
5161 gtm = mktime (gmtime (&gtm));
5162 time_rec.tm_hour = 99; /* force gettimeofday to get date */
5163 time_rec.tm_isdst = lstm->tm_isdst;
5164 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
5166 #endif
5168 #ifdef abort
5169 #undef abort
5170 void
5171 dos_abort (file, line)
5172 char *file;
5173 int line;
5175 char buffer1[200], buffer2[400];
5176 int i, j;
5178 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
5179 for (i = j = 0; buffer1[i]; i++) {
5180 buffer2[j++] = buffer1[i];
5181 buffer2[j++] = 0x70;
5183 dosmemput (buffer2, j, (int)ScreenPrimary);
5184 ScreenSetCursor (2, 0);
5185 abort ();
5187 #else
5188 void
5189 abort ()
5191 dos_ttcooked ();
5192 ScreenSetCursor (10, 0);
5193 cputs ("\r\n\nEmacs aborted!\r\n");
5194 #if __DJGPP__ > 1
5195 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5196 if (screen_virtual_segment)
5197 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
5198 /* Generate traceback, so we could tell whodunit. */
5199 signal (SIGINT, SIG_DFL);
5200 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5201 #else /* __DJGPP_MINOR__ >= 2 */
5202 raise (SIGABRT);
5203 #endif /* __DJGPP_MINOR__ >= 2 */
5204 #endif
5205 exit (2);
5207 #endif
5209 /* The following variables are required so that cus-start.el won't
5210 complain about unbound variables. */
5211 #ifndef subprocesses
5212 /* Nonzero means delete a process right away if it exits (process.c). */
5213 static int delete_exited_processes;
5214 #endif
5216 syms_of_msdos ()
5218 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
5219 staticpro (&recent_doskeys);
5221 #ifndef HAVE_X_WINDOWS
5223 /* The following two are from xfns.c: */
5224 Qreverse = intern ("reverse");
5225 staticpro (&Qreverse);
5227 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
5228 doc: /* *Glyph to display instead of chars not supported by current codepage.
5229 This variable is used only by MS-DOS terminals. */);
5230 Vdos_unsupported_char_glyph = make_number ('\177');
5232 #endif
5233 #ifndef subprocesses
5234 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
5235 doc: /* *Non-nil means delete processes immediately when they exit.
5236 A value of nil means don't delete them until `list-processes' is run. */);
5237 delete_exited_processes = 0;
5238 #endif
5240 defsubr (&Srecent_doskeys);
5241 defsubr (&Smsdos_long_file_names);
5242 defsubr (&Smsdos_downcase_filename);
5243 defsubr (&Smsdos_remember_default_colors);
5244 defsubr (&Smsdos_set_mouse_buttons);
5247 #endif /* MSDOS */
5249 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5250 (do not change this comment) */