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