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