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