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