(mail-fetch-field): Use buffer-substring-no-properties.
[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". */
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 1382void
fadfaf55 1383mouse_get_pos (f, insist, bar_window, part, x, y, time)
1b94449f 1384 FRAME_PTR *f;
fadfaf55 1385 int insist;
1b94449f
RS
1386 Lisp_Object *bar_window, *x, *y;
1387 enum scroll_bar_part *part;
1388 unsigned long *time;
1389{
87485d6f 1390 int ix, iy;
1b94449f
RS
1391 union REGS regs;
1392 struct timeval tv;
1393
1394 regs.x.ax = 0x0003;
1395 int86 (0x33, &regs, &regs);
1396 *f = selected_frame;
1397 *bar_window = Qnil;
1398 gettimeofday (&tv, NULL);
87485d6f 1399 mouse_get_xy (&ix, &iy);
f2f23562 1400 selected_frame->mouse_moved = 0;
87485d6f
MW
1401 *x = make_number (ix);
1402 *y = make_number (iy);
1403 *time = tv.tv_usec;
1b94449f
RS
1404}
1405
1406void
1407mouse_check_moved ()
1408{
87485d6f 1409 int x, y;
1b94449f 1410
87485d6f 1411 mouse_get_xy (&x, &y);
f2f23562 1412 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
87485d6f
MW
1413 mouse_last_x = x;
1414 mouse_last_y = y;
1b94449f
RS
1415}
1416
1417int
1418mouse_init1 ()
1419{
1420 union REGS regs;
1421 int present;
1422
87485d6f
MW
1423#ifdef HAVE_X_WINDOWS
1424 if (!inhibit_window_system)
1425 return 0;
1426#endif
e118d5ef
RS
1427 if (!internal_terminal)
1428 return 0;
1429
1b94449f
RS
1430 regs.x.ax = 0x0021;
1431 int86 (0x33, &regs, &regs);
e118d5ef
RS
1432 present = (regs.x.ax & 0xffff) == 0xffff;
1433 if (!present)
1434 {
1435 /* Reportedly, the above doesn't work for some mouse drivers. There
1436 is an additional detection method that should work, but might be
1437 a little slower. Use that as an alternative. */
1438 regs.x.ax = 0x0000;
1439 int86 (0x33, &regs, &regs);
1440 present = (regs.x.ax & 0xffff) == 0xffff;
1441 }
1442
1b94449f
RS
1443 if (present)
1444 {
1445 if (regs.x.bx == 3)
1446 {
1447 mouse_button_count = 3;
1448 mouse_button_translate[0] = 0; /* Left */
1449 mouse_button_translate[1] = 2; /* Middle */
1450 mouse_button_translate[2] = 1; /* Right */
1451 }
1452 else
1453 {
1454 mouse_button_count = 2;
1455 mouse_button_translate[0] = 0;
1456 mouse_button_translate[1] = 1;
1457 }
1458 mouse_position_hook = &mouse_get_pos;
1459 mouse_init ();
1460 }
1461 return present;
1462}
1463
87485d6f 1464#ifndef HAVE_X_WINDOWS
49a09c76
RS
1465/* See xterm.c for more info. */
1466void
1467pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1468 FRAME_PTR f;
1469 register int pix_x, pix_y;
1470 register int *x, *y;
1471 void /* XRectangle */ *bounds;
1472 int noclip;
1473{
1474 if (bounds) abort ();
1475
1476 /* Ignore clipping. */
1477
1478 *x = pix_x;
1479 *y = pix_y;
1480}
1481
1482void
1483glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1484 FRAME_PTR f;
1485 register int x, y;
1486 register int *pix_x, *pix_y;
1487{
1488 *pix_x = x;
1489 *pix_y = y;
1490}
87485d6f
MW
1491\f
1492/* Simulation of X's menus. Nothing too fancy here -- just make it work
1493 for now.
1494
1495 Actually, I don't know the meaning of all the parameters of the functions
1496 here -- I only know how they are called by xmenu.c. I could of course
1497 grab the nearest Xlib manual (down the hall, second-to-last door on the
1498 left), but I don't think it's worth the effort. */
1499
1500static XMenu *
1501IT_menu_create ()
1502{
1503 XMenu *menu;
1504
1505 menu = (XMenu *) xmalloc (sizeof (XMenu));
1506 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1507 return menu;
1508}
1509
1510/* Allocate some (more) memory for MENU ensuring that there is room for one
1511 for item. */
1512static void
1513IT_menu_make_room (XMenu *menu)
1514{
1515 if (menu->allocated == 0)
1516 {
1517 int count = menu->allocated = 10;
1518 menu->text = (char **) xmalloc (count * sizeof (char *));
1519 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1520 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1521 }
1522 else if (menu->allocated == menu->count)
1523 {
1524 int count = menu->allocated = menu->allocated + 10;
1525 menu->text
1526 = (char **) xrealloc (menu->text, count * sizeof (char *));
1527 menu->submenu
1528 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1529 menu->panenumber
1530 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1531 }
1532}
1533
1534/* Search the given menu structure for a given pane number. */
1535static XMenu *
1536IT_menu_search_pane (XMenu *menu, int pane)
1537{
1538 int i;
1539 XMenu *try;
1540
1541 for (i = 0; i < menu->count; i++)
1542 if (menu->submenu[i])
1543 if (pane == menu->panenumber[i])
1544 return menu->submenu[i];
1545 else
1546 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1547 return try;
1548 return (XMenu *) 0;
1549}
1550
1551/* Determine how much screen space a given menu needs. */
1552static void
1553IT_menu_calc_size (XMenu *menu, int *width, int *height)
1554{
1555 int i, h2, w2, maxsubwidth, maxheight;
1556
1557 maxsubwidth = 0;
1558 maxheight = menu->count;
1559 for (i = 0; i < menu->count; i++)
1560 {
1561 if (menu->submenu[i])
1562 {
1563 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1564 if (w2 > maxsubwidth) maxsubwidth = w2;
1565 if (i + h2 > maxheight) maxheight = i + h2;
1566 }
1567 }
1568 *width = menu->width + maxsubwidth;
1569 *height = maxheight;
1570}
1571
1572/* Display MENU at (X,Y) using FACES. */
1573static void
1574IT_menu_display (XMenu *menu, int y, int x, int *faces)
1575{
1576 int i, j, face, width;
1577 GLYPH *text, *p;
1578 char *q;
1579 int mx, my;
1580 int enabled, mousehere;
1581 int row, col;
1582
1583 width = menu->width;
1584 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1585 ScreenGetCursor (&row, &col);
1586 mouse_get_xy (&mx, &my);
1587 mouse_off ();
1588 (*update_begin_hook) ();
1589 for (i = 0; i < menu->count; i++)
1590 {
1591 (*cursor_to_hook) (y + i, x);
1592 enabled
1593 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1594 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1595 face = faces[enabled + mousehere * 2];
1596 p = text;
1597 *p++ = FAST_MAKE_GLYPH (' ', face);
1598 for (j = 0, q = menu->text[i]; *q; j++)
1599 *p++ = FAST_MAKE_GLYPH (*q++, face);
1600 for (; j < width; j++)
1601 *p++ = FAST_MAKE_GLYPH (' ', face);
1602 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1603 (*write_glyphs_hook) (text, width + 2);
1604 }
1605 internal_flush (stdout);
1606 (*update_end_hook) ();
1607 mouse_on ();
1608 ScreenSetCursor (row, col);
1609 xfree (text);
1610}
1611
1612/* Create a brand new menu structure. */
1613XMenu *
1189e5a2 1614XMenuCreate (Display *foo1, Window foo2, char *foo3)
87485d6f
MW
1615{
1616 return IT_menu_create ();
1617}
1618
1619/* Create a new pane and place it on the outer-most level. It is not
1620 clear that it should be placed out there, but I don't know what else
1621 to do. */
1622int
1189e5a2 1623XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
87485d6f
MW
1624{
1625 int len;
1626
1627 if (!enable)
1628 abort ();
1629
1630 IT_menu_make_room (menu);
1631 menu->submenu[menu->count] = IT_menu_create ();
1632 menu->text[menu->count] = txt;
1633 menu->panenumber[menu->count] = ++menu->panecount;
1634 menu->count++;
1635 if ((len = strlen (txt)) > menu->width) menu->width = len;
1636 return menu->panecount;
1637}
1638
1639/* Create a new item in a menu pane. */
1640int
1189e5a2
RS
1641XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1642 int foo, char *txt, int enable)
87485d6f
MW
1643{
1644 int len;
1645
1646 if (pane)
1647 if (!(menu = IT_menu_search_pane (menu, pane)))
1648 return XM_FAILURE;
1649 IT_menu_make_room (menu);
1650 menu->submenu[menu->count] = (XMenu *) 0;
1651 menu->text[menu->count] = txt;
1652 menu->panenumber[menu->count] = enable;
1653 menu->count++;
1654 if ((len = strlen (txt)) > menu->width) menu->width = len;
1655 return XM_SUCCESS;
1656}
1657
1658/* Decide where the menu would be placed if requested at (X,Y). */
1189e5a2
RS
1659void
1660XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
87485d6f
MW
1661 int *ulx, int *uly, int *width, int *height)
1662{
1663 if (menu->count == 1 && menu->submenu[0])
1664 /* Special case: the menu consists of only one pane. */
1665 IT_menu_calc_size (menu->submenu[0], width, height);
1666 else
1667 IT_menu_calc_size (menu, width, height);
1668 *ulx = x + 1;
1669 *uly = y;
1670 *width += 2;
1671}
1672
1673typedef struct
1674{
1675 void *screen_behind;
1676 XMenu *menu;
1677 int pane;
1678 int x, y;
1679} IT_menu_state;
1680
1681
1682/* Display menu, wait for user's response, and return that response. */
1683int
1189e5a2 1684XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
87485d6f
MW
1685 int x0, int y0, unsigned ButtonMask, char **txt)
1686{
1687 IT_menu_state *state;
1688 int statecount;
1689 int x, y, i, b;
1690 int screensize;
1691 int faces[4], selectface;
1692 int leave, result, onepane;
1693
1694 /* Just in case we got here without a mouse present... */
1695 if (!have_mouse)
1696 return XM_IA_SELECT;
1697
1698 state = alloca (menu->panecount * sizeof (IT_menu_state));
1699 screensize = ScreenRows () * ScreenCols () * 2;
1700 faces[0]
1701 = compute_glyph_face (&the_only_frame,
1702 face_name_id_number
1703 (&the_only_frame,
1704 intern ("msdos-menu-passive-face")),
1705 0);
1706 faces[1]
1707 = compute_glyph_face (&the_only_frame,
1708 face_name_id_number
1709 (&the_only_frame,
1710 intern ("msdos-menu-active-face")),
1711 0);
1712 selectface
1713 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1714 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1715 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1716
1717 statecount = 1;
1718 state[0].menu = menu;
1719 mouse_off ();
1720 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1721 mouse_on ();
1722 if ((onepane = menu->count == 1 && menu->submenu[0]))
1723 {
1724 menu->width = menu->submenu[0]->width;
1725 state[0].menu = menu->submenu[0];
1726 }
1727 else
1728 {
1729 state[0].menu = menu;
1730 }
1731 state[0].x = x0 - 1;
1732 state[0].y = y0;
1733 state[0].pane = onepane;
1734
1735 mouse_last_x = -1; /* A hack that forces display. */
1736 leave = 0;
1737 while (!leave)
1738 {
1739 mouse_check_moved ();
f2f23562 1740 if (selected_frame->mouse_moved)
87485d6f 1741 {
f2f23562 1742 selected_frame->mouse_moved = 0;
87485d6f
MW
1743 result = XM_IA_SELECT;
1744 mouse_get_xy (&x, &y);
1745 for (i = 0; i < statecount; i++)
1746 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1747 {
1748 int dy = y - state[i].y;
1749 if (0 <= dy && dy < state[i].menu->count)
1750 {
1751 if (!state[i].menu->submenu[dy])
1752 if (state[i].menu->panenumber[dy])
1753 result = XM_SUCCESS;
1754 else
1755 result = XM_IA_SELECT;
1756 *pane = state[i].pane - 1;
1757 *selidx = dy;
1758 /* We hit some part of a menu, so drop extra menues that
1759 have been opened. That does not include an open and
1760 active submenu. */
1761 if (i != statecount - 2
1762 || state[i].menu->submenu[dy] != state[i+1].menu)
1763 while (i != statecount - 1)
1764 {
1765 statecount--;
1766 mouse_off ();
1767 ScreenUpdate (state[statecount].screen_behind);
1768 mouse_on ();
1769 xfree (state[statecount].screen_behind);
1770 }
1771 if (i == statecount - 1 && state[i].menu->submenu[dy])
1772 {
1773 IT_menu_display (state[i].menu,
1774 state[i].y,
1775 state[i].x,
1776 faces);
1777 state[statecount].menu = state[i].menu->submenu[dy];
1778 state[statecount].pane = state[i].menu->panenumber[dy];
1779 mouse_off ();
1780 ScreenRetrieve (state[statecount].screen_behind
1781 = xmalloc (screensize));
1782 mouse_on ();
1783 state[statecount].x
1784 = state[i].x + state[i].menu->width + 2;
1785 state[statecount].y = y;
1786 statecount++;
1787 }
1788 }
1789 }
1790 IT_menu_display (state[statecount - 1].menu,
1791 state[statecount - 1].y,
1792 state[statecount - 1].x,
1793 faces);
1794 }
1795 for (b = 0; b < mouse_button_count; b++)
1796 {
1797 (void) mouse_pressed (b, &x, &y);
1798 if (mouse_released (b, &x, &y))
1799 leave = 1;
1800 }
1801 }
1802
1803 mouse_off ();
1804 ScreenUpdate (state[0].screen_behind);
1805 mouse_on ();
1806 while (statecount--)
1807 xfree (state[statecount].screen_behind);
1808 return result;
1809}
1810
1811/* Dispose of a menu. */
1189e5a2
RS
1812void
1813XMenuDestroy (Display *foo, XMenu *menu)
87485d6f
MW
1814{
1815 int i;
1816 if (menu->allocated)
1817 {
1818 for (i = 0; i < menu->count; i++)
1819 if (menu->submenu[i])
1189e5a2 1820 XMenuDestroy (foo, menu->submenu[i]);
87485d6f
MW
1821 xfree (menu->text);
1822 xfree (menu->submenu);
1823 xfree (menu->panenumber);
1824 }
1825 xfree (menu);
1826}
1827
1828int x_pixel_width (struct frame *f)
1829{
1830 return FRAME_WIDTH(f);
1831}
1832
1833int x_pixel_height (struct frame *f)
1834{
1835 return FRAME_HEIGHT(f);
1836}
1837#endif /* !HAVE_X_WINDOWS */
49a09c76 1838
1b94449f 1839#endif /* MSDOS */