1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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)
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.
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Contributed by Morten Welinder */
22 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
30 #include <sys/param.h>
36 #include "termhooks.h"
37 #include "dispextern.h"
44 /* #include <process.h> */
45 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
48 static int break_stat
; /* BREAK check mode status. */
49 static int stdin_stat
; /* stdin IOCTL status. */
50 static int extended_kbd
; /* 101 (102) keyboard present. */
52 int have_mouse
; /* Mouse present? */
53 static int mouse_last_x
;
54 static int mouse_last_y
;
56 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of control chars
57 by Dos. Determine the keyboard type. */
61 union REGS inregs
, outregs
;
64 int86 (0x15, &inregs
, &outregs
);
65 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
67 break_stat
= getcbrk ();
69 install_ctrl_break_check ();
70 have_mouse
= mouse_init1 ();
72 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
73 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
74 intdos (&inregs
, &outregs
);
75 stdin_stat
= outregs
.h
.dl
;
77 inregs
.x
.dx
= (outregs
.x
.dx
| 0x0020) & 0x0027; /* raw mode */
79 intdos (&inregs
, &outregs
);
80 return !outregs
.x
.cflag
;
83 /* Restore status of standard input and Ctrl-C checking. */
87 union REGS inregs
, outregs
;
90 if (have_mouse
) mouse_off ();
92 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
93 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
94 inregs
.x
.dx
= stdin_stat
;
95 intdos (&inregs
, &outregs
);
96 return !outregs
.x
.cflag
;
100 ibmpc_translate_map
[] =
102 /* --------------- 00 to 0f --------------- */
105 0xffb1, /* Keypad 1 */
106 0xffb2, /* Keypad 2 */
107 0xffb3, /* Keypad 3 */
108 0xffb4, /* Keypad 4 */
109 0xffb5, /* Keypad 5 */
110 0xffb6, /* Keypad 6 */
111 0xffb7, /* Keypad 7 */
112 0xffb8, /* Keypad 8 */
113 0xffb9, /* Keypad 9 */
114 0xffb0, /* Keypad 0 */
116 0xff08, /* Backspace */
117 0xff74, /* (Shift) Tab [Tab doesn't use this table] */
119 /* --------------- 10 to 1f --------------- */
120 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
121 0xff8d, /* Keypad Enter */
125 /* --------------- 20 to 2f --------------- */
126 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
128 '\\', 'z', 'x', 'c', 'v',
130 /* --------------- 30 to 3f --------------- */
131 'b', 'n', 'm', ',', '.',
144 /* --------------- 40 to 4f --------------- */
154 0xff55, /* Page Up */
157 0xffb5, /* Keypad 5 */
162 /* --------------- 50 to 5f --------------- */
164 0xff56, /* Page Down */
167 0xffbe, /* (Shift) F1 */
168 0xffbf, /* (Shift) F2 */
169 0xffc0, /* (Shift) F3 */
170 0xffc1, /* (Shift) F4 */
171 0xffc2, /* (Shift) F5 */
172 0xffc3, /* (Shift) F6 */
173 0xffc4, /* (Shift) F7 */
174 0xffc5, /* (Shift) F8 */
175 0xffc6, /* (Shift) F9 */
176 0xffc7, /* (Shift) F10 */
177 0xffbe, /* (Ctrl) F1 */
178 0xffbf, /* (Ctrl) F2 */
180 /* --------------- 60 to 6f --------------- */
181 0xffc0, /* (Ctrl) F3 */
182 0xffc1, /* (Ctrl) F4 */
183 0xffc2, /* (Ctrl) F5 */
184 0xffc3, /* (Ctrl) F6 */
185 0xffc4, /* (Ctrl) F7 */
186 0xffc5, /* (Ctrl) F8 */
187 0xffc6, /* (Ctrl) F9 */
188 0xffc7, /* (Ctrl) F10 */
189 0xffbe, /* (Alt) F1 */
190 0xffbf, /* (Alt) F2 */
191 0xffc0, /* (Alt) F3 */
192 0xffc1, /* (Alt) F4 */
193 0xffc2, /* (Alt) F5 */
194 0xffc3, /* (Alt) F6 */
195 0xffc4, /* (Alt) F7 */
196 0xffc5, /* (Alt) F8 */
198 /* --------------- 70 to 7f --------------- */
199 0xffc6, /* (Alt) F9 */
200 0xffc7, /* (Alt) F10 */
201 0xff6d, /* (Ctrl) Sys Rq */
202 0xff51, /* (Ctrl) Left */
203 0xff53, /* (Ctrl) Right */
204 0xff57, /* (Ctrl) End */
205 0xff56, /* (Ctrl) Page Down */
206 0xff50, /* (Ctrl) Home */
207 '1', '2', '3', '4', '5', '6', '7', '8', /* (Alt) */
209 /* --------------- 80 to 8f --------------- */
210 '9', '0', '-', '=', /* (Alt) */
211 0xff55, /* (Ctrl) Page Up */
214 0xffc8, /* (Shift) F11 */
215 0xffc9, /* (Shift) F12 */
216 0xffc8, /* (Ctrl) F11 */
217 0xffc9, /* (Ctrl) F12 */
218 0xffc8, /* (Alt) F11 */
219 0xffc9, /* (Alt) F12 */
220 0xff52, /* (Ctrl) Up */
221 0xffae, /* (Ctrl) Grey - */
222 0xffb5, /* (Ctrl) Keypad 5 */
224 /* --------------- 90 to 9f --------------- */
225 0xffab, /* (Ctrl) Grey + */
226 0xff54, /* (Ctrl) Down */
227 0xff63, /* (Ctrl) Insert */
228 0xffff, /* (Ctrl) Delete */
229 0xff09, /* (Ctrl) Tab */
230 0xffaf, /* (Ctrl) Grey / */
231 0xffaa, /* (Ctrl) Grey * */
232 0xff50, /* (Alt) Home */
233 0xff52, /* (Alt) Up */
234 0xff55, /* (Alt) Page Up */
236 0xff51, /* (Alt) Left */
238 0xff53, /* (Alt) Right */
240 0xff57, /* (Alt) End */
242 /* --------------- a0 to af --------------- */
243 0xff54, /* (Alt) Down */
244 0xff56, /* (Alt) Page Down */
245 0xff63, /* (Alt) Insert */
246 0xffff, /* (Alt) Delete */
247 0xffaf, /* (Alt) Grey / */
248 0xff09, /* (Alt) Tab */
249 0xff0d /* (Alt) Enter */
252 /* Get a char from keyboard. Function keys are put into the event queue. */
256 struct input_event event
;
259 int ctrl_p
, alt_p
, shift_p
;
261 /* Calculate modifier bits */
262 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
263 int86 (0x16, ®s
, ®s
);
264 ctrl_p
= ((regs
.h
.al
& 4) != 0);
265 shift_p
= ((regs
.h
.al
& 3) != 0);
266 /* Please be very careful here not to break international keyboard support.
267 When Keyb.Com is loaded, the key marked `Alt Gr' is used for accessing
268 characters like { and } if their positions are overlaid. */
269 alt_p
= ((extended_kbd
? (regs
.h
.ah
& 2) : (regs
.h
.al
& 8)) != 0);
271 /* The following condition is equivalent to `kbhit ()', except that
272 it uses the bios to do its job. This pleases DESQview/X. */
273 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
274 int86 (0x16, ®s
, ®s
),
275 (regs
.x
.flags
& 0x40) == 0)
278 register unsigned char c
;
281 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
282 int86 (0x16, ®s
, ®s
);
286 /* Determine from the scan code if a keypad key was pressed. */
287 if (c
>= '0' && c
<= '9' && sc
> 0xb)
288 sc
= (c
== '0') ? 0xb : (c
- '0' + 1), c
= 0;
289 else if (sc
== 0x53 && c
!= 0xe0)
291 code
= 0xffae; /* Keypad decimal point/comma. */
298 case 10: /* Ctrl Enter */
314 || (ctrl_p
&& shift_p
)
315 || (c
== 0xe0 && sc
!= 0) /* Pseudo-key */
316 || sc
== 0x37 /* Grey * */
317 || sc
== 0x4a /* Grey - */
318 || sc
== 0x4e /* Grey + */
319 || sc
== 0x0e) /* Back space *key*, not Ctrl-h */
321 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
324 code
= ibmpc_translate_map
[sc
];
330 event
.kind
= non_ascii_keystroke
;
331 event
.code
= (code
& 0xff) + 0xff00;
335 /* Don't return S- if we don't have to. `shifted' is
336 supposed to be the shifted versions of the characters
337 in `unshifted'. Unfortunately, this is only true for
338 US keyboard layout. If anyone knows how to do this
339 right, please tell us. */
340 static char *unshifted
341 = "abcdefghijklmnopqrstuvwxyz,./=;[\\]'-`0123456789";
343 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ<>?+:{|}\"_~)!@#$%^&*(";
346 if (shift_p
&& (pos
= strchr (unshifted
, code
)))
348 c
= shifted
[pos
- unshifted
];
352 if (c
== 0) c
= code
;
353 event
.kind
= ascii_keystroke
;
357 = (shift_p
? shift_modifier
: 0)
358 + (ctrl_p
? ctrl_modifier
: 0)
359 + (alt_p
? meta_modifier
: 0);
360 /* EMACS == Enter Meta Alt Control Shift */
361 XSETFRAME (event
.frame_or_window
, selected_frame
);
362 gettimeofday (&tv
, NULL
);
363 event
.timestamp
= tv
.tv_usec
;
364 kbd_buffer_store_event (&event
);
372 int but
, press
, x
, y
, ok
;
374 /* Check for mouse movement *before* buttons. */
375 mouse_check_moved ();
377 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
378 for (press
= 0; press
< 2; press
++)
381 ok
= mouse_pressed (but
, &x
, &y
);
383 ok
= mouse_released (but
, &x
, &y
);
386 event
.kind
= mouse_click
;
389 = (shift_p
? shift_modifier
: 0)
390 + (ctrl_p
? ctrl_modifier
: 0)
391 + (alt_p
? meta_modifier
: 0)
392 + (press
? down_modifier
: up_modifier
);
395 XSETFRAME (event
.frame_or_window
, selected_frame
);
396 gettimeofday (&tv
, NULL
);
397 event
.timestamp
= tv
.tv_usec
;
398 kbd_buffer_store_event (&event
);
406 static int prev_get_char
= -1;
408 /* Return 1 if a key is ready to be read without suspending execution. */
411 if (prev_get_char
!= -1)
414 return ((prev_get_char
= dos_rawgetc ()) != -1);
417 /* Read a key. Return -1 if no key is ready. */
420 if (prev_get_char
!= -1)
422 int c
= prev_get_char
;
427 return dos_rawgetc ();
430 /* Hostnames for a pc are not really funny, but they are used in change log
431 so we emulate the best we can. */
432 gethostname (p
, size
)
436 char *q
= egetenv ("HOSTNAME");
443 /* Destructively turn backslashes into slashes. */
445 dostounix_filename (p
)
456 /* Destructively turn slashes into backslashes. */
458 unixtodos_filename (p
)
469 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
471 getdefdir (drive
, dst
)
479 regs
.x
.si
= (int) dst
;
481 intdos (®s
, ®s
);
482 return !regs
.x
.cflag
;
485 /* Remove all CR's that are followed by a LF. */
489 register unsigned char *buf
;
491 unsigned char *np
= buf
;
492 unsigned char *startp
= buf
;
493 unsigned char *endp
= buf
+ n
;
498 while (buf
< endp
- 1)
502 if (*(++buf
) != 0x0a)
514 /* Run command as specified by ARGV in directory DIR.
515 The command is run with input from TEMPIN and output to file TEMPOUT. */
517 run_msdos_command (argv
, dir
, tempin
, tempout
)
518 unsigned char **argv
;
522 char *saveargv1
, *saveargv2
, **envv
;
523 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
524 int msshell
, result
= -1;
525 int in
, out
, inbak
, outbak
, errbak
;
528 /* Get current directory as MSDOS cwd is not per-process. */
531 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
532 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
533 && !strcmp ("-c", argv
[1]);
541 char *p
= alloca (strlen (argv
[2]) + 1);
543 strcpy (argv
[2] = p
, saveargv2
);
544 while (*p
&& isspace (*p
))
546 while (*p
&& !isspace (*p
))
554 /* Build the environment array. */
556 extern Lisp_Object Vprocess_environment
;
557 Lisp_Object tmp
, lst
;
560 lst
= Vprocess_environment
;
561 len
= XFASTINT (Flength (lst
));
563 envv
= alloca ((len
+ 1) * sizeof (char *));
564 for (i
= 0; i
< len
; i
++)
568 CHECK_STRING (tmp
, 0);
569 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
570 strcpy (envv
[i
], XSTRING (tmp
)->data
);
572 envv
[len
] = (char *) 0;
576 chdir (XSTRING (dir
)->data
);
580 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
581 goto done
; /* Allocation might fail due to lack of descriptors. */
586 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
606 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
611 /* A list of unimplemented functions that we silently ignore. */
612 unsigned alarm (s
) unsigned s
; {}
613 fork () { return 0; }
614 int kill (x
, y
) int x
, y
; { return -1; }
616 void volatile pause () {}
618 setpgrp () {return 0; }
619 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
620 sigsetmask (x
) int x
; { return 0; }
621 unrequest_sigio () {}
631 int len
= strlen (path
);
632 char *tmp
= (char *) alloca (len
+ 1);
633 /* Gotta do this extern here due to the corresponding #define: */
636 if (*path
&& path
[1] == ':' && (getdisk () != tolower (path
[0]) - 'a'))
637 setdisk (tolower (path
[0]) - 'a');
640 if (strcmp (path
, "/") && strcmp (path
+ 1, ":/") && (path
[len
- 1] == '/'))
645 /* Sleep SECS. If KBDOK also return immediately if a key is pressed. */
647 sleep_or_kbd_hit (secs
, kbdok
)
653 gettimeofday (&t
, NULL
);
654 clnow
= t
.tv_sec
* 100 + t
.tv_usec
/ 10000;
655 clthen
= clnow
+ (100 * secs
);
659 gettimeofday (&t
, NULL
);
660 clnow
= t
.tv_sec
* 100 + t
.tv_usec
/ 10000;
661 if (kbdok
&& detect_input_pending ())
664 while (clnow
< clthen
);
667 /* The Emacs root directory as determined by init_environment. */
668 static char emacsroot
[MAXPATHLEN
];
671 rootrelativepath (rel
)
674 static char result
[MAXPATHLEN
+ 10];
676 strcpy (result
, emacsroot
);
677 strcat (result
, "/");
678 strcat (result
, rel
);
682 /* Define a lot of environment variables if not already defined. Don't
683 remove anything unless you know what you're doing -- lots of code will
684 break if one or more of these are missing. */
686 init_environment (argc
, argv
, skip_args
)
694 /* Find our root from argv[0]. Assuming argv[0] is, say,
695 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
696 root
= alloca (MAXPATHLEN
+ 20);
697 _fixpath (argv
[0], root
);
700 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
703 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
704 root
[len
- 4] = '\0';
706 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
708 strcpy (emacsroot
, root
);
710 /* We default HOME to our root. */
711 setenv ("HOME", root
, 0);
713 /* We default EMACSPATH to root + "/bin". */
714 strcpy (root
+ len
, "/bin");
715 setenv ("EMACSPATH", root
, 0);
717 /* I don't expect anybody to ever use other terminals so the internal
718 terminal is the default. */
719 setenv ("TERM", "internal", 0);
721 #ifdef HAVE_X_WINDOWS
722 /* Emacs expects DISPLAY to be set. */
723 setenv ("DISPLAY", "unix:0.0", 0);
726 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
727 downcase it and mirror the backslashes. */
728 s
= getenv ("COMSPEC");
729 if (!s
) s
= "c:/command.com";
730 t
= alloca (strlen (s
) + 1);
733 dostounix_filename (t
);
734 setenv ("SHELL", t
, 0);
736 /* PATH is also downcased and backslashes mirrored. */
739 t
= alloca (strlen (s
) + 3);
740 /* Current directory is always considered part of MsDos's path but it is
741 not normally mentioned. Now it is. */
742 strcat (strcpy (t
, ".;"), s
);
744 dostounix_filename (t
); /* Not a single file name, but this should work. */
745 setenv ("PATH", t
, 1);
747 /* In some sense all dos users have root privileges, so... */
748 setenv ("USER", "root", 0);
749 setenv ("NAME", getenv ("USER"), 0);
751 /* Time zone determined from country code. To make this possible, the
752 country code may not span more than one time zone. In other words,
753 in the USA, you lose. */
754 switch (dos_country_code
)
756 case 31: /* Belgium */
757 case 32: /* The Netherlands */
758 case 33: /* France */
760 case 36: /* Hungary */
761 case 38: /* Yugoslavia (or what's left of it?) */
763 case 41: /* Switzerland */
764 case 42: /* Tjekia */
765 case 45: /* Denmark */
766 case 46: /* Sweden */
767 case 47: /* Norway */
768 case 48: /* Poland */
769 case 49: /* Germany */
770 /* Daylight saving from last Sunday in March to last Sunday in
771 September, both at 2AM. */
772 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
774 case 44: /* United Kingdom */
775 case 351: /* Portugal */
776 case 354: /* Iceland */
777 setenv ("TZ", "GMT+00", 0);
781 setenv ("TZ", "???-09", 0);
783 case 90: /* Turkey */
784 case 358: /* Finland */
785 case 972: /* Israel */
786 setenv ("TZ", "EET-02", 0);
790 init_gettimeofday ();
793 /* Flash the screen as a substitute for BEEPs. */
796 do_visible_bell (xorattr
)
797 unsigned char xorattr
;
802 movl _ScreenPrimary,%%eax
809 xorb %%al,%%gs:(%%ebx)
825 : "m" (xorattr
), "g" (ScreenCols () * ScreenRows ())
826 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
829 /* At screen position (X,Y), output C characters from string S with
830 attribute A. Do it fast! */
833 output_string (x
, y
, s
, c
, a
)
838 char *t
= (char *)ScreenPrimary
+ 2 * (x
+ ScreenCols () * y
);
848 movw %%ax,%%gs:(%%edi)
854 : "m" (a
), "g" (t
), "g" (c
), "g" (s
)
855 : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
858 static int internal_terminal
= 0;
859 static int highlight
;
867 static char spaces
[] = " ";
870 unsigned char *cp
, *cp0
;
873 if (internal_terminal
&& f
== stdout
)
875 if (have_mouse
) mouse_off ();
877 count
= stdout
->_ptr
- stdout
->_base
;
891 ScreenAttrib
= *cp
++;
895 do_visible_bell (*cp
++);
904 i
= ScreenCols () - x
;
906 while (i
>= sizeof spaces
)
908 output_string (j
, y
, spaces
, sizeof spaces
,
914 output_string (j
, y
, spaces
, i
, ScreenAttrib
);
926 ScreenAttrib
^= *cp
++;
934 write (1, "\007", 1);
952 while (count
> 0 && *cp
>= ' ')
954 output_string (x
, y
, cp0
, cp
- cp0
, ScreenAttrib
);
959 ScreenSetCursor (y
, x
);
960 if (have_mouse
) mouse_on ();
963 /* This is a call to the original fflush. */
967 #ifndef HAVE_X_WINDOWS
971 /* Rien du tout, cela va sans dire! */
979 /* This creates an xor-mask that will swap the default fore- and
980 background colors. */
981 if (have_mouse
) mouse_off ();
982 do_visible_bell (((the_only_x_display
.foreground_pixel
983 ^ the_only_x_display
.background_pixel
)
985 if (have_mouse
) mouse_on ();
988 /* Write it directly to ms-dos -- don't let it go through our terminal
989 emulator. This way the mouse cursor won't blink. */
990 write (1, "\007", 1);
994 IT_set_face (int face
)
997 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
999 if (face
== 1 || (face
== 0 && highlight
))
1000 fp
= FRAME_MODE_LINE_FACE (foo
);
1001 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
1002 fp
= FRAME_DEFAULT_FACE (foo
);
1004 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
1007 putchar ((FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
));
1011 IT_write_glyphs (GLYPH
*str
, int len
)
1018 newface
= FAST_GLYPH_FACE (*str
);
1019 if (newface
!= face
)
1020 IT_set_face ((face
= newface
));
1021 putchar (FAST_GLYPH_CHAR (*str
));
1027 IT_clear_end_of_line (first_unused
)
1034 IT_cursor_to (int y
, int x
)
1042 IT_reassert_line_highlight (new, vpos
)
1046 IT_set_face (0); /* To possibly clear the highlighting. */
1050 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
1052 highlight
= new_highlight
;
1053 IT_set_face (0); /* To possibly clear the highlighting. */
1054 IT_cursor_to (vpos
, 0);
1055 IT_clear_end_of_line (first_unused_hpos
);
1062 IT_set_face (0); /* To possibly clear the highlighting. */
1065 /* This was more or less copied from xterm.c */
1067 IT_set_menu_bar_lines (window
, n
)
1071 struct window
*w
= XWINDOW (window
);
1073 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
1074 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
1076 /* Handle just the top child in a vertical split. */
1077 if (!NILP (w
->vchild
))
1078 IT_set_menu_bar_lines (w
->vchild
, n
);
1080 /* Adjust all children in a horizontal split. */
1081 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
1083 w
= XWINDOW (window
);
1084 IT_set_menu_bar_lines (window
, n
);
1089 IT_set_frame_parameters (frame
, alist
)
1095 extern unsigned long load_color ();
1096 FRAME_PTR f
= (FRAME_PTR
) &the_only_frame
;
1099 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1101 Lisp_Object elt
, prop
, val
;
1106 CHECK_SYMBOL (prop
, 1);
1108 if (EQ (prop
, intern ("foreground-color")))
1110 unsigned long new_color
= load_color (f
, val
);
1111 if (new_color
!= ~0)
1113 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1117 else if (EQ (prop
, intern ("background-color")))
1119 unsigned long new_color
= load_color (f
, val
);
1120 if (new_color
!= ~0)
1122 FRAME_BACKGROUND_PIXEL (f
) = new_color
& ~8;
1126 else if (EQ (prop
, intern ("menu-bar-lines")))
1129 int old
= FRAME_MENU_BAR_LINES (the_only_frame
);
1135 FRAME_MENU_BAR_LINES (f
) = new;
1136 IT_set_menu_bar_lines (the_only_frame
.root_window
, new - old
);
1142 recompute_basic_faces (f
);
1143 Fredraw_frame (Fselected_frame ());
1147 /* Similar to the_only_frame. */
1148 struct x_display the_only_x_display
;
1150 /* This is never dereferenced. */
1151 Display
*x_current_display
;
1153 #endif /* !HAVE_X_WINDOWS */
1155 /* Do we need the internal terminal? */
1157 internal_terminal_init ()
1159 char *term
= getenv ("TERM");
1161 #ifdef HAVE_X_WINDOWS
1162 if (!inhibit_window_system
)
1167 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1169 #ifndef HAVE_X_WINDOWS
1170 if (internal_terminal
&& !inhibit_window_system
)
1172 Vwindow_system
= intern ("pc");
1173 Vwindow_system_version
= make_number (1);
1175 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1176 the_only_x_display
.background_pixel
= 7; /* White */
1177 the_only_x_display
.foreground_pixel
= 0; /* Black */
1178 the_only_x_display
.line_height
= 1;
1179 the_only_frame
.display
.x
= &the_only_x_display
;
1180 the_only_frame
.output_method
= output_msdos_raw
;
1182 init_frame_faces ((FRAME_PTR
) &the_only_frame
);
1184 ring_bell_hook
= IT_ring_bell
;
1185 write_glyphs_hook
= IT_write_glyphs
;
1186 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1187 clear_end_of_line_hook
= IT_clear_end_of_line
;
1188 change_line_highlight_hook
= IT_change_line_highlight
;
1189 update_begin_hook
= IT_update_begin
;
1190 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1192 /* These hooks are called by term.c without being checked. */
1193 set_terminal_modes_hook
1194 = reset_terminal_modes_hook
1196 = set_terminal_window_hook
1197 = (void *)rien_du_tout
;
1200 the_only_frame
.output_method
= output_termcap
;
1204 /* When time zones are set from Ms-Dos too may C-libraries are playing
1205 tricks with time values. We solve this by defining our own version
1206 of `gettimeofday' bypassing GO32. Our version needs to be initialized
1207 once and after each call to `tzset' with TZ changed. */
1209 static int daylight
, gmtoffset
;
1212 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
1222 tmrec
.tm_year
= d
.da_year
- 1900;
1223 tmrec
.tm_mon
= d
.da_mon
- 1;
1224 tmrec
.tm_mday
= d
.da_day
;
1225 tmrec
.tm_hour
= t
.ti_hour
;
1226 tmrec
.tm_min
= t
.ti_min
;
1227 tmrec
.tm_sec
= t
.ti_sec
;
1228 tmrec
.tm_gmtoff
= gmtoffset
;
1229 tmrec
.tm_isdst
= daylight
;
1230 tp
->tv_sec
= mktime (&tmrec
);
1231 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
1235 tzp
->tz_minuteswest
= gmtoffset
;
1236 tzp
->tz_dsttime
= daylight
;
1242 init_gettimeofday ()
1249 ltm
= gtm
= time (NULL
);
1250 ltm
= mktime (lstm
= localtime (<m
));
1251 gtm
= mktime (gmtime (>m
));
1252 daylight
= lstm
->tm_isdst
;
1253 gmtoffset
= (int)(gtm
- ltm
) / 60;
1256 /* These must be global. */
1257 static _go32_dpmi_seginfo ctrl_break_vector
;
1258 static _go32_dpmi_registers ctrl_break_regs
;
1259 static int ctrlbreakinstalled
= 0;
1261 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
1263 ctrl_break_func (regs
)
1264 _go32_dpmi_registers
*regs
;
1270 install_ctrl_break_check ()
1272 if (!ctrlbreakinstalled
)
1274 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
1275 was compiler with Djgpp 1.11 maintenance level 5 or later! */
1276 ctrlbreakinstalled
= 1;
1277 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
1278 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
1280 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
1284 /* Mouse routines follow. Coordinates are in screen positions and zero
1285 based. Mouse buttons are numbered from left to right and also zero
1288 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
1289 static int mouse_button_count
;
1298 regs
.x
.dx
= 8 * (ScreenCols () - 1);
1299 int86 (0x33, ®s
, ®s
);
1303 regs
.x
.dx
= 8 * (ScreenRows () - 1);
1304 int86 (0x33, ®s
, ®s
);
1306 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
1316 int86 (0x33, ®s
, ®s
);
1325 int86 (0x33, ®s
, ®s
);
1335 mouse_last_x
= regs
.x
.cx
= x
* 8;
1336 mouse_last_y
= regs
.x
.dx
= y
* 8;
1337 int86 (0x33, ®s
, ®s
);
1341 mouse_pressed (b
, xp
, yp
)
1346 if (b
>= mouse_button_count
)
1349 regs
.x
.bx
= mouse_button_translate
[b
];
1350 int86 (0x33, ®s
, ®s
);
1352 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
1353 return (regs
.x
.bx
!= 0);
1357 mouse_released (b
, xp
, yp
)
1362 if (b
>= mouse_button_count
)
1365 regs
.x
.bx
= mouse_button_translate
[b
];
1366 int86 (0x33, ®s
, ®s
);
1368 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
1369 return (regs
.x
.bx
!= 0);
1373 mouse_get_xy (int *x
, int *y
)
1378 int86 (0x33, ®s
, ®s
);
1384 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
1387 Lisp_Object
*bar_window
, *x
, *y
;
1388 enum scroll_bar_part
*part
;
1389 unsigned long *time
;
1396 int86 (0x33, ®s
, ®s
);
1397 *f
= selected_frame
;
1399 gettimeofday (&tv
, NULL
);
1400 mouse_get_xy (&ix
, &iy
);
1401 selected_frame
->mouse_moved
= 0;
1402 *x
= make_number (ix
);
1403 *y
= make_number (iy
);
1408 mouse_check_moved ()
1412 mouse_get_xy (&x
, &y
);
1413 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
1424 #ifdef HAVE_X_WINDOWS
1425 if (!inhibit_window_system
)
1428 if (!internal_terminal
)
1432 int86 (0x33, ®s
, ®s
);
1433 present
= (regs
.x
.ax
& 0xffff) == 0xffff;
1436 /* Reportedly, the above doesn't work for some mouse drivers. There
1437 is an additional detection method that should work, but might be
1438 a little slower. Use that as an alternative. */
1440 int86 (0x33, ®s
, ®s
);
1441 present
= (regs
.x
.ax
& 0xffff) == 0xffff;
1448 mouse_button_count
= 3;
1449 mouse_button_translate
[0] = 0; /* Left */
1450 mouse_button_translate
[1] = 2; /* Middle */
1451 mouse_button_translate
[2] = 1; /* Right */
1455 mouse_button_count
= 2;
1456 mouse_button_translate
[0] = 0;
1457 mouse_button_translate
[1] = 1;
1459 mouse_position_hook
= &mouse_get_pos
;
1465 #ifndef HAVE_X_WINDOWS
1466 /* See xterm.c for more info. */
1468 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1470 register int pix_x
, pix_y
;
1471 register int *x
, *y
;
1472 void /* XRectangle */ *bounds
;
1475 if (bounds
) abort ();
1477 /* Ignore clipping. */
1484 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1487 register int *pix_x
, *pix_y
;
1493 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1496 Actually, I don't know the meaning of all the parameters of the functions
1497 here -- I only know how they are called by xmenu.c. I could of course
1498 grab the nearest Xlib manual (down the hall, second-to-last door on the
1499 left), but I don't think it's worth the effort. */
1506 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1507 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1511 /* Allocate some (more) memory for MENU ensuring that there is room for one
1514 IT_menu_make_room (XMenu
*menu
)
1516 if (menu
->allocated
== 0)
1518 int count
= menu
->allocated
= 10;
1519 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1520 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1521 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1523 else if (menu
->allocated
== menu
->count
)
1525 int count
= menu
->allocated
= menu
->allocated
+ 10;
1527 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1529 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1531 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1535 /* Search the given menu structure for a given pane number. */
1537 IT_menu_search_pane (XMenu
*menu
, int pane
)
1542 for (i
= 0; i
< menu
->count
; i
++)
1543 if (menu
->submenu
[i
])
1544 if (pane
== menu
->panenumber
[i
])
1545 return menu
->submenu
[i
];
1547 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1552 /* Determine how much screen space a given menu needs. */
1554 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1556 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1559 maxheight
= menu
->count
;
1560 for (i
= 0; i
< menu
->count
; i
++)
1562 if (menu
->submenu
[i
])
1564 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1565 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1566 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1569 *width
= menu
->width
+ maxsubwidth
;
1570 *height
= maxheight
;
1573 /* Display MENU at (X,Y) using FACES. */
1575 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1577 int i
, j
, face
, width
;
1581 int enabled
, mousehere
;
1584 width
= menu
->width
;
1585 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1586 ScreenGetCursor (&row
, &col
);
1587 mouse_get_xy (&mx
, &my
);
1589 (*update_begin_hook
) ();
1590 for (i
= 0; i
< menu
->count
; i
++)
1592 (*cursor_to_hook
) (y
+ i
, x
);
1594 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1595 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1596 face
= faces
[enabled
+ mousehere
* 2];
1598 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1599 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1600 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1601 for (; j
< width
; j
++)
1602 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1603 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1604 (*write_glyphs_hook
) (text
, width
+ 2);
1606 internal_flush (stdout
);
1607 (*update_end_hook
) ();
1609 ScreenSetCursor (row
, col
);
1613 /* Create a brand new menu structure. */
1615 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1617 return IT_menu_create ();
1620 /* Create a new pane and place it on the outer-most level. It is not
1621 clear that it should be placed out there, but I don't know what else
1624 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1631 IT_menu_make_room (menu
);
1632 menu
->submenu
[menu
->count
] = IT_menu_create ();
1633 menu
->text
[menu
->count
] = txt
;
1634 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1636 if ((len
= strlen (txt
)) > menu
->width
) menu
->width
= len
;
1637 return menu
->panecount
;
1640 /* Create a new item in a menu pane. */
1642 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1643 int foo
, char *txt
, int enable
)
1648 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1650 IT_menu_make_room (menu
);
1651 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1652 menu
->text
[menu
->count
] = txt
;
1653 menu
->panenumber
[menu
->count
] = enable
;
1655 if ((len
= strlen (txt
)) > menu
->width
) menu
->width
= len
;
1659 /* Decide where the menu would be placed if requested at (X,Y). */
1661 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1662 int *ulx
, int *uly
, int *width
, int *height
)
1664 if (menu
->count
== 1 && menu
->submenu
[0])
1665 /* Special case: the menu consists of only one pane. */
1666 IT_menu_calc_size (menu
->submenu
[0], width
, height
);
1668 IT_menu_calc_size (menu
, width
, height
);
1676 void *screen_behind
;
1683 /* Display menu, wait for user's response, and return that response. */
1685 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1686 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1688 IT_menu_state
*state
;
1692 int faces
[4], selectface
;
1693 int leave
, result
, onepane
;
1695 /* Just in case we got here without a mouse present... */
1697 return XM_IA_SELECT
;
1699 state
= alloca (menu
->panecount
* sizeof (IT_menu_state
));
1700 screensize
= ScreenRows () * ScreenCols () * 2;
1702 = compute_glyph_face (&the_only_frame
,
1705 intern ("msdos-menu-passive-face")),
1708 = compute_glyph_face (&the_only_frame
,
1711 intern ("msdos-menu-active-face")),
1714 = face_name_id_number (&the_only_frame
, intern ("msdos-menu-select-face"));
1715 faces
[2] = compute_glyph_face (&the_only_frame
, selectface
, faces
[0]);
1716 faces
[3] = compute_glyph_face (&the_only_frame
, selectface
, faces
[1]);
1719 state
[0].menu
= menu
;
1721 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
1723 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
1725 menu
->width
= menu
->submenu
[0]->width
;
1726 state
[0].menu
= menu
->submenu
[0];
1730 state
[0].menu
= menu
;
1732 state
[0].x
= x0
- 1;
1734 state
[0].pane
= onepane
;
1736 mouse_last_x
= -1; /* A hack that forces display. */
1740 mouse_check_moved ();
1741 if (selected_frame
->mouse_moved
)
1743 selected_frame
->mouse_moved
= 0;
1744 result
= XM_IA_SELECT
;
1745 mouse_get_xy (&x
, &y
);
1746 for (i
= 0; i
< statecount
; i
++)
1747 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
1749 int dy
= y
- state
[i
].y
;
1750 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
1752 if (!state
[i
].menu
->submenu
[dy
])
1753 if (state
[i
].menu
->panenumber
[dy
])
1754 result
= XM_SUCCESS
;
1756 result
= XM_IA_SELECT
;
1757 *pane
= state
[i
].pane
- 1;
1759 /* We hit some part of a menu, so drop extra menues that
1760 have been opened. That does not include an open and
1762 if (i
!= statecount
- 2
1763 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
1764 while (i
!= statecount
- 1)
1768 ScreenUpdate (state
[statecount
].screen_behind
);
1770 xfree (state
[statecount
].screen_behind
);
1772 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
1774 IT_menu_display (state
[i
].menu
,
1778 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
1779 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
1781 ScreenRetrieve (state
[statecount
].screen_behind
1782 = xmalloc (screensize
));
1785 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
1786 state
[statecount
].y
= y
;
1791 IT_menu_display (state
[statecount
- 1].menu
,
1792 state
[statecount
- 1].y
,
1793 state
[statecount
- 1].x
,
1796 for (b
= 0; b
< mouse_button_count
; b
++)
1798 (void) mouse_pressed (b
, &x
, &y
);
1799 if (mouse_released (b
, &x
, &y
))
1805 ScreenUpdate (state
[0].screen_behind
);
1807 while (statecount
--)
1808 xfree (state
[statecount
].screen_behind
);
1812 /* Dispose of a menu. */
1814 XMenuDestroy (Display
*foo
, XMenu
*menu
)
1817 if (menu
->allocated
)
1819 for (i
= 0; i
< menu
->count
; i
++)
1820 if (menu
->submenu
[i
])
1821 XMenuDestroy (foo
, menu
->submenu
[i
]);
1823 xfree (menu
->submenu
);
1824 xfree (menu
->panenumber
);
1829 int x_pixel_width (struct frame
*f
)
1831 return FRAME_WIDTH(f
);
1834 int x_pixel_height (struct frame
*f
)
1836 return FRAME_HEIGHT(f
);
1838 #endif /* !HAVE_X_WINDOWS */