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