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