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 #define DO_TERMSCRIPT /* define if you want open-termscript to work on msdos */
58 /* Standard putchar may call _flsbuf which doesn't go through
59 fflush's overlayed internal_flush routine. */
62 (--(stdout)->_cnt>=0? \
63 ((int)((unsigned char)((*(stdout)->_ptr++=(unsigned)(x))))): \
64 (internal_flush (stdout), --(stdout)->_cnt, *(stdout)->_ptr++=(unsigned)(x)))
67 mouse_get_xy (int *x
, int *y
);
69 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of control chars
70 by Dos. Determine the keyboard type. */
74 union REGS inregs
, outregs
;
75 static int only_once
= 1;
79 int86 (0x15, &inregs
, &outregs
);
80 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
83 break_stat
= getcbrk ();
85 install_ctrl_break_check ();
88 have_mouse
= mouse_init1 ();
90 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
91 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
92 intdos (&inregs
, &outregs
);
93 stdin_stat
= outregs
.h
.dl
;
97 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
98 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
99 intdos (&inregs
, &outregs
);
100 return !outregs
.x
.cflag
;
103 /* Restore status of standard input and Ctrl-C checking. */
107 union REGS inregs
, outregs
;
109 setcbrk (break_stat
);
112 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
113 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
114 inregs
.x
.dx
= stdin_stat
;
115 intdos (&inregs
, &outregs
);
116 return !outregs
.x
.cflag
;
119 /* generate a reliable event timestamp, KFS 1995-07-06 */
137 static unsigned short
138 ibmpc_translate_map
[] =
140 /* --------------- 00 to 0f --------------- */
143 0xffb1, /* Keypad 1 */
144 0xffb2, /* Keypad 2 */
145 0xffb3, /* Keypad 3 */
146 0xffb4, /* Keypad 4 */
147 0xffb5, /* Keypad 5 */
148 0xffb6, /* Keypad 6 */
149 0xffb7, /* Keypad 7 */
150 0xffb8, /* Keypad 8 */
151 0xffb9, /* Keypad 9 */
152 0xffb0, /* Keypad 0 */
154 0xff08, /* Backspace */
155 0xff74, /* (Shift) Tab [Tab doesn't use this table] */
157 /* --------------- 10 to 1f --------------- */
158 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
159 0xff8d, /* Keypad Enter */
163 /* --------------- 20 to 2f --------------- */
164 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
166 '\\', 'z', 'x', 'c', 'v',
168 /* --------------- 30 to 3f --------------- */
169 'b', 'n', 'm', ',', '.',
182 /* --------------- 40 to 4f --------------- */
192 0xff55, /* Page Up */
195 0xffb5, /* Keypad 5 */
200 /* --------------- 50 to 5f --------------- */
202 0xff56, /* Page Down */
205 0xffbe, /* (Shift) F1 */
206 0xffbf, /* (Shift) F2 */
207 0xffc0, /* (Shift) F3 */
208 0xffc1, /* (Shift) F4 */
209 0xffc2, /* (Shift) F5 */
210 0xffc3, /* (Shift) F6 */
211 0xffc4, /* (Shift) F7 */
212 0xffc5, /* (Shift) F8 */
213 0xffc6, /* (Shift) F9 */
214 0xffc7, /* (Shift) F10 */
215 0xffbe, /* (Ctrl) F1 */
216 0xffbf, /* (Ctrl) F2 */
218 /* --------------- 60 to 6f --------------- */
219 0xffc0, /* (Ctrl) F3 */
220 0xffc1, /* (Ctrl) F4 */
221 0xffc2, /* (Ctrl) F5 */
222 0xffc3, /* (Ctrl) F6 */
223 0xffc4, /* (Ctrl) F7 */
224 0xffc5, /* (Ctrl) F8 */
225 0xffc6, /* (Ctrl) F9 */
226 0xffc7, /* (Ctrl) F10 */
227 0xffbe, /* (Alt) F1 */
228 0xffbf, /* (Alt) F2 */
229 0xffc0, /* (Alt) F3 */
230 0xffc1, /* (Alt) F4 */
231 0xffc2, /* (Alt) F5 */
232 0xffc3, /* (Alt) F6 */
233 0xffc4, /* (Alt) F7 */
234 0xffc5, /* (Alt) F8 */
236 /* --------------- 70 to 7f --------------- */
237 0xffc6, /* (Alt) F9 */
238 0xffc7, /* (Alt) F10 */
239 0xff6d, /* (Ctrl) Sys Rq */
240 0xff51, /* (Ctrl) Left */
241 0xff53, /* (Ctrl) Right */
242 0xff57, /* (Ctrl) End */
243 0xff56, /* (Ctrl) Page Down */
244 0xff50, /* (Ctrl) Home */
245 '1', '2', '3', '4', '5', '6', '7', '8', /* (Alt) */
247 /* --------------- 80 to 8f --------------- */
248 '9', '0', '-', '=', /* (Alt) */
249 0xff55, /* (Ctrl) Page Up */
252 0xffc8, /* (Shift) F11 */
253 0xffc9, /* (Shift) F12 */
254 0xffc8, /* (Ctrl) F11 */
255 0xffc9, /* (Ctrl) F12 */
256 0xffc8, /* (Alt) F11 */
257 0xffc9, /* (Alt) F12 */
258 0xff52, /* (Ctrl) Up */
259 0xffae, /* (Ctrl) Grey - */
260 0xffb5, /* (Ctrl) Keypad 5 */
262 /* --------------- 90 to 9f --------------- */
263 0xffab, /* (Ctrl) Grey + */
264 0xff54, /* (Ctrl) Down */
265 0xff63, /* (Ctrl) Insert */
266 0xffff, /* (Ctrl) Delete */
267 0xff09, /* (Ctrl) Tab */
268 0xffaf, /* (Ctrl) Grey / */
269 0xffaa, /* (Ctrl) Grey * */
270 0xff50, /* (Alt) Home */
271 0xff52, /* (Alt) Up */
272 0xff55, /* (Alt) Page Up */
274 0xff51, /* (Alt) Left */
276 0xff53, /* (Alt) Right */
278 0xff57, /* (Alt) End */
280 /* --------------- a0 to af --------------- */
281 0xff54, /* (Alt) Down */
282 0xff56, /* (Alt) Page Down */
283 0xff63, /* (Alt) Insert */
284 0xffff, /* (Alt) Delete */
285 0xffaf, /* (Alt) Grey / */
286 0xff09, /* (Alt) Tab */
287 0xff0d /* (Alt) Enter */
290 /* Get a char from keyboard. Function keys are put into the event queue. */
294 struct input_event event
;
296 int ctrl_p
, alt_p
, shift_p
;
298 /* Calculate modifier bits */
299 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
300 int86 (0x16, ®s
, ®s
);
301 ctrl_p
= ((regs
.h
.al
& 4) != 0);
302 shift_p
= ((regs
.h
.al
& 3) != 0);
303 /* Please be very careful here not to break international keyboard support.
304 When Keyb.Com is loaded, the key marked `Alt Gr' is used for accessing
305 characters like { and } if their positions are overlaid. */
306 alt_p
= ((extended_kbd
? (regs
.h
.ah
& 2) : (regs
.h
.al
& 8)) != 0);
308 /* The following condition is equivalent to `kbhit ()', except that
309 it uses the bios to do its job. This pleases DESQview/X. */
310 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
311 int86 (0x16, ®s
, ®s
),
312 (regs
.x
.flags
& 0x40) == 0)
315 register unsigned char c
;
318 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
319 int86 (0x16, ®s
, ®s
);
323 /* Determine from the scan code if a keypad key was pressed. */
324 if (c
>= '0' && c
<= '9' && sc
> 0xb)
325 sc
= (c
== '0') ? 0xb : (c
- '0' + 1), c
= 0;
326 else if (sc
== 0x53 && c
!= 0xe0)
328 code
= 0xffae; /* Keypad decimal point/comma. */
335 case 10: /* Ctrl Enter */
351 || (ctrl_p
&& shift_p
)
352 || (c
== 0xe0 && sc
!= 0) /* Pseudo-key */
353 || sc
== 0x37 /* Grey * */
354 || sc
== 0x4a /* Grey - */
355 || sc
== 0x4e /* Grey + */
356 || sc
== 0x0e) /* Back space *key*, not Ctrl-h */
358 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
361 code
= ibmpc_translate_map
[sc
];
367 event
.kind
= non_ascii_keystroke
;
368 event
.code
= (code
& 0xff) + 0xff00;
372 /* Don't return S- if we don't have to. `shifted' is
373 supposed to be the shifted versions of the characters
374 in `unshifted'. Unfortunately, this is only true for
375 US keyboard layout. If anyone knows how to do this
376 right, please tell us. */
377 static char *unshifted
378 = "abcdefghijklmnopqrstuvwxyz,./=;[\\]'-`0123456789";
380 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ<>?+:{|}\"_~)!@#$%^&*(";
383 if (shift_p
&& (pos
= strchr (unshifted
, code
)))
385 c
= shifted
[pos
- unshifted
];
389 if (c
== 0) c
= code
;
390 event
.kind
= ascii_keystroke
;
394 = (shift_p
? shift_modifier
: 0)
395 + (ctrl_p
? ctrl_modifier
: 0)
396 + (alt_p
? meta_modifier
: 0);
397 /* EMACS == Enter Meta Alt Control Shift */
398 XSETFRAME (event
.frame_or_window
, selected_frame
);
399 event
.timestamp
= event_timestamp ();
400 kbd_buffer_store_event (&event
);
408 int but
, press
, x
, y
, ok
;
410 /* Check for mouse movement *before* buttons. */
411 mouse_check_moved ();
413 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
414 for (press
= 0; press
< 2; press
++)
417 ok
= mouse_pressed (but
, &x
, &y
);
419 ok
= mouse_released (but
, &x
, &y
);
422 event
.kind
= mouse_click
;
425 = (shift_p
? shift_modifier
: 0)
426 + (ctrl_p
? ctrl_modifier
: 0)
427 + (alt_p
? meta_modifier
: 0)
428 + (press
? down_modifier
: up_modifier
);
431 XSETFRAME (event
.frame_or_window
, selected_frame
);
432 event
.timestamp
= event_timestamp ();
433 kbd_buffer_store_event (&event
);
441 static int prev_get_char
= -1;
443 /* Return 1 if a key is ready to be read without suspending execution. */
446 if (prev_get_char
!= -1)
449 return ((prev_get_char
= dos_rawgetc ()) != -1);
452 /* Read a key. Return -1 if no key is ready. */
455 if (prev_get_char
!= -1)
457 int c
= prev_get_char
;
462 return dos_rawgetc ();
465 /* Hostnames for a pc are not really funny, but they are used in change log
466 so we emulate the best we can. */
467 gethostname (p
, size
)
471 char *q
= egetenv ("HOSTNAME");
478 /* Destructively turn backslashes into slashes. */
480 dostounix_filename (p
)
491 /* Destructively turn slashes into backslashes. */
493 unixtodos_filename (p
)
504 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
506 getdefdir (drive
, dst
)
514 regs
.x
.si
= (int) dst
;
516 intdos (®s
, ®s
);
517 return !regs
.x
.cflag
;
520 /* Remove all CR's that are followed by a LF. */
524 register unsigned char *buf
;
526 unsigned char *np
= buf
;
527 unsigned char *startp
= buf
;
528 unsigned char *endp
= buf
+ n
;
533 while (buf
< endp
- 1)
537 if (*(++buf
) != 0x0a)
549 /* Run command as specified by ARGV in directory DIR.
550 The command is run with input from TEMPIN and output to file TEMPOUT. */
552 run_msdos_command (argv
, dir
, tempin
, tempout
)
553 unsigned char **argv
;
557 char *saveargv1
, *saveargv2
, **envv
;
558 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
559 int msshell
, result
= -1;
560 int in
, out
, inbak
, outbak
, errbak
;
564 /* Get current directory as MSDOS cwd is not per-process. */
567 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
568 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
569 && !strcmp ("-c", argv
[1]);
577 char *p
= alloca (strlen (argv
[2]) + 1);
579 strcpy (argv
[2] = p
, saveargv2
);
580 while (*p
&& isspace (*p
))
582 while (*p
&& !isspace (*p
))
590 /* Build the environment array. */
592 extern Lisp_Object Vprocess_environment
;
593 Lisp_Object tmp
, lst
;
596 lst
= Vprocess_environment
;
597 len
= XFASTINT (Flength (lst
));
599 envv
= alloca ((len
+ 1) * sizeof (char *));
600 for (i
= 0; i
< len
; i
++)
604 CHECK_STRING (tmp
, 0);
605 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
606 strcpy (envv
[i
], XSTRING (tmp
)->data
);
608 envv
[len
] = (char *) 0;
612 chdir (XSTRING (dir
)->data
);
616 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
617 goto done
; /* Allocation might fail due to lack of descriptors. */
621 mouse_get_xy (&x
, &y
);
624 dos_ttcooked(); /* do it here while 0 = stdin */
630 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
640 if (have_mouse
> 0) {
659 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
664 /* A list of unimplemented functions that we silently ignore. */
665 unsigned alarm (s
) unsigned s
; {}
666 fork () { return 0; }
667 int kill (x
, y
) int x
, y
; { return -1; }
669 void volatile pause () {}
671 setpgrp () {return 0; }
672 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
673 sigsetmask (x
) int x
; { return 0; }
674 unrequest_sigio () {}
684 int len
= strlen (path
);
685 char *tmp
= (char *)path
;
686 /* Gotta do this extern here due to the corresponding #define: */
689 if (*tmp
&& tmp
[1] == ':')
691 if (getdisk () != tolower (tmp
[0]) - 'a')
692 setdisk (tolower (tmp
[0]) - 'a');
693 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
697 if (len
> 1 && (tmp
[len
- 1] == '/'))
699 char *tmp1
= (char *) alloca (len
+ 1);
708 #include "sysselect.h"
710 /* Only event queue is checked. */
712 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
714 SELECT_TYPE
*rfds
, *wfds
, *efds
;
718 long timeoutval
, clnow
, cllast
;
732 if (nfds
!= 1 || !FD_ISSET (0, &orfds
))
735 /* If we are looking only for the terminal, with no timeout,
736 just read it and wait -- that's more efficient. */
739 while (! detect_input_pending ());
743 timeoutval
= EMACS_SECS (*timeout
) * 100 + EMACS_USECS (*timeout
) / 10000;
745 cllast
= t
.ti_sec
* 100 + t
.ti_hund
;
747 while (!detect_input_pending ())
750 clnow
= t
.ti_sec
* 100 + t
.ti_hund
;
751 if (clnow
< cllast
) /* time wrap */
752 timeoutval
-= clnow
+ 6000 - cllast
;
754 timeoutval
-= clnow
- cllast
;
755 if (timeoutval
<= 0) /* Stop on timer being cleared */
766 /* The Emacs root directory as determined by init_environment. */
767 static char emacsroot
[MAXPATHLEN
];
770 rootrelativepath (rel
)
773 static char result
[MAXPATHLEN
+ 10];
775 strcpy (result
, emacsroot
);
776 strcat (result
, "/");
777 strcat (result
, rel
);
781 /* Define a lot of environment variables if not already defined. Don't
782 remove anything unless you know what you're doing -- lots of code will
783 break if one or more of these are missing. */
785 init_environment (argc
, argv
, skip_args
)
793 /* Find our root from argv[0]. Assuming argv[0] is, say,
794 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
795 root
= alloca (MAXPATHLEN
+ 20);
796 _fixpath (argv
[0], root
);
799 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
802 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
803 root
[len
- 4] = '\0';
805 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
807 strcpy (emacsroot
, root
);
809 /* We default HOME to our root. */
810 setenv ("HOME", root
, 0);
812 /* We default EMACSPATH to root + "/bin". */
813 strcpy (root
+ len
, "/bin");
814 setenv ("EMACSPATH", root
, 0);
816 /* I don't expect anybody to ever use other terminals so the internal
817 terminal is the default. */
818 setenv ("TERM", "internal", 0);
820 #ifdef HAVE_X_WINDOWS
821 /* Emacs expects DISPLAY to be set. */
822 setenv ("DISPLAY", "unix:0.0", 0);
825 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
826 downcase it and mirror the backslashes. */
827 s
= getenv ("COMSPEC");
828 if (!s
) s
= "c:/command.com";
829 t
= alloca (strlen (s
) + 1);
832 dostounix_filename (t
);
833 setenv ("SHELL", t
, 0);
835 /* PATH is also downcased and backslashes mirrored. */
838 t
= alloca (strlen (s
) + 3);
839 /* Current directory is always considered part of MsDos's path but it is
840 not normally mentioned. Now it is. */
841 strcat (strcpy (t
, ".;"), s
);
843 dostounix_filename (t
); /* Not a single file name, but this should work. */
844 setenv ("PATH", t
, 1);
846 /* In some sense all dos users have root privileges, so... */
847 setenv ("USER", "root", 0);
848 setenv ("NAME", getenv ("USER"), 0);
850 /* Time zone determined from country code. To make this possible, the
851 country code may not span more than one time zone. In other words,
852 in the USA, you lose. */
853 switch (dos_country_code
)
855 case 31: /* Belgium */
856 case 32: /* The Netherlands */
857 case 33: /* France */
859 case 36: /* Hungary */
860 case 38: /* Yugoslavia (or what's left of it?) */
862 case 41: /* Switzerland */
863 case 42: /* Tjekia */
864 case 45: /* Denmark */
865 case 46: /* Sweden */
866 case 47: /* Norway */
867 case 48: /* Poland */
868 case 49: /* Germany */
869 /* Daylight saving from last Sunday in March to last Sunday in
870 September, both at 2AM. */
871 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
873 case 44: /* United Kingdom */
874 case 351: /* Portugal */
875 case 354: /* Iceland */
876 setenv ("TZ", "GMT+00", 0);
880 setenv ("TZ", "???-09", 0);
882 case 90: /* Turkey */
883 case 358: /* Finland */
884 case 972: /* Israel */
885 setenv ("TZ", "EET-02", 0);
890 /* Flash the screen as a substitute for BEEPs. */
893 do_visible_bell (xorattr
)
894 unsigned char xorattr
;
899 movl _ScreenPrimary,%%eax
906 xorb %%al,%%gs:(%%ebx)
922 : "m" (xorattr
), "g" (ScreenCols () * ScreenRows ())
923 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
926 /* At screen position (X,Y), output C characters from string S with
927 attribute A. Do it fast! */
930 output_string (x
, y
, s
, c
, a
)
935 char *t
= (char *)ScreenPrimary
+ 2 * (x
+ ScreenCols () * y
);
939 fprintf (termscript
, "<%d@%dx%d>", c
, x
, y
);
940 fwrite (s
, sizeof (unsigned char), c
, termscript
);
952 movw %%ax,%%gs:(%%edi)
958 : "m" (a
), "g" (t
), "g" (c
), "g" (s
)
959 : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
962 static int internal_terminal
= 0;
963 static int highlight
;
967 static int /* number of characters used by escape; -1 if incomplete */
968 flush_escape (resume
, cp
, count
, xp
, yp
)
975 static char spaces
[] = " ";
976 static unsigned char esc_cmd
[8];
977 static int esc_count
= 0;
988 while (esc_count
< 2)
992 esc_cmd
[esc_count
++] = *cp
++;
1011 while (esc_count
< esc_needed
)
1015 esc_cmd
[esc_count
++] = *cp
++;
1026 ScreenAttrib
= esc_cmd
[2];
1029 do_visible_bell (esc_cmd
[2]);
1036 i
= ScreenCols () - *xp
;
1038 while (i
>= sizeof spaces
)
1040 output_string (j
, *yp
, spaces
, sizeof spaces
, ScreenAttrib
);
1045 output_string (j
, *yp
, spaces
, i
, ScreenAttrib
);
1054 ScreenAttrib
^= esc_cmd
[2];
1057 output_string (*xp
, *yp
, &esc_cmd
[1], 1, ScreenAttrib
);
1072 static int resume_esc
= 0;
1073 unsigned char *cp
, *cp0
;
1076 if (!internal_terminal
|| f
!= stdout
)
1078 /* This is a call to the original fflush. */
1085 count
= stdout
->_ptr
- stdout
->_base
;
1087 #ifdef DO_TERMSCRIPT
1089 fprintf (termscript
, "\n<FLUSH%s %d>\n", resume_esc
? " RESUME" : "", count
);
1094 i
= flush_escape (1, cp
, count
, &x
, &y
);
1110 i
= flush_escape (0, cp
, count
, &x
, &y
);
1123 write (1, "\007", 1);
1141 while (count
> 0 && *cp
>= ' ')
1143 output_string (x
, y
, cp0
, cp
- cp0
, ScreenAttrib
);
1148 ScreenSetCursor (y
, x
);
1152 #ifndef HAVE_X_WINDOWS
1156 /* Rien du tout, cela va sans dire! */
1164 /* This creates an xor-mask that will swap the default fore- and
1165 background colors. */
1167 do_visible_bell (((the_only_x_display
.foreground_pixel
1168 ^ the_only_x_display
.background_pixel
)
1173 /* Write it directly to ms-dos -- don't let it go through our terminal
1174 emulator. This way the mouse cursor won't blink. */
1175 write (1, "\007", 1);
1179 IT_set_face (int face
)
1182 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
1184 if (face
== 1 || (face
== 0 && highlight
))
1185 fp
= FRAME_MODE_LINE_FACE (foo
);
1186 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
1187 fp
= FRAME_DEFAULT_FACE (foo
);
1189 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
1190 #ifdef DO_TERMSCRIPT
1192 fprintf (termscript
, "<FACE:%d:%d>", FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
1196 putchar ((FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
));
1200 IT_write_glyphs (GLYPH
*str
, int len
)
1208 newface
= FAST_GLYPH_FACE (*str
);
1209 if (newface
!= face
)
1210 IT_set_face ((face
= newface
));
1211 ch
= FAST_GLYPH_CHAR (*str
);
1212 #ifdef DO_TERMSCRIPT
1214 fputc (ch
, termscript
);
1216 if (ch
== '\e') putchar (ch
); /* allow esc to be printed */
1223 IT_clear_end_of_line (first_unused
)
1226 #ifdef DO_TERMSCRIPT
1228 fprintf (termscript
, "<CLR:EOL>");
1235 IT_cursor_to (int y
, int x
)
1237 #ifdef DO_TERMSCRIPT
1239 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1247 IT_reassert_line_highlight (new, vpos
)
1251 IT_set_face (0); /* To possibly clear the highlighting. */
1255 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
1257 highlight
= new_highlight
;
1258 IT_set_face (0); /* To possibly clear the highlighting. */
1259 IT_cursor_to (vpos
, 0);
1260 IT_clear_end_of_line (first_unused_hpos
);
1267 IT_set_face (0); /* To possibly clear the highlighting. */
1270 /* This was more or less copied from xterm.c */
1272 IT_set_menu_bar_lines (window
, n
)
1276 struct window
*w
= XWINDOW (window
);
1278 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
1279 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
1281 /* Handle just the top child in a vertical split. */
1282 if (!NILP (w
->vchild
))
1283 IT_set_menu_bar_lines (w
->vchild
, n
);
1285 /* Adjust all children in a horizontal split. */
1286 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
1288 w
= XWINDOW (window
);
1289 IT_set_menu_bar_lines (window
, n
);
1294 IT_set_frame_parameters (frame
, alist
)
1300 extern unsigned long load_color ();
1301 FRAME_PTR f
= (FRAME_PTR
) &the_only_frame
;
1304 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1306 Lisp_Object elt
, prop
, val
;
1311 CHECK_SYMBOL (prop
, 1);
1313 if (EQ (prop
, intern ("foreground-color")))
1315 unsigned long new_color
= load_color (f
, val
);
1316 if (new_color
!= ~0)
1318 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1322 else if (EQ (prop
, intern ("background-color")))
1324 unsigned long new_color
= load_color (f
, val
);
1325 if (new_color
!= ~0)
1327 FRAME_BACKGROUND_PIXEL (f
) = new_color
& ~8;
1331 else if (EQ (prop
, intern ("menu-bar-lines")))
1334 int old
= FRAME_MENU_BAR_LINES (the_only_frame
);
1340 FRAME_MENU_BAR_LINES (f
) = new;
1341 IT_set_menu_bar_lines (the_only_frame
.root_window
, new - old
);
1347 recompute_basic_faces (f
);
1348 Fredraw_frame (Fselected_frame ());
1352 /* Similar to the_only_frame. */
1353 struct x_display the_only_x_display
;
1355 /* This is never dereferenced. */
1356 Display
*x_current_display
;
1358 #endif /* !HAVE_X_WINDOWS */
1360 /* Do we need the internal terminal? */
1362 internal_terminal_init ()
1364 char *term
= getenv ("TERM");
1367 #ifdef HAVE_X_WINDOWS
1368 if (!inhibit_window_system
)
1373 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1375 #ifndef HAVE_X_WINDOWS
1376 if (internal_terminal
&& !inhibit_window_system
)
1378 Vwindow_system
= intern ("pc");
1379 Vwindow_system_version
= make_number (1);
1381 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1382 the_only_x_display
.background_pixel
= 7; /* White */
1383 the_only_x_display
.foreground_pixel
= 0; /* Black */
1384 colors
= getenv ("EMACSCOLORS");
1385 if (colors
&& strlen (colors
) >=2)
1387 the_only_x_display
.foreground_pixel
= colors
[0] & 0x07;
1388 the_only_x_display
.background_pixel
= colors
[1] & 0x07;
1390 the_only_x_display
.line_height
= 1;
1391 the_only_frame
.display
.x
= &the_only_x_display
;
1392 the_only_frame
.output_method
= output_msdos_raw
;
1394 init_frame_faces ((FRAME_PTR
) &the_only_frame
);
1396 ring_bell_hook
= IT_ring_bell
;
1397 write_glyphs_hook
= IT_write_glyphs
;
1398 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1399 clear_end_of_line_hook
= IT_clear_end_of_line
;
1400 change_line_highlight_hook
= IT_change_line_highlight
;
1401 update_begin_hook
= IT_update_begin
;
1402 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1404 /* These hooks are called by term.c without being checked. */
1405 set_terminal_modes_hook
1406 = reset_terminal_modes_hook
1408 = set_terminal_window_hook
1409 = (void *)rien_du_tout
;
1412 the_only_frame
.output_method
= output_termcap
;
1416 /* When time zones are set from Ms-Dos too may C-libraries are playing
1417 tricks with time values. We solve this by defining our own version
1418 of `gettimeofday' bypassing GO32. Our version needs to be initialized
1419 once and after each call to `tzset' with TZ changed. */
1421 static int daylight
, gmtoffset
;
1424 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
1433 /* If midnight occurs here, the results can be incorrect. */
1435 tmrec
.tm_year
= d
.da_year
- 1900;
1436 tmrec
.tm_mon
= d
.da_mon
- 1;
1437 tmrec
.tm_mday
= d
.da_day
;
1438 tmrec
.tm_hour
= t
.ti_hour
;
1439 tmrec
.tm_min
= t
.ti_min
;
1440 tmrec
.tm_sec
= t
.ti_sec
;
1441 tmrec
.tm_gmtoff
= gmtoffset
;
1442 tmrec
.tm_isdst
= daylight
;
1443 tp
->tv_sec
= mktime (&tmrec
);
1444 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
1446 /* Ignore tzp; it's obsolescent. */
1451 init_gettimeofday ()
1456 extern void tzset (void);
1461 ltm
= gtm
= time (NULL
);
1462 ltm
= mktime (lstm
= localtime (<m
));
1463 gtm
= mktime (gmtime (>m
));
1464 daylight
= lstm
->tm_isdst
;
1465 gmtoffset
= (int)(gtm
- ltm
) / 60;
1468 /* These must be global. */
1469 static _go32_dpmi_seginfo ctrl_break_vector
;
1470 static _go32_dpmi_registers ctrl_break_regs
;
1471 static int ctrlbreakinstalled
= 0;
1473 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
1475 ctrl_break_func (regs
)
1476 _go32_dpmi_registers
*regs
;
1482 install_ctrl_break_check ()
1484 if (!ctrlbreakinstalled
)
1486 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
1487 was compiler with Djgpp 1.11 maintenance level 5 or later! */
1488 ctrlbreakinstalled
= 1;
1489 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
1490 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
1492 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
1496 /* Mouse routines follow. Coordinates are in screen positions and zero
1497 based. Mouse buttons are numbered from left to right and also zero
1500 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
1501 static int mouse_button_count
;
1510 regs
.x
.dx
= 8 * (ScreenCols () - 1);
1511 int86 (0x33, ®s
, ®s
);
1515 regs
.x
.dx
= 8 * (ScreenRows () - 1);
1516 int86 (0x33, ®s
, ®s
);
1518 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
1530 int86 (0x33, ®s
, ®s
);
1542 int86 (0x33, ®s
, ®s
);
1553 mouse_last_x
= regs
.x
.cx
= x
* 8;
1554 mouse_last_y
= regs
.x
.dx
= y
* 8;
1555 int86 (0x33, ®s
, ®s
);
1559 mouse_pressed (b
, xp
, yp
)
1564 if (b
>= mouse_button_count
)
1567 regs
.x
.bx
= mouse_button_translate
[b
];
1568 int86 (0x33, ®s
, ®s
);
1570 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
1571 return (regs
.x
.bx
!= 0);
1575 mouse_released (b
, xp
, yp
)
1580 if (b
>= mouse_button_count
)
1583 regs
.x
.bx
= mouse_button_translate
[b
];
1584 int86 (0x33, ®s
, ®s
);
1586 if (regs
.x
.ax
& (1 << mouse_button_translate
[b
]))
1587 regs
.x
.bx
= 0; /* if mouse is still pressed, ignore release */
1590 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
1591 return (regs
.x
.bx
!= 0);
1595 mouse_get_xy (int *x
, int *y
)
1600 int86 (0x33, ®s
, ®s
);
1606 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
1609 Lisp_Object
*bar_window
, *x
, *y
;
1610 enum scroll_bar_part
*part
;
1611 unsigned long *time
;
1617 int86 (0x33, ®s
, ®s
);
1618 *f
= selected_frame
;
1620 mouse_get_xy (&ix
, &iy
);
1621 selected_frame
->mouse_moved
= 0;
1622 *x
= make_number (ix
);
1623 *y
= make_number (iy
);
1624 *time
= event_timestamp ();
1628 mouse_check_moved ()
1632 mouse_get_xy (&x
, &y
);
1633 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
1644 #ifdef HAVE_X_WINDOWS
1645 if (!inhibit_window_system
)
1648 if (!internal_terminal
)
1652 int86 (0x33, ®s
, ®s
);
1653 present
= (regs
.x
.ax
& 0xffff) == 0xffff;
1656 /* Reportedly, the above doesn't work for some mouse drivers. There
1657 is an additional detection method that should work, but might be
1658 a little slower. Use that as an alternative. */
1660 int86 (0x33, ®s
, ®s
);
1661 present
= (regs
.x
.ax
& 0xffff) == 0xffff;
1668 mouse_button_count
= 3;
1669 mouse_button_translate
[0] = 0; /* Left */
1670 mouse_button_translate
[1] = 2; /* Middle */
1671 mouse_button_translate
[2] = 1; /* Right */
1675 mouse_button_count
= 2;
1676 mouse_button_translate
[0] = 0;
1677 mouse_button_translate
[1] = 1;
1679 mouse_position_hook
= &mouse_get_pos
;
1685 #ifndef HAVE_X_WINDOWS
1686 /* See xterm.c for more info. */
1688 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1690 register int pix_x
, pix_y
;
1691 register int *x
, *y
;
1692 void /* XRectangle */ *bounds
;
1695 if (bounds
) abort ();
1697 /* Ignore clipping. */
1704 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1707 register int *pix_x
, *pix_y
;
1713 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1716 Actually, I don't know the meaning of all the parameters of the functions
1717 here -- I only know how they are called by xmenu.c. I could of course
1718 grab the nearest Xlib manual (down the hall, second-to-last door on the
1719 left), but I don't think it's worth the effort. */
1726 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1727 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1731 /* Allocate some (more) memory for MENU ensuring that there is room for one
1735 IT_menu_make_room (XMenu
*menu
)
1737 if (menu
->allocated
== 0)
1739 int count
= menu
->allocated
= 10;
1740 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1741 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1742 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1744 else if (menu
->allocated
== menu
->count
)
1746 int count
= menu
->allocated
= menu
->allocated
+ 10;
1748 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1750 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1752 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1756 /* Search the given menu structure for a given pane number. */
1759 IT_menu_search_pane (XMenu
*menu
, int pane
)
1764 for (i
= 0; i
< menu
->count
; i
++)
1765 if (menu
->submenu
[i
])
1767 if (pane
== menu
->panenumber
[i
])
1768 return menu
->submenu
[i
];
1769 else if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1775 /* Determine how much screen space a given menu needs. */
1778 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1780 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1783 maxheight
= menu
->count
;
1784 for (i
= 0; i
< menu
->count
; i
++)
1786 if (menu
->submenu
[i
])
1788 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1789 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1790 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1793 *width
= menu
->width
+ maxsubwidth
;
1794 *height
= maxheight
;
1797 /* Display MENU at (X,Y) using FACES. */
1800 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1802 int i
, j
, face
, width
;
1806 int enabled
, mousehere
;
1809 width
= menu
->width
;
1810 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1811 ScreenGetCursor (&row
, &col
);
1812 mouse_get_xy (&mx
, &my
);
1814 (*update_begin_hook
) ();
1815 for (i
= 0; i
< menu
->count
; i
++)
1817 (*cursor_to_hook
) (y
+ i
, x
);
1819 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1820 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1821 face
= faces
[enabled
+ mousehere
* 2];
1823 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1824 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1825 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1826 for (; j
< width
; j
++)
1827 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1828 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1829 (*write_glyphs_hook
) (text
, width
+ 2);
1831 internal_flush (stdout
);
1832 (*update_end_hook
) ();
1834 ScreenSetCursor (row
, col
);
1838 /* Create a brand new menu structure. */
1841 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1843 return IT_menu_create ();
1846 /* Create a new pane and place it on the outer-most level. It is not
1847 clear that it should be placed out there, but I don't know what else
1851 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1858 IT_menu_make_room (menu
);
1859 menu
->submenu
[menu
->count
] = IT_menu_create ();
1860 menu
->text
[menu
->count
] = txt
;
1861 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1863 if ((len
= strlen (txt
)) > menu
->width
)
1865 return menu
->panecount
;
1868 /* Create a new item in a menu pane. */
1871 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1872 int foo
, char *txt
, int enable
)
1877 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1879 IT_menu_make_room (menu
);
1880 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1881 menu
->text
[menu
->count
] = txt
;
1882 menu
->panenumber
[menu
->count
] = enable
;
1884 if ((len
= strlen (txt
)) > menu
->width
)
1889 /* Decide where the menu would be placed if requested at (X,Y). */
1892 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1893 int *ulx
, int *uly
, int *width
, int *height
)
1895 if (menu
->count
== 1 && menu
->submenu
[0])
1896 /* Special case: the menu consists of only one pane. */
1897 IT_menu_calc_size (menu
->submenu
[0], width
, height
);
1899 IT_menu_calc_size (menu
, width
, height
);
1905 struct IT_menu_state
1907 void *screen_behind
;
1914 /* Display menu, wait for user's response, and return that response. */
1917 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1918 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1920 struct IT_menu_state
*state
;
1924 int faces
[4], selectface
;
1925 int leave
, result
, onepane
;
1927 /* Just in case we got here without a mouse present... */
1928 if (have_mouse
<= 0)
1929 return XM_IA_SELECT
;
1931 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1932 screensize
= ScreenRows () * ScreenCols () * 2;
1934 = compute_glyph_face (&the_only_frame
,
1937 intern ("msdos-menu-passive-face")),
1940 = compute_glyph_face (&the_only_frame
,
1943 intern ("msdos-menu-active-face")),
1946 = face_name_id_number (&the_only_frame
, intern ("msdos-menu-select-face"));
1947 faces
[2] = compute_glyph_face (&the_only_frame
, selectface
, faces
[0]);
1948 faces
[3] = compute_glyph_face (&the_only_frame
, selectface
, faces
[1]);
1951 state
[0].menu
= menu
;
1953 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
1955 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
1957 menu
->width
= menu
->submenu
[0]->width
;
1958 state
[0].menu
= menu
->submenu
[0];
1962 state
[0].menu
= menu
;
1964 state
[0].x
= x0
- 1;
1966 state
[0].pane
= onepane
;
1968 mouse_last_x
= -1; /* A hack that forces display. */
1972 mouse_check_moved ();
1973 if (selected_frame
->mouse_moved
)
1975 selected_frame
->mouse_moved
= 0;
1976 result
= XM_IA_SELECT
;
1977 mouse_get_xy (&x
, &y
);
1978 for (i
= 0; i
< statecount
; i
++)
1979 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
1981 int dy
= y
- state
[i
].y
;
1982 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
1984 if (!state
[i
].menu
->submenu
[dy
])
1985 if (state
[i
].menu
->panenumber
[dy
])
1986 result
= XM_SUCCESS
;
1988 result
= XM_IA_SELECT
;
1989 *pane
= state
[i
].pane
- 1;
1991 /* We hit some part of a menu, so drop extra menues that
1992 have been opened. That does not include an open and
1994 if (i
!= statecount
- 2
1995 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
1996 while (i
!= statecount
- 1)
2000 ScreenUpdate (state
[statecount
].screen_behind
);
2002 xfree (state
[statecount
].screen_behind
);
2004 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2006 IT_menu_display (state
[i
].menu
,
2010 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2011 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2013 ScreenRetrieve (state
[statecount
].screen_behind
2014 = xmalloc (screensize
));
2017 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2018 state
[statecount
].y
= y
;
2023 IT_menu_display (state
[statecount
- 1].menu
,
2024 state
[statecount
- 1].y
,
2025 state
[statecount
- 1].x
,
2028 for (b
= 0; b
< mouse_button_count
; b
++)
2030 (void) mouse_pressed (b
, &x
, &y
);
2031 if (mouse_released (b
, &x
, &y
))
2037 ScreenUpdate (state
[0].screen_behind
);
2039 while (statecount
--)
2040 xfree (state
[statecount
].screen_behind
);
2044 /* Dispose of a menu. */
2047 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2050 if (menu
->allocated
)
2052 for (i
= 0; i
< menu
->count
; i
++)
2053 if (menu
->submenu
[i
])
2054 XMenuDestroy (foo
, menu
->submenu
[i
]);
2056 xfree (menu
->submenu
);
2057 xfree (menu
->panenumber
);
2063 x_pixel_width (struct frame
*f
)
2065 return FRAME_WIDTH (f
);
2069 x_pixel_height (struct frame
*f
)
2071 return FRAME_HEIGHT (f
);
2073 #endif /* !HAVE_X_WINDOWS */