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