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