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