(comint-password-prompt-regexp): Synch with main trunk.
[emacs.git] / src / msdos.c
blob967796f5e1adc992080e7f719e9d465b73595d4e
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999, 2000, 2001
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Contributed by Morten Welinder */
23 /* New display, keyboard, and mouse control by Kim F. Storm */
25 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
27 #include <config.h>
29 #ifdef MSDOS
30 #include "lisp.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <sys/param.h>
35 #include <sys/time.h>
36 #include <dos.h>
37 #include <errno.h>
38 #include <string.h> /* for bzero and string functions */
39 #include <sys/stat.h> /* for _fixpath */
40 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #if __DJGPP__ >= 2
42 #include <fcntl.h>
43 #include <io.h> /* for setmode */
44 #include <dpmi.h> /* for __dpmi_xxx stuff */
45 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
46 #include <libc/dosio.h> /* for _USE_LFN */
47 #include <conio.h> /* for cputs */
48 #endif
50 #include "msdos.h"
51 #include "systime.h"
52 #include "termhooks.h"
53 #include "termchar.h"
54 #include "dispextern.h"
55 #include "dosfns.h"
56 #include "termopts.h"
57 #include "charset.h"
58 #include "coding.h"
59 #include "disptab.h"
60 #include "frame.h"
61 #include "window.h"
62 #include "buffer.h"
63 #include "commands.h"
64 #include "blockinput.h"
65 #include "keyboard.h"
66 #include <go32.h>
67 #include <pc.h>
68 #include <ctype.h>
69 /* #include <process.h> */
70 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
71 #define P_WAIT 1
73 #ifndef _USE_LFN
74 #define _USE_LFN 0
75 #endif
77 #ifndef _dos_ds
78 #define _dos_ds _go32_info_block.selector_for_linear_memory
79 #endif
81 #if __DJGPP__ > 1
83 #include <signal.h>
84 #include "syssignal.h"
86 #ifndef SYSTEM_MALLOC
88 #ifdef GNU_MALLOC
90 /* If other `malloc' than ours is used, force our `sbrk' behave like
91 Unix programs expect (resize memory blocks to keep them contiguous).
92 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
93 because that's what `gmalloc' expects to get. */
94 #include <crt0.h>
96 #ifdef REL_ALLOC
97 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
98 #else /* not REL_ALLOC */
99 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
100 #endif /* not REL_ALLOC */
101 #endif /* GNU_MALLOC */
103 #endif /* not SYSTEM_MALLOC */
104 #endif /* __DJGPP__ > 1 */
106 static unsigned long
107 event_timestamp ()
109 struct time t;
110 unsigned long s;
112 gettime (&t);
113 s = t.ti_min;
114 s *= 60;
115 s += t.ti_sec;
116 s *= 1000;
117 s += t.ti_hund * 10;
119 return s;
123 /* ------------------------ Mouse control ---------------------------
125 * Coordinates are in screen positions and zero based.
126 * Mouse buttons are numbered from left to right and also zero based.
129 /* This used to be in termhooks.h, but mainstream Emacs code no longer
130 uses it, and it was removed... */
131 #define NUM_MOUSE_BUTTONS (5)
133 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
134 static int mouse_visible;
136 static int mouse_last_x;
137 static int mouse_last_y;
139 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
140 static int mouse_button_count;
142 void
143 mouse_on ()
145 union REGS regs;
147 if (have_mouse > 0 && !mouse_visible)
149 if (termscript)
150 fprintf (termscript, "<M_ON>");
151 regs.x.ax = 0x0001;
152 int86 (0x33, &regs, &regs);
153 mouse_visible = 1;
157 void
158 mouse_off ()
160 union REGS regs;
162 if (have_mouse > 0 && mouse_visible)
164 if (termscript)
165 fprintf (termscript, "<M_OFF>");
166 regs.x.ax = 0x0002;
167 int86 (0x33, &regs, &regs);
168 mouse_visible = 0;
172 static void
173 mouse_setup_buttons (int n_buttons)
175 if (n_buttons == 3)
177 mouse_button_count = 3;
178 mouse_button_translate[0] = 0; /* Left */
179 mouse_button_translate[1] = 2; /* Middle */
180 mouse_button_translate[2] = 1; /* Right */
182 else /* two, what else? */
184 mouse_button_count = 2;
185 mouse_button_translate[0] = 0;
186 mouse_button_translate[1] = 1;
190 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
191 1, 1, "NSet number of mouse buttons to: ",
192 "Set the number of mouse buttons to use by Emacs.\n\
193 This is useful with mice that report the number of buttons inconsistently,\n\
194 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of\n\
195 them. This happens with wheeled mice on Windows 9X, for example.")
196 (nbuttons)
197 Lisp_Object nbuttons;
199 int n;
201 CHECK_NUMBER (nbuttons, 0);
202 n = XINT (nbuttons);
203 if (n < 2 || n > 3)
204 Fsignal (Qargs_out_of_range,
205 Fcons (build_string ("only 2 or 3 mouse buttons are supported"),
206 Fcons (nbuttons, Qnil)));
207 mouse_setup_buttons (n);
208 return Qnil;
211 static void
212 mouse_get_xy (int *x, int *y)
214 union REGS regs;
216 regs.x.ax = 0x0003;
217 int86 (0x33, &regs, &regs);
218 *x = regs.x.cx / 8;
219 *y = regs.x.dx / 8;
222 void
223 mouse_moveto (x, y)
224 int x, y;
226 union REGS regs;
228 if (termscript)
229 fprintf (termscript, "<M_XY=%dx%d>", x, y);
230 regs.x.ax = 0x0004;
231 mouse_last_x = regs.x.cx = x * 8;
232 mouse_last_y = regs.x.dx = y * 8;
233 int86 (0x33, &regs, &regs);
236 static int
237 mouse_pressed (b, xp, yp)
238 int b, *xp, *yp;
240 union REGS regs;
242 if (b >= mouse_button_count)
243 return 0;
244 regs.x.ax = 0x0005;
245 regs.x.bx = mouse_button_translate[b];
246 int86 (0x33, &regs, &regs);
247 if (regs.x.bx)
248 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
249 return (regs.x.bx != 0);
252 static int
253 mouse_released (b, xp, yp)
254 int b, *xp, *yp;
256 union REGS regs;
258 if (b >= mouse_button_count)
259 return 0;
260 regs.x.ax = 0x0006;
261 regs.x.bx = mouse_button_translate[b];
262 int86 (0x33, &regs, &regs);
263 if (regs.x.bx)
264 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
265 return (regs.x.bx != 0);
268 static int
269 mouse_button_depressed (b, xp, yp)
270 int b, *xp, *yp;
272 union REGS regs;
274 if (b >= mouse_button_count)
275 return 0;
276 regs.x.ax = 0x0003;
277 int86 (0x33, &regs, &regs);
278 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
280 *xp = regs.x.cx / 8;
281 *yp = regs.x.dx / 8;
282 return 1;
284 return 0;
287 void
288 mouse_get_pos (f, insist, bar_window, part, x, y, time)
289 FRAME_PTR *f;
290 int insist;
291 Lisp_Object *bar_window, *x, *y;
292 enum scroll_bar_part *part;
293 unsigned long *time;
295 int ix, iy;
296 Lisp_Object frame, tail;
298 /* Clear the mouse-moved flag for every frame on this display. */
299 FOR_EACH_FRAME (tail, frame)
300 XFRAME (frame)->mouse_moved = 0;
302 *f = SELECTED_FRAME();
303 *bar_window = Qnil;
304 mouse_get_xy (&ix, &iy);
305 *time = event_timestamp ();
306 *x = make_number (mouse_last_x = ix);
307 *y = make_number (mouse_last_y = iy);
310 static void
311 mouse_check_moved ()
313 int x, y;
315 mouse_get_xy (&x, &y);
316 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
317 mouse_last_x = x;
318 mouse_last_y = y;
321 /* Force the mouse driver to ``forget'' about any button clicks until
322 now. */
323 static void
324 mouse_clear_clicks (void)
326 int b;
328 for (b = 0; b < mouse_button_count; b++)
330 int dummy_x, dummy_y;
332 (void) mouse_pressed (b, &dummy_x, &dummy_y);
333 (void) mouse_released (b, &dummy_x, &dummy_y);
337 void
338 mouse_init ()
340 union REGS regs;
342 if (termscript)
343 fprintf (termscript, "<M_INIT>");
345 regs.x.ax = 0x0021;
346 int86 (0x33, &regs, &regs);
348 /* Reset the mouse last press/release info. It seems that Windows
349 doesn't do that automatically when function 21h is called, which
350 causes Emacs to ``remember'' the click that switched focus to the
351 window just before Emacs was started from that window. */
352 mouse_clear_clicks ();
354 regs.x.ax = 0x0007;
355 regs.x.cx = 0;
356 regs.x.dx = 8 * (ScreenCols () - 1);
357 int86 (0x33, &regs, &regs);
359 regs.x.ax = 0x0008;
360 regs.x.cx = 0;
361 regs.x.dx = 8 * (ScreenRows () - 1);
362 int86 (0x33, &regs, &regs);
364 mouse_moveto (0, 0);
365 mouse_visible = 0;
368 /* ------------------------- Screen control ----------------------
372 static int internal_terminal = 0;
374 #ifndef HAVE_X_WINDOWS
375 extern unsigned char ScreenAttrib;
376 static int screen_face;
377 static int highlight;
379 static int screen_size_X;
380 static int screen_size_Y;
381 static int screen_size;
383 static int current_pos_X;
384 static int current_pos_Y;
385 static int new_pos_X;
386 static int new_pos_Y;
388 static void *startup_screen_buffer;
389 static int startup_screen_size_X;
390 static int startup_screen_size_Y;
391 static int startup_pos_X;
392 static int startup_pos_Y;
393 static unsigned char startup_screen_attrib;
395 static clock_t startup_time;
397 static int term_setup_done;
399 static unsigned short outside_cursor;
401 /* Similar to the_only_frame. */
402 struct x_output the_only_x_display;
404 /* Support for DOS/V (allows Japanese characters to be displayed on
405 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
407 /* Holds the address of the text-mode screen buffer. */
408 static unsigned long screen_old_address = 0;
409 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
410 static unsigned short screen_virtual_segment = 0;
411 static unsigned short screen_virtual_offset = 0;
412 /* A flag to control how to display unibyte 8-bit characters. */
413 extern int unibyte_display_via_language_environment;
415 Lisp_Object Qbar;
417 static int initial_screen_colors[2];
419 #if __DJGPP__ > 1
420 /* Update the screen from a part of relocated DOS/V screen buffer which
421 begins at OFFSET and includes COUNT characters. */
422 static void
423 dosv_refresh_virtual_screen (int offset, int count)
425 __dpmi_regs regs;
427 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
428 return;
430 regs.h.ah = 0xff; /* update relocated screen */
431 regs.x.es = screen_virtual_segment;
432 regs.x.di = screen_virtual_offset + offset;
433 regs.x.cx = count;
434 __dpmi_int (0x10, &regs);
436 #endif
438 static void
439 dos_direct_output (y, x, buf, len)
440 int y;
441 int x;
442 char *buf;
443 int len;
445 int t0 = 2 * (x + y * screen_size_X);
446 int t = t0 + (int) ScreenPrimary;
447 int l0 = len;
449 #if (__DJGPP__ < 2)
450 while (--len >= 0) {
451 dosmemput (buf++, 1, t);
452 t += 2;
454 #else
455 /* This is faster. */
456 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
457 _farnspokeb (t, *buf);
459 if (screen_virtual_segment)
460 dosv_refresh_virtual_screen (t0, l0);
461 #endif
463 #endif
465 /* Flash the screen as a substitute for BEEPs. */
467 #if (__DJGPP__ < 2)
468 static void
469 do_visible_bell (xorattr)
470 unsigned char xorattr;
472 asm volatile
473 (" movb $1,%%dl \n\
474 visible_bell_0: \n\
475 movl _ScreenPrimary,%%eax \n\
476 call dosmemsetup \n\
477 movl %%eax,%%ebx \n\
478 movl %1,%%ecx \n\
479 movb %0,%%al \n\
480 incl %%ebx \n\
481 visible_bell_1: \n\
482 xorb %%al,%%gs:(%%ebx) \n\
483 addl $2,%%ebx \n\
484 decl %%ecx \n\
485 jne visible_bell_1 \n\
486 decb %%dl \n\
487 jne visible_bell_3 \n\
488 visible_bell_2: \n\
489 movzwl %%ax,%%eax \n\
490 movzwl %%ax,%%eax \n\
491 movzwl %%ax,%%eax \n\
492 movzwl %%ax,%%eax \n\
493 decw %%cx \n\
494 jne visible_bell_2 \n\
495 jmp visible_bell_0 \n\
496 visible_bell_3:"
497 : /* no output */
498 : "m" (xorattr), "g" (screen_size)
499 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
502 static void
503 ScreenVisualBell (void)
505 /* This creates an xor-mask that will swap the default fore- and
506 background colors. */
507 do_visible_bell (((the_only_x_display.foreground_pixel
508 ^ the_only_x_display.background_pixel)
509 * 0x11) & 0x7f);
511 #endif
513 #ifndef HAVE_X_WINDOWS
515 static int blink_bit = -1; /* the state of the blink bit at startup */
517 /* Enable bright background colors. */
518 static void
519 bright_bg (void)
521 union REGS regs;
523 /* Remember the original state of the blink/bright-background bit.
524 It is stored at 0040:0065h in the BIOS data area. */
525 if (blink_bit == -1)
526 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
528 regs.h.bl = 0;
529 regs.x.ax = 0x1003;
530 int86 (0x10, &regs, &regs);
533 /* Disable bright background colors (and enable blinking) if we found
534 the video system in that state at startup. */
535 static void
536 maybe_enable_blinking (void)
538 if (blink_bit == 1)
540 union REGS regs;
542 regs.h.bl = 1;
543 regs.x.ax = 0x1003;
544 int86 (0x10, &regs, &regs);
548 /* Return non-zero if the system has a VGA adapter. */
549 static int
550 vga_installed (void)
552 union REGS regs;
554 regs.x.ax = 0x1a00;
555 int86 (0x10, &regs, &regs);
556 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
557 return 1;
558 return 0;
561 /* Set the screen dimensions so that it can show no less than
562 ROWS x COLS frame. */
564 void
565 dos_set_window_size (rows, cols)
566 int *rows, *cols;
568 char video_name[30];
569 Lisp_Object video_mode;
570 int video_mode_value;
571 int have_vga = 0;
572 union REGS regs;
573 int current_rows = ScreenRows (), current_cols = ScreenCols ();
575 if (*rows == current_rows && *cols == current_cols)
576 return;
578 mouse_off ();
579 have_vga = vga_installed ();
581 /* If the user specified a special video mode for these dimensions,
582 use that mode. */
583 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
584 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
585 Qnil))-> value;
587 if (INTEGERP (video_mode)
588 && (video_mode_value = XINT (video_mode)) > 0)
590 regs.x.ax = video_mode_value;
591 int86 (0x10, &regs, &regs);
593 if (have_mouse)
595 /* Must hardware-reset the mouse, or else it won't update
596 its notion of screen dimensions for some non-standard
597 video modes. This is *painfully* slow... */
598 regs.x.ax = 0;
599 int86 (0x33, &regs, &regs);
603 /* Find one of the dimensions supported by standard EGA/VGA
604 which gives us at least the required dimensions. */
606 #if __DJGPP__ > 1
608 else
610 static struct {
611 int rows;
612 int need_vga;
613 } std_dimension[] = {
614 {25, 0},
615 {28, 1},
616 {35, 0},
617 {40, 1},
618 {43, 0},
619 {50, 1}
621 int i = 0;
623 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
625 if (std_dimension[i].need_vga <= have_vga
626 && std_dimension[i].rows >= *rows)
628 if (std_dimension[i].rows != current_rows
629 || *cols != current_cols)
630 _set_screen_lines (std_dimension[i].rows);
631 break;
633 i++;
637 #else /* not __DJGPP__ > 1 */
639 else if (*rows <= 25)
641 if (current_rows != 25 || current_cols != 80)
643 regs.x.ax = 3;
644 int86 (0x10, &regs, &regs);
645 regs.x.ax = 0x1101;
646 regs.h.bl = 0;
647 int86 (0x10, &regs, &regs);
648 regs.x.ax = 0x1200;
649 regs.h.bl = 32;
650 int86 (0x10, &regs, &regs);
651 regs.x.ax = 3;
652 int86 (0x10, &regs, &regs);
655 else if (*rows <= 50)
656 if (have_vga && (current_rows != 50 || current_cols != 80)
657 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
659 regs.x.ax = 3;
660 int86 (0x10, &regs, &regs);
661 regs.x.ax = 0x1112;
662 regs.h.bl = 0;
663 int86 (0x10, &regs, &regs);
664 regs.x.ax = 0x1200;
665 regs.h.bl = 32;
666 int86 (0x10, &regs, &regs);
667 regs.x.ax = 0x0100;
668 regs.x.cx = 7;
669 int86 (0x10, &regs, &regs);
671 #endif /* not __DJGPP__ > 1 */
673 if (have_mouse)
675 mouse_init ();
676 mouse_on ();
679 /* Tell the caller what dimensions have been REALLY set. */
680 *rows = ScreenRows ();
681 *cols = ScreenCols ();
683 /* Update Emacs' notion of screen dimensions. */
684 screen_size_X = *cols;
685 screen_size_Y = *rows;
686 screen_size = *cols * *rows;
688 #if __DJGPP__ > 1
689 /* If the dimensions changed, the mouse highlight info is invalid. */
690 if (current_rows != *rows || current_cols != *cols)
692 struct frame *f = SELECTED_FRAME();
693 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
694 Lisp_Object window = dpyinfo->mouse_face_window;
696 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
698 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
699 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
700 dpyinfo->mouse_face_window = Qnil;
703 #endif
705 /* Enable bright background colors. */
706 bright_bg ();
708 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
709 be defensive anyway. */
710 if (screen_virtual_segment)
711 dosv_refresh_virtual_screen (0, *cols * *rows);
714 /* If we write a character in the position where the mouse is,
715 the mouse cursor may need to be refreshed. */
717 static void
718 mouse_off_maybe ()
720 int x, y;
722 if (!mouse_visible)
723 return;
725 mouse_get_xy (&x, &y);
726 if (y != new_pos_Y || x < new_pos_X)
727 return;
729 mouse_off ();
732 #define DEFAULT_CURSOR_START (-1)
733 #define DEFAULT_CURSOR_WIDTH (-1)
734 #define BOX_CURSOR_WIDTH (-32)
736 /* Set cursor to begin at scan line START_LINE in the character cell
737 and extend for WIDTH scan lines. Scan lines are counted from top
738 of the character cell, starting from zero. */
739 static void
740 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
742 #if __DJGPP__ > 1
743 unsigned desired_cursor;
744 __dpmi_regs regs;
745 int max_line, top_line, bot_line;
747 /* Avoid the costly BIOS call if F isn't the currently selected
748 frame. Allow for NULL as unconditionally meaning the selected
749 frame. */
750 if (f && f != SELECTED_FRAME())
751 return;
753 /* The character cell size in scan lines is stored at 40:85 in the
754 BIOS data area. */
755 max_line = _farpeekw (_dos_ds, 0x485) - 1;
756 switch (max_line)
758 default: /* this relies on CGA cursor emulation being ON! */
759 case 7:
760 bot_line = 7;
761 break;
762 case 9:
763 bot_line = 9;
764 break;
765 case 13:
766 bot_line = 12;
767 break;
768 case 15:
769 bot_line = 14;
770 break;
773 if (width < 0)
775 if (width == BOX_CURSOR_WIDTH)
777 top_line = 0;
778 bot_line = max_line;
780 else if (start_line != DEFAULT_CURSOR_START)
782 top_line = start_line;
783 bot_line = top_line - width - 1;
785 else if (width != DEFAULT_CURSOR_WIDTH)
787 top_line = 0;
788 bot_line = -1 - width;
790 else
791 top_line = bot_line + 1;
793 else if (width == 0)
795 /* [31, 0] seems to DTRT for all screen sizes. */
796 top_line = 31;
797 bot_line = 0;
799 else /* WIDTH is positive */
801 if (start_line != DEFAULT_CURSOR_START)
802 bot_line = start_line;
803 top_line = bot_line - (width - 1);
806 /* If the current cursor shape is already what they want, we are
807 history here. */
808 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
809 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
810 return;
812 regs.h.ah = 1;
813 regs.x.cx = desired_cursor;
814 __dpmi_int (0x10, &regs);
815 #endif /* __DJGPP__ > 1 */
818 static void
819 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
821 if (EQ (cursor_type, Qbar))
823 /* Just BAR means the normal EGA/VGA cursor. */
824 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
826 else if (CONSP (cursor_type) && EQ (XCAR (cursor_type), Qbar))
828 Lisp_Object bar_parms = XCDR (cursor_type);
829 int width;
831 if (INTEGERP (bar_parms))
833 /* Feature: negative WIDTH means cursor at the top
834 of the character cell, zero means invisible cursor. */
835 width = XINT (bar_parms);
836 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
837 width);
839 else if (CONSP (bar_parms)
840 && INTEGERP (XCAR (bar_parms))
841 && INTEGERP (XCDR (bar_parms)))
843 int start_line = XINT (XCDR (bar_parms));
845 width = XINT (XCAR (bar_parms));
846 msdos_set_cursor_shape (f, start_line, width);
849 else
850 /* Treat anything unknown as "box cursor". This includes nil, so
851 that a frame which doesn't specify a cursor type gets a box,
852 which is the default in Emacs. */
853 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
856 static void
857 IT_ring_bell (void)
859 if (visible_bell)
861 mouse_off ();
862 ScreenVisualBell ();
864 else
866 union REGS inregs, outregs;
867 inregs.h.ah = 2;
868 inregs.h.dl = 7;
869 intdos (&inregs, &outregs);
873 /* Given a face id FACE, extract the face parameters to be used for
874 display until the face changes. The face parameters (actually, its
875 color) are used to construct the video attribute byte for each
876 glyph during the construction of the buffer that is then blitted to
877 the video RAM. */
878 static void
879 IT_set_face (int face)
881 struct frame *sf = SELECTED_FRAME();
882 struct face *fp = FACE_FROM_ID (sf, face);
883 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
884 unsigned long fg, bg, dflt_fg, dflt_bg;
886 if (!fp)
888 fp = dfp;
889 /* The default face for the frame should always be realized and
890 cached. */
891 if (!fp)
892 abort ();
894 screen_face = face;
895 fg = fp->foreground;
896 bg = fp->background;
897 dflt_fg = dfp->foreground;
898 dflt_bg = dfp->background;
900 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
901 colors mean use the colors of the default face, except that if
902 highlight is on, invert the foreground and the background. Note
903 that we assume all 16 colors to be available for the background,
904 since Emacs switches on this mode (and loses the blinking
905 attribute) at startup. */
906 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
907 fg = FRAME_FOREGROUND_PIXEL (sf);
908 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
909 fg = FRAME_BACKGROUND_PIXEL (sf);
910 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
911 bg = FRAME_BACKGROUND_PIXEL (sf);
912 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
913 bg = FRAME_FOREGROUND_PIXEL (sf);
915 /* Make sure highlighted lines really stand out, come what may. */
916 if ((highlight || fp->tty_reverse_p)
917 && (fg == dflt_fg && bg == dflt_bg))
919 unsigned long tem = fg;
921 fg = bg;
922 bg = tem;
924 /* If the user requested inverse video, obey. */
925 if (inverse_video)
927 unsigned long tem2 = fg;
929 fg = bg;
930 bg = tem2;
932 if (termscript)
933 fprintf (termscript, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face,
934 highlight ? "H" : "", fp->foreground, fp->background, fg, bg);
935 if (fg >= 0 && fg < 16)
937 ScreenAttrib &= 0xf0;
938 ScreenAttrib |= fg;
940 if (bg >= 0 && bg < 16)
942 ScreenAttrib &= 0x0f;
943 ScreenAttrib |= ((bg & 0x0f) << 4);
947 Lisp_Object Vdos_unsupported_char_glyph;
949 static void
950 IT_write_glyphs (struct glyph *str, int str_len)
952 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
953 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
954 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
955 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
956 register int sl = str_len;
957 register int tlen = GLYPH_TABLE_LENGTH;
958 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
960 /* If terminal_coding does any conversion, use it, otherwise use
961 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
962 because it always returns 1 if terminal_coding.src_multibyte is 1. */
963 struct coding_system *coding =
964 (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
965 ? &terminal_coding
966 : &safe_terminal_coding);
967 struct frame *sf;
969 /* Do we need to consider conversion of unibyte characters to
970 multibyte? */
971 int convert_unibyte_characters
972 = (NILP (current_buffer->enable_multibyte_characters)
973 && unibyte_display_via_language_environment);
975 unsigned char conversion_buffer[256];
976 int conversion_buffer_size = sizeof conversion_buffer;
978 if (str_len <= 0) return;
980 screen_buf = screen_bp = alloca (str_len * 2);
981 screen_buf_end = screen_buf + str_len * 2;
982 sf = SELECTED_FRAME();
984 /* Since faces get cached and uncached behind our back, we can't
985 rely on their indices in the cache being consistent across
986 invocations. So always reset the screen face to the default
987 face of the frame, before writing glyphs, and let the glyphs
988 set the right face if it's different from the default. */
989 IT_set_face (DEFAULT_FACE_ID);
991 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
992 the tail. */
993 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
994 while (sl)
996 int cf, chlen, enclen;
997 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
998 unsigned ch;
1000 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
1001 only for the redisplay code to know how many columns does
1002 this character occupy on the screen. Skip padding glyphs. */
1003 if (CHAR_GLYPH_PADDING_P (*str))
1005 str++;
1006 sl--;
1008 else
1010 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
1011 int glyph_not_in_table = 0;
1013 /* If g is negative, it means we have a multibyte character
1014 in *str. That's what GLYPH_FROM_CHAR_GLYPH returns for
1015 multibyte characters. */
1016 if (g < 0 || g >= tlen)
1018 /* This glyph doesn't have an entry in Vglyph_table. */
1019 ch = str->u.ch;
1020 glyph_not_in_table = 1;
1022 else
1024 /* This glyph has an entry in Vglyph_table, so process
1025 any aliases before testing for simpleness. */
1026 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
1027 ch = FAST_GLYPH_CHAR (g);
1030 /* Convert the character code to multibyte, if they
1031 requested display via language environment. We only want
1032 to convert unibyte characters to multibyte in unibyte
1033 buffers! Otherwise, the 8-bit value in CH came from the
1034 display table set up to display foreign characters. */
1035 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
1036 && (ch >= 0240
1037 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
1038 ch = unibyte_char_to_multibyte (ch);
1040 /* Invalid characters are displayed with a special glyph. */
1041 if (! CHAR_VALID_P (ch, 0))
1043 g = !NILP (Vdos_unsupported_char_glyph)
1044 ? Vdos_unsupported_char_glyph
1045 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
1046 ch = FAST_GLYPH_CHAR (g);
1049 /* If the face of this glyph is different from the current
1050 screen face, update the screen attribute byte. */
1051 cf = str->face_id;
1052 if (cf != screen_face)
1053 IT_set_face (cf); /* handles invalid faces gracefully */
1055 if (glyph_not_in_table || GLYPH_SIMPLE_P (tbase, tlen, g))
1057 /* We generate the multi-byte form of CH in WORKBUF. */
1058 chlen = CHAR_STRING (ch, workbuf);
1059 buf = workbuf;
1061 else
1063 /* We have a string in Vglyph_table. */
1064 chlen = GLYPH_LENGTH (tbase, g);
1065 buf = GLYPH_STRING (tbase, g);
1068 /* If the character is not multibyte, don't bother converting it. */
1069 if (chlen == 1)
1071 *conversion_buffer = (unsigned char)ch;
1072 chlen = 0;
1073 enclen = 1;
1075 else
1077 coding->src_multibyte = 1;
1078 encode_coding (coding, buf, conversion_buffer, chlen,
1079 conversion_buffer_size);
1080 chlen -= coding->consumed;
1081 enclen = coding->produced;
1083 /* Replace glyph codes that cannot be converted by
1084 terminal_coding with Vdos_unsupported_char_glyph. */
1085 if (*conversion_buffer == '?')
1087 unsigned char *cbp = conversion_buffer;
1089 while (cbp < conversion_buffer + enclen && *cbp == '?')
1090 *cbp++ = unsupported_char;
1091 if (unsupported_face != screen_face)
1092 IT_set_face (unsupported_face);
1096 if (enclen + chlen > screen_buf_end - screen_bp)
1098 /* The allocated buffer for screen writes is too small.
1099 Flush it and loop again without incrementing STR, so
1100 that the next loop will begin with the same glyph. */
1101 int nbytes = screen_bp - screen_buf;
1103 mouse_off_maybe ();
1104 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1105 if (screen_virtual_segment)
1106 dosv_refresh_virtual_screen (offset, nbytes / 2);
1107 new_pos_X += nbytes / 2;
1108 offset += nbytes;
1110 /* Prepare to reuse the same buffer again. */
1111 screen_bp = screen_buf;
1113 else
1115 /* There's enough place in the allocated buffer to add
1116 the encoding of this glyph. */
1118 /* First, copy the encoded bytes. */
1119 for (bp = conversion_buffer; enclen--; bp++)
1121 *screen_bp++ = (unsigned char)*bp;
1122 *screen_bp++ = ScreenAttrib;
1123 if (termscript)
1124 fputc (*bp, termscript);
1127 /* Now copy the bytes not consumed by the encoding. */
1128 if (chlen > 0)
1130 buf += coding->consumed;
1131 while (chlen--)
1133 if (termscript)
1134 fputc (*buf, termscript);
1135 *screen_bp++ = (unsigned char)*buf++;
1136 *screen_bp++ = ScreenAttrib;
1140 /* Update STR and its remaining length. */
1141 str++;
1142 sl--;
1147 /* Dump whatever is left in the screen buffer. */
1148 mouse_off_maybe ();
1149 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1150 if (screen_virtual_segment)
1151 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1152 new_pos_X += (screen_bp - screen_buf) / 2;
1154 /* We may have to output some codes to terminate the writing. */
1155 if (CODING_REQUIRE_FLUSHING (coding))
1157 coding->mode |= CODING_MODE_LAST_BLOCK;
1158 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
1159 if (coding->produced > 0)
1161 screen_buf = alloca (coding->produced * 2);
1162 for (screen_bp = screen_buf, bp = conversion_buffer;
1163 coding->produced--; bp++)
1165 *screen_bp++ = (unsigned char)*bp;
1166 *screen_bp++ = ScreenAttrib;
1167 if (termscript)
1168 fputc (*bp, termscript);
1170 offset += screen_bp - screen_buf;
1171 mouse_off_maybe ();
1172 dosmemput (screen_buf, screen_bp - screen_buf,
1173 (int)ScreenPrimary + offset);
1174 if (screen_virtual_segment)
1175 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1176 new_pos_X += (screen_bp - screen_buf) / 2;
1181 /************************************************************************
1182 Mouse Highlight (and friends..)
1183 ************************************************************************/
1185 /* This is used for debugging, to turn off note_mouse_highlight. */
1186 int disable_mouse_highlight;
1188 /* If non-nil, dos_rawgetc generates an event to display that string.
1189 (The display is done in keyboard.c:read_char, by calling
1190 show_help_echo.) */
1191 static Lisp_Object help_echo;
1192 static Lisp_Object previous_help_echo; /* a helper temporary variable */
1194 /* These record the window, the object and the position where the help
1195 echo string was generated. */
1196 static Lisp_Object help_echo_window;
1197 static Lisp_Object help_echo_object;
1198 static int help_echo_pos;
1200 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1202 /* Set the mouse pointer shape according to whether it is in the
1203 area where the mouse highlight is in effect. */
1204 static void
1205 IT_set_mouse_pointer (int mode)
1207 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1208 many possibilities to change its shape, and the available
1209 functionality pretty much sucks (e.g., almost every reasonable
1210 shape will conceal the character it is on). Since the color of
1211 the pointer changes in the highlighted area, it is not clear to
1212 me whether anything else is required, anyway. */
1215 /* Display the active region described by mouse_face_*
1216 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1217 static void
1218 show_mouse_face (struct display_info *dpyinfo, int hl)
1220 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1221 struct frame *f = XFRAME (WINDOW_FRAME (w));
1222 int i;
1223 struct face *fp;
1226 /* If window is in the process of being destroyed, don't bother
1227 doing anything. */
1228 if (w->current_matrix == NULL)
1229 goto set_cursor_shape;
1231 /* Recognize when we are called to operate on rows that don't exist
1232 anymore. This can happen when a window is split. */
1233 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1234 goto set_cursor_shape;
1236 /* There's no sense to do anything if the mouse face isn't realized. */
1237 if (hl > 0)
1239 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1240 if (!fp)
1241 goto set_cursor_shape;
1244 /* Note that mouse_face_beg_row etc. are window relative. */
1245 for (i = dpyinfo->mouse_face_beg_row;
1246 i <= dpyinfo->mouse_face_end_row;
1247 i++)
1249 int start_hpos, end_hpos;
1250 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1252 /* Don't do anything if row doesn't have valid contents. */
1253 if (!row->enabled_p)
1254 continue;
1256 /* For all but the first row, the highlight starts at column 0. */
1257 if (i == dpyinfo->mouse_face_beg_row)
1258 start_hpos = dpyinfo->mouse_face_beg_col;
1259 else
1260 start_hpos = 0;
1262 if (i == dpyinfo->mouse_face_end_row)
1263 end_hpos = dpyinfo->mouse_face_end_col;
1264 else
1265 end_hpos = row->used[TEXT_AREA];
1267 if (end_hpos <= start_hpos)
1268 continue;
1269 /* Record that some glyphs of this row are displayed in
1270 mouse-face. */
1271 row->mouse_face_p = hl > 0;
1272 if (hl > 0)
1274 int vpos = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1275 int kstart = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1276 int nglyphs = end_hpos - start_hpos;
1277 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1278 int start_offset = offset;
1280 if (termscript)
1281 fprintf (termscript, "\n<MH+ %d-%d:%d>",
1282 kstart, kstart + nglyphs - 1, vpos);
1284 mouse_off ();
1285 IT_set_face (dpyinfo->mouse_face_face_id);
1286 /* Since we are going to change only the _colors_ of the
1287 displayed text, there's no need to go through all the
1288 pain of generating and encoding the text from the glyphs.
1289 Instead, we simply poke the attribute byte of each
1290 affected position in video memory with the colors
1291 computed by IT_set_face! */
1292 _farsetsel (_dos_ds);
1293 while (nglyphs--)
1295 _farnspokeb (offset, ScreenAttrib);
1296 offset += 2;
1298 if (screen_virtual_segment)
1299 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1300 mouse_on ();
1302 else
1304 /* We are removing a previously-drawn mouse highlight. The
1305 safest way to do so is to redraw the glyphs anew, since
1306 all kinds of faces and display tables could have changed
1307 behind our back. */
1308 int nglyphs = end_hpos - start_hpos;
1309 int save_x = new_pos_X, save_y = new_pos_Y;
1311 if (end_hpos >= row->used[TEXT_AREA])
1312 nglyphs = row->used[TEXT_AREA] - start_hpos;
1314 /* IT_write_glyphs writes at cursor position, so we need to
1315 temporarily move cursor coordinates to the beginning of
1316 the highlight region. */
1317 new_pos_X = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1318 new_pos_Y = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1320 if (termscript)
1321 fprintf (termscript, "<MH- %d-%d:%d>",
1322 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1323 IT_write_glyphs (row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1324 if (termscript)
1325 fputs ("\n", termscript);
1326 new_pos_X = save_x;
1327 new_pos_Y = save_y;
1331 set_cursor_shape:
1333 /* Change the mouse pointer shape. */
1334 IT_set_mouse_pointer (hl);
1337 /* Clear out the mouse-highlighted active region.
1338 Redraw it un-highlighted first. */
1339 static void
1340 clear_mouse_face (struct display_info *dpyinfo)
1342 if (! NILP (dpyinfo->mouse_face_window))
1343 show_mouse_face (dpyinfo, 0);
1345 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1346 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1347 dpyinfo->mouse_face_window = Qnil;
1350 /* Find the glyph matrix position of buffer position POS in window W.
1351 *HPOS and *VPOS are set to the positions found. W's current glyphs
1352 must be up to date. If POS is above window start return (0, 0).
1353 If POS is after end of W, return end of last line in W. */
1354 static int
1355 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1357 int i;
1358 int lastcol;
1359 int maybe_next_line_p = 0;
1360 int line_start_position;
1361 int yb = window_text_bottom_y (w);
1362 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
1363 struct glyph_row *best_row = row;
1365 while (row->y < yb)
1367 if (row->used[TEXT_AREA])
1368 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1369 else
1370 line_start_position = 0;
1372 if (line_start_position > pos)
1373 break;
1374 /* If the position sought is the end of the buffer,
1375 don't include the blank lines at the bottom of the window. */
1376 else if (line_start_position == pos
1377 && pos == BUF_ZV (XBUFFER (w->buffer)))
1379 maybe_next_line_p = 1;
1380 break;
1382 else if (line_start_position > 0)
1383 best_row = row;
1385 /* Don't overstep the last matrix row, lest we get into the
1386 never-never land... */
1387 if (row->y + 1 >= yb)
1388 break;
1390 ++row;
1393 /* Find the right column within BEST_ROW. */
1394 lastcol = 0;
1395 row = best_row;
1396 for (i = 0; i < row->used[TEXT_AREA]; i++)
1398 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1399 int charpos;
1401 charpos = glyph->charpos;
1402 if (charpos == pos)
1404 *hpos = i;
1405 *vpos = row->y;
1406 return 1;
1408 else if (charpos > pos)
1409 break;
1410 else if (charpos > 0)
1411 lastcol = i;
1414 /* If we're looking for the end of the buffer,
1415 and we didn't find it in the line we scanned,
1416 use the start of the following line. */
1417 if (maybe_next_line_p)
1419 ++row;
1420 lastcol = 0;
1423 *vpos = row->y;
1424 *hpos = lastcol + 1;
1425 return 0;
1428 /* Take proper action when mouse has moved to the mode or top line of
1429 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1430 mode line. X is relative to the start of the text display area of
1431 W, so the width of bitmap areas and scroll bars must be subtracted
1432 to get a position relative to the start of the mode line. */
1433 static void
1434 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1436 struct frame *f = XFRAME (w->frame);
1437 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1438 struct glyph_row *row;
1440 if (mode_line_p)
1441 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1442 else
1443 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1445 if (row->enabled_p)
1447 extern Lisp_Object Qhelp_echo;
1448 struct glyph *glyph, *end;
1449 Lisp_Object help, map;
1451 /* Find the glyph under X. */
1452 glyph = row->glyphs[TEXT_AREA]
1453 + x - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
1454 end = glyph + row->used[TEXT_AREA];
1455 if (glyph < end
1456 && STRINGP (glyph->object)
1457 && XSTRING (glyph->object)->intervals
1458 && glyph->charpos >= 0
1459 && glyph->charpos < XSTRING (glyph->object)->size)
1461 /* If we're on a string with `help-echo' text property,
1462 arrange for the help to be displayed. This is done by
1463 setting the global variable help_echo to the help string. */
1464 help = Fget_text_property (make_number (glyph->charpos),
1465 Qhelp_echo, glyph->object);
1466 if (!NILP (help))
1468 help_echo = help;
1469 XSETWINDOW (help_echo_window, w);
1470 help_echo_object = glyph->object;
1471 help_echo_pos = glyph->charpos;
1477 /* Take proper action when the mouse has moved to position X, Y on
1478 frame F as regards highlighting characters that have mouse-face
1479 properties. Also de-highlighting chars where the mouse was before.
1480 X and Y can be negative or out of range. */
1481 static void
1482 IT_note_mouse_highlight (struct frame *f, int x, int y)
1484 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1485 int portion = -1;
1486 Lisp_Object window;
1487 struct window *w;
1489 /* When a menu is active, don't highlight because this looks odd. */
1490 if (mouse_preempted)
1491 return;
1493 if (disable_mouse_highlight
1494 || !f->glyphs_initialized_p)
1495 return;
1497 dpyinfo->mouse_face_mouse_x = x;
1498 dpyinfo->mouse_face_mouse_y = y;
1499 dpyinfo->mouse_face_mouse_frame = f;
1501 if (dpyinfo->mouse_face_defer)
1502 return;
1504 if (gc_in_progress)
1506 dpyinfo->mouse_face_deferred_gc = 1;
1507 return;
1510 /* Which window is that in? */
1511 window = window_from_coordinates (f, x, y, &portion, 0);
1513 /* If we were displaying active text in another window, clear that. */
1514 if (! EQ (window, dpyinfo->mouse_face_window))
1515 clear_mouse_face (dpyinfo);
1517 /* Not on a window -> return. */
1518 if (!WINDOWP (window))
1519 return;
1521 /* Convert to window-relative coordinates. */
1522 w = XWINDOW (window);
1523 x -= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1524 y -= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1526 if (portion == 1 || portion == 3)
1528 /* Mouse is on the mode or top line. */
1529 IT_note_mode_line_highlight (w, x, portion == 1);
1530 return;
1532 else
1533 IT_set_mouse_pointer (0);
1535 /* Are we in a window whose display is up to date?
1536 And verify the buffer's text has not changed. */
1537 if (/* Within text portion of the window. */
1538 portion == 0
1539 && EQ (w->window_end_valid, w->buffer)
1540 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1541 && (XFASTINT (w->last_overlay_modified)
1542 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1544 int pos, i;
1545 struct glyph_row *row;
1546 struct glyph *glyph;
1547 int nrows = w->current_matrix->nrows;
1549 /* Find the glyph under X/Y. */
1550 glyph = NULL;
1551 if (y >= 0 && y < nrows)
1553 row = MATRIX_ROW (w->current_matrix, y);
1554 /* Give up if some row before the one we are looking for is
1555 not enabled. */
1556 for (i = 0; i <= y; i++)
1557 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1558 break;
1559 if (i > y /* all rows upto and including the one at Y are enabled */
1560 && row->displays_text_p
1561 && x < window_box_width (w, TEXT_AREA))
1563 glyph = row->glyphs[TEXT_AREA];
1564 if (x >= row->used[TEXT_AREA])
1565 glyph = NULL;
1566 else
1568 glyph += x;
1569 if (!BUFFERP (glyph->object))
1570 glyph = NULL;
1575 /* Clear mouse face if X/Y not over text. */
1576 if (glyph == NULL)
1578 clear_mouse_face (dpyinfo);
1579 return;
1582 if (!BUFFERP (glyph->object))
1583 abort ();
1584 pos = glyph->charpos;
1586 /* Check for mouse-face and help-echo. */
1588 extern Lisp_Object Qmouse_face;
1589 Lisp_Object mouse_face, overlay, position;
1590 Lisp_Object *overlay_vec;
1591 int len, noverlays;
1592 struct buffer *obuf;
1593 int obegv, ozv;
1595 /* If we get an out-of-range value, return now; avoid an error. */
1596 if (pos > BUF_Z (XBUFFER (w->buffer)))
1597 return;
1599 /* Make the window's buffer temporarily current for
1600 overlays_at and compute_char_face. */
1601 obuf = current_buffer;
1602 current_buffer = XBUFFER (w->buffer);
1603 obegv = BEGV;
1604 ozv = ZV;
1605 BEGV = BEG;
1606 ZV = Z;
1608 /* Is this char mouse-active or does it have help-echo? */
1609 XSETINT (position, pos);
1611 /* Put all the overlays we want in a vector in overlay_vec.
1612 Store the length in len. If there are more than 10, make
1613 enough space for all, and try again. */
1614 len = 10;
1615 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1616 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
1617 if (noverlays > len)
1619 len = noverlays;
1620 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1621 noverlays = overlays_at (pos,
1622 0, &overlay_vec, &len, NULL, NULL, 0);
1625 /* Sort overlays into increasing priority order. */
1626 noverlays = sort_overlays (overlay_vec, noverlays, w);
1628 /* Check mouse-face highlighting. */
1629 if (! (EQ (window, dpyinfo->mouse_face_window)
1630 && y >= dpyinfo->mouse_face_beg_row
1631 && y <= dpyinfo->mouse_face_end_row
1632 && (y > dpyinfo->mouse_face_beg_row
1633 || x >= dpyinfo->mouse_face_beg_col)
1634 && (y < dpyinfo->mouse_face_end_row
1635 || x < dpyinfo->mouse_face_end_col
1636 || dpyinfo->mouse_face_past_end)))
1638 /* Clear the display of the old active region, if any. */
1639 clear_mouse_face (dpyinfo);
1641 /* Find highest priority overlay that has a mouse-face prop. */
1642 overlay = Qnil;
1643 for (i = noverlays - 1; i >= 0; --i)
1645 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1646 if (!NILP (mouse_face))
1648 overlay = overlay_vec[i];
1649 break;
1653 /* If no overlay applies, get a text property. */
1654 if (NILP (overlay))
1655 mouse_face = Fget_text_property (position, Qmouse_face,
1656 w->buffer);
1658 /* Handle the overlay case. */
1659 if (! NILP (overlay))
1661 /* Find the range of text around this char that
1662 should be active. */
1663 Lisp_Object before, after;
1664 int ignore;
1666 before = Foverlay_start (overlay);
1667 after = Foverlay_end (overlay);
1668 /* Record this as the current active region. */
1669 fast_find_position (w, XFASTINT (before),
1670 &dpyinfo->mouse_face_beg_col,
1671 &dpyinfo->mouse_face_beg_row);
1672 dpyinfo->mouse_face_past_end
1673 = !fast_find_position (w, XFASTINT (after),
1674 &dpyinfo->mouse_face_end_col,
1675 &dpyinfo->mouse_face_end_row);
1676 dpyinfo->mouse_face_window = window;
1677 dpyinfo->mouse_face_face_id
1678 = face_at_buffer_position (w, pos, 0, 0,
1679 &ignore, pos + 1, 1);
1681 /* Display it as active. */
1682 show_mouse_face (dpyinfo, 1);
1684 /* Handle the text property case. */
1685 else if (! NILP (mouse_face))
1687 /* Find the range of text around this char that
1688 should be active. */
1689 Lisp_Object before, after, beginning, end;
1690 int ignore;
1692 beginning = Fmarker_position (w->start);
1693 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1694 - XFASTINT (w->window_end_pos)));
1695 before
1696 = Fprevious_single_property_change (make_number (pos + 1),
1697 Qmouse_face,
1698 w->buffer, beginning);
1699 after
1700 = Fnext_single_property_change (position, Qmouse_face,
1701 w->buffer, end);
1702 /* Record this as the current active region. */
1703 fast_find_position (w, XFASTINT (before),
1704 &dpyinfo->mouse_face_beg_col,
1705 &dpyinfo->mouse_face_beg_row);
1706 dpyinfo->mouse_face_past_end
1707 = !fast_find_position (w, XFASTINT (after),
1708 &dpyinfo->mouse_face_end_col,
1709 &dpyinfo->mouse_face_end_row);
1710 dpyinfo->mouse_face_window = window;
1711 dpyinfo->mouse_face_face_id
1712 = face_at_buffer_position (w, pos, 0, 0,
1713 &ignore, pos + 1, 1);
1715 /* Display it as active. */
1716 show_mouse_face (dpyinfo, 1);
1720 /* Look for a `help-echo' property. */
1722 Lisp_Object help;
1723 extern Lisp_Object Qhelp_echo;
1725 /* Check overlays first. */
1726 help = Qnil;
1727 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1729 overlay = overlay_vec[i];
1730 help = Foverlay_get (overlay, Qhelp_echo);
1733 if (!NILP (help))
1735 help_echo = help;
1736 help_echo_window = window;
1737 help_echo_object = overlay;
1738 help_echo_pos = pos;
1740 /* Try text properties. */
1741 else if (NILP (help)
1742 && ((STRINGP (glyph->object)
1743 && glyph->charpos >= 0
1744 && glyph->charpos < XSTRING (glyph->object)->size)
1745 || (BUFFERP (glyph->object)
1746 && glyph->charpos >= BEGV
1747 && glyph->charpos < ZV)))
1749 help = Fget_text_property (make_number (glyph->charpos),
1750 Qhelp_echo, glyph->object);
1751 if (!NILP (help))
1753 help_echo = help;
1754 help_echo_window = window;
1755 help_echo_object = glyph->object;
1756 help_echo_pos = glyph->charpos;
1761 BEGV = obegv;
1762 ZV = ozv;
1763 current_buffer = obuf;
1768 static void
1769 IT_clear_end_of_line (int first_unused)
1771 char *spaces, *sp;
1772 int i, j;
1773 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1774 extern int fatal_error_in_progress;
1776 if (new_pos_X >= first_unused || fatal_error_in_progress)
1777 return;
1779 IT_set_face (0);
1780 i = (j = first_unused - new_pos_X) * 2;
1781 if (termscript)
1782 fprintf (termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1783 spaces = sp = alloca (i);
1785 while (--j >= 0)
1787 *sp++ = ' ';
1788 *sp++ = ScreenAttrib;
1791 mouse_off_maybe ();
1792 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1793 if (screen_virtual_segment)
1794 dosv_refresh_virtual_screen (offset, i / 2);
1796 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1797 Let's follow their lead, in case someone relies on this. */
1798 new_pos_X = first_unused;
1801 static void
1802 IT_clear_screen (void)
1804 if (termscript)
1805 fprintf (termscript, "<CLR:SCR>");
1806 /* We are sometimes called (from clear_garbaged_frames) when a new
1807 frame is being created, but its faces are not yet realized. In
1808 such a case we cannot call IT_set_face, since it will fail to find
1809 any valid faces and will abort. Instead, use the initial screen
1810 colors; that should mimic what a Unix tty does, which simply clears
1811 the screen with whatever default colors are in use. */
1812 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1813 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1814 else
1815 IT_set_face (0);
1816 mouse_off ();
1817 ScreenClear ();
1818 if (screen_virtual_segment)
1819 dosv_refresh_virtual_screen (0, screen_size);
1820 new_pos_X = new_pos_Y = 0;
1823 static void
1824 IT_clear_to_end (void)
1826 if (termscript)
1827 fprintf (termscript, "<CLR:EOS>");
1829 while (new_pos_Y < screen_size_Y) {
1830 new_pos_X = 0;
1831 IT_clear_end_of_line (screen_size_X);
1832 new_pos_Y++;
1836 static void
1837 IT_cursor_to (int y, int x)
1839 if (termscript)
1840 fprintf (termscript, "\n<XY=%dx%d>", x, y);
1841 new_pos_X = x;
1842 new_pos_Y = y;
1845 static int cursor_cleared;
1847 static void
1848 IT_display_cursor (int on)
1850 if (on && cursor_cleared)
1852 ScreenSetCursor (current_pos_Y, current_pos_X);
1853 cursor_cleared = 0;
1855 else if (!on && !cursor_cleared)
1857 ScreenSetCursor (-1, -1);
1858 cursor_cleared = 1;
1862 /* Emacs calls cursor-movement functions a lot when it updates the
1863 display (probably a legacy of old terminals where you cannot
1864 update a screen line without first moving the cursor there).
1865 However, cursor movement is expensive on MSDOS (it calls a slow
1866 BIOS function and requires 2 mode switches), while actual screen
1867 updates access the video memory directly and don't depend on
1868 cursor position. To avoid slowing down the redisplay, we cheat:
1869 all functions that move the cursor only set internal variables
1870 which record the cursor position, whereas the cursor is only
1871 moved to its final position whenever screen update is complete.
1873 `IT_cmgoto' is called from the keyboard reading loop and when the
1874 frame update is complete. This means that we are ready for user
1875 input, so we update the cursor position to show where the point is,
1876 and also make the mouse pointer visible.
1878 Special treatment is required when the cursor is in the echo area,
1879 to put the cursor at the end of the text displayed there. */
1881 static void
1882 IT_cmgoto (FRAME_PTR f)
1884 /* Only set the cursor to where it should be if the display is
1885 already in sync with the window contents. */
1886 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1888 /* FIXME: This needs to be rewritten for the new redisplay, or
1889 removed. */
1890 #if 0
1891 static int previous_pos_X = -1;
1893 update_cursor_pos = 1; /* temporary!!! */
1895 /* If the display is in sync, forget any previous knowledge about
1896 cursor position. This is primarily for unexpected events like
1897 C-g in the minibuffer. */
1898 if (update_cursor_pos && previous_pos_X >= 0)
1899 previous_pos_X = -1;
1900 /* If we are in the echo area, put the cursor at the
1901 end of the echo area message. */
1902 if (!update_cursor_pos
1903 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1905 int tem_X = current_pos_X, dummy;
1907 if (echo_area_glyphs)
1909 tem_X = echo_area_glyphs_length;
1910 /* Save current cursor position, to be restored after the
1911 echo area message is erased. Only remember one level
1912 of previous cursor position. */
1913 if (previous_pos_X == -1)
1914 ScreenGetCursor (&dummy, &previous_pos_X);
1916 else if (previous_pos_X >= 0)
1918 /* We wind up here after the echo area message is erased.
1919 Restore the cursor position we remembered above. */
1920 tem_X = previous_pos_X;
1921 previous_pos_X = -1;
1924 if (current_pos_X != tem_X)
1926 new_pos_X = tem_X;
1927 update_cursor_pos = 1;
1930 #endif
1932 if (update_cursor_pos
1933 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1935 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1936 if (termscript)
1937 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1940 /* Maybe cursor is invisible, so make it visible. */
1941 IT_display_cursor (1);
1943 /* Mouse pointer should be always visible if we are waiting for
1944 keyboard input. */
1945 if (!mouse_visible)
1946 mouse_on ();
1949 static void
1950 IT_reassert_line_highlight (int new, int vpos)
1952 highlight = new;
1955 static void
1956 IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1958 highlight = new_highlight;
1959 IT_cursor_to (vpos, 0);
1960 IT_clear_end_of_line (first_unused_hpos);
1963 static void
1964 IT_update_begin (struct frame *f)
1966 struct display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1967 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1969 highlight = 0;
1971 BLOCK_INPUT;
1973 if (f && f == mouse_face_frame)
1975 /* Don't do highlighting for mouse motion during the update. */
1976 display_info->mouse_face_defer = 1;
1978 /* If F needs to be redrawn, simply forget about any prior mouse
1979 highlighting. */
1980 if (FRAME_GARBAGED_P (f))
1981 display_info->mouse_face_window = Qnil;
1983 /* Can we tell that this update does not affect the window
1984 where the mouse highlight is? If so, no need to turn off.
1985 Likewise, don't do anything if none of the enabled rows
1986 contains glyphs highlighted in mouse face. */
1987 if (!NILP (display_info->mouse_face_window)
1988 && WINDOWP (display_info->mouse_face_window))
1990 struct window *w = XWINDOW (display_info->mouse_face_window);
1991 int i;
1993 /* If the mouse highlight is in the window that was deleted
1994 (e.g., if it was popped by completion), clear highlight
1995 unconditionally. */
1996 if (NILP (w->buffer))
1997 display_info->mouse_face_window = Qnil;
1998 else
2000 for (i = 0; i < w->desired_matrix->nrows; ++i)
2001 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
2002 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
2003 break;
2006 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
2007 clear_mouse_face (display_info);
2010 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
2012 /* If the frame with mouse highlight was deleted, invalidate the
2013 highlight info. */
2014 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
2015 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
2016 display_info->mouse_face_window = Qnil;
2017 display_info->mouse_face_deferred_gc = 0;
2018 display_info->mouse_face_mouse_frame = NULL;
2021 UNBLOCK_INPUT;
2024 static void
2025 IT_update_end (struct frame *f)
2027 highlight = 0;
2028 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
2031 Lisp_Object Qcursor_type;
2033 static void
2034 IT_frame_up_to_date (struct frame *f)
2036 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
2037 Lisp_Object new_cursor, frame_desired_cursor;
2038 struct window *sw;
2040 if (dpyinfo->mouse_face_deferred_gc
2041 || (f && f == dpyinfo->mouse_face_mouse_frame))
2043 BLOCK_INPUT;
2044 if (dpyinfo->mouse_face_mouse_frame)
2045 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2046 dpyinfo->mouse_face_mouse_x,
2047 dpyinfo->mouse_face_mouse_y);
2048 dpyinfo->mouse_face_deferred_gc = 0;
2049 UNBLOCK_INPUT;
2052 /* Set the cursor type to whatever they wanted. In a minibuffer
2053 window, we want the cursor to appear only if we are reading input
2054 from this window, and we want the cursor to be taken from the
2055 frame parameters. For the selected window, we use either its
2056 buffer-local value or the value from the frame parameters if the
2057 buffer doesn't define its local value for the cursor type. */
2058 sw = XWINDOW (f->selected_window);
2059 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
2060 if (cursor_in_echo_area
2061 && FRAME_HAS_MINIBUF_P (f)
2062 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
2063 && sw == XWINDOW (echo_area_window))
2064 new_cursor = frame_desired_cursor;
2065 else
2067 struct buffer *b = XBUFFER (sw->buffer);
2069 if (EQ (b->cursor_type, Qt))
2070 new_cursor = frame_desired_cursor;
2071 else if (NILP (b->cursor_type)) /* nil means no cursor */
2072 new_cursor = Fcons (Qbar, make_number (0));
2073 else
2074 new_cursor = b->cursor_type;
2077 IT_set_cursor_type (f, new_cursor);
2079 IT_cmgoto (f); /* position cursor when update is done */
2082 /* Copy LEN glyphs displayed on a single line whose vertical position
2083 is YPOS, beginning at horizontal position XFROM to horizontal
2084 position XTO, by moving blocks in the video memory. Used by
2085 functions that insert and delete glyphs. */
2086 static void
2087 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
2089 /* The offsets of source and destination relative to the
2090 conventional memorty selector. */
2091 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
2092 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
2094 if (from == to || len <= 0)
2095 return;
2097 _farsetsel (_dos_ds);
2099 /* The source and destination might overlap, so we need to move
2100 glyphs non-destructively. */
2101 if (from > to)
2103 for ( ; len; from += 2, to += 2, len--)
2104 _farnspokew (to, _farnspeekw (from));
2106 else
2108 from += (len - 1) * 2;
2109 to += (len - 1) * 2;
2110 for ( ; len; from -= 2, to -= 2, len--)
2111 _farnspokew (to, _farnspeekw (from));
2113 if (screen_virtual_segment)
2114 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
2117 /* Insert and delete glyphs. */
2118 static void
2119 IT_insert_glyphs (start, len)
2120 register struct glyph *start;
2121 register int len;
2123 int shift_by_width = screen_size_X - (new_pos_X + len);
2125 /* Shift right the glyphs from the nominal cursor position to the
2126 end of this line. */
2127 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
2129 /* Now write the glyphs to be inserted. */
2130 IT_write_glyphs (start, len);
2133 static void
2134 IT_delete_glyphs (n)
2135 register int n;
2137 abort ();
2140 /* set-window-configuration on window.c needs this. */
2141 void
2142 x_set_menu_bar_lines (f, value, oldval)
2143 struct frame *f;
2144 Lisp_Object value, oldval;
2146 set_menu_bar_lines (f, value, oldval);
2149 /* This was copied from xfaces.c */
2151 extern Lisp_Object Qbackground_color;
2152 extern Lisp_Object Qforeground_color;
2153 Lisp_Object Qreverse;
2154 extern Lisp_Object Qtitle;
2156 /* IT_set_terminal_modes is called when emacs is started,
2157 resumed, and whenever the screen is redrawn! */
2159 static void
2160 IT_set_terminal_modes (void)
2162 if (termscript)
2163 fprintf (termscript, "\n<SET_TERM>");
2164 highlight = 0;
2166 screen_size_X = ScreenCols ();
2167 screen_size_Y = ScreenRows ();
2168 screen_size = screen_size_X * screen_size_Y;
2170 new_pos_X = new_pos_Y = 0;
2171 current_pos_X = current_pos_Y = -1;
2173 if (term_setup_done)
2174 return;
2175 term_setup_done = 1;
2177 startup_screen_size_X = screen_size_X;
2178 startup_screen_size_Y = screen_size_Y;
2179 startup_screen_attrib = ScreenAttrib;
2181 #if __DJGPP__ > 1
2182 /* Is DOS/V (or any other RSIS software which relocates
2183 the screen) installed? */
2185 unsigned short es_value;
2186 __dpmi_regs regs;
2188 regs.h.ah = 0xfe; /* get relocated screen address */
2189 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2190 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2191 else if (screen_old_address) /* already switched to Japanese mode once */
2192 regs.x.es = (screen_old_address >> 4) & 0xffff;
2193 else
2194 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2195 regs.x.di = 0;
2196 es_value = regs.x.es;
2197 __dpmi_int (0x10, &regs);
2199 if (regs.x.es != es_value)
2201 /* screen_old_address is only set if ScreenPrimary does NOT
2202 already point to the relocated buffer address returned by
2203 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2204 ScreenPrimary to that address at startup under DOS/V. */
2205 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2206 screen_old_address = ScreenPrimary;
2207 screen_virtual_segment = regs.x.es;
2208 screen_virtual_offset = regs.x.di;
2209 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2212 #endif /* __DJGPP__ > 1 */
2214 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2215 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2217 if (termscript)
2218 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2219 screen_size_X, screen_size_Y);
2221 bright_bg ();
2224 /* IT_reset_terminal_modes is called when emacs is
2225 suspended or killed. */
2227 static void
2228 IT_reset_terminal_modes (void)
2230 int display_row_start = (int) ScreenPrimary;
2231 int saved_row_len = startup_screen_size_X * 2;
2232 int update_row_len = ScreenCols () * 2;
2233 int current_rows = ScreenRows ();
2234 int to_next_row = update_row_len;
2235 unsigned char *saved_row = startup_screen_buffer;
2236 int cursor_pos_X = ScreenCols () - 1;
2237 int cursor_pos_Y = ScreenRows () - 1;
2239 if (termscript)
2240 fprintf (termscript, "\n<RESET_TERM>");
2242 highlight = 0;
2244 if (!term_setup_done)
2245 return;
2247 mouse_off ();
2249 /* Leave the video system in the same state as we found it,
2250 as far as the blink/bright-background bit is concerned. */
2251 maybe_enable_blinking ();
2253 /* We have a situation here.
2254 We cannot just do ScreenUpdate(startup_screen_buffer) because
2255 the luser could have changed screen dimensions inside Emacs
2256 and failed (or didn't want) to restore them before killing
2257 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2258 thus will happily use memory outside what was allocated for
2259 `startup_screen_buffer'.
2260 Thus we only restore as much as the current screen dimensions
2261 can hold, and clear the rest (if the saved screen is smaller than
2262 the current) with the color attribute saved at startup. The cursor
2263 is also restored within the visible dimensions. */
2265 ScreenAttrib = startup_screen_attrib;
2267 /* Don't restore the screen if we are exiting less than 2 seconds
2268 after startup: we might be crashing, and the screen might show
2269 some vital clues to what's wrong. */
2270 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2272 ScreenClear ();
2273 if (screen_virtual_segment)
2274 dosv_refresh_virtual_screen (0, screen_size);
2276 if (update_row_len > saved_row_len)
2277 update_row_len = saved_row_len;
2278 if (current_rows > startup_screen_size_Y)
2279 current_rows = startup_screen_size_Y;
2281 if (termscript)
2282 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2283 update_row_len / 2, current_rows);
2285 while (current_rows--)
2287 dosmemput (saved_row, update_row_len, display_row_start);
2288 if (screen_virtual_segment)
2289 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2290 update_row_len / 2);
2291 saved_row += saved_row_len;
2292 display_row_start += to_next_row;
2295 if (startup_pos_X < cursor_pos_X)
2296 cursor_pos_X = startup_pos_X;
2297 if (startup_pos_Y < cursor_pos_Y)
2298 cursor_pos_Y = startup_pos_Y;
2300 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2301 xfree (startup_screen_buffer);
2303 term_setup_done = 0;
2306 static void
2307 IT_set_terminal_window (int foo)
2311 /* Remember the screen colors of the curent frame, to serve as the
2312 default colors for newly-created frames. */
2313 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2314 Smsdos_remember_default_colors, 1, 1, 0,
2315 "Remember the screen colors of the current frame.")
2316 (frame)
2317 Lisp_Object frame;
2319 struct frame *f;
2321 CHECK_FRAME (frame, 0);
2322 f= XFRAME (frame);
2324 /* This function is called after applying default-frame-alist to the
2325 initial frame. At that time, if reverse-colors option was
2326 specified in default-frame-alist, it was already applied, and
2327 frame colors are reversed. We need to account for that. */
2328 if (EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt))
2330 initial_screen_colors[0] = FRAME_BACKGROUND_PIXEL (f);
2331 initial_screen_colors[1] = FRAME_FOREGROUND_PIXEL (f);
2333 else
2335 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2336 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2340 void
2341 IT_set_frame_parameters (f, alist)
2342 struct frame *f;
2343 Lisp_Object alist;
2345 Lisp_Object tail;
2346 int length = XINT (Flength (alist));
2347 int i, j;
2348 Lisp_Object *parms
2349 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2350 Lisp_Object *values
2351 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2352 /* Do we have to reverse the foreground and background colors? */
2353 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2354 int was_reverse = reverse;
2355 int redraw = 0, fg_set = 0, bg_set = 0;
2356 int need_to_reverse;
2357 unsigned long orig_fg;
2358 unsigned long orig_bg;
2359 Lisp_Object frame_bg, frame_fg;
2360 extern Lisp_Object Qdefault, QCforeground, QCbackground;
2362 /* If we are creating a new frame, begin with the original screen colors
2363 used for the initial frame. */
2364 if (alist == Vdefault_frame_alist
2365 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2367 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2368 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2370 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2371 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2372 frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2373 frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2374 /* frame_fg and frame_bg could be nil if, for example,
2375 f->param_alist is nil, e.g. if we are called from
2376 Fmake_terminal_frame. */
2377 if (NILP (frame_fg))
2378 frame_fg = build_string (unspecified_fg);
2379 if (NILP (frame_bg))
2380 frame_bg = build_string (unspecified_bg);
2382 /* Extract parm names and values into those vectors. */
2383 i = 0;
2384 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2386 Lisp_Object elt;
2388 elt = Fcar (tail);
2389 parms[i] = Fcar (elt);
2390 CHECK_SYMBOL (parms[i], 1);
2391 values[i] = Fcdr (elt);
2392 i++;
2395 j = i;
2397 for (i = 0; i < j; i++)
2399 Lisp_Object prop, val;
2401 prop = parms[i];
2402 val = values[i];
2404 if (EQ (prop, Qreverse))
2405 reverse = EQ (val, Qt);
2408 need_to_reverse = reverse && !was_reverse;
2409 if (termscript && need_to_reverse)
2410 fprintf (termscript, "<INVERSE-VIDEO>\n");
2412 /* Now process the alist elements in reverse of specified order. */
2413 for (i--; i >= 0; i--)
2415 Lisp_Object prop, val;
2416 Lisp_Object frame;
2418 prop = parms[i];
2419 val = values[i];
2421 if (EQ (prop, Qforeground_color))
2423 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2424 ? LFACE_BACKGROUND_INDEX
2425 : LFACE_FOREGROUND_INDEX);
2426 if (new_color != FACE_TTY_DEFAULT_COLOR
2427 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2428 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2430 FRAME_FOREGROUND_PIXEL (f) = new_color;
2431 /* Make sure the foreground of the default face for this
2432 frame is changed as well. */
2433 XSETFRAME (frame, f);
2434 if (need_to_reverse)
2436 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2437 val, frame);
2438 prop = Qbackground_color;
2439 bg_set = 1;
2441 else
2443 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2444 val, frame);
2445 fg_set = 1;
2447 redraw = 1;
2448 if (termscript)
2449 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
2452 else if (EQ (prop, Qbackground_color))
2454 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2455 ? LFACE_FOREGROUND_INDEX
2456 : LFACE_BACKGROUND_INDEX);
2457 if (new_color != FACE_TTY_DEFAULT_COLOR
2458 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2459 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2461 FRAME_BACKGROUND_PIXEL (f) = new_color;
2462 /* Make sure the background of the default face for this
2463 frame is changed as well. */
2464 XSETFRAME (frame, f);
2465 if (need_to_reverse)
2467 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2468 val, frame);
2469 prop = Qforeground_color;
2470 fg_set = 1;
2472 else
2474 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2475 val, frame);
2476 bg_set = 1;
2478 redraw = 1;
2479 if (termscript)
2480 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
2483 else if (EQ (prop, Qtitle))
2485 x_set_title (f, val);
2486 if (termscript)
2487 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
2489 else if (EQ (prop, Qcursor_type))
2491 IT_set_cursor_type (f, val);
2492 if (termscript)
2493 fprintf (termscript, "<CTYPE: %s>\n",
2494 EQ (val, Qbar) || CONSP (val) && EQ (XCAR (val), Qbar)
2495 ? "bar" : "box");
2497 store_frame_param (f, prop, val);
2500 /* If they specified "reverse", but not the colors, we need to swap
2501 the current frame colors. */
2502 if (need_to_reverse)
2504 Lisp_Object frame;
2506 if (!fg_set)
2508 XSETFRAME (frame, f);
2509 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2510 tty_color_name (f, orig_bg),
2511 frame);
2512 redraw = 1;
2514 if (!bg_set)
2516 XSETFRAME (frame, f);
2517 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2518 tty_color_name (f, orig_fg),
2519 frame);
2520 redraw = 1;
2524 if (redraw)
2526 face_change_count++; /* forces xdisp.c to recompute basic faces */
2527 if (f == SELECTED_FRAME())
2528 redraw_frame (f);
2532 extern void init_frame_faces (FRAME_PTR);
2534 #endif /* !HAVE_X_WINDOWS */
2537 /* Do we need the internal terminal? */
2539 void
2540 internal_terminal_init ()
2542 char *term = getenv ("TERM");
2543 char *colors;
2544 struct frame *sf = SELECTED_FRAME();
2546 #ifdef HAVE_X_WINDOWS
2547 if (!inhibit_window_system)
2548 return;
2549 #endif
2551 internal_terminal
2552 = (!noninteractive) && term && !strcmp (term, "internal");
2554 if (getenv ("EMACSTEST"))
2555 termscript = fopen (getenv ("EMACSTEST"), "wt");
2557 #ifndef HAVE_X_WINDOWS
2558 if (!internal_terminal || inhibit_window_system)
2560 sf->output_method = output_termcap;
2561 return;
2564 Vwindow_system = intern ("pc");
2565 Vwindow_system_version = make_number (1);
2566 sf->output_method = output_msdos_raw;
2568 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2569 screen_old_address = 0;
2571 /* Forget the stale screen colors as well. */
2572 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2574 bzero (&the_only_x_display, sizeof the_only_x_display);
2575 the_only_x_display.background_pixel = 7; /* White */
2576 the_only_x_display.foreground_pixel = 0; /* Black */
2577 bright_bg ();
2578 colors = getenv ("EMACSCOLORS");
2579 if (colors && strlen (colors) >= 2)
2581 /* The colors use 4 bits each (we enable bright background). */
2582 if (isdigit (colors[0]))
2583 colors[0] -= '0';
2584 else if (isxdigit (colors[0]))
2585 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2586 if (colors[0] >= 0 && colors[0] < 16)
2587 the_only_x_display.foreground_pixel = colors[0];
2588 if (isdigit (colors[1]))
2589 colors[1] -= '0';
2590 else if (isxdigit (colors[1]))
2591 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2592 if (colors[1] >= 0 && colors[1] < 16)
2593 the_only_x_display.background_pixel = colors[1];
2595 the_only_x_display.line_height = 1;
2596 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
2597 the_only_x_display.display_info.mouse_face_mouse_frame = NULL;
2598 the_only_x_display.display_info.mouse_face_deferred_gc = 0;
2599 the_only_x_display.display_info.mouse_face_beg_row =
2600 the_only_x_display.display_info.mouse_face_beg_col = -1;
2601 the_only_x_display.display_info.mouse_face_end_row =
2602 the_only_x_display.display_info.mouse_face_end_col = -1;
2603 the_only_x_display.display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2604 the_only_x_display.display_info.mouse_face_window = Qnil;
2605 the_only_x_display.display_info.mouse_face_mouse_x =
2606 the_only_x_display.display_info.mouse_face_mouse_y = 0;
2607 the_only_x_display.display_info.mouse_face_defer = 0;
2609 init_frame_faces (sf);
2611 ring_bell_hook = IT_ring_bell;
2612 insert_glyphs_hook = IT_insert_glyphs;
2613 delete_glyphs_hook = IT_delete_glyphs;
2614 write_glyphs_hook = IT_write_glyphs;
2615 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
2616 clear_to_end_hook = IT_clear_to_end;
2617 clear_end_of_line_hook = IT_clear_end_of_line;
2618 clear_frame_hook = IT_clear_screen;
2619 change_line_highlight_hook = IT_change_line_highlight;
2620 update_begin_hook = IT_update_begin;
2621 update_end_hook = IT_update_end;
2622 reassert_line_highlight_hook = IT_reassert_line_highlight;
2623 frame_up_to_date_hook = IT_frame_up_to_date;
2625 /* These hooks are called by term.c without being checked. */
2626 set_terminal_modes_hook = IT_set_terminal_modes;
2627 reset_terminal_modes_hook = IT_reset_terminal_modes;
2628 set_terminal_window_hook = IT_set_terminal_window;
2629 char_ins_del_ok = 0;
2630 #endif
2633 dos_get_saved_screen (screen, rows, cols)
2634 char **screen;
2635 int *rows;
2636 int *cols;
2638 #ifndef HAVE_X_WINDOWS
2639 *screen = startup_screen_buffer;
2640 *cols = startup_screen_size_X;
2641 *rows = startup_screen_size_Y;
2642 return *screen != (char *)0;
2643 #else
2644 return 0;
2645 #endif
2648 #ifndef HAVE_X_WINDOWS
2650 /* We are not X, but we can emulate it well enough for our needs... */
2651 void
2652 check_x (void)
2654 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2655 error ("Not running under a window system");
2658 #endif
2661 /* ----------------------- Keyboard control ----------------------
2663 * Keymaps reflect the following keyboard layout:
2665 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2666 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2667 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2668 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2669 * SPACE
2672 #define Ignore 0x0000
2673 #define Normal 0x0000 /* normal key - alt changes scan-code */
2674 #define FctKey 0x1000 /* func key if c == 0, else c */
2675 #define Special 0x2000 /* func key even if c != 0 */
2676 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2677 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2678 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2679 #define Grey 0x6000 /* Grey keypad key */
2681 #define Alt 0x0100 /* alt scan-code */
2682 #define Ctrl 0x0200 /* ctrl scan-code */
2683 #define Shift 0x0400 /* shift scan-code */
2685 static int extended_kbd; /* 101 (102) keyboard present. */
2687 struct kbd_translate {
2688 unsigned char sc;
2689 unsigned char ch;
2690 unsigned short code;
2693 struct dos_keyboard_map
2695 char *unshifted;
2696 char *shifted;
2697 char *alt_gr;
2698 struct kbd_translate *translate_table;
2702 static struct dos_keyboard_map us_keyboard = {
2703 /* 0 1 2 3 4 5 */
2704 /* 01234567890123456789012345678901234567890 12345678901234 */
2705 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2706 /* 0123456789012345678901234567890123456789 012345678901234 */
2707 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2708 0, /* no Alt-Gr key */
2709 0 /* no translate table */
2712 static struct dos_keyboard_map fr_keyboard = {
2713 /* 0 1 2 3 4 5 */
2714 /* 012 3456789012345678901234567890123456789012345678901234 */
2715 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2716 /* 0123456789012345678901234567890123456789012345678901234 */
2717 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2718 /* 01234567 89012345678901234567890123456789012345678901234 */
2719 " ~#{[|`\\^@]} Ï ",
2720 0 /* no translate table */
2724 * Italian keyboard support, country code 39.
2725 * '<' 56:3c*0000
2726 * '>' 56:3e*0000
2727 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2728 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2731 static struct kbd_translate it_kbd_translate_table[] = {
2732 { 0x56, 0x3c, Normal | 13 },
2733 { 0x56, 0x3e, Normal | 27 },
2734 { 0, 0, 0 }
2736 static struct dos_keyboard_map it_keyboard = {
2737 /* 0 1 2 3 4 5 */
2738 /* 0 123456789012345678901234567890123456789012345678901234 */
2739 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2740 /* 01 23456789012345678901234567890123456789012345678901234 */
2741 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2742 /* 0123456789012345678901234567890123456789012345678901234 */
2743 " {}~` [] @# ",
2744 it_kbd_translate_table
2747 static struct dos_keyboard_map dk_keyboard = {
2748 /* 0 1 2 3 4 5 */
2749 /* 0123456789012345678901234567890123456789012345678901234 */
2750 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2751 /* 01 23456789012345678901234567890123456789012345678901234 */
2752 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2753 /* 0123456789012345678901234567890123456789012345678901234 */
2754 " @œ$ {[]} | ",
2755 0 /* no translate table */
2758 static struct kbd_translate jp_kbd_translate_table[] = {
2759 { 0x73, 0x5c, Normal | 0 },
2760 { 0x73, 0x5f, Normal | 0 },
2761 { 0x73, 0x1c, Map | 0 },
2762 { 0x7d, 0x5c, Normal | 13 },
2763 { 0x7d, 0x7c, Normal | 13 },
2764 { 0x7d, 0x1c, Map | 13 },
2765 { 0, 0, 0 }
2767 static struct dos_keyboard_map jp_keyboard = {
2768 /* 0 1 2 3 4 5 */
2769 /* 0123456789012 345678901234567890123456789012345678901234 */
2770 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2771 /* 01 23456789012345678901234567890123456789012345678901234 */
2772 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2773 0, /* no Alt-Gr key */
2774 jp_kbd_translate_table
2777 static struct keyboard_layout_list
2779 int country_code;
2780 struct dos_keyboard_map *keyboard_map;
2781 } keyboard_layout_list[] =
2783 1, &us_keyboard,
2784 33, &fr_keyboard,
2785 39, &it_keyboard,
2786 45, &dk_keyboard,
2787 81, &jp_keyboard
2790 static struct dos_keyboard_map *keyboard;
2791 static int keyboard_map_all;
2792 static int international_keyboard;
2795 dos_set_keyboard (code, always)
2796 int code;
2797 int always;
2799 int i;
2800 _go32_dpmi_registers regs;
2802 /* See if Keyb.Com is installed (for international keyboard support).
2803 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2804 of Windows 9X! So don't do that! */
2805 regs.x.ax = 0xad80;
2806 regs.x.ss = regs.x.sp = regs.x.flags = 0;
2807 _go32_dpmi_simulate_int (0x2f, &regs);
2808 if (regs.h.al == 0xff)
2809 international_keyboard = 1;
2811 /* Initialize to US settings, for countries that don't have their own. */
2812 keyboard = keyboard_layout_list[0].keyboard_map;
2813 keyboard_map_all = always;
2814 dos_keyboard_layout = 1;
2816 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2817 if (code == keyboard_layout_list[i].country_code)
2819 keyboard = keyboard_layout_list[i].keyboard_map;
2820 keyboard_map_all = always;
2821 dos_keyboard_layout = code;
2822 return 1;
2824 return 0;
2827 static struct
2829 unsigned char char_code; /* normal code */
2830 unsigned char meta_code; /* M- code */
2831 unsigned char keypad_code; /* keypad code */
2832 unsigned char editkey_code; /* edit key */
2833 } keypad_translate_map[] = {
2834 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2835 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2836 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2837 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2838 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2839 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2840 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2841 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2842 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2843 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2844 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2847 static struct
2849 unsigned char char_code; /* normal code */
2850 unsigned char keypad_code; /* keypad code */
2851 } grey_key_translate_map[] = {
2852 '/', 0xaf, /* kp-decimal */
2853 '*', 0xaa, /* kp-multiply */
2854 '-', 0xad, /* kp-subtract */
2855 '+', 0xab, /* kp-add */
2856 '\r', 0x8d /* kp-enter */
2859 static unsigned short
2860 ibmpc_translate_map[] =
2862 /* --------------- 00 to 0f --------------- */
2863 Normal | 0xff, /* Ctrl Break + Alt-NNN */
2864 Alt | ModFct | 0x1b, /* Escape */
2865 Normal | 1, /* '1' */
2866 Normal | 2, /* '2' */
2867 Normal | 3, /* '3' */
2868 Normal | 4, /* '4' */
2869 Normal | 5, /* '5' */
2870 Normal | 6, /* '6' */
2871 Normal | 7, /* '7' */
2872 Normal | 8, /* '8' */
2873 Normal | 9, /* '9' */
2874 Normal | 10, /* '0' */
2875 Normal | 11, /* '-' */
2876 Normal | 12, /* '=' */
2877 Special | 0x08, /* Backspace */
2878 ModFct | 0x74, /* Tab/Backtab */
2880 /* --------------- 10 to 1f --------------- */
2881 Map | 15, /* 'q' */
2882 Map | 16, /* 'w' */
2883 Map | 17, /* 'e' */
2884 Map | 18, /* 'r' */
2885 Map | 19, /* 't' */
2886 Map | 20, /* 'y' */
2887 Map | 21, /* 'u' */
2888 Map | 22, /* 'i' */
2889 Map | 23, /* 'o' */
2890 Map | 24, /* 'p' */
2891 Map | 25, /* '[' */
2892 Map | 26, /* ']' */
2893 ModFct | 0x0d, /* Return */
2894 Ignore, /* Ctrl */
2895 Map | 30, /* 'a' */
2896 Map | 31, /* 's' */
2898 /* --------------- 20 to 2f --------------- */
2899 Map | 32, /* 'd' */
2900 Map | 33, /* 'f' */
2901 Map | 34, /* 'g' */
2902 Map | 35, /* 'h' */
2903 Map | 36, /* 'j' */
2904 Map | 37, /* 'k' */
2905 Map | 38, /* 'l' */
2906 Map | 39, /* ';' */
2907 Map | 40, /* '\'' */
2908 Map | 0, /* '`' */
2909 Ignore, /* Left shift */
2910 Map | 41, /* '\\' */
2911 Map | 45, /* 'z' */
2912 Map | 46, /* 'x' */
2913 Map | 47, /* 'c' */
2914 Map | 48, /* 'v' */
2916 /* --------------- 30 to 3f --------------- */
2917 Map | 49, /* 'b' */
2918 Map | 50, /* 'n' */
2919 Map | 51, /* 'm' */
2920 Map | 52, /* ',' */
2921 Map | 53, /* '.' */
2922 Map | 54, /* '/' */
2923 Ignore, /* Right shift */
2924 Grey | 1, /* Grey * */
2925 Ignore, /* Alt */
2926 Normal | 55, /* ' ' */
2927 Ignore, /* Caps Lock */
2928 FctKey | 0xbe, /* F1 */
2929 FctKey | 0xbf, /* F2 */
2930 FctKey | 0xc0, /* F3 */
2931 FctKey | 0xc1, /* F4 */
2932 FctKey | 0xc2, /* F5 */
2934 /* --------------- 40 to 4f --------------- */
2935 FctKey | 0xc3, /* F6 */
2936 FctKey | 0xc4, /* F7 */
2937 FctKey | 0xc5, /* F8 */
2938 FctKey | 0xc6, /* F9 */
2939 FctKey | 0xc7, /* F10 */
2940 Ignore, /* Num Lock */
2941 Ignore, /* Scroll Lock */
2942 KeyPad | 7, /* Home */
2943 KeyPad | 8, /* Up */
2944 KeyPad | 9, /* Page Up */
2945 Grey | 2, /* Grey - */
2946 KeyPad | 4, /* Left */
2947 KeyPad | 5, /* Keypad 5 */
2948 KeyPad | 6, /* Right */
2949 Grey | 3, /* Grey + */
2950 KeyPad | 1, /* End */
2952 /* --------------- 50 to 5f --------------- */
2953 KeyPad | 2, /* Down */
2954 KeyPad | 3, /* Page Down */
2955 KeyPad | 0, /* Insert */
2956 KeyPad | 10, /* Delete */
2957 Shift | FctKey | 0xbe, /* (Shift) F1 */
2958 Shift | FctKey | 0xbf, /* (Shift) F2 */
2959 Shift | FctKey | 0xc0, /* (Shift) F3 */
2960 Shift | FctKey | 0xc1, /* (Shift) F4 */
2961 Shift | FctKey | 0xc2, /* (Shift) F5 */
2962 Shift | FctKey | 0xc3, /* (Shift) F6 */
2963 Shift | FctKey | 0xc4, /* (Shift) F7 */
2964 Shift | FctKey | 0xc5, /* (Shift) F8 */
2965 Shift | FctKey | 0xc6, /* (Shift) F9 */
2966 Shift | FctKey | 0xc7, /* (Shift) F10 */
2967 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
2968 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
2970 /* --------------- 60 to 6f --------------- */
2971 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
2972 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
2973 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
2974 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
2975 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
2976 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
2977 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
2978 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
2979 Alt | FctKey | 0xbe, /* (Alt) F1 */
2980 Alt | FctKey | 0xbf, /* (Alt) F2 */
2981 Alt | FctKey | 0xc0, /* (Alt) F3 */
2982 Alt | FctKey | 0xc1, /* (Alt) F4 */
2983 Alt | FctKey | 0xc2, /* (Alt) F5 */
2984 Alt | FctKey | 0xc3, /* (Alt) F6 */
2985 Alt | FctKey | 0xc4, /* (Alt) F7 */
2986 Alt | FctKey | 0xc5, /* (Alt) F8 */
2988 /* --------------- 70 to 7f --------------- */
2989 Alt | FctKey | 0xc6, /* (Alt) F9 */
2990 Alt | FctKey | 0xc7, /* (Alt) F10 */
2991 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
2992 Ctrl | KeyPad | 4, /* (Ctrl) Left */
2993 Ctrl | KeyPad | 6, /* (Ctrl) Right */
2994 Ctrl | KeyPad | 1, /* (Ctrl) End */
2995 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
2996 Ctrl | KeyPad | 7, /* (Ctrl) Home */
2997 Alt | Map | 1, /* '1' */
2998 Alt | Map | 2, /* '2' */
2999 Alt | Map | 3, /* '3' */
3000 Alt | Map | 4, /* '4' */
3001 Alt | Map | 5, /* '5' */
3002 Alt | Map | 6, /* '6' */
3003 Alt | Map | 7, /* '7' */
3004 Alt | Map | 8, /* '8' */
3006 /* --------------- 80 to 8f --------------- */
3007 Alt | Map | 9, /* '9' */
3008 Alt | Map | 10, /* '0' */
3009 Alt | Map | 11, /* '-' */
3010 Alt | Map | 12, /* '=' */
3011 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
3012 FctKey | 0xc8, /* F11 */
3013 FctKey | 0xc9, /* F12 */
3014 Shift | FctKey | 0xc8, /* (Shift) F11 */
3015 Shift | FctKey | 0xc9, /* (Shift) F12 */
3016 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
3017 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
3018 Alt | FctKey | 0xc8, /* (Alt) F11 */
3019 Alt | FctKey | 0xc9, /* (Alt) F12 */
3020 Ctrl | KeyPad | 8, /* (Ctrl) Up */
3021 Ctrl | Grey | 2, /* (Ctrl) Grey - */
3022 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
3024 /* --------------- 90 to 9f --------------- */
3025 Ctrl | Grey | 3, /* (Ctrl) Grey + */
3026 Ctrl | KeyPad | 2, /* (Ctrl) Down */
3027 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
3028 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
3029 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
3030 Ctrl | Grey | 0, /* (Ctrl) Grey / */
3031 Ctrl | Grey | 1, /* (Ctrl) Grey * */
3032 Alt | FctKey | 0x50, /* (Alt) Home */
3033 Alt | FctKey | 0x52, /* (Alt) Up */
3034 Alt | FctKey | 0x55, /* (Alt) Page Up */
3035 Ignore, /* NO KEY */
3036 Alt | FctKey | 0x51, /* (Alt) Left */
3037 Ignore, /* NO KEY */
3038 Alt | FctKey | 0x53, /* (Alt) Right */
3039 Ignore, /* NO KEY */
3040 Alt | FctKey | 0x57, /* (Alt) End */
3042 /* --------------- a0 to af --------------- */
3043 Alt | KeyPad | 2, /* (Alt) Down */
3044 Alt | KeyPad | 3, /* (Alt) Page Down */
3045 Alt | KeyPad | 0, /* (Alt) Insert */
3046 Alt | KeyPad | 10, /* (Alt) Delete */
3047 Alt | Grey | 0, /* (Alt) Grey / */
3048 Alt | FctKey | 0x09, /* (Alt) Tab */
3049 Alt | Grey | 4 /* (Alt) Keypad Enter */
3052 /* These bit-positions corresponds to values returned by BIOS */
3053 #define SHIFT_P 0x0003 /* two bits! */
3054 #define CTRL_P 0x0004
3055 #define ALT_P 0x0008
3056 #define SCRLOCK_P 0x0010
3057 #define NUMLOCK_P 0x0020
3058 #define CAPSLOCK_P 0x0040
3059 #define ALT_GR_P 0x0800
3060 #define SUPER_P 0x4000 /* pseudo */
3061 #define HYPER_P 0x8000 /* pseudo */
3063 static int
3064 dos_get_modifiers (keymask)
3065 int *keymask;
3067 union REGS regs;
3068 int mask;
3069 int modifiers = 0;
3071 /* Calculate modifier bits */
3072 regs.h.ah = extended_kbd ? 0x12 : 0x02;
3073 int86 (0x16, &regs, &regs);
3075 if (!extended_kbd)
3077 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
3078 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
3080 else
3082 mask = regs.h.al & (SHIFT_P |
3083 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
3085 /* Do not break international keyboard support. */
3086 /* When Keyb.Com is loaded, the right Alt key is */
3087 /* used for accessing characters like { and } */
3088 if (regs.h.ah & 2) /* Left ALT pressed ? */
3089 mask |= ALT_P;
3091 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
3093 mask |= ALT_GR_P;
3094 if (dos_hyper_key == 1)
3096 mask |= HYPER_P;
3097 modifiers |= hyper_modifier;
3099 else if (dos_super_key == 1)
3101 mask |= SUPER_P;
3102 modifiers |= super_modifier;
3104 else if (!international_keyboard)
3106 /* If Keyb.Com is NOT installed, let Right Alt behave
3107 like the Left Alt. */
3108 mask &= ~ALT_GR_P;
3109 mask |= ALT_P;
3113 if (regs.h.ah & 1) /* Left CTRL pressed ? */
3114 mask |= CTRL_P;
3116 if (regs.h.ah & 4) /* Right CTRL pressed ? */
3118 if (dos_hyper_key == 2)
3120 mask |= HYPER_P;
3121 modifiers |= hyper_modifier;
3123 else if (dos_super_key == 2)
3125 mask |= SUPER_P;
3126 modifiers |= super_modifier;
3128 else
3129 mask |= CTRL_P;
3133 if (mask & SHIFT_P)
3134 modifiers |= shift_modifier;
3135 if (mask & CTRL_P)
3136 modifiers |= ctrl_modifier;
3137 if (mask & ALT_P)
3138 modifiers |= meta_modifier;
3140 if (keymask)
3141 *keymask = mask;
3142 return modifiers;
3145 #define NUM_RECENT_DOSKEYS (100)
3146 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
3147 int total_doskeys; /* Total number of elements stored into recent_doskeys */
3148 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
3150 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
3151 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
3152 Each input key receives two values in this vector: first the ASCII code,\n\
3153 and then the scan code.")
3156 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
3157 Lisp_Object val;
3159 if (total_doskeys < NUM_RECENT_DOSKEYS)
3160 return Fvector (total_doskeys, keys);
3161 else
3163 val = Fvector (NUM_RECENT_DOSKEYS, keys);
3164 bcopy (keys + recent_doskeys_index,
3165 XVECTOR (val)->contents,
3166 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
3167 bcopy (keys,
3168 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
3169 recent_doskeys_index * sizeof (Lisp_Object));
3170 return val;
3174 /* Get a char from keyboard. Function keys are put into the event queue. */
3175 static int
3176 dos_rawgetc ()
3178 struct input_event event;
3179 union REGS regs;
3181 #ifndef HAVE_X_WINDOWS
3182 /* Maybe put the cursor where it should be. */
3183 IT_cmgoto (SELECTED_FRAME());
3184 #endif
3186 /* The following condition is equivalent to `kbhit ()', except that
3187 it uses the bios to do its job. This pleases DESQview/X. */
3188 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
3189 int86 (0x16, &regs, &regs),
3190 (regs.x.flags & 0x40) == 0)
3192 union REGS regs;
3193 register unsigned char c;
3194 int sc, code = -1, mask, kp_mode;
3195 int modifiers;
3197 regs.h.ah = extended_kbd ? 0x10 : 0x00;
3198 int86 (0x16, &regs, &regs);
3199 c = regs.h.al;
3200 sc = regs.h.ah;
3202 total_doskeys += 2;
3203 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3204 = make_number (c);
3205 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3206 recent_doskeys_index = 0;
3207 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3208 = make_number (sc);
3209 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3210 recent_doskeys_index = 0;
3212 modifiers = dos_get_modifiers (&mask);
3214 #ifndef HAVE_X_WINDOWS
3215 if (!NILP (Vdos_display_scancodes))
3217 char buf[11];
3218 sprintf (buf, "%02x:%02x*%04x",
3219 (unsigned) (sc&0xff), (unsigned) c, mask);
3220 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
3222 #endif
3224 if (sc == 0xe0)
3226 switch (c)
3228 case 10: /* Ctrl Grey Enter */
3229 code = Ctrl | Grey | 4;
3230 break;
3231 case 13: /* Grey Enter */
3232 code = Grey | 4;
3233 break;
3234 case '/': /* Grey / */
3235 code = Grey | 0;
3236 break;
3237 default:
3238 continue;
3240 c = 0;
3242 else
3244 /* Try the keyboard-private translation table first. */
3245 if (keyboard->translate_table)
3247 struct kbd_translate *p = keyboard->translate_table;
3249 while (p->sc)
3251 if (p->sc == sc && p->ch == c)
3253 code = p->code;
3254 break;
3256 p++;
3259 /* If the private table didn't translate it, use the general
3260 one. */
3261 if (code == -1)
3263 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3264 continue;
3265 if ((code = ibmpc_translate_map[sc]) == Ignore)
3266 continue;
3270 if (c == 0)
3272 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3273 Emacs is ready to read a key. Therefore, if they press
3274 `Alt-x' when Emacs is busy, by the time we get to
3275 `dos_get_modifiers', they might have already released the
3276 Alt key, and Emacs gets just `x', which is BAD.
3277 However, for keys with the `Map' property set, the ASCII
3278 code returns zero iff Alt is pressed. So, when we DON'T
3279 have to support international_keyboard, we don't have to
3280 distinguish between the left and right Alt keys, and we
3281 can set the META modifier for any keys with the `Map'
3282 property if they return zero ASCII code (c = 0). */
3283 if ( (code & Alt)
3284 || ( (code & 0xf000) == Map && !international_keyboard))
3285 modifiers |= meta_modifier;
3286 if (code & Ctrl)
3287 modifiers |= ctrl_modifier;
3288 if (code & Shift)
3289 modifiers |= shift_modifier;
3292 switch (code & 0xf000)
3294 case ModFct:
3295 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3296 return c;
3297 c = 0; /* Special */
3299 case FctKey:
3300 if (c != 0)
3301 return c;
3303 case Special:
3304 code |= 0xff00;
3305 break;
3307 case Normal:
3308 if (sc == 0)
3310 if (c == 0) /* ctrl-break */
3311 continue;
3312 return c; /* ALT-nnn */
3314 if (!keyboard_map_all)
3316 if (c != ' ')
3317 return c;
3318 code = c;
3319 break;
3322 case Map:
3323 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3324 if (!keyboard_map_all)
3325 return c;
3327 code &= 0xff;
3328 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3329 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
3331 if (mask & SHIFT_P)
3333 code = keyboard->shifted[code];
3334 mask -= SHIFT_P;
3335 modifiers &= ~shift_modifier;
3337 else
3338 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3339 code = keyboard->alt_gr[code];
3340 else
3341 code = keyboard->unshifted[code];
3342 break;
3344 case KeyPad:
3345 code &= 0xff;
3346 if (c == 0xe0) /* edit key */
3347 kp_mode = 3;
3348 else
3349 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3350 kp_mode = dos_keypad_mode & 0x03;
3351 else
3352 kp_mode = (dos_keypad_mode >> 4) & 0x03;
3354 switch (kp_mode)
3356 case 0:
3357 if (code == 10 && dos_decimal_point)
3358 return dos_decimal_point;
3359 return keypad_translate_map[code].char_code;
3361 case 1:
3362 code = 0xff00 | keypad_translate_map[code].keypad_code;
3363 break;
3365 case 2:
3366 code = keypad_translate_map[code].meta_code;
3367 modifiers = meta_modifier;
3368 break;
3370 case 3:
3371 code = 0xff00 | keypad_translate_map[code].editkey_code;
3372 break;
3374 break;
3376 case Grey:
3377 code &= 0xff;
3378 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3379 if (dos_keypad_mode & kp_mode)
3380 code = 0xff00 | grey_key_translate_map[code].keypad_code;
3381 else
3382 code = grey_key_translate_map[code].char_code;
3383 break;
3386 make_event:
3387 if (code == 0)
3388 continue;
3390 if (code >= 0x100)
3391 event.kind = non_ascii_keystroke;
3392 else
3393 event.kind = ascii_keystroke;
3394 event.code = code;
3395 event.modifiers = modifiers;
3396 event.frame_or_window = selected_frame;
3397 event.arg = Qnil;
3398 event.timestamp = event_timestamp ();
3399 kbd_buffer_store_event (&event);
3402 if (have_mouse > 0 && !mouse_preempted)
3404 int but, press, x, y, ok;
3405 int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3407 /* Check for mouse movement *before* buttons. */
3408 mouse_check_moved ();
3410 /* If the mouse moved from the spot of its last sighting, we
3411 might need to update mouse highlight. */
3412 if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3414 previous_help_echo = help_echo;
3415 help_echo = help_echo_object = help_echo_window = Qnil;
3416 help_echo_pos = -1;
3417 IT_note_mouse_highlight (SELECTED_FRAME(),
3418 mouse_last_x, mouse_last_y);
3419 /* If the contents of the global variable help_echo has
3420 changed, generate a HELP_EVENT. */
3421 if (!NILP (help_echo) || !NILP (previous_help_echo))
3423 /* HELP_EVENT takes 2 events in the event loop. */
3424 event.kind = HELP_EVENT;
3425 event.frame_or_window = selected_frame;
3426 event.arg = help_echo_object;
3427 event.x = make_number (help_echo_pos);
3428 event.timestamp = event_timestamp ();
3429 event.code = 0;
3430 kbd_buffer_store_event (&event);
3431 if (WINDOWP (help_echo_window))
3432 event.frame_or_window = help_echo_window;
3433 event.arg = help_echo;
3434 event.code = 1;
3435 kbd_buffer_store_event (&event);
3439 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3440 for (press = 0; press < 2; press++)
3442 int button_num = but;
3444 if (press)
3445 ok = mouse_pressed (but, &x, &y);
3446 else
3447 ok = mouse_released (but, &x, &y);
3448 if (ok)
3450 /* Allow a simultaneous press/release of Mouse-1 and
3451 Mouse-2 to simulate Mouse-3 on two-button mice. */
3452 if (mouse_button_count == 2 && but < 2)
3454 int x2, y2; /* don't clobber original coordinates */
3456 /* If only one button is pressed, wait 100 msec and
3457 check again. This way, Speedy Gonzales isn't
3458 punished, while the slow get their chance. */
3459 if (press && mouse_pressed (1-but, &x2, &y2)
3460 || !press && mouse_released (1-but, &x2, &y2))
3461 button_num = 2;
3462 else
3464 delay (100);
3465 if (press && mouse_pressed (1-but, &x2, &y2)
3466 || !press && mouse_released (1-but, &x2, &y2))
3467 button_num = 2;
3471 event.kind = mouse_click;
3472 event.code = button_num;
3473 event.modifiers = dos_get_modifiers (0)
3474 | (press ? down_modifier : up_modifier);
3475 event.x = x;
3476 event.y = y;
3477 event.frame_or_window = selected_frame;
3478 event.arg = Qnil;
3479 event.timestamp = event_timestamp ();
3480 kbd_buffer_store_event (&event);
3485 return -1;
3488 static int prev_get_char = -1;
3490 /* Return 1 if a key is ready to be read without suspending execution. */
3492 dos_keysns ()
3494 if (prev_get_char != -1)
3495 return 1;
3496 else
3497 return ((prev_get_char = dos_rawgetc ()) != -1);
3500 /* Read a key. Return -1 if no key is ready. */
3502 dos_keyread ()
3504 if (prev_get_char != -1)
3506 int c = prev_get_char;
3507 prev_get_char = -1;
3508 return c;
3510 else
3511 return dos_rawgetc ();
3514 #ifndef HAVE_X_WINDOWS
3515 /* See xterm.c for more info. */
3516 void
3517 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
3518 FRAME_PTR f;
3519 register int pix_x, pix_y;
3520 register int *x, *y;
3521 XRectangle *bounds;
3522 int noclip;
3524 if (bounds) abort ();
3526 /* Ignore clipping. */
3528 *x = pix_x;
3529 *y = pix_y;
3532 void
3533 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
3534 FRAME_PTR f;
3535 register int x, y;
3536 register int *pix_x, *pix_y;
3538 *pix_x = x;
3539 *pix_y = y;
3542 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3543 for now.
3545 Actually, I don't know the meaning of all the parameters of the functions
3546 here -- I only know how they are called by xmenu.c. I could of course
3547 grab the nearest Xlib manual (down the hall, second-to-last door on the
3548 left), but I don't think it's worth the effort. */
3550 /* These hold text of the current and the previous menu help messages. */
3551 static char *menu_help_message, *prev_menu_help_message;
3552 /* Pane number and item number of the menu item which generated the
3553 last menu help message. */
3554 static int menu_help_paneno, menu_help_itemno;
3556 static XMenu *
3557 IT_menu_create ()
3559 XMenu *menu;
3561 menu = (XMenu *) xmalloc (sizeof (XMenu));
3562 menu->allocated = menu->count = menu->panecount = menu->width = 0;
3563 return menu;
3566 /* Allocate some (more) memory for MENU ensuring that there is room for one
3567 for item. */
3569 static void
3570 IT_menu_make_room (XMenu *menu)
3572 if (menu->allocated == 0)
3574 int count = menu->allocated = 10;
3575 menu->text = (char **) xmalloc (count * sizeof (char *));
3576 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3577 menu->panenumber = (int *) xmalloc (count * sizeof (int));
3578 menu->help_text = (char **) xmalloc (count * sizeof (char *));
3580 else if (menu->allocated == menu->count)
3582 int count = menu->allocated = menu->allocated + 10;
3583 menu->text
3584 = (char **) xrealloc (menu->text, count * sizeof (char *));
3585 menu->submenu
3586 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3587 menu->panenumber
3588 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3589 menu->help_text
3590 = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3594 /* Search the given menu structure for a given pane number. */
3596 static XMenu *
3597 IT_menu_search_pane (XMenu *menu, int pane)
3599 int i;
3600 XMenu *try;
3602 for (i = 0; i < menu->count; i++)
3603 if (menu->submenu[i])
3605 if (pane == menu->panenumber[i])
3606 return menu->submenu[i];
3607 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3608 return try;
3610 return (XMenu *) 0;
3613 /* Determine how much screen space a given menu needs. */
3615 static void
3616 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3618 int i, h2, w2, maxsubwidth, maxheight;
3620 maxsubwidth = 0;
3621 maxheight = menu->count;
3622 for (i = 0; i < menu->count; i++)
3624 if (menu->submenu[i])
3626 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3627 if (w2 > maxsubwidth) maxsubwidth = w2;
3628 if (i + h2 > maxheight) maxheight = i + h2;
3631 *width = menu->width + maxsubwidth;
3632 *height = maxheight;
3635 /* Display MENU at (X,Y) using FACES. */
3637 static void
3638 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3640 int i, j, face, width;
3641 struct glyph *text, *p;
3642 char *q;
3643 int mx, my;
3644 int enabled, mousehere;
3645 int row, col;
3646 struct frame *sf = SELECTED_FRAME();
3648 menu_help_message = NULL;
3650 width = menu->width;
3651 text = (struct glyph *) xmalloc ((width + 2) * sizeof (struct glyph));
3652 ScreenGetCursor (&row, &col);
3653 mouse_get_xy (&mx, &my);
3654 IT_update_begin (sf);
3655 for (i = 0; i < menu->count; i++)
3657 int max_width = width + 2;
3659 IT_cursor_to (y + i, x);
3660 enabled
3661 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3662 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
3663 face = faces[enabled + mousehere * 2];
3664 /* The following if clause means that we display the menu help
3665 strings even if the menu item is currently disabled. */
3666 if (disp_help && enabled + mousehere * 2 >= 2)
3668 menu_help_message = menu->help_text[i];
3669 menu_help_paneno = pn - 1;
3670 menu_help_itemno = i;
3672 p = text;
3673 SET_CHAR_GLYPH (*p, ' ', face, 0);
3674 p++;
3675 for (j = 0, q = menu->text[i]; *q; j++)
3677 if (*q > 26)
3679 SET_CHAR_GLYPH (*p, *q++, face, 0);
3680 p++;
3682 else /* make '^x' */
3684 SET_CHAR_GLYPH (*p, '^', face, 0);
3685 p++;
3686 j++;
3687 SET_CHAR_GLYPH (*p, *q++ + 64, face, 0);
3688 p++;
3691 /* Don't let the menu text overflow into the next screen row. */
3692 if (x + max_width > screen_size_X)
3694 max_width = screen_size_X - x;
3695 text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3697 for (; j < max_width - 2; j++, p++)
3698 SET_CHAR_GLYPH (*p, ' ', face, 0);
3700 SET_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3701 p++;
3702 IT_write_glyphs (text, max_width);
3704 IT_update_end (sf);
3705 IT_cursor_to (row, col);
3706 xfree (text);
3709 /* --------------------------- X Menu emulation ---------------------- */
3711 /* Report availability of menus. */
3714 have_menus_p ()
3716 return 1;
3719 /* Create a brand new menu structure. */
3721 XMenu *
3722 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3724 return IT_menu_create ();
3727 /* Create a new pane and place it on the outer-most level. It is not
3728 clear that it should be placed out there, but I don't know what else
3729 to do. */
3732 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3734 int len;
3735 char *p;
3737 if (!enable)
3738 abort ();
3740 IT_menu_make_room (menu);
3741 menu->submenu[menu->count] = IT_menu_create ();
3742 menu->text[menu->count] = txt;
3743 menu->panenumber[menu->count] = ++menu->panecount;
3744 menu->help_text[menu->count] = NULL;
3745 menu->count++;
3747 /* Adjust length for possible control characters (which will
3748 be written as ^x). */
3749 for (len = strlen (txt), p = txt; *p; p++)
3750 if (*p < 27)
3751 len++;
3753 if (len > menu->width)
3754 menu->width = len;
3756 return menu->panecount;
3759 /* Create a new item in a menu pane. */
3762 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3763 int foo, char *txt, int enable, char *help_text)
3765 int len;
3766 char *p;
3768 if (pane)
3769 if (!(menu = IT_menu_search_pane (menu, pane)))
3770 return XM_FAILURE;
3771 IT_menu_make_room (menu);
3772 menu->submenu[menu->count] = (XMenu *) 0;
3773 menu->text[menu->count] = txt;
3774 menu->panenumber[menu->count] = enable;
3775 menu->help_text[menu->count] = help_text;
3776 menu->count++;
3778 /* Adjust length for possible control characters (which will
3779 be written as ^x). */
3780 for (len = strlen (txt), p = txt; *p; p++)
3781 if (*p < 27)
3782 len++;
3784 if (len > menu->width)
3785 menu->width = len;
3787 return XM_SUCCESS;
3790 /* Decide where the menu would be placed if requested at (X,Y). */
3792 void
3793 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3794 int *ulx, int *uly, int *width, int *height)
3796 IT_menu_calc_size (menu, width, height);
3797 *ulx = x + 1;
3798 *uly = y;
3799 *width += 2;
3802 struct IT_menu_state
3804 void *screen_behind;
3805 XMenu *menu;
3806 int pane;
3807 int x, y;
3811 /* Display menu, wait for user's response, and return that response. */
3814 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3815 int x0, int y0, unsigned ButtonMask, char **txt,
3816 void (*help_callback)(char *, int, int))
3818 struct IT_menu_state *state;
3819 int statecount;
3820 int x, y, i, b;
3821 int screensize;
3822 int faces[4];
3823 Lisp_Object selectface;
3824 int leave, result, onepane;
3825 int title_faces[4]; /* face to display the menu title */
3826 int buffers_num_deleted = 0;
3827 struct frame *sf = SELECTED_FRAME();
3828 Lisp_Object saved_echo_area_message;
3830 /* Just in case we got here without a mouse present... */
3831 if (have_mouse <= 0)
3832 return XM_IA_SELECT;
3833 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3834 around the display. */
3835 if (x0 <= 0)
3836 x0 = 1;
3837 if (y0 <= 0)
3838 y0 = 1;
3840 /* We will process all the mouse events directly, so we had
3841 better prevent dos_rawgetc from stealing them from us. */
3842 mouse_preempted++;
3844 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3845 screensize = screen_size * 2;
3846 faces[0]
3847 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3848 0, DEFAULT_FACE_ID);
3849 faces[1]
3850 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3851 0, DEFAULT_FACE_ID);
3852 selectface = intern ("msdos-menu-select-face");
3853 faces[2] = lookup_derived_face (sf, selectface,
3854 0, faces[0]);
3855 faces[3] = lookup_derived_face (sf, selectface,
3856 0, faces[1]);
3858 /* Make sure the menu title is always displayed with
3859 `msdos-menu-active-face', no matter where the mouse pointer is. */
3860 for (i = 0; i < 4; i++)
3861 title_faces[i] = faces[3];
3863 statecount = 1;
3865 /* Don't let the title for the "Buffers" popup menu include a
3866 digit (which is ugly).
3868 This is a terrible kludge, but I think the "Buffers" case is
3869 the only one where the title includes a number, so it doesn't
3870 seem to be necessary to make this more general. */
3871 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3873 menu->text[0][7] = '\0';
3874 buffers_num_deleted = 1;
3877 /* We need to save the current echo area message, so that we could
3878 restore it below, before we exit. See the commentary below,
3879 before the call to message_with_string. */
3880 saved_echo_area_message = Fcurrent_message ();
3881 state[0].menu = menu;
3882 mouse_off ();
3883 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3885 /* Turn off the cursor. Otherwise it shows through the menu
3886 panes, which is ugly. */
3887 IT_display_cursor (0);
3889 /* Display the menu title. */
3890 IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3891 if (buffers_num_deleted)
3892 menu->text[0][7] = ' ';
3893 if ((onepane = menu->count == 1 && menu->submenu[0]))
3895 menu->width = menu->submenu[0]->width;
3896 state[0].menu = menu->submenu[0];
3898 else
3900 state[0].menu = menu;
3902 state[0].x = x0 - 1;
3903 state[0].y = y0;
3904 state[0].pane = onepane;
3906 mouse_last_x = -1; /* A hack that forces display. */
3907 leave = 0;
3908 while (!leave)
3910 if (!mouse_visible) mouse_on ();
3911 mouse_check_moved ();
3912 if (sf->mouse_moved)
3914 sf->mouse_moved = 0;
3915 result = XM_IA_SELECT;
3916 mouse_get_xy (&x, &y);
3917 for (i = 0; i < statecount; i++)
3918 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3920 int dy = y - state[i].y;
3921 if (0 <= dy && dy < state[i].menu->count)
3923 if (!state[i].menu->submenu[dy])
3924 if (state[i].menu->panenumber[dy])
3925 result = XM_SUCCESS;
3926 else
3927 result = XM_IA_SELECT;
3928 *pane = state[i].pane - 1;
3929 *selidx = dy;
3930 /* We hit some part of a menu, so drop extra menus that
3931 have been opened. That does not include an open and
3932 active submenu. */
3933 if (i != statecount - 2
3934 || state[i].menu->submenu[dy] != state[i+1].menu)
3935 while (i != statecount - 1)
3937 statecount--;
3938 mouse_off ();
3939 ScreenUpdate (state[statecount].screen_behind);
3940 if (screen_virtual_segment)
3941 dosv_refresh_virtual_screen (0, screen_size);
3942 xfree (state[statecount].screen_behind);
3944 if (i == statecount - 1 && state[i].menu->submenu[dy])
3946 IT_menu_display (state[i].menu,
3947 state[i].y,
3948 state[i].x,
3949 state[i].pane,
3950 faces, 1);
3951 state[statecount].menu = state[i].menu->submenu[dy];
3952 state[statecount].pane = state[i].menu->panenumber[dy];
3953 mouse_off ();
3954 ScreenRetrieve (state[statecount].screen_behind
3955 = xmalloc (screensize));
3956 state[statecount].x
3957 = state[i].x + state[i].menu->width + 2;
3958 state[statecount].y = y;
3959 statecount++;
3963 IT_menu_display (state[statecount - 1].menu,
3964 state[statecount - 1].y,
3965 state[statecount - 1].x,
3966 state[statecount - 1].pane,
3967 faces, 1);
3969 else
3971 if ((menu_help_message || prev_menu_help_message)
3972 && menu_help_message != prev_menu_help_message)
3974 help_callback (menu_help_message,
3975 menu_help_paneno, menu_help_itemno);
3976 IT_display_cursor (0);
3977 prev_menu_help_message = menu_help_message;
3979 /* We are busy-waiting for the mouse to move, so let's be nice
3980 to other Windows applications by releasing our time slice. */
3981 __dpmi_yield ();
3983 for (b = 0; b < mouse_button_count && !leave; b++)
3985 /* Only leave if user both pressed and released the mouse, and in
3986 that order. This avoids popping down the menu pane unless
3987 the user is really done with it. */
3988 if (mouse_pressed (b, &x, &y))
3990 while (mouse_button_depressed (b, &x, &y))
3991 __dpmi_yield ();
3992 leave = 1;
3994 (void) mouse_released (b, &x, &y);
3998 mouse_off ();
3999 ScreenUpdate (state[0].screen_behind);
4000 if (screen_virtual_segment)
4001 dosv_refresh_virtual_screen (0, screen_size);
4003 /* We have a situation here. ScreenUpdate has just restored the
4004 screen contents as it was before we started drawing this menu.
4005 That includes any echo area message that could have been
4006 displayed back then. (In reality, that echo area message will
4007 almost always be the ``keystroke echo'' that echoes the sequence
4008 of menu items chosen by the user.) However, if the menu had some
4009 help messages, then displaying those messages caused Emacs to
4010 forget about the original echo area message. So when
4011 ScreenUpdate restored it, it created a discrepancy between the
4012 actual screen contents and what Emacs internal data structures
4013 know about it.
4015 To avoid this conflict, we force Emacs to restore the original
4016 echo area message as we found it when we entered this function.
4017 The irony of this is that we then erase the restored message
4018 right away, so the only purpose of restoring it is so that
4019 erasing it works correctly... */
4020 if (! NILP (saved_echo_area_message))
4021 message_with_string ("%s", saved_echo_area_message, 0);
4022 message (0);
4023 while (statecount--)
4024 xfree (state[statecount].screen_behind);
4025 IT_display_cursor (1); /* turn cursor back on */
4026 /* Clean up any mouse events that are waiting inside Emacs event queue.
4027 These events are likely to be generated before the menu was even
4028 displayed, probably because the user pressed and released the button
4029 (which invoked the menu) too quickly. If we don't remove these events,
4030 Emacs will process them after we return and surprise the user. */
4031 discard_mouse_events ();
4032 mouse_clear_clicks ();
4033 if (!kbd_buffer_events_waiting (1))
4034 clear_input_pending ();
4035 /* Allow mouse events generation by dos_rawgetc. */
4036 mouse_preempted--;
4037 return result;
4040 /* Dispose of a menu. */
4042 void
4043 XMenuDestroy (Display *foo, XMenu *menu)
4045 int i;
4046 if (menu->allocated)
4048 for (i = 0; i < menu->count; i++)
4049 if (menu->submenu[i])
4050 XMenuDestroy (foo, menu->submenu[i]);
4051 xfree (menu->text);
4052 xfree (menu->submenu);
4053 xfree (menu->panenumber);
4054 xfree (menu->help_text);
4056 xfree (menu);
4057 menu_help_message = prev_menu_help_message = NULL;
4061 x_pixel_width (struct frame *f)
4063 return FRAME_WIDTH (f);
4067 x_pixel_height (struct frame *f)
4069 return FRAME_HEIGHT (f);
4071 #endif /* !HAVE_X_WINDOWS */
4073 /* ----------------------- DOS / UNIX conversion --------------------- */
4075 void msdos_downcase_filename (unsigned char *);
4077 /* Destructively turn backslashes into slashes. */
4079 void
4080 dostounix_filename (p)
4081 register char *p;
4083 msdos_downcase_filename (p);
4085 while (*p)
4087 if (*p == '\\')
4088 *p = '/';
4089 p++;
4093 /* Destructively turn slashes into backslashes. */
4095 void
4096 unixtodos_filename (p)
4097 register char *p;
4099 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4101 *p += 'a' - 'A';
4102 p += 2;
4105 while (*p)
4107 if (*p == '/')
4108 *p = '\\';
4109 p++;
4113 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4116 getdefdir (drive, dst)
4117 int drive;
4118 char *dst;
4120 char in_path[4], *p = in_path;
4121 int e = errno;
4123 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4124 if (drive != 0)
4126 *p++ = drive + 'A' - 1;
4127 *p++ = ':';
4130 *p++ = '.';
4131 *p = '\0';
4132 errno = 0;
4133 _fixpath (in_path, dst);
4134 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4135 it queries the LFN support, so ignore that error. */
4136 if ((errno && errno != ENOSYS) || *dst == '\0')
4137 return 0;
4139 msdos_downcase_filename (dst);
4141 errno = e;
4142 return 1;
4145 char *
4146 emacs_root_dir (void)
4148 static char root_dir[4];
4150 sprintf (root_dir, "%c:/", 'A' + getdisk ());
4151 root_dir[0] = tolower (root_dir[0]);
4152 return root_dir;
4155 /* Remove all CR's that are followed by a LF. */
4158 crlf_to_lf (n, buf)
4159 register int n;
4160 register unsigned char *buf;
4162 unsigned char *np = buf;
4163 unsigned char *startp = buf;
4164 unsigned char *endp = buf + n;
4166 if (n == 0)
4167 return n;
4168 while (buf < endp - 1)
4170 if (*buf == 0x0d)
4172 if (*(++buf) != 0x0a)
4173 *np++ = 0x0d;
4175 else
4176 *np++ = *buf++;
4178 if (buf < endp)
4179 *np++ = *buf++;
4180 return np - startp;
4183 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4185 /* In DJGPP v2.0, library `write' can call `malloc', which might
4186 cause relocation of the buffer whose address we get in ADDR.
4187 Here is a version of `write' that avoids calling `malloc',
4188 to serve us until such time as the library is fixed.
4189 Actually, what we define here is called `__write', because
4190 `write' is a stub that just jmp's to `__write' (to be
4191 POSIXLY-correct with respect to the global name-space). */
4193 #include <io.h> /* for _write */
4194 #include <libc/dosio.h> /* for __file_handle_modes[] */
4196 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
4198 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4201 __write (int handle, const void *buffer, size_t count)
4203 if (count == 0)
4204 return 0;
4206 if(__file_handle_modes[handle] & O_BINARY)
4207 return _write (handle, buffer, count);
4208 else
4210 char *xbp = xbuf;
4211 const char *bp = buffer;
4212 int total_written = 0;
4213 int nmoved = 0, ncr = 0;
4215 while (count)
4217 /* The next test makes sure there's space for at least 2 more
4218 characters in xbuf[], so both CR and LF can be put there. */
4219 if (xbp < XBUF_END)
4221 if (*bp == '\n')
4223 ncr++;
4224 *xbp++ = '\r';
4226 *xbp++ = *bp++;
4227 nmoved++;
4228 count--;
4230 if (xbp >= XBUF_END || !count)
4232 size_t to_write = nmoved + ncr;
4233 int written = _write (handle, xbuf, to_write);
4235 if (written == -1)
4236 return -1;
4237 else
4238 total_written += nmoved; /* CRs aren't counted in ret value */
4240 /* If some, but not all were written (disk full?), return
4241 an estimate of the total written bytes not counting CRs. */
4242 if (written < to_write)
4243 return total_written - (to_write - written) * nmoved/to_write;
4245 nmoved = 0;
4246 ncr = 0;
4247 xbp = xbuf;
4250 return total_written;
4254 /* A low-level file-renaming function which works around Windows 95 bug.
4255 This is pulled directly out of DJGPP v2.01 library sources, and only
4256 used when you compile with DJGPP v2.0. */
4258 #include <io.h>
4260 int _rename(const char *old, const char *new)
4262 __dpmi_regs r;
4263 int olen = strlen(old) + 1;
4264 int i;
4265 int use_lfn = _USE_LFN;
4266 char tempfile[FILENAME_MAX];
4267 const char *orig = old;
4268 int lfn_fd = -1;
4270 r.x.dx = __tb_offset;
4271 r.x.di = __tb_offset + olen;
4272 r.x.ds = r.x.es = __tb_segment;
4274 if (use_lfn)
4276 /* Windows 95 bug: for some filenames, when you rename
4277 file -> file~ (as in Emacs, to leave a backup), the
4278 short 8+3 alias doesn't change, which effectively
4279 makes OLD and NEW the same file. We must rename
4280 through a temporary file to work around this. */
4282 char *pbase = 0, *p;
4283 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
4284 int idx = sizeof(try_char) - 1;
4286 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4287 might point to another drive, which will fail the DOS call. */
4288 strcpy(tempfile, old);
4289 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
4290 if (*p == '/' || *p == '\\' || *p == ':')
4291 pbase = p;
4292 if (pbase)
4293 pbase++;
4294 else
4295 pbase = tempfile;
4296 strcpy(pbase, "X$$djren$$.$$temp$$");
4300 if (idx <= 0)
4301 return -1;
4302 *pbase = try_char[--idx];
4303 } while (_chmod(tempfile, 0) != -1);
4305 r.x.ax = 0x7156;
4306 _put_path2(tempfile, olen);
4307 _put_path(old);
4308 __dpmi_int(0x21, &r);
4309 if (r.x.flags & 1)
4311 errno = __doserr_to_errno(r.x.ax);
4312 return -1;
4315 /* Now create a file with the original name. This will
4316 ensure that NEW will always have a 8+3 alias
4317 different from that of OLD. (Seems to be required
4318 when NameNumericTail in the Registry is set to 0.) */
4319 lfn_fd = _creat(old, 0);
4321 olen = strlen(tempfile) + 1;
4322 old = tempfile;
4323 r.x.di = __tb_offset + olen;
4326 for (i=0; i<2; i++)
4328 if(use_lfn)
4329 r.x.ax = 0x7156;
4330 else
4331 r.h.ah = 0x56;
4332 _put_path2(new, olen);
4333 _put_path(old);
4334 __dpmi_int(0x21, &r);
4335 if(r.x.flags & 1)
4337 if (r.x.ax == 5 && i == 0) /* access denied */
4338 remove(new); /* and try again */
4339 else
4341 errno = __doserr_to_errno(r.x.ax);
4343 /* Restore to original name if we renamed it to temporary. */
4344 if (use_lfn)
4346 if (lfn_fd != -1)
4348 _close (lfn_fd);
4349 remove (orig);
4351 _put_path2(orig, olen);
4352 _put_path(tempfile);
4353 r.x.ax = 0x7156;
4354 __dpmi_int(0x21, &r);
4356 return -1;
4359 else
4360 break;
4363 /* Success. Delete the file possibly created to work
4364 around the Windows 95 bug. */
4365 if (lfn_fd != -1)
4366 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
4367 return 0;
4370 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4372 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
4373 0, 0, 0,
4374 "Return non-nil if long file names are supported on MSDOS.")
4377 return (_USE_LFN ? Qt : Qnil);
4380 /* Convert alphabetic characters in a filename to lower-case. */
4382 void
4383 msdos_downcase_filename (p)
4384 register unsigned char *p;
4386 /* Always lower-case drive letters a-z, even if the filesystem
4387 preserves case in filenames.
4388 This is so MSDOS filenames could be compared by string comparison
4389 functions that are case-sensitive. Even case-preserving filesystems
4390 do not distinguish case in drive letters. */
4391 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4393 *p += 'a' - 'A';
4394 p += 2;
4397 /* Under LFN we expect to get pathnames in their true case. */
4398 if (NILP (Fmsdos_long_file_names ()))
4399 for ( ; *p; p++)
4400 if (*p >= 'A' && *p <= 'Z')
4401 *p += 'a' - 'A';
4404 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
4405 1, 1, 0,
4406 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4407 When long filenames are supported, doesn't change FILENAME.\n\
4408 If FILENAME is not a string, returns nil.\n\
4409 The argument object is never altered--the value is a copy.")
4410 (filename)
4411 Lisp_Object filename;
4413 Lisp_Object tem;
4415 if (! STRINGP (filename))
4416 return Qnil;
4418 tem = Fcopy_sequence (filename);
4419 msdos_downcase_filename (XSTRING (tem)->data);
4420 return tem;
4423 /* The Emacs root directory as determined by init_environment. */
4425 static char emacsroot[MAXPATHLEN];
4427 char *
4428 rootrelativepath (rel)
4429 char *rel;
4431 static char result[MAXPATHLEN + 10];
4433 strcpy (result, emacsroot);
4434 strcat (result, "/");
4435 strcat (result, rel);
4436 return result;
4439 /* Define a lot of environment variables if not already defined. Don't
4440 remove anything unless you know what you're doing -- lots of code will
4441 break if one or more of these are missing. */
4443 void
4444 init_environment (argc, argv, skip_args)
4445 int argc;
4446 char **argv;
4447 int skip_args;
4449 char *s, *t, *root;
4450 int len;
4451 static const char * const tempdirs[] = {
4452 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4454 int i;
4455 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4457 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4458 temporary files and assume "/tmp" if $TMPDIR is unset, which
4459 will break on DOS/Windows. Refuse to work if we cannot find
4460 a directory, not even "c:/", usable for that purpose. */
4461 for (i = 0; i < imax ; i++)
4463 const char *tmp = tempdirs[i];
4465 if (*tmp == '$')
4466 tmp = getenv (tmp + 1);
4467 /* Note that `access' can lie to us if the directory resides on a
4468 read-only filesystem, like CD-ROM or a write-protected floppy.
4469 The only way to be really sure is to actually create a file and
4470 see if it succeeds. But I think that's too much to ask. */
4471 if (tmp && access (tmp, D_OK) == 0)
4473 setenv ("TMPDIR", tmp, 1);
4474 break;
4477 if (i >= imax)
4478 cmd_error_internal
4479 (Fcons (Qerror,
4480 Fcons (build_string ("no usable temporary directories found!!"),
4481 Qnil)),
4482 "While setting TMPDIR: ");
4484 /* Note the startup time, so we know not to clear the screen if we
4485 exit immediately; see IT_reset_terminal_modes.
4486 (Yes, I know `clock' returns zero the first time it's called, but
4487 I do this anyway, in case some wiseguy changes that at some point.) */
4488 startup_time = clock ();
4490 /* Find our root from argv[0]. Assuming argv[0] is, say,
4491 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4492 root = alloca (MAXPATHLEN + 20);
4493 _fixpath (argv[0], root);
4494 msdos_downcase_filename (root);
4495 len = strlen (root);
4496 while (len > 0 && root[len] != '/' && root[len] != ':')
4497 len--;
4498 root[len] = '\0';
4499 if (len > 4
4500 && (strcmp (root + len - 4, "/bin") == 0
4501 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4502 root[len - 4] = '\0';
4503 else
4504 strcpy (root, "c:/emacs"); /* let's be defensive */
4505 len = strlen (root);
4506 strcpy (emacsroot, root);
4508 /* We default HOME to our root. */
4509 setenv ("HOME", root, 0);
4511 /* We default EMACSPATH to root + "/bin". */
4512 strcpy (root + len, "/bin");
4513 setenv ("EMACSPATH", root, 0);
4515 /* I don't expect anybody to ever use other terminals so the internal
4516 terminal is the default. */
4517 setenv ("TERM", "internal", 0);
4519 #ifdef HAVE_X_WINDOWS
4520 /* Emacs expects DISPLAY to be set. */
4521 setenv ("DISPLAY", "unix:0.0", 0);
4522 #endif
4524 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4525 downcase it and mirror the backslashes. */
4526 s = getenv ("COMSPEC");
4527 if (!s) s = "c:/command.com";
4528 t = alloca (strlen (s) + 1);
4529 strcpy (t, s);
4530 dostounix_filename (t);
4531 setenv ("SHELL", t, 0);
4533 /* PATH is also downcased and backslashes mirrored. */
4534 s = getenv ("PATH");
4535 if (!s) s = "";
4536 t = alloca (strlen (s) + 3);
4537 /* Current directory is always considered part of MsDos's path but it is
4538 not normally mentioned. Now it is. */
4539 strcat (strcpy (t, ".;"), s);
4540 dostounix_filename (t); /* Not a single file name, but this should work. */
4541 setenv ("PATH", t, 1);
4543 /* In some sense all dos users have root privileges, so... */
4544 setenv ("USER", "root", 0);
4545 setenv ("NAME", getenv ("USER"), 0);
4547 /* Time zone determined from country code. To make this possible, the
4548 country code may not span more than one time zone. In other words,
4549 in the USA, you lose. */
4550 if (!getenv ("TZ"))
4551 switch (dos_country_code)
4553 case 31: /* Belgium */
4554 case 32: /* The Netherlands */
4555 case 33: /* France */
4556 case 34: /* Spain */
4557 case 36: /* Hungary */
4558 case 38: /* Yugoslavia (or what's left of it?) */
4559 case 39: /* Italy */
4560 case 41: /* Switzerland */
4561 case 42: /* Tjekia */
4562 case 45: /* Denmark */
4563 case 46: /* Sweden */
4564 case 47: /* Norway */
4565 case 48: /* Poland */
4566 case 49: /* Germany */
4567 /* Daylight saving from last Sunday in March to last Sunday in
4568 September, both at 2AM. */
4569 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4570 break;
4571 case 44: /* United Kingdom */
4572 case 351: /* Portugal */
4573 case 354: /* Iceland */
4574 setenv ("TZ", "GMT+00", 0);
4575 break;
4576 case 81: /* Japan */
4577 case 82: /* Korea */
4578 setenv ("TZ", "JST-09", 0);
4579 break;
4580 case 90: /* Turkey */
4581 case 358: /* Finland */
4582 setenv ("TZ", "EET-02", 0);
4583 break;
4584 case 972: /* Israel */
4585 /* This is an approximation. (For exact rules, use the
4586 `zoneinfo/israel' file which comes with DJGPP, but you need
4587 to install it in `/usr/share/zoneinfo/' directory first.) */
4588 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4589 break;
4591 tzset ();
4596 static int break_stat; /* BREAK check mode status. */
4597 static int stdin_stat; /* stdin IOCTL status. */
4599 #if __DJGPP__ < 2
4601 /* These must be global. */
4602 static _go32_dpmi_seginfo ctrl_break_vector;
4603 static _go32_dpmi_registers ctrl_break_regs;
4604 static int ctrlbreakinstalled = 0;
4606 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4608 void
4609 ctrl_break_func (regs)
4610 _go32_dpmi_registers *regs;
4612 Vquit_flag = Qt;
4615 void
4616 install_ctrl_break_check ()
4618 if (!ctrlbreakinstalled)
4620 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4621 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4622 ctrlbreakinstalled = 1;
4623 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
4624 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
4625 &ctrl_break_regs);
4626 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
4630 #endif /* __DJGPP__ < 2 */
4632 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4633 control chars by DOS. Determine the keyboard type. */
4636 dos_ttraw ()
4638 union REGS inregs, outregs;
4639 static int first_time = 1;
4641 break_stat = getcbrk ();
4642 setcbrk (0);
4643 #if __DJGPP__ < 2
4644 install_ctrl_break_check ();
4645 #endif
4647 if (first_time)
4649 inregs.h.ah = 0xc0;
4650 int86 (0x15, &inregs, &outregs);
4651 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4653 have_mouse = 0;
4655 if (internal_terminal
4656 #ifdef HAVE_X_WINDOWS
4657 && inhibit_window_system
4658 #endif
4661 inregs.x.ax = 0x0021;
4662 int86 (0x33, &inregs, &outregs);
4663 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4664 if (!have_mouse)
4666 /* Reportedly, the above doesn't work for some mouse drivers. There
4667 is an additional detection method that should work, but might be
4668 a little slower. Use that as an alternative. */
4669 inregs.x.ax = 0x0000;
4670 int86 (0x33, &inregs, &outregs);
4671 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4674 if (have_mouse)
4676 have_mouse = 1; /* enable mouse */
4677 mouse_visible = 0;
4678 mouse_setup_buttons (outregs.x.bx);
4679 mouse_position_hook = &mouse_get_pos;
4680 mouse_init ();
4683 #ifndef HAVE_X_WINDOWS
4684 #if __DJGPP__ >= 2
4685 /* Save the cursor shape used outside Emacs. */
4686 outside_cursor = _farpeekw (_dos_ds, 0x460);
4687 #endif
4688 #endif
4691 first_time = 0;
4693 #if __DJGPP__ >= 2
4695 stdin_stat = setmode (fileno (stdin), O_BINARY);
4696 return (stdin_stat != -1);
4698 else
4699 return (setmode (fileno (stdin), O_BINARY) != -1);
4701 #else /* __DJGPP__ < 2 */
4705 /* I think it is wrong to overwrite `stdin_stat' every time
4706 but the first one this function is called, but I don't
4707 want to change the way it used to work in v1.x.--EZ */
4709 inregs.x.ax = 0x4400; /* Get IOCTL status. */
4710 inregs.x.bx = 0x00; /* 0 = stdin. */
4711 intdos (&inregs, &outregs);
4712 stdin_stat = outregs.h.dl;
4714 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
4715 inregs.x.ax = 0x4401; /* Set IOCTL status */
4716 intdos (&inregs, &outregs);
4717 return !outregs.x.cflag;
4719 #endif /* __DJGPP__ < 2 */
4722 /* Restore status of standard input and Ctrl-C checking. */
4725 dos_ttcooked ()
4727 union REGS inregs, outregs;
4729 setcbrk (break_stat);
4730 mouse_off ();
4732 #if __DJGPP__ >= 2
4734 #ifndef HAVE_X_WINDOWS
4735 /* Restore the cursor shape we found on startup. */
4736 if (outside_cursor)
4738 inregs.h.ah = 1;
4739 inregs.x.cx = outside_cursor;
4740 int86 (0x10, &inregs, &outregs);
4742 #endif
4744 return (setmode (fileno (stdin), stdin_stat) != -1);
4746 #else /* not __DJGPP__ >= 2 */
4748 inregs.x.ax = 0x4401; /* Set IOCTL status. */
4749 inregs.x.bx = 0x00; /* 0 = stdin. */
4750 inregs.x.dx = stdin_stat;
4751 intdos (&inregs, &outregs);
4752 return !outregs.x.cflag;
4754 #endif /* not __DJGPP__ >= 2 */
4758 /* Run command as specified by ARGV in directory DIR.
4759 The command is run with input from TEMPIN, output to
4760 file TEMPOUT and stderr to TEMPERR. */
4763 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4764 unsigned char **argv;
4765 const char *working_dir;
4766 int tempin, tempout, temperr;
4767 char **envv;
4769 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4770 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
4771 int msshell, result = -1;
4772 int inbak, outbak, errbak;
4773 int x, y;
4774 Lisp_Object cmd;
4776 /* Get current directory as MSDOS cwd is not per-process. */
4777 getwd (oldwd);
4779 /* If argv[0] is the shell, it might come in any lettercase.
4780 Since `Fmember' is case-sensitive, we need to downcase
4781 argv[0], even if we are on case-preserving filesystems. */
4782 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4783 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4785 *pl = *pa++;
4786 if (*pl >= 'A' && *pl <= 'Z')
4787 *pl += 'a' - 'A';
4789 *pl = '\0';
4791 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4792 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4793 && !strcmp ("-c", argv[1]);
4794 if (msshell)
4796 saveargv1 = argv[1];
4797 saveargv2 = argv[2];
4798 argv[1] = "/c";
4799 /* We only need to mirror slashes if a DOS shell will be invoked
4800 not via `system' (which does the mirroring itself). Yes, that
4801 means DJGPP v1.x will lose here. */
4802 if (argv[2] && argv[3])
4804 char *p = alloca (strlen (argv[2]) + 1);
4806 strcpy (argv[2] = p, saveargv2);
4807 while (*p && isspace (*p))
4808 p++;
4809 while (*p)
4811 if (*p == '/')
4812 *p++ = '\\';
4813 else
4814 p++;
4819 chdir (working_dir);
4820 inbak = dup (0);
4821 outbak = dup (1);
4822 errbak = dup (2);
4823 if (inbak < 0 || outbak < 0 || errbak < 0)
4824 goto done; /* Allocation might fail due to lack of descriptors. */
4826 if (have_mouse > 0)
4827 mouse_get_xy (&x, &y);
4829 dos_ttcooked (); /* do it here while 0 = stdin */
4831 dup2 (tempin, 0);
4832 dup2 (tempout, 1);
4833 dup2 (temperr, 2);
4835 #if __DJGPP__ > 1
4837 if (msshell && !argv[3])
4839 /* MS-DOS native shells are too restrictive. For starters, they
4840 cannot grok commands longer than 126 characters. In DJGPP v2
4841 and later, `system' is much smarter, so we'll call it instead. */
4843 const char *cmnd;
4845 /* A shell gets a single argument--its full command
4846 line--whose original was saved in `saveargv2'. */
4848 /* Don't let them pass empty command lines to `system', since
4849 with some shells it will try to invoke an interactive shell,
4850 which will hang Emacs. */
4851 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4853 if (*cmnd)
4855 extern char **environ;
4856 char **save_env = environ;
4857 int save_system_flags = __system_flags;
4859 /* Request the most powerful version of `system'. We need
4860 all the help we can get to avoid calling stock DOS shells. */
4861 __system_flags = (__system_redirect
4862 | __system_use_shell
4863 | __system_allow_multiple_cmds
4864 | __system_allow_long_cmds
4865 | __system_handle_null_commands
4866 | __system_emulate_chdir);
4868 environ = envv;
4869 result = system (cmnd);
4870 __system_flags = save_system_flags;
4871 environ = save_env;
4873 else
4874 result = 0; /* emulate Unixy shell behavior with empty cmd line */
4876 else
4878 #endif /* __DJGPP__ > 1 */
4880 result = spawnve (P_WAIT, argv[0], argv, envv);
4882 dup2 (inbak, 0);
4883 dup2 (outbak, 1);
4884 dup2 (errbak, 2);
4885 emacs_close (inbak);
4886 emacs_close (outbak);
4887 emacs_close (errbak);
4889 dos_ttraw ();
4890 if (have_mouse > 0)
4892 mouse_init ();
4893 mouse_moveto (x, y);
4896 /* Some programs might change the meaning of the highest bit of the
4897 text attribute byte, so we get blinking characters instead of the
4898 bright background colors. Restore that. */
4899 bright_bg ();
4901 done:
4902 chdir (oldwd);
4903 if (msshell)
4905 argv[1] = saveargv1;
4906 argv[2] = saveargv2;
4908 return result;
4911 croak (badfunc)
4912 char *badfunc;
4914 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4915 reset_sys_modes ();
4916 exit (1);
4919 #if __DJGPP__ < 2
4921 /* ------------------------- Compatibility functions -------------------
4922 * gethostname
4923 * gettimeofday
4926 /* Hostnames for a pc are not really funny,
4927 but they are used in change log so we emulate the best we can. */
4929 gethostname (p, size)
4930 char *p;
4931 int size;
4933 char *q = egetenv ("HOSTNAME");
4935 if (!q) q = "pc";
4936 strcpy (p, q);
4937 return 0;
4940 /* When time zones are set from Ms-Dos too many C-libraries are playing
4941 tricks with time values. We solve this by defining our own version
4942 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4943 once and after each call to `tzset' with TZ changed. That is
4944 accomplished by aliasing tzset to init_gettimeofday. */
4946 static struct tm time_rec;
4949 gettimeofday (struct timeval *tp, struct timezone *tzp)
4951 if (tp)
4953 struct time t;
4954 struct tm tm;
4956 gettime (&t);
4957 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
4959 struct date d;
4960 getdate (&d);
4961 time_rec.tm_year = d.da_year - 1900;
4962 time_rec.tm_mon = d.da_mon - 1;
4963 time_rec.tm_mday = d.da_day;
4966 time_rec.tm_hour = t.ti_hour;
4967 time_rec.tm_min = t.ti_min;
4968 time_rec.tm_sec = t.ti_sec;
4970 tm = time_rec;
4971 tm.tm_gmtoff = dos_timezone_offset;
4973 tp->tv_sec = mktime (&tm); /* may modify tm */
4974 tp->tv_usec = t.ti_hund * (1000000 / 100);
4976 /* Ignore tzp; it's obsolescent. */
4977 return 0;
4980 #endif /* __DJGPP__ < 2 */
4983 * A list of unimplemented functions that we silently ignore.
4986 #if __DJGPP__ < 2
4987 unsigned alarm (s) unsigned s; {}
4988 fork () { return 0; }
4989 int kill (x, y) int x, y; { return -1; }
4990 nice (p) int p; {}
4991 void volatile pause () {}
4992 sigsetmask (x) int x; { return 0; }
4993 sigblock (mask) int mask; { return 0; }
4994 #endif
4996 void request_sigio (void) {}
4997 setpgrp () {return 0; }
4998 setpriority (x,y,z) int x,y,z; { return 0; }
4999 void unrequest_sigio (void) {}
5001 #if __DJGPP__ > 1
5003 #ifdef POSIX_SIGNALS
5005 /* Augment DJGPP library POSIX signal functions. This is needed
5006 as of DJGPP v2.01, but might be in the library in later releases. */
5008 #include <libc/bss.h>
5010 /* A counter to know when to re-initialize the static sets. */
5011 static int sigprocmask_count = -1;
5013 /* Which signals are currently blocked (initially none). */
5014 static sigset_t current_mask;
5016 /* Which signals are pending (initially none). */
5017 static sigset_t pending_signals;
5019 /* Previous handlers to restore when the blocked signals are unblocked. */
5020 typedef void (*sighandler_t)(int);
5021 static sighandler_t prev_handlers[320];
5023 /* A signal handler which just records that a signal occured
5024 (it will be raised later, if and when the signal is unblocked). */
5025 static void
5026 sig_suspender (signo)
5027 int signo;
5029 sigaddset (&pending_signals, signo);
5033 sigprocmask (how, new_set, old_set)
5034 int how;
5035 const sigset_t *new_set;
5036 sigset_t *old_set;
5038 int signo;
5039 sigset_t new_mask;
5041 /* If called for the first time, initialize. */
5042 if (sigprocmask_count != __bss_count)
5044 sigprocmask_count = __bss_count;
5045 sigemptyset (&pending_signals);
5046 sigemptyset (&current_mask);
5047 for (signo = 0; signo < 320; signo++)
5048 prev_handlers[signo] = SIG_ERR;
5051 if (old_set)
5052 *old_set = current_mask;
5054 if (new_set == 0)
5055 return 0;
5057 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
5059 errno = EINVAL;
5060 return -1;
5063 sigemptyset (&new_mask);
5065 /* DJGPP supports upto 320 signals. */
5066 for (signo = 0; signo < 320; signo++)
5068 if (sigismember (&current_mask, signo))
5069 sigaddset (&new_mask, signo);
5070 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
5072 sigaddset (&new_mask, signo);
5074 /* SIGKILL is silently ignored, as on other platforms. */
5075 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
5076 prev_handlers[signo] = signal (signo, sig_suspender);
5078 if (( how == SIG_UNBLOCK
5079 && sigismember (&new_mask, signo)
5080 && sigismember (new_set, signo))
5081 || (how == SIG_SETMASK
5082 && sigismember (&new_mask, signo)
5083 && !sigismember (new_set, signo)))
5085 sigdelset (&new_mask, signo);
5086 if (prev_handlers[signo] != SIG_ERR)
5088 signal (signo, prev_handlers[signo]);
5089 prev_handlers[signo] = SIG_ERR;
5091 if (sigismember (&pending_signals, signo))
5093 sigdelset (&pending_signals, signo);
5094 raise (signo);
5098 current_mask = new_mask;
5099 return 0;
5102 #else /* not POSIX_SIGNALS */
5104 sigsetmask (x) int x; { return 0; }
5105 sigblock (mask) int mask; { return 0; }
5107 #endif /* not POSIX_SIGNALS */
5108 #endif /* __DJGPP__ > 1 */
5110 #ifndef HAVE_SELECT
5111 #include "sysselect.h"
5113 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5114 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5115 ((long)(time).tv_sec < 0 \
5116 || ((time).tv_sec == 0 \
5117 && (long)(time).tv_usec <= 0))
5118 #endif
5120 /* This yields the rest of the current time slice to the task manager.
5121 It should be called by any code which knows that it has nothing
5122 useful to do except idle.
5124 I don't use __dpmi_yield here, since versions of library before 2.02
5125 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5126 on some versions of Windows 9X. */
5128 void
5129 dos_yield_time_slice (void)
5131 _go32_dpmi_registers r;
5133 r.x.ax = 0x1680;
5134 r.x.ss = r.x.sp = r.x.flags = 0;
5135 _go32_dpmi_simulate_int (0x2f, &r);
5136 if (r.h.al == 0x80)
5137 errno = ENOSYS;
5140 /* Only event queue is checked. */
5141 /* We don't have to call timer_check here
5142 because wait_reading_process_input takes care of that. */
5144 sys_select (nfds, rfds, wfds, efds, timeout)
5145 int nfds;
5146 SELECT_TYPE *rfds, *wfds, *efds;
5147 EMACS_TIME *timeout;
5149 int check_input;
5150 struct time t;
5152 check_input = 0;
5153 if (rfds)
5155 check_input = FD_ISSET (0, rfds);
5156 FD_ZERO (rfds);
5158 if (wfds)
5159 FD_ZERO (wfds);
5160 if (efds)
5161 FD_ZERO (efds);
5163 if (nfds != 1)
5164 abort ();
5166 /* If we are looking only for the terminal, with no timeout,
5167 just read it and wait -- that's more efficient. */
5168 if (!timeout)
5170 while (!detect_input_pending ())
5172 dos_yield_time_slice ();
5175 else
5177 EMACS_TIME clnow, cllast, cldiff;
5179 gettime (&t);
5180 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
5182 while (!check_input || !detect_input_pending ())
5184 gettime (&t);
5185 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
5186 EMACS_SUB_TIME (cldiff, clnow, cllast);
5188 /* When seconds wrap around, we assume that no more than
5189 1 minute passed since last `gettime'. */
5190 if (EMACS_TIME_NEG_P (cldiff))
5191 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
5192 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
5194 /* Stop when timeout value crosses zero. */
5195 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
5196 return 0;
5197 cllast = clnow;
5198 dos_yield_time_slice ();
5202 FD_SET (0, rfds);
5203 return 1;
5205 #endif
5208 * Define overlaid functions:
5210 * chdir -> sys_chdir
5211 * tzset -> init_gettimeofday
5212 * abort -> dos_abort
5215 #ifdef chdir
5216 #undef chdir
5217 extern int chdir ();
5220 sys_chdir (path)
5221 const char* path;
5223 int len = strlen (path);
5224 char *tmp = (char *)path;
5226 if (*tmp && tmp[1] == ':')
5228 if (getdisk () != tolower (tmp[0]) - 'a')
5229 setdisk (tolower (tmp[0]) - 'a');
5230 tmp += 2; /* strip drive: KFS 1995-07-06 */
5231 len -= 2;
5234 if (len > 1 && (tmp[len - 1] == '/'))
5236 char *tmp1 = (char *) alloca (len + 1);
5237 strcpy (tmp1, tmp);
5238 tmp1[len - 1] = 0;
5239 tmp = tmp1;
5241 return chdir (tmp);
5243 #endif
5245 #ifdef tzset
5246 #undef tzset
5247 extern void tzset (void);
5249 void
5250 init_gettimeofday ()
5252 time_t ltm, gtm;
5253 struct tm *lstm;
5255 tzset ();
5256 ltm = gtm = time (NULL);
5257 ltm = mktime (lstm = localtime (&ltm));
5258 gtm = mktime (gmtime (&gtm));
5259 time_rec.tm_hour = 99; /* force gettimeofday to get date */
5260 time_rec.tm_isdst = lstm->tm_isdst;
5261 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
5263 #endif
5265 #ifdef abort
5266 #undef abort
5267 void
5268 dos_abort (file, line)
5269 char *file;
5270 int line;
5272 char buffer1[200], buffer2[400];
5273 int i, j;
5275 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
5276 for (i = j = 0; buffer1[i]; i++) {
5277 buffer2[j++] = buffer1[i];
5278 buffer2[j++] = 0x70;
5280 dosmemput (buffer2, j, (int)ScreenPrimary);
5281 ScreenSetCursor (2, 0);
5282 abort ();
5284 #else
5285 void
5286 abort ()
5288 dos_ttcooked ();
5289 ScreenSetCursor (10, 0);
5290 cputs ("\r\n\nEmacs aborted!\r\n");
5291 #if __DJGPP__ > 1
5292 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5293 if (screen_virtual_segment)
5294 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
5295 /* Generate traceback, so we could tell whodunit. */
5296 signal (SIGINT, SIG_DFL);
5297 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5298 #else /* __DJGPP_MINOR__ >= 2 */
5299 raise (SIGABRT);
5300 #endif /* __DJGPP_MINOR__ >= 2 */
5301 #endif
5302 exit (2);
5304 #endif
5306 /* The following variables are required so that cus-start.el won't
5307 complain about unbound variables. */
5308 #ifndef HAVE_X_WINDOWS
5309 /* Search path for bitmap files (xfns.c). */
5310 Lisp_Object Vx_bitmap_file_path;
5311 int x_stretch_cursor_p;
5312 #endif
5313 #ifndef subprocesses
5314 /* Nonzero means delete a process right away if it exits (process.c). */
5315 static int delete_exited_processes;
5316 #endif
5318 syms_of_msdos ()
5320 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
5321 staticpro (&recent_doskeys);
5322 #ifndef HAVE_X_WINDOWS
5323 help_echo = Qnil;
5324 staticpro (&help_echo);
5325 help_echo_object = Qnil;
5326 staticpro (&help_echo_object);
5327 help_echo_window = Qnil;
5328 staticpro (&help_echo_window);
5329 previous_help_echo = Qnil;
5330 staticpro (&previous_help_echo);
5331 help_echo_pos = -1;
5333 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
5334 "List of directories to search for bitmap files for X.");
5335 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
5337 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
5338 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5339 For example, if a block cursor is over a tab, it will be drawn as\n\
5340 wide as that tab on the display. (No effect on MS-DOS.)");
5341 x_stretch_cursor_p = 0;
5343 /* The following two are from xfns.c: */
5344 Qbar = intern ("bar");
5345 staticpro (&Qbar);
5346 Qcursor_type = intern ("cursor-type");
5347 staticpro (&Qcursor_type);
5348 Qreverse = intern ("reverse");
5349 staticpro (&Qreverse);
5351 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
5352 "*Glyph to display instead of chars not supported by current codepage.\n\
5354 This variable is used only by MSDOS terminals.");
5355 Vdos_unsupported_char_glyph = '\177';
5356 #endif
5357 #ifndef subprocesses
5358 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
5359 "*Non-nil means delete processes immediately when they exit.\n\
5360 nil means don't delete them until `list-processes' is run.");
5361 delete_exited_processes = 0;
5362 #endif
5364 defsubr (&Srecent_doskeys);
5365 defsubr (&Smsdos_long_file_names);
5366 defsubr (&Smsdos_downcase_filename);
5367 defsubr (&Smsdos_remember_default_colors);
5368 defsubr (&Smsdos_set_mouse_buttons);
5371 #endif /* MSDOS */