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