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