* w32-fns.el (w32-shell-dos-semantics):
[emacs.git] / src / msdos.c
blob86b765fb68b49d5568c04f34ec6685e95c4ca184
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
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 Lisp_Object Vdos_unsupported_char_glyph;
961 extern unsigned char *encode_terminal_code (struct glyph *, int,
962 struct coding_system *);
963 static void
964 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
966 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
967 int unsupported_face = 0;
968 unsigned unsupported_char = '\177';
969 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
970 register int sl = str_len;
971 register int tlen = GLYPH_TABLE_LENGTH;
972 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
973 struct tty_display_info *tty = FRAME_TTY (f);
974 struct frame *sf;
975 unsigned char *conversion_buffer;
977 /* Do we need to consider conversion of unibyte characters to
978 multibyte? */
979 int convert_unibyte_characters
980 = (NILP (current_buffer->enable_multibyte_characters)
981 && unibyte_display_via_language_environment);
983 /* If terminal_coding does any conversion, use it, otherwise use
984 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
985 because it always returns 1 if terminal_coding.src_multibyte is 1. */
986 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
988 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
989 coding = &safe_terminal_coding;
991 if (str_len <= 0) return;
993 screen_buf = screen_bp = alloca (str_len * 2);
994 screen_buf_end = screen_buf + str_len * 2;
995 sf = SELECTED_FRAME();
997 /* Since faces get cached and uncached behind our back, we can't
998 rely on their indices in the cache being consistent across
999 invocations. So always reset the screen face to the default
1000 face of the frame, before writing glyphs, and let the glyphs
1001 set the right face if it's different from the default. */
1002 IT_set_face (DEFAULT_FACE_ID);
1004 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1005 the tail. */
1006 coding->mode &= ~CODING_MODE_LAST_BLOCK;
1007 while (sl > 0)
1009 int cf;
1011 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
1012 only for the redisplay code to know how many columns does
1013 this character occupy on the screen. Skip padding glyphs. */
1014 if (CHAR_GLYPH_PADDING_P (*str))
1016 str++;
1017 sl--;
1019 else
1021 /* If the face of this glyph is different from the current
1022 screen face, update the screen attribute byte. */
1023 cf = str->face_id;
1024 if (cf != screen_face)
1025 IT_set_face (cf); /* handles invalid faces gracefully */
1027 if (sl <= 1)
1028 /* This is the last glyph. */
1029 coding->mode |= CODING_MODE_LAST_BLOCK;
1031 conversion_buffer = encode_terminal_code (str, 1, coding);
1032 if (coding->produced > 0)
1034 if (2*coding->produced > screen_buf_end - screen_bp)
1036 /* The allocated buffer for screen writes is too small.
1037 Flush it and loop again without incrementing STR, so
1038 that the next loop will begin with the same glyph. */
1039 int nbytes = screen_bp - screen_buf;
1041 mouse_off_maybe ();
1042 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1043 if (screen_virtual_segment)
1044 dosv_refresh_virtual_screen (offset, nbytes / 2);
1045 new_pos_X += nbytes / 2;
1046 offset += nbytes;
1048 /* Prepare to reuse the same buffer again. */
1049 screen_bp = screen_buf;
1050 continue;
1052 else
1054 /* There's enough place in the allocated buffer to add
1055 the encoding of this glyph. */
1057 /* Copy the encoded bytes to the allocated buffer. */
1058 for (bp = conversion_buffer; coding->produced--; bp++)
1060 *screen_bp++ = (unsigned char)*bp;
1061 *screen_bp++ = ScreenAttrib;
1062 if (tty->termscript)
1063 fputc (*bp, tty->termscript);
1067 /* Update STR and its remaining length. */
1068 str++;
1069 sl--;
1073 /* Dump whatever is left in the screen buffer. */
1074 mouse_off_maybe ();
1075 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1076 if (screen_virtual_segment)
1077 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1078 new_pos_X += (screen_bp - screen_buf) / 2;
1081 /************************************************************************
1082 Mouse Highlight (and friends..)
1083 ************************************************************************/
1085 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1086 static Lisp_Object last_mouse_window;
1088 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1090 /* Set the mouse pointer shape according to whether it is in the
1091 area where the mouse highlight is in effect. */
1092 static void
1093 IT_set_mouse_pointer (int mode)
1095 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1096 many possibilities to change its shape, and the available
1097 functionality pretty much sucks (e.g., almost every reasonable
1098 shape will conceal the character it is on). Since the color of
1099 the pointer changes in the highlighted area, it is not clear to
1100 me whether anything else is required, anyway. */
1103 /* Display the active region described by mouse_face_*
1104 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1105 static void
1106 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
1108 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1109 struct frame *f = XFRAME (WINDOW_FRAME (w));
1110 int i;
1111 struct face *fp;
1112 struct tty_display_info *tty = FRAME_TTY (f);
1115 /* If window is in the process of being destroyed, don't bother
1116 doing anything. */
1117 if (w->current_matrix == NULL)
1118 goto set_cursor_shape;
1120 /* Recognize when we are called to operate on rows that don't exist
1121 anymore. This can happen when a window is split. */
1122 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1123 goto set_cursor_shape;
1125 /* There's no sense to do anything if the mouse face isn't realized. */
1126 if (hl > 0)
1128 if (dpyinfo->mouse_face_hidden)
1129 goto set_cursor_shape;
1131 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1132 if (!fp)
1133 goto set_cursor_shape;
1136 /* Note that mouse_face_beg_row etc. are window relative. */
1137 for (i = dpyinfo->mouse_face_beg_row;
1138 i <= dpyinfo->mouse_face_end_row;
1139 i++)
1141 int start_hpos, end_hpos;
1142 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1144 /* Don't do anything if row doesn't have valid contents. */
1145 if (!row->enabled_p)
1146 continue;
1148 /* For all but the first row, the highlight starts at column 0. */
1149 if (i == dpyinfo->mouse_face_beg_row)
1150 start_hpos = dpyinfo->mouse_face_beg_col;
1151 else
1152 start_hpos = 0;
1154 if (i == dpyinfo->mouse_face_end_row)
1155 end_hpos = dpyinfo->mouse_face_end_col;
1156 else
1157 end_hpos = row->used[TEXT_AREA];
1159 if (end_hpos <= start_hpos)
1160 continue;
1161 /* Record that some glyphs of this row are displayed in
1162 mouse-face. */
1163 row->mouse_face_p = hl > 0;
1164 if (hl > 0)
1166 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1167 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1168 int nglyphs = end_hpos - start_hpos;
1169 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1170 int start_offset = offset;
1172 if (tty->termscript)
1173 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1174 kstart, kstart + nglyphs - 1, vpos);
1176 mouse_off ();
1177 IT_set_face (dpyinfo->mouse_face_face_id);
1178 /* Since we are going to change only the _colors_ of the
1179 displayed text, there's no need to go through all the
1180 pain of generating and encoding the text from the glyphs.
1181 Instead, we simply poke the attribute byte of each
1182 affected position in video memory with the colors
1183 computed by IT_set_face! */
1184 _farsetsel (_dos_ds);
1185 while (nglyphs--)
1187 _farnspokeb (offset, ScreenAttrib);
1188 offset += 2;
1190 if (screen_virtual_segment)
1191 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1192 mouse_on ();
1194 else
1196 /* We are removing a previously-drawn mouse highlight. The
1197 safest way to do so is to redraw the glyphs anew, since
1198 all kinds of faces and display tables could have changed
1199 behind our back. */
1200 int nglyphs = end_hpos - start_hpos;
1201 int save_x = new_pos_X, save_y = new_pos_Y;
1203 if (end_hpos >= row->used[TEXT_AREA])
1204 nglyphs = row->used[TEXT_AREA] - start_hpos;
1206 /* IT_write_glyphs writes at cursor position, so we need to
1207 temporarily move cursor coordinates to the beginning of
1208 the highlight region. */
1209 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1210 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1212 if (tty->termscript)
1213 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1214 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1215 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1216 if (tty->termscript)
1217 fputs ("\n", tty->termscript);
1218 new_pos_X = save_x;
1219 new_pos_Y = save_y;
1223 set_cursor_shape:
1224 /* Change the mouse pointer shape. */
1225 IT_set_mouse_pointer (hl);
1228 /* Clear out the mouse-highlighted active region.
1229 Redraw it un-highlighted first. */
1230 static void
1231 clear_mouse_face (struct tty_display_info *dpyinfo)
1233 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1234 show_mouse_face (dpyinfo, 0);
1236 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1237 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1238 dpyinfo->mouse_face_window = Qnil;
1241 /* Find the glyph matrix position of buffer position POS in window W.
1242 *HPOS and *VPOS are set to the positions found. W's current glyphs
1243 must be up to date. If POS is above window start return (0, 0).
1244 If POS is after end of W, return end of last line in W. */
1245 static int
1246 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1248 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1249 int yb = window_text_bottom_y (w);
1250 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1252 while (row->y < yb)
1254 if (row->used[TEXT_AREA])
1255 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1256 else
1257 line_start_position = 0;
1259 if (line_start_position > pos)
1260 break;
1261 /* If the position sought is the end of the buffer,
1262 don't include the blank lines at the bottom of the window. */
1263 else if (line_start_position == pos
1264 && pos == BUF_ZV (XBUFFER (w->buffer)))
1266 maybe_next_line_p = 1;
1267 break;
1269 else if (line_start_position > 0)
1270 best_row = row;
1272 /* Don't overstep the last matrix row, lest we get into the
1273 never-never land... */
1274 if (row->y + 1 >= yb)
1275 break;
1277 ++row;
1280 /* Find the right column within BEST_ROW. */
1281 lastcol = 0;
1282 row = best_row;
1283 for (i = 0; i < row->used[TEXT_AREA]; i++)
1285 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1286 int charpos;
1288 charpos = glyph->charpos;
1289 if (charpos == pos)
1291 *hpos = i;
1292 *vpos = row->y;
1293 return 1;
1295 else if (charpos > pos)
1296 break;
1297 else if (charpos > 0)
1298 lastcol = i;
1301 /* If we're looking for the end of the buffer,
1302 and we didn't find it in the line we scanned,
1303 use the start of the following line. */
1304 if (maybe_next_line_p)
1306 ++row;
1307 lastcol = 0;
1310 *vpos = row->y;
1311 *hpos = lastcol + 1;
1312 return 0;
1315 /* Take proper action when mouse has moved to the mode or top line of
1316 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1317 mode line. X is relative to the start of the text display area of
1318 W, so the width of fringes and scroll bars must be subtracted
1319 to get a position relative to the start of the mode line. */
1320 static void
1321 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1323 struct frame *f = XFRAME (w->frame);
1324 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1325 struct glyph_row *row;
1327 if (mode_line_p)
1328 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1329 else
1330 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1332 if (row->enabled_p)
1334 extern Lisp_Object Qhelp_echo;
1335 struct glyph *glyph, *end;
1336 Lisp_Object help, map;
1338 /* Find the glyph under X. */
1339 glyph = (row->glyphs[TEXT_AREA]
1341 /* in case someone implements scroll bars some day... */
1342 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1343 end = glyph + row->used[TEXT_AREA];
1344 if (glyph < end
1345 && STRINGP (glyph->object)
1346 && STRING_INTERVALS (glyph->object)
1347 && glyph->charpos >= 0
1348 && glyph->charpos < SCHARS (glyph->object))
1350 /* If we're on a string with `help-echo' text property,
1351 arrange for the help to be displayed. This is done by
1352 setting the global variable help_echo to the help string. */
1353 help = Fget_text_property (make_number (glyph->charpos),
1354 Qhelp_echo, glyph->object);
1355 if (!NILP (help))
1357 help_echo_string = help;
1358 XSETWINDOW (help_echo_window, w);
1359 help_echo_object = glyph->object;
1360 help_echo_pos = glyph->charpos;
1366 /* Take proper action when the mouse has moved to position X, Y on
1367 frame F as regards highlighting characters that have mouse-face
1368 properties. Also de-highlighting chars where the mouse was before.
1369 X and Y can be negative or out of range. */
1370 static void
1371 IT_note_mouse_highlight (struct frame *f, int x, int y)
1373 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1374 enum window_part part = ON_NOTHING;
1375 Lisp_Object window;
1376 struct window *w;
1378 /* When a menu is active, don't highlight because this looks odd. */
1379 if (mouse_preempted)
1380 return;
1382 if (NILP (Vmouse_highlight)
1383 || !f->glyphs_initialized_p)
1384 return;
1386 dpyinfo->mouse_face_mouse_x = x;
1387 dpyinfo->mouse_face_mouse_y = y;
1388 dpyinfo->mouse_face_mouse_frame = f;
1390 if (dpyinfo->mouse_face_defer)
1391 return;
1393 if (gc_in_progress)
1395 dpyinfo->mouse_face_deferred_gc = 1;
1396 return;
1399 /* Which window is that in? */
1400 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1402 /* If we were displaying active text in another window, clear that. */
1403 if (! EQ (window, dpyinfo->mouse_face_window))
1404 clear_mouse_face (dpyinfo);
1406 /* Not on a window -> return. */
1407 if (!WINDOWP (window))
1408 return;
1410 /* Convert to window-relative coordinates. */
1411 w = XWINDOW (window);
1413 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1415 /* Mouse is on the mode or top line. */
1416 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1417 return;
1420 IT_set_mouse_pointer (0);
1422 /* Are we in a window whose display is up to date?
1423 And verify the buffer's text has not changed. */
1424 if (part == ON_TEXT
1425 && EQ (w->window_end_valid, w->buffer)
1426 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1427 && (XFASTINT (w->last_overlay_modified)
1428 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1430 int pos, i, nrows = w->current_matrix->nrows;
1431 struct glyph_row *row;
1432 struct glyph *glyph;
1434 /* Find the glyph under X/Y. */
1435 glyph = NULL;
1436 if (y >= 0 && y < nrows)
1438 row = MATRIX_ROW (w->current_matrix, y);
1439 /* Give up if some row before the one we are looking for is
1440 not enabled. */
1441 for (i = 0; i <= y; i++)
1442 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1443 break;
1444 if (i > y /* all rows upto and including the one at Y are enabled */
1445 && row->displays_text_p
1446 && x < window_box_width (w, TEXT_AREA))
1448 glyph = row->glyphs[TEXT_AREA];
1449 if (x >= row->used[TEXT_AREA])
1450 glyph = NULL;
1451 else
1453 glyph += x;
1454 if (!BUFFERP (glyph->object))
1455 glyph = NULL;
1460 /* Clear mouse face if X/Y not over text. */
1461 if (glyph == NULL)
1463 clear_mouse_face (dpyinfo);
1464 return;
1467 if (!BUFFERP (glyph->object))
1468 abort ();
1469 pos = glyph->charpos;
1471 /* Check for mouse-face and help-echo. */
1473 extern Lisp_Object Qmouse_face;
1474 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1475 int noverlays, obegv, ozv;
1476 struct buffer *obuf;
1478 /* If we get an out-of-range value, return now; avoid an error. */
1479 if (pos > BUF_Z (XBUFFER (w->buffer)))
1480 return;
1482 /* Make the window's buffer temporarily current for
1483 overlays_at and compute_char_face. */
1484 obuf = current_buffer;
1485 current_buffer = XBUFFER (w->buffer);
1486 obegv = BEGV;
1487 ozv = ZV;
1488 BEGV = BEG;
1489 ZV = Z;
1491 /* Is this char mouse-active or does it have help-echo? */
1492 XSETINT (position, pos);
1494 /* Put all the overlays we want in a vector in overlay_vec. */
1495 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1496 /* Sort overlays into increasing priority order. */
1497 noverlays = sort_overlays (overlay_vec, noverlays, w);
1499 /* Check mouse-face highlighting. */
1500 if (! (EQ (window, dpyinfo->mouse_face_window)
1501 && y >= dpyinfo->mouse_face_beg_row
1502 && y <= dpyinfo->mouse_face_end_row
1503 && (y > dpyinfo->mouse_face_beg_row
1504 || x >= dpyinfo->mouse_face_beg_col)
1505 && (y < dpyinfo->mouse_face_end_row
1506 || x < dpyinfo->mouse_face_end_col
1507 || dpyinfo->mouse_face_past_end)))
1509 /* Clear the display of the old active region, if any. */
1510 clear_mouse_face (dpyinfo);
1512 /* Find highest priority overlay that has a mouse-face prop. */
1513 overlay = Qnil;
1514 for (i = noverlays - 1; i >= 0; --i)
1516 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1517 if (!NILP (mouse_face))
1519 overlay = overlay_vec[i];
1520 break;
1524 /* If no overlay applies, get a text property. */
1525 if (NILP (overlay))
1526 mouse_face = Fget_text_property (position, Qmouse_face,
1527 w->buffer);
1529 /* Handle the overlay case. */
1530 if (! NILP (overlay))
1532 /* Find the range of text around this char that
1533 should be active. */
1534 Lisp_Object before, after;
1535 EMACS_INT ignore;
1537 before = Foverlay_start (overlay);
1538 after = Foverlay_end (overlay);
1539 /* Record this as the current active region. */
1540 fast_find_position (w, XFASTINT (before),
1541 &dpyinfo->mouse_face_beg_col,
1542 &dpyinfo->mouse_face_beg_row);
1543 dpyinfo->mouse_face_past_end
1544 = !fast_find_position (w, XFASTINT (after),
1545 &dpyinfo->mouse_face_end_col,
1546 &dpyinfo->mouse_face_end_row);
1547 dpyinfo->mouse_face_window = window;
1548 dpyinfo->mouse_face_face_id
1549 = face_at_buffer_position (w, pos, 0, 0,
1550 &ignore, pos + 1,
1551 !dpyinfo->mouse_face_hidden);
1553 /* Display it as active. */
1554 show_mouse_face (dpyinfo, 1);
1556 /* Handle the text property case. */
1557 else if (! NILP (mouse_face))
1559 /* Find the range of text around this char that
1560 should be active. */
1561 Lisp_Object before, after, beginning, end;
1562 EMACS_INT ignore;
1564 beginning = Fmarker_position (w->start);
1565 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1566 - XFASTINT (w->window_end_pos)));
1567 before
1568 = Fprevious_single_property_change (make_number (pos + 1),
1569 Qmouse_face,
1570 w->buffer, beginning);
1571 after
1572 = Fnext_single_property_change (position, Qmouse_face,
1573 w->buffer, end);
1574 /* Record this as the current active region. */
1575 fast_find_position (w, XFASTINT (before),
1576 &dpyinfo->mouse_face_beg_col,
1577 &dpyinfo->mouse_face_beg_row);
1578 dpyinfo->mouse_face_past_end
1579 = !fast_find_position (w, XFASTINT (after),
1580 &dpyinfo->mouse_face_end_col,
1581 &dpyinfo->mouse_face_end_row);
1582 dpyinfo->mouse_face_window = window;
1583 dpyinfo->mouse_face_face_id
1584 = face_at_buffer_position (w, pos, 0, 0,
1585 &ignore, pos + 1,
1586 !dpyinfo->mouse_face_hidden);
1588 /* Display it as active. */
1589 show_mouse_face (dpyinfo, 1);
1593 /* Look for a `help-echo' property. */
1595 Lisp_Object help;
1596 extern Lisp_Object Qhelp_echo;
1598 /* Check overlays first. */
1599 help = Qnil;
1600 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1602 overlay = overlay_vec[i];
1603 help = Foverlay_get (overlay, Qhelp_echo);
1606 if (!NILP (help))
1608 help_echo_string = help;
1609 help_echo_window = window;
1610 help_echo_object = overlay;
1611 help_echo_pos = pos;
1613 /* Try text properties. */
1614 else if (NILP (help)
1615 && ((STRINGP (glyph->object)
1616 && glyph->charpos >= 0
1617 && glyph->charpos < SCHARS (glyph->object))
1618 || (BUFFERP (glyph->object)
1619 && glyph->charpos >= BEGV
1620 && glyph->charpos < ZV)))
1622 help = Fget_text_property (make_number (glyph->charpos),
1623 Qhelp_echo, glyph->object);
1624 if (!NILP (help))
1626 help_echo_string = help;
1627 help_echo_window = window;
1628 help_echo_object = glyph->object;
1629 help_echo_pos = glyph->charpos;
1634 BEGV = obegv;
1635 ZV = ozv;
1636 current_buffer = obuf;
1641 static void
1642 IT_clear_end_of_line (struct frame *f, int first_unused)
1644 char *spaces, *sp;
1645 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1646 extern int fatal_error_in_progress;
1647 struct tty_display_info *tty = FRAME_TTY (f);
1649 if (new_pos_X >= first_unused || fatal_error_in_progress)
1650 return;
1652 IT_set_face (0);
1653 i = (j = first_unused - new_pos_X) * 2;
1654 if (tty->termscript)
1655 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1656 spaces = sp = alloca (i);
1658 while (--j >= 0)
1660 *sp++ = ' ';
1661 *sp++ = ScreenAttrib;
1664 mouse_off_maybe ();
1665 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1666 if (screen_virtual_segment)
1667 dosv_refresh_virtual_screen (offset, i / 2);
1669 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1670 Let's follow their lead, in case someone relies on this. */
1671 new_pos_X = first_unused;
1674 static void
1675 IT_clear_screen (struct frame *f)
1677 struct tty_display_info *tty = FRAME_TTY (f);
1679 if (tty->termscript)
1680 fprintf (tty->termscript, "<CLR:SCR>");
1681 /* We are sometimes called (from clear_garbaged_frames) when a new
1682 frame is being created, but its faces are not yet realized. In
1683 such a case we cannot call IT_set_face, since it will fail to find
1684 any valid faces and will abort. Instead, use the initial screen
1685 colors; that should mimic what a Unix tty does, which simply clears
1686 the screen with whatever default colors are in use. */
1687 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1688 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1689 else
1690 IT_set_face (0);
1691 mouse_off ();
1692 ScreenClear ();
1693 if (screen_virtual_segment)
1694 dosv_refresh_virtual_screen (0, screen_size);
1695 new_pos_X = new_pos_Y = 0;
1698 static void
1699 IT_clear_to_end (struct frame *f)
1701 struct tty_display_info *tty = FRAME_TTY (f);
1703 if (tty->termscript)
1704 fprintf (tty->termscript, "<CLR:EOS>");
1706 while (new_pos_Y < screen_size_Y) {
1707 new_pos_X = 0;
1708 IT_clear_end_of_line (f, screen_size_X);
1709 new_pos_Y++;
1713 static void
1714 IT_cursor_to (struct frame *f, int y, int x)
1716 struct tty_display_info *tty = FRAME_TTY (f);
1718 if (tty->termscript)
1719 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1720 new_pos_X = x;
1721 new_pos_Y = y;
1724 static int cursor_cleared;
1726 static void
1727 IT_display_cursor (int on)
1729 struct tty_display_info *tty = CURTTY ();
1731 if (on && cursor_cleared)
1733 ScreenSetCursor (current_pos_Y, current_pos_X);
1734 cursor_cleared = 0;
1735 if (tty->termscript)
1736 fprintf (tty->termscript, "\nCURSOR ON");
1738 else if (!on && !cursor_cleared)
1740 ScreenSetCursor (-1, -1);
1741 cursor_cleared = 1;
1742 if (tty->termscript)
1743 fprintf (tty->termscript, "\nCURSOR OFF");
1747 /* Emacs calls cursor-movement functions a lot when it updates the
1748 display (probably a legacy of old terminals where you cannot
1749 update a screen line without first moving the cursor there).
1750 However, cursor movement is expensive on MSDOS (it calls a slow
1751 BIOS function and requires 2 mode switches), while actual screen
1752 updates access the video memory directly and don't depend on
1753 cursor position. To avoid slowing down the redisplay, we cheat:
1754 all functions that move the cursor only set internal variables
1755 which record the cursor position, whereas the cursor is only
1756 moved to its final position whenever screen update is complete.
1758 `IT_cmgoto' is called from the keyboard reading loop and when the
1759 frame update is complete. This means that we are ready for user
1760 input, so we update the cursor position to show where the point is,
1761 and also make the mouse pointer visible.
1763 Special treatment is required when the cursor is in the echo area,
1764 to put the cursor at the end of the text displayed there. */
1766 static void
1767 IT_cmgoto (FRAME_PTR f)
1769 /* Only set the cursor to where it should be if the display is
1770 already in sync with the window contents. */
1771 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1772 struct tty_display_info *tty = FRAME_TTY (f);
1774 /* FIXME: This needs to be rewritten for the new redisplay, or
1775 removed. */
1776 #if 0
1777 static int previous_pos_X = -1;
1779 update_cursor_pos = 1; /* temporary!!! */
1781 /* If the display is in sync, forget any previous knowledge about
1782 cursor position. This is primarily for unexpected events like
1783 C-g in the minibuffer. */
1784 if (update_cursor_pos && previous_pos_X >= 0)
1785 previous_pos_X = -1;
1786 /* If we are in the echo area, put the cursor at the
1787 end of the echo area message. */
1788 if (!update_cursor_pos
1789 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1791 int tem_X = current_pos_X, dummy;
1793 if (echo_area_glyphs)
1795 tem_X = echo_area_glyphs_length;
1796 /* Save current cursor position, to be restored after the
1797 echo area message is erased. Only remember one level
1798 of previous cursor position. */
1799 if (previous_pos_X == -1)
1800 ScreenGetCursor (&dummy, &previous_pos_X);
1802 else if (previous_pos_X >= 0)
1804 /* We wind up here after the echo area message is erased.
1805 Restore the cursor position we remembered above. */
1806 tem_X = previous_pos_X;
1807 previous_pos_X = -1;
1810 if (current_pos_X != tem_X)
1812 new_pos_X = tem_X;
1813 update_cursor_pos = 1;
1816 #endif
1818 if (update_cursor_pos
1819 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1821 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1822 if (tty->termscript)
1823 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1826 /* Maybe cursor is invisible, so make it visible. */
1827 IT_display_cursor (1);
1829 /* Mouse pointer should be always visible if we are waiting for
1830 keyboard input. */
1831 if (!mouse_visible)
1832 mouse_on ();
1835 static void
1836 IT_update_begin (struct frame *f)
1838 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1839 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1841 if (display_info->termscript)
1842 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1844 BLOCK_INPUT;
1846 if (f && f == mouse_face_frame)
1848 /* Don't do highlighting for mouse motion during the update. */
1849 display_info->mouse_face_defer = 1;
1851 /* If F needs to be redrawn, simply forget about any prior mouse
1852 highlighting. */
1853 if (FRAME_GARBAGED_P (f))
1854 display_info->mouse_face_window = Qnil;
1856 /* Can we tell that this update does not affect the window
1857 where the mouse highlight is? If so, no need to turn off.
1858 Likewise, don't do anything if none of the enabled rows
1859 contains glyphs highlighted in mouse face. */
1860 if (!NILP (display_info->mouse_face_window)
1861 && WINDOWP (display_info->mouse_face_window))
1863 struct window *w = XWINDOW (display_info->mouse_face_window);
1864 int i;
1866 /* If the mouse highlight is in the window that was deleted
1867 (e.g., if it was popped by completion), clear highlight
1868 unconditionally. */
1869 if (NILP (w->buffer))
1870 display_info->mouse_face_window = Qnil;
1871 else
1873 for (i = 0; i < w->desired_matrix->nrows; ++i)
1874 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1875 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1876 break;
1879 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1880 clear_mouse_face (display_info);
1883 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1885 /* If the frame with mouse highlight was deleted, invalidate the
1886 highlight info. */
1887 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1888 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1889 display_info->mouse_face_window = Qnil;
1890 display_info->mouse_face_deferred_gc = 0;
1891 display_info->mouse_face_mouse_frame = NULL;
1894 UNBLOCK_INPUT;
1897 static void
1898 IT_update_end (struct frame *f)
1900 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1902 if (dpyinfo->termscript)
1903 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1904 dpyinfo->mouse_face_defer = 0;
1907 static void
1908 IT_frame_up_to_date (struct frame *f)
1910 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1911 Lisp_Object new_cursor, frame_desired_cursor;
1912 struct window *sw;
1914 if (dpyinfo->mouse_face_deferred_gc
1915 || (f && f == dpyinfo->mouse_face_mouse_frame))
1917 BLOCK_INPUT;
1918 if (dpyinfo->mouse_face_mouse_frame)
1919 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1920 dpyinfo->mouse_face_mouse_x,
1921 dpyinfo->mouse_face_mouse_y);
1922 dpyinfo->mouse_face_deferred_gc = 0;
1923 UNBLOCK_INPUT;
1926 /* Set the cursor type to whatever they wanted. In a minibuffer
1927 window, we want the cursor to appear only if we are reading input
1928 from this window, and we want the cursor to be taken from the
1929 frame parameters. For the selected window, we use either its
1930 buffer-local value or the value from the frame parameters if the
1931 buffer doesn't define its local value for the cursor type. */
1932 sw = XWINDOW (f->selected_window);
1933 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1934 if (cursor_in_echo_area
1935 && FRAME_HAS_MINIBUF_P (f)
1936 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1937 && sw == XWINDOW (echo_area_window))
1938 new_cursor = frame_desired_cursor;
1939 else
1941 struct buffer *b = XBUFFER (sw->buffer);
1943 if (EQ (b->cursor_type, Qt))
1944 new_cursor = frame_desired_cursor;
1945 else if (NILP (b->cursor_type)) /* nil means no cursor */
1946 new_cursor = Fcons (Qbar, make_number (0));
1947 else
1948 new_cursor = b->cursor_type;
1951 IT_set_cursor_type (f, new_cursor);
1953 IT_cmgoto (f); /* position cursor when update is done */
1956 /* Copy LEN glyphs displayed on a single line whose vertical position
1957 is YPOS, beginning at horizontal position XFROM to horizontal
1958 position XTO, by moving blocks in the video memory. Used by
1959 functions that insert and delete glyphs. */
1960 static void
1961 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1963 /* The offsets of source and destination relative to the
1964 conventional memorty selector. */
1965 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1966 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1968 if (from == to || len <= 0)
1969 return;
1971 _farsetsel (_dos_ds);
1973 /* The source and destination might overlap, so we need to move
1974 glyphs non-destructively. */
1975 if (from > to)
1977 for ( ; len; from += 2, to += 2, len--)
1978 _farnspokew (to, _farnspeekw (from));
1980 else
1982 from += (len - 1) * 2;
1983 to += (len - 1) * 2;
1984 for ( ; len; from -= 2, to -= 2, len--)
1985 _farnspokew (to, _farnspeekw (from));
1987 if (screen_virtual_segment)
1988 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1991 /* Insert and delete glyphs. */
1992 static void
1993 IT_insert_glyphs (f, start, len)
1994 struct frame *f;
1995 register struct glyph *start;
1996 register int len;
1998 int shift_by_width = screen_size_X - (new_pos_X + len);
2000 /* Shift right the glyphs from the nominal cursor position to the
2001 end of this line. */
2002 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
2004 /* Now write the glyphs to be inserted. */
2005 IT_write_glyphs (f, start, len);
2008 static void
2009 IT_delete_glyphs (f, n)
2010 struct frame *f;
2011 register int n;
2013 abort ();
2016 /* set-window-configuration on window.c needs this. */
2017 void
2018 x_set_menu_bar_lines (f, value, oldval)
2019 struct frame *f;
2020 Lisp_Object value, oldval;
2022 set_menu_bar_lines (f, value, oldval);
2025 /* This was copied from xfaces.c */
2027 extern Lisp_Object Qbackground_color;
2028 extern Lisp_Object Qforeground_color;
2029 Lisp_Object Qreverse;
2030 extern Lisp_Object Qtitle;
2032 /* IT_set_terminal_modes is called when emacs is started,
2033 resumed, and whenever the screen is redrawn! */
2035 static void
2036 IT_set_terminal_modes (struct terminal *term)
2038 struct tty_display_info *tty;
2040 /* If called with initial terminal, it's too early to do anything
2041 useful. */
2042 if (term->type == output_initial)
2043 return;
2045 tty = term->display_info.tty;
2047 if (tty->termscript)
2048 fprintf (tty->termscript, "\n<SET_TERM>");
2050 screen_size_X = ScreenCols ();
2051 screen_size_Y = ScreenRows ();
2052 screen_size = screen_size_X * screen_size_Y;
2054 new_pos_X = new_pos_Y = 0;
2055 current_pos_X = current_pos_Y = -1;
2057 if (term_setup_done)
2058 return;
2059 term_setup_done = 1;
2061 startup_screen_size_X = screen_size_X;
2062 startup_screen_size_Y = screen_size_Y;
2063 startup_screen_attrib = ScreenAttrib;
2065 #if __DJGPP__ > 1
2066 /* Is DOS/V (or any other RSIS software which relocates
2067 the screen) installed? */
2069 unsigned short es_value;
2070 __dpmi_regs regs;
2072 regs.h.ah = 0xfe; /* get relocated screen address */
2073 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2074 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2075 else if (screen_old_address) /* already switched to Japanese mode once */
2076 regs.x.es = (screen_old_address >> 4) & 0xffff;
2077 else
2078 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2079 regs.x.di = 0;
2080 es_value = regs.x.es;
2081 __dpmi_int (0x10, &regs);
2083 if (regs.x.es != es_value)
2085 /* screen_old_address is only set if ScreenPrimary does NOT
2086 already point to the relocated buffer address returned by
2087 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2088 ScreenPrimary to that address at startup under DOS/V. */
2089 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2090 screen_old_address = ScreenPrimary;
2091 screen_virtual_segment = regs.x.es;
2092 screen_virtual_offset = regs.x.di;
2093 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2096 #endif /* __DJGPP__ > 1 */
2098 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2099 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2101 bright_bg ();
2104 /* IT_reset_terminal_modes is called when emacs is
2105 suspended or killed. */
2107 static void
2108 IT_reset_terminal_modes (struct terminal *term)
2110 int display_row_start = (int) ScreenPrimary;
2111 int saved_row_len = startup_screen_size_X * 2;
2112 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
2113 int to_next_row = update_row_len;
2114 unsigned char *saved_row = startup_screen_buffer;
2115 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
2116 struct tty_display_info *tty = term->display_info.tty;
2118 if (tty->termscript)
2119 fprintf (tty->termscript, "\n<RESET_TERM>");
2121 if (!term_setup_done)
2122 return;
2124 mouse_off ();
2126 /* Leave the video system in the same state as we found it,
2127 as far as the blink/bright-background bit is concerned. */
2128 maybe_enable_blinking ();
2130 /* We have a situation here.
2131 We cannot just do ScreenUpdate(startup_screen_buffer) because
2132 the luser could have changed screen dimensions inside Emacs
2133 and failed (or didn't want) to restore them before killing
2134 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2135 thus will happily use memory outside what was allocated for
2136 `startup_screen_buffer'.
2137 Thus we only restore as much as the current screen dimensions
2138 can hold, and clear the rest (if the saved screen is smaller than
2139 the current) with the color attribute saved at startup. The cursor
2140 is also restored within the visible dimensions. */
2142 ScreenAttrib = startup_screen_attrib;
2144 /* Don't restore the screen if we are exiting less than 2 seconds
2145 after startup: we might be crashing, and the screen might show
2146 some vital clues to what's wrong. */
2147 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2149 ScreenClear ();
2150 if (screen_virtual_segment)
2151 dosv_refresh_virtual_screen (0, screen_size);
2153 if (update_row_len > saved_row_len)
2154 update_row_len = saved_row_len;
2155 if (current_rows > startup_screen_size_Y)
2156 current_rows = startup_screen_size_Y;
2158 if (tty->termscript)
2159 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2160 update_row_len / 2, current_rows);
2162 while (current_rows--)
2164 dosmemput (saved_row, update_row_len, display_row_start);
2165 if (screen_virtual_segment)
2166 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2167 update_row_len / 2);
2168 saved_row += saved_row_len;
2169 display_row_start += to_next_row;
2172 if (startup_pos_X < cursor_pos_X)
2173 cursor_pos_X = startup_pos_X;
2174 if (startup_pos_Y < cursor_pos_Y)
2175 cursor_pos_Y = startup_pos_Y;
2177 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2178 xfree (startup_screen_buffer);
2179 startup_screen_buffer = NULL;
2181 term_setup_done = 0;
2184 static void
2185 IT_set_terminal_window (struct frame *f, int foo)
2189 /* Remember the screen colors of the curent frame, to serve as the
2190 default colors for newly-created frames. */
2191 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2192 Smsdos_remember_default_colors, 1, 1, 0,
2193 doc: /* Remember the screen colors of the current frame. */)
2194 (frame)
2195 Lisp_Object frame;
2197 struct frame *f;
2199 CHECK_FRAME (frame);
2200 f = XFRAME (frame);
2202 /* This function is called after applying default-frame-alist to the
2203 initial frame. At that time, if reverse-colors option was
2204 specified in default-frame-alist, it was already applied, and
2205 frame colors are reversed. */
2206 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2207 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2210 void
2211 IT_set_frame_parameters (f, alist)
2212 struct frame *f;
2213 Lisp_Object alist;
2215 Lisp_Object tail;
2216 int i, j, length = XINT (Flength (alist));
2217 Lisp_Object *parms
2218 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2219 Lisp_Object *values
2220 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2221 /* Do we have to reverse the foreground and background colors? */
2222 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2223 int need_to_reverse, was_reverse = reverse;
2224 int redraw = 0, fg_set = 0, bg_set = 0;
2225 unsigned long orig_fg, orig_bg;
2226 Lisp_Object frame_bg, frame_fg;
2227 extern Lisp_Object Qdefault, QCforeground, QCbackground;
2228 struct tty_display_info *tty = FRAME_TTY (f);
2230 /* If we are creating a new frame, begin with the original screen colors
2231 used for the initial frame. */
2232 if (EQ (alist, Vdefault_frame_alist)
2233 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2235 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2236 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2237 init_frame_faces (f);
2239 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2240 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2241 frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2242 frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2243 /* frame_fg and frame_bg could be nil if, for example,
2244 f->param_alist is nil, e.g. if we are called from
2245 Fmake_terminal_frame. */
2246 if (NILP (frame_fg))
2247 frame_fg = build_string (unspecified_fg);
2248 if (NILP (frame_bg))
2249 frame_bg = build_string (unspecified_bg);
2251 /* Extract parm names and values into those vectors. */
2252 i = 0;
2253 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2255 Lisp_Object elt;
2257 elt = Fcar (tail);
2258 parms[i] = Fcar (elt);
2259 CHECK_SYMBOL (parms[i]);
2260 values[i] = Fcdr (elt);
2261 i++;
2264 j = i;
2266 for (i = 0; i < j; i++)
2268 Lisp_Object prop, val;
2270 prop = parms[i];
2271 val = values[i];
2273 if (EQ (prop, Qreverse))
2274 reverse = EQ (val, Qt);
2277 need_to_reverse = reverse && !was_reverse;
2278 if (tty->termscript && need_to_reverse)
2279 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2281 /* Now process the alist elements in reverse of specified order. */
2282 for (i--; i >= 0; i--)
2284 Lisp_Object prop, val, frame;
2286 prop = parms[i];
2287 val = values[i];
2289 if (EQ (prop, Qforeground_color))
2291 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2292 ? LFACE_BACKGROUND_INDEX
2293 : LFACE_FOREGROUND_INDEX);
2294 if (new_color != FACE_TTY_DEFAULT_COLOR
2295 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2296 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2298 FRAME_FOREGROUND_PIXEL (f) = new_color;
2299 /* Make sure the foreground of the default face for this
2300 frame is changed as well. */
2301 XSETFRAME (frame, f);
2302 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2303 val, frame);
2304 fg_set = 1;
2305 redraw = 1;
2306 if (tty->termscript)
2307 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2310 else if (EQ (prop, Qbackground_color))
2312 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2313 ? LFACE_FOREGROUND_INDEX
2314 : LFACE_BACKGROUND_INDEX);
2315 if (new_color != FACE_TTY_DEFAULT_COLOR
2316 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2317 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2319 FRAME_BACKGROUND_PIXEL (f) = new_color;
2320 /* Make sure the background of the default face for this
2321 frame is changed as well. */
2322 XSETFRAME (frame, f);
2323 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2324 val, frame);
2325 bg_set = 1;
2326 redraw = 1;
2327 if (tty->termscript)
2328 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2331 else if (EQ (prop, Qtitle))
2333 x_set_title (f, val);
2334 if (tty->termscript)
2335 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2337 else if (EQ (prop, Qcursor_type))
2339 IT_set_cursor_type (f, val);
2340 if (tty->termscript)
2341 fprintf (tty->termscript, "<CTYPE: %s>\n",
2342 EQ (val, Qbar) || EQ (val, Qhbar)
2343 || CONSP (val) && (EQ (XCAR (val), Qbar)
2344 || EQ (XCAR (val), Qhbar))
2345 ? "bar" : "box");
2347 else if (EQ (prop, Qtty_type))
2349 internal_terminal_init ();
2350 if (tty->termscript)
2351 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2352 SBYTES (val), SDATA (val));
2354 store_frame_param (f, prop, val);
2357 /* If they specified "reverse", but not the colors, we need to swap
2358 the current frame colors. */
2359 if (need_to_reverse)
2361 Lisp_Object frame;
2363 if (!fg_set)
2365 XSETFRAME (frame, f);
2366 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2367 tty_color_name (f, orig_bg),
2368 frame);
2369 redraw = 1;
2371 if (!bg_set)
2373 XSETFRAME (frame, f);
2374 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2375 tty_color_name (f, orig_fg),
2376 frame);
2377 redraw = 1;
2381 if (redraw)
2383 face_change_count++; /* forces xdisp.c to recompute basic faces */
2384 if (f == SELECTED_FRAME())
2385 redraw_frame (f);
2389 extern void init_frame_faces (FRAME_PTR);
2391 #endif /* !HAVE_X_WINDOWS */
2394 /* Do we need the internal terminal? */
2396 void
2397 internal_terminal_init ()
2399 static int init_needed = 1;
2400 char *term = getenv ("TERM"), *colors;
2401 struct frame *sf = SELECTED_FRAME();
2402 struct tty_display_info *tty;
2404 #ifdef HAVE_X_WINDOWS
2405 if (!inhibit_window_system)
2406 return;
2407 #endif
2409 /* If this is the initial terminal, we are done here. */
2410 if (sf->output_method == output_initial)
2411 return;
2413 internal_terminal
2414 = (!noninteractive) && term && !strcmp (term, "internal");
2416 #ifndef HAVE_X_WINDOWS
2417 if (!internal_terminal || inhibit_window_system)
2419 sf->output_method = output_termcap;
2420 return;
2423 tty = FRAME_TTY (sf);
2424 current_kboard->Vwindow_system = Qpc;
2425 sf->output_method = output_msdos_raw;
2426 if (init_needed)
2428 if (!tty->termscript && getenv ("EMACSTEST"))
2429 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2430 if (tty->termscript)
2432 time_t now = time (NULL);
2433 struct tm *tnow = localtime (&now);
2434 char tbuf[100];
2436 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2437 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2438 fprintf (tty->termscript, "=====================\n\n");
2441 Vinitial_window_system = Qpc;
2442 Vwindow_system_version = make_number (23); /* RE Emacs version */
2443 tty->terminal->type = output_msdos_raw;
2445 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2446 address. */
2447 screen_old_address = 0;
2449 /* Forget the stale screen colors as well. */
2450 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2452 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2453 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2454 bright_bg ();
2455 colors = getenv ("EMACSCOLORS");
2456 if (colors && strlen (colors) >= 2)
2458 /* The colors use 4 bits each (we enable bright background). */
2459 if (isdigit (colors[0]))
2460 colors[0] -= '0';
2461 else if (isxdigit (colors[0]))
2462 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2463 if (colors[0] >= 0 && colors[0] < 16)
2464 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2465 if (isdigit (colors[1]))
2466 colors[1] -= '0';
2467 else if (isxdigit (colors[1]))
2468 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2469 if (colors[1] >= 0 && colors[1] < 16)
2470 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2472 the_only_display_info.mouse_face_mouse_frame = NULL;
2473 the_only_display_info.mouse_face_deferred_gc = 0;
2474 the_only_display_info.mouse_face_beg_row =
2475 the_only_display_info.mouse_face_beg_col = -1;
2476 the_only_display_info.mouse_face_end_row =
2477 the_only_display_info.mouse_face_end_col = -1;
2478 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2479 the_only_display_info.mouse_face_window = Qnil;
2480 the_only_display_info.mouse_face_mouse_x =
2481 the_only_display_info.mouse_face_mouse_y = 0;
2482 the_only_display_info.mouse_face_defer = 0;
2483 the_only_display_info.mouse_face_hidden = 0;
2485 if (have_mouse) /* detected in dos_ttraw, which see */
2487 have_mouse = 1; /* enable mouse */
2488 mouse_visible = 0;
2489 mouse_setup_buttons (mouse_button_count);
2490 tty->terminal->mouse_position_hook = &mouse_get_pos;
2491 mouse_init ();
2494 if (tty->termscript && screen_size)
2495 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2496 screen_size_X, screen_size_Y);
2498 init_frame_faces (sf);
2499 init_needed = 0;
2501 #endif
2504 void
2505 initialize_msdos_display (struct terminal *term)
2507 term->rif = 0; /* we don't support window-based display */
2508 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2509 term->clear_to_end_hook = IT_clear_to_end;
2510 term->clear_frame_hook = IT_clear_screen;
2511 term->clear_end_of_line_hook = IT_clear_end_of_line;
2512 term->ins_del_lines_hook = 0;
2513 term->insert_glyphs_hook = IT_insert_glyphs;
2514 term->write_glyphs_hook = IT_write_glyphs;
2515 term->delete_glyphs_hook = IT_delete_glyphs;
2516 term->ring_bell_hook = IT_ring_bell;
2517 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2518 term->set_terminal_modes_hook = IT_set_terminal_modes;
2519 term->set_terminal_window_hook = IT_set_terminal_window;
2520 term->update_begin_hook = IT_update_begin;
2521 term->update_end_hook = IT_update_end;
2522 term->frame_up_to_date_hook = IT_frame_up_to_date;
2523 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2524 term->frame_rehighlight_hook = 0;
2525 term->frame_raise_lower_hook = 0;
2526 term->set_vertical_scroll_bar_hook = 0;
2527 term->condemn_scroll_bars_hook = 0;
2528 term->redeem_scroll_bar_hook = 0;
2529 term->judge_scroll_bars_hook = 0;
2530 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2533 dos_get_saved_screen (screen, rows, cols)
2534 char **screen;
2535 int *rows;
2536 int *cols;
2538 #ifndef HAVE_X_WINDOWS
2539 *screen = startup_screen_buffer;
2540 *cols = startup_screen_size_X;
2541 *rows = startup_screen_size_Y;
2542 return *screen != (char *)0;
2543 #else
2544 return 0;
2545 #endif
2548 #ifndef HAVE_X_WINDOWS
2550 /* We are not X, but we can emulate it well enough for our needs... */
2551 void
2552 check_x (void)
2554 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2555 error ("Not running under a window system");
2558 #endif
2561 /* ----------------------- Keyboard control ----------------------
2563 * Keymaps reflect the following keyboard layout:
2565 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2566 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2567 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2568 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2569 * SPACE
2572 #define Ignore 0x0000
2573 #define Normal 0x0000 /* normal key - alt changes scan-code */
2574 #define FctKey 0x1000 /* func key if c == 0, else c */
2575 #define Special 0x2000 /* func key even if c != 0 */
2576 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2577 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2578 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2579 #define Grey 0x6000 /* Grey keypad key */
2581 #define Alt 0x0100 /* alt scan-code */
2582 #define Ctrl 0x0200 /* ctrl scan-code */
2583 #define Shift 0x0400 /* shift scan-code */
2585 static int extended_kbd; /* 101 (102) keyboard present. */
2587 struct kbd_translate {
2588 unsigned char sc;
2589 unsigned char ch;
2590 unsigned short code;
2593 struct dos_keyboard_map
2595 char *unshifted;
2596 char *shifted;
2597 char *alt_gr;
2598 struct kbd_translate *translate_table;
2602 static struct dos_keyboard_map us_keyboard = {
2603 /* 0 1 2 3 4 5 */
2604 /* 01234567890123456789012345678901234567890 12345678901234 */
2605 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2606 /* 0123456789012345678901234567890123456789 012345678901234 */
2607 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2608 0, /* no Alt-Gr key */
2609 0 /* no translate table */
2612 static struct dos_keyboard_map fr_keyboard = {
2613 /* 0 1 2 3 4 5 */
2614 /* 012 3456789012345678901234567890123456789012345678901234 */
2615 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2616 /* 0123456789012345678901234567890123456789012345678901234 */
2617 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2618 /* 01234567 89012345678901234567890123456789012345678901234 */
2619 " ~#{[|`\\^@]} Ï ",
2620 0 /* no translate table */
2624 * Italian keyboard support, country code 39.
2625 * '<' 56:3c*0000
2626 * '>' 56:3e*0000
2627 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2628 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2631 static struct kbd_translate it_kbd_translate_table[] = {
2632 { 0x56, 0x3c, Normal | 13 },
2633 { 0x56, 0x3e, Normal | 27 },
2634 { 0, 0, 0 }
2636 static struct dos_keyboard_map it_keyboard = {
2637 /* 0 1 2 3 4 5 */
2638 /* 0 123456789012345678901234567890123456789012345678901234 */
2639 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2640 /* 01 23456789012345678901234567890123456789012345678901234 */
2641 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2642 /* 0123456789012345678901234567890123456789012345678901234 */
2643 " {}~` [] @# ",
2644 it_kbd_translate_table
2647 static struct dos_keyboard_map dk_keyboard = {
2648 /* 0 1 2 3 4 5 */
2649 /* 0123456789012345678901234567890123456789012345678901234 */
2650 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2651 /* 01 23456789012345678901234567890123456789012345678901234 */
2652 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2653 /* 0123456789012345678901234567890123456789012345678901234 */
2654 " @œ$ {[]} | ",
2655 0 /* no translate table */
2658 static struct kbd_translate jp_kbd_translate_table[] = {
2659 { 0x73, 0x5c, Normal | 0 },
2660 { 0x73, 0x5f, Normal | 0 },
2661 { 0x73, 0x1c, Map | 0 },
2662 { 0x7d, 0x5c, Normal | 13 },
2663 { 0x7d, 0x7c, Normal | 13 },
2664 { 0x7d, 0x1c, Map | 13 },
2665 { 0, 0, 0 }
2667 static struct dos_keyboard_map jp_keyboard = {
2668 /* 0 1 2 3 4 5 */
2669 /* 0123456789012 345678901234567890123456789012345678901234 */
2670 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2671 /* 01 23456789012345678901234567890123456789012345678901234 */
2672 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2673 0, /* no Alt-Gr key */
2674 jp_kbd_translate_table
2677 static struct keyboard_layout_list
2679 int country_code;
2680 struct dos_keyboard_map *keyboard_map;
2681 } keyboard_layout_list[] =
2683 1, &us_keyboard,
2684 33, &fr_keyboard,
2685 39, &it_keyboard,
2686 45, &dk_keyboard,
2687 81, &jp_keyboard
2690 static struct dos_keyboard_map *keyboard;
2691 static int keyboard_map_all;
2692 static int international_keyboard;
2695 dos_set_keyboard (code, always)
2696 int code;
2697 int always;
2699 int i;
2700 _go32_dpmi_registers regs;
2702 /* See if Keyb.Com is installed (for international keyboard support).
2703 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2704 of Windows 9X! So don't do that! */
2705 regs.x.ax = 0xad80;
2706 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2707 _go32_dpmi_simulate_int (0x2f, &regs);
2708 if (regs.h.al == 0xff)
2709 international_keyboard = 1;
2711 /* Initialize to US settings, for countries that don't have their own. */
2712 keyboard = keyboard_layout_list[0].keyboard_map;
2713 keyboard_map_all = always;
2714 dos_keyboard_layout = 1;
2716 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2717 if (code == keyboard_layout_list[i].country_code)
2719 keyboard = keyboard_layout_list[i].keyboard_map;
2720 keyboard_map_all = always;
2721 dos_keyboard_layout = code;
2722 return 1;
2724 return 0;
2727 static struct
2729 unsigned char char_code; /* normal code */
2730 unsigned char meta_code; /* M- code */
2731 unsigned char keypad_code; /* keypad code */
2732 unsigned char editkey_code; /* edit key */
2733 } keypad_translate_map[] = {
2734 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2735 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2736 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2737 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2738 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2739 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2740 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2741 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2742 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2743 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2744 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2747 static struct
2749 unsigned char char_code; /* normal code */
2750 unsigned char keypad_code; /* keypad code */
2751 } grey_key_translate_map[] = {
2752 '/', 0xaf, /* kp-decimal */
2753 '*', 0xaa, /* kp-multiply */
2754 '-', 0xad, /* kp-subtract */
2755 '+', 0xab, /* kp-add */
2756 '\r', 0x8d /* kp-enter */
2759 static unsigned short
2760 ibmpc_translate_map[] =
2762 /* --------------- 00 to 0f --------------- */
2763 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2764 Alt | ModFct | 0x1b, /* Escape */
2765 Normal | 1, /* '1' */
2766 Normal | 2, /* '2' */
2767 Normal | 3, /* '3' */
2768 Normal | 4, /* '4' */
2769 Normal | 5, /* '5' */
2770 Normal | 6, /* '6' */
2771 Normal | 7, /* '7' */
2772 Normal | 8, /* '8' */
2773 Normal | 9, /* '9' */
2774 Normal | 10, /* '0' */
2775 Normal | 11, /* '-' */
2776 Normal | 12, /* '=' */
2777 Special | 0x08, /* Backspace */
2778 ModFct | 0x74, /* Tab/Backtab */
2780 /* --------------- 10 to 1f --------------- */
2781 Map | 15, /* 'q' */
2782 Map | 16, /* 'w' */
2783 Map | 17, /* 'e' */
2784 Map | 18, /* 'r' */
2785 Map | 19, /* 't' */
2786 Map | 20, /* 'y' */
2787 Map | 21, /* 'u' */
2788 Map | 22, /* 'i' */
2789 Map | 23, /* 'o' */
2790 Map | 24, /* 'p' */
2791 Map | 25, /* '[' */
2792 Map | 26, /* ']' */
2793 ModFct | 0x0d, /* Return */
2794 Ignore, /* Ctrl */
2795 Map | 30, /* 'a' */
2796 Map | 31, /* 's' */
2798 /* --------------- 20 to 2f --------------- */
2799 Map | 32, /* 'd' */
2800 Map | 33, /* 'f' */
2801 Map | 34, /* 'g' */
2802 Map | 35, /* 'h' */
2803 Map | 36, /* 'j' */
2804 Map | 37, /* 'k' */
2805 Map | 38, /* 'l' */
2806 Map | 39, /* ';' */
2807 Map | 40, /* '\'' */
2808 Map | 0, /* '`' */
2809 Ignore, /* Left shift */
2810 Map | 41, /* '\\' */
2811 Map | 45, /* 'z' */
2812 Map | 46, /* 'x' */
2813 Map | 47, /* 'c' */
2814 Map | 48, /* 'v' */
2816 /* --------------- 30 to 3f --------------- */
2817 Map | 49, /* 'b' */
2818 Map | 50, /* 'n' */
2819 Map | 51, /* 'm' */
2820 Map | 52, /* ',' */
2821 Map | 53, /* '.' */
2822 Map | 54, /* '/' */
2823 Ignore, /* Right shift */
2824 Grey | 1, /* Grey * */
2825 Ignore, /* Alt */
2826 Normal | 55, /* ' ' */
2827 Ignore, /* Caps Lock */
2828 FctKey | 0xbe, /* F1 */
2829 FctKey | 0xbf, /* F2 */
2830 FctKey | 0xc0, /* F3 */
2831 FctKey | 0xc1, /* F4 */
2832 FctKey | 0xc2, /* F5 */
2834 /* --------------- 40 to 4f --------------- */
2835 FctKey | 0xc3, /* F6 */
2836 FctKey | 0xc4, /* F7 */
2837 FctKey | 0xc5, /* F8 */
2838 FctKey | 0xc6, /* F9 */
2839 FctKey | 0xc7, /* F10 */
2840 Ignore, /* Num Lock */
2841 Ignore, /* Scroll Lock */
2842 KeyPad | 7, /* Home */
2843 KeyPad | 8, /* Up */
2844 KeyPad | 9, /* Page Up */
2845 Grey | 2, /* Grey - */
2846 KeyPad | 4, /* Left */
2847 KeyPad | 5, /* Keypad 5 */
2848 KeyPad | 6, /* Right */
2849 Grey | 3, /* Grey + */
2850 KeyPad | 1, /* End */
2852 /* --------------- 50 to 5f --------------- */
2853 KeyPad | 2, /* Down */
2854 KeyPad | 3, /* Page Down */
2855 KeyPad | 0, /* Insert */
2856 KeyPad | 10, /* Delete */
2857 Shift | FctKey | 0xbe, /* (Shift) F1 */
2858 Shift | FctKey | 0xbf, /* (Shift) F2 */
2859 Shift | FctKey | 0xc0, /* (Shift) F3 */
2860 Shift | FctKey | 0xc1, /* (Shift) F4 */
2861 Shift | FctKey | 0xc2, /* (Shift) F5 */
2862 Shift | FctKey | 0xc3, /* (Shift) F6 */
2863 Shift | FctKey | 0xc4, /* (Shift) F7 */
2864 Shift | FctKey | 0xc5, /* (Shift) F8 */
2865 Shift | FctKey | 0xc6, /* (Shift) F9 */
2866 Shift | FctKey | 0xc7, /* (Shift) F10 */
2867 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2868 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2870 /* --------------- 60 to 6f --------------- */
2871 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2872 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2873 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2874 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2875 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2876 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2877 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2878 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2879 Alt | FctKey | 0xbe, /* (Alt) F1 */
2880 Alt | FctKey | 0xbf, /* (Alt) F2 */
2881 Alt | FctKey | 0xc0, /* (Alt) F3 */
2882 Alt | FctKey | 0xc1, /* (Alt) F4 */
2883 Alt | FctKey | 0xc2, /* (Alt) F5 */
2884 Alt | FctKey | 0xc3, /* (Alt) F6 */
2885 Alt | FctKey | 0xc4, /* (Alt) F7 */
2886 Alt | FctKey | 0xc5, /* (Alt) F8 */
2888 /* --------------- 70 to 7f --------------- */
2889 Alt | FctKey | 0xc6, /* (Alt) F9 */
2890 Alt | FctKey | 0xc7, /* (Alt) F10 */
2891 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2892 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2893 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2894 Ctrl | KeyPad | 1, /* (Ctrl) End */
2895 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2896 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2897 Alt | Map | 1, /* '1' */
2898 Alt | Map | 2, /* '2' */
2899 Alt | Map | 3, /* '3' */
2900 Alt | Map | 4, /* '4' */
2901 Alt | Map | 5, /* '5' */
2902 Alt | Map | 6, /* '6' */
2903 Alt | Map | 7, /* '7' */
2904 Alt | Map | 8, /* '8' */
2906 /* --------------- 80 to 8f --------------- */
2907 Alt | Map | 9, /* '9' */
2908 Alt | Map | 10, /* '0' */
2909 Alt | Map | 11, /* '-' */
2910 Alt | Map | 12, /* '=' */
2911 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
2912 FctKey | 0xc8, /* F11 */
2913 FctKey | 0xc9, /* F12 */
2914 Shift | FctKey | 0xc8, /* (Shift) F11 */
2915 Shift | FctKey | 0xc9, /* (Shift) F12 */
2916 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
2917 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
2918 Alt | FctKey | 0xc8, /* (Alt) F11 */
2919 Alt | FctKey | 0xc9, /* (Alt) F12 */
2920 Ctrl | KeyPad | 8, /* (Ctrl) Up */
2921 Ctrl | Grey | 2, /* (Ctrl) Grey - */
2922 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
2924 /* --------------- 90 to 9f --------------- */
2925 Ctrl | Grey | 3, /* (Ctrl) Grey + */
2926 Ctrl | KeyPad | 2, /* (Ctrl) Down */
2927 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
2928 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
2929 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
2930 Ctrl | Grey | 0, /* (Ctrl) Grey / */
2931 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2932 Alt | FctKey | 0x50, /* (Alt) Home */
2933 Alt | FctKey | 0x52, /* (Alt) Up */
2934 Alt | FctKey | 0x55, /* (Alt) Page Up */
2935 Ignore, /* NO KEY */
2936 Alt | FctKey | 0x51, /* (Alt) Left */
2937 Ignore, /* NO KEY */
2938 Alt | FctKey | 0x53, /* (Alt) Right */
2939 Ignore, /* NO KEY */
2940 Alt | FctKey | 0x57, /* (Alt) End */
2942 /* --------------- a0 to af --------------- */
2943 Alt | KeyPad | 2, /* (Alt) Down */
2944 Alt | KeyPad | 3, /* (Alt) Page Down */
2945 Alt | KeyPad | 0, /* (Alt) Insert */
2946 Alt | KeyPad | 10, /* (Alt) Delete */
2947 Alt | Grey | 0, /* (Alt) Grey / */
2948 Alt | FctKey | 0x09, /* (Alt) Tab */
2949 Alt | Grey | 4 /* (Alt) Keypad Enter */
2952 /* These bit-positions corresponds to values returned by BIOS */
2953 #define SHIFT_P 0x0003 /* two bits! */
2954 #define CTRL_P 0x0004
2955 #define ALT_P 0x0008
2956 #define SCRLOCK_P 0x0010
2957 #define NUMLOCK_P 0x0020
2958 #define CAPSLOCK_P 0x0040
2959 #define ALT_GR_P 0x0800
2960 #define SUPER_P 0x4000 /* pseudo */
2961 #define HYPER_P 0x8000 /* pseudo */
2963 static int
2964 dos_get_modifiers (keymask)
2965 int *keymask;
2967 union REGS regs;
2968 int mask, modifiers = 0;
2970 /* Calculate modifier bits */
2971 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2972 int86 (0x16, &regs, &regs);
2974 if (!extended_kbd)
2976 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2977 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2979 else
2981 mask = regs.h.al & (SHIFT_P |
2982 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2984 /* Do not break international keyboard support. */
2985 /* When Keyb.Com is loaded, the right Alt key is */
2986 /* used for accessing characters like { and } */
2987 if (regs.h.ah & 2) /* Left ALT pressed ? */
2988 mask |= ALT_P;
2990 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2992 mask |= ALT_GR_P;
2993 if (dos_hyper_key == 1)
2995 mask |= HYPER_P;
2996 modifiers |= hyper_modifier;
2998 else if (dos_super_key == 1)
3000 mask |= SUPER_P;
3001 modifiers |= super_modifier;
3003 else if (!international_keyboard)
3005 /* If Keyb.Com is NOT installed, let Right Alt behave
3006 like the Left Alt. */
3007 mask &= ~ALT_GR_P;
3008 mask |= ALT_P;
3012 if (regs.h.ah & 1) /* Left CTRL pressed ? */
3013 mask |= CTRL_P;
3015 if (regs.h.ah & 4) /* Right CTRL pressed ? */
3017 if (dos_hyper_key == 2)
3019 mask |= HYPER_P;
3020 modifiers |= hyper_modifier;
3022 else if (dos_super_key == 2)
3024 mask |= SUPER_P;
3025 modifiers |= super_modifier;
3027 else
3028 mask |= CTRL_P;
3032 if (mask & SHIFT_P)
3033 modifiers |= shift_modifier;
3034 if (mask & CTRL_P)
3035 modifiers |= ctrl_modifier;
3036 if (mask & ALT_P)
3037 modifiers |= meta_modifier;
3039 if (keymask)
3040 *keymask = mask;
3041 return modifiers;
3044 #define NUM_RECENT_DOSKEYS (100)
3045 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
3046 int total_doskeys; /* Total number of elements stored into recent_doskeys */
3047 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
3049 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
3050 doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3051 Each input key receives two values in this vector: first the ASCII code,
3052 and then the scan code. */)
3055 Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
3057 if (total_doskeys < NUM_RECENT_DOSKEYS)
3058 return Fvector (total_doskeys, keys);
3059 else
3061 val = Fvector (NUM_RECENT_DOSKEYS, keys);
3062 bcopy (keys + recent_doskeys_index,
3063 XVECTOR (val)->contents,
3064 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
3065 bcopy (keys,
3066 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
3067 recent_doskeys_index * sizeof (Lisp_Object));
3068 return val;
3072 /* Get a char from keyboard. Function keys are put into the event queue. */
3073 static int
3074 dos_rawgetc ()
3076 struct input_event event;
3077 union REGS regs;
3078 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3079 EVENT_INIT (event);
3081 #ifndef HAVE_X_WINDOWS
3082 /* Maybe put the cursor where it should be. */
3083 IT_cmgoto (SELECTED_FRAME());
3084 #endif
3086 /* The following condition is equivalent to `kbhit ()', except that
3087 it uses the bios to do its job. This pleases DESQview/X. */
3088 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
3089 int86 (0x16, &regs, &regs),
3090 (regs.x.flags & 0x40) == 0)
3092 union REGS regs;
3093 register unsigned char c;
3094 int modifiers, sc, code = -1, mask, kp_mode;
3096 regs.h.ah = extended_kbd ? 0x10 : 0x00;
3097 int86 (0x16, &regs, &regs);
3098 c = regs.h.al;
3099 sc = regs.h.ah;
3101 total_doskeys += 2;
3102 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3103 = make_number (c);
3104 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3105 recent_doskeys_index = 0;
3106 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3107 = make_number (sc);
3108 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3109 recent_doskeys_index = 0;
3111 modifiers = dos_get_modifiers (&mask);
3113 #ifndef HAVE_X_WINDOWS
3114 if (!NILP (Vdos_display_scancodes))
3116 char buf[11];
3117 sprintf (buf, "%02x:%02x*%04x",
3118 (unsigned) (sc&0xff), (unsigned) c, mask);
3119 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
3121 #endif
3123 if (sc == 0xe0)
3125 switch (c)
3127 case 10: /* Ctrl Grey Enter */
3128 code = Ctrl | Grey | 4;
3129 break;
3130 case 13: /* Grey Enter */
3131 code = Grey | 4;
3132 break;
3133 case '/': /* Grey / */
3134 code = Grey | 0;
3135 break;
3136 default:
3137 continue;
3139 c = 0;
3141 else
3143 /* Try the keyboard-private translation table first. */
3144 if (keyboard->translate_table)
3146 struct kbd_translate *p = keyboard->translate_table;
3148 while (p->sc)
3150 if (p->sc == sc && p->ch == c)
3152 code = p->code;
3153 break;
3155 p++;
3158 /* If the private table didn't translate it, use the general
3159 one. */
3160 if (code == -1)
3162 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3163 continue;
3164 if ((code = ibmpc_translate_map[sc]) == Ignore)
3165 continue;
3169 if (c == 0)
3171 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3172 Emacs is ready to read a key. Therefore, if they press
3173 `Alt-x' when Emacs is busy, by the time we get to
3174 `dos_get_modifiers', they might have already released the
3175 Alt key, and Emacs gets just `x', which is BAD.
3176 However, for keys with the `Map' property set, the ASCII
3177 code returns zero only if Alt is pressed. So, when we DON'T
3178 have to support international_keyboard, we don't have to
3179 distinguish between the left and right Alt keys, and we
3180 can set the META modifier for any keys with the `Map'
3181 property if they return zero ASCII code (c = 0). */
3182 if ( (code & Alt)
3183 || ( (code & 0xf000) == Map && !international_keyboard))
3184 modifiers |= meta_modifier;
3185 if (code & Ctrl)
3186 modifiers |= ctrl_modifier;
3187 if (code & Shift)
3188 modifiers |= shift_modifier;
3191 switch (code & 0xf000)
3193 case ModFct:
3194 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3195 return c;
3196 c = 0; /* Special */
3198 case FctKey:
3199 if (c != 0)
3200 return c;
3202 case Special:
3203 code |= 0xff00;
3204 break;
3206 case Normal:
3207 if (sc == 0)
3209 if (c == 0) /* ctrl-break */
3210 continue;
3211 return c; /* ALT-nnn */
3213 if (!keyboard_map_all)
3215 if (c != ' ')
3216 return c;
3217 code = c;
3218 break;
3221 case Map:
3222 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3223 if (!keyboard_map_all)
3224 return c;
3226 code &= 0xff;
3227 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3228 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3230 if (mask & SHIFT_P)
3232 code = keyboard->shifted[code];
3233 mask -= SHIFT_P;
3234 modifiers &= ~shift_modifier;
3236 else
3237 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3238 code = keyboard->alt_gr[code];
3239 else
3240 code = keyboard->unshifted[code];
3241 break;
3243 case KeyPad:
3244 code &= 0xff;
3245 if (c == 0xe0) /* edit key */
3246 kp_mode = 3;
3247 else
3248 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3249 kp_mode = dos_keypad_mode & 0x03;
3250 else
3251 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3253 switch (kp_mode)
3255 case 0:
3256 if (code == 10 && dos_decimal_point)
3257 return dos_decimal_point;
3258 return keypad_translate_map[code].char_code;
3260 case 1:
3261 code = 0xff00 | keypad_translate_map[code].keypad_code;
3262 break;
3264 case 2:
3265 code = keypad_translate_map[code].meta_code;
3266 modifiers = meta_modifier;
3267 break;
3269 case 3:
3270 code = 0xff00 | keypad_translate_map[code].editkey_code;
3271 break;
3273 break;
3275 case Grey:
3276 code &= 0xff;
3277 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3278 if (dos_keypad_mode & kp_mode)
3279 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3280 else
3281 code = grey_key_translate_map[code].char_code;
3282 break;
3285 make_event:
3286 if (code == 0)
3287 continue;
3289 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3291 clear_mouse_face (dpyinfo);
3292 dpyinfo->mouse_face_hidden = 1;
3295 if (code >= 0x100)
3296 event.kind = NON_ASCII_KEYSTROKE_EVENT;
3297 else
3298 event.kind = ASCII_KEYSTROKE_EVENT;
3299 event.code = code;
3300 event.modifiers = modifiers;
3301 event.frame_or_window = selected_frame;
3302 event.arg = Qnil;
3303 event.timestamp = event_timestamp ();
3304 kbd_buffer_store_event (&event);
3307 if (have_mouse > 0 && !mouse_preempted)
3309 int but, press, x, y, ok;
3310 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3311 Lisp_Object mouse_window = Qnil;
3313 /* Check for mouse movement *before* buttons. */
3314 mouse_check_moved ();
3316 /* If the mouse moved from the spot of its last sighting, we
3317 might need to update mouse highlight. */
3318 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3320 if (dpyinfo->mouse_face_hidden)
3322 dpyinfo->mouse_face_hidden = 0;
3323 clear_mouse_face (dpyinfo);
3326 /* Generate SELECT_WINDOW_EVENTs when needed. */
3327 if (!NILP (Vmouse_autoselect_window))
3329 mouse_window = window_from_coordinates (SELECTED_FRAME(),
3330 mouse_last_x,
3331 mouse_last_y,
3332 0, 0, 0, 0);
3333 /* A window will be selected only when it is not
3334 selected now, and the last mouse movement event was
3335 not in it. A minibuffer window will be selected iff
3336 it is active. */
3337 if (WINDOWP (mouse_window)
3338 && !EQ (mouse_window, last_mouse_window)
3339 && !EQ (mouse_window, selected_window))
3341 event.kind = SELECT_WINDOW_EVENT;
3342 event.frame_or_window = mouse_window;
3343 event.arg = Qnil;
3344 event.timestamp = event_timestamp ();
3345 kbd_buffer_store_event (&event);
3347 last_mouse_window = mouse_window;
3349 else
3350 last_mouse_window = Qnil;
3352 previous_help_echo_string = help_echo_string;
3353 help_echo_string = help_echo_object = help_echo_window = Qnil;
3354 help_echo_pos = -1;
3355 IT_note_mouse_highlight (SELECTED_FRAME(),
3356 mouse_last_x, mouse_last_y);
3357 /* If the contents of the global variable help_echo has
3358 changed, generate a HELP_EVENT. */
3359 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3361 event.kind = HELP_EVENT;
3362 event.frame_or_window = selected_frame;
3363 event.arg = help_echo_object;
3364 event.x = WINDOWP (help_echo_window)
3365 ? help_echo_window : selected_frame;
3366 event.y = help_echo_string;
3367 event.timestamp = event_timestamp ();
3368 event.code = help_echo_pos;
3369 kbd_buffer_store_event (&event);
3373 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3374 for (press = 0; press < 2; press++)
3376 int button_num = but;
3378 if (press)
3379 ok = mouse_pressed (but, &x, &y);
3380 else
3381 ok = mouse_released (but, &x, &y);
3382 if (ok)
3384 /* Allow a simultaneous press/release of Mouse-1 and
3385 Mouse-2 to simulate Mouse-3 on two-button mice. */
3386 if (mouse_button_count == 2 && but < 2)
3388 int x2, y2; /* don't clobber original coordinates */
3390 /* If only one button is pressed, wait 100 msec and
3391 check again. This way, Speedy Gonzales isn't
3392 punished, while the slow get their chance. */
3393 if (press && mouse_pressed (1-but, &x2, &y2)
3394 || !press && mouse_released (1-but, &x2, &y2))
3395 button_num = 2;
3396 else
3398 delay (100);
3399 if (press && mouse_pressed (1-but, &x2, &y2)
3400 || !press && mouse_released (1-but, &x2, &y2))
3401 button_num = 2;
3405 event.kind = MOUSE_CLICK_EVENT;
3406 event.code = button_num;
3407 event.modifiers = dos_get_modifiers (0)
3408 | (press ? down_modifier : up_modifier);
3409 event.x = make_number (x);
3410 event.y = make_number (y);
3411 event.frame_or_window = selected_frame;
3412 event.arg = Qnil;
3413 event.timestamp = event_timestamp ();
3414 kbd_buffer_store_event (&event);
3419 return -1;
3422 static int prev_get_char = -1;
3424 /* Return 1 if a key is ready to be read without suspending execution. */
3426 dos_keysns ()
3428 if (prev_get_char != -1)
3429 return 1;
3430 else
3431 return ((prev_get_char = dos_rawgetc ()) != -1);
3434 /* Read a key. Return -1 if no key is ready. */
3436 dos_keyread ()
3438 if (prev_get_char != -1)
3440 int c = prev_get_char;
3441 prev_get_char = -1;
3442 return c;
3444 else
3445 return dos_rawgetc ();
3448 #ifndef HAVE_X_WINDOWS
3450 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3451 for now.
3453 Actually, I don't know the meaning of all the parameters of the functions
3454 here -- I only know how they are called by xmenu.c. I could of course
3455 grab the nearest Xlib manual (down the hall, second-to-last door on the
3456 left), but I don't think it's worth the effort. */
3458 /* These hold text of the current and the previous menu help messages. */
3459 static char *menu_help_message, *prev_menu_help_message;
3460 /* Pane number and item number of the menu item which generated the
3461 last menu help message. */
3462 static int menu_help_paneno, menu_help_itemno;
3464 static XMenu *
3465 IT_menu_create ()
3467 XMenu *menu;
3469 menu = (XMenu *) xmalloc (sizeof (XMenu));
3470 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3471 return menu;
3474 /* Allocate some (more) memory for MENU ensuring that there is room for one
3475 for item. */
3477 static void
3478 IT_menu_make_room (XMenu *menu)
3480 if (menu->allocated == 0)
3482 int count = menu->allocated = 10;
3483 menu->text = (char **) xmalloc (count * sizeof (char *));
3484 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3485 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3486 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3488 else if (menu->allocated == menu->count)
3490 int count = menu->allocated = menu->allocated + 10;
3491 menu->text
3492 = (char **) xrealloc (menu->text, count * sizeof (char *));
3493 menu->submenu
3494 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3495 menu->panenumber
3496 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3497 menu->help_text
3498 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3502 /* Search the given menu structure for a given pane number. */
3504 static XMenu *
3505 IT_menu_search_pane (XMenu *menu, int pane)
3507 int i;
3508 XMenu *try;
3510 for (i = 0; i < menu->count; i++)
3511 if (menu->submenu[i])
3513 if (pane == menu->panenumber[i])
3514 return menu->submenu[i];
3515 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3516 return try;
3518 return (XMenu *) 0;
3521 /* Determine how much screen space a given menu needs. */
3523 static void
3524 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3526 int i, h2, w2, maxsubwidth, maxheight;
3528 maxsubwidth = 0;
3529 maxheight = menu->count;
3530 for (i = 0; i < menu->count; i++)
3532 if (menu->submenu[i])
3534 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3535 if (w2 > maxsubwidth) maxsubwidth = w2;
3536 if (i + h2 > maxheight) maxheight = i + h2;
3539 *width = menu->width + maxsubwidth;
3540 *height = maxheight;
3543 /* Display MENU at (X,Y) using FACES. */
3545 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3546 do \
3548 (GLYPH).type = CHAR_GLYPH; \
3549 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3550 (GLYPH).charpos = -1; \
3552 while (0)
3554 static void
3555 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3557 int i, j, face, width, mx, my, enabled, mousehere, row, col;
3558 struct glyph *text, *p;
3559 const unsigned char *q;
3560 struct frame *sf = SELECTED_FRAME();
3562 menu_help_message = NULL;
3564 width = menu->width;
3565 /* We multiply width by 2 to account for possible control characters.
3566 FIXME: cater to non-ASCII characters in menus. */
3567 text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3568 ScreenGetCursor (&row, &col);
3569 mouse_get_xy (&mx, &my);
3570 IT_update_begin (sf);
3571 for (i = 0; i < menu->count; i++)
3573 int max_width = width + 2;
3575 IT_cursor_to (sf, y + i, x);
3576 enabled
3577 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3578 mousehere = (y + i == my && x <= mx && mx < x + max_width);
3579 face = faces[enabled + mousehere * 2];
3580 /* The following if clause means that we display the menu help
3581 strings even if the menu item is currently disabled. */
3582 if (disp_help && enabled + mousehere * 2 >= 2)
3584 menu_help_message = menu->help_text[i];
3585 menu_help_paneno = pn - 1;
3586 menu_help_itemno = i;
3588 p = text;
3589 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3590 p++;
3591 for (j = 0, q = menu->text[i]; *q; j++)
3593 unsigned c = STRING_CHAR_ADVANCE (q);
3595 if (c > 26)
3597 BUILD_CHAR_GLYPH (*p, c, face, 0);
3598 p++;
3600 else /* make '^x' */
3602 BUILD_CHAR_GLYPH (*p, '^', face, 0);
3603 p++;
3604 j++;
3605 BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3606 p++;
3609 /* Don't let the menu text overflow into the next screen row. */
3610 if (x + max_width > screen_size_X)
3612 max_width = screen_size_X - x;
3613 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3615 for (; j < max_width - 2; j++, p++)
3616 BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3618 /* 16 is the character code of a character that on DOS terminal
3619 produces a nice-looking right-pointing arrow glyph. */
3620 BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3621 p++;
3622 IT_write_glyphs (sf, text, max_width);
3624 IT_update_end (sf);
3625 IT_cursor_to (sf, row, col);
3626 xfree (text);
3629 /* --------------------------- X Menu emulation ---------------------- */
3631 /* Report availability of menus. */
3634 have_menus_p () { return 1; }
3636 /* Create a brand new menu structure. */
3638 XMenu *
3639 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3641 return IT_menu_create ();
3644 /* Create a new pane and place it on the outer-most level. It is not
3645 clear that it should be placed out there, but I don't know what else
3646 to do. */
3649 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3651 int len;
3652 char *p;
3654 if (!enable)
3655 abort ();
3657 IT_menu_make_room (menu);
3658 menu->submenu[menu->count] = IT_menu_create ();
3659 menu->text[menu->count] = txt;
3660 menu->panenumber[menu->count] = ++menu->panecount;
3661 menu->help_text[menu->count] = NULL;
3662 menu->count++;
3664 /* Adjust length for possible control characters (which will
3665 be written as ^x). */
3666 for (len = strlen (txt), p = txt; *p; p++)
3667 if (*p < 27)
3668 len++;
3670 if (len > menu->width)
3671 menu->width = len;
3673 return menu->panecount;
3676 /* Create a new item in a menu pane. */
3679 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3680 int foo, char *txt, int enable, char *help_text)
3682 int len;
3683 char *p;
3685 if (pane)
3686 if (!(menu = IT_menu_search_pane (menu, pane)))
3687 return XM_FAILURE;
3688 IT_menu_make_room (menu);
3689 menu->submenu[menu->count] = (XMenu *) 0;
3690 menu->text[menu->count] = txt;
3691 menu->panenumber[menu->count] = enable;
3692 menu->help_text[menu->count] = help_text;
3693 menu->count++;
3695 /* Adjust length for possible control characters (which will
3696 be written as ^x). */
3697 for (len = strlen (txt), p = txt; *p; p++)
3698 if (*p < 27)
3699 len++;
3701 if (len > menu->width)
3702 menu->width = len;
3704 return XM_SUCCESS;
3707 /* Decide where the menu would be placed if requested at (X,Y). */
3709 void
3710 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3711 int *ulx, int *uly, int *width, int *height)
3713 IT_menu_calc_size (menu, width, height);
3714 *ulx = x + 1;
3715 *uly = y;
3716 *width += 2;
3719 struct IT_menu_state
3721 void *screen_behind;
3722 XMenu *menu;
3723 int pane;
3724 int x, y;
3728 /* Display menu, wait for user's response, and return that response. */
3731 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3732 int x0, int y0, unsigned ButtonMask, char **txt,
3733 void (*help_callback)(char *, int, int))
3735 struct IT_menu_state *state;
3736 int statecount, x, y, i, b, screensize, leave, result, onepane;
3737 int title_faces[4]; /* face to display the menu title */
3738 int faces[4], buffers_num_deleted = 0;
3739 struct frame *sf = SELECTED_FRAME();
3740 Lisp_Object saved_echo_area_message, selectface;
3742 /* Just in case we got here without a mouse present... */
3743 if (have_mouse <= 0)
3744 return XM_IA_SELECT;
3745 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3746 around the display. */
3747 if (x0 <= 0)
3748 x0 = 1;
3749 if (y0 <= 0)
3750 y0 = 1;
3752 /* We will process all the mouse events directly, so we had
3753 better prevent dos_rawgetc from stealing them from us. */
3754 mouse_preempted++;
3756 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3757 screensize = screen_size * 2;
3758 faces[0]
3759 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3760 DEFAULT_FACE_ID, 1);
3761 faces[1]
3762 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3763 DEFAULT_FACE_ID, 1);
3764 selectface = intern ("msdos-menu-select-face");
3765 faces[2] = lookup_derived_face (sf, selectface,
3766 faces[0], 1);
3767 faces[3] = lookup_derived_face (sf, selectface,
3768 faces[1], 1);
3770 /* Make sure the menu title is always displayed with
3771 `msdos-menu-active-face', no matter where the mouse pointer is. */
3772 for (i = 0; i < 4; i++)
3773 title_faces[i] = faces[3];
3775 statecount = 1;
3777 /* Don't let the title for the "Buffers" popup menu include a
3778 digit (which is ugly).
3780 This is a terrible kludge, but I think the "Buffers" case is
3781 the only one where the title includes a number, so it doesn't
3782 seem to be necessary to make this more general. */
3783 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3785 menu->text[0][7] = '\0';
3786 buffers_num_deleted = 1;
3789 /* We need to save the current echo area message, so that we could
3790 restore it below, before we exit. See the commentary below,
3791 before the call to message_with_string. */
3792 saved_echo_area_message = Fcurrent_message ();
3793 state[0].menu = menu;
3794 mouse_off ();
3795 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3797 /* Turn off the cursor. Otherwise it shows through the menu
3798 panes, which is ugly. */
3799 IT_display_cursor (0);
3801 /* Display the menu title. */
3802 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3803 if (buffers_num_deleted)
3804 menu->text[0][7] = ' ';
3805 if ((onepane = menu->count == 1 && menu->submenu[0]))
3807 menu->width = menu->submenu[0]->width;
3808 state[0].menu = menu->submenu[0];
3810 else
3812 state[0].menu = menu;
3814 state[0].x = x0 - 1;
3815 state[0].y = y0;
3816 state[0].pane = onepane;
3818 mouse_last_x = -1; /* A hack that forces display. */
3819 leave = 0;
3820 while (!leave)
3822 if (!mouse_visible) mouse_on ();
3823 mouse_check_moved ();
3824 if (sf->mouse_moved)
3826 sf->mouse_moved = 0;
3827 result = XM_IA_SELECT;
3828 mouse_get_xy (&x, &y);
3829 for (i = 0; i < statecount; i++)
3830 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3832 int dy = y - state[i].y;
3833 if (0 <= dy && dy < state[i].menu->count)
3835 if (!state[i].menu->submenu[dy])
3836 if (state[i].menu->panenumber[dy])
3837 result = XM_SUCCESS;
3838 else
3839 result = XM_IA_SELECT;
3840 *pane = state[i].pane - 1;
3841 *selidx = dy;
3842 /* We hit some part of a menu, so drop extra menus that
3843 have been opened. That does not include an open and
3844 active submenu. */
3845 if (i != statecount - 2
3846 || state[i].menu->submenu[dy] != state[i+1].menu)
3847 while (i != statecount - 1)
3849 statecount--;
3850 mouse_off ();
3851 ScreenUpdate (state[statecount].screen_behind);
3852 if (screen_virtual_segment)
3853 dosv_refresh_virtual_screen (0, screen_size);
3854 xfree (state[statecount].screen_behind);
3856 if (i == statecount - 1 && state[i].menu->submenu[dy])
3858 IT_menu_display (state[i].menu,
3859 state[i].y,
3860 state[i].x,
3861 state[i].pane,
3862 faces, 1);
3863 state[statecount].menu = state[i].menu->submenu[dy];
3864 state[statecount].pane = state[i].menu->panenumber[dy];
3865 mouse_off ();
3866 ScreenRetrieve (state[statecount].screen_behind
3867 = xmalloc (screensize));
3868 state[statecount].x
3869 = state[i].x + state[i].menu->width + 2;
3870 state[statecount].y = y;
3871 statecount++;
3875 IT_menu_display (state[statecount - 1].menu,
3876 state[statecount - 1].y,
3877 state[statecount - 1].x,
3878 state[statecount - 1].pane,
3879 faces, 1);
3881 else
3883 if ((menu_help_message || prev_menu_help_message)
3884 && menu_help_message != prev_menu_help_message)
3886 help_callback (menu_help_message,
3887 menu_help_paneno, menu_help_itemno);
3888 IT_display_cursor (0);
3889 prev_menu_help_message = menu_help_message;
3891 /* We are busy-waiting for the mouse to move, so let's be nice
3892 to other Windows applications by releasing our time slice. */
3893 __dpmi_yield ();
3895 for (b = 0; b < mouse_button_count && !leave; b++)
3897 /* Only leave if user both pressed and released the mouse, and in
3898 that order. This avoids popping down the menu pane unless
3899 the user is really done with it. */
3900 if (mouse_pressed (b, &x, &y))
3902 while (mouse_button_depressed (b, &x, &y))
3903 __dpmi_yield ();
3904 leave = 1;
3906 (void) mouse_released (b, &x, &y);
3910 mouse_off ();
3911 ScreenUpdate (state[0].screen_behind);
3912 if (screen_virtual_segment)
3913 dosv_refresh_virtual_screen (0, screen_size);
3915 /* We have a situation here. ScreenUpdate has just restored the
3916 screen contents as it was before we started drawing this menu.
3917 That includes any echo area message that could have been
3918 displayed back then. (In reality, that echo area message will
3919 almost always be the ``keystroke echo'' that echoes the sequence
3920 of menu items chosen by the user.) However, if the menu had some
3921 help messages, then displaying those messages caused Emacs to
3922 forget about the original echo area message. So when
3923 ScreenUpdate restored it, it created a discrepancy between the
3924 actual screen contents and what Emacs internal data structures
3925 know about it.
3927 To avoid this conflict, we force Emacs to restore the original
3928 echo area message as we found it when we entered this function.
3929 The irony of this is that we then erase the restored message
3930 right away, so the only purpose of restoring it is so that
3931 erasing it works correctly... */
3932 if (! NILP (saved_echo_area_message))
3933 message_with_string ("%s", saved_echo_area_message, 0);
3934 message (0);
3935 while (statecount--)
3936 xfree (state[statecount].screen_behind);
3937 IT_display_cursor (1); /* turn cursor back on */
3938 /* Clean up any mouse events that are waiting inside Emacs event queue.
3939 These events are likely to be generated before the menu was even
3940 displayed, probably because the user pressed and released the button
3941 (which invoked the menu) too quickly. If we don't remove these events,
3942 Emacs will process them after we return and surprise the user. */
3943 discard_mouse_events ();
3944 mouse_clear_clicks ();
3945 if (!kbd_buffer_events_waiting (1))
3946 clear_input_pending ();
3947 /* Allow mouse events generation by dos_rawgetc. */
3948 mouse_preempted--;
3949 return result;
3952 /* Dispose of a menu. */
3954 void
3955 XMenuDestroy (Display *foo, XMenu *menu)
3957 int i;
3958 if (menu->allocated)
3960 for (i = 0; i < menu->count; i++)
3961 if (menu->submenu[i])
3962 XMenuDestroy (foo, menu->submenu[i]);
3963 xfree (menu->text);
3964 xfree (menu->submenu);
3965 xfree (menu->panenumber);
3966 xfree (menu->help_text);
3968 xfree (menu);
3969 menu_help_message = prev_menu_help_message = NULL;
3973 x_pixel_width (struct frame *f)
3975 return FRAME_COLS (f);
3979 x_pixel_height (struct frame *f)
3981 return FRAME_LINES (f);
3983 #endif /* !HAVE_X_WINDOWS */
3985 /* ----------------------- DOS / UNIX conversion --------------------- */
3987 void msdos_downcase_filename (unsigned char *);
3989 /* Destructively turn backslashes into slashes. */
3991 void
3992 dostounix_filename (p)
3993 register char *p;
3995 msdos_downcase_filename (p);
3997 while (*p)
3999 if (*p == '\\')
4000 *p = '/';
4001 p++;
4005 /* Destructively turn slashes into backslashes. */
4007 void
4008 unixtodos_filename (p)
4009 register char *p;
4011 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4013 *p += 'a' - 'A';
4014 p += 2;
4017 while (*p)
4019 if (*p == '/')
4020 *p = '\\';
4021 p++;
4025 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4028 getdefdir (drive, dst)
4029 int drive;
4030 char *dst;
4032 char in_path[4], *p = in_path, e = errno;
4034 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4035 if (drive != 0)
4037 *p++ = drive + 'A' - 1;
4038 *p++ = ':';
4041 *p++ = '.';
4042 *p = '\0';
4043 errno = 0;
4044 _fixpath (in_path, dst);
4045 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4046 it queries the LFN support, so ignore that error. */
4047 if ((errno && errno != ENOSYS) || *dst == '\0')
4048 return 0;
4050 msdos_downcase_filename (dst);
4052 errno = e;
4053 return 1;
4056 char *
4057 emacs_root_dir (void)
4059 static char root_dir[4];
4061 sprintf (root_dir, "%c:/", 'A' + getdisk ());
4062 root_dir[0] = tolower (root_dir[0]);
4063 return root_dir;
4066 /* Remove all CR's that are followed by a LF. */
4069 crlf_to_lf (n, buf)
4070 register int n;
4071 register unsigned char *buf;
4073 unsigned char *np = buf, *startp = buf, *endp = buf + n;
4075 if (n == 0)
4076 return n;
4077 while (buf < endp - 1)
4079 if (*buf == 0x0d)
4081 if (*(++buf) != 0x0a)
4082 *np++ = 0x0d;
4084 else
4085 *np++ = *buf++;
4087 if (buf < endp)
4088 *np++ = *buf++;
4089 return np - startp;
4092 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4094 /* In DJGPP v2.0, library `write' can call `malloc', which might
4095 cause relocation of the buffer whose address we get in ADDR.
4096 Here is a version of `write' that avoids calling `malloc',
4097 to serve us until such time as the library is fixed.
4098 Actually, what we define here is called `__write', because
4099 `write' is a stub that just jmp's to `__write' (to be
4100 POSIXLY-correct with respect to the global name-space). */
4102 #include <io.h> /* for _write */
4103 #include <libc/dosio.h> /* for __file_handle_modes[] */
4105 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
4107 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4110 __write (int handle, const void *buffer, size_t count)
4112 if (count == 0)
4113 return 0;
4115 if(__file_handle_modes[handle] & O_BINARY)
4116 return _write (handle, buffer, count);
4117 else
4119 char *xbp = xbuf;
4120 const char *bp = buffer;
4121 int total_written = 0;
4122 int nmoved = 0, ncr = 0;
4124 while (count)
4126 /* The next test makes sure there's space for at least 2 more
4127 characters in xbuf[], so both CR and LF can be put there. */
4128 if (xbp < XBUF_END)
4130 if (*bp == '\n')
4132 ncr++;
4133 *xbp++ = '\r';
4135 *xbp++ = *bp++;
4136 nmoved++;
4137 count--;
4139 if (xbp >= XBUF_END || !count)
4141 size_t to_write = nmoved + ncr;
4142 int written = _write (handle, xbuf, to_write);
4144 if (written == -1)
4145 return -1;
4146 else
4147 total_written += nmoved; /* CRs aren't counted in ret value */
4149 /* If some, but not all were written (disk full?), return
4150 an estimate of the total written bytes not counting CRs. */
4151 if (written < to_write)
4152 return total_written - (to_write - written) * nmoved/to_write;
4154 nmoved = 0;
4155 ncr = 0;
4156 xbp = xbuf;
4159 return total_written;
4163 /* A low-level file-renaming function which works around Windows 95 bug.
4164 This is pulled directly out of DJGPP v2.01 library sources, and only
4165 used when you compile with DJGPP v2.0. */
4167 #include <io.h>
4169 int _rename(const char *old, const char *new)
4171 __dpmi_regs r;
4172 int olen = strlen(old) + 1;
4173 int i;
4174 int use_lfn = _USE_LFN;
4175 char tempfile[FILENAME_MAX];
4176 const char *orig = old;
4177 int lfn_fd = -1;
4179 r.x.dx = __tb_offset;
4180 r.x.di = __tb_offset + olen;
4181 r.x.ds = r.x.es = __tb_segment;
4183 if (use_lfn)
4185 /* Windows 95 bug: for some filenames, when you rename
4186 file -> file~ (as in Emacs, to leave a backup), the
4187 short 8+3 alias doesn't change, which effectively
4188 makes OLD and NEW the same file. We must rename
4189 through a temporary file to work around this. */
4191 char *pbase = 0, *p;
4192 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
4193 int idx = sizeof(try_char) - 1;
4195 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4196 might point to another drive, which will fail the DOS call. */
4197 strcpy(tempfile, old);
4198 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
4199 if (*p == '/' || *p == '\\' || *p == ':')
4200 pbase = p;
4201 if (pbase)
4202 pbase++;
4203 else
4204 pbase = tempfile;
4205 strcpy(pbase, "X$$djren$$.$$temp$$");
4209 if (idx <= 0)
4210 return -1;
4211 *pbase = try_char[--idx];
4212 } while (_chmod(tempfile, 0) != -1);
4214 r.x.ax = 0x7156;
4215 _put_path2(tempfile, olen);
4216 _put_path(old);
4217 __dpmi_int(0x21, &r);
4218 if (r.x.flags & 1)
4220 errno = __doserr_to_errno(r.x.ax);
4221 return -1;
4224 /* Now create a file with the original name. This will
4225 ensure that NEW will always have a 8+3 alias
4226 different from that of OLD. (Seems to be required
4227 when NameNumericTail in the Registry is set to 0.) */
4228 lfn_fd = _creat(old, 0);
4230 olen = strlen(tempfile) + 1;
4231 old = tempfile;
4232 r.x.di = __tb_offset + olen;
4235 for (i=0; i<2; i++)
4237 if(use_lfn)
4238 r.x.ax = 0x7156;
4239 else
4240 r.h.ah = 0x56;
4241 _put_path2(new, olen);
4242 _put_path(old);
4243 __dpmi_int(0x21, &r);
4244 if(r.x.flags & 1)
4246 if (r.x.ax == 5 && i == 0) /* access denied */
4247 remove(new); /* and try again */
4248 else
4250 errno = __doserr_to_errno(r.x.ax);
4252 /* Restore to original name if we renamed it to temporary. */
4253 if (use_lfn)
4255 if (lfn_fd != -1)
4257 _close (lfn_fd);
4258 remove (orig);
4260 _put_path2(orig, olen);
4261 _put_path(tempfile);
4262 r.x.ax = 0x7156;
4263 __dpmi_int(0x21, &r);
4265 return -1;
4268 else
4269 break;
4272 /* Success. Delete the file possibly created to work
4273 around the Windows 95 bug. */
4274 if (lfn_fd != -1)
4275 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
4276 return 0;
4279 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4281 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
4282 0, 0, 0,
4283 doc: /* Return non-nil if long file names are supported on MS-DOS. */)
4286 return (_USE_LFN ? Qt : Qnil);
4289 /* Convert alphabetic characters in a filename to lower-case. */
4291 void
4292 msdos_downcase_filename (p)
4293 register unsigned char *p;
4295 /* Always lower-case drive letters a-z, even if the filesystem
4296 preserves case in filenames.
4297 This is so MSDOS filenames could be compared by string comparison
4298 functions that are case-sensitive. Even case-preserving filesystems
4299 do not distinguish case in drive letters. */
4300 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4302 *p += 'a' - 'A';
4303 p += 2;
4306 /* Under LFN we expect to get pathnames in their true case. */
4307 if (NILP (Fmsdos_long_file_names ()))
4308 for ( ; *p; p++)
4309 if (*p >= 'A' && *p <= 'Z')
4310 *p += 'a' - 'A';
4313 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
4314 1, 1, 0,
4315 doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
4316 When long filenames are supported, doesn't change FILENAME.
4317 If FILENAME is not a string, returns nil.
4318 The argument object is never altered--the value is a copy. */)
4319 (filename)
4320 Lisp_Object filename;
4322 Lisp_Object tem;
4324 if (! STRINGP (filename))
4325 return Qnil;
4327 tem = Fcopy_sequence (filename);
4328 msdos_downcase_filename (SDATA (tem));
4329 return tem;
4332 /* The Emacs root directory as determined by init_environment. */
4334 static char emacsroot[MAXPATHLEN];
4336 char *
4337 rootrelativepath (rel)
4338 char *rel;
4340 static char result[MAXPATHLEN + 10];
4342 strcpy (result, emacsroot);
4343 strcat (result, "/");
4344 strcat (result, rel);
4345 return result;
4348 /* Define a lot of environment variables if not already defined. Don't
4349 remove anything unless you know what you're doing -- lots of code will
4350 break if one or more of these are missing. */
4352 void
4353 init_environment (argc, argv, skip_args)
4354 int argc;
4355 char **argv;
4356 int skip_args;
4358 char *s, *t, *root;
4359 int len, i;
4360 static const char * const tempdirs[] = {
4361 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4363 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4365 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4366 temporary files and assume "/tmp" if $TMPDIR is unset, which
4367 will break on DOS/Windows. Refuse to work if we cannot find
4368 a directory, not even "c:/", usable for that purpose. */
4369 for (i = 0; i < imax ; i++)
4371 const char *tmp = tempdirs[i];
4372 char buf[FILENAME_MAX];
4374 if (*tmp == '$')
4376 int tmp_len;
4378 tmp = getenv (tmp + 1);
4379 if (!tmp)
4380 continue;
4382 /* Some lusers set TMPDIR=e:, probably because some losing
4383 programs cannot handle multiple slashes if they use e:/.
4384 e: fails in `access' below, so we interpret e: as e:/. */
4385 tmp_len = strlen(tmp);
4386 if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4388 strcpy(buf, tmp);
4389 buf[tmp_len++] = '/', buf[tmp_len] = 0;
4390 tmp = buf;
4394 /* Note that `access' can lie to us if the directory resides on a
4395 read-only filesystem, like CD-ROM or a write-protected floppy.
4396 The only way to be really sure is to actually create a file and
4397 see if it succeeds. But I think that's too much to ask. */
4398 if (tmp && access (tmp, D_OK) == 0)
4400 setenv ("TMPDIR", tmp, 1);
4401 break;
4404 if (i >= imax)
4405 cmd_error_internal
4406 (Fcons (Qerror,
4407 Fcons (build_string ("no usable temporary directories found!!"),
4408 Qnil)),
4409 "While setting TMPDIR: ");
4411 /* Note the startup time, so we know not to clear the screen if we
4412 exit immediately; see IT_reset_terminal_modes.
4413 (Yes, I know `clock' returns zero the first time it's called, but
4414 I do this anyway, in case some wiseguy changes that at some point.) */
4415 startup_time = clock ();
4417 /* Find our root from argv[0]. Assuming argv[0] is, say,
4418 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4419 root = alloca (MAXPATHLEN + 20);
4420 _fixpath (argv[0], root);
4421 msdos_downcase_filename (root);
4422 len = strlen (root);
4423 while (len > 0 && root[len] != '/' && root[len] != ':')
4424 len--;
4425 root[len] = '\0';
4426 if (len > 4
4427 && (strcmp (root + len - 4, "/bin") == 0
4428 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4429 root[len - 4] = '\0';
4430 else
4431 strcpy (root, "c:/emacs"); /* let's be defensive */
4432 len = strlen (root);
4433 strcpy (emacsroot, root);
4435 /* We default HOME to our root. */
4436 setenv ("HOME", root, 0);
4438 /* We default EMACSPATH to root + "/bin". */
4439 strcpy (root + len, "/bin");
4440 setenv ("EMACSPATH", root, 0);
4442 /* I don't expect anybody to ever use other terminals so the internal
4443 terminal is the default. */
4444 setenv ("TERM", "internal", 0);
4446 #ifdef HAVE_X_WINDOWS
4447 /* Emacs expects DISPLAY to be set. */
4448 setenv ("DISPLAY", "unix:0.0", 0);
4449 #endif
4451 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4452 downcase it and mirror the backslashes. */
4453 s = getenv ("COMSPEC");
4454 if (!s) s = "c:/command.com";
4455 t = alloca (strlen (s) + 1);
4456 strcpy (t, s);
4457 dostounix_filename (t);
4458 setenv ("SHELL", t, 0);
4460 /* PATH is also downcased and backslashes mirrored. */
4461 s = getenv ("PATH");
4462 if (!s) s = "";
4463 t = alloca (strlen (s) + 3);
4464 /* Current directory is always considered part of MsDos's path but it is
4465 not normally mentioned. Now it is. */
4466 strcat (strcpy (t, ".;"), s);
4467 dostounix_filename (t); /* Not a single file name, but this should work. */
4468 setenv ("PATH", t, 1);
4470 /* In some sense all dos users have root privileges, so... */
4471 setenv ("USER", "root", 0);
4472 setenv ("NAME", getenv ("USER"), 0);
4474 /* Time zone determined from country code. To make this possible, the
4475 country code may not span more than one time zone. In other words,
4476 in the USA, you lose. */
4477 if (!getenv ("TZ"))
4478 switch (dos_country_code)
4480 case 31: /* Belgium */
4481 case 32: /* The Netherlands */
4482 case 33: /* France */
4483 case 34: /* Spain */
4484 case 36: /* Hungary */
4485 case 38: /* Yugoslavia (or what's left of it?) */
4486 case 39: /* Italy */
4487 case 41: /* Switzerland */
4488 case 42: /* Tjekia */
4489 case 45: /* Denmark */
4490 case 46: /* Sweden */
4491 case 47: /* Norway */
4492 case 48: /* Poland */
4493 case 49: /* Germany */
4494 /* Daylight saving from last Sunday in March to last Sunday in
4495 September, both at 2AM. */
4496 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4497 break;
4498 case 44: /* United Kingdom */
4499 case 351: /* Portugal */
4500 case 354: /* Iceland */
4501 setenv ("TZ", "GMT+00", 0);
4502 break;
4503 case 81: /* Japan */
4504 case 82: /* Korea */
4505 setenv ("TZ", "JST-09", 0);
4506 break;
4507 case 90: /* Turkey */
4508 case 358: /* Finland */
4509 setenv ("TZ", "EET-02", 0);
4510 break;
4511 case 972: /* Israel */
4512 /* This is an approximation. (For exact rules, use the
4513 `zoneinfo/israel' file which comes with DJGPP, but you need
4514 to install it in `/usr/share/zoneinfo/' directory first.) */
4515 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4516 break;
4518 tzset ();
4523 static int break_stat; /* BREAK check mode status. */
4524 static int stdin_stat; /* stdin IOCTL status. */
4526 #if __DJGPP__ < 2
4528 /* These must be global. */
4529 static _go32_dpmi_seginfo ctrl_break_vector;
4530 static _go32_dpmi_registers ctrl_break_regs;
4531 static int ctrlbreakinstalled = 0;
4533 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4535 void
4536 ctrl_break_func (regs)
4537 _go32_dpmi_registers *regs;
4539 Vquit_flag = Qt;
4542 void
4543 install_ctrl_break_check ()
4545 if (!ctrlbreakinstalled)
4547 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4548 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4549 ctrlbreakinstalled = 1;
4550 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
4551 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
4552 &ctrl_break_regs);
4553 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
4557 #endif /* __DJGPP__ < 2 */
4559 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4560 control chars by DOS. Determine the keyboard type. */
4563 dos_ttraw (struct tty_display_info *tty)
4565 union REGS inregs, outregs;
4566 static int first_time = 1;
4568 /* If we are called for the initial terminal, it's too early to do
4569 anything, and termscript isn't set up. */
4570 if (tty->terminal->type == output_initial)
4571 return;
4573 break_stat = getcbrk ();
4574 setcbrk (0);
4575 #if __DJGPP__ < 2
4576 install_ctrl_break_check ();
4577 #endif
4579 if (first_time)
4581 inregs.h.ah = 0xc0;
4582 int86 (0x15, &inregs, &outregs);
4583 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4585 have_mouse = 0;
4587 if (1
4588 #ifdef HAVE_X_WINDOWS
4589 && inhibit_window_system
4590 #endif
4593 inregs.x.ax = 0x0021;
4594 int86 (0x33, &inregs, &outregs);
4595 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4596 if (!have_mouse)
4598 /* Reportedly, the above doesn't work for some mouse drivers. There
4599 is an additional detection method that should work, but might be
4600 a little slower. Use that as an alternative. */
4601 inregs.x.ax = 0x0000;
4602 int86 (0x33, &inregs, &outregs);
4603 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4605 if (have_mouse)
4606 mouse_button_count = outregs.x.bx;
4608 #ifndef HAVE_X_WINDOWS
4609 #if __DJGPP__ >= 2
4610 /* Save the cursor shape used outside Emacs. */
4611 outside_cursor = _farpeekw (_dos_ds, 0x460);
4612 #endif
4613 #endif
4616 first_time = 0;
4618 #if __DJGPP__ >= 2
4620 stdin_stat = setmode (fileno (stdin), O_BINARY);
4621 return (stdin_stat != -1);
4623 else
4624 return (setmode (fileno (stdin), O_BINARY) != -1);
4626 #else /* __DJGPP__ < 2 */
4630 /* I think it is wrong to overwrite `stdin_stat' every time
4631 but the first one this function is called, but I don't
4632 want to change the way it used to work in v1.x.--EZ */
4634 inregs.x.ax = 0x4400; /* Get IOCTL status. */
4635 inregs.x.bx = 0x00; /* 0 = stdin. */
4636 intdos (&inregs, &outregs);
4637 stdin_stat = outregs.h.dl;
4639 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
4640 inregs.x.ax = 0x4401; /* Set IOCTL status */
4641 intdos (&inregs, &outregs);
4642 return !outregs.x.cflag;
4644 #endif /* __DJGPP__ < 2 */
4647 /* Restore status of standard input and Ctrl-C checking. */
4650 dos_ttcooked ()
4652 union REGS inregs, outregs;
4654 setcbrk (break_stat);
4655 mouse_off ();
4657 #if __DJGPP__ >= 2
4659 #ifndef HAVE_X_WINDOWS
4660 /* Restore the cursor shape we found on startup. */
4661 if (outside_cursor)
4663 inregs.h.ah = 1;
4664 inregs.x.cx = outside_cursor;
4665 int86 (0x10, &inregs, &outregs);
4667 #endif
4669 return (setmode (fileno (stdin), stdin_stat) != -1);
4671 #else /* not __DJGPP__ >= 2 */
4673 inregs.x.ax = 0x4401; /* Set IOCTL status. */
4674 inregs.x.bx = 0x00; /* 0 = stdin. */
4675 inregs.x.dx = stdin_stat;
4676 intdos (&inregs, &outregs);
4677 return !outregs.x.cflag;
4679 #endif /* not __DJGPP__ >= 2 */
4683 /* Run command as specified by ARGV in directory DIR.
4684 The command is run with input from TEMPIN, output to
4685 file TEMPOUT and stderr to TEMPERR. */
4688 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4689 unsigned char **argv;
4690 const char *working_dir;
4691 int tempin, tempout, temperr;
4692 char **envv;
4694 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4695 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4696 int msshell, result = -1, inbak, outbak, errbak, x, y;
4697 Lisp_Object cmd;
4699 /* Get current directory as MSDOS cwd is not per-process. */
4700 getwd (oldwd);
4702 /* If argv[0] is the shell, it might come in any lettercase.
4703 Since `Fmember' is case-sensitive, we need to downcase
4704 argv[0], even if we are on case-preserving filesystems. */
4705 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4706 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4708 *pl = *pa++;
4709 if (*pl >= 'A' && *pl <= 'Z')
4710 *pl += 'a' - 'A';
4712 *pl = '\0';
4714 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4715 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4716 && !strcmp ("-c", argv[1]);
4717 if (msshell)
4719 saveargv1 = argv[1];
4720 saveargv2 = argv[2];
4721 argv[1] = "/c";
4722 /* We only need to mirror slashes if a DOS shell will be invoked
4723 not via `system' (which does the mirroring itself). Yes, that
4724 means DJGPP v1.x will lose here. */
4725 if (argv[2] && argv[3])
4727 char *p = alloca (strlen (argv[2]) + 1);
4729 strcpy (argv[2] = p, saveargv2);
4730 while (*p && isspace (*p))
4731 p++;
4732 while (*p)
4734 if (*p == '/')
4735 *p++ = '\\';
4736 else
4737 p++;
4742 chdir (working_dir);
4743 inbak = dup (0);
4744 outbak = dup (1);
4745 errbak = dup (2);
4746 if (inbak < 0 || outbak < 0 || errbak < 0)
4747 goto done; /* Allocation might fail due to lack of descriptors. */
4749 if (have_mouse > 0)
4750 mouse_get_xy (&x, &y);
4752 dos_ttcooked (); /* do it here while 0 = stdin */
4754 dup2 (tempin, 0);
4755 dup2 (tempout, 1);
4756 dup2 (temperr, 2);
4758 #if __DJGPP__ > 1
4760 if (msshell && !argv[3])
4762 /* MS-DOS native shells are too restrictive. For starters, they
4763 cannot grok commands longer than 126 characters. In DJGPP v2
4764 and later, `system' is much smarter, so we'll call it instead. */
4766 const char *cmnd;
4768 /* A shell gets a single argument--its full command
4769 line--whose original was saved in `saveargv2'. */
4771 /* Don't let them pass empty command lines to `system', since
4772 with some shells it will try to invoke an interactive shell,
4773 which will hang Emacs. */
4774 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4776 if (*cmnd)
4778 extern char **environ;
4779 char **save_env = environ;
4780 int save_system_flags = __system_flags;
4782 /* Request the most powerful version of `system'. We need
4783 all the help we can get to avoid calling stock DOS shells. */
4784 __system_flags = (__system_redirect
4785 | __system_use_shell
4786 | __system_allow_multiple_cmds
4787 | __system_allow_long_cmds
4788 | __system_handle_null_commands
4789 | __system_emulate_chdir);
4791 environ = envv;
4792 result = system (cmnd);
4793 __system_flags = save_system_flags;
4794 environ = save_env;
4796 else
4797 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4799 else
4801 #endif /* __DJGPP__ > 1 */
4803 result = spawnve (P_WAIT, argv[0], argv, envv);
4805 dup2 (inbak, 0);
4806 dup2 (outbak, 1);
4807 dup2 (errbak, 2);
4808 emacs_close (inbak);
4809 emacs_close (outbak);
4810 emacs_close (errbak);
4812 dos_ttraw (CURTTY ());
4813 if (have_mouse > 0)
4815 mouse_init ();
4816 mouse_moveto (x, y);
4819 /* Some programs might change the meaning of the highest bit of the
4820 text attribute byte, so we get blinking characters instead of the
4821 bright background colors. Restore that. */
4822 bright_bg ();
4824 done:
4825 chdir (oldwd);
4826 if (msshell)
4828 argv[1] = saveargv1;
4829 argv[2] = saveargv2;
4831 return result;
4834 void
4835 croak (badfunc)
4836 char *badfunc;
4838 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4839 reset_all_sys_modes ();
4840 exit (1);
4843 #if __DJGPP__ < 2
4845 /* ------------------------- Compatibility functions -------------------
4846 * gethostname
4847 * gettimeofday
4850 /* Hostnames for a pc are not really funny,
4851 but they are used in change log so we emulate the best we can. */
4853 gethostname (p, size)
4854 char *p;
4855 int size;
4857 char *q = egetenv ("HOSTNAME");
4859 if (!q) q = "pc";
4860 strcpy (p, q);
4861 return 0;
4864 /* When time zones are set from Ms-Dos too many C-libraries are playing
4865 tricks with time values. We solve this by defining our own version
4866 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4867 once and after each call to `tzset' with TZ changed. That is
4868 accomplished by aliasing tzset to init_gettimeofday. */
4870 static struct tm time_rec;
4873 gettimeofday (struct timeval *tp, struct timezone *tzp)
4875 if (tp)
4877 struct time t;
4878 struct tm tm;
4880 gettime (&t);
4881 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
4883 struct date d;
4884 getdate (&d);
4885 time_rec.tm_year = d.da_year - 1900;
4886 time_rec.tm_mon = d.da_mon - 1;
4887 time_rec.tm_mday = d.da_day;
4890 time_rec.tm_hour = t.ti_hour;
4891 time_rec.tm_min = t.ti_min;
4892 time_rec.tm_sec = t.ti_sec;
4894 tm = time_rec;
4895 tm.tm_gmtoff = dos_timezone_offset;
4897 tp->tv_sec = mktime (&tm); /* may modify tm */
4898 tp->tv_usec = t.ti_hund * (1000000 / 100);
4900 /* Ignore tzp; it's obsolescent. */
4901 return 0;
4904 #endif /* __DJGPP__ < 2 */
4907 * A list of unimplemented functions that we silently ignore.
4910 #if __DJGPP__ < 2
4911 unsigned alarm (s) unsigned s; {}
4912 fork () { return 0; }
4913 int kill (x, y) int x, y; { return -1; }
4914 nice (p) int p; {}
4915 void volatile pause () {}
4916 sigsetmask (x) int x; { return 0; }
4917 sigblock (mask) int mask; { return 0; }
4918 #endif
4920 setpgrp () {return 0; }
4921 setpriority (x,y,z) int x,y,z; { return 0; }
4923 #if __DJGPP__ > 1
4924 #if __DJGPP_MINOR__ < 2
4926 #ifdef POSIX_SIGNALS
4928 /* Augment DJGPP library POSIX signal functions. This is needed
4929 as of DJGPP v2.01, but might be in the library in later releases. */
4931 #include <libc/bss.h>
4933 /* A counter to know when to re-initialize the static sets. */
4934 static int sigprocmask_count = -1;
4936 /* Which signals are currently blocked (initially none). */
4937 static sigset_t current_mask;
4939 /* Which signals are pending (initially none). */
4940 static sigset_t pending_signals;
4942 /* Previous handlers to restore when the blocked signals are unblocked. */
4943 typedef void (*sighandler_t)(int);
4944 static sighandler_t prev_handlers[320];
4946 /* A signal handler which just records that a signal occurred
4947 (it will be raised later, if and when the signal is unblocked). */
4948 static void
4949 sig_suspender (signo)
4950 int signo;
4952 sigaddset (&pending_signals, signo);
4956 sigprocmask (how, new_set, old_set)
4957 int how;
4958 const sigset_t *new_set;
4959 sigset_t *old_set;
4961 int signo;
4962 sigset_t new_mask;
4964 /* If called for the first time, initialize. */
4965 if (sigprocmask_count != __bss_count)
4967 sigprocmask_count = __bss_count;
4968 sigemptyset (&pending_signals);
4969 sigemptyset (&current_mask);
4970 for (signo = 0; signo < 320; signo++)
4971 prev_handlers[signo] = SIG_ERR;
4974 if (old_set)
4975 *old_set = current_mask;
4977 if (new_set == 0)
4978 return 0;
4980 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4982 errno = EINVAL;
4983 return -1;
4986 sigemptyset (&new_mask);
4988 /* DJGPP supports upto 320 signals. */
4989 for (signo = 0; signo < 320; signo++)
4991 if (sigismember (&current_mask, signo))
4992 sigaddset (&new_mask, signo);
4993 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4995 sigaddset (&new_mask, signo);
4997 /* SIGKILL is silently ignored, as on other platforms. */
4998 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4999 prev_handlers[signo] = signal (signo, sig_suspender);
5001 if (( how == SIG_UNBLOCK
5002 && sigismember (&new_mask, signo)
5003 && sigismember (new_set, signo))
5004 || (how == SIG_SETMASK
5005 && sigismember (&new_mask, signo)
5006 && !sigismember (new_set, signo)))
5008 sigdelset (&new_mask, signo);
5009 if (prev_handlers[signo] != SIG_ERR)
5011 signal (signo, prev_handlers[signo]);
5012 prev_handlers[signo] = SIG_ERR;
5014 if (sigismember (&pending_signals, signo))
5016 sigdelset (&pending_signals, signo);
5017 raise (signo);
5021 current_mask = new_mask;
5022 return 0;
5025 #else /* not POSIX_SIGNALS */
5027 sigsetmask (x) int x; { return 0; }
5028 sigblock (mask) int mask; { return 0; }
5030 #endif /* not POSIX_SIGNALS */
5031 #endif /* not __DJGPP_MINOR__ < 2 */
5032 #endif /* __DJGPP__ > 1 */
5034 #ifndef HAVE_SELECT
5035 #include "sysselect.h"
5037 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5038 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5039 ((long)(time).tv_sec < 0 \
5040 || ((time).tv_sec == 0 \
5041 && (long)(time).tv_usec <= 0))
5042 #endif
5044 /* This yields the rest of the current time slice to the task manager.
5045 It should be called by any code which knows that it has nothing
5046 useful to do except idle.
5048 I don't use __dpmi_yield here, since versions of library before 2.02
5049 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5050 on some versions of Windows 9X. */
5052 void
5053 dos_yield_time_slice (void)
5055 _go32_dpmi_registers r;
5057 r.x.ax = 0x1680;
5058 r.x.ss = r.x.sp = r.x.flags = 0;
5059 _go32_dpmi_simulate_int (0x2f, &r);
5060 if (r.h.al == 0x80)
5061 errno = ENOSYS;
5064 /* Only event queue is checked. */
5065 /* We don't have to call timer_check here
5066 because wait_reading_process_output takes care of that. */
5068 sys_select (nfds, rfds, wfds, efds, timeout)
5069 int nfds;
5070 SELECT_TYPE *rfds, *wfds, *efds;
5071 EMACS_TIME *timeout;
5073 int check_input;
5074 struct time t;
5076 check_input = 0;
5077 if (rfds)
5079 check_input = FD_ISSET (0, rfds);
5080 FD_ZERO (rfds);
5082 if (wfds)
5083 FD_ZERO (wfds);
5084 if (efds)
5085 FD_ZERO (efds);
5087 if (nfds != 1)
5088 abort ();
5090 /* If we are looking only for the terminal, with no timeout,
5091 just read it and wait -- that's more efficient. */
5092 if (!timeout)
5094 while (!detect_input_pending ())
5096 dos_yield_time_slice ();
5099 else
5101 EMACS_TIME clnow, cllast, cldiff;
5103 gettime (&t);
5104 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
5106 while (!check_input || !detect_input_pending ())
5108 gettime (&t);
5109 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
5110 EMACS_SUB_TIME (cldiff, clnow, cllast);
5112 /* When seconds wrap around, we assume that no more than
5113 1 minute passed since last `gettime'. */
5114 if (EMACS_TIME_NEG_P (cldiff))
5115 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
5116 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
5118 /* Stop when timeout value crosses zero. */
5119 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
5120 return 0;
5121 cllast = clnow;
5122 dos_yield_time_slice ();
5126 FD_SET (0, rfds);
5127 return 1;
5129 #endif
5132 * Define overlaid functions:
5134 * chdir -> sys_chdir
5135 * tzset -> init_gettimeofday
5136 * abort -> dos_abort
5139 #ifdef chdir
5140 #undef chdir
5141 extern int chdir ();
5144 sys_chdir (path)
5145 const char* path;
5147 int len = strlen (path);
5148 char *tmp = (char *)path;
5150 if (*tmp && tmp[1] == ':')
5152 if (getdisk () != tolower (tmp[0]) - 'a')
5153 setdisk (tolower (tmp[0]) - 'a');
5154 tmp += 2; /* strip drive: KFS 1995-07-06 */
5155 len -= 2;
5158 if (len > 1 && (tmp[len - 1] == '/'))
5160 char *tmp1 = (char *) alloca (len + 1);
5161 strcpy (tmp1, tmp);
5162 tmp1[len - 1] = 0;
5163 tmp = tmp1;
5165 return chdir (tmp);
5167 #endif
5169 #ifdef tzset
5170 #undef tzset
5171 extern void tzset (void);
5173 void
5174 init_gettimeofday ()
5176 time_t ltm, gtm;
5177 struct tm *lstm;
5179 tzset ();
5180 ltm = gtm = time (NULL);
5181 ltm = mktime (lstm = localtime (&ltm));
5182 gtm = mktime (gmtime (&gtm));
5183 time_rec.tm_hour = 99; /* force gettimeofday to get date */
5184 time_rec.tm_isdst = lstm->tm_isdst;
5185 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
5187 #endif
5189 #ifdef abort
5190 #undef abort
5191 void
5192 dos_abort (file, line)
5193 char *file;
5194 int line;
5196 char buffer1[200], buffer2[400];
5197 int i, j;
5199 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
5200 for (i = j = 0; buffer1[i]; i++) {
5201 buffer2[j++] = buffer1[i];
5202 buffer2[j++] = 0x70;
5204 dosmemput (buffer2, j, (int)ScreenPrimary);
5205 ScreenSetCursor (2, 0);
5206 abort ();
5208 #else
5209 void
5210 abort ()
5212 dos_ttcooked ();
5213 ScreenSetCursor (10, 0);
5214 cputs ("\r\n\nEmacs aborted!\r\n");
5215 #if __DJGPP__ > 1
5216 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5217 if (screen_virtual_segment)
5218 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
5219 /* Generate traceback, so we could tell whodunit. */
5220 signal (SIGINT, SIG_DFL);
5221 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5222 #else /* __DJGPP_MINOR__ >= 2 */
5223 raise (SIGABRT);
5224 #endif /* __DJGPP_MINOR__ >= 2 */
5225 #endif
5226 exit (2);
5228 #endif
5230 /* The following variables are required so that cus-start.el won't
5231 complain about unbound variables. */
5232 #ifndef subprocesses
5233 /* Nonzero means delete a process right away if it exits (process.c). */
5234 static int delete_exited_processes;
5235 #endif
5237 syms_of_msdos ()
5239 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
5240 staticpro (&recent_doskeys);
5242 #ifndef HAVE_X_WINDOWS
5244 /* The following two are from xfns.c: */
5245 Qreverse = intern ("reverse");
5246 staticpro (&Qreverse);
5248 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
5249 doc: /* *Glyph to display instead of chars not supported by current codepage.
5250 This variable is used only by MS-DOS terminals. */);
5251 Vdos_unsupported_char_glyph = make_number ('\177');
5253 #endif
5254 #ifndef subprocesses
5255 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
5256 doc: /* *Non-nil means delete processes immediately when they exit.
5257 A value of nil means don't delete them until `list-processes' is run. */);
5258 delete_exited_processes = 0;
5259 #endif
5261 defsubr (&Srecent_doskeys);
5262 defsubr (&Smsdos_long_file_names);
5263 defsubr (&Smsdos_downcase_filename);
5264 defsubr (&Smsdos_remember_default_colors);
5265 defsubr (&Smsdos_set_mouse_buttons);
5268 #endif /* MSDOS */
5270 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5271 (do not change this comment) */