]> code.delx.au - gnu-emacs/blob - src/msdos.c
(IT_set_frame_parameters): Actually store the frame
[gnu-emacs] / src / msdos.c
1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
23
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
25
26 #include <config.h>
27
28 #ifdef MSDOS
29 #include "lisp.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <dos.h>
35 #include <errno.h>
36 #include <string.h> /* for bzero and string functions */
37 #include <sys/stat.h> /* for _fixpath */
38 #include <unistd.h> /* for chdir, dup, dup2, etc. */
39 #if __DJGPP__ >= 2
40 #include <fcntl.h>
41 #include <io.h> /* for setmode */
42 #include <dpmi.h> /* for __dpmi_xxx stuff */
43 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
44 #include <libc/dosio.h> /* for _USE_LFN */
45 #include <conio.h> /* for cputs */
46 #endif
47
48 #include "dosfns.h"
49 #include "msdos.h"
50 #include "systime.h"
51 #include "termhooks.h"
52 #include "dispextern.h"
53 #include "termopts.h"
54 #include "frame.h"
55 #include "window.h"
56 #include "buffer.h"
57 #include "commands.h"
58 #include <go32.h>
59 #include <pc.h>
60 #include <ctype.h>
61 /* #include <process.h> */
62 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
63 #define P_WAIT 1
64
65 #ifndef _USE_LFN
66 #define _USE_LFN 0
67 #endif
68
69 #ifndef _dos_ds
70 #define _dos_ds _go32_info_block.selector_for_linear_memory
71 #endif
72
73 #if __DJGPP__ > 1
74
75 #include <signal.h>
76 #include "syssignal.h"
77
78 #ifndef SYSTEM_MALLOC
79
80 #ifdef GNU_MALLOC
81
82 /* If other `malloc' than ours is used, force our `sbrk' behave like
83 Unix programs expect (resize memory blocks to keep them contiguous).
84 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
85 because that's what `gmalloc' expects to get. */
86 #include <crt0.h>
87
88 #ifdef REL_ALLOC
89 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
90 #else /* not REL_ALLOC */
91 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
92 #endif /* not REL_ALLOC */
93 #endif /* GNU_MALLOC */
94
95 #endif /* not SYSTEM_MALLOC */
96 #endif /* __DJGPP__ > 1 */
97
98 static unsigned long
99 event_timestamp ()
100 {
101 struct time t;
102 unsigned long s;
103
104 gettime (&t);
105 s = t.ti_min;
106 s *= 60;
107 s += t.ti_sec;
108 s *= 1000;
109 s += t.ti_hund * 10;
110
111 return s;
112 }
113
114 \f
115 /* ------------------------ Mouse control ---------------------------
116 *
117 * Coordinates are in screen positions and zero based.
118 * Mouse buttons are numbered from left to right and also zero based.
119 */
120
121 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
122 static int mouse_visible;
123
124 static int mouse_last_x;
125 static int mouse_last_y;
126
127 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
128 static int mouse_button_count;
129
130 void
131 mouse_on ()
132 {
133 union REGS regs;
134
135 if (have_mouse > 0 && !mouse_visible)
136 {
137 if (termscript)
138 fprintf (termscript, "<M_ON>");
139 regs.x.ax = 0x0001;
140 int86 (0x33, &regs, &regs);
141 mouse_visible = 1;
142 }
143 }
144
145 void
146 mouse_off ()
147 {
148 union REGS regs;
149
150 if (have_mouse > 0 && mouse_visible)
151 {
152 if (termscript)
153 fprintf (termscript, "<M_OFF>");
154 regs.x.ax = 0x0002;
155 int86 (0x33, &regs, &regs);
156 mouse_visible = 0;
157 }
158 }
159
160 void
161 mouse_moveto (x, y)
162 int x, y;
163 {
164 union REGS regs;
165
166 if (termscript)
167 fprintf (termscript, "<M_XY=%dx%d>", x, y);
168 regs.x.ax = 0x0004;
169 mouse_last_x = regs.x.cx = x * 8;
170 mouse_last_y = regs.x.dx = y * 8;
171 int86 (0x33, &regs, &regs);
172 }
173
174 static int
175 mouse_pressed (b, xp, yp)
176 int b, *xp, *yp;
177 {
178 union REGS regs;
179
180 if (b >= mouse_button_count)
181 return 0;
182 regs.x.ax = 0x0005;
183 regs.x.bx = mouse_button_translate[b];
184 int86 (0x33, &regs, &regs);
185 if (regs.x.bx)
186 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
187 return (regs.x.bx != 0);
188 }
189
190 static int
191 mouse_released (b, xp, yp)
192 int b, *xp, *yp;
193 {
194 union REGS regs;
195
196 if (b >= mouse_button_count)
197 return 0;
198 regs.x.ax = 0x0006;
199 regs.x.bx = mouse_button_translate[b];
200 int86 (0x33, &regs, &regs);
201 if (regs.x.bx)
202 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
203 return (regs.x.bx != 0);
204 }
205
206 static void
207 mouse_get_xy (int *x, int *y)
208 {
209 union REGS regs;
210
211 regs.x.ax = 0x0003;
212 int86 (0x33, &regs, &regs);
213 *x = regs.x.cx / 8;
214 *y = regs.x.dx / 8;
215 }
216
217 void
218 mouse_get_pos (f, insist, bar_window, part, x, y, time)
219 FRAME_PTR *f;
220 int insist;
221 Lisp_Object *bar_window, *x, *y;
222 enum scroll_bar_part *part;
223 unsigned long *time;
224 {
225 int ix, iy;
226 union REGS regs;
227
228 regs.x.ax = 0x0003;
229 int86 (0x33, &regs, &regs);
230 *f = selected_frame;
231 *bar_window = Qnil;
232 mouse_get_xy (&ix, &iy);
233 selected_frame->mouse_moved = 0;
234 *x = make_number (ix);
235 *y = make_number (iy);
236 *time = event_timestamp ();
237 }
238
239 static void
240 mouse_check_moved ()
241 {
242 int x, y;
243
244 mouse_get_xy (&x, &y);
245 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
246 mouse_last_x = x;
247 mouse_last_y = y;
248 }
249
250 void
251 mouse_init ()
252 {
253 union REGS regs;
254
255 if (termscript)
256 fprintf (termscript, "<M_INIT>");
257
258 regs.x.ax = 0x0021;
259 int86 (0x33, &regs, &regs);
260
261 regs.x.ax = 0x0007;
262 regs.x.cx = 0;
263 regs.x.dx = 8 * (ScreenCols () - 1);
264 int86 (0x33, &regs, &regs);
265
266 regs.x.ax = 0x0008;
267 regs.x.cx = 0;
268 regs.x.dx = 8 * (ScreenRows () - 1);
269 int86 (0x33, &regs, &regs);
270
271 mouse_moveto (0, 0);
272 mouse_visible = 0;
273 }
274 \f
275 /* ------------------------- Screen control ----------------------
276 *
277 */
278
279 static int internal_terminal = 0;
280
281 #ifndef HAVE_X_WINDOWS
282 extern unsigned char ScreenAttrib;
283 static int screen_face;
284 static int highlight;
285
286 static int screen_size_X;
287 static int screen_size_Y;
288 static int screen_size;
289
290 static int current_pos_X;
291 static int current_pos_Y;
292 static int new_pos_X;
293 static int new_pos_Y;
294
295 static void *startup_screen_buffer;
296 static int startup_screen_size_X;
297 static int startup_screen_size_Y;
298 static int startup_pos_X;
299 static int startup_pos_Y;
300 static unsigned char startup_screen_attrib;
301
302 static int term_setup_done;
303
304 /* Similar to the_only_frame. */
305 struct x_output the_only_x_display;
306
307 /* This is never dereferenced. */
308 Display *x_current_display;
309
310 static
311 dos_direct_output (y, x, buf, len)
312 int y;
313 int x;
314 char *buf;
315 int len;
316 {
317 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
318
319 #if (__DJGPP__ < 2)
320 while (--len >= 0) {
321 dosmemput (buf++, 1, t);
322 t += 2;
323 }
324 #else
325 /* This is faster. */
326 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
327 _farnspokeb (t, *buf);
328 #endif
329 }
330 #endif
331
332 /* Flash the screen as a substitute for BEEPs. */
333
334 #if (__DJGPP__ < 2)
335 static void
336 do_visible_bell (xorattr)
337 unsigned char xorattr;
338 {
339 asm volatile
340 (" movb $1,%%dl
341 visible_bell_0:
342 movl _ScreenPrimary,%%eax
343 call dosmemsetup
344 movl %%eax,%%ebx
345 movl %1,%%ecx
346 movb %0,%%al
347 incl %%ebx
348 visible_bell_1:
349 xorb %%al,%%gs:(%%ebx)
350 addl $2,%%ebx
351 decl %%ecx
352 jne visible_bell_1
353 decb %%dl
354 jne visible_bell_3
355 visible_bell_2:
356 movzwl %%ax,%%eax
357 movzwl %%ax,%%eax
358 movzwl %%ax,%%eax
359 movzwl %%ax,%%eax
360 decw %%cx
361 jne visible_bell_2
362 jmp visible_bell_0
363 visible_bell_3:"
364 : /* no output */
365 : "m" (xorattr), "g" (screen_size)
366 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
367 }
368
369 static void
370 ScreenVisualBell (void)
371 {
372 /* This creates an xor-mask that will swap the default fore- and
373 background colors. */
374 do_visible_bell (((the_only_x_display.foreground_pixel
375 ^ the_only_x_display.background_pixel)
376 * 0x11) & 0x7f);
377 }
378 #endif
379
380 #ifndef HAVE_X_WINDOWS
381
382 static int blink_bit = -1; /* the state of the blink bit at startup */
383
384 /* Enable bright background colors. */
385 static void
386 bright_bg (void)
387 {
388 union REGS regs;
389
390 /* Remember the original state of the blink/bright-background bit.
391 It is stored at 0040:0065h in the BIOS data area. */
392 if (blink_bit == -1)
393 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
394
395 regs.h.bl = 0;
396 regs.x.ax = 0x1003;
397 int86 (0x10, &regs, &regs);
398 }
399
400 /* Disable bright background colors (and enable blinking) if we found
401 the video system in that state at startup. */
402 static void
403 maybe_enable_blinking (void)
404 {
405 if (blink_bit == 1)
406 {
407 union REGS regs;
408
409 regs.h.bl = 1;
410 regs.x.ax = 0x1003;
411 int86 (0x10, &regs, &regs);
412 }
413 }
414
415 /* Set the screen dimensions so that it can show no less than
416 ROWS x COLS frame. */
417
418 void
419 dos_set_window_size (rows, cols)
420 int *rows, *cols;
421 {
422 char video_name[30];
423 Lisp_Object video_mode;
424 int video_mode_value;
425 int have_vga = 0;
426 union REGS regs;
427 int current_rows = ScreenRows (), current_cols = ScreenCols ();
428
429 if (*rows == current_rows && *cols == current_cols)
430 return;
431
432 /* Do we have a VGA? */
433 regs.x.ax = 0x1a00;
434 int86 (0x10, &regs, &regs);
435 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
436 have_vga = 1;
437
438 mouse_off ();
439
440 /* If the user specified a special video mode for these dimensions,
441 use that mode. */
442 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
443 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
444 Qnil))-> value;
445
446 if (INTEGERP (video_mode)
447 && (video_mode_value = XINT (video_mode)) > 0)
448 {
449 regs.x.ax = video_mode_value;
450 int86 (0x10, &regs, &regs);
451
452 if (have_mouse)
453 {
454 /* Must hardware-reset the mouse, or else it won't update
455 its notion of screen dimensions for some non-standard
456 video modes. This is *painfully* slow... */
457 regs.x.ax = 0;
458 int86 (0x33, &regs, &regs);
459 }
460 }
461
462 /* Find one of the dimensions supported by standard EGA/VGA
463 which gives us at least the required dimensions. */
464
465 #if __DJGPP__ > 1
466
467 else
468 {
469 static struct {
470 int rows;
471 int need_vga;
472 } std_dimension[] = {
473 {25, 0},
474 {28, 1},
475 {35, 0},
476 {40, 1},
477 {43, 0},
478 {50, 1}
479 };
480 int i = 0;
481
482 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
483 {
484 if (std_dimension[i].need_vga <= have_vga
485 && std_dimension[i].rows >= *rows)
486 {
487 if (std_dimension[i].rows != current_rows
488 || *cols != current_cols)
489 _set_screen_lines (std_dimension[i].rows);
490 break;
491 }
492 i++;
493 }
494 }
495
496 #else /* not __DJGPP__ > 1 */
497
498 else if (*rows <= 25)
499 {
500 if (current_rows != 25 || current_cols != 80)
501 {
502 regs.x.ax = 3;
503 int86 (0x10, &regs, &regs);
504 regs.x.ax = 0x1101;
505 regs.h.bl = 0;
506 int86 (0x10, &regs, &regs);
507 regs.x.ax = 0x1200;
508 regs.h.bl = 32;
509 int86 (0x10, &regs, &regs);
510 regs.x.ax = 3;
511 int86 (0x10, &regs, &regs);
512 }
513 }
514 else if (*rows <= 50)
515 if (have_vga && (current_rows != 50 || current_cols != 80)
516 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
517 {
518 regs.x.ax = 3;
519 int86 (0x10, &regs, &regs);
520 regs.x.ax = 0x1112;
521 regs.h.bl = 0;
522 int86 (0x10, &regs, &regs);
523 regs.x.ax = 0x1200;
524 regs.h.bl = 32;
525 int86 (0x10, &regs, &regs);
526 regs.x.ax = 0x0100;
527 regs.x.cx = 7;
528 int86 (0x10, &regs, &regs);
529 }
530 #endif /* not __DJGPP__ > 1 */
531
532 if (have_mouse)
533 {
534 mouse_init ();
535 mouse_on ();
536 }
537
538 /* Tell the caller what dimensions have been REALLY set. */
539 *rows = ScreenRows ();
540 *cols = ScreenCols ();
541
542 /* Enable bright background colors. */
543 bright_bg ();
544 }
545
546 /* If we write a character in the position where the mouse is,
547 the mouse cursor may need to be refreshed. */
548
549 static void
550 mouse_off_maybe ()
551 {
552 int x, y;
553
554 if (!mouse_visible)
555 return;
556
557 mouse_get_xy (&x, &y);
558 if (y != new_pos_Y || x < new_pos_X)
559 return;
560
561 mouse_off ();
562 }
563
564 static
565 IT_ring_bell ()
566 {
567 if (visible_bell)
568 {
569 mouse_off ();
570 ScreenVisualBell ();
571 }
572 else
573 {
574 union REGS inregs, outregs;
575 inregs.h.ah = 2;
576 inregs.h.dl = 7;
577 intdos (&inregs, &outregs);
578 }
579 }
580
581 static void
582 IT_set_face (int face)
583 {
584 struct face *fp;
585 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
586
587 if (face == 1 || (face == 0 && highlight))
588 fp = FRAME_MODE_LINE_FACE (foo);
589 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
590 fp = FRAME_DEFAULT_FACE (foo);
591 else
592 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
593 if (termscript)
594 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
595 screen_face = face;
596 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
597 }
598
599 static
600 IT_write_glyphs (GLYPH *str, int len)
601 {
602 int newface;
603 int ch, l = len;
604 unsigned char *buf, *bp;
605
606 if (len == 0) return;
607
608 buf = bp = alloca (len * 2);
609
610 while (--l >= 0)
611 {
612 newface = FAST_GLYPH_FACE (*str);
613 if (newface != screen_face)
614 IT_set_face (newface);
615 ch = FAST_GLYPH_CHAR (*str);
616 *bp++ = (unsigned char)ch;
617 *bp++ = ScreenAttrib;
618
619 if (termscript)
620 fputc (ch, termscript);
621 str++;
622 }
623
624 mouse_off_maybe ();
625 dosmemput (buf, 2 * len,
626 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
627 new_pos_X += len;
628 }
629
630 static
631 IT_clear_end_of_line (first_unused)
632 {
633 char *spaces, *sp;
634 int i, j;
635
636 IT_set_face (0);
637 if (termscript)
638 fprintf (termscript, "<CLR:EOL>");
639 i = (j = screen_size_X - new_pos_X) * 2;
640 spaces = sp = alloca (i);
641
642 while (--j >= 0)
643 {
644 *sp++ = ' ';
645 *sp++ = ScreenAttrib;
646 }
647
648 mouse_off_maybe ();
649 dosmemput (spaces, i,
650 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
651 }
652
653 static
654 IT_clear_screen (void)
655 {
656 if (termscript)
657 fprintf (termscript, "<CLR:SCR>");
658 IT_set_face (0);
659 mouse_off ();
660 ScreenClear ();
661 new_pos_X = new_pos_Y = 0;
662 }
663
664 static
665 IT_clear_to_end (void)
666 {
667 if (termscript)
668 fprintf (termscript, "<CLR:EOS>");
669
670 while (new_pos_Y < screen_size_Y) {
671 new_pos_X = 0;
672 IT_clear_end_of_line (0);
673 new_pos_Y++;
674 }
675 }
676
677 static
678 IT_cursor_to (int y, int x)
679 {
680 if (termscript)
681 fprintf (termscript, "\n<XY=%dx%d>", x, y);
682 new_pos_X = x;
683 new_pos_Y = y;
684 }
685
686 static int cursor_cleared;
687
688 static
689 IT_display_cursor (int on)
690 {
691 if (on && cursor_cleared)
692 {
693 ScreenSetCursor (current_pos_Y, current_pos_X);
694 cursor_cleared = 0;
695 }
696 else if (!on && !cursor_cleared)
697 {
698 ScreenSetCursor (-1, -1);
699 cursor_cleared = 1;
700 }
701 }
702
703 /* Emacs calls cursor-movement functions a lot when it updates the
704 display (probably a legacy of old terminals where you cannot
705 update a screen line without first moving the cursor there).
706 However, cursor movement is expensive on MSDOS (it calls a slow
707 BIOS function and requires 2 mode switches), while actual screen
708 updates access the video memory directly and don't depend on
709 cursor position. To avoid slowing down the redisplay, we cheat:
710 all functions that move the cursor only set internal variables
711 which record the cursor position, whereas the cursor is only
712 moved to its final position whenever screen update is complete.
713
714 `IT_cmgoto' is called from the keyboard reading loop and when the
715 frame update is complete. This means that we are ready for user
716 input, so we update the cursor position to show where the point is,
717 and also make the mouse pointer visible.
718
719 Special treatment is required when the cursor is in the echo area,
720 to put the cursor at the end of the text displayed there. */
721
722 static
723 IT_cmgoto (f)
724 FRAME_PTR f;
725 {
726 /* Only set the cursor to where it should be if the display is
727 already in sync with the window contents. */
728 int update_cursor_pos = MODIFF == unchanged_modified;
729
730 /* If we are in the echo area, put the cursor at the end of text. */
731 if (!update_cursor_pos
732 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
733 {
734 new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
735 update_cursor_pos = 1;
736 }
737
738 if (update_cursor_pos
739 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
740 {
741 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
742 if (termscript)
743 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
744 }
745
746 /* Maybe cursor is invisible, so make it visible. */
747 IT_display_cursor (1);
748
749 /* Mouse pointer should be always visible if we are waiting for
750 keyboard input. */
751 if (!mouse_visible)
752 mouse_on ();
753 }
754
755 static
756 IT_reassert_line_highlight (new, vpos)
757 int new, vpos;
758 {
759 highlight = new;
760 IT_set_face (0); /* To possibly clear the highlighting. */
761 }
762
763 static
764 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
765 {
766 highlight = new_highlight;
767 IT_set_face (0); /* To possibly clear the highlighting. */
768 IT_cursor_to (vpos, 0);
769 IT_clear_end_of_line (first_unused_hpos);
770 }
771
772 static
773 IT_update_begin ()
774 {
775 highlight = 0;
776 IT_set_face (0); /* To possibly clear the highlighting. */
777 screen_face = -1;
778 }
779
780 static
781 IT_update_end ()
782 {
783 }
784
785 /* This was more or less copied from xterm.c
786
787 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
788 on xfns.c */
789
790 static void
791 IT_set_menu_bar_lines (window, n)
792 Lisp_Object window;
793 int n;
794 {
795 struct window *w = XWINDOW (window);
796
797 XSETFASTINT (w->last_modified, 0);
798 XSETFASTINT (w->last_overlay_modified, 0);
799 XSETFASTINT (w->top, XFASTINT (w->top) + n);
800 XSETFASTINT (w->height, XFASTINT (w->height) - n);
801
802 /* Handle just the top child in a vertical split. */
803 if (!NILP (w->vchild))
804 IT_set_menu_bar_lines (w->vchild, n);
805
806 /* Adjust all children in a horizontal split. */
807 for (window = w->hchild; !NILP (window); window = w->next)
808 {
809 w = XWINDOW (window);
810 IT_set_menu_bar_lines (window, n);
811 }
812 }
813
814 /* This was copied from xfns.c */
815
816 Lisp_Object Qbackground_color;
817 Lisp_Object Qforeground_color;
818
819 void
820 x_set_menu_bar_lines (f, value, oldval)
821 struct frame *f;
822 Lisp_Object value, oldval;
823 {
824 int nlines;
825 int olines = FRAME_MENU_BAR_LINES (f);
826
827 /* Right now, menu bars don't work properly in minibuf-only frames;
828 most of the commands try to apply themselves to the minibuffer
829 frame itslef, and get an error because you can't switch buffers
830 in or split the minibuffer window. */
831 if (FRAME_MINIBUF_ONLY_P (f))
832 return;
833
834 if (INTEGERP (value))
835 nlines = XINT (value);
836 else
837 nlines = 0;
838
839 FRAME_MENU_BAR_LINES (f) = nlines;
840 IT_set_menu_bar_lines (f->root_window, nlines - olines);
841 }
842
843 /* IT_set_terminal_modes is called when emacs is started,
844 resumed, and whenever the screen is redrawn! */
845
846 static
847 IT_set_terminal_modes (void)
848 {
849 if (termscript)
850 fprintf (termscript, "\n<SET_TERM>");
851 highlight = 0;
852
853 screen_size_X = ScreenCols ();
854 screen_size_Y = ScreenRows ();
855 screen_size = screen_size_X * screen_size_Y;
856
857 new_pos_X = new_pos_Y = 0;
858 current_pos_X = current_pos_Y = -1;
859
860 if (term_setup_done)
861 return;
862 term_setup_done = 1;
863
864 startup_screen_size_X = screen_size_X;
865 startup_screen_size_Y = screen_size_Y;
866 startup_screen_attrib = ScreenAttrib;
867
868 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
869 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
870
871 if (termscript)
872 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
873 screen_size_X, screen_size_Y);
874
875 bright_bg ();
876 }
877
878 /* IT_reset_terminal_modes is called when emacs is
879 suspended or killed. */
880
881 static
882 IT_reset_terminal_modes (void)
883 {
884 int display_row_start = (int) ScreenPrimary;
885 int saved_row_len = startup_screen_size_X * 2;
886 int update_row_len = ScreenCols () * 2;
887 int current_rows = ScreenRows ();
888 int to_next_row = update_row_len;
889 unsigned char *saved_row = startup_screen_buffer;
890 int cursor_pos_X = ScreenCols () - 1;
891 int cursor_pos_Y = ScreenRows () - 1;
892
893 if (termscript)
894 fprintf (termscript, "\n<RESET_TERM>");
895
896 highlight = 0;
897
898 if (!term_setup_done)
899 return;
900
901 mouse_off ();
902
903 /* Leave the video system in the same state as we found it,
904 as far as the blink/bright-background bit is concerned. */
905 maybe_enable_blinking ();
906
907 /* We have a situation here.
908 We cannot just do ScreenUpdate(startup_screen_buffer) because
909 the luser could have changed screen dimensions inside Emacs
910 and failed (or didn't want) to restore them before killing
911 Emacs. ScreenUpdate() uses the *current* screen dimensions and
912 thus will happily use memory outside what was allocated for
913 `startup_screen_buffer'.
914 Thus we only restore as much as the current screen dimensions
915 can hold, and clear the rest (if the saved screen is smaller than
916 the current) with the color attribute saved at startup. The cursor
917 is also restored within the visible dimensions. */
918
919 ScreenAttrib = startup_screen_attrib;
920 ScreenClear ();
921
922 if (update_row_len > saved_row_len)
923 update_row_len = saved_row_len;
924 if (current_rows > startup_screen_size_Y)
925 current_rows = startup_screen_size_Y;
926
927 if (termscript)
928 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
929 update_row_len / 2, current_rows);
930
931 while (current_rows--)
932 {
933 dosmemput (saved_row, update_row_len, display_row_start);
934 saved_row += saved_row_len;
935 display_row_start += to_next_row;
936 }
937 if (startup_pos_X < cursor_pos_X)
938 cursor_pos_X = startup_pos_X;
939 if (startup_pos_Y < cursor_pos_Y)
940 cursor_pos_Y = startup_pos_Y;
941
942 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
943 xfree (startup_screen_buffer);
944
945 term_setup_done = 0;
946 }
947
948 static
949 IT_set_terminal_window (void)
950 {
951 }
952
953 void
954 IT_set_frame_parameters (f, alist)
955 FRAME_PTR f;
956 Lisp_Object alist;
957 {
958 Lisp_Object tail;
959 int length = XINT (Flength (alist));
960 int i;
961 Lisp_Object *parms
962 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
963 Lisp_Object *values
964 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
965 int redraw;
966 extern unsigned long load_color ();
967
968 redraw = 0;
969
970 /* Extract parm names and values into those vectors. */
971 i = 0;
972 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
973 {
974 Lisp_Object elt;
975
976 elt = Fcar (tail);
977 parms[i] = Fcar (elt);
978 CHECK_SYMBOL (parms[i], 1);
979 values[i] = Fcdr (elt);
980 i++;
981 }
982
983
984 /* Now process them in reverse of specified order. */
985 for (i--; i >= 0; i--)
986 {
987 Lisp_Object prop = parms[i];
988 Lisp_Object val = values[i];
989
990 if (EQ (prop, intern ("foreground-color")))
991 {
992 unsigned long new_color = load_color (f, val);
993 if (new_color != ~0)
994 {
995 FRAME_FOREGROUND_PIXEL (f) = new_color;
996 redraw = 1;
997 if (termscript)
998 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
999 }
1000 }
1001 else if (EQ (prop, intern ("background-color")))
1002 {
1003 unsigned long new_color = load_color (f, val);
1004 if (new_color != ~0)
1005 {
1006 FRAME_BACKGROUND_PIXEL (f) = new_color;
1007 redraw = 1;
1008 if (termscript)
1009 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
1010 }
1011 }
1012 else if (EQ (prop, intern ("menu-bar-lines")))
1013 x_set_menu_bar_lines (f, val, 0);
1014
1015 store_frame_param (f, prop, val);
1016
1017 }
1018
1019 if (redraw)
1020 {
1021 extern void recompute_basic_faces (FRAME_PTR);
1022 extern void redraw_frame (FRAME_PTR);
1023
1024 recompute_basic_faces (f);
1025 if (f == selected_frame)
1026 redraw_frame (f);
1027 }
1028 }
1029
1030 extern void init_frame_faces (FRAME_PTR);
1031
1032 #endif /* !HAVE_X_WINDOWS */
1033
1034
1035 /* Do we need the internal terminal? */
1036
1037 void
1038 internal_terminal_init ()
1039 {
1040 char *term = getenv ("TERM");
1041 char *colors;
1042
1043 #ifdef HAVE_X_WINDOWS
1044 if (!inhibit_window_system)
1045 return;
1046 #endif
1047
1048 internal_terminal
1049 = (!noninteractive) && term && !strcmp (term, "internal");
1050
1051 if (getenv ("EMACSTEST"))
1052 termscript = fopen (getenv ("EMACSTEST"), "wt");
1053
1054 #ifndef HAVE_X_WINDOWS
1055 if (!internal_terminal || inhibit_window_system)
1056 {
1057 selected_frame->output_method = output_termcap;
1058 return;
1059 }
1060
1061 Vwindow_system = intern ("pc");
1062 Vwindow_system_version = make_number (1);
1063
1064 bzero (&the_only_x_display, sizeof the_only_x_display);
1065 the_only_x_display.background_pixel = 7; /* White */
1066 the_only_x_display.foreground_pixel = 0; /* Black */
1067 bright_bg ();
1068 colors = getenv ("EMACSCOLORS");
1069 if (colors && strlen (colors) >= 2)
1070 {
1071 /* The colors use 4 bits each (we enable bright background). */
1072 if (isdigit (colors[0]))
1073 colors[0] -= '0';
1074 else if (isxdigit (colors[0]))
1075 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1076 if (colors[0] >= 0 && colors[0] < 16)
1077 the_only_x_display.foreground_pixel = colors[0];
1078 if (isdigit (colors[1]))
1079 colors[1] -= '0';
1080 else if (isxdigit (colors[1]))
1081 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1082 if (colors[1] >= 0 && colors[1] < 16)
1083 the_only_x_display.background_pixel = colors[1];
1084 }
1085 the_only_x_display.line_height = 1;
1086 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1087
1088 init_frame_faces (selected_frame);
1089
1090 ring_bell_hook = IT_ring_bell;
1091 write_glyphs_hook = IT_write_glyphs;
1092 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1093 clear_to_end_hook = IT_clear_to_end;
1094 clear_end_of_line_hook = IT_clear_end_of_line;
1095 clear_frame_hook = IT_clear_screen;
1096 change_line_highlight_hook = IT_change_line_highlight;
1097 update_begin_hook = IT_update_begin;
1098 update_end_hook = IT_update_end;
1099 reassert_line_highlight_hook = IT_reassert_line_highlight;
1100 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1101
1102 /* These hooks are called by term.c without being checked. */
1103 set_terminal_modes_hook = IT_set_terminal_modes;
1104 reset_terminal_modes_hook = IT_reset_terminal_modes;
1105 set_terminal_window_hook = IT_set_terminal_window;
1106 #endif
1107 }
1108
1109 dos_get_saved_screen (screen, rows, cols)
1110 char **screen;
1111 int *rows;
1112 int *cols;
1113 {
1114 #ifndef HAVE_X_WINDOWS
1115 *screen = startup_screen_buffer;
1116 *cols = startup_screen_size_X;
1117 *rows = startup_screen_size_Y;
1118 return 1;
1119 #else
1120 return 0;
1121 #endif
1122 }
1123
1124 #ifndef HAVE_X_WINDOWS
1125
1126 /* We are not X, but we can emulate it well enough for our needs... */
1127 void
1128 check_x (void)
1129 {
1130 if (! FRAME_MSDOS_P (selected_frame))
1131 error ("Not running under a windows system");
1132 }
1133
1134 #endif
1135
1136 \f
1137 /* ----------------------- Keyboard control ----------------------
1138 *
1139 * Keymaps reflect the following keyboard layout:
1140 *
1141 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1142 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1143 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1144 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1145 * SPACE
1146 */
1147
1148 static int extended_kbd; /* 101 (102) keyboard present. */
1149
1150 struct dos_keyboard_map
1151 {
1152 char *unshifted;
1153 char *shifted;
1154 char *alt_gr;
1155 };
1156
1157
1158 static struct dos_keyboard_map us_keyboard = {
1159 /* 0 1 2 3 4 5 */
1160 /* 01234567890123456789012345678901234567890 12345678901234 */
1161 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1162 /* 0123456789012345678901234567890123456789 012345678901234 */
1163 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1164 0 /* no Alt-Gr key */
1165 };
1166
1167 static struct dos_keyboard_map fr_keyboard = {
1168 /* 0 1 2 3 4 5 */
1169 /* 012 3456789012345678901234567890123456789012345678901234 */
1170 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1171 /* 0123456789012345678901234567890123456789012345678901234 */
1172 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1173 /* 01234567 89012345678901234567890123456789012345678901234 */
1174 " ~#{[|`\\^@]} Ï "
1175 };
1176
1177 static struct dos_keyboard_map dk_keyboard = {
1178 /* 0 1 2 3 4 5 */
1179 /* 0123456789012345678901234567890123456789012345678901234 */
1180 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1181 /* 01 23456789012345678901234567890123456789012345678901234 */
1182 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1183 /* 0123456789012345678901234567890123456789012345678901234 */
1184 " @\9c$ {[]} | "
1185 };
1186
1187 static struct keyboard_layout_list
1188 {
1189 int country_code;
1190 struct dos_keyboard_map *keyboard_map;
1191 } keyboard_layout_list[] =
1192 {
1193 1, &us_keyboard,
1194 33, &fr_keyboard,
1195 45, &dk_keyboard
1196 };
1197
1198 static struct dos_keyboard_map *keyboard;
1199 static int keyboard_map_all;
1200 static int international_keyboard;
1201
1202 int
1203 dos_set_keyboard (code, always)
1204 int code;
1205 int always;
1206 {
1207 int i;
1208 union REGS regs;
1209
1210 /* See if Keyb.Com is installed (for international keyboard support). */
1211 regs.x.ax = 0xad80;
1212 int86 (0x2f, &regs, &regs);
1213 if (regs.h.al == 0xff)
1214 international_keyboard = 1;
1215
1216 /* Initialize to US settings, for countries that don't have their own. */
1217 keyboard = keyboard_layout_list[0].keyboard_map;
1218 keyboard_map_all = always;
1219 dos_keyboard_layout = 1;
1220
1221 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1222 if (code == keyboard_layout_list[i].country_code)
1223 {
1224 keyboard = keyboard_layout_list[i].keyboard_map;
1225 keyboard_map_all = always;
1226 dos_keyboard_layout = code;
1227 return 1;
1228 }
1229 return 0;
1230 }
1231 \f
1232 #define Ignore 0x0000
1233 #define Normal 0x0000 /* normal key - alt changes scan-code */
1234 #define FctKey 0x1000 /* func key if c == 0, else c */
1235 #define Special 0x2000 /* func key even if c != 0 */
1236 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1237 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1238 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1239 #define Grey 0x6000 /* Grey keypad key */
1240
1241 #define Alt 0x0100 /* alt scan-code */
1242 #define Ctrl 0x0200 /* ctrl scan-code */
1243 #define Shift 0x0400 /* shift scan-code */
1244
1245 static struct
1246 {
1247 unsigned char char_code; /* normal code */
1248 unsigned char meta_code; /* M- code */
1249 unsigned char keypad_code; /* keypad code */
1250 unsigned char editkey_code; /* edit key */
1251 } keypad_translate_map[] = {
1252 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1253 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1254 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1255 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1256 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1257 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1258 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1259 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1260 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1261 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1262 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1263 };
1264
1265 static struct
1266 {
1267 unsigned char char_code; /* normal code */
1268 unsigned char keypad_code; /* keypad code */
1269 } grey_key_translate_map[] = {
1270 '/', 0xaf, /* kp-decimal */
1271 '*', 0xaa, /* kp-multiply */
1272 '-', 0xad, /* kp-subtract */
1273 '+', 0xab, /* kp-add */
1274 '\r', 0x8d /* kp-enter */
1275 };
1276
1277 static unsigned short
1278 ibmpc_translate_map[] =
1279 {
1280 /* --------------- 00 to 0f --------------- */
1281 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1282 Alt | ModFct | 0x1b, /* Escape */
1283 Normal | 1, /* '1' */
1284 Normal | 2, /* '2' */
1285 Normal | 3, /* '3' */
1286 Normal | 4, /* '4' */
1287 Normal | 5, /* '5' */
1288 Normal | 6, /* '6' */
1289 Normal | 7, /* '7' */
1290 Normal | 8, /* '8' */
1291 Normal | 9, /* '9' */
1292 Normal | 10, /* '0' */
1293 Normal | 11, /* '-' */
1294 Normal | 12, /* '=' */
1295 Special | 0x08, /* Backspace */
1296 ModFct | 0x74, /* Tab/Backtab */
1297
1298 /* --------------- 10 to 1f --------------- */
1299 Map | 15, /* 'q' */
1300 Map | 16, /* 'w' */
1301 Map | 17, /* 'e' */
1302 Map | 18, /* 'r' */
1303 Map | 19, /* 't' */
1304 Map | 20, /* 'y' */
1305 Map | 21, /* 'u' */
1306 Map | 22, /* 'i' */
1307 Map | 23, /* 'o' */
1308 Map | 24, /* 'p' */
1309 Map | 25, /* '[' */
1310 Map | 26, /* ']' */
1311 ModFct | 0x0d, /* Return */
1312 Ignore, /* Ctrl */
1313 Map | 30, /* 'a' */
1314 Map | 31, /* 's' */
1315
1316 /* --------------- 20 to 2f --------------- */
1317 Map | 32, /* 'd' */
1318 Map | 33, /* 'f' */
1319 Map | 34, /* 'g' */
1320 Map | 35, /* 'h' */
1321 Map | 36, /* 'j' */
1322 Map | 37, /* 'k' */
1323 Map | 38, /* 'l' */
1324 Map | 39, /* ';' */
1325 Map | 40, /* '\'' */
1326 Map | 0, /* '`' */
1327 Ignore, /* Left shift */
1328 Map | 41, /* '\\' */
1329 Map | 45, /* 'z' */
1330 Map | 46, /* 'x' */
1331 Map | 47, /* 'c' */
1332 Map | 48, /* 'v' */
1333
1334 /* --------------- 30 to 3f --------------- */
1335 Map | 49, /* 'b' */
1336 Map | 50, /* 'n' */
1337 Map | 51, /* 'm' */
1338 Map | 52, /* ',' */
1339 Map | 53, /* '.' */
1340 Map | 54, /* '/' */
1341 Ignore, /* Right shift */
1342 Grey | 1, /* Grey * */
1343 Ignore, /* Alt */
1344 Normal | ' ', /* ' ' */
1345 Ignore, /* Caps Lock */
1346 FctKey | 0xbe, /* F1 */
1347 FctKey | 0xbf, /* F2 */
1348 FctKey | 0xc0, /* F3 */
1349 FctKey | 0xc1, /* F4 */
1350 FctKey | 0xc2, /* F5 */
1351
1352 /* --------------- 40 to 4f --------------- */
1353 FctKey | 0xc3, /* F6 */
1354 FctKey | 0xc4, /* F7 */
1355 FctKey | 0xc5, /* F8 */
1356 FctKey | 0xc6, /* F9 */
1357 FctKey | 0xc7, /* F10 */
1358 Ignore, /* Num Lock */
1359 Ignore, /* Scroll Lock */
1360 KeyPad | 7, /* Home */
1361 KeyPad | 8, /* Up */
1362 KeyPad | 9, /* Page Up */
1363 Grey | 2, /* Grey - */
1364 KeyPad | 4, /* Left */
1365 KeyPad | 5, /* Keypad 5 */
1366 KeyPad | 6, /* Right */
1367 Grey | 3, /* Grey + */
1368 KeyPad | 1, /* End */
1369
1370 /* --------------- 50 to 5f --------------- */
1371 KeyPad | 2, /* Down */
1372 KeyPad | 3, /* Page Down */
1373 KeyPad | 0, /* Insert */
1374 KeyPad | 10, /* Delete */
1375 Shift | FctKey | 0xbe, /* (Shift) F1 */
1376 Shift | FctKey | 0xbf, /* (Shift) F2 */
1377 Shift | FctKey | 0xc0, /* (Shift) F3 */
1378 Shift | FctKey | 0xc1, /* (Shift) F4 */
1379 Shift | FctKey | 0xc2, /* (Shift) F5 */
1380 Shift | FctKey | 0xc3, /* (Shift) F6 */
1381 Shift | FctKey | 0xc4, /* (Shift) F7 */
1382 Shift | FctKey | 0xc5, /* (Shift) F8 */
1383 Shift | FctKey | 0xc6, /* (Shift) F9 */
1384 Shift | FctKey | 0xc7, /* (Shift) F10 */
1385 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1386 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1387
1388 /* --------------- 60 to 6f --------------- */
1389 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1390 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1391 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1392 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1393 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1394 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1395 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1396 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1397 Alt | FctKey | 0xbe, /* (Alt) F1 */
1398 Alt | FctKey | 0xbf, /* (Alt) F2 */
1399 Alt | FctKey | 0xc0, /* (Alt) F3 */
1400 Alt | FctKey | 0xc1, /* (Alt) F4 */
1401 Alt | FctKey | 0xc2, /* (Alt) F5 */
1402 Alt | FctKey | 0xc3, /* (Alt) F6 */
1403 Alt | FctKey | 0xc4, /* (Alt) F7 */
1404 Alt | FctKey | 0xc5, /* (Alt) F8 */
1405
1406 /* --------------- 70 to 7f --------------- */
1407 Alt | FctKey | 0xc6, /* (Alt) F9 */
1408 Alt | FctKey | 0xc7, /* (Alt) F10 */
1409 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1410 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1411 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1412 Ctrl | KeyPad | 1, /* (Ctrl) End */
1413 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1414 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1415 Alt | Map | 1, /* '1' */
1416 Alt | Map | 2, /* '2' */
1417 Alt | Map | 3, /* '3' */
1418 Alt | Map | 4, /* '4' */
1419 Alt | Map | 5, /* '5' */
1420 Alt | Map | 6, /* '6' */
1421 Alt | Map | 7, /* '7' */
1422 Alt | Map | 8, /* '8' */
1423
1424 /* --------------- 80 to 8f --------------- */
1425 Alt | Map | 9, /* '9' */
1426 Alt | Map | 10, /* '0' */
1427 Alt | Map | 11, /* '-' */
1428 Alt | Map | 12, /* '=' */
1429 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1430 FctKey | 0xc8, /* F11 */
1431 FctKey | 0xc9, /* F12 */
1432 Shift | FctKey | 0xc8, /* (Shift) F11 */
1433 Shift | FctKey | 0xc9, /* (Shift) F12 */
1434 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1435 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1436 Alt | FctKey | 0xc8, /* (Alt) F11 */
1437 Alt | FctKey | 0xc9, /* (Alt) F12 */
1438 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1439 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1440 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1441
1442 /* --------------- 90 to 9f --------------- */
1443 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1444 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1445 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1446 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1447 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1448 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1449 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1450 Alt | FctKey | 0x50, /* (Alt) Home */
1451 Alt | FctKey | 0x52, /* (Alt) Up */
1452 Alt | FctKey | 0x55, /* (Alt) Page Up */
1453 Ignore, /* NO KEY */
1454 Alt | FctKey | 0x51, /* (Alt) Left */
1455 Ignore, /* NO KEY */
1456 Alt | FctKey | 0x53, /* (Alt) Right */
1457 Ignore, /* NO KEY */
1458 Alt | FctKey | 0x57, /* (Alt) End */
1459
1460 /* --------------- a0 to af --------------- */
1461 Alt | KeyPad | 2, /* (Alt) Down */
1462 Alt | KeyPad | 3, /* (Alt) Page Down */
1463 Alt | KeyPad | 0, /* (Alt) Insert */
1464 Alt | KeyPad | 10, /* (Alt) Delete */
1465 Alt | Grey | 0, /* (Alt) Grey / */
1466 Alt | FctKey | 0x09, /* (Alt) Tab */
1467 Alt | Grey | 4 /* (Alt) Keypad Enter */
1468 };
1469 \f
1470 /* These bit-positions corresponds to values returned by BIOS */
1471 #define SHIFT_P 0x0003 /* two bits! */
1472 #define CTRL_P 0x0004
1473 #define ALT_P 0x0008
1474 #define SCRLOCK_P 0x0010
1475 #define NUMLOCK_P 0x0020
1476 #define CAPSLOCK_P 0x0040
1477 #define ALT_GR_P 0x0800
1478 #define SUPER_P 0x4000 /* pseudo */
1479 #define HYPER_P 0x8000 /* pseudo */
1480
1481 static int
1482 dos_get_modifiers (keymask)
1483 int *keymask;
1484 {
1485 union REGS regs;
1486 int mask;
1487 int modifiers = 0;
1488
1489 /* Calculate modifier bits */
1490 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1491 int86 (0x16, &regs, &regs);
1492
1493 if (!extended_kbd)
1494 {
1495 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1496 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1497 }
1498 else
1499 {
1500 mask = regs.h.al & (SHIFT_P |
1501 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1502
1503 /* Do not break international keyboard support. */
1504 /* When Keyb.Com is loaded, the right Alt key is */
1505 /* used for accessing characters like { and } */
1506 if (regs.h.ah & 2) /* Left ALT pressed ? */
1507 mask |= ALT_P;
1508
1509 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1510 {
1511 mask |= ALT_GR_P;
1512 if (dos_hyper_key == 1)
1513 {
1514 mask |= HYPER_P;
1515 modifiers |= hyper_modifier;
1516 }
1517 else if (dos_super_key == 1)
1518 {
1519 mask |= SUPER_P;
1520 modifiers |= super_modifier;
1521 }
1522 else if (!international_keyboard)
1523 {
1524 /* If Keyb.Com is NOT installed, let Right Alt behave
1525 like the Left Alt. */
1526 mask &= ~ALT_GR_P;
1527 mask |= ALT_P;
1528 }
1529 }
1530
1531 if (regs.h.ah & 1) /* Left CTRL pressed ? */
1532 mask |= CTRL_P;
1533
1534 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1535 {
1536 if (dos_hyper_key == 2)
1537 {
1538 mask |= HYPER_P;
1539 modifiers |= hyper_modifier;
1540 }
1541 else if (dos_super_key == 2)
1542 {
1543 mask |= SUPER_P;
1544 modifiers |= super_modifier;
1545 }
1546 else
1547 mask |= CTRL_P;
1548 }
1549 }
1550
1551 if (mask & SHIFT_P)
1552 modifiers |= shift_modifier;
1553 if (mask & CTRL_P)
1554 modifiers |= ctrl_modifier;
1555 if (mask & ALT_P)
1556 modifiers |= meta_modifier;
1557
1558 if (keymask)
1559 *keymask = mask;
1560 return modifiers;
1561 }
1562
1563 #define NUM_RECENT_DOSKEYS (100)
1564 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1565 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1566 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1567
1568 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1569 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1570 Each input key receives two values in this vector: first the ASCII code,\n\
1571 and then the scan code.")
1572 ()
1573 {
1574 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1575 Lisp_Object val;
1576
1577 if (total_doskeys < NUM_RECENT_DOSKEYS)
1578 return Fvector (total_doskeys, keys);
1579 else
1580 {
1581 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1582 bcopy (keys + recent_doskeys_index,
1583 XVECTOR (val)->contents,
1584 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1585 bcopy (keys,
1586 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1587 recent_doskeys_index * sizeof (Lisp_Object));
1588 return val;
1589 }
1590 }
1591
1592 /* Get a char from keyboard. Function keys are put into the event queue. */
1593
1594 extern void kbd_buffer_store_event (struct input_event *);
1595
1596 static int
1597 dos_rawgetc ()
1598 {
1599 struct input_event event;
1600 union REGS regs;
1601
1602 #ifndef HAVE_X_WINDOWS
1603 /* Maybe put the cursor where it should be. */
1604 IT_cmgoto (selected_frame);
1605 #endif
1606
1607 /* The following condition is equivalent to `kbhit ()', except that
1608 it uses the bios to do its job. This pleases DESQview/X. */
1609 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1610 int86 (0x16, &regs, &regs),
1611 (regs.x.flags & 0x40) == 0)
1612 {
1613 union REGS regs;
1614 register unsigned char c;
1615 int sc, code, mask, kp_mode;
1616 int modifiers;
1617
1618 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1619 int86 (0x16, &regs, &regs);
1620 c = regs.h.al;
1621 sc = regs.h.ah;
1622
1623 total_doskeys += 2;
1624 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1625 = make_number (c);
1626 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1627 recent_doskeys_index = 0;
1628 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1629 = make_number (sc);
1630 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1631 recent_doskeys_index = 0;
1632
1633 modifiers = dos_get_modifiers (&mask);
1634
1635 #ifndef HAVE_X_WINDOWS
1636 if (!NILP (Vdos_display_scancodes))
1637 {
1638 char buf[11];
1639 sprintf (buf, "%02x:%02x*%04x",
1640 (unsigned) (sc&0xff), (unsigned) c, mask);
1641 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1642 }
1643 #endif
1644
1645 if (sc == 0xe0)
1646 {
1647 switch (c)
1648 {
1649 case 10: /* Ctrl Grey Enter */
1650 code = Ctrl | Grey | 4;
1651 break;
1652 case 13: /* Grey Enter */
1653 code = Grey | 4;
1654 break;
1655 case '/': /* Grey / */
1656 code = Grey | 0;
1657 break;
1658 default:
1659 continue;
1660 };
1661 c = 0;
1662 }
1663 else
1664 {
1665 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1666 continue;
1667 if ((code = ibmpc_translate_map[sc]) == Ignore)
1668 continue;
1669 }
1670
1671 if (c == 0)
1672 {
1673 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1674 Emacs is ready to read a key. Therefore, if they press
1675 `Alt-x' when Emacs is busy, by the time we get to
1676 `dos_get_modifiers', they might have already released the
1677 Alt key, and Emacs gets just `x', which is BAD.
1678 However, for keys with the `Map' property set, the ASCII
1679 code returns zero iff Alt is pressed. So, when we DON'T
1680 have to support international_keyboard, we don't have to
1681 distinguish between the left and right Alt keys, and we
1682 can set the META modifier for any keys with the `Map'
1683 property if they return zero ASCII code (c = 0). */
1684 if ( (code & Alt)
1685 || ( (code & 0xf000) == Map && !international_keyboard))
1686 modifiers |= meta_modifier;
1687 if (code & Ctrl)
1688 modifiers |= ctrl_modifier;
1689 if (code & Shift)
1690 modifiers |= shift_modifier;
1691 }
1692
1693 switch (code & 0xf000)
1694 {
1695 case ModFct:
1696 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1697 return c;
1698 c = 0; /* Special */
1699
1700 case FctKey:
1701 if (c != 0)
1702 return c;
1703
1704 case Special:
1705 code |= 0xff00;
1706 break;
1707
1708 case Normal:
1709 if (sc == 0)
1710 {
1711 if (c == 0) /* ctrl-break */
1712 continue;
1713 return c; /* ALT-nnn */
1714 }
1715 if (!keyboard_map_all)
1716 {
1717 if (c != ' ')
1718 return c;
1719 code = c;
1720 break;
1721 }
1722
1723 case Map:
1724 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1725 if (!keyboard_map_all)
1726 return c;
1727
1728 code &= 0xff;
1729 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1730 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1731
1732 if (mask & SHIFT_P)
1733 {
1734 code = keyboard->shifted[code];
1735 mask -= SHIFT_P;
1736 modifiers &= ~shift_modifier;
1737 }
1738 else
1739 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1740 code = keyboard->alt_gr[code];
1741 else
1742 code = keyboard->unshifted[code];
1743 break;
1744
1745 case KeyPad:
1746 code &= 0xff;
1747 if (c == 0xe0) /* edit key */
1748 kp_mode = 3;
1749 else
1750 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1751 kp_mode = dos_keypad_mode & 0x03;
1752 else
1753 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1754
1755 switch (kp_mode)
1756 {
1757 case 0:
1758 if (code == 10 && dos_decimal_point)
1759 return dos_decimal_point;
1760 return keypad_translate_map[code].char_code;
1761
1762 case 1:
1763 code = 0xff00 | keypad_translate_map[code].keypad_code;
1764 break;
1765
1766 case 2:
1767 code = keypad_translate_map[code].meta_code;
1768 modifiers = meta_modifier;
1769 break;
1770
1771 case 3:
1772 code = 0xff00 | keypad_translate_map[code].editkey_code;
1773 break;
1774 }
1775 break;
1776
1777 case Grey:
1778 code &= 0xff;
1779 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1780 if (dos_keypad_mode & kp_mode)
1781 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1782 else
1783 code = grey_key_translate_map[code].char_code;
1784 break;
1785 }
1786
1787 make_event:
1788 if (code == 0)
1789 continue;
1790
1791 if (code >= 0x100)
1792 event.kind = non_ascii_keystroke;
1793 else
1794 event.kind = ascii_keystroke;
1795 event.code = code;
1796 event.modifiers = modifiers;
1797 XSETFRAME (event.frame_or_window, selected_frame);
1798 event.timestamp = event_timestamp ();
1799 kbd_buffer_store_event (&event);
1800 }
1801
1802 if (have_mouse > 0)
1803 {
1804 int but, press, x, y, ok;
1805
1806 /* Check for mouse movement *before* buttons. */
1807 mouse_check_moved ();
1808
1809 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1810 for (press = 0; press < 2; press++)
1811 {
1812 int button_num = but;
1813
1814 if (press)
1815 ok = mouse_pressed (but, &x, &y);
1816 else
1817 ok = mouse_released (but, &x, &y);
1818 if (ok)
1819 {
1820 /* Allow a simultaneous press/release of Mouse-1 and
1821 Mouse-2 to simulate Mouse-3 on two-button mice. */
1822 if (mouse_button_count == 2 && but < 2)
1823 {
1824 int x2, y2; /* don't clobber original coordinates */
1825
1826 /* If only one button is pressed, wait 100 msec and
1827 check again. This way, Speedy Gonzales isn't
1828 punished, while the slow get their chance. */
1829 if (press && mouse_pressed (1-but, &x2, &y2)
1830 || !press && mouse_released (1-but, &x2, &y2))
1831 button_num = 2;
1832 else
1833 {
1834 delay (100);
1835 if (press && mouse_pressed (1-but, &x2, &y2)
1836 || !press && mouse_released (1-but, &x2, &y2))
1837 button_num = 2;
1838 }
1839 }
1840
1841 event.kind = mouse_click;
1842 event.code = button_num;
1843 event.modifiers = dos_get_modifiers (0)
1844 | (press ? down_modifier : up_modifier);
1845 event.x = x;
1846 event.y = y;
1847 XSETFRAME (event.frame_or_window, selected_frame);
1848 event.timestamp = event_timestamp ();
1849 kbd_buffer_store_event (&event);
1850 }
1851 }
1852 }
1853
1854 return -1;
1855 }
1856
1857 static int prev_get_char = -1;
1858
1859 /* Return 1 if a key is ready to be read without suspending execution. */
1860
1861 dos_keysns ()
1862 {
1863 if (prev_get_char != -1)
1864 return 1;
1865 else
1866 return ((prev_get_char = dos_rawgetc ()) != -1);
1867 }
1868
1869 /* Read a key. Return -1 if no key is ready. */
1870
1871 dos_keyread ()
1872 {
1873 if (prev_get_char != -1)
1874 {
1875 int c = prev_get_char;
1876 prev_get_char = -1;
1877 return c;
1878 }
1879 else
1880 return dos_rawgetc ();
1881 }
1882 \f
1883 #ifndef HAVE_X_WINDOWS
1884 /* See xterm.c for more info. */
1885 void
1886 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1887 FRAME_PTR f;
1888 register int pix_x, pix_y;
1889 register int *x, *y;
1890 void /* XRectangle */ *bounds;
1891 int noclip;
1892 {
1893 if (bounds) abort ();
1894
1895 /* Ignore clipping. */
1896
1897 *x = pix_x;
1898 *y = pix_y;
1899 }
1900
1901 void
1902 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1903 FRAME_PTR f;
1904 register int x, y;
1905 register int *pix_x, *pix_y;
1906 {
1907 *pix_x = x;
1908 *pix_y = y;
1909 }
1910 \f
1911 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1912 for now.
1913
1914 Actually, I don't know the meaning of all the parameters of the functions
1915 here -- I only know how they are called by xmenu.c. I could of course
1916 grab the nearest Xlib manual (down the hall, second-to-last door on the
1917 left), but I don't think it's worth the effort. */
1918
1919 static XMenu *
1920 IT_menu_create ()
1921 {
1922 XMenu *menu;
1923
1924 menu = (XMenu *) xmalloc (sizeof (XMenu));
1925 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1926 return menu;
1927 }
1928
1929 /* Allocate some (more) memory for MENU ensuring that there is room for one
1930 for item. */
1931
1932 static void
1933 IT_menu_make_room (XMenu *menu)
1934 {
1935 if (menu->allocated == 0)
1936 {
1937 int count = menu->allocated = 10;
1938 menu->text = (char **) xmalloc (count * sizeof (char *));
1939 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1940 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1941 }
1942 else if (menu->allocated == menu->count)
1943 {
1944 int count = menu->allocated = menu->allocated + 10;
1945 menu->text
1946 = (char **) xrealloc (menu->text, count * sizeof (char *));
1947 menu->submenu
1948 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1949 menu->panenumber
1950 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1951 }
1952 }
1953
1954 /* Search the given menu structure for a given pane number. */
1955
1956 static XMenu *
1957 IT_menu_search_pane (XMenu *menu, int pane)
1958 {
1959 int i;
1960 XMenu *try;
1961
1962 for (i = 0; i < menu->count; i++)
1963 if (menu->submenu[i])
1964 {
1965 if (pane == menu->panenumber[i])
1966 return menu->submenu[i];
1967 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1968 return try;
1969 }
1970 return (XMenu *) 0;
1971 }
1972
1973 /* Determine how much screen space a given menu needs. */
1974
1975 static void
1976 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1977 {
1978 int i, h2, w2, maxsubwidth, maxheight;
1979
1980 maxsubwidth = 0;
1981 maxheight = menu->count;
1982 for (i = 0; i < menu->count; i++)
1983 {
1984 if (menu->submenu[i])
1985 {
1986 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1987 if (w2 > maxsubwidth) maxsubwidth = w2;
1988 if (i + h2 > maxheight) maxheight = i + h2;
1989 }
1990 }
1991 *width = menu->width + maxsubwidth;
1992 *height = maxheight;
1993 }
1994
1995 /* Display MENU at (X,Y) using FACES. */
1996
1997 static void
1998 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1999 {
2000 int i, j, face, width;
2001 GLYPH *text, *p;
2002 char *q;
2003 int mx, my;
2004 int enabled, mousehere;
2005 int row, col;
2006
2007 width = menu->width;
2008 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
2009 ScreenGetCursor (&row, &col);
2010 mouse_get_xy (&mx, &my);
2011 IT_update_begin ();
2012 for (i = 0; i < menu->count; i++)
2013 {
2014 IT_cursor_to (y + i, x);
2015 enabled
2016 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2017 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
2018 face = faces[enabled + mousehere * 2];
2019 p = text;
2020 *p++ = FAST_MAKE_GLYPH (' ', face);
2021 for (j = 0, q = menu->text[i]; *q; j++)
2022 {
2023 if (*q > 26)
2024 *p++ = FAST_MAKE_GLYPH (*q++, face);
2025 else /* make '^x' */
2026 {
2027 *p++ = FAST_MAKE_GLYPH ('^', face);
2028 j++;
2029 *p++ = FAST_MAKE_GLYPH (*q++ + 64, face);
2030 }
2031 }
2032
2033 for (; j < width; j++)
2034 *p++ = FAST_MAKE_GLYPH (' ', face);
2035 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
2036 IT_write_glyphs (text, width + 2);
2037 }
2038 IT_update_end ();
2039 IT_cursor_to (row, col);
2040 xfree (text);
2041 }
2042 \f
2043 /* --------------------------- X Menu emulation ---------------------- */
2044
2045 /* Report availability of menus. */
2046
2047 int
2048 have_menus_p ()
2049 {
2050 return 1;
2051 }
2052
2053 /* Create a brand new menu structure. */
2054
2055 XMenu *
2056 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2057 {
2058 return IT_menu_create ();
2059 }
2060
2061 /* Create a new pane and place it on the outer-most level. It is not
2062 clear that it should be placed out there, but I don't know what else
2063 to do. */
2064
2065 int
2066 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
2067 {
2068 int len;
2069 char *p;
2070
2071 if (!enable)
2072 abort ();
2073
2074 IT_menu_make_room (menu);
2075 menu->submenu[menu->count] = IT_menu_create ();
2076 menu->text[menu->count] = txt;
2077 menu->panenumber[menu->count] = ++menu->panecount;
2078 menu->count++;
2079
2080 /* Adjust length for possible control characters (which will
2081 be written as ^x). */
2082 for (len = strlen (txt), p = txt; *p; p++)
2083 if (*p < 27)
2084 len++;
2085
2086 if (len > menu->width)
2087 menu->width = len;
2088
2089 return menu->panecount;
2090 }
2091
2092 /* Create a new item in a menu pane. */
2093
2094 int
2095 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
2096 int foo, char *txt, int enable)
2097 {
2098 int len;
2099 char *p;
2100
2101 if (pane)
2102 if (!(menu = IT_menu_search_pane (menu, pane)))
2103 return XM_FAILURE;
2104 IT_menu_make_room (menu);
2105 menu->submenu[menu->count] = (XMenu *) 0;
2106 menu->text[menu->count] = txt;
2107 menu->panenumber[menu->count] = enable;
2108 menu->count++;
2109
2110 /* Adjust length for possible control characters (which will
2111 be written as ^x). */
2112 for (len = strlen (txt), p = txt; *p; p++)
2113 if (*p < 27)
2114 len++;
2115
2116 if (len > menu->width)
2117 menu->width = len;
2118
2119 return XM_SUCCESS;
2120 }
2121
2122 /* Decide where the menu would be placed if requested at (X,Y). */
2123
2124 void
2125 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
2126 int *ulx, int *uly, int *width, int *height)
2127 {
2128 IT_menu_calc_size (menu, width, height);
2129 *ulx = x + 1;
2130 *uly = y;
2131 *width += 2;
2132 }
2133
2134 struct IT_menu_state
2135 {
2136 void *screen_behind;
2137 XMenu *menu;
2138 int pane;
2139 int x, y;
2140 };
2141
2142
2143 /* Display menu, wait for user's response, and return that response. */
2144
2145 int
2146 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
2147 int x0, int y0, unsigned ButtonMask, char **txt)
2148 {
2149 struct IT_menu_state *state;
2150 int statecount;
2151 int x, y, i, b;
2152 int screensize;
2153 int faces[4], selectface;
2154 int leave, result, onepane;
2155 int title_faces[4]; /* face to display the menu title */
2156 int buffers_num_deleted = 0;
2157
2158 /* Just in case we got here without a mouse present... */
2159 if (have_mouse <= 0)
2160 return XM_IA_SELECT;
2161 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2162 around the display. */
2163 if (x0 <= 0)
2164 x0 = 1;
2165 if (y0 <= 0)
2166 y0 = 1;
2167
2168 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
2169 screensize = screen_size * 2;
2170 faces[0]
2171 = compute_glyph_face (selected_frame,
2172 face_name_id_number
2173 (selected_frame,
2174 intern ("msdos-menu-passive-face")),
2175 0);
2176 faces[1]
2177 = compute_glyph_face (selected_frame,
2178 face_name_id_number
2179 (selected_frame,
2180 intern ("msdos-menu-active-face")),
2181 0);
2182 selectface
2183 = face_name_id_number (selected_frame, intern ("msdos-menu-select-face"));
2184 faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]);
2185 faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]);
2186
2187 /* Make sure the menu title is always displayed with
2188 `msdos-menu-active-face', no matter where the mouse pointer is. */
2189 for (i = 0; i < 4; i++)
2190 title_faces[i] = faces[3];
2191
2192 statecount = 1;
2193
2194 /* Don't let the title for the "Buffers" popup menu include a
2195 digit (which is ugly).
2196
2197 This is a terrible kludge, but I think the "Buffers" case is
2198 the only one where the title includes a number, so it doesn't
2199 seem to be necessary to make this more general. */
2200 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2201 {
2202 menu->text[0][7] = '\0';
2203 buffers_num_deleted = 1;
2204 }
2205 state[0].menu = menu;
2206 mouse_off ();
2207 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2208
2209 /* Turn off the cursor. Otherwise it shows through the menu
2210 panes, which is ugly. */
2211 IT_display_cursor (0);
2212
2213 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2214 if (buffers_num_deleted)
2215 menu->text[0][7] = ' ';
2216 if ((onepane = menu->count == 1 && menu->submenu[0]))
2217 {
2218 menu->width = menu->submenu[0]->width;
2219 state[0].menu = menu->submenu[0];
2220 }
2221 else
2222 {
2223 state[0].menu = menu;
2224 }
2225 state[0].x = x0 - 1;
2226 state[0].y = y0;
2227 state[0].pane = onepane;
2228
2229 mouse_last_x = -1; /* A hack that forces display. */
2230 leave = 0;
2231 while (!leave)
2232 {
2233 if (!mouse_visible) mouse_on ();
2234 mouse_check_moved ();
2235 if (selected_frame->mouse_moved)
2236 {
2237 selected_frame->mouse_moved = 0;
2238 result = XM_IA_SELECT;
2239 mouse_get_xy (&x, &y);
2240 for (i = 0; i < statecount; i++)
2241 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2242 {
2243 int dy = y - state[i].y;
2244 if (0 <= dy && dy < state[i].menu->count)
2245 {
2246 if (!state[i].menu->submenu[dy])
2247 if (state[i].menu->panenumber[dy])
2248 result = XM_SUCCESS;
2249 else
2250 result = XM_IA_SELECT;
2251 *pane = state[i].pane - 1;
2252 *selidx = dy;
2253 /* We hit some part of a menu, so drop extra menus that
2254 have been opened. That does not include an open and
2255 active submenu. */
2256 if (i != statecount - 2
2257 || state[i].menu->submenu[dy] != state[i+1].menu)
2258 while (i != statecount - 1)
2259 {
2260 statecount--;
2261 mouse_off ();
2262 ScreenUpdate (state[statecount].screen_behind);
2263 xfree (state[statecount].screen_behind);
2264 }
2265 if (i == statecount - 1 && state[i].menu->submenu[dy])
2266 {
2267 IT_menu_display (state[i].menu,
2268 state[i].y,
2269 state[i].x,
2270 faces);
2271 state[statecount].menu = state[i].menu->submenu[dy];
2272 state[statecount].pane = state[i].menu->panenumber[dy];
2273 mouse_off ();
2274 ScreenRetrieve (state[statecount].screen_behind
2275 = xmalloc (screensize));
2276 state[statecount].x
2277 = state[i].x + state[i].menu->width + 2;
2278 state[statecount].y = y;
2279 statecount++;
2280 }
2281 }
2282 }
2283 IT_menu_display (state[statecount - 1].menu,
2284 state[statecount - 1].y,
2285 state[statecount - 1].x,
2286 faces);
2287 }
2288 for (b = 0; b < mouse_button_count; b++)
2289 {
2290 (void) mouse_pressed (b, &x, &y);
2291 if (mouse_released (b, &x, &y))
2292 leave = 1;
2293 }
2294 }
2295
2296 mouse_off ();
2297 ScreenUpdate (state[0].screen_behind);
2298 while (statecount--)
2299 xfree (state[statecount].screen_behind);
2300 IT_display_cursor (1); /* turn cursor back on */
2301 return result;
2302 }
2303
2304 /* Dispose of a menu. */
2305
2306 void
2307 XMenuDestroy (Display *foo, XMenu *menu)
2308 {
2309 int i;
2310 if (menu->allocated)
2311 {
2312 for (i = 0; i < menu->count; i++)
2313 if (menu->submenu[i])
2314 XMenuDestroy (foo, menu->submenu[i]);
2315 xfree (menu->text);
2316 xfree (menu->submenu);
2317 xfree (menu->panenumber);
2318 }
2319 xfree (menu);
2320 }
2321
2322 int
2323 x_pixel_width (struct frame *f)
2324 {
2325 return FRAME_WIDTH (f);
2326 }
2327
2328 int
2329 x_pixel_height (struct frame *f)
2330 {
2331 return FRAME_HEIGHT (f);
2332 }
2333 #endif /* !HAVE_X_WINDOWS */
2334 \f
2335 /* ----------------------- DOS / UNIX conversion --------------------- */
2336
2337 void msdos_downcase_filename (unsigned char *);
2338
2339 /* Destructively turn backslashes into slashes. */
2340
2341 void
2342 dostounix_filename (p)
2343 register char *p;
2344 {
2345 msdos_downcase_filename (p);
2346
2347 while (*p)
2348 {
2349 if (*p == '\\')
2350 *p = '/';
2351 p++;
2352 }
2353 }
2354
2355 /* Destructively turn slashes into backslashes. */
2356
2357 void
2358 unixtodos_filename (p)
2359 register char *p;
2360 {
2361 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2362 {
2363 *p += 'a' - 'A';
2364 p += 2;
2365 }
2366
2367 while (*p)
2368 {
2369 if (*p == '/')
2370 *p = '\\';
2371 p++;
2372 }
2373 }
2374
2375 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2376
2377 int
2378 getdefdir (drive, dst)
2379 int drive;
2380 char *dst;
2381 {
2382 char in_path[4], *p = in_path;
2383 int e = errno;
2384
2385 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2386 if (drive != 0)
2387 {
2388 *p++ = drive + 'A' - 1;
2389 *p++ = ':';
2390 }
2391
2392 *p++ = '.';
2393 *p = '\0';
2394 errno = 0;
2395 _fixpath (in_path, dst);
2396 if (errno)
2397 return 0;
2398
2399 msdos_downcase_filename (dst);
2400
2401 errno = e;
2402 return 1;
2403 }
2404
2405 /* Remove all CR's that are followed by a LF. */
2406
2407 int
2408 crlf_to_lf (n, buf)
2409 register int n;
2410 register unsigned char *buf;
2411 {
2412 unsigned char *np = buf;
2413 unsigned char *startp = buf;
2414 unsigned char *endp = buf + n;
2415
2416 if (n == 0)
2417 return n;
2418 while (buf < endp - 1)
2419 {
2420 if (*buf == 0x0d)
2421 {
2422 if (*(++buf) != 0x0a)
2423 *np++ = 0x0d;
2424 }
2425 else
2426 *np++ = *buf++;
2427 }
2428 if (buf < endp)
2429 *np++ = *buf++;
2430 return np - startp;
2431 }
2432
2433 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2434
2435 /* In DJGPP v2.0, library `write' can call `malloc', which might
2436 cause relocation of the buffer whose address we get in ADDR.
2437 Here is a version of `write' that avoids calling `malloc',
2438 to serve us until such time as the library is fixed.
2439 Actually, what we define here is called `__write', because
2440 `write' is a stub that just jmp's to `__write' (to be
2441 POSIXLY-correct with respect to the global name-space). */
2442
2443 #include <io.h> /* for _write */
2444 #include <libc/dosio.h> /* for __file_handle_modes[] */
2445
2446 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
2447
2448 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2449
2450 int
2451 __write (int handle, const void *buffer, size_t count)
2452 {
2453 if (count == 0)
2454 return 0;
2455
2456 if(__file_handle_modes[handle] & O_BINARY)
2457 return _write (handle, buffer, count);
2458 else
2459 {
2460 char *xbp = xbuf;
2461 const char *bp = buffer;
2462 int total_written = 0;
2463 int nmoved = 0, ncr = 0;
2464
2465 while (count)
2466 {
2467 /* The next test makes sure there's space for at least 2 more
2468 characters in xbuf[], so both CR and LF can be put there. */
2469 if (xbp < XBUF_END)
2470 {
2471 if (*bp == '\n')
2472 {
2473 ncr++;
2474 *xbp++ = '\r';
2475 }
2476 *xbp++ = *bp++;
2477 nmoved++;
2478 count--;
2479 }
2480 if (xbp >= XBUF_END || !count)
2481 {
2482 size_t to_write = nmoved + ncr;
2483 int written = _write (handle, xbuf, to_write);
2484
2485 if (written == -1)
2486 return -1;
2487 else
2488 total_written += nmoved; /* CRs aren't counted in ret value */
2489
2490 /* If some, but not all were written (disk full?), return
2491 an estimate of the total written bytes not counting CRs. */
2492 if (written < to_write)
2493 return total_written - (to_write - written) * nmoved/to_write;
2494
2495 nmoved = 0;
2496 ncr = 0;
2497 xbp = xbuf;
2498 }
2499 }
2500 return total_written;
2501 }
2502 }
2503
2504 /* A low-level file-renaming function which works around Windows 95 bug.
2505 This is pulled directly out of DJGPP v2.01 library sources, and only
2506 used when you compile with DJGPP v2.0. */
2507
2508 #include <io.h>
2509
2510 int _rename(const char *old, const char *new)
2511 {
2512 __dpmi_regs r;
2513 int olen = strlen(old) + 1;
2514 int i;
2515 int use_lfn = _USE_LFN;
2516 char tempfile[FILENAME_MAX];
2517 const char *orig = old;
2518 int lfn_fd = -1;
2519
2520 r.x.dx = __tb_offset;
2521 r.x.di = __tb_offset + olen;
2522 r.x.ds = r.x.es = __tb_segment;
2523
2524 if (use_lfn)
2525 {
2526 /* Windows 95 bug: for some filenames, when you rename
2527 file -> file~ (as in Emacs, to leave a backup), the
2528 short 8+3 alias doesn't change, which effectively
2529 makes OLD and NEW the same file. We must rename
2530 through a temporary file to work around this. */
2531
2532 char *pbase = 0, *p;
2533 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
2534 int idx = sizeof(try_char) - 1;
2535
2536 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2537 might point to another drive, which will fail the DOS call. */
2538 strcpy(tempfile, old);
2539 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
2540 if (*p == '/' || *p == '\\' || *p == ':')
2541 pbase = p;
2542 if (pbase)
2543 pbase++;
2544 else
2545 pbase = tempfile;
2546 strcpy(pbase, "X$$djren$$.$$temp$$");
2547
2548 do
2549 {
2550 if (idx <= 0)
2551 return -1;
2552 *pbase = try_char[--idx];
2553 } while (_chmod(tempfile, 0) != -1);
2554
2555 r.x.ax = 0x7156;
2556 _put_path2(tempfile, olen);
2557 _put_path(old);
2558 __dpmi_int(0x21, &r);
2559 if (r.x.flags & 1)
2560 {
2561 errno = __doserr_to_errno(r.x.ax);
2562 return -1;
2563 }
2564
2565 /* Now create a file with the original name. This will
2566 ensure that NEW will always have a 8+3 alias
2567 different from that of OLD. (Seems to be required
2568 when NameNumericTail in the Registry is set to 0.) */
2569 lfn_fd = _creat(old, 0);
2570
2571 olen = strlen(tempfile) + 1;
2572 old = tempfile;
2573 r.x.di = __tb_offset + olen;
2574 }
2575
2576 for (i=0; i<2; i++)
2577 {
2578 if(use_lfn)
2579 r.x.ax = 0x7156;
2580 else
2581 r.h.ah = 0x56;
2582 _put_path2(new, olen);
2583 _put_path(old);
2584 __dpmi_int(0x21, &r);
2585 if(r.x.flags & 1)
2586 {
2587 if (r.x.ax == 5 && i == 0) /* access denied */
2588 remove(new); /* and try again */
2589 else
2590 {
2591 errno = __doserr_to_errno(r.x.ax);
2592
2593 /* Restore to original name if we renamed it to temporary. */
2594 if (use_lfn)
2595 {
2596 if (lfn_fd != -1)
2597 {
2598 _close (lfn_fd);
2599 remove (orig);
2600 }
2601 _put_path2(orig, olen);
2602 _put_path(tempfile);
2603 r.x.ax = 0x7156;
2604 __dpmi_int(0x21, &r);
2605 }
2606 return -1;
2607 }
2608 }
2609 else
2610 break;
2611 }
2612
2613 /* Success. Delete the file possibly created to work
2614 around the Windows 95 bug. */
2615 if (lfn_fd != -1)
2616 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
2617 return 0;
2618 }
2619
2620 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2621
2622 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
2623 0, 0, 0,
2624 "Return non-nil if long file names are supported on MSDOS.")
2625 ()
2626 {
2627 return (_USE_LFN ? Qt : Qnil);
2628 }
2629
2630 /* Convert alphabetic characters in a filename to lower-case. */
2631
2632 void
2633 msdos_downcase_filename (p)
2634 register unsigned char *p;
2635 {
2636 /* Always lower-case drive letters a-z, even if the filesystem
2637 preserves case in filenames.
2638 This is so MSDOS filenames could be compared by string comparison
2639 functions that are case-sensitive. Even case-preserving filesystems
2640 do not distinguish case in drive letters. */
2641 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2642 {
2643 *p += 'a' - 'A';
2644 p += 2;
2645 }
2646
2647 /* Under LFN we expect to get pathnames in their true case. */
2648 if (NILP (Fmsdos_long_file_names ()))
2649 for ( ; *p; p++)
2650 if (*p >= 'A' && *p <= 'Z')
2651 *p += 'a' - 'A';
2652 }
2653
2654 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
2655 1, 1, 0,
2656 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2657 When long filenames are supported, doesn't change FILENAME.\n\
2658 If FILENAME is not a string, returns nil.\n\
2659 The argument object is never altered--the value is a copy.")
2660 (filename)
2661 Lisp_Object filename;
2662 {
2663 Lisp_Object tem;
2664
2665 if (! STRINGP (filename))
2666 return Qnil;
2667
2668 tem = Fcopy_sequence (filename);
2669 msdos_downcase_filename (XSTRING (tem)->data);
2670 return tem;
2671 }
2672 \f
2673 /* The Emacs root directory as determined by init_environment. */
2674
2675 static char emacsroot[MAXPATHLEN];
2676
2677 char *
2678 rootrelativepath (rel)
2679 char *rel;
2680 {
2681 static char result[MAXPATHLEN + 10];
2682
2683 strcpy (result, emacsroot);
2684 strcat (result, "/");
2685 strcat (result, rel);
2686 return result;
2687 }
2688
2689 /* Define a lot of environment variables if not already defined. Don't
2690 remove anything unless you know what you're doing -- lots of code will
2691 break if one or more of these are missing. */
2692
2693 void
2694 init_environment (argc, argv, skip_args)
2695 int argc;
2696 char **argv;
2697 int skip_args;
2698 {
2699 char *s, *t, *root;
2700 int len;
2701
2702 /* Find our root from argv[0]. Assuming argv[0] is, say,
2703 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2704 root = alloca (MAXPATHLEN + 20);
2705 _fixpath (argv[0], root);
2706 msdos_downcase_filename (root);
2707 len = strlen (root);
2708 while (len > 0 && root[len] != '/' && root[len] != ':')
2709 len--;
2710 root[len] = '\0';
2711 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
2712 root[len - 4] = '\0';
2713 else
2714 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
2715 len = strlen (root);
2716 strcpy (emacsroot, root);
2717
2718 /* We default HOME to our root. */
2719 setenv ("HOME", root, 0);
2720
2721 /* We default EMACSPATH to root + "/bin". */
2722 strcpy (root + len, "/bin");
2723 setenv ("EMACSPATH", root, 0);
2724
2725 /* I don't expect anybody to ever use other terminals so the internal
2726 terminal is the default. */
2727 setenv ("TERM", "internal", 0);
2728
2729 #ifdef HAVE_X_WINDOWS
2730 /* Emacs expects DISPLAY to be set. */
2731 setenv ("DISPLAY", "unix:0.0", 0);
2732 #endif
2733
2734 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2735 downcase it and mirror the backslashes. */
2736 s = getenv ("COMSPEC");
2737 if (!s) s = "c:/command.com";
2738 t = alloca (strlen (s) + 1);
2739 strcpy (t, s);
2740 dostounix_filename (t);
2741 setenv ("SHELL", t, 0);
2742
2743 /* PATH is also downcased and backslashes mirrored. */
2744 s = getenv ("PATH");
2745 if (!s) s = "";
2746 t = alloca (strlen (s) + 3);
2747 /* Current directory is always considered part of MsDos's path but it is
2748 not normally mentioned. Now it is. */
2749 strcat (strcpy (t, ".;"), s);
2750 dostounix_filename (t); /* Not a single file name, but this should work. */
2751 setenv ("PATH", t, 1);
2752
2753 /* In some sense all dos users have root privileges, so... */
2754 setenv ("USER", "root", 0);
2755 setenv ("NAME", getenv ("USER"), 0);
2756
2757 /* Time zone determined from country code. To make this possible, the
2758 country code may not span more than one time zone. In other words,
2759 in the USA, you lose. */
2760 if (!getenv ("TZ"))
2761 switch (dos_country_code)
2762 {
2763 case 31: /* Belgium */
2764 case 32: /* The Netherlands */
2765 case 33: /* France */
2766 case 34: /* Spain */
2767 case 36: /* Hungary */
2768 case 38: /* Yugoslavia (or what's left of it?) */
2769 case 39: /* Italy */
2770 case 41: /* Switzerland */
2771 case 42: /* Tjekia */
2772 case 45: /* Denmark */
2773 case 46: /* Sweden */
2774 case 47: /* Norway */
2775 case 48: /* Poland */
2776 case 49: /* Germany */
2777 /* Daylight saving from last Sunday in March to last Sunday in
2778 September, both at 2AM. */
2779 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2780 break;
2781 case 44: /* United Kingdom */
2782 case 351: /* Portugal */
2783 case 354: /* Iceland */
2784 setenv ("TZ", "GMT+00", 0);
2785 break;
2786 case 81: /* Japan */
2787 case 82: /* Korea */
2788 setenv ("TZ", "JST-09", 0);
2789 break;
2790 case 90: /* Turkey */
2791 case 358: /* Finland */
2792 setenv ("TZ", "EET-02", 0);
2793 break;
2794 case 972: /* Israel */
2795 /* This is an approximation. (For exact rules, use the
2796 `zoneinfo/israel' file which comes with DJGPP, but you need
2797 to install it in `/usr/share/zoneinfo/' directory first.) */
2798 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2799 break;
2800 }
2801 tzset ();
2802 }
2803
2804 \f
2805
2806 static int break_stat; /* BREAK check mode status. */
2807 static int stdin_stat; /* stdin IOCTL status. */
2808
2809 #if __DJGPP__ < 2
2810
2811 /* These must be global. */
2812 static _go32_dpmi_seginfo ctrl_break_vector;
2813 static _go32_dpmi_registers ctrl_break_regs;
2814 static int ctrlbreakinstalled = 0;
2815
2816 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2817
2818 void
2819 ctrl_break_func (regs)
2820 _go32_dpmi_registers *regs;
2821 {
2822 Vquit_flag = Qt;
2823 }
2824
2825 void
2826 install_ctrl_break_check ()
2827 {
2828 if (!ctrlbreakinstalled)
2829 {
2830 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2831 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2832 ctrlbreakinstalled = 1;
2833 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2834 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2835 &ctrl_break_regs);
2836 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2837 }
2838 }
2839
2840 #endif /* __DJGPP__ < 2 */
2841
2842 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2843 control chars by DOS. Determine the keyboard type. */
2844
2845 int
2846 dos_ttraw ()
2847 {
2848 union REGS inregs, outregs;
2849 static int first_time = 1;
2850
2851 break_stat = getcbrk ();
2852 setcbrk (0);
2853 #if __DJGPP__ < 2
2854 install_ctrl_break_check ();
2855 #endif
2856
2857 if (first_time)
2858 {
2859 inregs.h.ah = 0xc0;
2860 int86 (0x15, &inregs, &outregs);
2861 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2862
2863 have_mouse = 0;
2864
2865 if (internal_terminal
2866 #ifdef HAVE_X_WINDOWS
2867 && inhibit_window_system
2868 #endif
2869 )
2870 {
2871 inregs.x.ax = 0x0021;
2872 int86 (0x33, &inregs, &outregs);
2873 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2874 if (!have_mouse)
2875 {
2876 /* Reportedly, the above doesn't work for some mouse drivers. There
2877 is an additional detection method that should work, but might be
2878 a little slower. Use that as an alternative. */
2879 inregs.x.ax = 0x0000;
2880 int86 (0x33, &inregs, &outregs);
2881 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2882 }
2883
2884 if (have_mouse)
2885 {
2886 have_mouse = 1; /* enable mouse */
2887 mouse_visible = 0;
2888
2889 if (outregs.x.bx == 3)
2890 {
2891 mouse_button_count = 3;
2892 mouse_button_translate[0] = 0; /* Left */
2893 mouse_button_translate[1] = 2; /* Middle */
2894 mouse_button_translate[2] = 1; /* Right */
2895 }
2896 else
2897 {
2898 mouse_button_count = 2;
2899 mouse_button_translate[0] = 0;
2900 mouse_button_translate[1] = 1;
2901 }
2902 mouse_position_hook = &mouse_get_pos;
2903 mouse_init ();
2904 }
2905 }
2906
2907 first_time = 0;
2908
2909 #if __DJGPP__ >= 2
2910
2911 stdin_stat = setmode (fileno (stdin), O_BINARY);
2912 return (stdin_stat != -1);
2913 }
2914 else
2915 return (setmode (fileno (stdin), O_BINARY) != -1);
2916
2917 #else /* __DJGPP__ < 2 */
2918
2919 }
2920
2921 /* I think it is wrong to overwrite `stdin_stat' every time
2922 but the first one this function is called, but I don't
2923 want to change the way it used to work in v1.x.--EZ */
2924
2925 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2926 inregs.x.bx = 0x00; /* 0 = stdin. */
2927 intdos (&inregs, &outregs);
2928 stdin_stat = outregs.h.dl;
2929
2930 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2931 inregs.x.ax = 0x4401; /* Set IOCTL status */
2932 intdos (&inregs, &outregs);
2933 return !outregs.x.cflag;
2934
2935 #endif /* __DJGPP__ < 2 */
2936 }
2937
2938 /* Restore status of standard input and Ctrl-C checking. */
2939
2940 int
2941 dos_ttcooked ()
2942 {
2943 union REGS inregs, outregs;
2944
2945 setcbrk (break_stat);
2946 mouse_off ();
2947
2948 #if __DJGPP__ >= 2
2949
2950 return (setmode (fileno (stdin), stdin_stat) != -1);
2951
2952 #else /* not __DJGPP__ >= 2 */
2953
2954 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2955 inregs.x.bx = 0x00; /* 0 = stdin. */
2956 inregs.x.dx = stdin_stat;
2957 intdos (&inregs, &outregs);
2958 return !outregs.x.cflag;
2959
2960 #endif /* not __DJGPP__ >= 2 */
2961 }
2962
2963 \f
2964 /* Run command as specified by ARGV in directory DIR.
2965 The command is run with input from TEMPIN, output to
2966 file TEMPOUT and stderr to TEMPERR. */
2967
2968 int
2969 run_msdos_command (argv, dir, tempin, tempout, temperr)
2970 unsigned char **argv;
2971 Lisp_Object dir;
2972 int tempin, tempout, temperr;
2973 {
2974 char *saveargv1, *saveargv2, **envv, *lowcase_argv0, *pa, *pl;
2975 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2976 int msshell, result = -1;
2977 int inbak, outbak, errbak;
2978 int x, y;
2979 Lisp_Object cmd;
2980
2981 /* Get current directory as MSDOS cwd is not per-process. */
2982 getwd (oldwd);
2983
2984 /* If argv[0] is the shell, it might come in any lettercase.
2985 Since `Fmember' is case-sensitive, we need to downcase
2986 argv[0], even if we are on case-preserving filesystems. */
2987 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
2988 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
2989 {
2990 *pl = *pa++;
2991 if (*pl >= 'A' && *pl <= 'Z')
2992 *pl += 'a' - 'A';
2993 }
2994 *pl = '\0';
2995
2996 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
2997 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2998 && !strcmp ("-c", argv[1]);
2999 if (msshell)
3000 {
3001 saveargv1 = argv[1];
3002 saveargv2 = argv[2];
3003 argv[1] = "/c";
3004 if (argv[2])
3005 {
3006 char *p = alloca (strlen (argv[2]) + 1);
3007
3008 strcpy (argv[2] = p, saveargv2);
3009 while (*p && isspace (*p))
3010 p++;
3011 while (*p && !isspace (*p))
3012 if (*p == '/')
3013 *p++ = '\\';
3014 else
3015 p++;
3016 }
3017 }
3018
3019 /* Build the environment array. */
3020 {
3021 extern Lisp_Object Vprocess_environment;
3022 Lisp_Object tmp, lst;
3023 int i, len;
3024
3025 lst = Vprocess_environment;
3026 len = XFASTINT (Flength (lst));
3027
3028 envv = alloca ((len + 1) * sizeof (char *));
3029 for (i = 0; i < len; i++)
3030 {
3031 tmp = Fcar (lst);
3032 lst = Fcdr (lst);
3033 CHECK_STRING (tmp, 0);
3034 envv[i] = alloca (XSTRING (tmp)->size + 1);
3035 strcpy (envv[i], XSTRING (tmp)->data);
3036 }
3037 envv[len] = (char *) 0;
3038 }
3039
3040 if (STRINGP (dir))
3041 chdir (XSTRING (dir)->data);
3042 inbak = dup (0);
3043 outbak = dup (1);
3044 errbak = dup (2);
3045 if (inbak < 0 || outbak < 0 || errbak < 0)
3046 goto done; /* Allocation might fail due to lack of descriptors. */
3047
3048 if (have_mouse > 0)
3049 mouse_get_xy (&x, &y);
3050
3051 dos_ttcooked (); /* do it here while 0 = stdin */
3052
3053 dup2 (tempin, 0);
3054 dup2 (tempout, 1);
3055 dup2 (temperr, 2);
3056
3057 #if __DJGPP__ > 1
3058
3059 if (msshell && !argv[3])
3060 {
3061 /* MS-DOS native shells are too restrictive. For starters, they
3062 cannot grok commands longer than 126 characters. In DJGPP v2
3063 and later, `system' is much smarter, so we'll call it instead. */
3064
3065 extern char **environ;
3066 environ = envv;
3067
3068 /* A shell gets a single argument--its full command
3069 line--whose original was saved in `saveargv2'. */
3070 result = system (saveargv2);
3071 }
3072 else
3073
3074 #endif /* __DJGPP__ > 1 */
3075
3076 result = spawnve (P_WAIT, argv[0], argv, envv);
3077
3078 dup2 (inbak, 0);
3079 dup2 (outbak, 1);
3080 dup2 (errbak, 2);
3081 close (inbak);
3082 close (outbak);
3083 close (errbak);
3084
3085 dos_ttraw ();
3086 if (have_mouse > 0)
3087 {
3088 mouse_init ();
3089 mouse_moveto (x, y);
3090 }
3091
3092 /* Some programs might change the meaning of the highest bit of the
3093 text attribute byte, so we get blinking characters instead of the
3094 bright background colors. Restore that. */
3095 bright_bg ();
3096
3097 done:
3098 chdir (oldwd);
3099 if (msshell)
3100 {
3101 argv[1] = saveargv1;
3102 argv[2] = saveargv2;
3103 }
3104 return result;
3105 }
3106
3107 croak (badfunc)
3108 char *badfunc;
3109 {
3110 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3111 reset_sys_modes ();
3112 exit (1);
3113 }
3114 \f
3115 #if __DJGPP__ < 2
3116
3117 /* ------------------------- Compatibility functions -------------------
3118 * gethostname
3119 * gettimeofday
3120 */
3121
3122 /* Hostnames for a pc are not really funny,
3123 but they are used in change log so we emulate the best we can. */
3124
3125 gethostname (p, size)
3126 char *p;
3127 int size;
3128 {
3129 char *q = egetenv ("HOSTNAME");
3130
3131 if (!q) q = "pc";
3132 strcpy (p, q);
3133 return 0;
3134 }
3135
3136 /* When time zones are set from Ms-Dos too many C-libraries are playing
3137 tricks with time values. We solve this by defining our own version
3138 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3139 once and after each call to `tzset' with TZ changed. That is
3140 accomplished by aliasing tzset to init_gettimeofday. */
3141
3142 static struct tm time_rec;
3143
3144 int
3145 gettimeofday (struct timeval *tp, struct timezone *tzp)
3146 {
3147 if (tp)
3148 {
3149 struct time t;
3150 struct tm tm;
3151
3152 gettime (&t);
3153 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
3154 {
3155 struct date d;
3156 getdate (&d);
3157 time_rec.tm_year = d.da_year - 1900;
3158 time_rec.tm_mon = d.da_mon - 1;
3159 time_rec.tm_mday = d.da_day;
3160 }
3161
3162 time_rec.tm_hour = t.ti_hour;
3163 time_rec.tm_min = t.ti_min;
3164 time_rec.tm_sec = t.ti_sec;
3165
3166 tm = time_rec;
3167 tm.tm_gmtoff = dos_timezone_offset;
3168
3169 tp->tv_sec = mktime (&tm); /* may modify tm */
3170 tp->tv_usec = t.ti_hund * (1000000 / 100);
3171 }
3172 /* Ignore tzp; it's obsolescent. */
3173 return 0;
3174 }
3175
3176 #endif /* __DJGPP__ < 2 */
3177
3178 /*
3179 * A list of unimplemented functions that we silently ignore.
3180 */
3181
3182 #if __DJGPP__ < 2
3183 unsigned alarm (s) unsigned s; {}
3184 fork () { return 0; }
3185 int kill (x, y) int x, y; { return -1; }
3186 nice (p) int p; {}
3187 void volatile pause () {}
3188 sigsetmask (x) int x; { return 0; }
3189 sigblock (mask) int mask; { return 0; }
3190 #endif
3191
3192 request_sigio () {}
3193 setpgrp () {return 0; }
3194 setpriority (x,y,z) int x,y,z; { return 0; }
3195 unrequest_sigio () {}
3196
3197 #if __DJGPP__ > 1
3198
3199 #ifdef POSIX_SIGNALS
3200
3201 /* Augment DJGPP library POSIX signal functions. This is needed
3202 as of DJGPP v2.01, but might be in the library in later releases. */
3203
3204 #include <libc/bss.h>
3205
3206 /* A counter to know when to re-initialize the static sets. */
3207 static int sigprocmask_count = -1;
3208
3209 /* Which signals are currently blocked (initially none). */
3210 static sigset_t current_mask;
3211
3212 /* Which signals are pending (initially none). */
3213 static sigset_t pending_signals;
3214
3215 /* Previous handlers to restore when the blocked signals are unblocked. */
3216 typedef void (*sighandler_t)(int);
3217 static sighandler_t prev_handlers[320];
3218
3219 /* A signal handler which just records that a signal occured
3220 (it will be raised later, if and when the signal is unblocked). */
3221 static void
3222 sig_suspender (signo)
3223 int signo;
3224 {
3225 sigaddset (&pending_signals, signo);
3226 }
3227
3228 int
3229 sigprocmask (how, new_set, old_set)
3230 int how;
3231 const sigset_t *new_set;
3232 sigset_t *old_set;
3233 {
3234 int signo;
3235 sigset_t new_mask;
3236
3237 /* If called for the first time, initialize. */
3238 if (sigprocmask_count != __bss_count)
3239 {
3240 sigprocmask_count = __bss_count;
3241 sigemptyset (&pending_signals);
3242 sigemptyset (&current_mask);
3243 for (signo = 0; signo < 320; signo++)
3244 prev_handlers[signo] = SIG_ERR;
3245 }
3246
3247 if (old_set)
3248 *old_set = current_mask;
3249
3250 if (new_set == 0)
3251 return 0;
3252
3253 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3254 {
3255 errno = EINVAL;
3256 return -1;
3257 }
3258
3259 sigemptyset (&new_mask);
3260
3261 /* DJGPP supports upto 320 signals. */
3262 for (signo = 0; signo < 320; signo++)
3263 {
3264 if (sigismember (&current_mask, signo))
3265 sigaddset (&new_mask, signo);
3266 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3267 {
3268 sigaddset (&new_mask, signo);
3269
3270 /* SIGKILL is silently ignored, as on other platforms. */
3271 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3272 prev_handlers[signo] = signal (signo, sig_suspender);
3273 }
3274 if (( how == SIG_UNBLOCK
3275 && sigismember (&new_mask, signo)
3276 && sigismember (new_set, signo))
3277 || (how == SIG_SETMASK
3278 && sigismember (&new_mask, signo)
3279 && !sigismember (new_set, signo)))
3280 {
3281 sigdelset (&new_mask, signo);
3282 if (prev_handlers[signo] != SIG_ERR)
3283 {
3284 signal (signo, prev_handlers[signo]);
3285 prev_handlers[signo] = SIG_ERR;
3286 }
3287 if (sigismember (&pending_signals, signo))
3288 {
3289 sigdelset (&pending_signals, signo);
3290 raise (signo);
3291 }
3292 }
3293 }
3294 current_mask = new_mask;
3295 return 0;
3296 }
3297
3298 #else /* not POSIX_SIGNALS */
3299
3300 sigsetmask (x) int x; { return 0; }
3301 sigblock (mask) int mask; { return 0; }
3302
3303 #endif /* not POSIX_SIGNALS */
3304 #endif /* __DJGPP__ > 1 */
3305
3306 #ifndef HAVE_SELECT
3307 #include "sysselect.h"
3308
3309 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3310 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3311 ((long)(time).tv_sec < 0 \
3312 || ((time).tv_sec == 0 \
3313 && (long)(time).tv_usec <= 0))
3314 #endif
3315
3316
3317 /* Only event queue is checked. */
3318 /* We don't have to call timer_check here
3319 because wait_reading_process_input takes care of that. */
3320 int
3321 sys_select (nfds, rfds, wfds, efds, timeout)
3322 int nfds;
3323 SELECT_TYPE *rfds, *wfds, *efds;
3324 EMACS_TIME *timeout;
3325 {
3326 int check_input;
3327 struct time t;
3328
3329 check_input = 0;
3330 if (rfds)
3331 {
3332 check_input = FD_ISSET (0, rfds);
3333 FD_ZERO (rfds);
3334 }
3335 if (wfds)
3336 FD_ZERO (wfds);
3337 if (efds)
3338 FD_ZERO (efds);
3339
3340 if (nfds != 1)
3341 abort ();
3342
3343 /* If we are looking only for the terminal, with no timeout,
3344 just read it and wait -- that's more efficient. */
3345 if (!timeout)
3346 {
3347 while (!detect_input_pending ())
3348 {
3349 #if __DJGPP__ >= 2
3350 __dpmi_yield ();
3351 #endif
3352 }
3353 }
3354 else
3355 {
3356 EMACS_TIME clnow, cllast, cldiff;
3357
3358 gettime (&t);
3359 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
3360
3361 while (!check_input || !detect_input_pending ())
3362 {
3363 gettime (&t);
3364 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
3365 EMACS_SUB_TIME (cldiff, clnow, cllast);
3366
3367 /* When seconds wrap around, we assume that no more than
3368 1 minute passed since last `gettime'. */
3369 if (EMACS_TIME_NEG_P (cldiff))
3370 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
3371 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
3372
3373 /* Stop when timeout value crosses zero. */
3374 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
3375 return 0;
3376 cllast = clnow;
3377 #if __DJGPP__ >= 2
3378 __dpmi_yield ();
3379 #endif
3380 }
3381 }
3382
3383 FD_SET (0, rfds);
3384 return 1;
3385 }
3386 #endif
3387
3388 /*
3389 * Define overlaid functions:
3390 *
3391 * chdir -> sys_chdir
3392 * tzset -> init_gettimeofday
3393 * abort -> dos_abort
3394 */
3395
3396 #ifdef chdir
3397 #undef chdir
3398 extern int chdir ();
3399
3400 int
3401 sys_chdir (path)
3402 const char* path;
3403 {
3404 int len = strlen (path);
3405 char *tmp = (char *)path;
3406
3407 if (*tmp && tmp[1] == ':')
3408 {
3409 if (getdisk () != tolower (tmp[0]) - 'a')
3410 setdisk (tolower (tmp[0]) - 'a');
3411 tmp += 2; /* strip drive: KFS 1995-07-06 */
3412 len -= 2;
3413 }
3414
3415 if (len > 1 && (tmp[len - 1] == '/'))
3416 {
3417 char *tmp1 = (char *) alloca (len + 1);
3418 strcpy (tmp1, tmp);
3419 tmp1[len - 1] = 0;
3420 tmp = tmp1;
3421 }
3422 return chdir (tmp);
3423 }
3424 #endif
3425
3426 #ifdef tzset
3427 #undef tzset
3428 extern void tzset (void);
3429
3430 void
3431 init_gettimeofday ()
3432 {
3433 time_t ltm, gtm;
3434 struct tm *lstm;
3435
3436 tzset ();
3437 ltm = gtm = time (NULL);
3438 ltm = mktime (lstm = localtime (&ltm));
3439 gtm = mktime (gmtime (&gtm));
3440 time_rec.tm_hour = 99; /* force gettimeofday to get date */
3441 time_rec.tm_isdst = lstm->tm_isdst;
3442 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
3443 }
3444 #endif
3445
3446 #ifdef abort
3447 #undef abort
3448 void
3449 dos_abort (file, line)
3450 char *file;
3451 int line;
3452 {
3453 char buffer1[200], buffer2[400];
3454 int i, j;
3455
3456 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
3457 for (i = j = 0; buffer1[i]; i++) {
3458 buffer2[j++] = buffer1[i];
3459 buffer2[j++] = 0x70;
3460 }
3461 dosmemput (buffer2, j, (int)ScreenPrimary);
3462 ScreenSetCursor (2, 0);
3463 abort ();
3464 }
3465 #else
3466 void
3467 abort ()
3468 {
3469 dos_ttcooked ();
3470 ScreenSetCursor (10, 0);
3471 cputs ("\r\n\nEmacs aborted!\r\n");
3472 #if __DJGPP__ > 1
3473 /* Generate traceback, so we could tell whodunit. */
3474 signal (SIGINT, SIG_DFL);
3475 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3476 #endif
3477 exit (2);
3478 }
3479 #endif
3480
3481 syms_of_msdos ()
3482 {
3483 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
3484 staticpro (&recent_doskeys);
3485
3486 defsubr (&Srecent_doskeys);
3487 defsubr (&Smsdos_long_file_names);
3488 defsubr (&Smsdos_downcase_filename);
3489 }
3490
3491 #endif /* MSDOS */