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