(Freplace_match): New arg SUBEXP.
[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
edfc0d45 8the Free Software Foundation; either version 2, or (at your option)
1b94449f
RS
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". */
872e2c82
RS
696 root = alloca (MAXPATHLEN + 20);
697 _fixpath (argv[0], root);
87485d6f
MW
698 strlwr (root);
699 len = strlen (root);
88b28483
RS
700 while (len > 0 && root[len] != '/' && root[len] != ':')
701 len--;
702 root[len] = '\0';
703 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
704 root[len - 4] = '\0';
1b94449f 705 else
88b28483
RS
706 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
707 len = strlen (root);
708 strcpy (emacsroot, root);
709
710 /* We default HOME to our root. */
711 setenv ("HOME", root, 0);
712
713 /* We default EMACSPATH to root + "/bin". */
714 strcpy (root + len, "/bin");
715 setenv ("EMACSPATH", root, 0);
1b94449f
RS
716
717 /* I don't expect anybody to ever use other terminals so the internal
718 terminal is the default. */
719 setenv ("TERM", "internal", 0);
720
87485d6f
MW
721#ifdef HAVE_X_WINDOWS
722 /* Emacs expects DISPLAY to be set. */
723 setenv ("DISPLAY", "unix:0.0", 0);
724#endif
725
1b94449f
RS
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);
731 strcpy (t, s);
732 strlwr (t);
733 dostounix_filename (t);
734 setenv ("SHELL", t, 0);
735
736 /* PATH is also downcased and backslashes mirrored. */
737 s = getenv ("PATH");
738 if (!s) s = "";
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);
743 strlwr (t);
744 dostounix_filename (t); /* Not a single file name, but this should work. */
745 setenv ("PATH", t, 1);
746
747 /* In some sense all dos users have root privileges, so... */
748 setenv ("USER", "root", 0);
749 setenv ("NAME", getenv ("USER"), 0);
750
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)
755 {
756 case 31: /* Belgium */
757 case 32: /* The Netherlands */
758 case 33: /* France */
759 case 34: /* Spain */
760 case 36: /* Hungary */
761 case 38: /* Yugoslavia (or what's left of it?) */
762 case 39: /* Italy */
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);
773 break;
774 case 44: /* United Kingdom */
775 case 351: /* Portugal */
776 case 354: /* Iceland */
777 setenv ("TZ", "GMT+00", 0);
778 break;
779 case 81: /* Japan */
780 case 82: /* Korea */
781 setenv ("TZ", "???-09", 0);
782 break;
783 case 90: /* Turkey */
784 case 358: /* Finland */
785 case 972: /* Israel */
786 setenv ("TZ", "EET-02", 0);
787 break;
788 }
789 tzset ();
b278e52a 790 init_gettimeofday ();
1b94449f
RS
791}
792
793/* Flash the screen as a substitute for BEEPs. */
794
49a09c76 795static void
fcea9cd4 796do_visible_bell (xorattr)
1b94449f
RS
797 unsigned char xorattr;
798{
49a09c76 799 asm volatile
ca986694 800 (" movb $1,%%dl
1b94449f 801visible_bell_0:
ca986694 802 movl _ScreenPrimary,%%eax
49a09c76 803 call dosmemsetup
ca986694
RS
804 movl %%eax,%%ebx
805 movl %1,%%ecx
806 movb %0,%%al
807 incl %%ebx
1b94449f 808visible_bell_1:
ca986694
RS
809 xorb %%al,%%gs:(%%ebx)
810 addl $2,%%ebx
811 decl %%ecx
49a09c76 812 jne visible_bell_1
ca986694 813 decb %%dl
49a09c76 814 jne visible_bell_3
1b94449f 815visible_bell_2:
ca986694
RS
816 movzwl %%ax,%%eax
817 movzwl %%ax,%%eax
818 movzwl %%ax,%%eax
819 movzwl %%ax,%%eax
820 decw %%cx
49a09c76
RS
821 jne visible_bell_2
822 jmp visible_bell_0
ca986694
RS
823visible_bell_3:"
824 : /* no output */
825 : "m" (xorattr), "g" (ScreenCols () * ScreenRows ())
826 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
827}
828
09e2ac30
RS
829/* At screen position (X,Y), output C characters from string S with
830 attribute A. Do it fast! */
831
832static void
833output_string (x, y, s, c, a)
834 int x, y, c;
835 unsigned char *s;
836 unsigned char a;
837{
838 char *t = (char *)ScreenPrimary + 2 * (x + ScreenCols () * y);
839 asm volatile
840 (" movl %1,%%eax
841 call dosmemsetup
842 movl %%eax,%%edi
843 movb %0,%%ah
844 movl %2,%%ecx
845 movl %3,%%esi
846output_string1:
847 movb (%%esi),%%al
848 movw %%ax,%%gs:(%%edi)
849 addl $2,%%edi
850 incl %%esi
851 decl %%ecx
852 jne output_string1"
853 : /* no output */
854 : "m" (a), "g" (t), "g" (c), "g" (s)
855 : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
856}
857
1b94449f 858static int internal_terminal = 0;
87485d6f
MW
859static int highlight;
860
1b94449f
RS
861#undef fflush
862
863int
864internal_flush (f)
865 FILE *f;
866{
09e2ac30 867 static char spaces[] = " ";
1b94449f
RS
868 static int x;
869 static int y;
09e2ac30
RS
870 unsigned char *cp, *cp0;
871 int count, i, j;
1b94449f
RS
872
873 if (internal_terminal && f == stdout)
874 {
49a09c76 875 if (have_mouse) mouse_off ();
1b94449f
RS
876 cp = stdout->_base;
877 count = stdout->_ptr - stdout->_base;
878 while (count > 0)
879 {
09e2ac30 880 switch (*cp++)
1b94449f
RS
881 {
882 case 27:
883 switch (*cp++)
884 {
885 case '@':
886 y = *cp++;
887 x = *cp++;
888 count -= 4;
889 break;
890 case 'A':
891 ScreenAttrib = *cp++;
892 count -= 3;
893 break;
894 case 'B':
fcea9cd4 895 do_visible_bell (*cp++);
1b94449f
RS
896 count -= 3;
897 break;
898 case 'C':
899 ScreenClear ();
900 x = y = 0;
901 count -= 2;
902 break;
903 case 'E':
09e2ac30
RS
904 i = ScreenCols () - x;
905 j = x;
906 while (i >= sizeof spaces)
907 {
908 output_string (j, y, spaces, sizeof spaces,
909 ScreenAttrib);
910 j += sizeof spaces;
911 i -= sizeof spaces;
912 }
913 if (i > 0)
914 output_string (j, y, spaces, i, ScreenAttrib);
1b94449f
RS
915 count -= 2;
916 break;
917 case 'R':
918 x++;
919 count -= 2;
920 break;
921 case 'U':
922 y--;
923 count -= 2;
924 break;
925 case 'X':
926 ScreenAttrib ^= *cp++;
927 count -= 3;
928 break;
929 default:
930 count -= 2;
931 }
932 break;
fcea9cd4
RS
933 case 7:
934 write (1, "\007", 1);
935 count--;
936 break;
1b94449f
RS
937 case 8:
938 x--;
939 count--;
940 break;
941 case 13:
942 x = 0;
943 count--;
944 break;
945 case 10:
946 y++;
947 count--;
948 break;
949 default:
09e2ac30 950 cp0 = cp - 1;
1b94449f 951 count--;
09e2ac30
RS
952 while (count > 0 && *cp >= ' ')
953 cp++, count--;
954 output_string (x, y, cp0, cp - cp0, ScreenAttrib);
955 x += (cp - cp0);
1b94449f
RS
956 }
957 }
958 fpurge (stdout);
959 ScreenSetCursor (y, x);
49a09c76 960 if (have_mouse) mouse_on ();
1b94449f
RS
961 }
962 else
963 /* This is a call to the original fflush. */
964 fflush (f);
965}
966
87485d6f
MW
967#ifndef HAVE_X_WINDOWS
968static void
969rien_du_tout ()
970{
971 /* Rien du tout, cela va sans dire! */
972}
973
974static
975IT_ring_bell ()
976{
977 if (visible_bell)
978 {
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)
984 * 0x11) & 0x7f);
985 if (have_mouse) mouse_on ();
986 }
987 else
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);
991}
992
993static void
994IT_set_face (int face)
995{
996 struct face *fp;
997 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
998
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);
1003 else
1004 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
1005 putchar ('\e');
1006 putchar ('A');
1007 putchar ((FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp));
1008}
1009
1010static
1011IT_write_glyphs (GLYPH *str, int len)
1012{
1013 int face = -1;
1014 int newface;
1015
1016 while (len > 0)
1017 {
1018 newface = FAST_GLYPH_FACE (*str);
1019 if (newface != face)
1020 IT_set_face ((face = newface));
1021 putchar (FAST_GLYPH_CHAR (*str));
1022 str++, len--;
1023 }
1024}
1025
1026static
1027IT_clear_end_of_line (first_unused)
1028{
1029 putchar ('\e');
1030 putchar ('E');
1031}
1032
1033static
1034IT_cursor_to (int y, int x)
1035{
1036 putchar ('\e');
1037 putchar ('@');
1038 putchar (y);
1039 putchar (x);
1040}
1041
1042IT_reassert_line_highlight (new, vpos)
1043 int new, vpos;
1044{
1045 highlight = new;
1046 IT_set_face (0); /* To possibly clear the highlighting. */
1047}
1048
1049static
1050IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
1051{
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);
1056}
1057
1058static
1059IT_update_begin ()
1060{
1061 highlight = 0;
1062 IT_set_face (0); /* To possibly clear the highlighting. */
1063}
1064
1065/* This was more or less copied from xterm.c */
1066static void
1067IT_set_menu_bar_lines (window, n)
1068 Lisp_Object window;
1069 int n;
1070{
1071 struct window *w = XWINDOW (window);
1072
1073 XSETFASTINT (w->top, XFASTINT (w->top) + n);
1074 XSETFASTINT (w->height, XFASTINT (w->height) - n);
1075
1076 /* Handle just the top child in a vertical split. */
1077 if (!NILP (w->vchild))
1078 IT_set_menu_bar_lines (w->vchild, n);
1079
1080 /* Adjust all children in a horizontal split. */
1081 for (window = w->hchild; !NILP (window); window = w->next)
1082 {
1083 w = XWINDOW (window);
1084 IT_set_menu_bar_lines (window, n);
1085 }
1086}
1087
1088void
1089IT_set_frame_parameters (frame, alist)
1090 FRAME_PTR frame;
1091 Lisp_Object alist;
1092{
1093 Lisp_Object tail;
1094 int redraw;
1095 extern unsigned long load_color ();
1096 FRAME_PTR f = (FRAME_PTR) &the_only_frame;
1097
1098 redraw = 0;
1099 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1100 {
1101 Lisp_Object elt, prop, val;
1102
1103 elt = Fcar (tail);
1104 prop = Fcar (elt);
1105 val = Fcdr (elt);
1106 CHECK_SYMBOL (prop, 1);
1107
1108 if (EQ (prop, intern ("foreground-color")))
1109 {
1110 unsigned long new_color = load_color (f, val);
1111 if (new_color != ~0)
1112 {
1113 FRAME_FOREGROUND_PIXEL (f) = new_color;
1114 redraw = 1;
1115 }
1116 }
1117 else if (EQ (prop, intern ("background-color")))
1118 {
1119 unsigned long new_color = load_color (f, val);
1120 if (new_color != ~0)
1121 {
1122 FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
1123 redraw = 1;
1124 }
1125 }
1126 else if (EQ (prop, intern ("menu-bar-lines")))
1127 {
1128 int new;
1129 int old = FRAME_MENU_BAR_LINES (the_only_frame);
1130
1131 if (INTEGERP (val))
1132 new = XINT (val);
1133 else
1134 new = 0;
1135 FRAME_MENU_BAR_LINES (f) = new;
1136 IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
1137 }
1138 }
1139
1140 if (redraw)
1141 {
1142 recompute_basic_faces (f);
1143 Fredraw_frame (Fselected_frame ());
1144 }
1145}
1146
1147/* Similar to the_only_frame. */
1148struct x_display the_only_x_display;
1149
1150/* This is never dereferenced. */
1151Display *x_current_display;
1152
1153#endif /* !HAVE_X_WINDOWS */
1154
1b94449f
RS
1155/* Do we need the internal terminal? */
1156void
1157internal_terminal_init ()
1158{
1159 char *term = getenv ("TERM");
1160
87485d6f
MW
1161#ifdef HAVE_X_WINDOWS
1162 if (!inhibit_window_system)
1163 return;
1164#endif
1165
1b94449f
RS
1166 internal_terminal
1167 = (!noninteractive) && term && !strcmp (term, "internal");
87485d6f
MW
1168
1169#ifndef HAVE_X_WINDOWS
1170 if (internal_terminal && !inhibit_window_system)
1171 {
1172 Vwindow_system = intern ("pc");
1173 Vwindow_system_version = make_number (1);
1174
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;
1181
1182 init_frame_faces ((FRAME_PTR) &the_only_frame);
1183
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;
1191
1192 /* These hooks are called by term.c without being checked. */
1193 set_terminal_modes_hook
1194 = reset_terminal_modes_hook
1195 = update_end_hook
1196 = set_terminal_window_hook
1197 = (void *)rien_du_tout;
1198 }
1199 else
1200 the_only_frame.output_method = output_termcap;
1201#endif
1b94449f 1202}
b278e52a
RS
1203\f
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. */
1b94449f 1208
b278e52a
RS
1209static int daylight, gmtoffset;
1210
1211int
1212gettimeofday (struct timeval *tp, struct timezone *tzp)
1213{
1214 if (tp)
1215 {
1216 struct time t;
1217 struct date d;
1218 struct tm tmrec;
1219
1220 gettime (&t);
1221 getdate (&d);
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);
1232 }
1233 if (tzp)
1234 {
1235 tzp->tz_minuteswest = gmtoffset;
1236 tzp->tz_dsttime = daylight;
1237 }
1238 return 0;
1239}
1240
1241void
1242init_gettimeofday ()
1243{
1244 time_t ltm, gtm;
1245 struct tm *lstm;
1246
1247 daylight = 0;
1248 gmtoffset = 0;
1249 ltm = gtm = time (NULL);
1250 ltm = mktime (lstm = localtime (&ltm));
1251 gtm = mktime (gmtime (&gtm));
1252 daylight = lstm->tm_isdst;
1253 gmtoffset = (int)(gtm - ltm) / 60;
1254}
1255\f
1b94449f
RS
1256/* These must be global. */
1257static _go32_dpmi_seginfo ctrl_break_vector;
1258static _go32_dpmi_registers ctrl_break_regs;
1259static int ctrlbreakinstalled = 0;
1260
1261/* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
1262void
1263ctrl_break_func (regs)
1264 _go32_dpmi_registers *regs;
1265{
1266 Vquit_flag = Qt;
1267}
1268
1269void
1270install_ctrl_break_check ()
1271{
1272 if (!ctrlbreakinstalled)
1273 {
1274 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
ca986694 1275 was compiler with Djgpp 1.11 maintenance level 5 or later! */
1b94449f
RS
1276 ctrlbreakinstalled = 1;
1277 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
1278 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
1279 &ctrl_break_regs);
1280 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
1281 }
1282}
1283\f
87485d6f
MW
1284/* Mouse routines follow. Coordinates are in screen positions and zero
1285 based. Mouse buttons are numbered from left to right and also zero
1286 based. */
1b94449f
RS
1287
1288static int mouse_button_translate[NUM_MOUSE_BUTTONS];
1289static int mouse_button_count;
1290
1291void
1292mouse_init ()
1293{
1294 union REGS regs;
1295
1296 regs.x.ax = 0x0007;
1297 regs.x.cx = 0;
1298 regs.x.dx = 8 * (ScreenCols () - 1);
1299 int86 (0x33, &regs, &regs);
1300
1301 regs.x.ax = 0x0008;
1302 regs.x.cx = 0;
1303 regs.x.dx = 8 * (ScreenRows () - 1);
1304 int86 (0x33, &regs, &regs);
1305
1306 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
1307 mouse_on ();
1308}
1309
1310void
1311mouse_on ()
1312{
1313 union REGS regs;
1314
1315 regs.x.ax = 0x0001;
1316 int86 (0x33, &regs, &regs);
1317}
1318
1319void
1320mouse_off ()
1321{
1322 union REGS regs;
1323
1324 regs.x.ax = 0x0002;
1325 int86 (0x33, &regs, &regs);
1326}
1327
1328void
1329mouse_moveto (x, y)
1330 int x, y;
1331{
1332 union REGS regs;
1333
1334 regs.x.ax = 0x0004;
1335 mouse_last_x = regs.x.cx = x * 8;
1336 mouse_last_y = regs.x.dx = y * 8;
1337 int86 (0x33, &regs, &regs);
1338}
1339
1340int
1341mouse_pressed (b, xp, yp)
1342 int b, *xp, *yp;
1343{
1344 union REGS regs;
1345
1346 if (b >= mouse_button_count)
1347 return 0;
1348 regs.x.ax = 0x0005;
1349 regs.x.bx = mouse_button_translate[b];
1350 int86 (0x33, &regs, &regs);
1351 if (regs.x.bx)
ca986694 1352 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1b94449f
RS
1353 return (regs.x.bx != 0);
1354}
1355
1356int
1357mouse_released (b, xp, yp)
1358 int b, *xp, *yp;
1359{
1360 union REGS regs;
1361
1362 if (b >= mouse_button_count)
1363 return 0;
1364 regs.x.ax = 0x0006;
1365 regs.x.bx = mouse_button_translate[b];
1366 int86 (0x33, &regs, &regs);
1367 if (regs.x.bx)
1368 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1369 return (regs.x.bx != 0);
1370}
1371
87485d6f
MW
1372static void
1373mouse_get_xy (int *x, int *y)
1374{
1375 union REGS regs;
1376
1377 regs.x.ax = 0x0003;
1378 int86 (0x33, &regs, &regs);
1379 *x = regs.x.cx / 8;
1380 *y = regs.x.dx / 8;
1381}
1382
1b94449f 1383void
fadfaf55 1384mouse_get_pos (f, insist, bar_window, part, x, y, time)
1b94449f 1385 FRAME_PTR *f;
fadfaf55 1386 int insist;
1b94449f
RS
1387 Lisp_Object *bar_window, *x, *y;
1388 enum scroll_bar_part *part;
1389 unsigned long *time;
1390{
87485d6f 1391 int ix, iy;
1b94449f
RS
1392 union REGS regs;
1393 struct timeval tv;
1394
1395 regs.x.ax = 0x0003;
1396 int86 (0x33, &regs, &regs);
1397 *f = selected_frame;
1398 *bar_window = Qnil;
1399 gettimeofday (&tv, NULL);
87485d6f 1400 mouse_get_xy (&ix, &iy);
f2f23562 1401 selected_frame->mouse_moved = 0;
87485d6f
MW
1402 *x = make_number (ix);
1403 *y = make_number (iy);
1404 *time = tv.tv_usec;
1b94449f
RS
1405}
1406
1407void
1408mouse_check_moved ()
1409{
87485d6f 1410 int x, y;
1b94449f 1411
87485d6f 1412 mouse_get_xy (&x, &y);
f2f23562 1413 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
87485d6f
MW
1414 mouse_last_x = x;
1415 mouse_last_y = y;
1b94449f
RS
1416}
1417
1418int
1419mouse_init1 ()
1420{
1421 union REGS regs;
1422 int present;
1423
87485d6f
MW
1424#ifdef HAVE_X_WINDOWS
1425 if (!inhibit_window_system)
1426 return 0;
1427#endif
e118d5ef
RS
1428 if (!internal_terminal)
1429 return 0;
1430
1b94449f
RS
1431 regs.x.ax = 0x0021;
1432 int86 (0x33, &regs, &regs);
e118d5ef
RS
1433 present = (regs.x.ax & 0xffff) == 0xffff;
1434 if (!present)
1435 {
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. */
1439 regs.x.ax = 0x0000;
1440 int86 (0x33, &regs, &regs);
1441 present = (regs.x.ax & 0xffff) == 0xffff;
1442 }
1443
1b94449f
RS
1444 if (present)
1445 {
1446 if (regs.x.bx == 3)
1447 {
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 */
1452 }
1453 else
1454 {
1455 mouse_button_count = 2;
1456 mouse_button_translate[0] = 0;
1457 mouse_button_translate[1] = 1;
1458 }
1459 mouse_position_hook = &mouse_get_pos;
1460 mouse_init ();
1461 }
1462 return present;
1463}
1464
87485d6f 1465#ifndef HAVE_X_WINDOWS
49a09c76
RS
1466/* See xterm.c for more info. */
1467void
1468pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1469 FRAME_PTR f;
1470 register int pix_x, pix_y;
1471 register int *x, *y;
1472 void /* XRectangle */ *bounds;
1473 int noclip;
1474{
1475 if (bounds) abort ();
1476
1477 /* Ignore clipping. */
1478
1479 *x = pix_x;
1480 *y = pix_y;
1481}
1482
1483void
1484glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1485 FRAME_PTR f;
1486 register int x, y;
1487 register int *pix_x, *pix_y;
1488{
1489 *pix_x = x;
1490 *pix_y = y;
1491}
87485d6f
MW
1492\f
1493/* Simulation of X's menus. Nothing too fancy here -- just make it work
1494 for now.
1495
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. */
1500
1501static XMenu *
1502IT_menu_create ()
1503{
1504 XMenu *menu;
1505
1506 menu = (XMenu *) xmalloc (sizeof (XMenu));
1507 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1508 return menu;
1509}
1510
1511/* Allocate some (more) memory for MENU ensuring that there is room for one
1512 for item. */
1513static void
1514IT_menu_make_room (XMenu *menu)
1515{
1516 if (menu->allocated == 0)
1517 {
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));
1522 }
1523 else if (menu->allocated == menu->count)
1524 {
1525 int count = menu->allocated = menu->allocated + 10;
1526 menu->text
1527 = (char **) xrealloc (menu->text, count * sizeof (char *));
1528 menu->submenu
1529 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1530 menu->panenumber
1531 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1532 }
1533}
1534
1535/* Search the given menu structure for a given pane number. */
1536static XMenu *
1537IT_menu_search_pane (XMenu *menu, int pane)
1538{
1539 int i;
1540 XMenu *try;
1541
1542 for (i = 0; i < menu->count; i++)
1543 if (menu->submenu[i])
1544 if (pane == menu->panenumber[i])
1545 return menu->submenu[i];
1546 else
1547 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1548 return try;
1549 return (XMenu *) 0;
1550}
1551
1552/* Determine how much screen space a given menu needs. */
1553static void
1554IT_menu_calc_size (XMenu *menu, int *width, int *height)
1555{
1556 int i, h2, w2, maxsubwidth, maxheight;
1557
1558 maxsubwidth = 0;
1559 maxheight = menu->count;
1560 for (i = 0; i < menu->count; i++)
1561 {
1562 if (menu->submenu[i])
1563 {
1564 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1565 if (w2 > maxsubwidth) maxsubwidth = w2;
1566 if (i + h2 > maxheight) maxheight = i + h2;
1567 }
1568 }
1569 *width = menu->width + maxsubwidth;
1570 *height = maxheight;
1571}
1572
1573/* Display MENU at (X,Y) using FACES. */
1574static void
1575IT_menu_display (XMenu *menu, int y, int x, int *faces)
1576{
1577 int i, j, face, width;
1578 GLYPH *text, *p;
1579 char *q;
1580 int mx, my;
1581 int enabled, mousehere;
1582 int row, col;
1583
1584 width = menu->width;
1585 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1586 ScreenGetCursor (&row, &col);
1587 mouse_get_xy (&mx, &my);
1588 mouse_off ();
1589 (*update_begin_hook) ();
1590 for (i = 0; i < menu->count; i++)
1591 {
1592 (*cursor_to_hook) (y + i, x);
1593 enabled
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];
1597 p = text;
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);
1605 }
1606 internal_flush (stdout);
1607 (*update_end_hook) ();
1608 mouse_on ();
1609 ScreenSetCursor (row, col);
1610 xfree (text);
1611}
1612
1613/* Create a brand new menu structure. */
1614XMenu *
1189e5a2 1615XMenuCreate (Display *foo1, Window foo2, char *foo3)
87485d6f
MW
1616{
1617 return IT_menu_create ();
1618}
1619
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
1622 to do. */
1623int
1189e5a2 1624XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
87485d6f
MW
1625{
1626 int len;
1627
1628 if (!enable)
1629 abort ();
1630
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;
1635 menu->count++;
1636 if ((len = strlen (txt)) > menu->width) menu->width = len;
1637 return menu->panecount;
1638}
1639
1640/* Create a new item in a menu pane. */
1641int
1189e5a2
RS
1642XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1643 int foo, char *txt, int enable)
87485d6f
MW
1644{
1645 int len;
1646
1647 if (pane)
1648 if (!(menu = IT_menu_search_pane (menu, pane)))
1649 return XM_FAILURE;
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;
1654 menu->count++;
1655 if ((len = strlen (txt)) > menu->width) menu->width = len;
1656 return XM_SUCCESS;
1657}
1658
1659/* Decide where the menu would be placed if requested at (X,Y). */
1189e5a2
RS
1660void
1661XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
87485d6f
MW
1662 int *ulx, int *uly, int *width, int *height)
1663{
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);
1667 else
1668 IT_menu_calc_size (menu, width, height);
1669 *ulx = x + 1;
1670 *uly = y;
1671 *width += 2;
1672}
1673
1674typedef struct
1675{
1676 void *screen_behind;
1677 XMenu *menu;
1678 int pane;
1679 int x, y;
1680} IT_menu_state;
1681
1682
1683/* Display menu, wait for user's response, and return that response. */
1684int
1189e5a2 1685XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
87485d6f
MW
1686 int x0, int y0, unsigned ButtonMask, char **txt)
1687{
1688 IT_menu_state *state;
1689 int statecount;
1690 int x, y, i, b;
1691 int screensize;
1692 int faces[4], selectface;
1693 int leave, result, onepane;
1694
1695 /* Just in case we got here without a mouse present... */
1696 if (!have_mouse)
1697 return XM_IA_SELECT;
1698
1699 state = alloca (menu->panecount * sizeof (IT_menu_state));
1700 screensize = ScreenRows () * ScreenCols () * 2;
1701 faces[0]
1702 = compute_glyph_face (&the_only_frame,
1703 face_name_id_number
1704 (&the_only_frame,
1705 intern ("msdos-menu-passive-face")),
1706 0);
1707 faces[1]
1708 = compute_glyph_face (&the_only_frame,
1709 face_name_id_number
1710 (&the_only_frame,
1711 intern ("msdos-menu-active-face")),
1712 0);
1713 selectface
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]);
1717
1718 statecount = 1;
1719 state[0].menu = menu;
1720 mouse_off ();
1721 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1722 mouse_on ();
1723 if ((onepane = menu->count == 1 && menu->submenu[0]))
1724 {
1725 menu->width = menu->submenu[0]->width;
1726 state[0].menu = menu->submenu[0];
1727 }
1728 else
1729 {
1730 state[0].menu = menu;
1731 }
1732 state[0].x = x0 - 1;
1733 state[0].y = y0;
1734 state[0].pane = onepane;
1735
1736 mouse_last_x = -1; /* A hack that forces display. */
1737 leave = 0;
1738 while (!leave)
1739 {
1740 mouse_check_moved ();
f2f23562 1741 if (selected_frame->mouse_moved)
87485d6f 1742 {
f2f23562 1743 selected_frame->mouse_moved = 0;
87485d6f
MW
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)
1748 {
1749 int dy = y - state[i].y;
1750 if (0 <= dy && dy < state[i].menu->count)
1751 {
1752 if (!state[i].menu->submenu[dy])
1753 if (state[i].menu->panenumber[dy])
1754 result = XM_SUCCESS;
1755 else
1756 result = XM_IA_SELECT;
1757 *pane = state[i].pane - 1;
1758 *selidx = dy;
1759 /* We hit some part of a menu, so drop extra menues that
1760 have been opened. That does not include an open and
1761 active submenu. */
1762 if (i != statecount - 2
1763 || state[i].menu->submenu[dy] != state[i+1].menu)
1764 while (i != statecount - 1)
1765 {
1766 statecount--;
1767 mouse_off ();
1768 ScreenUpdate (state[statecount].screen_behind);
1769 mouse_on ();
1770 xfree (state[statecount].screen_behind);
1771 }
1772 if (i == statecount - 1 && state[i].menu->submenu[dy])
1773 {
1774 IT_menu_display (state[i].menu,
1775 state[i].y,
1776 state[i].x,
1777 faces);
1778 state[statecount].menu = state[i].menu->submenu[dy];
1779 state[statecount].pane = state[i].menu->panenumber[dy];
1780 mouse_off ();
1781 ScreenRetrieve (state[statecount].screen_behind
1782 = xmalloc (screensize));
1783 mouse_on ();
1784 state[statecount].x
1785 = state[i].x + state[i].menu->width + 2;
1786 state[statecount].y = y;
1787 statecount++;
1788 }
1789 }
1790 }
1791 IT_menu_display (state[statecount - 1].menu,
1792 state[statecount - 1].y,
1793 state[statecount - 1].x,
1794 faces);
1795 }
1796 for (b = 0; b < mouse_button_count; b++)
1797 {
1798 (void) mouse_pressed (b, &x, &y);
1799 if (mouse_released (b, &x, &y))
1800 leave = 1;
1801 }
1802 }
1803
1804 mouse_off ();
1805 ScreenUpdate (state[0].screen_behind);
1806 mouse_on ();
1807 while (statecount--)
1808 xfree (state[statecount].screen_behind);
1809 return result;
1810}
1811
1812/* Dispose of a menu. */
1189e5a2
RS
1813void
1814XMenuDestroy (Display *foo, XMenu *menu)
87485d6f
MW
1815{
1816 int i;
1817 if (menu->allocated)
1818 {
1819 for (i = 0; i < menu->count; i++)
1820 if (menu->submenu[i])
1189e5a2 1821 XMenuDestroy (foo, menu->submenu[i]);
87485d6f
MW
1822 xfree (menu->text);
1823 xfree (menu->submenu);
1824 xfree (menu->panenumber);
1825 }
1826 xfree (menu);
1827}
1828
1829int x_pixel_width (struct frame *f)
1830{
1831 return FRAME_WIDTH(f);
1832}
1833
1834int x_pixel_height (struct frame *f)
1835{
1836 return FRAME_HEIGHT(f);
1837}
1838#endif /* !HAVE_X_WINDOWS */
49a09c76 1839
1b94449f 1840#endif /* MSDOS */