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