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