(x_mouse_leave): Add neutralizing define.
[bpt/emacs.git] / src / msdos.c
CommitLineData
9da6e765
RS
1/* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
1b94449f
RS
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
9da6e765
RS
20/* Contributed by Morten Welinder */
21
1b94449f
RS
22/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
23
48984716 24#include <config.h>
1b94449f
RS
25
26#ifdef MSDOS
27#include "lisp.h"
28#include <stdio.h>
29#include <stdlib.h>
30#include <sys/param.h>
31#include <sys/time.h>
32#include <dos.h>
33#include "dosfns.h"
34#include "msdos.h"
35#include "systime.h"
36#include "termhooks.h"
87485d6f
MW
37#include "dispextern.h"
38#include "termopts.h"
1b94449f 39#include "frame.h"
87485d6f 40#include "window.h"
1b94449f
RS
41#include <go32.h>
42#include <pc.h>
43#include <ctype.h>
44/* #include <process.h> */
45/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
46#define P_WAIT 1
47
48static int break_stat; /* BREAK check mode status. */
49static int stdin_stat; /* stdin IOCTL status. */
50static int extended_kbd; /* 101 (102) keyboard present. */
51
52int have_mouse; /* Mouse present? */
53static int mouse_last_x;
54static int mouse_last_y;
55
56/* Turn off Dos' Ctrl-C checking and inhibit interpretation of control chars
57 by Dos. Determine the keyboard type. */
58int
59dos_ttraw ()
60{
61 union REGS inregs, outregs;
62
63 inregs.h.ah = 0xc0;
64 int86 (0x15, &inregs, &outregs);
65 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
66
67 break_stat = getcbrk ();
68 setcbrk (0);
69 install_ctrl_break_check ();
49a09c76 70 have_mouse = mouse_init1 ();
1b94449f
RS
71
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;
76
77 inregs.x.dx = (outregs.x.dx | 0x0020) & 0x0027; /* raw mode */
78 inregs.h.al = 0x01;
79 intdos (&inregs, &outregs);
80 return !outregs.x.cflag;
81}
82
83/* Restore status of standard input and Ctrl-C checking. */
84int
85dos_ttcooked ()
86{
87 union REGS inregs, outregs;
88
89 setcbrk (break_stat);
49a09c76 90 if (have_mouse) mouse_off ();
1b94449f
RS
91
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;
97}
98
99static unsigned short
100ibmpc_translate_map[] =
101{
102 /* --------------- 00 to 0f --------------- */
103 0, /* Ctrl Break */
104 0xff1b, /* Escape */
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 */
115 '-', '=',
116 0xff08, /* Backspace */
117 0xff74, /* (Shift) Tab [Tab doesn't use this table] */
118
119 /* --------------- 10 to 1f --------------- */
120 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
121 0xff8d, /* Keypad Enter */
122 0, /* Ctrl */
123 'a', 's',
124
125 /* --------------- 20 to 2f --------------- */
126 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
127 0, /* Left shift */
128 '\\', 'z', 'x', 'c', 'v',
129
130 /* --------------- 30 to 3f --------------- */
131 'b', 'n', 'm', ',', '.',
132 0xffaf, /* Grey / */
133 0, /* Right shift */
134 0xffaa, /* Grey * */
135 0, /* Alt */
136 ' ',
137 0, /* Caps Lock */
138 0xffbe, /* F1 */
139 0xffbf, /* F2 */
140 0xffc0, /* F3 */
141 0xffc1, /* F4 */
142 0xffc2, /* F5 */
143
144 /* --------------- 40 to 4f --------------- */
145 0xffc3, /* F6 */
146 0xffc4, /* F7 */
147 0xffc5, /* F8 */
148 0xffc6, /* F9 */
149 0xffc7, /* F10 */
150 0, /* Num Lock */
151 0, /* Scroll Lock */
152 0xff50, /* Home */
153 0xff52, /* Up */
154 0xff55, /* Page Up */
155 0xffad, /* Grey - */
156 0xff51, /* Left */
157 0xffb5, /* Keypad 5 */
158 0xff53, /* Right */
159 0xffab, /* Grey + */
160 0xff57, /* End */
161
162 /* --------------- 50 to 5f --------------- */
163 0xff54, /* Down */
164 0xff56, /* Page Down */
165 0xff63, /* Insert */
166 0xffff, /* Delete */
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 */
179
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 */
197
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) */
208
209 /* --------------- 80 to 8f --------------- */
210 '9', '0', '-', '=', /* (Alt) */
211 0xff55, /* (Ctrl) Page Up */
212 0xffc8, /* F11 */
213 0xffc9, /* F12 */
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 */
223
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 */
235 0, /* NO KEY */
236 0xff51, /* (Alt) Left */
237 0, /* NO KEY */
238 0xff53, /* (Alt) Right */
239 0, /* NO KEY */
240 0xff57, /* (Alt) End */
241
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 */
250};
251
252/* Get a char from keyboard. Function keys are put into the event queue. */
253static int
254dos_rawgetc ()
255{
256 struct input_event event;
257 struct timeval tv;
258 union REGS regs;
259 int ctrl_p, alt_p, shift_p;
260
261 /* Calculate modifier bits */
262 regs.h.ah = extended_kbd ? 0x12 : 0x02;
263 int86 (0x16, &regs, &regs);
264 ctrl_p = ((regs.h.al & 4) != 0);
265 shift_p = ((regs.h.al & 3) != 0);
9da6e765
RS
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. */
1b94449f
RS
269 alt_p = ((extended_kbd ? (regs.h.ah & 2) : (regs.h.al & 8)) != 0);
270
3ec5651b
RS
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, &regs, &regs),
275 (regs.x.flags & 0x40) == 0)
1b94449f
RS
276 {
277 union REGS regs;
278 register unsigned char c;
279 int sc, code;
280
281 regs.h.ah = extended_kbd ? 0x10 : 0x00;
282 int86 (0x16, &regs, &regs);
283 c = regs.h.al;
284 sc = regs.h.ah;
285
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;
9da6e765
RS
289 else if (sc == 0x53 && c != 0xe0)
290 {
291 code = 0xffae; /* Keypad decimal point/comma. */
292 goto nonascii;
293 }
1b94449f
RS
294 else if (sc == 0xe0)
295 {
296 switch (c)
297 {
298 case 10: /* Ctrl Enter */
299 case 13:
300 sc = 0x1c;
301 break;
1b94449f
RS
302 case '/':
303 sc = 0x35;
304 break;
305 default:
306 sc = 0;
307 };
308 c = 0;
309 }
310
311 if (c == 0
312 || c == ' '
313 || alt_p
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 */
320 {
321 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
322 code = 0;
323 else
324 code = ibmpc_translate_map[sc];
325 if (code != 0)
326 {
327 if (code >= 0x100)
328 {
9da6e765 329 nonascii:
1b94449f 330 event.kind = non_ascii_keystroke;
49a09c76 331 event.code = (code & 0xff) + 0xff00;
1b94449f
RS
332 }
333 else
334 {
9da6e765
RS
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";
342 static char *shifted
343 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ<>?+:{|}\"_~)!@#$%^&*(";
344 char *pos;
345
346 if (shift_p && (pos = strchr (unshifted, code)))
1b94449f 347 {
9da6e765 348 c = shifted[pos - unshifted];
1b94449f
RS
349 shift_p = 0;
350 }
351 else
352 if (c == 0) c = code;
353 event.kind = ascii_keystroke;
354 event.code = c;
355 }
356 event.modifiers
9da6e765
RS
357 = (shift_p ? shift_modifier : 0)
358 + (ctrl_p ? ctrl_modifier : 0)
359 + (alt_p ? meta_modifier : 0);
1b94449f 360 /* EMACS == Enter Meta Alt Control Shift */
87485d6f 361 XSETFRAME (event.frame_or_window, selected_frame);
1b94449f
RS
362 gettimeofday (&tv, NULL);
363 event.timestamp = tv.tv_usec;
364 kbd_buffer_store_event (&event);
365 }
366 } else
367 return c;
368 }
369
370 if (have_mouse)
371 {
372 int but, press, x, y, ok;
373
374 /* Check for mouse movement *before* buttons. */
49a09c76 375 mouse_check_moved ();
1b94449f
RS
376
377 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
378 for (press = 0; press < 2; press++)
379 {
380 if (press)
49a09c76 381 ok = mouse_pressed (but, &x, &y);
1b94449f 382 else
49a09c76 383 ok = mouse_released (but, &x, &y);
1b94449f
RS
384 if (ok)
385 {
386 event.kind = mouse_click;
387 event.code = but;
388 event.modifiers
9da6e765
RS
389 = (shift_p ? shift_modifier : 0)
390 + (ctrl_p ? ctrl_modifier : 0)
391 + (alt_p ? meta_modifier : 0)
392 + (press ? down_modifier : up_modifier);
1b94449f
RS
393 event.x = x;
394 event.y = y;
87485d6f 395 XSETFRAME (event.frame_or_window, selected_frame);
1b94449f
RS
396 gettimeofday (&tv, NULL);
397 event.timestamp = tv.tv_usec;
398 kbd_buffer_store_event (&event);
399 }
400 }
401 }
402
403 return -1;
404}
405
406static int prev_get_char = -1;
407
408/* Return 1 if a key is ready to be read without suspending execution. */
409dos_keysns ()
410{
411 if (prev_get_char != -1)
412 return 1;
413 else
414 return ((prev_get_char = dos_rawgetc ()) != -1);
415}
416
417/* Read a key. Return -1 if no key is ready. */
418dos_keyread ()
419{
420 if (prev_get_char != -1)
421 {
422 int c = prev_get_char;
423 prev_get_char = -1;
424 return c;
425 }
426 else
427 return dos_rawgetc ();
428}
429
430/* Hostnames for a pc are not really funny, but they are used in change log
431 so we emulate the best we can. */
432gethostname (p, size)
433 char *p;
434 int size;
435{
436 char *q = egetenv ("HOSTNAME");
437
438 if (!q) q = "pc";
439 strcpy (p, q);
440 return 0;
441}
442
443/* Destructively turn backslashes into slashes. */
444void
445dostounix_filename (p)
446 register char *p;
447{
448 while (*p)
449 {
450 if (*p == '\\')
451 *p = '/';
452 p++;
453 }
454}
455
456/* Destructively turn slashes into backslashes. */
457void
458unixtodos_filename (p)
459 register char *p;
460{
461 while (*p)
462 {
463 if (*p == '/')
464 *p = '\\';
465 p++;
466 }
467}
468
469/* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
470int
471getdefdir (drive, dst)
472 int drive;
473 char *dst;
474{
475 union REGS regs;
476
477 *dst++ = '/';
478 regs.h.dl = drive;
479 regs.x.si = (int) dst;
480 regs.h.ah = 0x47;
481 intdos (&regs, &regs);
482 return !regs.x.cflag;
483}
484
485/* Remove all CR's that are followed by a LF. */
486int
487crlf_to_lf (n, buf)
488 register int n;
489 register unsigned char *buf;
490{
491 unsigned char *np = buf;
492 unsigned char *startp = buf;
493 unsigned char *endp = buf + n;
494 unsigned char c;
495
496 if (n == 0)
497 return n;
3d4ad6e0 498 while (buf < endp - 1)
1b94449f
RS
499 {
500 if (*buf == 0x0d)
501 {
502 if (*(++buf) != 0x0a)
503 *np++ = 0x0d;
504 }
505 else
506 *np++ = *buf++;
507 }
3d4ad6e0
RS
508 if (buf < endp)
509 *np++ = *buf++;
1b94449f
RS
510 return np - startp;
511}
512
513
514/* Run command as specified by ARGV in directory DIR.
515 The command is run with input from TEMPIN and output to file TEMPOUT. */
516int
517run_msdos_command (argv, dir, tempin, tempout)
518 unsigned char **argv;
519 Lisp_Object dir;
520 int tempin, tempout;
521{
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;
526 Lisp_Object cmd;
527
528 /* Get current directory as MSDOS cwd is not per-process. */
529 getwd (oldwd);
530
531 cmd = Ffile_name_nondirectory (build_string (argv[0]));
532 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
533 && !strcmp ("-c", argv[1]);
534 if (msshell)
535 {
536 saveargv1 = argv[1];
647c32eb 537 saveargv2 = argv[2];
1b94449f
RS
538 argv[1] = "/c";
539 if (argv[2])
540 {
647c32eb
KH
541 char *p = alloca (strlen (argv[2]) + 1);
542
543 strcpy (argv[2] = p, saveargv2);
544 while (*p && isspace (*p))
545 p++;
546 while (*p && !isspace (*p))
547 if (*p == '/')
548 *p++ = '\\';
549 else
550 p++;
1b94449f
RS
551 }
552 }
553
554 /* Build the environment array. */
555 {
556 extern Lisp_Object Vprocess_environment;
091d0bdf
KH
557 Lisp_Object tmp, lst;
558 int i, len;
559
560 lst = Vprocess_environment;
561 len = XFASTINT (Flength (lst));
1b94449f
RS
562
563 envv = alloca ((len + 1) * sizeof (char *));
564 for (i = 0; i < len; i++)
565 {
566 tmp = Fcar (lst);
567 lst = Fcdr (lst);
568 CHECK_STRING (tmp, 0);
569 envv[i] = alloca (XSTRING (tmp)->size + 1);
570 strcpy (envv[i], XSTRING (tmp)->data);
571 }
572 envv[len] = (char *) 0;
573 }
574
30d0f552 575 if (STRINGP (dir))
1b94449f
RS
576 chdir (XSTRING (dir)->data);
577 inbak = dup (0);
578 outbak = dup (1);
579 errbak = dup (2);
580 if (inbak < 0 || outbak < 0 || errbak < 0)
581 goto done; /* Allocation might fail due to lack of descriptors. */
582 dup2 (tempin, 0);
583 dup2 (tempout, 1);
584 dup2 (tempout, 2);
585 dos_ttcooked ();
586 result = spawnve (P_WAIT, argv[0], argv, envv);
587 dos_ttraw ();
588 dup2 (inbak, 0);
589 dup2 (outbak, 1);
590 dup2 (errbak, 2);
591
592 done:
593 chdir (oldwd);
594 if (msshell)
595 {
596 argv[1] = saveargv1;
647c32eb 597 argv[2] = saveargv2;
1b94449f
RS
598 }
599 return result;
600}
601
602
603croak (badfunc)
604 char *badfunc;
605{
606 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
607 reset_sys_modes ();
608 exit (1);
609}
610
611/* A list of unimplemented functions that we silently ignore. */
612unsigned alarm (s) unsigned s; {}
613fork () { return 0; }
614int kill (x, y) int x, y; { return -1; }
615nice (p) int p; {}
616void volatile pause () {}
617request_sigio () {}
618setpgrp () {return 0; }
619setpriority (x,y,z) int x,y,z; { return 0; }
620sigsetmask (x) int x; { return 0; }
621unrequest_sigio () {}
622
623#ifdef chdir
624#undef chdir
625#endif
626
627int
628sys_chdir (path)
629 const char* path;
630{
631 int len = strlen (path);
632 char *tmp = (char *) alloca (len + 1);
633 /* Gotta do this extern here due to the corresponding #define: */
634 extern int chdir ();
635
636 if (*path && path[1] == ':' && (getdisk () != tolower (path[0]) - 'a'))
637 setdisk (tolower (path[0]) - 'a');
638
639 strcpy (tmp, path);
640 if (strcmp (path, "/") && strcmp (path + 1, ":/") && (path[len - 1] == '/'))
641 tmp[len - 1] = 0;
642 return chdir (tmp);
643}
644
645/* Sleep SECS. If KBDOK also return immediately if a key is pressed. */
646void
647sleep_or_kbd_hit (secs, kbdok)
648 int secs, kbdok;
649{
650 long clnow, clthen;
651 struct timeval t;
652
653 gettimeofday (&t, NULL);
654 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
655 clthen = clnow + (100 * secs);
656
657 do
658 {
659 gettimeofday (&t, NULL);
660 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
661 if (kbdok && detect_input_pending ())
662 return;
663 }
664 while (clnow < clthen);
665}
666
88b28483
RS
667/* The Emacs root directory as determined by init_environment. */
668static char emacsroot[MAXPATHLEN];
669
670char *
671rootrelativepath (rel)
672 char *rel;
673{
674 static char result[MAXPATHLEN + 10];
675
676 strcpy (result, emacsroot);
677 strcat (result, "/");
678 strcat (result, rel);
679 return result;
680}
681
1b94449f
RS
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. */
685void
686init_environment (argc, argv, skip_args)
687 int argc;
688 char **argv;
689 int skip_args;
690{
88b28483
RS
691 char *s, *t, *root;
692 int len;
693
694 /* Find our root from argv[0]. Assuming argv[0] is, say,
695 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
87485d6f
MW
696 _fixpath (argv[0], root = alloca (MAXPATHLEN + 20));
697 strlwr (root);
698 len = strlen (root);
88b28483
RS
699 while (len > 0 && root[len] != '/' && root[len] != ':')
700 len--;
701 root[len] = '\0';
702 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
703 root[len - 4] = '\0';
1b94449f 704 else
88b28483
RS
705 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
706 len = strlen (root);
707 strcpy (emacsroot, root);
708
709 /* We default HOME to our root. */
710 setenv ("HOME", root, 0);
711
712 /* We default EMACSPATH to root + "/bin". */
713 strcpy (root + len, "/bin");
714 setenv ("EMACSPATH", root, 0);
1b94449f
RS
715
716 /* I don't expect anybody to ever use other terminals so the internal
717 terminal is the default. */
718 setenv ("TERM", "internal", 0);
719
87485d6f
MW
720#ifdef HAVE_X_WINDOWS
721 /* Emacs expects DISPLAY to be set. */
722 setenv ("DISPLAY", "unix:0.0", 0);
723#endif
724
1b94449f
RS
725 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
726 downcase it and mirror the backslashes. */
727 s = getenv ("COMSPEC");
728 if (!s) s = "c:/command.com";
729 t = alloca (strlen (s) + 1);
730 strcpy (t, s);
731 strlwr (t);
732 dostounix_filename (t);
733 setenv ("SHELL", t, 0);
734
735 /* PATH is also downcased and backslashes mirrored. */
736 s = getenv ("PATH");
737 if (!s) s = "";
738 t = alloca (strlen (s) + 3);
739 /* Current directory is always considered part of MsDos's path but it is
740 not normally mentioned. Now it is. */
741 strcat (strcpy (t, ".;"), s);
742 strlwr (t);
743 dostounix_filename (t); /* Not a single file name, but this should work. */
744 setenv ("PATH", t, 1);
745
746 /* In some sense all dos users have root privileges, so... */
747 setenv ("USER", "root", 0);
748 setenv ("NAME", getenv ("USER"), 0);
749
750 /* Time zone determined from country code. To make this possible, the
751 country code may not span more than one time zone. In other words,
752 in the USA, you lose. */
753 switch (dos_country_code)
754 {
755 case 31: /* Belgium */
756 case 32: /* The Netherlands */
757 case 33: /* France */
758 case 34: /* Spain */
759 case 36: /* Hungary */
760 case 38: /* Yugoslavia (or what's left of it?) */
761 case 39: /* Italy */
762 case 41: /* Switzerland */
763 case 42: /* Tjekia */
764 case 45: /* Denmark */
765 case 46: /* Sweden */
766 case 47: /* Norway */
767 case 48: /* Poland */
768 case 49: /* Germany */
769 /* Daylight saving from last Sunday in March to last Sunday in
770 September, both at 2AM. */
771 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
772 break;
773 case 44: /* United Kingdom */
774 case 351: /* Portugal */
775 case 354: /* Iceland */
776 setenv ("TZ", "GMT+00", 0);
777 break;
778 case 81: /* Japan */
779 case 82: /* Korea */
780 setenv ("TZ", "???-09", 0);
781 break;
782 case 90: /* Turkey */
783 case 358: /* Finland */
784 case 972: /* Israel */
785 setenv ("TZ", "EET-02", 0);
786 break;
787 }
788 tzset ();
b278e52a 789 init_gettimeofday ();
1b94449f
RS
790}
791
792/* Flash the screen as a substitute for BEEPs. */
793
49a09c76 794static void
fcea9cd4 795do_visible_bell (xorattr)
1b94449f
RS
796 unsigned char xorattr;
797{
49a09c76 798 asm volatile
ca986694 799 (" movb $1,%%dl
1b94449f 800visible_bell_0:
ca986694 801 movl _ScreenPrimary,%%eax
49a09c76 802 call dosmemsetup
ca986694
RS
803 movl %%eax,%%ebx
804 movl %1,%%ecx
805 movb %0,%%al
806 incl %%ebx
1b94449f 807visible_bell_1:
ca986694
RS
808 xorb %%al,%%gs:(%%ebx)
809 addl $2,%%ebx
810 decl %%ecx
49a09c76 811 jne visible_bell_1
ca986694 812 decb %%dl
49a09c76 813 jne visible_bell_3
1b94449f 814visible_bell_2:
ca986694
RS
815 movzwl %%ax,%%eax
816 movzwl %%ax,%%eax
817 movzwl %%ax,%%eax
818 movzwl %%ax,%%eax
819 decw %%cx
49a09c76
RS
820 jne visible_bell_2
821 jmp visible_bell_0
ca986694
RS
822visible_bell_3:"
823 : /* no output */
824 : "m" (xorattr), "g" (ScreenCols () * ScreenRows ())
825 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
826}
827
09e2ac30
RS
828/* At screen position (X,Y), output C characters from string S with
829 attribute A. Do it fast! */
830
831static void
832output_string (x, y, s, c, a)
833 int x, y, c;
834 unsigned char *s;
835 unsigned char a;
836{
837 char *t = (char *)ScreenPrimary + 2 * (x + ScreenCols () * y);
838 asm volatile
839 (" movl %1,%%eax
840 call dosmemsetup
841 movl %%eax,%%edi
842 movb %0,%%ah
843 movl %2,%%ecx
844 movl %3,%%esi
845output_string1:
846 movb (%%esi),%%al
847 movw %%ax,%%gs:(%%edi)
848 addl $2,%%edi
849 incl %%esi
850 decl %%ecx
851 jne output_string1"
852 : /* no output */
853 : "m" (a), "g" (t), "g" (c), "g" (s)
854 : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
855}
856
1b94449f 857static int internal_terminal = 0;
87485d6f
MW
858static int highlight;
859
1b94449f
RS
860#undef fflush
861
862int
863internal_flush (f)
864 FILE *f;
865{
09e2ac30 866 static char spaces[] = " ";
1b94449f
RS
867 static int x;
868 static int y;
09e2ac30
RS
869 unsigned char *cp, *cp0;
870 int count, i, j;
1b94449f
RS
871
872 if (internal_terminal && f == stdout)
873 {
49a09c76 874 if (have_mouse) mouse_off ();
1b94449f
RS
875 cp = stdout->_base;
876 count = stdout->_ptr - stdout->_base;
877 while (count > 0)
878 {
09e2ac30 879 switch (*cp++)
1b94449f
RS
880 {
881 case 27:
882 switch (*cp++)
883 {
884 case '@':
885 y = *cp++;
886 x = *cp++;
887 count -= 4;
888 break;
889 case 'A':
890 ScreenAttrib = *cp++;
891 count -= 3;
892 break;
893 case 'B':
fcea9cd4 894 do_visible_bell (*cp++);
1b94449f
RS
895 count -= 3;
896 break;
897 case 'C':
898 ScreenClear ();
899 x = y = 0;
900 count -= 2;
901 break;
902 case 'E':
09e2ac30
RS
903 i = ScreenCols () - x;
904 j = x;
905 while (i >= sizeof spaces)
906 {
907 output_string (j, y, spaces, sizeof spaces,
908 ScreenAttrib);
909 j += sizeof spaces;
910 i -= sizeof spaces;
911 }
912 if (i > 0)
913 output_string (j, y, spaces, i, ScreenAttrib);
1b94449f
RS
914 count -= 2;
915 break;
916 case 'R':
917 x++;
918 count -= 2;
919 break;
920 case 'U':
921 y--;
922 count -= 2;
923 break;
924 case 'X':
925 ScreenAttrib ^= *cp++;
926 count -= 3;
927 break;
928 default:
929 count -= 2;
930 }
931 break;
fcea9cd4
RS
932 case 7:
933 write (1, "\007", 1);
934 count--;
935 break;
1b94449f
RS
936 case 8:
937 x--;
938 count--;
939 break;
940 case 13:
941 x = 0;
942 count--;
943 break;
944 case 10:
945 y++;
946 count--;
947 break;
948 default:
09e2ac30 949 cp0 = cp - 1;
1b94449f 950 count--;
09e2ac30
RS
951 while (count > 0 && *cp >= ' ')
952 cp++, count--;
953 output_string (x, y, cp0, cp - cp0, ScreenAttrib);
954 x += (cp - cp0);
1b94449f
RS
955 }
956 }
957 fpurge (stdout);
958 ScreenSetCursor (y, x);
49a09c76 959 if (have_mouse) mouse_on ();
1b94449f
RS
960 }
961 else
962 /* This is a call to the original fflush. */
963 fflush (f);
964}
965
87485d6f
MW
966#ifndef HAVE_X_WINDOWS
967static void
968rien_du_tout ()
969{
970 /* Rien du tout, cela va sans dire! */
971}
972
973static
974IT_ring_bell ()
975{
976 if (visible_bell)
977 {
978 /* This creates an xor-mask that will swap the default fore- and
979 background colors. */
980 if (have_mouse) mouse_off ();
981 do_visible_bell (((the_only_x_display.foreground_pixel
982 ^ the_only_x_display.background_pixel)
983 * 0x11) & 0x7f);
984 if (have_mouse) mouse_on ();
985 }
986 else
987 /* Write it directly to ms-dos -- don't let it go through our terminal
988 emulator. This way the mouse cursor won't blink. */
989 write (1, "\007", 1);
990}
991
992static void
993IT_set_face (int face)
994{
995 struct face *fp;
996 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
997
998 if (face == 1 || (face == 0 && highlight))
999 fp = FRAME_MODE_LINE_FACE (foo);
1000 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
1001 fp = FRAME_DEFAULT_FACE (foo);
1002 else
1003 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
1004 putchar ('\e');
1005 putchar ('A');
1006 putchar ((FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp));
1007}
1008
1009static
1010IT_write_glyphs (GLYPH *str, int len)
1011{
1012 int face = -1;
1013 int newface;
1014
1015 while (len > 0)
1016 {
1017 newface = FAST_GLYPH_FACE (*str);
1018 if (newface != face)
1019 IT_set_face ((face = newface));
1020 putchar (FAST_GLYPH_CHAR (*str));
1021 str++, len--;
1022 }
1023}
1024
1025static
1026IT_clear_end_of_line (first_unused)
1027{
1028 putchar ('\e');
1029 putchar ('E');
1030}
1031
1032static
1033IT_cursor_to (int y, int x)
1034{
1035 putchar ('\e');
1036 putchar ('@');
1037 putchar (y);
1038 putchar (x);
1039}
1040
1041IT_reassert_line_highlight (new, vpos)
1042 int new, vpos;
1043{
1044 highlight = new;
1045 IT_set_face (0); /* To possibly clear the highlighting. */
1046}
1047
1048static
1049IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
1050{
1051 highlight = new_highlight;
1052 IT_set_face (0); /* To possibly clear the highlighting. */
1053 IT_cursor_to (vpos, 0);
1054 IT_clear_end_of_line (first_unused_hpos);
1055}
1056
1057static
1058IT_update_begin ()
1059{
1060 highlight = 0;
1061 IT_set_face (0); /* To possibly clear the highlighting. */
1062}
1063
1064/* This was more or less copied from xterm.c */
1065static void
1066IT_set_menu_bar_lines (window, n)
1067 Lisp_Object window;
1068 int n;
1069{
1070 struct window *w = XWINDOW (window);
1071
1072 XSETFASTINT (w->top, XFASTINT (w->top) + n);
1073 XSETFASTINT (w->height, XFASTINT (w->height) - n);
1074
1075 /* Handle just the top child in a vertical split. */
1076 if (!NILP (w->vchild))
1077 IT_set_menu_bar_lines (w->vchild, n);
1078
1079 /* Adjust all children in a horizontal split. */
1080 for (window = w->hchild; !NILP (window); window = w->next)
1081 {
1082 w = XWINDOW (window);
1083 IT_set_menu_bar_lines (window, n);
1084 }
1085}
1086
1087void
1088IT_set_frame_parameters (frame, alist)
1089 FRAME_PTR frame;
1090 Lisp_Object alist;
1091{
1092 Lisp_Object tail;
1093 int redraw;
1094 extern unsigned long load_color ();
1095 FRAME_PTR f = (FRAME_PTR) &the_only_frame;
1096
1097 redraw = 0;
1098 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1099 {
1100 Lisp_Object elt, prop, val;
1101
1102 elt = Fcar (tail);
1103 prop = Fcar (elt);
1104 val = Fcdr (elt);
1105 CHECK_SYMBOL (prop, 1);
1106
1107 if (EQ (prop, intern ("foreground-color")))
1108 {
1109 unsigned long new_color = load_color (f, val);
1110 if (new_color != ~0)
1111 {
1112 FRAME_FOREGROUND_PIXEL (f) = new_color;
1113 redraw = 1;
1114 }
1115 }
1116 else if (EQ (prop, intern ("background-color")))
1117 {
1118 unsigned long new_color = load_color (f, val);
1119 if (new_color != ~0)
1120 {
1121 FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
1122 redraw = 1;
1123 }
1124 }
1125 else if (EQ (prop, intern ("menu-bar-lines")))
1126 {
1127 int new;
1128 int old = FRAME_MENU_BAR_LINES (the_only_frame);
1129
1130 if (INTEGERP (val))
1131 new = XINT (val);
1132 else
1133 new = 0;
1134 FRAME_MENU_BAR_LINES (f) = new;
1135 IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
1136 }
1137 }
1138
1139 if (redraw)
1140 {
1141 recompute_basic_faces (f);
1142 Fredraw_frame (Fselected_frame ());
1143 }
1144}
1145
1146/* Similar to the_only_frame. */
1147struct x_display the_only_x_display;
1148
1149/* This is never dereferenced. */
1150Display *x_current_display;
1151
1152#endif /* !HAVE_X_WINDOWS */
1153
1b94449f
RS
1154/* Do we need the internal terminal? */
1155void
1156internal_terminal_init ()
1157{
1158 char *term = getenv ("TERM");
1159
87485d6f
MW
1160#ifdef HAVE_X_WINDOWS
1161 if (!inhibit_window_system)
1162 return;
1163#endif
1164
1b94449f
RS
1165 internal_terminal
1166 = (!noninteractive) && term && !strcmp (term, "internal");
87485d6f
MW
1167
1168#ifndef HAVE_X_WINDOWS
1169 if (internal_terminal && !inhibit_window_system)
1170 {
1171 Vwindow_system = intern ("pc");
1172 Vwindow_system_version = make_number (1);
1173
1174 bzero (&the_only_x_display, sizeof the_only_x_display);
1175 the_only_x_display.background_pixel = 7; /* White */
1176 the_only_x_display.foreground_pixel = 0; /* Black */
1177 the_only_x_display.line_height = 1;
1178 the_only_frame.display.x = &the_only_x_display;
1179 the_only_frame.output_method = output_msdos_raw;
1180
1181 init_frame_faces ((FRAME_PTR) &the_only_frame);
1182
1183 ring_bell_hook = IT_ring_bell;
1184 write_glyphs_hook = IT_write_glyphs;
1185 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1186 clear_end_of_line_hook = IT_clear_end_of_line;
1187 change_line_highlight_hook = IT_change_line_highlight;
1188 update_begin_hook = IT_update_begin;
1189 reassert_line_highlight_hook = IT_reassert_line_highlight;
1190
1191 /* These hooks are called by term.c without being checked. */
1192 set_terminal_modes_hook
1193 = reset_terminal_modes_hook
1194 = update_end_hook
1195 = set_terminal_window_hook
1196 = (void *)rien_du_tout;
1197 }
1198 else
1199 the_only_frame.output_method = output_termcap;
1200#endif
1b94449f 1201}
b278e52a
RS
1202\f
1203/* When time zones are set from Ms-Dos too may C-libraries are playing
1204 tricks with time values. We solve this by defining our own version
1205 of `gettimeofday' bypassing GO32. Our version needs to be initialized
1206 once and after each call to `tzset' with TZ changed. */
1b94449f 1207
b278e52a
RS
1208static int daylight, gmtoffset;
1209
1210int
1211gettimeofday (struct timeval *tp, struct timezone *tzp)
1212{
1213 if (tp)
1214 {
1215 struct time t;
1216 struct date d;
1217 struct tm tmrec;
1218
1219 gettime (&t);
1220 getdate (&d);
1221 tmrec.tm_year = d.da_year - 1900;
1222 tmrec.tm_mon = d.da_mon - 1;
1223 tmrec.tm_mday = d.da_day;
1224 tmrec.tm_hour = t.ti_hour;
1225 tmrec.tm_min = t.ti_min;
1226 tmrec.tm_sec = t.ti_sec;
1227 tmrec.tm_gmtoff = gmtoffset;
1228 tmrec.tm_isdst = daylight;
1229 tp->tv_sec = mktime (&tmrec);
1230 tp->tv_usec = t.ti_hund * (1000000 / 100);
1231 }
1232 if (tzp)
1233 {
1234 tzp->tz_minuteswest = gmtoffset;
1235 tzp->tz_dsttime = daylight;
1236 }
1237 return 0;
1238}
1239
1240void
1241init_gettimeofday ()
1242{
1243 time_t ltm, gtm;
1244 struct tm *lstm;
1245
1246 daylight = 0;
1247 gmtoffset = 0;
1248 ltm = gtm = time (NULL);
1249 ltm = mktime (lstm = localtime (&ltm));
1250 gtm = mktime (gmtime (&gtm));
1251 daylight = lstm->tm_isdst;
1252 gmtoffset = (int)(gtm - ltm) / 60;
1253}
1254\f
1b94449f
RS
1255/* These must be global. */
1256static _go32_dpmi_seginfo ctrl_break_vector;
1257static _go32_dpmi_registers ctrl_break_regs;
1258static int ctrlbreakinstalled = 0;
1259
1260/* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
1261void
1262ctrl_break_func (regs)
1263 _go32_dpmi_registers *regs;
1264{
1265 Vquit_flag = Qt;
1266}
1267
1268void
1269install_ctrl_break_check ()
1270{
1271 if (!ctrlbreakinstalled)
1272 {
1273 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
ca986694 1274 was compiler with Djgpp 1.11 maintenance level 5 or later! */
1b94449f
RS
1275 ctrlbreakinstalled = 1;
1276 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
1277 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
1278 &ctrl_break_regs);
1279 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
1280 }
1281}
1282\f
87485d6f
MW
1283/* Mouse routines follow. Coordinates are in screen positions and zero
1284 based. Mouse buttons are numbered from left to right and also zero
1285 based. */
1b94449f
RS
1286
1287static int mouse_button_translate[NUM_MOUSE_BUTTONS];
1288static int mouse_button_count;
1289
1290void
1291mouse_init ()
1292{
1293 union REGS regs;
1294
1295 regs.x.ax = 0x0007;
1296 regs.x.cx = 0;
1297 regs.x.dx = 8 * (ScreenCols () - 1);
1298 int86 (0x33, &regs, &regs);
1299
1300 regs.x.ax = 0x0008;
1301 regs.x.cx = 0;
1302 regs.x.dx = 8 * (ScreenRows () - 1);
1303 int86 (0x33, &regs, &regs);
1304
1305 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
1306 mouse_on ();
1307}
1308
1309void
1310mouse_on ()
1311{
1312 union REGS regs;
1313
1314 regs.x.ax = 0x0001;
1315 int86 (0x33, &regs, &regs);
1316}
1317
1318void
1319mouse_off ()
1320{
1321 union REGS regs;
1322
1323 regs.x.ax = 0x0002;
1324 int86 (0x33, &regs, &regs);
1325}
1326
1327void
1328mouse_moveto (x, y)
1329 int x, y;
1330{
1331 union REGS regs;
1332
1333 regs.x.ax = 0x0004;
1334 mouse_last_x = regs.x.cx = x * 8;
1335 mouse_last_y = regs.x.dx = y * 8;
1336 int86 (0x33, &regs, &regs);
1337}
1338
1339int
1340mouse_pressed (b, xp, yp)
1341 int b, *xp, *yp;
1342{
1343 union REGS regs;
1344
1345 if (b >= mouse_button_count)
1346 return 0;
1347 regs.x.ax = 0x0005;
1348 regs.x.bx = mouse_button_translate[b];
1349 int86 (0x33, &regs, &regs);
1350 if (regs.x.bx)
ca986694 1351 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1b94449f
RS
1352 return (regs.x.bx != 0);
1353}
1354
1355int
1356mouse_released (b, xp, yp)
1357 int b, *xp, *yp;
1358{
1359 union REGS regs;
1360
1361 if (b >= mouse_button_count)
1362 return 0;
1363 regs.x.ax = 0x0006;
1364 regs.x.bx = mouse_button_translate[b];
1365 int86 (0x33, &regs, &regs);
1366 if (regs.x.bx)
1367 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1368 return (regs.x.bx != 0);
1369}
1370
87485d6f
MW
1371static void
1372mouse_get_xy (int *x, int *y)
1373{
1374 union REGS regs;
1375
1376 regs.x.ax = 0x0003;
1377 int86 (0x33, &regs, &regs);
1378 *x = regs.x.cx / 8;
1379 *y = regs.x.dx / 8;
1380}
1381
1b94449f
RS
1382void
1383mouse_get_pos (f, bar_window, part, x, y, time)
1384 FRAME_PTR *f;
1385 Lisp_Object *bar_window, *x, *y;
1386 enum scroll_bar_part *part;
1387 unsigned long *time;
1388{
87485d6f 1389 int ix, iy;
1b94449f
RS
1390 union REGS regs;
1391 struct timeval tv;
1392
1393 regs.x.ax = 0x0003;
1394 int86 (0x33, &regs, &regs);
1395 *f = selected_frame;
1396 *bar_window = Qnil;
1397 gettimeofday (&tv, NULL);
87485d6f 1398 mouse_get_xy (&ix, &iy);
1b94449f 1399 mouse_moved = 0;
87485d6f
MW
1400 *x = make_number (ix);
1401 *y = make_number (iy);
1402 *time = tv.tv_usec;
1b94449f
RS
1403}
1404
1405void
1406mouse_check_moved ()
1407{
87485d6f 1408 int x, y;
1b94449f 1409
87485d6f
MW
1410 mouse_get_xy (&x, &y);
1411 mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
1412 mouse_last_x = x;
1413 mouse_last_y = y;
1b94449f
RS
1414}
1415
1416int
1417mouse_init1 ()
1418{
1419 union REGS regs;
1420 int present;
1421
87485d6f
MW
1422#ifdef HAVE_X_WINDOWS
1423 if (!inhibit_window_system)
1424 return 0;
1425#endif
e118d5ef
RS
1426 if (!internal_terminal)
1427 return 0;
1428
1b94449f
RS
1429 regs.x.ax = 0x0021;
1430 int86 (0x33, &regs, &regs);
e118d5ef
RS
1431 present = (regs.x.ax & 0xffff) == 0xffff;
1432 if (!present)
1433 {
1434 /* Reportedly, the above doesn't work for some mouse drivers. There
1435 is an additional detection method that should work, but might be
1436 a little slower. Use that as an alternative. */
1437 regs.x.ax = 0x0000;
1438 int86 (0x33, &regs, &regs);
1439 present = (regs.x.ax & 0xffff) == 0xffff;
1440 }
1441
1b94449f
RS
1442 if (present)
1443 {
1444 if (regs.x.bx == 3)
1445 {
1446 mouse_button_count = 3;
1447 mouse_button_translate[0] = 0; /* Left */
1448 mouse_button_translate[1] = 2; /* Middle */
1449 mouse_button_translate[2] = 1; /* Right */
1450 }
1451 else
1452 {
1453 mouse_button_count = 2;
1454 mouse_button_translate[0] = 0;
1455 mouse_button_translate[1] = 1;
1456 }
1457 mouse_position_hook = &mouse_get_pos;
1458 mouse_init ();
1459 }
1460 return present;
1461}
1462
87485d6f 1463#ifndef HAVE_X_WINDOWS
49a09c76
RS
1464/* See xterm.c for more info. */
1465void
1466pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1467 FRAME_PTR f;
1468 register int pix_x, pix_y;
1469 register int *x, *y;
1470 void /* XRectangle */ *bounds;
1471 int noclip;
1472{
1473 if (bounds) abort ();
1474
1475 /* Ignore clipping. */
1476
1477 *x = pix_x;
1478 *y = pix_y;
1479}
1480
1481void
1482glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1483 FRAME_PTR f;
1484 register int x, y;
1485 register int *pix_x, *pix_y;
1486{
1487 *pix_x = x;
1488 *pix_y = y;
1489}
87485d6f
MW
1490\f
1491/* Simulation of X's menus. Nothing too fancy here -- just make it work
1492 for now.
1493
1494 Actually, I don't know the meaning of all the parameters of the functions
1495 here -- I only know how they are called by xmenu.c. I could of course
1496 grab the nearest Xlib manual (down the hall, second-to-last door on the
1497 left), but I don't think it's worth the effort. */
1498
1499static XMenu *
1500IT_menu_create ()
1501{
1502 XMenu *menu;
1503
1504 menu = (XMenu *) xmalloc (sizeof (XMenu));
1505 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1506 return menu;
1507}
1508
1509/* Allocate some (more) memory for MENU ensuring that there is room for one
1510 for item. */
1511static void
1512IT_menu_make_room (XMenu *menu)
1513{
1514 if (menu->allocated == 0)
1515 {
1516 int count = menu->allocated = 10;
1517 menu->text = (char **) xmalloc (count * sizeof (char *));
1518 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1519 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1520 }
1521 else if (menu->allocated == menu->count)
1522 {
1523 int count = menu->allocated = menu->allocated + 10;
1524 menu->text
1525 = (char **) xrealloc (menu->text, count * sizeof (char *));
1526 menu->submenu
1527 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1528 menu->panenumber
1529 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1530 }
1531}
1532
1533/* Search the given menu structure for a given pane number. */
1534static XMenu *
1535IT_menu_search_pane (XMenu *menu, int pane)
1536{
1537 int i;
1538 XMenu *try;
1539
1540 for (i = 0; i < menu->count; i++)
1541 if (menu->submenu[i])
1542 if (pane == menu->panenumber[i])
1543 return menu->submenu[i];
1544 else
1545 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1546 return try;
1547 return (XMenu *) 0;
1548}
1549
1550/* Determine how much screen space a given menu needs. */
1551static void
1552IT_menu_calc_size (XMenu *menu, int *width, int *height)
1553{
1554 int i, h2, w2, maxsubwidth, maxheight;
1555
1556 maxsubwidth = 0;
1557 maxheight = menu->count;
1558 for (i = 0; i < menu->count; i++)
1559 {
1560 if (menu->submenu[i])
1561 {
1562 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1563 if (w2 > maxsubwidth) maxsubwidth = w2;
1564 if (i + h2 > maxheight) maxheight = i + h2;
1565 }
1566 }
1567 *width = menu->width + maxsubwidth;
1568 *height = maxheight;
1569}
1570
1571/* Display MENU at (X,Y) using FACES. */
1572static void
1573IT_menu_display (XMenu *menu, int y, int x, int *faces)
1574{
1575 int i, j, face, width;
1576 GLYPH *text, *p;
1577 char *q;
1578 int mx, my;
1579 int enabled, mousehere;
1580 int row, col;
1581
1582 width = menu->width;
1583 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1584 ScreenGetCursor (&row, &col);
1585 mouse_get_xy (&mx, &my);
1586 mouse_off ();
1587 (*update_begin_hook) ();
1588 for (i = 0; i < menu->count; i++)
1589 {
1590 (*cursor_to_hook) (y + i, x);
1591 enabled
1592 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1593 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1594 face = faces[enabled + mousehere * 2];
1595 p = text;
1596 *p++ = FAST_MAKE_GLYPH (' ', face);
1597 for (j = 0, q = menu->text[i]; *q; j++)
1598 *p++ = FAST_MAKE_GLYPH (*q++, face);
1599 for (; j < width; j++)
1600 *p++ = FAST_MAKE_GLYPH (' ', face);
1601 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1602 (*write_glyphs_hook) (text, width + 2);
1603 }
1604 internal_flush (stdout);
1605 (*update_end_hook) ();
1606 mouse_on ();
1607 ScreenSetCursor (row, col);
1608 xfree (text);
1609}
1610
1611/* Create a brand new menu structure. */
1612XMenu *
1189e5a2 1613XMenuCreate (Display *foo1, Window foo2, char *foo3)
87485d6f
MW
1614{
1615 return IT_menu_create ();
1616}
1617
1618/* Create a new pane and place it on the outer-most level. It is not
1619 clear that it should be placed out there, but I don't know what else
1620 to do. */
1621int
1189e5a2 1622XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
87485d6f
MW
1623{
1624 int len;
1625
1626 if (!enable)
1627 abort ();
1628
1629 IT_menu_make_room (menu);
1630 menu->submenu[menu->count] = IT_menu_create ();
1631 menu->text[menu->count] = txt;
1632 menu->panenumber[menu->count] = ++menu->panecount;
1633 menu->count++;
1634 if ((len = strlen (txt)) > menu->width) menu->width = len;
1635 return menu->panecount;
1636}
1637
1638/* Create a new item in a menu pane. */
1639int
1189e5a2
RS
1640XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1641 int foo, char *txt, int enable)
87485d6f
MW
1642{
1643 int len;
1644
1645 if (pane)
1646 if (!(menu = IT_menu_search_pane (menu, pane)))
1647 return XM_FAILURE;
1648 IT_menu_make_room (menu);
1649 menu->submenu[menu->count] = (XMenu *) 0;
1650 menu->text[menu->count] = txt;
1651 menu->panenumber[menu->count] = enable;
1652 menu->count++;
1653 if ((len = strlen (txt)) > menu->width) menu->width = len;
1654 return XM_SUCCESS;
1655}
1656
1657/* Decide where the menu would be placed if requested at (X,Y). */
1189e5a2
RS
1658void
1659XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
87485d6f
MW
1660 int *ulx, int *uly, int *width, int *height)
1661{
1662 if (menu->count == 1 && menu->submenu[0])
1663 /* Special case: the menu consists of only one pane. */
1664 IT_menu_calc_size (menu->submenu[0], width, height);
1665 else
1666 IT_menu_calc_size (menu, width, height);
1667 *ulx = x + 1;
1668 *uly = y;
1669 *width += 2;
1670}
1671
1672typedef struct
1673{
1674 void *screen_behind;
1675 XMenu *menu;
1676 int pane;
1677 int x, y;
1678} IT_menu_state;
1679
1680
1681/* Display menu, wait for user's response, and return that response. */
1682int
1189e5a2 1683XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
87485d6f
MW
1684 int x0, int y0, unsigned ButtonMask, char **txt)
1685{
1686 IT_menu_state *state;
1687 int statecount;
1688 int x, y, i, b;
1689 int screensize;
1690 int faces[4], selectface;
1691 int leave, result, onepane;
1692
1693 /* Just in case we got here without a mouse present... */
1694 if (!have_mouse)
1695 return XM_IA_SELECT;
1696
1697 state = alloca (menu->panecount * sizeof (IT_menu_state));
1698 screensize = ScreenRows () * ScreenCols () * 2;
1699 faces[0]
1700 = compute_glyph_face (&the_only_frame,
1701 face_name_id_number
1702 (&the_only_frame,
1703 intern ("msdos-menu-passive-face")),
1704 0);
1705 faces[1]
1706 = compute_glyph_face (&the_only_frame,
1707 face_name_id_number
1708 (&the_only_frame,
1709 intern ("msdos-menu-active-face")),
1710 0);
1711 selectface
1712 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1713 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1714 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1715
1716 statecount = 1;
1717 state[0].menu = menu;
1718 mouse_off ();
1719 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1720 mouse_on ();
1721 if ((onepane = menu->count == 1 && menu->submenu[0]))
1722 {
1723 menu->width = menu->submenu[0]->width;
1724 state[0].menu = menu->submenu[0];
1725 }
1726 else
1727 {
1728 state[0].menu = menu;
1729 }
1730 state[0].x = x0 - 1;
1731 state[0].y = y0;
1732 state[0].pane = onepane;
1733
1734 mouse_last_x = -1; /* A hack that forces display. */
1735 leave = 0;
1736 while (!leave)
1737 {
1738 mouse_check_moved ();
1739 if (mouse_moved)
1740 {
1741 mouse_moved = 0;
1742 result = XM_IA_SELECT;
1743 mouse_get_xy (&x, &y);
1744 for (i = 0; i < statecount; i++)
1745 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1746 {
1747 int dy = y - state[i].y;
1748 if (0 <= dy && dy < state[i].menu->count)
1749 {
1750 if (!state[i].menu->submenu[dy])
1751 if (state[i].menu->panenumber[dy])
1752 result = XM_SUCCESS;
1753 else
1754 result = XM_IA_SELECT;
1755 *pane = state[i].pane - 1;
1756 *selidx = dy;
1757 /* We hit some part of a menu, so drop extra menues that
1758 have been opened. That does not include an open and
1759 active submenu. */
1760 if (i != statecount - 2
1761 || state[i].menu->submenu[dy] != state[i+1].menu)
1762 while (i != statecount - 1)
1763 {
1764 statecount--;
1765 mouse_off ();
1766 ScreenUpdate (state[statecount].screen_behind);
1767 mouse_on ();
1768 xfree (state[statecount].screen_behind);
1769 }
1770 if (i == statecount - 1 && state[i].menu->submenu[dy])
1771 {
1772 IT_menu_display (state[i].menu,
1773 state[i].y,
1774 state[i].x,
1775 faces);
1776 state[statecount].menu = state[i].menu->submenu[dy];
1777 state[statecount].pane = state[i].menu->panenumber[dy];
1778 mouse_off ();
1779 ScreenRetrieve (state[statecount].screen_behind
1780 = xmalloc (screensize));
1781 mouse_on ();
1782 state[statecount].x
1783 = state[i].x + state[i].menu->width + 2;
1784 state[statecount].y = y;
1785 statecount++;
1786 }
1787 }
1788 }
1789 IT_menu_display (state[statecount - 1].menu,
1790 state[statecount - 1].y,
1791 state[statecount - 1].x,
1792 faces);
1793 }
1794 for (b = 0; b < mouse_button_count; b++)
1795 {
1796 (void) mouse_pressed (b, &x, &y);
1797 if (mouse_released (b, &x, &y))
1798 leave = 1;
1799 }
1800 }
1801
1802 mouse_off ();
1803 ScreenUpdate (state[0].screen_behind);
1804 mouse_on ();
1805 while (statecount--)
1806 xfree (state[statecount].screen_behind);
1807 return result;
1808}
1809
1810/* Dispose of a menu. */
1189e5a2
RS
1811void
1812XMenuDestroy (Display *foo, XMenu *menu)
87485d6f
MW
1813{
1814 int i;
1815 if (menu->allocated)
1816 {
1817 for (i = 0; i < menu->count; i++)
1818 if (menu->submenu[i])
1189e5a2 1819 XMenuDestroy (foo, menu->submenu[i]);
87485d6f
MW
1820 xfree (menu->text);
1821 xfree (menu->submenu);
1822 xfree (menu->panenumber);
1823 }
1824 xfree (menu);
1825}
1826
1827int x_pixel_width (struct frame *f)
1828{
1829 return FRAME_WIDTH(f);
1830}
1831
1832int x_pixel_height (struct frame *f)
1833{
1834 return FRAME_HEIGHT(f);
1835}
1836#endif /* !HAVE_X_WINDOWS */
49a09c76 1837
1b94449f 1838#endif /* MSDOS */