1/* MS-DOS specific C utilities.          -*- coding: raw-text -*-
2   Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3                 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING.  If not, write to
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA.  */
21
22/* Contributed by Morten Welinder */
23/* New display, keyboard, and mouse control by Kim F. Storm */
24
25/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26
27#include <config.h>
28
29#ifdef MSDOS
30#include "lisp.h"
31#include <stdio.h>
32#include <stdlib.h>
33#include <time.h>
34#include <sys/param.h>
35#include <sys/time.h>
36#include <dos.h>
37#include <errno.h>
38#include <string.h>	 /* for bzero and string functions */
39#include <sys/stat.h>    /* for _fixpath */
40#include <unistd.h>	 /* for chdir, dup, dup2, etc. */
41#include <dir.h>	 /* for getdisk */
42#if __DJGPP__ >= 2
43#pragma pack(0)		 /* dir.h does a pack(4), which isn't GCC's default */
44#include <fcntl.h>
45#include <io.h>		 /* for setmode */
46#include <dpmi.h>	 /* for __dpmi_xxx stuff */
47#include <sys/farptr.h>	 /* for _farsetsel, _farnspokeb */
48#include <libc/dosio.h>  /* for _USE_LFN */
49#include <conio.h>	 /* for cputs */
50#endif
51
52#include "msdos.h"
53#include "systime.h"
54#include "termhooks.h"
55#include "termchar.h"
56#include "dispextern.h"
57#include "dosfns.h"
58#include "termopts.h"
59#include "charset.h"
60#include "coding.h"
61#include "disptab.h"
62#include "frame.h"
63#include "window.h"
64#include "buffer.h"
65#include "commands.h"
66#include "blockinput.h"
67#include "keyboard.h"
68#include "intervals.h"
69#include <go32.h>
70#include <pc.h>
71#include <ctype.h>
72/* #include <process.h> */
73/* Damn that local process.h!  Instead we can define P_WAIT ourselves.  */
74#define P_WAIT 1
75
76#ifndef _USE_LFN
77#define _USE_LFN 0
78#endif
79
80#ifndef _dos_ds
81#define _dos_ds _go32_info_block.selector_for_linear_memory
82#endif
83
84#if __DJGPP__ > 1
85
86#include <signal.h>
87#include "syssignal.h"
88
89#ifndef SYSTEM_MALLOC
90
91#ifdef GNU_MALLOC
92
93/* If other `malloc' than ours is used, force our `sbrk' behave like
94   Unix programs expect (resize memory blocks to keep them contiguous).
95   If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
96   because that's what `gmalloc' expects to get.  */
97#include <crt0.h>
98
99#ifdef REL_ALLOC
100int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
101#else  /* not REL_ALLOC */
102int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
103#endif /* not REL_ALLOC */
104#endif /* GNU_MALLOC */
105
106#endif /* not SYSTEM_MALLOC */
107#endif /* __DJGPP__ > 1 */
108
109static unsigned long
110event_timestamp ()
111{
112  struct time t;
113  unsigned long s;
114
115  gettime (&t);
116  s = t.ti_min;
117  s *= 60;
118  s += t.ti_sec;
119  s *= 1000;
120  s += t.ti_hund * 10;
121
122  return s;
123}
124
125
126/* ------------------------ Mouse control ---------------------------
127 *
128 * Coordinates are in screen positions and zero based.
129 * Mouse buttons are numbered from left to right and also zero based.
130 */
131
132/* This used to be in termhooks.h, but mainstream Emacs code no longer
133   uses it, and it was removed...  */
134#define NUM_MOUSE_BUTTONS (5)
135
136int have_mouse;          /* 0: no, 1: enabled, -1: disabled */
137static int mouse_visible;
138
139static int mouse_last_x;
140static int mouse_last_y;
141
142static int mouse_button_translate[NUM_MOUSE_BUTTONS];
143static int mouse_button_count;
144
145void
146mouse_on ()
147{
148  union REGS regs;
149
150  if (have_mouse > 0 && !mouse_visible)
151    {
152      if (termscript)
153	fprintf (termscript, "<M_ON>");
154      regs.x.ax = 0x0001;
155      int86 (0x33, &regs, &regs);
156      mouse_visible = 1;
157    }
158}
159
160void
161mouse_off ()
162{
163  union REGS regs;
164
165  if (have_mouse > 0 && mouse_visible)
166    {
167      if (termscript)
168	fprintf (termscript, "<M_OFF>");
169      regs.x.ax = 0x0002;
170      int86 (0x33, &regs, &regs);
171      mouse_visible = 0;
172    }
173}
174
175static void
176mouse_setup_buttons (int n_buttons)
177{
178  if (n_buttons == 3)
179    {
180      mouse_button_count = 3;
181      mouse_button_translate[0] = 0; /* Left */
182      mouse_button_translate[1] = 2; /* Middle */
183      mouse_button_translate[2] = 1; /* Right */
184    }
185  else	/* two, what else? */
186    {
187      mouse_button_count = 2;
188      mouse_button_translate[0] = 0;
189      mouse_button_translate[1] = 1;
190    }
191}
192
193DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
194       1, 1, "NSet number of mouse buttons to: ",
195       doc: /* Set the number of mouse buttons to use by Emacs.
196This is useful with mice that report the number of buttons inconsistently,
197e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
198them.  This happens with wheeled mice on Windows 9X, for example.  */)
199     (nbuttons)
200     Lisp_Object nbuttons;
201{
202  int n;
203
204  CHECK_NUMBER (nbuttons);
205  n = XINT (nbuttons);
206  if (n < 2 || n > 3)
207    xsignal2 (Qargs_out_of_range,
208	      build_string ("only 2 or 3 mouse buttons are supported"),
209	      nbuttons);
210  mouse_setup_buttons (n);
211  return Qnil;
212}
213
214static void
215mouse_get_xy (int *x, int *y)
216{
217  union REGS regs;
218
219  regs.x.ax = 0x0003;
220  int86 (0x33, &regs, &regs);
221  *x = regs.x.cx / 8;
222  *y = regs.x.dx / 8;
223}
224
225void
226mouse_moveto (x, y)
227     int x, y;
228{
229  union REGS regs;
230
231  if (termscript)
232    fprintf (termscript, "<M_XY=%dx%d>", x, y);
233  regs.x.ax = 0x0004;
234  mouse_last_x = regs.x.cx = x * 8;
235  mouse_last_y = regs.x.dx = y * 8;
236  int86 (0x33, &regs, &regs);
237}
238
239static int
240mouse_pressed (b, xp, yp)
241     int b, *xp, *yp;
242{
243  union REGS regs;
244
245  if (b >= mouse_button_count)
246    return 0;
247  regs.x.ax = 0x0005;
248  regs.x.bx = mouse_button_translate[b];
249  int86 (0x33, &regs, &regs);
250  if (regs.x.bx)
251    *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
252  return (regs.x.bx != 0);
253}
254
255static int
256mouse_released (b, xp, yp)
257     int b, *xp, *yp;
258{
259  union REGS regs;
260
261  if (b >= mouse_button_count)
262    return 0;
263  regs.x.ax = 0x0006;
264  regs.x.bx = mouse_button_translate[b];
265  int86 (0x33, &regs, &regs);
266  if (regs.x.bx)
267    *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
268  return (regs.x.bx != 0);
269}
270
271static int
272mouse_button_depressed (b, xp, yp)
273     int b, *xp, *yp;
274{
275  union REGS regs;
276
277  if (b >= mouse_button_count)
278    return 0;
279  regs.x.ax = 0x0003;
280  int86 (0x33, &regs, &regs);
281  if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
282    {
283      *xp = regs.x.cx / 8;
284      *yp = regs.x.dx / 8;
285      return 1;
286    }
287  return 0;
288}
289
290void
291mouse_get_pos (f, insist, bar_window, part, x, y, time)
292     FRAME_PTR *f;
293     int insist;
294     Lisp_Object *bar_window, *x, *y;
295     enum scroll_bar_part *part;
296     unsigned long *time;
297{
298  int ix, iy;
299  Lisp_Object frame, tail;
300
301  /* Clear the mouse-moved flag for every frame on this display.  */
302  FOR_EACH_FRAME (tail, frame)
303    XFRAME (frame)->mouse_moved = 0;
304
305  *f = SELECTED_FRAME();
306  *bar_window = Qnil;
307  mouse_get_xy (&ix, &iy);
308  *time = event_timestamp ();
309  *x = make_number (mouse_last_x = ix);
310  *y = make_number (mouse_last_y = iy);
311}
312
313static void
314mouse_check_moved ()
315{
316  int x, y;
317
318  mouse_get_xy (&x, &y);
319  SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
320  mouse_last_x = x;
321  mouse_last_y = y;
322}
323
324/* Force the mouse driver to ``forget'' about any button clicks until
325   now.  */
326static void
327mouse_clear_clicks (void)
328{
329  int b;
330
331  for (b = 0; b < mouse_button_count; b++)
332    {
333      int dummy_x, dummy_y;
334
335      (void) mouse_pressed (b, &dummy_x, &dummy_y);
336      (void) mouse_released (b, &dummy_x, &dummy_y);
337    }
338}
339
340void
341mouse_init ()
342{
343  union REGS regs;
344
345  if (termscript)
346    fprintf (termscript, "<M_INIT>");
347
348  regs.x.ax = 0x0021;
349  int86 (0x33, &regs, &regs);
350
351  /* Reset the mouse last press/release info.  It seems that Windows
352     doesn't do that automatically when function 21h is called, which
353     causes Emacs to ``remember'' the click that switched focus to the
354     window just before Emacs was started from that window.  */
355  mouse_clear_clicks ();
356
357  regs.x.ax = 0x0007;
358  regs.x.cx = 0;
359  regs.x.dx = 8 * (ScreenCols () - 1);
360  int86 (0x33, &regs, &regs);
361
362  regs.x.ax = 0x0008;
363  regs.x.cx = 0;
364  regs.x.dx = 8 * (ScreenRows () - 1);
365  int86 (0x33, &regs, &regs);
366
367  mouse_moveto (0, 0);
368  mouse_visible = 0;
369}
370
371/* ------------------------- Screen control ----------------------
372 *
373 */
374
375static int internal_terminal = 0;
376
377#ifndef HAVE_X_WINDOWS
378extern unsigned char ScreenAttrib;
379static int screen_face;
380
381static int screen_size_X;
382static int screen_size_Y;
383static int screen_size;
384
385static int current_pos_X;
386static int current_pos_Y;
387static int new_pos_X;
388static int new_pos_Y;
389
390static void *startup_screen_buffer;
391static int startup_screen_size_X;
392static int startup_screen_size_Y;
393static int startup_pos_X;
394static int startup_pos_Y;
395static unsigned char startup_screen_attrib;
396
397static clock_t startup_time;
398
399static int term_setup_done;
400
401static unsigned short outside_cursor;
402
403/* Similar to the_only_frame.  */
404struct x_output the_only_x_display;
405
406/* Support for DOS/V (allows Japanese characters to be displayed on
407   standard, non-Japanese, ATs).  Only supported for DJGPP v2 and later.  */
408
409/* Holds the address of the text-mode screen buffer.  */
410static unsigned long screen_old_address = 0;
411/* Segment and offset of the virtual screen.  If 0, DOS/V is NOT loaded.  */
412static unsigned short screen_virtual_segment = 0;
413static unsigned short screen_virtual_offset = 0;
414/* A flag to control how to display unibyte 8-bit characters.  */
415extern int unibyte_display_via_language_environment;
416
417extern Lisp_Object Qcursor_type;
418extern Lisp_Object Qbar, Qhbar;
419
420/* The screen colors of the current frame, which serve as the default
421   colors for newly-created frames.  */
422static int initial_screen_colors[2];
423
424#if __DJGPP__ > 1
425/* Update the screen from a part of relocated DOS/V screen buffer which
426   begins at OFFSET and includes COUNT characters.  */
427static void
428dosv_refresh_virtual_screen (int offset, int count)
429{
430  __dpmi_regs regs;
431
432  if (offset < 0 || count < 0)	/* paranoia; invalid values crash DOS/V */
433    return;
434
435  regs.h.ah = 0xff;	/* update relocated screen */
436  regs.x.es = screen_virtual_segment;
437  regs.x.di = screen_virtual_offset + offset;
438  regs.x.cx = count;
439  __dpmi_int (0x10, &regs);
440}
441#endif
442
443static void
444dos_direct_output (y, x, buf, len)
445     int x, y;
446     char *buf;
447     int len;
448{
449  int t0 = 2 * (x + y * screen_size_X);
450  int t = t0 + (int) ScreenPrimary;
451  int l0 = len;
452
453#if (__DJGPP__ < 2)
454  while (--len >= 0) {
455    dosmemput (buf++, 1, t);
456    t += 2;
457  }
458#else
459  /* This is faster.  */
460  for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
461    _farnspokeb (t, *buf);
462
463  if (screen_virtual_segment)
464    dosv_refresh_virtual_screen (t0, l0);
465#endif
466}
467#endif
468
469/* Flash the screen as a substitute for BEEPs.  */
470
471#if (__DJGPP__ < 2)
472static void
473do_visible_bell (xorattr)
474     unsigned char xorattr;
475{
476  asm volatile
477    ("  movb   $1,%%dl				\n\
478visible_bell_0:					\n\
479	movl   _ScreenPrimary,%%eax		\n\
480	call   dosmemsetup			\n\
481	movl   %%eax,%%ebx			\n\
482	movl   %1,%%ecx				\n\
483	movb   %0,%%al				\n\
484	incl   %%ebx				\n\
485visible_bell_1:					\n\
486	xorb   %%al,%%gs:(%%ebx)		\n\
487	addl   $2,%%ebx				\n\
488	decl   %%ecx				\n\
489	jne    visible_bell_1			\n\
490	decb   %%dl				\n\
491	jne    visible_bell_3			\n\
492visible_bell_2:					\n\
493	movzwl %%ax,%%eax			\n\
494        movzwl %%ax,%%eax			\n\
495	movzwl %%ax,%%eax			\n\
496	movzwl %%ax,%%eax			\n\
497	decw   %%cx				\n\
498	jne    visible_bell_2			\n\
499	jmp    visible_bell_0                   \n\
500visible_bell_3:"
501     : /* no output */
502     : "m" (xorattr), "g" (screen_size)
503     : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
504}
505
506static void
507ScreenVisualBell (void)
508{
509  /* This creates an xor-mask that will swap the default fore- and
510     background colors.  */
511  do_visible_bell (((the_only_x_display.foreground_pixel
512		     ^ the_only_x_display.background_pixel)
513		    * 0x11) & 0x7f);
514}
515#endif
516
517#ifndef HAVE_X_WINDOWS
518
519static int blink_bit = -1;	/* the state of the blink bit at startup */
520
521/* Enable bright background colors.  */
522static void
523bright_bg (void)
524{
525  union REGS regs;
526
527  /* Remember the original state of the blink/bright-background bit.
528     It is stored at 0040:0065h in the BIOS data area.  */
529  if (blink_bit == -1)
530    blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
531
532  regs.h.bl = 0;
533  regs.x.ax = 0x1003;
534  int86 (0x10, &regs, &regs);
535}
536
537/* Disable bright background colors (and enable blinking) if we found
538   the video system in that state at startup.  */
539static void
540maybe_enable_blinking (void)
541{
542  if (blink_bit == 1)
543    {
544      union REGS regs;
545
546      regs.h.bl = 1;
547      regs.x.ax = 0x1003;
548      int86 (0x10, &regs, &regs);
549    }
550}
551
552/* Return non-zero if the system has a VGA adapter.  */
553static int
554vga_installed (void)
555{
556  union REGS regs;
557
558  regs.x.ax = 0x1a00;
559  int86 (0x10, &regs, &regs);
560  if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
561    return 1;
562  return 0;
563}
564
565/* Set the screen dimensions so that it can show no less than
566   ROWS x COLS frame.  */
567
568void
569dos_set_window_size (rows, cols)
570     int *rows, *cols;
571{
572  char video_name[30];
573  union REGS regs;
574  Lisp_Object video_mode;
575  int video_mode_value, have_vga = 0;
576  int current_rows = ScreenRows (), current_cols = ScreenCols ();
577
578  if (*rows == current_rows && *cols == current_cols)
579    return;
580
581  mouse_off ();
582  have_vga = vga_installed ();
583
584  /* If the user specified a special video mode for these dimensions,
585     use that mode.  */
586  sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
587  video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
588				      Qnil))-> value;
589
590  if (INTEGERP (video_mode)
591      && (video_mode_value = XINT (video_mode)) > 0)
592    {
593      regs.x.ax = video_mode_value;
594      int86 (0x10, &regs, &regs);
595
596      if (have_mouse)
597	{
598	  /* Must hardware-reset the mouse, or else it won't update
599	     its notion of screen dimensions for some non-standard
600	     video modes.  This is *painfully* slow...  */
601	  regs.x.ax = 0;
602	  int86 (0x33, &regs, &regs);
603	}
604    }
605
606  /* Find one of the dimensions supported by standard EGA/VGA
607     which gives us at least the required dimensions.  */
608
609#if __DJGPP__ > 1
610
611  else
612    {
613      static struct {
614	int rows, need_vga;
615      }	std_dimension[] = {
616	  {25, 0},
617	  {28, 1},
618	  {35, 0},
619	  {40, 1},
620	  {43, 0},
621	  {50, 1}
622      };
623      int i = 0;
624
625      while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
626	{
627	 if (std_dimension[i].need_vga <= have_vga
628	     && std_dimension[i].rows >= *rows)
629	   {
630	     if (std_dimension[i].rows != current_rows
631		 || *cols != current_cols)
632	       _set_screen_lines (std_dimension[i].rows);
633	     break;
634	   }
635	 i++;
636	}
637    }
638
639#else /* not __DJGPP__ > 1 */
640
641  else if (*rows <= 25)
642    {
643      if (current_rows != 25 || current_cols != 80)
644	{
645	  regs.x.ax = 3;
646	  int86 (0x10, &regs, &regs);
647	  regs.x.ax = 0x1101;
648	  regs.h.bl = 0;
649	  int86 (0x10, &regs, &regs);
650	  regs.x.ax = 0x1200;
651	  regs.h.bl = 32;
652	  int86 (0x10, &regs, &regs);
653	  regs.x.ax = 3;
654	  int86 (0x10, &regs, &regs);
655	}
656    }
657  else if (*rows <= 50)
658    if (have_vga && (current_rows != 50 || current_cols != 80)
659	|| *rows <= 43 && (current_rows != 43 || current_cols != 80))
660      {
661	regs.x.ax = 3;
662	int86 (0x10, &regs, &regs);
663	regs.x.ax = 0x1112;
664	regs.h.bl = 0;
665	int86 (0x10, &regs, &regs);
666	regs.x.ax = 0x1200;
667	regs.h.bl = 32;
668	int86 (0x10, &regs, &regs);
669	regs.x.ax = 0x0100;
670	regs.x.cx = 7;
671	int86 (0x10, &regs, &regs);
672      }
673#endif /* not __DJGPP__ > 1 */
674
675  if (have_mouse)
676    {
677      mouse_init ();
678      mouse_on ();
679    }
680
681  /* Tell the caller what dimensions have been REALLY set.  */
682  *rows = ScreenRows ();
683  *cols = ScreenCols ();
684
685  /* Update Emacs' notion of screen dimensions.  */
686  screen_size_X = *cols;
687  screen_size_Y = *rows;
688  screen_size = *cols * *rows;
689
690#if __DJGPP__ > 1
691  /* If the dimensions changed, the mouse highlight info is invalid.  */
692  if (current_rows != *rows || current_cols != *cols)
693    {
694      struct frame *f = SELECTED_FRAME();
695      struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
696      Lisp_Object window = dpyinfo->mouse_face_window;
697
698      if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
699	{
700	  dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
701	  dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
702	  dpyinfo->mouse_face_window = Qnil;
703	}
704    }
705#endif
706
707  /* Enable bright background colors.  */
708  bright_bg ();
709
710  /* FIXME: I'm not sure the above will run at all on DOS/V.  But let's
711     be defensive anyway.  */
712  if (screen_virtual_segment)
713    dosv_refresh_virtual_screen (0, *cols * *rows);
714}
715
716/* If we write a character in the position where the mouse is,
717   the mouse cursor may need to be refreshed.  */
718
719static void
720mouse_off_maybe ()
721{
722  int x, y;
723
724  if (!mouse_visible)
725    return;
726
727  mouse_get_xy (&x, &y);
728  if (y != new_pos_Y || x < new_pos_X)
729    return;
730
731  mouse_off ();
732}
733
734#define DEFAULT_CURSOR_START (-1)
735#define DEFAULT_CURSOR_WIDTH (-1)
736#define BOX_CURSOR_WIDTH     (-32)
737
738/* Set cursor to begin at scan line START_LINE in the character cell
739   and extend for WIDTH scan lines.  Scan lines are counted from top
740   of the character cell, starting from zero.  */
741static void
742msdos_set_cursor_shape (struct frame *f, int start_line, int width)
743{
744#if __DJGPP__ > 1
745  unsigned desired_cursor;
746  __dpmi_regs regs;
747  int max_line, top_line, bot_line;
748
749  /* Avoid the costly BIOS call if F isn't the currently selected
750     frame.  Allow for NULL as unconditionally meaning the selected
751     frame.  */
752  if (f && f != SELECTED_FRAME())
753    return;
754
755  if (termscript)
756    fprintf (termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
757
758  /* The character cell size in scan lines is stored at 40:85 in the
759     BIOS data area.  */
760  max_line = _farpeekw (_dos_ds, 0x485) - 1;
761  switch (max_line)
762    {
763      default:	/* this relies on CGA cursor emulation being ON! */
764      case 7:
765	bot_line = 7;
766	break;
767      case 9:
768	bot_line = 9;
769	break;
770      case 13:
771	bot_line = 12;
772	break;
773      case 15:
774	bot_line = 14;
775	break;
776    }
777
778  if (width < 0)
779    {
780      if (width == BOX_CURSOR_WIDTH)
781	{
782	  top_line = 0;
783	  bot_line = max_line;
784	}
785      else if (start_line != DEFAULT_CURSOR_START)
786	{
787	  top_line = start_line;
788	  bot_line = top_line - width - 1;
789	}
790      else if (width != DEFAULT_CURSOR_WIDTH)
791	{
792	  top_line = 0;
793	  bot_line = -1 - width;
794	}
795      else
796	top_line = bot_line + 1;
797    }
798  else if (width == 0)
799    {
800      /* [31, 0] seems to DTRT for all screen sizes.  */
801      top_line = 31;
802      bot_line = 0;
803    }
804  else	/* WIDTH is positive */
805    {
806      if (start_line != DEFAULT_CURSOR_START)
807	bot_line = start_line;
808      top_line = bot_line - (width - 1);
809    }
810
811  /* If the current cursor shape is already what they want, we are
812     history here.  */
813  desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
814  if (desired_cursor == _farpeekw (_dos_ds, 0x460))
815    return;
816
817  regs.h.ah = 1;
818  regs.x.cx = desired_cursor;
819  __dpmi_int (0x10, &regs);
820#endif /* __DJGPP__ > 1 */
821}
822
823static void
824IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
825{
826  if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
827    {
828      /* Just BAR means the normal EGA/VGA cursor.  */
829      msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
830    }
831  else if (CONSP (cursor_type)
832	   && (EQ (XCAR (cursor_type), Qbar)
833	       || EQ (XCAR (cursor_type), Qhbar)))
834    {
835      Lisp_Object bar_parms = XCDR (cursor_type);
836      int width;
837
838      if (INTEGERP (bar_parms))
839	{
840	  /* Feature: negative WIDTH means cursor at the top
841	     of the character cell, zero means invisible cursor.  */
842	  width = XINT (bar_parms);
843	  msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
844				  width);
845	}
846      else if (CONSP (bar_parms)
847	       && INTEGERP (XCAR (bar_parms))
848	       && INTEGERP (XCDR (bar_parms)))
849	{
850	  int start_line = XINT (XCDR (bar_parms));
851
852	  width = XINT (XCAR (bar_parms));
853	  msdos_set_cursor_shape (f, start_line, width);
854	}
855    }
856  else
857    {
858      /* Treat anything unknown as "box cursor".  This includes nil, so
859	 that a frame which doesn't specify a cursor type gets a box,
860	 which is the default in Emacs.  */
861      msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
862    }
863}
864
865static void
866IT_ring_bell (void)
867{
868  if (visible_bell)
869    {
870      mouse_off ();
871      ScreenVisualBell ();
872    }
873  else
874    {
875      union REGS inregs, outregs;
876      inregs.h.ah = 2;
877      inregs.h.dl = 7;
878      intdos (&inregs, &outregs);
879    }
880}
881
882/* Given a face id FACE, extract the face parameters to be used for
883   display until the face changes.  The face parameters (actually, its
884   color) are used to construct the video attribute byte for each
885   glyph during the construction of the buffer that is then blitted to
886   the video RAM.  */
887static void
888IT_set_face (int face)
889{
890  struct frame *sf = SELECTED_FRAME();
891  struct face *fp  = FACE_FROM_ID (sf, face);
892  struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
893  unsigned long fg, bg, dflt_fg, dflt_bg;
894
895  if (!fp)
896    {
897      fp = dfp;
898      /* The default face for the frame should always be realized and
899	 cached.  */
900      if (!fp)
901	abort ();
902    }
903  screen_face = face;
904  fg = fp->foreground;
905  bg = fp->background;
906  dflt_fg = dfp->foreground;
907  dflt_bg = dfp->background;
908
909  /* Don't use invalid colors.  In particular, FACE_TTY_DEFAULT_* colors
910     mean use the colors of the default face.  Note that we assume all
911     16 colors to be available for the background, since Emacs switches
912     on this mode (and loses the blinking attribute) at startup.  */
913  if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
914    fg = FRAME_FOREGROUND_PIXEL (sf);
915  else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
916    fg = FRAME_BACKGROUND_PIXEL (sf);
917  if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
918    bg = FRAME_BACKGROUND_PIXEL (sf);
919  else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
920    bg = FRAME_FOREGROUND_PIXEL (sf);
921
922  /* Make sure highlighted lines really stand out, come what may.  */
923  if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
924    {
925      unsigned long tem = fg;
926
927      fg = bg;
928      bg = tem;
929    }
930  /* If the user requested inverse video, obey.  */
931  if (inverse_video)
932    {
933      unsigned long tem2 = fg;
934
935      fg = bg;
936      bg = tem2;
937    }
938  if (termscript)
939    fprintf (termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
940	     fp->foreground, fp->background, fg, bg);
941  if (fg >= 0 && fg < 16)
942    {
943      ScreenAttrib &= 0xf0;
944      ScreenAttrib |= fg;
945    }
946  if (bg >= 0 && bg < 16)
947    {
948      ScreenAttrib &= 0x0f;
949      ScreenAttrib |= ((bg & 0x0f) << 4);
950    }
951}
952
953Lisp_Object Vdos_unsupported_char_glyph;
954
955static void
956IT_write_glyphs (struct glyph *str, int str_len)
957{
958  unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
959  int unsupported_face = 0;
960  unsigned unsupported_char = '\177';
961  int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
962  register int sl = str_len;
963  register int tlen = GLYPH_TABLE_LENGTH;
964  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
965
966  /* If terminal_coding does any conversion, use it, otherwise use
967     safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
968     because it always returns 1 if terminal_coding.src_multibyte is 1.  */
969  struct coding_system *coding =
970    (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
971     ? &terminal_coding
972     : &safe_terminal_coding);
973  struct frame *sf;
974
975  /* Do we need to consider conversion of unibyte characters to
976     multibyte?  */
977  int convert_unibyte_characters
978    = (NILP (current_buffer->enable_multibyte_characters)
979       && unibyte_display_via_language_environment);
980
981  unsigned char conversion_buffer[256];
982  int conversion_buffer_size = sizeof conversion_buffer;
983
984  if (str_len <= 0) return;
985
986  /* Set up the unsupported character glyph */
987  if (!NILP (Vdos_unsupported_char_glyph))
988    {
989      unsupported_char = FAST_GLYPH_CHAR (XINT (Vdos_unsupported_char_glyph));
990      unsupported_face = FAST_GLYPH_FACE (XINT (Vdos_unsupported_char_glyph));
991    }
992
993  screen_buf = screen_bp = alloca (str_len * 2);
994  screen_buf_end = screen_buf + str_len * 2;
995  sf = SELECTED_FRAME();
996
997  /* Since faces get cached and uncached behind our back, we can't
998     rely on their indices in the cache being consistent across
999     invocations.  So always reset the screen face to the default
1000     face of the frame, before writing glyphs, and let the glyphs
1001     set the right face if it's different from the default.  */
1002  IT_set_face (DEFAULT_FACE_ID);
1003
1004  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1005     the tail.  */
1006  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
1007  while (sl)
1008    {
1009      int cf, chlen, enclen;
1010      unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
1011      unsigned ch;
1012
1013      /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
1014	 only for the redisplay code to know how many columns does
1015         this character occupy on the screen.  Skip padding glyphs.  */
1016      if (CHAR_GLYPH_PADDING_P (*str))
1017	{
1018	  str++;
1019	  sl--;
1020	}
1021      else
1022	{
1023	  register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
1024	  int glyph_not_in_table = 0;
1025
1026	  /* If g is negative, it means we have a multibyte character
1027	     in *str.  That's what GLYPH_FROM_CHAR_GLYPH returns for
1028	     multibyte characters.  */
1029	  if (g < 0 || g >= tlen)
1030	    {
1031	      /* This glyph doesn't have an entry in Vglyph_table.  */
1032	      ch = str->u.ch;
1033	      glyph_not_in_table = 1;
1034	    }
1035	  else
1036	    {
1037	      /* This glyph has an entry in Vglyph_table, so process
1038		 any aliases before testing for simpleness.  */
1039	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
1040	      ch = FAST_GLYPH_CHAR (g);
1041	    }
1042
1043	  /* Convert the character code to multibyte, if they
1044	     requested display via language environment.  We only want
1045	     to convert unibyte characters to multibyte in unibyte
1046	     buffers!  Otherwise, the 8-bit value in CH came from the
1047	     display table set up to display foreign characters.  */
1048	  if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
1049	      && (ch >= 0240
1050		  || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
1051	    ch = unibyte_char_to_multibyte (ch);
1052
1053	  /* Invalid characters are displayed with a special glyph.  */
1054	  if (! CHAR_VALID_P (ch, 0))
1055	    {
1056	      g = !NILP (Vdos_unsupported_char_glyph)
1057		? XINT (Vdos_unsupported_char_glyph)
1058		: MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
1059	      ch = FAST_GLYPH_CHAR (g);
1060	    }
1061
1062	  /* If the face of this glyph is different from the current
1063	     screen face, update the screen attribute byte.  */
1064	  cf = str->face_id;
1065	  if (cf != screen_face)
1066	    IT_set_face (cf);	/* handles invalid faces gracefully */
1067
1068	  if (glyph_not_in_table || GLYPH_SIMPLE_P (tbase, tlen, g))
1069	    {
1070	      /* We generate the multi-byte form of CH in WORKBUF.  */
1071	      chlen = CHAR_STRING (ch, workbuf);
1072	      buf = workbuf;
1073	    }
1074	  else
1075	    {
1076	      /* We have a string in Vglyph_table.  */
1077	      chlen = GLYPH_LENGTH (tbase, g);
1078	      buf = GLYPH_STRING (tbase, g);
1079	    }
1080
1081	  /* If the character is not multibyte, don't bother converting it.  */
1082	  if (chlen == 1)
1083	    {
1084	      *conversion_buffer = (unsigned char)ch;
1085	      chlen = 0;
1086	      enclen = 1;
1087	    }
1088	  else
1089	    {
1090	      coding->src_multibyte = 1;
1091	      encode_coding (coding, buf, conversion_buffer, chlen,
1092			     conversion_buffer_size);
1093	      chlen -= coding->consumed;
1094	      enclen = coding->produced;
1095
1096	      /* Replace glyph codes that cannot be converted by
1097		 terminal_coding with Vdos_unsupported_char_glyph.  */
1098	      if (*conversion_buffer == '?')
1099		{
1100		  unsigned char *cbp = conversion_buffer;
1101
1102		  while (cbp < conversion_buffer + enclen && *cbp == '?')
1103		    *cbp++ = unsupported_char;
1104		  if (unsupported_face != screen_face)
1105		    IT_set_face (unsupported_face);
1106		}
1107	    }
1108
1109	  if (enclen + chlen > screen_buf_end - screen_bp)
1110	    {
1111	      /* The allocated buffer for screen writes is too small.
1112		 Flush it and loop again without incrementing STR, so
1113		 that the next loop will begin with the same glyph.  */
1114	      int nbytes = screen_bp - screen_buf;
1115
1116	      mouse_off_maybe ();
1117	      dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1118	      if (screen_virtual_segment)
1119		dosv_refresh_virtual_screen (offset, nbytes / 2);
1120	      new_pos_X += nbytes / 2;
1121	      offset += nbytes;
1122
1123	      /* Prepare to reuse the same buffer again.  */
1124	      screen_bp = screen_buf;
1125	    }
1126	  else
1127	    {
1128	      /* There's enough place in the allocated buffer to add
1129		 the encoding of this glyph.  */
1130
1131	      /* First, copy the encoded bytes.  */
1132	      for (bp = conversion_buffer; enclen--; bp++)
1133		{
1134		  *screen_bp++ = (unsigned char)*bp;
1135		  *screen_bp++ = ScreenAttrib;
1136		  if (termscript)
1137		    fputc (*bp, termscript);
1138		}
1139
1140	      /* Now copy the bytes not consumed by the encoding.  */
1141	      if (chlen > 0)
1142		{
1143		  buf += coding->consumed;
1144		  while (chlen--)
1145		    {
1146		      if (termscript)
1147			fputc (*buf, termscript);
1148		      *screen_bp++ = (unsigned char)*buf++;
1149		      *screen_bp++ = ScreenAttrib;
1150		    }
1151		}
1152
1153	      /* Update STR and its remaining length.  */
1154	      str++;
1155	      sl--;
1156	    }
1157	}
1158    }
1159
1160  /* Dump whatever is left in the screen buffer.  */
1161  mouse_off_maybe ();
1162  dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1163  if (screen_virtual_segment)
1164    dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1165  new_pos_X += (screen_bp - screen_buf) / 2;
1166
1167  /* We may have to output some codes to terminate the writing.  */
1168  if (CODING_REQUIRE_FLUSHING (coding))
1169    {
1170      coding->mode |= CODING_MODE_LAST_BLOCK;
1171      encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
1172      if (coding->produced > 0)
1173	{
1174	  screen_buf = alloca (coding->produced * 2);
1175	  for (screen_bp = screen_buf, bp = conversion_buffer;
1176	       coding->produced--; bp++)
1177	    {
1178	      *screen_bp++ = (unsigned char)*bp;
1179	      *screen_bp++ = ScreenAttrib;
1180	      if (termscript)
1181		fputc (*bp, termscript);
1182	    }
1183	  offset += screen_bp - screen_buf;
1184	  mouse_off_maybe ();
1185	  dosmemput (screen_buf, screen_bp - screen_buf,
1186		     (int)ScreenPrimary + offset);
1187	  if (screen_virtual_segment)
1188	    dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1189	  new_pos_X += (screen_bp - screen_buf) / 2;
1190	}
1191    }
1192}
1193
1194/************************************************************************
1195			  Mouse Highlight (and friends..)
1196 ************************************************************************/
1197
1198/* Last window where we saw the mouse.  Used by mouse-autoselect-window.  */
1199static Lisp_Object last_mouse_window;
1200
1201static int mouse_preempted = 0;	/* non-zero when XMenu gobbles mouse events */
1202
1203/* Set the mouse pointer shape according to whether it is in the
1204   area where the mouse highlight is in effect.  */
1205static void
1206IT_set_mouse_pointer (int mode)
1207{
1208  /* A no-op for now.  DOS text-mode mouse pointer doesn't offer too
1209     many possibilities to change its shape, and the available
1210     functionality pretty much sucks (e.g., almost every reasonable
1211     shape will conceal the character it is on).  Since the color of
1212     the pointer changes in the highlighted area, it is not clear to
1213     me whether anything else is required, anyway.  */
1214}
1215
1216/* Display the active region described by mouse_face_*
1217   in its mouse-face if HL > 0, in its normal face if HL = 0.  */
1218static void
1219show_mouse_face (struct display_info *dpyinfo, int hl)
1220{
1221  struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1222  struct frame *f = XFRAME (WINDOW_FRAME (w));
1223  int i;
1224  struct face *fp;
1225
1226
1227  /* If window is in the process of being destroyed, don't bother
1228     doing anything.  */
1229  if (w->current_matrix == NULL)
1230    goto set_cursor_shape;
1231
1232  /* Recognize when we are called to operate on rows that don't exist
1233     anymore.  This can happen when a window is split.  */
1234  if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1235    goto set_cursor_shape;
1236
1237  /* There's no sense to do anything if the mouse face isn't realized.  */
1238  if (hl > 0)
1239    {
1240      if (dpyinfo->mouse_face_hidden)
1241	goto set_cursor_shape;
1242
1243      fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1244      if (!fp)
1245	goto set_cursor_shape;
1246    }
1247
1248  /* Note that mouse_face_beg_row etc. are window relative.  */
1249  for (i = dpyinfo->mouse_face_beg_row;
1250       i <= dpyinfo->mouse_face_end_row;
1251       i++)
1252    {
1253      int start_hpos, end_hpos;
1254      struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1255
1256      /* Don't do anything if row doesn't have valid contents.  */
1257      if (!row->enabled_p)
1258	continue;
1259
1260      /* For all but the first row, the highlight starts at column 0.  */
1261      if (i == dpyinfo->mouse_face_beg_row)
1262	start_hpos = dpyinfo->mouse_face_beg_col;
1263      else
1264	start_hpos = 0;
1265
1266      if (i == dpyinfo->mouse_face_end_row)
1267	end_hpos = dpyinfo->mouse_face_end_col;
1268      else
1269	end_hpos = row->used[TEXT_AREA];
1270
1271      if (end_hpos <= start_hpos)
1272	continue;
1273      /* Record that some glyphs of this row are displayed in
1274         mouse-face.  */
1275      row->mouse_face_p = hl > 0;
1276      if (hl > 0)
1277	{
1278	  int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1279	  int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1280	  int nglyphs = end_hpos - start_hpos;
1281	  int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1282	  int start_offset = offset;
1283
1284	  if (termscript)
1285	    fprintf (termscript, "\n<MH+ %d-%d:%d>",
1286		     kstart, kstart + nglyphs - 1, vpos);
1287
1288	  mouse_off ();
1289	  IT_set_face (dpyinfo->mouse_face_face_id);
1290	  /* Since we are going to change only the _colors_ of the
1291	     displayed text, there's no need to go through all the
1292	     pain of generating and encoding the text from the glyphs.
1293	     Instead, we simply poke the attribute byte of each
1294	     affected position in video memory with the colors
1295	     computed by IT_set_face!  */
1296	  _farsetsel (_dos_ds);
1297	  while (nglyphs--)
1298	    {
1299	      _farnspokeb (offset, ScreenAttrib);
1300	      offset += 2;
1301	    }
1302	  if (screen_virtual_segment)
1303	    dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1304	  mouse_on ();
1305	}
1306      else
1307	{
1308	  /* We are removing a previously-drawn mouse highlight.  The
1309	     safest way to do so is to redraw the glyphs anew, since
1310	     all kinds of faces and display tables could have changed
1311	     behind our back.  */
1312	  int nglyphs = end_hpos - start_hpos;
1313	  int save_x = new_pos_X, save_y = new_pos_Y;
1314
1315	  if (end_hpos >= row->used[TEXT_AREA])
1316	    nglyphs = row->used[TEXT_AREA] - start_hpos;
1317
1318	  /* IT_write_glyphs writes at cursor position, so we need to
1319	     temporarily move cursor coordinates to the beginning of
1320	     the highlight region.  */
1321	  new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1322	  new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1323
1324	  if (termscript)
1325	    fprintf (termscript, "<MH- %d-%d:%d>",
1326		     new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1327	  IT_write_glyphs (row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1328	  if (termscript)
1329	    fputs ("\n", termscript);
1330	  new_pos_X = save_x;
1331	  new_pos_Y = save_y;
1332	}
1333    }
1334
1335 set_cursor_shape:
1336  /* Change the mouse pointer shape.  */
1337  IT_set_mouse_pointer (hl);
1338}
1339
1340/* Clear out the mouse-highlighted active region.
1341   Redraw it un-highlighted first.  */
1342static void
1343clear_mouse_face (struct display_info *dpyinfo)
1344{
1345  if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1346    show_mouse_face (dpyinfo, 0);
1347
1348  dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1349  dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1350  dpyinfo->mouse_face_window = Qnil;
1351}
1352
1353/* Find the glyph matrix position of buffer position POS in window W.
1354   *HPOS and *VPOS are set to the positions found.  W's current glyphs
1355   must be up to date.  If POS is above window start return (0, 0).
1356   If POS is after end of W, return end of last line in W.  */
1357static int
1358fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1359{
1360  int i, lastcol, line_start_position, maybe_next_line_p = 0;
1361  int yb = window_text_bottom_y (w);
1362  struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1363
1364  while (row->y < yb)
1365    {
1366      if (row->used[TEXT_AREA])
1367	line_start_position = row->glyphs[TEXT_AREA]->charpos;
1368      else
1369	line_start_position = 0;
1370
1371      if (line_start_position > pos)
1372	break;
1373      /* If the position sought is the end of the buffer,
1374	 don't include the blank lines at the bottom of the window.  */
1375      else if (line_start_position == pos
1376	       && pos == BUF_ZV (XBUFFER (w->buffer)))
1377	{
1378	  maybe_next_line_p = 1;
1379	  break;
1380	}
1381      else if (line_start_position > 0)
1382	best_row = row;
1383
1384      /* Don't overstep the last matrix row, lest we get into the
1385	 never-never land... */
1386      if (row->y + 1 >= yb)
1387	break;
1388
1389      ++row;
1390    }
1391
1392  /* Find the right column within BEST_ROW.  */
1393  lastcol = 0;
1394  row = best_row;
1395  for (i = 0; i < row->used[TEXT_AREA]; i++)
1396    {
1397      struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1398      int charpos;
1399
1400      charpos = glyph->charpos;
1401      if (charpos == pos)
1402	{
1403	  *hpos = i;
1404	  *vpos = row->y;
1405	  return 1;
1406	}
1407      else if (charpos > pos)
1408	break;
1409      else if (charpos > 0)
1410	lastcol = i;
1411    }
1412
1413  /* If we're looking for the end of the buffer,
1414     and we didn't find it in the line we scanned,
1415     use the start of the following line.  */
1416  if (maybe_next_line_p)
1417    {
1418      ++row;
1419      lastcol = 0;
1420    }
1421
1422  *vpos = row->y;
1423  *hpos = lastcol + 1;
1424  return 0;
1425}
1426
1427/* Take proper action when mouse has moved to the mode or top line of
1428   window W, x-position X.  MODE_LINE_P non-zero means mouse is on the
1429   mode line.  X is relative to the start of the text display area of
1430   W, so the width of fringes and scroll bars must be subtracted
1431   to get a position relative to the start of the mode line.  */
1432static void
1433IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1434{
1435  struct frame *f = XFRAME (w->frame);
1436  struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1437  struct glyph_row *row;
1438
1439  if (mode_line_p)
1440    row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1441  else
1442    row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1443
1444  if (row->enabled_p)
1445    {
1446      extern Lisp_Object Qhelp_echo;
1447      struct glyph *glyph, *end;
1448      Lisp_Object help, map;
1449
1450      /* Find the glyph under X.  */
1451      glyph = (row->glyphs[TEXT_AREA]
1452	       + x
1453	       /* in case someone implements scroll bars some day... */
1454	       - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1455      end = glyph + row->used[TEXT_AREA];
1456      if (glyph < end
1457	  && STRINGP (glyph->object)
1458	  && STRING_INTERVALS (glyph->object)
1459	  && glyph->charpos >= 0
1460	  && glyph->charpos < SCHARS (glyph->object))
1461	{
1462	  /* If we're on a string with `help-echo' text property,
1463	     arrange for the help to be displayed.  This is done by
1464	     setting the global variable help_echo to the help string.  */
1465	  help = Fget_text_property (make_number (glyph->charpos),
1466				     Qhelp_echo, glyph->object);
1467	  if (!NILP (help))
1468	    {
1469	      help_echo_string = help;
1470	      XSETWINDOW (help_echo_window, w);
1471	      help_echo_object = glyph->object;
1472	      help_echo_pos = glyph->charpos;
1473	    }
1474	}
1475    }
1476}
1477
1478/* Take proper action when the mouse has moved to position X, Y on
1479   frame F as regards highlighting characters that have mouse-face
1480   properties.  Also de-highlighting chars where the mouse was before.
1481   X and Y can be negative or out of range.  */
1482static void
1483IT_note_mouse_highlight (struct frame *f, int x, int y)
1484{
1485  struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1486  enum window_part part = ON_NOTHING;
1487  Lisp_Object window;
1488  struct window *w;
1489
1490  /* When a menu is active, don't highlight because this looks odd.  */
1491  if (mouse_preempted)
1492    return;
1493
1494  if (NILP (Vmouse_highlight)
1495      || !f->glyphs_initialized_p)
1496    return;
1497
1498  dpyinfo->mouse_face_mouse_x = x;
1499  dpyinfo->mouse_face_mouse_y = y;
1500  dpyinfo->mouse_face_mouse_frame = f;
1501
1502  if (dpyinfo->mouse_face_defer)
1503    return;
1504
1505  if (gc_in_progress)
1506    {
1507      dpyinfo->mouse_face_deferred_gc = 1;
1508      return;
1509    }
1510
1511  /* Which window is that in?  */
1512  window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1513
1514  /* If we were displaying active text in another window, clear that.  */
1515  if (! EQ (window, dpyinfo->mouse_face_window))
1516    clear_mouse_face (dpyinfo);
1517
1518  /* Not on a window -> return.  */
1519  if (!WINDOWP (window))
1520    return;
1521
1522  /* Convert to window-relative coordinates.  */
1523  w = XWINDOW (window);
1524
1525  if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1526    {
1527      /* Mouse is on the mode or top line.  */
1528      IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1529      return;
1530    }
1531
1532  IT_set_mouse_pointer (0);
1533
1534  /* Are we in a window whose display is up to date?
1535     And verify the buffer's text has not changed.  */
1536  if (part == ON_TEXT
1537      && EQ (w->window_end_valid, w->buffer)
1538      && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1539      && (XFASTINT (w->last_overlay_modified)
1540	  == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1541    {
1542      int pos, i, nrows = w->current_matrix->nrows;
1543      struct glyph_row *row;
1544      struct glyph *glyph;
1545
1546      /* Find the glyph under X/Y.  */
1547      glyph = NULL;
1548      if (y >= 0 && y < nrows)
1549	{
1550	  row = MATRIX_ROW (w->current_matrix, y);
1551	  /* Give up if some row before the one we are looking for is
1552	     not enabled.  */
1553	  for (i = 0; i <= y; i++)
1554	    if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1555	      break;
1556	  if (i > y  /* all rows upto and including the one at Y are enabled */
1557	      && row->displays_text_p
1558	      && x <  window_box_width (w, TEXT_AREA))
1559	    {
1560	      glyph = row->glyphs[TEXT_AREA];
1561	      if (x >= row->used[TEXT_AREA])
1562		glyph = NULL;
1563	      else
1564		{
1565		  glyph += x;
1566		  if (!BUFFERP (glyph->object))
1567		    glyph = NULL;
1568		}
1569	    }
1570	}
1571
1572      /* Clear mouse face if X/Y not over text.  */
1573      if (glyph == NULL)
1574	{
1575	  clear_mouse_face (dpyinfo);
1576	  return;
1577	}
1578
1579      if (!BUFFERP (glyph->object))
1580	abort ();
1581      pos = glyph->charpos;
1582
1583      /* Check for mouse-face and help-echo.  */
1584      {
1585	extern Lisp_Object Qmouse_face;
1586	Lisp_Object mouse_face, overlay, position, *overlay_vec;
1587	int noverlays, obegv, ozv;;
1588	struct buffer *obuf;
1589
1590	/* If we get an out-of-range value, return now; avoid an error.  */
1591	if (pos > BUF_Z (XBUFFER (w->buffer)))
1592	  return;
1593
1594	/* Make the window's buffer temporarily current for
1595	   overlays_at and compute_char_face.  */
1596	obuf = current_buffer;
1597	current_buffer = XBUFFER (w->buffer);
1598	obegv = BEGV;
1599	ozv = ZV;
1600	BEGV = BEG;
1601	ZV = Z;
1602
1603	/* Is this char mouse-active or does it have help-echo?  */
1604	XSETINT (position, pos);
1605
1606	/* Put all the overlays we want in a vector in overlay_vec. */
1607	GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1608	/* Sort overlays into increasing priority order.  */
1609	noverlays = sort_overlays (overlay_vec, noverlays, w);
1610
1611	/* Check mouse-face highlighting.  */
1612	if (! (EQ (window, dpyinfo->mouse_face_window)
1613	       && y >= dpyinfo->mouse_face_beg_row
1614	       && y <= dpyinfo->mouse_face_end_row
1615	       && (y > dpyinfo->mouse_face_beg_row
1616		   || x >= dpyinfo->mouse_face_beg_col)
1617	       && (y < dpyinfo->mouse_face_end_row
1618		   || x < dpyinfo->mouse_face_end_col
1619		   || dpyinfo->mouse_face_past_end)))
1620	  {
1621	    /* Clear the display of the old active region, if any.  */
1622	    clear_mouse_face (dpyinfo);
1623
1624	    /* Find highest priority overlay that has a mouse-face prop.  */
1625	    overlay = Qnil;
1626	    for (i = noverlays - 1; i >= 0; --i)
1627	      {
1628		mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1629		if (!NILP (mouse_face))
1630		  {
1631		    overlay = overlay_vec[i];
1632		    break;
1633		  }
1634	      }
1635
1636	    /* If no overlay applies, get a text property.  */
1637	    if (NILP (overlay))
1638	      mouse_face = Fget_text_property (position, Qmouse_face,
1639					       w->buffer);
1640
1641	    /* Handle the overlay case.  */
1642	    if (! NILP (overlay))
1643	      {
1644		/* Find the range of text around this char that
1645		   should be active.  */
1646		Lisp_Object before, after;
1647		int ignore;
1648
1649		before = Foverlay_start (overlay);
1650		after = Foverlay_end (overlay);
1651		/* Record this as the current active region.  */
1652		fast_find_position (w, XFASTINT (before),
1653				    &dpyinfo->mouse_face_beg_col,
1654				    &dpyinfo->mouse_face_beg_row);
1655		dpyinfo->mouse_face_past_end
1656		  = !fast_find_position (w, XFASTINT (after),
1657					 &dpyinfo->mouse_face_end_col,
1658					 &dpyinfo->mouse_face_end_row);
1659		dpyinfo->mouse_face_window = window;
1660		dpyinfo->mouse_face_face_id
1661		  = face_at_buffer_position (w, pos, 0, 0,
1662					     &ignore, pos + 1,
1663					     !dpyinfo->mouse_face_hidden);
1664
1665		/* Display it as active.  */
1666		show_mouse_face (dpyinfo, 1);
1667	      }
1668	    /* Handle the text property case.  */
1669	    else if (! NILP (mouse_face))
1670	      {
1671		/* Find the range of text around this char that
1672		   should be active.  */
1673		Lisp_Object before, after, beginning, end;
1674		int ignore;
1675
1676		beginning = Fmarker_position (w->start);
1677		XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1678			       - XFASTINT (w->window_end_pos)));
1679		before
1680		  = Fprevious_single_property_change (make_number (pos + 1),
1681						      Qmouse_face,
1682						      w->buffer, beginning);
1683		after
1684		  = Fnext_single_property_change (position, Qmouse_face,
1685						  w->buffer, end);
1686		/* Record this as the current active region.  */
1687		fast_find_position (w, XFASTINT (before),
1688				    &dpyinfo->mouse_face_beg_col,
1689				    &dpyinfo->mouse_face_beg_row);
1690		dpyinfo->mouse_face_past_end
1691		  = !fast_find_position (w, XFASTINT (after),
1692					 &dpyinfo->mouse_face_end_col,
1693					 &dpyinfo->mouse_face_end_row);
1694		dpyinfo->mouse_face_window = window;
1695		dpyinfo->mouse_face_face_id
1696		  = face_at_buffer_position (w, pos, 0, 0,
1697					     &ignore, pos + 1,
1698					     !dpyinfo->mouse_face_hidden);
1699
1700		/* Display it as active.  */
1701		show_mouse_face (dpyinfo, 1);
1702	      }
1703	  }
1704
1705	/* Look for a `help-echo' property.  */
1706	{
1707	  Lisp_Object help;
1708	  extern Lisp_Object Qhelp_echo;
1709
1710	  /* Check overlays first.  */
1711	  help = Qnil;
1712	  for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1713	    {
1714	      overlay = overlay_vec[i];
1715	      help = Foverlay_get (overlay, Qhelp_echo);
1716	    }
1717
1718	  if (!NILP (help))
1719	    {
1720	      help_echo_string = help;
1721	      help_echo_window = window;
1722	      help_echo_object = overlay;
1723	      help_echo_pos = pos;
1724	    }
1725	  /* Try text properties.  */
1726	  else if (NILP (help)
1727		   && ((STRINGP (glyph->object)
1728			&& glyph->charpos >= 0
1729			&& glyph->charpos < SCHARS (glyph->object))
1730		       || (BUFFERP (glyph->object)
1731			   && glyph->charpos >= BEGV
1732			   && glyph->charpos < ZV)))
1733	    {
1734	      help = Fget_text_property (make_number (glyph->charpos),
1735					 Qhelp_echo, glyph->object);
1736	      if (!NILP (help))
1737		{
1738		  help_echo_string = help;
1739		  help_echo_window = window;
1740		  help_echo_object = glyph->object;
1741		  help_echo_pos = glyph->charpos;
1742		}
1743	    }
1744	}
1745
1746	BEGV = obegv;
1747	ZV = ozv;
1748	current_buffer = obuf;
1749      }
1750    }
1751}
1752
1753static void
1754IT_clear_end_of_line (int first_unused)
1755{
1756  char *spaces, *sp;
1757  int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1758  extern int fatal_error_in_progress;
1759
1760  if (new_pos_X >= first_unused || fatal_error_in_progress)
1761    return;
1762
1763  IT_set_face (0);
1764  i = (j = first_unused - new_pos_X) * 2;
1765  if (termscript)
1766    fprintf (termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1767  spaces = sp = alloca (i);
1768
1769  while (--j >= 0)
1770    {
1771      *sp++ = ' ';
1772      *sp++ = ScreenAttrib;
1773    }
1774
1775  mouse_off_maybe ();
1776  dosmemput (spaces, i, (int)ScreenPrimary + offset);
1777  if (screen_virtual_segment)
1778    dosv_refresh_virtual_screen (offset, i / 2);
1779
1780  /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1781     Let's follow their lead, in case someone relies on this.  */
1782  new_pos_X = first_unused;
1783}
1784
1785static void
1786IT_clear_screen (void)
1787{
1788  if (termscript)
1789    fprintf (termscript, "<CLR:SCR>");
1790  /* We are sometimes called (from clear_garbaged_frames) when a new
1791     frame is being created, but its faces are not yet realized.  In
1792     such a case we cannot call IT_set_face, since it will fail to find
1793     any valid faces and will abort.  Instead, use the initial screen
1794     colors; that should mimic what a Unix tty does, which simply clears
1795     the screen with whatever default colors are in use.  */
1796  if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1797    ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1798  else
1799    IT_set_face (0);
1800  mouse_off ();
1801  ScreenClear ();
1802  if (screen_virtual_segment)
1803    dosv_refresh_virtual_screen (0, screen_size);
1804  new_pos_X = new_pos_Y = 0;
1805}
1806
1807static void
1808IT_clear_to_end (void)
1809{
1810  if (termscript)
1811    fprintf (termscript, "<CLR:EOS>");
1812
1813  while (new_pos_Y < screen_size_Y) {
1814    new_pos_X = 0;
1815    IT_clear_end_of_line (screen_size_X);
1816    new_pos_Y++;
1817  }
1818}
1819
1820static void
1821IT_cursor_to (int y, int x)
1822{
1823  if (termscript)
1824    fprintf (termscript, "\n<XY=%dx%d>", x, y);
1825  new_pos_X = x;
1826  new_pos_Y = y;
1827}
1828
1829static int cursor_cleared;
1830
1831static void
1832IT_display_cursor (int on)
1833{
1834  if (termscript)
1835    fprintf (termscript, "\nCURSOR %s", on ? "ON" : "OFF");
1836  if (on && cursor_cleared)
1837    {
1838      ScreenSetCursor (current_pos_Y, current_pos_X);
1839      cursor_cleared = 0;
1840    }
1841  else if (!on && !cursor_cleared)
1842    {
1843      ScreenSetCursor (-1, -1);
1844      cursor_cleared = 1;
1845    }
1846}
1847
1848/* Emacs calls cursor-movement functions a lot when it updates the
1849   display (probably a legacy of old terminals where you cannot
1850   update a screen line without first moving the cursor there).
1851   However, cursor movement is expensive on MSDOS (it calls a slow
1852   BIOS function and requires 2 mode switches), while actual screen
1853   updates access the video memory directly and don't depend on
1854   cursor position.  To avoid slowing down the redisplay, we cheat:
1855   all functions that move the cursor only set internal variables
1856   which record the cursor position, whereas the cursor is only
1857   moved to its final position whenever screen update is complete.
1858
1859   `IT_cmgoto' is called from the keyboard reading loop and when the
1860   frame update is complete.  This means that we are ready for user
1861   input, so we update the cursor position to show where the point is,
1862   and also make the mouse pointer visible.
1863
1864   Special treatment is required when the cursor is in the echo area,
1865   to put the cursor at the end of the text displayed there.  */
1866
1867static void
1868IT_cmgoto (FRAME_PTR f)
1869{
1870  /* Only set the cursor to where it should be if the display is
1871     already in sync with the window contents.  */
1872  int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1873
1874  /* FIXME: This needs to be rewritten for the new redisplay, or
1875     removed.  */
1876#if 0
1877  static int previous_pos_X = -1;
1878
1879  update_cursor_pos = 1;	/* temporary!!! */
1880
1881  /* If the display is in sync, forget any previous knowledge about
1882     cursor position.  This is primarily for unexpected events like
1883     C-g in the minibuffer.  */
1884  if (update_cursor_pos && previous_pos_X >= 0)
1885    previous_pos_X = -1;
1886  /* If we are in the echo area, put the cursor at the
1887     end of the echo area message.  */
1888  if (!update_cursor_pos
1889      && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1890    {
1891      int tem_X = current_pos_X, dummy;
1892
1893      if (echo_area_glyphs)
1894	{
1895	  tem_X = echo_area_glyphs_length;
1896	  /* Save current cursor position, to be restored after the
1897	     echo area message is erased.  Only remember one level
1898	     of previous cursor position.  */
1899	  if (previous_pos_X == -1)
1900	    ScreenGetCursor (&dummy, &previous_pos_X);
1901	}
1902      else if (previous_pos_X >= 0)
1903	{
1904	  /* We wind up here after the echo area message is erased.
1905	     Restore the cursor position we remembered above.  */
1906	  tem_X = previous_pos_X;
1907	  previous_pos_X = -1;
1908	}
1909
1910      if (current_pos_X != tem_X)
1911	{
1912	  new_pos_X = tem_X;
1913	  update_cursor_pos = 1;
1914	}
1915    }
1916#endif
1917
1918  if (update_cursor_pos
1919      && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1920    {
1921      ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1922      if (termscript)
1923	fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1924    }
1925
1926  /* Maybe cursor is invisible, so make it visible.  */
1927  IT_display_cursor (1);
1928
1929  /* Mouse pointer should be always visible if we are waiting for
1930     keyboard input.  */
1931  if (!mouse_visible)
1932    mouse_on ();
1933}
1934
1935static void
1936IT_update_begin (struct frame *f)
1937{
1938  struct display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1939  struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1940
1941  BLOCK_INPUT;
1942
1943  if (f && f == mouse_face_frame)
1944    {
1945      /* Don't do highlighting for mouse motion during the update.  */
1946      display_info->mouse_face_defer = 1;
1947
1948      /* If F needs to be redrawn, simply forget about any prior mouse
1949	 highlighting.  */
1950      if (FRAME_GARBAGED_P (f))
1951	display_info->mouse_face_window = Qnil;
1952
1953      /* Can we tell that this update does not affect the window
1954	 where the mouse highlight is?  If so, no need to turn off.
1955	 Likewise, don't do anything if none of the enabled rows
1956	 contains glyphs highlighted in mouse face.  */
1957      if (!NILP (display_info->mouse_face_window)
1958	  && WINDOWP (display_info->mouse_face_window))
1959	{
1960	  struct window *w = XWINDOW (display_info->mouse_face_window);
1961	  int i;
1962
1963	  /* If the mouse highlight is in the window that was deleted
1964	     (e.g., if it was popped by completion), clear highlight
1965	     unconditionally.  */
1966	  if (NILP (w->buffer))
1967	    display_info->mouse_face_window = Qnil;
1968	  else
1969	    {
1970	      for (i = 0; i < w->desired_matrix->nrows; ++i)
1971		if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1972		    && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1973		  break;
1974	    }
1975
1976	  if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1977	    clear_mouse_face (display_info);
1978	}
1979    }
1980  else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1981    {
1982      /* If the frame with mouse highlight was deleted, invalidate the
1983	 highlight info.  */
1984      display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1985      display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1986      display_info->mouse_face_window = Qnil;
1987      display_info->mouse_face_deferred_gc = 0;
1988      display_info->mouse_face_mouse_frame = NULL;
1989    }
1990
1991  UNBLOCK_INPUT;
1992}
1993
1994static void
1995IT_update_end (struct frame *f)
1996{
1997  FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
1998}
1999
2000static void
2001IT_frame_up_to_date (struct frame *f)
2002{
2003  struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
2004  Lisp_Object new_cursor, frame_desired_cursor;
2005  struct window *sw;
2006
2007  if (dpyinfo->mouse_face_deferred_gc
2008      || (f && f == dpyinfo->mouse_face_mouse_frame))
2009    {
2010      BLOCK_INPUT;
2011      if (dpyinfo->mouse_face_mouse_frame)
2012	IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2013				 dpyinfo->mouse_face_mouse_x,
2014				 dpyinfo->mouse_face_mouse_y);
2015      dpyinfo->mouse_face_deferred_gc = 0;
2016      UNBLOCK_INPUT;
2017    }
2018
2019  /* Set the cursor type to whatever they wanted.  In a minibuffer
2020     window, we want the cursor to appear only if we are reading input
2021     from this window, and we want the cursor to be taken from the
2022     frame parameters.  For the selected window, we use either its
2023     buffer-local value or the value from the frame parameters if the
2024     buffer doesn't define its local value for the cursor type.  */
2025  sw = XWINDOW (f->selected_window);
2026  frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
2027  if (cursor_in_echo_area
2028      && FRAME_HAS_MINIBUF_P (f)
2029      && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
2030      && sw == XWINDOW (echo_area_window))
2031    new_cursor = frame_desired_cursor;
2032  else
2033    {
2034      struct buffer *b = XBUFFER (sw->buffer);
2035
2036      if (EQ (b->cursor_type, Qt))
2037	new_cursor = frame_desired_cursor;
2038      else if (NILP (b->cursor_type)) /* nil means no cursor */
2039	new_cursor = Fcons (Qbar, make_number (0));
2040      else
2041	new_cursor = b->cursor_type;
2042    }
2043
2044  IT_set_cursor_type (f, new_cursor);
2045
2046  IT_cmgoto (f);  /* position cursor when update is done */
2047}
2048
2049/* Copy LEN glyphs displayed on a single line whose vertical position
2050   is YPOS, beginning at horizontal position XFROM to horizontal
2051   position XTO, by moving blocks in the video memory.  Used by
2052   functions that insert and delete glyphs.  */
2053static void
2054IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
2055{
2056  /* The offsets of source and destination relative to the
2057     conventional memorty selector.  */
2058  int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
2059  int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
2060
2061  if (from == to || len <= 0)
2062    return;
2063
2064  _farsetsel (_dos_ds);
2065
2066  /* The source and destination might overlap, so we need to move
2067     glyphs non-destructively.  */
2068  if (from > to)
2069    {
2070      for ( ; len; from += 2, to += 2, len--)
2071	_farnspokew (to, _farnspeekw (from));
2072    }
2073  else
2074    {
2075      from += (len - 1) * 2;
2076      to += (len - 1) * 2;
2077      for ( ; len; from -= 2, to -= 2, len--)
2078	_farnspokew (to, _farnspeekw (from));
2079    }
2080  if (screen_virtual_segment)
2081    dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
2082}
2083
2084/* Insert and delete glyphs.  */
2085static void
2086IT_insert_glyphs (start, len)
2087     register struct glyph *start;
2088     register int len;
2089{
2090  int shift_by_width = screen_size_X - (new_pos_X + len);
2091
2092  /* Shift right the glyphs from the nominal cursor position to the
2093     end of this line.  */
2094  IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
2095
2096  /* Now write the glyphs to be inserted.  */
2097  IT_write_glyphs (start, len);
2098}
2099
2100static void
2101IT_delete_glyphs (n)
2102     register int n;
2103{
2104  abort ();
2105}
2106
2107/* set-window-configuration on window.c needs this.  */
2108void
2109x_set_menu_bar_lines (f, value, oldval)
2110     struct frame *f;
2111     Lisp_Object value, oldval;
2112{
2113  set_menu_bar_lines (f, value, oldval);
2114}
2115
2116/* This was copied from xfaces.c  */
2117
2118extern Lisp_Object Qbackground_color;
2119extern Lisp_Object Qforeground_color;
2120Lisp_Object Qreverse;
2121extern Lisp_Object Qtitle;
2122
2123/* IT_set_terminal_modes is called when emacs is started,
2124   resumed, and whenever the screen is redrawn!  */
2125
2126static void
2127IT_set_terminal_modes (void)
2128{
2129  if (termscript)
2130    fprintf (termscript, "\n<SET_TERM>");
2131
2132  screen_size_X = ScreenCols ();
2133  screen_size_Y = ScreenRows ();
2134  screen_size = screen_size_X * screen_size_Y;
2135
2136  new_pos_X = new_pos_Y = 0;
2137  current_pos_X = current_pos_Y = -1;
2138
2139  if (term_setup_done)
2140    return;
2141  term_setup_done = 1;
2142
2143  startup_screen_size_X = screen_size_X;
2144  startup_screen_size_Y = screen_size_Y;
2145  startup_screen_attrib = ScreenAttrib;
2146
2147#if __DJGPP__ > 1
2148  /* Is DOS/V (or any other RSIS software which relocates
2149     the screen) installed?  */
2150  {
2151    unsigned short es_value;
2152    __dpmi_regs regs;
2153
2154    regs.h.ah = 0xfe;	/* get relocated screen address */
2155    if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2156      regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2157    else if (screen_old_address) /* already switched to Japanese mode once */
2158      regs.x.es = (screen_old_address >> 4) & 0xffff;
2159    else
2160      regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2161    regs.x.di = 0;
2162    es_value = regs.x.es;
2163    __dpmi_int (0x10, &regs);
2164
2165    if (regs.x.es != es_value)
2166      {
2167	/* screen_old_address is only set if ScreenPrimary does NOT
2168	   already point to the relocated buffer address returned by
2169	   the Int 10h/AX=FEh call above.  DJGPP v2.02 and later sets
2170	   ScreenPrimary to that address at startup under DOS/V.  */
2171	if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2172	  screen_old_address = ScreenPrimary;
2173	screen_virtual_segment = regs.x.es;
2174	screen_virtual_offset  = regs.x.di;
2175	ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2176      }
2177  }
2178#endif /* __DJGPP__ > 1 */
2179
2180  ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2181  ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2182
2183  if (termscript)
2184    fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2185	     screen_size_X, screen_size_Y);
2186
2187  bright_bg ();
2188}
2189
2190/* IT_reset_terminal_modes is called when emacs is
2191   suspended or killed.  */
2192
2193static void
2194IT_reset_terminal_modes (void)
2195{
2196  int display_row_start = (int) ScreenPrimary;
2197  int saved_row_len     = startup_screen_size_X * 2;
2198  int update_row_len    = ScreenCols () * 2, current_rows = ScreenRows ();
2199  int to_next_row       = update_row_len;
2200  unsigned char *saved_row = startup_screen_buffer;
2201  int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
2202
2203  if (termscript)
2204    fprintf (termscript, "\n<RESET_TERM>");
2205
2206  if (!term_setup_done)
2207    return;
2208
2209  mouse_off ();
2210
2211  /* Leave the video system in the same state as we found it,
2212     as far as the blink/bright-background bit is concerned.  */
2213  maybe_enable_blinking ();
2214
2215  /* We have a situation here.
2216     We cannot just do ScreenUpdate(startup_screen_buffer) because
2217     the luser could have changed screen dimensions inside Emacs
2218     and failed (or didn't want) to restore them before killing
2219     Emacs.  ScreenUpdate() uses the *current* screen dimensions and
2220     thus will happily use memory outside what was allocated for
2221     `startup_screen_buffer'.
2222     Thus we only restore as much as the current screen dimensions
2223     can hold, and clear the rest (if the saved screen is smaller than
2224     the current) with the color attribute saved at startup.  The cursor
2225     is also restored within the visible dimensions.  */
2226
2227  ScreenAttrib = startup_screen_attrib;
2228
2229  /* Don't restore the screen if we are exiting less than 2 seconds
2230     after startup: we might be crashing, and the screen might show
2231     some vital clues to what's wrong.  */
2232  if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2233    {
2234      ScreenClear ();
2235      if (screen_virtual_segment)
2236	dosv_refresh_virtual_screen (0, screen_size);
2237
2238      if (update_row_len > saved_row_len)
2239	update_row_len = saved_row_len;
2240      if (current_rows > startup_screen_size_Y)
2241	current_rows = startup_screen_size_Y;
2242
2243      if (termscript)
2244	fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2245		 update_row_len / 2, current_rows);
2246
2247      while (current_rows--)
2248	{
2249	  dosmemput (saved_row, update_row_len, display_row_start);
2250	  if (screen_virtual_segment)
2251	    dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2252					 update_row_len / 2);
2253	  saved_row         += saved_row_len;
2254	  display_row_start += to_next_row;
2255	}
2256    }
2257  if (startup_pos_X < cursor_pos_X)
2258    cursor_pos_X = startup_pos_X;
2259  if (startup_pos_Y < cursor_pos_Y)
2260    cursor_pos_Y = startup_pos_Y;
2261
2262  ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2263  xfree (startup_screen_buffer);
2264
2265  term_setup_done = 0;
2266}
2267
2268static void
2269IT_set_terminal_window (int foo)
2270{
2271}
2272
2273/* Remember the screen colors of the curent frame, to serve as the
2274   default colors for newly-created frames.  */
2275DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2276       Smsdos_remember_default_colors, 1, 1, 0,
2277       doc: /* Remember the screen colors of the current frame.  */)
2278     (frame)
2279     Lisp_Object frame;
2280{
2281  struct frame *f;
2282
2283  CHECK_FRAME (frame);
2284  f= XFRAME (frame);
2285
2286  /* This function is called after applying default-frame-alist to the
2287     initial frame.  At that time, if reverse-colors option was
2288     specified in default-frame-alist, it was already applied, and
2289     frame colors are reversed.  We need to account for that.  */
2290  if (EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt))
2291    {
2292      initial_screen_colors[0] = FRAME_BACKGROUND_PIXEL (f);
2293      initial_screen_colors[1] = FRAME_FOREGROUND_PIXEL (f);
2294    }
2295  else
2296    {
2297      initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2298      initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2299    }
2300}
2301
2302void
2303IT_set_frame_parameters (f, alist)
2304     struct frame *f;
2305     Lisp_Object alist;
2306{
2307  Lisp_Object tail;
2308  int i, j, length = XINT (Flength (alist));
2309  Lisp_Object *parms
2310    = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2311  Lisp_Object *values
2312    = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2313  /* Do we have to reverse the foreground and background colors?  */
2314  int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2315  int need_to_reverse, was_reverse = reverse;
2316  int redraw = 0, fg_set = 0, bg_set = 0;
2317  unsigned long orig_fg, orig_bg;
2318  Lisp_Object frame_bg, frame_fg;
2319  extern Lisp_Object Qdefault, QCforeground, QCbackground;
2320
2321  /* If we are creating a new frame, begin with the original screen colors
2322     used for the initial frame.  */
2323  if (EQ (alist, Vdefault_frame_alist)
2324      && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2325    {
2326      FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2327      FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2328    }
2329  orig_fg = FRAME_FOREGROUND_PIXEL (f);
2330  orig_bg = FRAME_BACKGROUND_PIXEL (f);
2331  frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2332  frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2333  /* frame_fg and frame_bg could be nil if, for example,
2334     f->param_alist is nil, e.g. if we are called from
2335     Fmake_terminal_frame.  */
2336  if (NILP (frame_fg))
2337    frame_fg = build_string (unspecified_fg);
2338  if (NILP (frame_bg))
2339    frame_bg = build_string (unspecified_bg);
2340
2341  /* Extract parm names and values into those vectors.  */
2342  i = 0;
2343  for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2344    {
2345      Lisp_Object elt;
2346
2347      elt = Fcar (tail);
2348      parms[i] = Fcar (elt);
2349      CHECK_SYMBOL (parms[i]);
2350      values[i] = Fcdr (elt);
2351      i++;
2352    }
2353
2354  j = i;
2355
2356  for (i = 0; i < j; i++)
2357    {
2358      Lisp_Object prop, val;
2359
2360      prop = parms[i];
2361      val  = values[i];
2362
2363      if (EQ (prop, Qreverse))
2364	reverse = EQ (val, Qt);
2365    }
2366
2367  need_to_reverse = reverse && !was_reverse;
2368  if (termscript && need_to_reverse)
2369    fprintf (termscript, "<INVERSE-VIDEO>\n");
2370
2371  /* Now process the alist elements in reverse of specified order.  */
2372  for (i--; i >= 0; i--)
2373    {
2374      Lisp_Object prop, val, frame;
2375
2376      prop = parms[i];
2377      val  = values[i];
2378
2379      if (EQ (prop, Qforeground_color))
2380	{
2381	  unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2382						? LFACE_BACKGROUND_INDEX
2383						: LFACE_FOREGROUND_INDEX);
2384	  if (new_color !=  FACE_TTY_DEFAULT_COLOR
2385	      && new_color != FACE_TTY_DEFAULT_FG_COLOR
2386	      && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2387	    {
2388	      FRAME_FOREGROUND_PIXEL (f) = new_color;
2389	      /* Make sure the foreground of the default face for this
2390		 frame is changed as well.  */
2391	      XSETFRAME (frame, f);
2392	      if (need_to_reverse)
2393		{
2394		  Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2395						     val, frame);
2396		  prop = Qbackground_color;
2397		  bg_set = 1;
2398		}
2399	      else
2400		{
2401		  Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2402						     val, frame);
2403		  fg_set = 1;
2404		}
2405	      redraw = 1;
2406	      if (termscript)
2407		fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
2408	    }
2409	}
2410      else if (EQ (prop, Qbackground_color))
2411	{
2412	  unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2413						? LFACE_FOREGROUND_INDEX
2414						: LFACE_BACKGROUND_INDEX);
2415	  if (new_color != FACE_TTY_DEFAULT_COLOR
2416	      && new_color != FACE_TTY_DEFAULT_FG_COLOR
2417	      && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2418	    {
2419	      FRAME_BACKGROUND_PIXEL (f) = new_color;
2420	      /* Make sure the background of the default face for this
2421		 frame is changed as well.  */
2422	      XSETFRAME (frame, f);
2423	      if (need_to_reverse)
2424		{
2425		  Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2426						     val, frame);
2427		  prop = Qforeground_color;
2428		  fg_set = 1;
2429		}
2430	      else
2431		{
2432		  Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2433						     val, frame);
2434		  bg_set = 1;
2435		}
2436	      redraw = 1;
2437	      if (termscript)
2438		fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
2439	    }
2440	}
2441      else if (EQ (prop, Qtitle))
2442	{
2443	  x_set_title (f, val);
2444	  if (termscript)
2445	    fprintf (termscript, "<TITLE: %s>\n", SDATA (val));
2446	}
2447      else if (EQ (prop, Qcursor_type))
2448	{
2449	  IT_set_cursor_type (f, val);
2450	  if (termscript)
2451	    fprintf (termscript, "<CTYPE: %s>\n",
2452		     EQ (val, Qbar) || EQ (val, Qhbar)
2453		     || CONSP (val) && (EQ (XCAR (val), Qbar)
2454					|| EQ (XCAR (val), Qhbar))
2455		     ? "bar" : "box");
2456	}
2457      store_frame_param (f, prop, val);
2458    }
2459
2460  /* If they specified "reverse", but not the colors, we need to swap
2461     the current frame colors.  */
2462  if (need_to_reverse)
2463    {
2464      Lisp_Object frame;
2465
2466      if (!fg_set)
2467	{
2468	  XSETFRAME (frame, f);
2469	  Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2470					     tty_color_name (f, orig_bg),
2471					     frame);
2472	  redraw = 1;
2473	}
2474      if (!bg_set)
2475	{
2476	  XSETFRAME (frame, f);
2477	  Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2478					     tty_color_name (f, orig_fg),
2479					     frame);
2480	  redraw = 1;
2481	}
2482    }
2483
2484  if (redraw)
2485    {
2486      face_change_count++;	/* forces xdisp.c to recompute basic faces */
2487      if (f == SELECTED_FRAME())
2488	redraw_frame (f);
2489    }
2490}
2491
2492extern void init_frame_faces (FRAME_PTR);
2493
2494#endif /* !HAVE_X_WINDOWS */
2495
2496
2497/* Do we need the internal terminal?  */
2498
2499void
2500internal_terminal_init ()
2501{
2502  char *term = getenv ("TERM"), *colors;
2503  struct frame *sf = SELECTED_FRAME();
2504
2505#ifdef HAVE_X_WINDOWS
2506  if (!inhibit_window_system)
2507    return;
2508#endif
2509
2510  internal_terminal
2511    = (!noninteractive) && term && !strcmp (term, "internal");
2512
2513  if (getenv ("EMACSTEST"))
2514    termscript = fopen (getenv ("EMACSTEST"), "wt");
2515
2516#ifndef HAVE_X_WINDOWS
2517  if (!internal_terminal || inhibit_window_system)
2518    {
2519      sf->output_method = output_termcap;
2520      return;
2521    }
2522
2523  Vwindow_system = intern ("pc");
2524  Vwindow_system_version = make_number (1);
2525  sf->output_method = output_msdos_raw;
2526
2527  /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address.  */
2528  screen_old_address = 0;
2529
2530  /* Forget the stale screen colors as well.  */
2531  initial_screen_colors[0] = initial_screen_colors[1] = -1;
2532
2533  bzero (&the_only_x_display, sizeof the_only_x_display);
2534  the_only_x_display.background_pixel = 7; /* White */
2535  the_only_x_display.foreground_pixel = 0; /* Black */
2536  bright_bg ();
2537  colors = getenv ("EMACSCOLORS");
2538  if (colors && strlen (colors) >= 2)
2539    {
2540      /* The colors use 4 bits each (we enable bright background).  */
2541      if (isdigit (colors[0]))
2542        colors[0] -= '0';
2543      else if (isxdigit (colors[0]))
2544        colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2545      if (colors[0] >= 0 && colors[0] < 16)
2546        the_only_x_display.foreground_pixel = colors[0];
2547      if (isdigit (colors[1]))
2548        colors[1] -= '0';
2549      else if (isxdigit (colors[1]))
2550        colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2551      if (colors[1] >= 0 && colors[1] < 16)
2552        the_only_x_display.background_pixel = colors[1];
2553    }
2554  the_only_x_display.font = (XFontStruct *)1;   /* must *not* be zero */
2555  the_only_x_display.display_info.mouse_face_mouse_frame = NULL;
2556  the_only_x_display.display_info.mouse_face_deferred_gc = 0;
2557  the_only_x_display.display_info.mouse_face_beg_row =
2558    the_only_x_display.display_info.mouse_face_beg_col = -1;
2559  the_only_x_display.display_info.mouse_face_end_row =
2560    the_only_x_display.display_info.mouse_face_end_col = -1;
2561  the_only_x_display.display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2562  the_only_x_display.display_info.mouse_face_window = Qnil;
2563  the_only_x_display.display_info.mouse_face_mouse_x =
2564    the_only_x_display.display_info.mouse_face_mouse_y = 0;
2565  the_only_x_display.display_info.mouse_face_defer = 0;
2566  the_only_x_display.display_info.mouse_face_hidden = 0;
2567
2568  init_frame_faces (sf);
2569
2570  ring_bell_hook = IT_ring_bell;
2571  insert_glyphs_hook = IT_insert_glyphs;
2572  delete_glyphs_hook = IT_delete_glyphs;
2573  write_glyphs_hook = IT_write_glyphs;
2574  cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
2575  clear_to_end_hook = IT_clear_to_end;
2576  clear_end_of_line_hook = IT_clear_end_of_line;
2577  clear_frame_hook = IT_clear_screen;
2578  update_begin_hook = IT_update_begin;
2579  update_end_hook = IT_update_end;
2580  frame_up_to_date_hook = IT_frame_up_to_date;
2581
2582  /* These hooks are called by term.c without being checked.  */
2583  set_terminal_modes_hook = IT_set_terminal_modes;
2584  reset_terminal_modes_hook = IT_reset_terminal_modes;
2585  set_terminal_window_hook = IT_set_terminal_window;
2586  char_ins_del_ok = 0;
2587#endif
2588}
2589
2590dos_get_saved_screen (screen, rows, cols)
2591     char **screen;
2592     int *rows;
2593     int *cols;
2594{
2595#ifndef HAVE_X_WINDOWS
2596  *screen = startup_screen_buffer;
2597  *cols = startup_screen_size_X;
2598  *rows = startup_screen_size_Y;
2599  return *screen != (char *)0;
2600#else
2601  return 0;
2602#endif
2603}
2604
2605#ifndef HAVE_X_WINDOWS
2606
2607/* We are not X, but we can emulate it well enough for our needs... */
2608void
2609check_x (void)
2610{
2611  if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2612    error ("Not running under a window system");
2613}
2614
2615#endif
2616
2617
2618/* ----------------------- Keyboard control ----------------------
2619 *
2620 * Keymaps reflect the following keyboard layout:
2621 *
2622 *    0  1  2  3  4  5  6  7  8  9  10 11 12  BS
2623 *    TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2624 *    CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2625 *    SH () 45 46 47 48 49 50 51 52 53 54  SHIFT
2626 *                    SPACE
2627 */
2628
2629#define Ignore	0x0000
2630#define Normal	0x0000	/* normal key - alt changes scan-code */
2631#define FctKey	0x1000	/* func key if c == 0, else c */
2632#define Special	0x2000	/* func key even if c != 0 */
2633#define ModFct	0x3000	/* special if mod-keys, else 'c' */
2634#define Map	0x4000	/* alt scan-code, map to unshift/shift key */
2635#define KeyPad	0x5000	/* map to insert/kp-0 depending on c == 0xe0 */
2636#define Grey	0x6000	/* Grey keypad key */
2637
2638#define Alt	0x0100	/* alt scan-code */
2639#define Ctrl	0x0200	/* ctrl scan-code */
2640#define Shift	0x0400	/* shift scan-code */
2641
2642static int extended_kbd; /* 101 (102) keyboard present. */
2643
2644struct kbd_translate {
2645  unsigned char  sc;
2646  unsigned char  ch;
2647  unsigned short code;
2648};
2649
2650struct dos_keyboard_map
2651{
2652  char *unshifted;
2653  char *shifted;
2654  char *alt_gr;
2655  struct kbd_translate *translate_table;
2656};
2657
2658
2659static struct dos_keyboard_map us_keyboard = {
2660/* 0         1         2         3         4         5      */
2661/* 01234567890123456789012345678901234567890 12345678901234 */
2662  "`1234567890-=  qwertyuiop[]   asdfghjkl;'\\   zxcvbnm,./  ",
2663/* 0123456789012345678901234567890123456789 012345678901234 */
2664  "~!@#$%^&*()_+  QWERTYUIOP{}   ASDFGHJKL:\"|   ZXCVBNM<>?  ",
2665  0,				/* no Alt-Gr key */
2666  0				/* no translate table */
2667};
2668
2669static struct dos_keyboard_map fr_keyboard = {
2670/* 0         1         2         3         4         5      */
2671/* 012 3456789012345678901234567890123456789012345678901234 */
2672  "�&�\",(-�_��)=  azertyuiop^$   qsdfghjklm�*   wxcvbnm;:!  ",
2673/* 0123456789012345678901234567890123456789012345678901234 */
2674  " 1234567890�+  AZERTYUIOP�   QSDFGHJKLM%�   WXCVBN?./�  ",
2675/* 01234567 89012345678901234567890123456789012345678901234 */
2676  "  ~#{[|`\\^@]}             �                              ",
2677  0				/* no translate table */
2678};
2679
2680/*
2681 * Italian keyboard support, country code 39.
2682 * '<' 56:3c*0000
2683 * '>' 56:3e*0000
2684 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2685 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2686 */
2687
2688static struct kbd_translate it_kbd_translate_table[] = {
2689  { 0x56, 0x3c, Normal | 13 },
2690  { 0x56, 0x3e, Normal | 27 },
2691  { 0, 0, 0 }
2692};
2693static struct dos_keyboard_map it_keyboard = {
2694/* 0          1         2         3         4         5     */
2695/* 0 123456789012345678901234567890123456789012345678901234 */
2696  "\\1234567890'�< qwertyuiop�+>  asdfghjkl���   zxcvbnm,.-  ",
2697/* 01 23456789012345678901234567890123456789012345678901234 */
2698  "|!\"�$%&/()=?^> QWERTYUIOP�*   ASDFGHJKL���   ZXCVBNM;:_  ",
2699/* 0123456789012345678901234567890123456789012345678901234 */
2700  "        {}~`             []             @#               ",
2701  it_kbd_translate_table
2702};
2703
2704static struct dos_keyboard_map dk_keyboard = {
2705/* 0         1         2         3         4         5      */
2706/* 0123456789012345678901234567890123456789012345678901234 */
2707  "�1234567890+|  qwertyuiop�~   asdfghjkl��'   zxcvbnm,.-  ",
2708/* 01 23456789012345678901234567890123456789012345678901234 */
2709  "�!\"#$%&/()=?`  QWERTYUIOP�^   ASDFGHJKL��*   ZXCVBNM;:_  ",
2710/* 0123456789012345678901234567890123456789012345678901234 */
2711  "  @�$  {[]} |                                             ",
2712  0				/* no translate table */
2713};
2714
2715static struct kbd_translate jp_kbd_translate_table[] = {
2716  { 0x73, 0x5c, Normal | 0 },
2717  { 0x73, 0x5f, Normal | 0 },
2718  { 0x73, 0x1c, Map | 0 },
2719  { 0x7d, 0x5c, Normal | 13 },
2720  { 0x7d, 0x7c, Normal | 13 },
2721  { 0x7d, 0x1c, Map | 13 },
2722  { 0, 0, 0 }
2723};
2724static struct dos_keyboard_map jp_keyboard = {
2725/*  0         1          2         3         4         5     */
2726/*  0123456789012 345678901234567890123456789012345678901234 */
2727  "\\1234567890-^\\ qwertyuiop@[   asdfghjkl;:]   zxcvbnm,./  ",
2728/*  01 23456789012345678901234567890123456789012345678901234 */
2729   "_!\"#$%&'()~=~| QWERTYUIOP`{   ASDFGHJKL+*}   ZXCVBNM<>?  ",
2730  0,				/* no Alt-Gr key */
2731  jp_kbd_translate_table
2732};
2733
2734static struct keyboard_layout_list
2735{
2736  int country_code;
2737  struct dos_keyboard_map *keyboard_map;
2738} keyboard_layout_list[] =
2739{
2740  1, &us_keyboard,
2741  33, &fr_keyboard,
2742  39, &it_keyboard,
2743  45, &dk_keyboard,
2744  81, &jp_keyboard
2745};
2746
2747static struct dos_keyboard_map *keyboard;
2748static int keyboard_map_all;
2749static int international_keyboard;
2750
2751int
2752dos_set_keyboard (code, always)
2753     int code;
2754     int always;
2755{
2756  int i;
2757  _go32_dpmi_registers regs;
2758
2759  /* See if Keyb.Com is installed (for international keyboard support).
2760     Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2761     of Windows 9X!  So don't do that!  */
2762  regs.x.ax = 0xad80;
2763  regs.x.ss = regs.x.sp = regs.x.flags = 0;
2764  _go32_dpmi_simulate_int (0x2f, &regs);
2765  if (regs.h.al == 0xff)
2766    international_keyboard = 1;
2767
2768  /* Initialize to US settings, for countries that don't have their own.  */
2769  keyboard = keyboard_layout_list[0].keyboard_map;
2770  keyboard_map_all = always;
2771  dos_keyboard_layout = 1;
2772
2773  for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2774    if (code == keyboard_layout_list[i].country_code)
2775      {
2776	keyboard = keyboard_layout_list[i].keyboard_map;
2777	keyboard_map_all = always;
2778	dos_keyboard_layout = code;
2779	return 1;
2780      }
2781  return 0;
2782}
2783
2784static struct
2785{
2786  unsigned char char_code;	/* normal code	*/
2787  unsigned char meta_code;	/* M- code	*/
2788  unsigned char keypad_code;	/* keypad code	*/
2789  unsigned char editkey_code;	/* edit key	*/
2790} keypad_translate_map[] = {
2791  '0',  '0',  0xb0, /* kp-0 */		0x63, /* insert */
2792  '1',  '1',  0xb1, /* kp-1 */		0x57, /* end */
2793  '2',  '2',  0xb2, /* kp-2 */		0x54, /* down */
2794  '3',  '3',  0xb3, /* kp-3 */		0x56, /* next */
2795  '4',  '4',  0xb4, /* kp-4 */		0x51, /* left */
2796  '5',  '5',  0xb5, /* kp-5 */		0xb5, /* kp-5 */
2797  '6',  '6',  0xb6, /* kp-6 */		0x53, /* right */
2798  '7',  '7',  0xb7, /* kp-7 */		0x50, /* home */
2799  '8',  '8',  0xb8, /* kp-8 */		0x52, /* up */
2800  '9',  '9',  0xb9, /* kp-9 */		0x55, /* prior */
2801  '.',  '-',  0xae, /* kp-decimal */	0xff  /* delete */
2802};
2803
2804static struct
2805{
2806  unsigned char char_code;	/* normal code	*/
2807  unsigned char keypad_code;	/* keypad code	*/
2808} grey_key_translate_map[] = {
2809  '/',  0xaf, /* kp-decimal */
2810  '*',  0xaa, /* kp-multiply */
2811  '-',  0xad, /* kp-subtract */
2812  '+',  0xab, /* kp-add */
2813  '\r', 0x8d  /* kp-enter */
2814};
2815
2816static unsigned short
2817ibmpc_translate_map[] =
2818{
2819  /* --------------- 00 to 0f --------------- */
2820  Normal | 0xff,	/* Ctrl Break + Alt-NNN */
2821  Alt | ModFct | 0x1b,		/* Escape */
2822  Normal | 1,			/* '1' */
2823  Normal | 2,			/* '2' */
2824  Normal | 3,			/* '3' */
2825  Normal | 4,			/* '4' */
2826  Normal | 5,			/* '5' */
2827  Normal | 6,			/* '6' */
2828  Normal | 7,			/* '7' */
2829  Normal | 8,			/* '8' */
2830  Normal | 9,			/* '9' */
2831  Normal | 10,			/* '0' */
2832  Normal | 11,			/* '-' */
2833  Normal | 12,			/* '=' */
2834  Special | 0x08,		/* Backspace */
2835  ModFct | 0x74,		/* Tab/Backtab */
2836
2837  /* --------------- 10 to 1f --------------- */
2838  Map | 15,			/* 'q' */
2839  Map | 16,			/* 'w' */
2840  Map | 17,			/* 'e' */
2841  Map | 18,			/* 'r' */
2842  Map | 19,			/* 't' */
2843  Map | 20,			/* 'y' */
2844  Map | 21,			/* 'u' */
2845  Map | 22,			/* 'i' */
2846  Map | 23,			/* 'o' */
2847  Map | 24,			/* 'p' */
2848  Map | 25,			/* '[' */
2849  Map | 26,			/* ']' */
2850  ModFct | 0x0d,		/* Return */
2851  Ignore,			/* Ctrl */
2852  Map | 30,			/* 'a' */
2853  Map | 31,			/* 's' */
2854
2855  /* --------------- 20 to 2f --------------- */
2856  Map | 32,			/* 'd' */
2857  Map | 33,			/* 'f' */
2858  Map | 34,			/* 'g' */
2859  Map | 35,			/* 'h' */
2860  Map | 36,			/* 'j' */
2861  Map | 37,			/* 'k' */
2862  Map | 38,			/* 'l' */
2863  Map | 39,			/* ';' */
2864  Map | 40,			/* '\'' */
2865  Map |  0,			/* '`' */
2866  Ignore,			/* Left shift */
2867  Map | 41,			/* '\\' */
2868  Map | 45,			/* 'z' */
2869  Map | 46,			/* 'x' */
2870  Map | 47,			/* 'c' */
2871  Map | 48,			/* 'v' */
2872
2873  /* --------------- 30 to 3f --------------- */
2874  Map | 49,			/* 'b' */
2875  Map | 50,			/* 'n' */
2876  Map | 51,			/* 'm' */
2877  Map | 52,			/* ',' */
2878  Map | 53,			/* '.' */
2879  Map | 54,			/* '/' */
2880  Ignore,			/* Right shift */
2881  Grey | 1,			/* Grey * */
2882  Ignore,			/* Alt */
2883  Normal | 55,			/* ' ' */
2884  Ignore,			/* Caps Lock */
2885  FctKey | 0xbe,		/* F1 */
2886  FctKey | 0xbf,		/* F2 */
2887  FctKey | 0xc0,		/* F3 */
2888  FctKey | 0xc1,		/* F4 */
2889  FctKey | 0xc2,		/* F5 */
2890
2891  /* --------------- 40 to 4f --------------- */
2892  FctKey | 0xc3,		/* F6 */
2893  FctKey | 0xc4,		/* F7 */
2894  FctKey | 0xc5,		/* F8 */
2895  FctKey | 0xc6,		/* F9 */
2896  FctKey | 0xc7,		/* F10 */
2897  Ignore,			/* Num Lock */
2898  Ignore,			/* Scroll Lock */
2899  KeyPad | 7,			/* Home */
2900  KeyPad | 8,			/* Up */
2901  KeyPad | 9,			/* Page Up */
2902  Grey | 2,			/* Grey - */
2903  KeyPad | 4,			/* Left */
2904  KeyPad | 5,			/* Keypad 5 */
2905  KeyPad | 6,			/* Right */
2906  Grey | 3,			/* Grey + */
2907  KeyPad | 1,			/* End */
2908
2909  /* --------------- 50 to 5f --------------- */
2910  KeyPad | 2,			/* Down */
2911  KeyPad | 3,			/* Page Down */
2912  KeyPad | 0,			/* Insert */
2913  KeyPad | 10,			/* Delete */
2914  Shift | FctKey | 0xbe,	/* (Shift) F1 */
2915  Shift | FctKey | 0xbf,	/* (Shift) F2 */
2916  Shift | FctKey | 0xc0,	/* (Shift) F3 */
2917  Shift | FctKey | 0xc1,	/* (Shift) F4 */
2918  Shift | FctKey | 0xc2,	/* (Shift) F5 */
2919  Shift | FctKey | 0xc3,	/* (Shift) F6 */
2920  Shift | FctKey | 0xc4,	/* (Shift) F7 */
2921  Shift | FctKey | 0xc5,	/* (Shift) F8 */
2922  Shift | FctKey | 0xc6,	/* (Shift) F9 */
2923  Shift | FctKey | 0xc7,	/* (Shift) F10 */
2924  Ctrl | FctKey | 0xbe,		/* (Ctrl) F1 */
2925  Ctrl | FctKey | 0xbf,		/* (Ctrl) F2 */
2926
2927  /* --------------- 60 to 6f --------------- */
2928  Ctrl | FctKey | 0xc0,		/* (Ctrl) F3 */
2929  Ctrl | FctKey | 0xc1,		/* (Ctrl) F4 */
2930  Ctrl | FctKey | 0xc2,		/* (Ctrl) F5 */
2931  Ctrl | FctKey | 0xc3,		/* (Ctrl) F6 */
2932  Ctrl | FctKey | 0xc4,		/* (Ctrl) F7 */
2933  Ctrl | FctKey | 0xc5,		/* (Ctrl) F8 */
2934  Ctrl | FctKey | 0xc6,		/* (Ctrl) F9 */
2935  Ctrl | FctKey | 0xc7,		/* (Ctrl) F10 */
2936  Alt | FctKey | 0xbe,		/* (Alt) F1 */
2937  Alt | FctKey | 0xbf,		/* (Alt) F2 */
2938  Alt | FctKey | 0xc0,		/* (Alt) F3 */
2939  Alt | FctKey | 0xc1,		/* (Alt) F4 */
2940  Alt | FctKey | 0xc2,		/* (Alt) F5 */
2941  Alt | FctKey | 0xc3,		/* (Alt) F6 */
2942  Alt | FctKey | 0xc4,		/* (Alt) F7 */
2943  Alt | FctKey | 0xc5,		/* (Alt) F8 */
2944
2945  /* --------------- 70 to 7f --------------- */
2946  Alt | FctKey | 0xc6,		/* (Alt) F9 */
2947  Alt | FctKey | 0xc7,		/* (Alt) F10 */
2948  Ctrl | FctKey | 0x6d,		/* (Ctrl) Sys Rq */
2949  Ctrl | KeyPad | 4,		/* (Ctrl) Left */
2950  Ctrl | KeyPad | 6,		/* (Ctrl) Right */
2951  Ctrl | KeyPad | 1,		/* (Ctrl) End */
2952  Ctrl | KeyPad | 3,		/* (Ctrl) Page Down */
2953  Ctrl | KeyPad | 7,		/* (Ctrl) Home */
2954  Alt | Map | 1,		/* '1' */
2955  Alt | Map | 2,		/* '2' */
2956  Alt | Map | 3,		/* '3' */
2957  Alt | Map | 4,		/* '4' */
2958  Alt | Map | 5,		/* '5' */
2959  Alt | Map | 6,		/* '6' */
2960  Alt | Map | 7,		/* '7' */
2961  Alt | Map | 8,		/* '8' */
2962
2963  /* --------------- 80 to 8f --------------- */
2964  Alt | Map | 9,		/* '9' */
2965  Alt | Map | 10,		/* '0' */
2966  Alt | Map | 11,		/* '-' */
2967  Alt | Map | 12,		/* '=' */
2968  Ctrl | KeyPad | 9,		/* (Ctrl) Page Up */
2969  FctKey | 0xc8,		/* F11 */
2970  FctKey | 0xc9,		/* F12 */
2971  Shift | FctKey | 0xc8,	/* (Shift) F11 */
2972  Shift | FctKey | 0xc9,	/* (Shift) F12 */
2973  Ctrl | FctKey | 0xc8,		/* (Ctrl) F11 */
2974  Ctrl | FctKey | 0xc9,		/* (Ctrl) F12 */
2975  Alt | FctKey | 0xc8,		/* (Alt) F11 */
2976  Alt | FctKey | 0xc9,		/* (Alt) F12 */
2977  Ctrl | KeyPad | 8,		/* (Ctrl) Up */
2978  Ctrl | Grey | 2,		/* (Ctrl) Grey - */
2979  Ctrl | KeyPad | 5,		/* (Ctrl) Keypad 5 */
2980
2981  /* --------------- 90 to 9f --------------- */
2982  Ctrl | Grey | 3,		/* (Ctrl) Grey + */
2983  Ctrl | KeyPad | 2,		/* (Ctrl) Down */
2984  Ctrl | KeyPad | 0,		/* (Ctrl) Insert */
2985  Ctrl | KeyPad | 10,		/* (Ctrl) Delete */
2986  Ctrl | FctKey | 0x09,		/* (Ctrl) Tab */
2987  Ctrl | Grey | 0,		/* (Ctrl) Grey / */
2988  Ctrl | Grey | 1,		/* (Ctrl) Grey * */
2989  Alt | FctKey | 0x50,		/* (Alt) Home */
2990  Alt | FctKey | 0x52,		/* (Alt) Up */
2991  Alt | FctKey | 0x55,		/* (Alt) Page Up */
2992  Ignore,			/* NO KEY */
2993  Alt | FctKey | 0x51,		/* (Alt) Left */
2994  Ignore,			/* NO KEY */
2995  Alt | FctKey | 0x53,		/* (Alt) Right */
2996  Ignore,			/* NO KEY */
2997  Alt | FctKey | 0x57,		/* (Alt) End */
2998
2999  /* --------------- a0 to af --------------- */
3000  Alt | KeyPad | 2,		/* (Alt) Down */
3001  Alt | KeyPad | 3,		/* (Alt) Page Down */
3002  Alt | KeyPad | 0,		/* (Alt) Insert */
3003  Alt | KeyPad | 10,		/* (Alt) Delete */
3004  Alt | Grey | 0,		/* (Alt) Grey / */
3005  Alt | FctKey | 0x09,		/* (Alt) Tab */
3006  Alt | Grey | 4		/* (Alt) Keypad Enter */
3007};
3008
3009/* These bit-positions corresponds to values returned by BIOS */
3010#define SHIFT_P		0x0003	/* two bits! */
3011#define CTRL_P		0x0004
3012#define ALT_P		0x0008
3013#define SCRLOCK_P	0x0010
3014#define NUMLOCK_P	0x0020
3015#define CAPSLOCK_P	0x0040
3016#define ALT_GR_P	0x0800
3017#define SUPER_P		0x4000	/* pseudo */
3018#define HYPER_P		0x8000	/* pseudo */
3019
3020static int
3021dos_get_modifiers (keymask)
3022     int *keymask;
3023{
3024  union REGS regs;
3025  int mask, modifiers = 0;
3026
3027  /* Calculate modifier bits */
3028  regs.h.ah = extended_kbd ? 0x12 : 0x02;
3029  int86 (0x16, &regs, &regs);
3030
3031  if (!extended_kbd)
3032    {
3033      mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
3034			  SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
3035    }
3036  else
3037    {
3038      mask = regs.h.al & (SHIFT_P |
3039			  SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
3040
3041      /* Do not break international keyboard support.   */
3042      /* When Keyb.Com is loaded, the right Alt key is  */
3043      /* used for accessing characters like { and } 	  */
3044      if (regs.h.ah & 2)		/* Left ALT pressed ? */
3045	mask |= ALT_P;
3046
3047      if ((regs.h.ah & 8) != 0)		/* Right ALT pressed ? */
3048	{
3049	  mask |= ALT_GR_P;
3050	  if (dos_hyper_key == 1)
3051	    {
3052	      mask |= HYPER_P;
3053	      modifiers |= hyper_modifier;
3054	    }
3055	  else if (dos_super_key == 1)
3056	    {
3057	      mask |= SUPER_P;
3058	      modifiers |= super_modifier;
3059	    }
3060	  else if (!international_keyboard)
3061	    {
3062	      /* If Keyb.Com is NOT installed, let Right Alt behave
3063		 like the Left Alt.  */
3064	      mask &= ~ALT_GR_P;
3065	      mask |= ALT_P;
3066	    }
3067	}
3068
3069      if (regs.h.ah & 1)		/* Left CTRL pressed ? */
3070	mask |= CTRL_P;
3071
3072      if (regs.h.ah & 4)	 	/* Right CTRL pressed ? */
3073	{
3074	  if (dos_hyper_key == 2)
3075	    {
3076	      mask |= HYPER_P;
3077	      modifiers |= hyper_modifier;
3078	    }
3079	  else if (dos_super_key == 2)
3080	    {
3081	      mask |= SUPER_P;
3082	      modifiers |= super_modifier;
3083	    }
3084	  else
3085	    mask |= CTRL_P;
3086	}
3087    }
3088
3089  if (mask & SHIFT_P)
3090    modifiers |= shift_modifier;
3091  if (mask & CTRL_P)
3092    modifiers |= ctrl_modifier;
3093  if (mask & ALT_P)
3094    modifiers |= meta_modifier;
3095
3096  if (keymask)
3097    *keymask = mask;
3098  return modifiers;
3099}
3100
3101#define NUM_RECENT_DOSKEYS (100)
3102int recent_doskeys_index;	/* Index for storing next element into recent_doskeys */
3103int total_doskeys;		/* Total number of elements stored into recent_doskeys */
3104Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
3105
3106DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
3107       doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3108Each input key receives two values in this vector: first the ASCII code,
3109and then the scan code.  */)
3110     ()
3111{
3112  Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
3113
3114  if (total_doskeys < NUM_RECENT_DOSKEYS)
3115    return Fvector (total_doskeys, keys);
3116  else
3117    {
3118      val = Fvector (NUM_RECENT_DOSKEYS, keys);
3119      bcopy (keys + recent_doskeys_index,
3120	     XVECTOR (val)->contents,
3121	     (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
3122      bcopy (keys,
3123	     XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
3124	     recent_doskeys_index * sizeof (Lisp_Object));
3125      return val;
3126    }
3127}
3128
3129/* Get a char from keyboard.  Function keys are put into the event queue.  */
3130static int
3131dos_rawgetc ()
3132{
3133  struct input_event event;
3134  union REGS regs;
3135  struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3136  EVENT_INIT (event);
3137
3138#ifndef HAVE_X_WINDOWS
3139  /* Maybe put the cursor where it should be.  */
3140  IT_cmgoto (SELECTED_FRAME());
3141#endif
3142
3143  /* The following condition is equivalent to `kbhit ()', except that
3144     it uses the bios to do its job.  This pleases DESQview/X.  */
3145  while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
3146	 int86 (0x16, &regs, &regs),
3147	 (regs.x.flags & 0x40) == 0)
3148    {
3149      union REGS regs;
3150      register unsigned char c;
3151      int modifiers, sc, code = -1, mask, kp_mode;
3152
3153      regs.h.ah = extended_kbd ? 0x10 : 0x00;
3154      int86 (0x16, &regs, &regs);
3155      c = regs.h.al;
3156      sc = regs.h.ah;
3157
3158      total_doskeys += 2;
3159      XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3160	= make_number (c);
3161      if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3162	recent_doskeys_index = 0;
3163      XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
3164	= make_number (sc);
3165      if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
3166	recent_doskeys_index = 0;
3167
3168      modifiers = dos_get_modifiers (&mask);
3169
3170#ifndef HAVE_X_WINDOWS
3171      if (!NILP (Vdos_display_scancodes))
3172	{
3173	  char buf[11];
3174	  sprintf (buf, "%02x:%02x*%04x",
3175		   (unsigned) (sc&0xff), (unsigned) c, mask);
3176	  dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
3177	}
3178#endif
3179
3180      if (sc == 0xe0)
3181	{
3182	  switch (c)
3183	    {
3184	    case 10:		/* Ctrl Grey Enter */
3185	      code = Ctrl | Grey | 4;
3186	      break;
3187	    case 13:		/* Grey Enter */
3188	      code = Grey | 4;
3189	      break;
3190	    case '/':		/* Grey / */
3191	      code = Grey | 0;
3192	      break;
3193	    default:
3194	      continue;
3195	    };
3196	  c = 0;
3197	}
3198      else
3199	{
3200	  /* Try the keyboard-private translation table first.  */
3201	  if (keyboard->translate_table)
3202	    {
3203	      struct kbd_translate *p = keyboard->translate_table;
3204
3205	      while (p->sc)
3206		{
3207		  if (p->sc == sc && p->ch == c)
3208		    {
3209		      code = p->code;
3210		      break;
3211		    }
3212		  p++;
3213		}
3214	    }
3215	  /* If the private table didn't translate it, use the general
3216             one.  */
3217	  if (code == -1)
3218	    {
3219	      if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3220		continue;
3221	      if ((code = ibmpc_translate_map[sc]) == Ignore)
3222		continue;
3223	    }
3224	}
3225
3226      if (c == 0)
3227	{
3228        /* We only look at the keyboard Ctrl/Shift/Alt keys when
3229           Emacs is ready to read a key.  Therefore, if they press
3230           `Alt-x' when Emacs is busy, by the time we get to
3231           `dos_get_modifiers', they might have already released the
3232           Alt key, and Emacs gets just `x', which is BAD.
3233           However, for keys with the `Map' property set, the ASCII
3234           code returns zero iff Alt is pressed.  So, when we DON'T
3235           have to support international_keyboard, we don't have to
3236           distinguish between the left and  right Alt keys, and we
3237           can set the META modifier for any keys with the `Map'
3238           property if they return zero ASCII code (c = 0).  */
3239        if ( (code & Alt)
3240             || ( (code & 0xf000) == Map && !international_keyboard))
3241	    modifiers |= meta_modifier;
3242	  if (code & Ctrl)
3243	    modifiers |= ctrl_modifier;
3244	  if (code & Shift)
3245	    modifiers |= shift_modifier;
3246	}
3247
3248      switch (code & 0xf000)
3249	{
3250	case ModFct:
3251	  if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3252	    return c;
3253	  c = 0;		/* Special */
3254
3255	case FctKey:
3256	  if (c != 0)
3257	    return c;
3258
3259	case Special:
3260	  code |= 0xff00;
3261	  break;
3262
3263	case Normal:
3264	  if (sc == 0)
3265	    {
3266	      if (c == 0)	/* ctrl-break */
3267		continue;
3268	      return c;		/* ALT-nnn */
3269	    }
3270	  if (!keyboard_map_all)
3271	    {
3272	      if (c != ' ')
3273		return c;
3274	      code = c;
3275	      break;
3276	    }
3277
3278	case Map:
3279	  if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3280	    if (!keyboard_map_all)
3281	      return c;
3282
3283	  code &= 0xff;
3284	  if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3285	    mask |= SHIFT_P;	/* ALT-1 => M-! etc. */
3286
3287	  if (mask & SHIFT_P)
3288	    {
3289	      code = keyboard->shifted[code];
3290	      mask -= SHIFT_P;
3291	      modifiers &= ~shift_modifier;
3292	    }
3293	  else
3294	    if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3295	      code = keyboard->alt_gr[code];
3296	    else
3297	      code = keyboard->unshifted[code];
3298	  break;
3299
3300	case KeyPad:
3301	  code &= 0xff;
3302	  if (c == 0xe0)	/* edit key */
3303	    kp_mode = 3;
3304	  else
3305	    if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3306	      kp_mode = dos_keypad_mode & 0x03;
3307	    else
3308	      kp_mode = (dos_keypad_mode >> 4) & 0x03;
3309
3310	  switch (kp_mode)
3311	    {
3312	    case 0:
3313	      if (code == 10 && dos_decimal_point)
3314		return dos_decimal_point;
3315	      return keypad_translate_map[code].char_code;
3316
3317	    case 1:
3318	      code = 0xff00 | keypad_translate_map[code].keypad_code;
3319	      break;
3320
3321	    case 2:
3322	      code = keypad_translate_map[code].meta_code;
3323	      modifiers = meta_modifier;
3324	      break;
3325
3326	    case 3:
3327	      code = 0xff00 | keypad_translate_map[code].editkey_code;
3328	      break;
3329	    }
3330	  break;
3331
3332	case Grey:
3333	  code &= 0xff;
3334	  kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3335	  if (dos_keypad_mode & kp_mode)
3336	    code = 0xff00 | grey_key_translate_map[code].keypad_code;
3337	  else
3338	    code = grey_key_translate_map[code].char_code;
3339	  break;
3340	}
3341
3342    make_event:
3343      if (code == 0)
3344	continue;
3345
3346      if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3347	{
3348	  clear_mouse_face (dpyinfo);
3349	  dpyinfo->mouse_face_hidden = 1;
3350	}
3351
3352      if (code >= 0x100)
3353	event.kind = NON_ASCII_KEYSTROKE_EVENT;
3354      else
3355	event.kind = ASCII_KEYSTROKE_EVENT;
3356      event.code = code;
3357      event.modifiers =	modifiers;
3358      event.frame_or_window = selected_frame;
3359      event.arg = Qnil;
3360      event.timestamp = event_timestamp ();
3361      kbd_buffer_store_event (&event);
3362    }
3363
3364  if (have_mouse > 0 && !mouse_preempted)
3365    {
3366      int but, press, x, y, ok;
3367      int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3368      Lisp_Object mouse_window = Qnil;
3369
3370      /* Check for mouse movement *before* buttons.  */
3371      mouse_check_moved ();
3372
3373      /* If the mouse moved from the spot of its last sighting, we
3374         might need to update mouse highlight.  */
3375      if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3376	{
3377	  if (dpyinfo->mouse_face_hidden)
3378	    {
3379	      dpyinfo->mouse_face_hidden = 0;
3380	      clear_mouse_face (dpyinfo);
3381	    }
3382
3383	  /* Generate SELECT_WINDOW_EVENTs when needed.  */
3384	  if (!NILP (Vmouse_autoselect_window))
3385	    {
3386	      mouse_window = window_from_coordinates (SELECTED_FRAME(),
3387						      mouse_last_x,
3388						      mouse_last_y,
3389						      0, 0, 0, 0);
3390	      /* A window will be selected only when it is not
3391		 selected now, and the last mouse movement event was
3392		 not in it.  A minibuffer window will be selected iff
3393		 it is active.  */
3394	      if (WINDOWP (mouse_window)
3395		  && !EQ (mouse_window, last_mouse_window)
3396		  && !EQ (mouse_window, selected_window))
3397		{
3398		  event.kind = SELECT_WINDOW_EVENT;
3399		  event.frame_or_window = mouse_window;
3400		  event.arg = Qnil;
3401		  event.timestamp = event_timestamp ();
3402		  kbd_buffer_store_event (&event);
3403		}
3404	      last_mouse_window = mouse_window;
3405	    }
3406	  else
3407	    last_mouse_window = Qnil;
3408
3409	  previous_help_echo_string = help_echo_string;
3410	  help_echo_string = help_echo_object = help_echo_window = Qnil;
3411	  help_echo_pos = -1;
3412	  IT_note_mouse_highlight (SELECTED_FRAME(),
3413				   mouse_last_x, mouse_last_y);
3414	  /* If the contents of the global variable help_echo has
3415	     changed, generate a HELP_EVENT.  */
3416	  if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3417	    {
3418	      event.kind = HELP_EVENT;
3419	      event.frame_or_window = selected_frame;
3420	      event.arg = help_echo_object;
3421	      event.x = WINDOWP (help_echo_window)
3422		? help_echo_window : selected_frame;
3423	      event.y = help_echo_string;
3424	      event.timestamp = event_timestamp ();
3425	      event.code = help_echo_pos;
3426	      kbd_buffer_store_event (&event);
3427	    }
3428	}
3429
3430      for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3431	for (press = 0; press < 2; press++)
3432	  {
3433	    int button_num = but;
3434
3435	    if (press)
3436	      ok = mouse_pressed (but, &x, &y);
3437	    else
3438	      ok = mouse_released (but, &x, &y);
3439	    if (ok)
3440	      {
3441		/* Allow a simultaneous press/release of Mouse-1 and
3442		   Mouse-2 to simulate Mouse-3 on two-button mice.  */
3443		if (mouse_button_count == 2 && but < 2)
3444		  {
3445		    int x2, y2;	/* don't clobber original coordinates */
3446
3447		    /* If only one button is pressed, wait 100 msec and
3448		       check again.  This way, Speedy Gonzales isn't
3449		       punished, while the slow get their chance.  */
3450		    if (press && mouse_pressed (1-but, &x2, &y2)
3451			|| !press && mouse_released (1-but, &x2, &y2))
3452		      button_num = 2;
3453		    else
3454		      {
3455			delay (100);
3456			if (press && mouse_pressed (1-but, &x2, &y2)
3457			    || !press && mouse_released (1-but, &x2, &y2))
3458			  button_num = 2;
3459		      }
3460		  }
3461
3462		event.kind = MOUSE_CLICK_EVENT;
3463		event.code = button_num;
3464		event.modifiers = dos_get_modifiers (0)
3465		  | (press ? down_modifier : up_modifier);
3466		event.x = make_number (x);
3467		event.y = make_number (y);
3468		event.frame_or_window = selected_frame;
3469		event.arg = Qnil;
3470		event.timestamp = event_timestamp ();
3471		kbd_buffer_store_event (&event);
3472	      }
3473	  }
3474    }
3475
3476  return -1;
3477}
3478
3479static int prev_get_char = -1;
3480
3481/* Return 1 if a key is ready to be read without suspending execution.  */
3482
3483dos_keysns ()
3484{
3485  if (prev_get_char != -1)
3486    return 1;
3487  else
3488    return ((prev_get_char = dos_rawgetc ()) != -1);
3489}
3490
3491/* Read a key.  Return -1 if no key is ready.  */
3492
3493dos_keyread ()
3494{
3495  if (prev_get_char != -1)
3496    {
3497      int c = prev_get_char;
3498      prev_get_char = -1;
3499      return c;
3500    }
3501  else
3502    return dos_rawgetc ();
3503}
3504
3505#ifndef HAVE_X_WINDOWS
3506
3507/* Simulation of X's menus.  Nothing too fancy here -- just make it work
3508   for now.
3509
3510   Actually, I don't know the meaning of all the parameters of the functions
3511   here -- I only know how they are called by xmenu.c.  I could of course
3512   grab the nearest Xlib manual (down the hall, second-to-last door on the
3513   left), but I don't think it's worth the effort.  */
3514
3515/* These hold text of the current and the previous menu help messages.  */
3516static char *menu_help_message, *prev_menu_help_message;
3517/* Pane number and item number of the menu item which generated the
3518   last menu help message.  */
3519static int menu_help_paneno, menu_help_itemno;
3520
3521static XMenu *
3522IT_menu_create ()
3523{
3524  XMenu *menu;
3525
3526  menu = (XMenu *) xmalloc (sizeof (XMenu));
3527  menu->allocated = menu->count = menu->panecount = menu->width = 0;
3528  return menu;
3529}
3530
3531/* Allocate some (more) memory for MENU ensuring that there is room for one
3532   for item.  */
3533
3534static void
3535IT_menu_make_room (XMenu *menu)
3536{
3537  if (menu->allocated == 0)
3538    {
3539      int count = menu->allocated = 10;
3540      menu->text = (char **) xmalloc (count * sizeof (char *));
3541      menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3542      menu->panenumber = (int *) xmalloc (count * sizeof (int));
3543      menu->help_text = (char **) xmalloc (count * sizeof (char *));
3544    }
3545  else if (menu->allocated == menu->count)
3546    {
3547      int count = menu->allocated = menu->allocated + 10;
3548      menu->text
3549	= (char **) xrealloc (menu->text, count * sizeof (char *));
3550      menu->submenu
3551	= (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3552      menu->panenumber
3553	= (int *) xrealloc (menu->panenumber, count * sizeof (int));
3554      menu->help_text
3555	= (char **) xrealloc (menu->help_text, count * sizeof (char *));
3556    }
3557}
3558
3559/* Search the given menu structure for a given pane number.  */
3560
3561static XMenu *
3562IT_menu_search_pane (XMenu *menu, int pane)
3563{
3564  int i;
3565  XMenu *try;
3566
3567  for (i = 0; i < menu->count; i++)
3568    if (menu->submenu[i])
3569      {
3570	if (pane == menu->panenumber[i])
3571	  return menu->submenu[i];
3572	if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3573	  return try;
3574      }
3575  return (XMenu *) 0;
3576}
3577
3578/* Determine how much screen space a given menu needs.  */
3579
3580static void
3581IT_menu_calc_size (XMenu *menu, int *width, int *height)
3582{
3583  int i, h2, w2, maxsubwidth, maxheight;
3584
3585  maxsubwidth = 0;
3586  maxheight = menu->count;
3587  for (i = 0; i < menu->count; i++)
3588    {
3589      if (menu->submenu[i])
3590	{
3591	  IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3592	  if (w2 > maxsubwidth) maxsubwidth = w2;
3593	  if (i + h2 > maxheight) maxheight = i + h2;
3594	}
3595    }
3596  *width = menu->width + maxsubwidth;
3597  *height = maxheight;
3598}
3599
3600/* Display MENU at (X,Y) using FACES.  */
3601
3602static void
3603IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3604{
3605  int i, j, face, width,  mx, my, enabled, mousehere, row, col;
3606  struct glyph *text, *p;
3607  char *q;
3608  struct frame *sf = SELECTED_FRAME();
3609
3610  menu_help_message = NULL;
3611
3612  width = menu->width;
3613  text = (struct glyph *) xmalloc ((width + 2) * sizeof (struct glyph));
3614  ScreenGetCursor (&row, &col);
3615  mouse_get_xy (&mx, &my);
3616  IT_update_begin (sf);
3617  for (i = 0; i < menu->count; i++)
3618    {
3619      int max_width = width + 2;
3620
3621      IT_cursor_to (y + i, x);
3622      enabled
3623	= (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3624      mousehere = (y + i == my && x <= mx && mx < x + width + 2);
3625      face = faces[enabled + mousehere * 2];
3626      /* The following if clause means that we display the menu help
3627	 strings even if the menu item is currently disabled.  */
3628      if (disp_help && enabled + mousehere * 2 >= 2)
3629	{
3630	  menu_help_message = menu->help_text[i];
3631	  menu_help_paneno = pn - 1;
3632	  menu_help_itemno = i;
3633	}
3634      p = text;
3635      SET_CHAR_GLYPH (*p, ' ', face, 0);
3636      p++;
3637      for (j = 0, q = menu->text[i]; *q; j++)
3638	{
3639	  if (*q > 26)
3640	    {
3641	      SET_CHAR_GLYPH (*p, *q++, face, 0);
3642	      p++;
3643	    }
3644	  else	/* make '^x' */
3645	    {
3646	      SET_CHAR_GLYPH (*p, '^', face, 0);
3647	      p++;
3648	      j++;
3649	      SET_CHAR_GLYPH (*p, *q++ + 64, face, 0);
3650	      p++;
3651	    }
3652	}
3653      /* Don't let the menu text overflow into the next screen row.  */
3654      if (x + max_width > screen_size_X)
3655	{
3656	  max_width = screen_size_X - x;
3657	  text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3658	}
3659      for (; j < max_width - 2; j++, p++)
3660	SET_CHAR_GLYPH (*p, ' ', face, 0);
3661
3662      SET_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3663      p++;
3664      IT_write_glyphs (text, max_width);
3665    }
3666  IT_update_end (sf);
3667  IT_cursor_to (row, col);
3668  xfree (text);
3669}
3670
3671/* --------------------------- X Menu emulation ---------------------- */
3672
3673/* Report availability of menus.  */
3674
3675int
3676have_menus_p () {  return 1; }
3677
3678/* Create a brand new menu structure.  */
3679
3680XMenu *
3681XMenuCreate (Display *foo1, Window foo2, char *foo3)
3682{
3683  return IT_menu_create ();
3684}
3685
3686/* Create a new pane and place it on the outer-most level.  It is not
3687   clear that it should be placed out there, but I don't know what else
3688   to do.  */
3689
3690int
3691XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3692{
3693  int len;
3694  char *p;
3695
3696  if (!enable)
3697    abort ();
3698
3699  IT_menu_make_room (menu);
3700  menu->submenu[menu->count] = IT_menu_create ();
3701  menu->text[menu->count] = txt;
3702  menu->panenumber[menu->count] = ++menu->panecount;
3703  menu->help_text[menu->count] = NULL;
3704  menu->count++;
3705
3706  /* Adjust length for possible control characters (which will
3707     be written as ^x).  */
3708  for (len = strlen (txt), p = txt; *p; p++)
3709    if (*p < 27)
3710      len++;
3711
3712  if (len > menu->width)
3713    menu->width = len;
3714
3715  return menu->panecount;
3716}
3717
3718/* Create a new item in a menu pane.  */
3719
3720int
3721XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3722		   int foo, char *txt, int enable, char *help_text)
3723{
3724  int len;
3725  char *p;
3726
3727  if (pane)
3728    if (!(menu = IT_menu_search_pane (menu, pane)))
3729      return XM_FAILURE;
3730  IT_menu_make_room (menu);
3731  menu->submenu[menu->count] = (XMenu *) 0;
3732  menu->text[menu->count] = txt;
3733  menu->panenumber[menu->count] = enable;
3734  menu->help_text[menu->count] = help_text;
3735  menu->count++;
3736
3737  /* Adjust length for possible control characters (which will
3738     be written as ^x).  */
3739  for (len = strlen (txt), p = txt; *p; p++)
3740    if (*p < 27)
3741      len++;
3742
3743  if (len > menu->width)
3744    menu->width = len;
3745
3746  return XM_SUCCESS;
3747}
3748
3749/* Decide where the menu would be placed if requested at (X,Y).  */
3750
3751void
3752XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3753	     int *ulx, int *uly, int *width, int *height)
3754{
3755  IT_menu_calc_size (menu, width, height);
3756  *ulx = x + 1;
3757  *uly = y;
3758  *width += 2;
3759}
3760
3761struct IT_menu_state
3762{
3763  void *screen_behind;
3764  XMenu *menu;
3765  int pane;
3766  int x, y;
3767};
3768
3769
3770/* Display menu, wait for user's response, and return that response.  */
3771
3772int
3773XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3774	       int x0, int y0, unsigned ButtonMask, char **txt,
3775	       void (*help_callback)(char *, int, int))
3776{
3777  struct IT_menu_state *state;
3778  int statecount, x, y, i, b, screensize, leave, result, onepane;
3779  int title_faces[4];		/* face to display the menu title */
3780  int faces[4], buffers_num_deleted = 0;
3781  struct frame *sf = SELECTED_FRAME();
3782  Lisp_Object saved_echo_area_message, selectface;
3783
3784  /* Just in case we got here without a mouse present...  */
3785  if (have_mouse <= 0)
3786    return XM_IA_SELECT;
3787  /* Don't allow non-positive x0 and y0, lest the menu will wrap
3788     around the display.  */
3789  if (x0 <= 0)
3790    x0 = 1;
3791  if (y0 <= 0)
3792    y0 = 1;
3793
3794  /* We will process all the mouse events directly, so we had
3795     better prevent dos_rawgetc from stealing them from us.  */
3796  mouse_preempted++;
3797
3798  state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3799  screensize = screen_size * 2;
3800  faces[0]
3801    = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3802			   0, DEFAULT_FACE_ID, 1);
3803  faces[1]
3804    = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3805			   0, DEFAULT_FACE_ID, 1);
3806  selectface = intern ("msdos-menu-select-face");
3807  faces[2] = lookup_derived_face (sf, selectface,
3808				  0, faces[0], 1);
3809  faces[3] = lookup_derived_face (sf, selectface,
3810				  0, faces[1], 1);
3811
3812  /* Make sure the menu title is always displayed with
3813     `msdos-menu-active-face', no matter where the mouse pointer is.  */
3814  for (i = 0; i < 4; i++)
3815    title_faces[i] = faces[3];
3816
3817  statecount = 1;
3818
3819  /* Don't let the title for the "Buffers" popup menu include a
3820     digit (which is ugly).
3821
3822     This is a terrible kludge, but I think the "Buffers" case is
3823     the only one where the title includes a number, so it doesn't
3824     seem to be necessary to make this more general.  */
3825  if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3826    {
3827      menu->text[0][7] = '\0';
3828      buffers_num_deleted = 1;
3829    }
3830
3831  /* We need to save the current echo area message, so that we could
3832     restore it below, before we exit.  See the commentary below,
3833     before the call to message_with_string.  */
3834  saved_echo_area_message = Fcurrent_message ();
3835  state[0].menu = menu;
3836  mouse_off ();
3837  ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3838
3839  /* Turn off the cursor.  Otherwise it shows through the menu
3840     panes, which is ugly.  */
3841  IT_display_cursor (0);
3842
3843  /* Display the menu title.  */
3844  IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3845  if (buffers_num_deleted)
3846    menu->text[0][7] = ' ';
3847  if ((onepane = menu->count == 1 && menu->submenu[0]))
3848    {
3849      menu->width = menu->submenu[0]->width;
3850      state[0].menu = menu->submenu[0];
3851    }
3852  else
3853    {
3854      state[0].menu = menu;
3855    }
3856  state[0].x = x0 - 1;
3857  state[0].y = y0;
3858  state[0].pane = onepane;
3859
3860  mouse_last_x = -1;  /* A hack that forces display.  */
3861  leave = 0;
3862  while (!leave)
3863    {
3864      if (!mouse_visible) mouse_on ();
3865      mouse_check_moved ();
3866      if (sf->mouse_moved)
3867	{
3868	  sf->mouse_moved = 0;
3869	  result = XM_IA_SELECT;
3870	  mouse_get_xy (&x, &y);
3871	  for (i = 0; i < statecount; i++)
3872	    if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3873	      {
3874		int dy = y - state[i].y;
3875		if (0 <= dy && dy < state[i].menu->count)
3876		  {
3877		    if (!state[i].menu->submenu[dy])
3878		      if (state[i].menu->panenumber[dy])
3879			result = XM_SUCCESS;
3880		      else
3881			result = XM_IA_SELECT;
3882		    *pane = state[i].pane - 1;
3883		    *selidx = dy;
3884		    /* We hit some part of a menu, so drop extra menus that
3885		       have been opened.  That does not include an open and
3886		       active submenu.  */
3887		    if (i != statecount - 2
3888			|| state[i].menu->submenu[dy] != state[i+1].menu)
3889		      while (i != statecount - 1)
3890			{
3891			  statecount--;
3892			  mouse_off ();
3893			  ScreenUpdate (state[statecount].screen_behind);
3894			  if (screen_virtual_segment)
3895			    dosv_refresh_virtual_screen (0, screen_size);
3896			  xfree (state[statecount].screen_behind);
3897			}
3898		    if (i == statecount - 1 && state[i].menu->submenu[dy])
3899		      {
3900			IT_menu_display (state[i].menu,
3901					 state[i].y,
3902					 state[i].x,
3903					 state[i].pane,
3904					 faces, 1);
3905			state[statecount].menu = state[i].menu->submenu[dy];
3906			state[statecount].pane = state[i].menu->panenumber[dy];
3907			mouse_off ();
3908			ScreenRetrieve (state[statecount].screen_behind
3909					= xmalloc (screensize));
3910			state[statecount].x
3911			  = state[i].x + state[i].menu->width + 2;
3912			state[statecount].y = y;
3913			statecount++;
3914		      }
3915		  }
3916	      }
3917	  IT_menu_display (state[statecount - 1].menu,
3918			   state[statecount - 1].y,
3919			   state[statecount - 1].x,
3920			   state[statecount - 1].pane,
3921			   faces, 1);
3922	}
3923      else
3924	{
3925	  if ((menu_help_message || prev_menu_help_message)
3926	      && menu_help_message != prev_menu_help_message)
3927	    {
3928	      help_callback (menu_help_message,
3929			     menu_help_paneno, menu_help_itemno);
3930	      IT_display_cursor (0);
3931	      prev_menu_help_message = menu_help_message;
3932	    }
3933	  /* We are busy-waiting for the mouse to move, so let's be nice
3934	     to other Windows applications by releasing our time slice.  */
3935	  __dpmi_yield ();
3936	}
3937      for (b = 0; b < mouse_button_count && !leave; b++)
3938	{
3939	  /* Only leave if user both pressed and released the mouse, and in
3940	     that order.  This avoids popping down the menu pane unless
3941	     the user is really done with it.  */
3942	  if (mouse_pressed (b, &x, &y))
3943	    {
3944	      while (mouse_button_depressed (b, &x, &y))
3945		__dpmi_yield ();
3946	      leave = 1;
3947	    }
3948	  (void) mouse_released (b, &x, &y);
3949	}
3950    }
3951
3952  mouse_off ();
3953  ScreenUpdate (state[0].screen_behind);
3954  if (screen_virtual_segment)
3955    dosv_refresh_virtual_screen (0, screen_size);
3956
3957  /* We have a situation here.  ScreenUpdate has just restored the
3958     screen contents as it was before we started drawing this menu.
3959     That includes any echo area message that could have been
3960     displayed back then.  (In reality, that echo area message will
3961     almost always be the ``keystroke echo'' that echoes the sequence
3962     of menu items chosen by the user.)  However, if the menu had some
3963     help messages, then displaying those messages caused Emacs to
3964     forget about the original echo area message.  So when
3965     ScreenUpdate restored it, it created a discrepancy between the
3966     actual screen contents and what Emacs internal data structures
3967     know about it.
3968
3969     To avoid this conflict, we force Emacs to restore the original
3970     echo area message as we found it when we entered this function.
3971     The irony of this is that we then erase the restored message
3972     right away, so the only purpose of restoring it is so that
3973     erasing it works correctly...  */
3974  if (! NILP (saved_echo_area_message))
3975    message_with_string ("%s", saved_echo_area_message, 0);
3976  message (0);
3977  while (statecount--)
3978    xfree (state[statecount].screen_behind);
3979  IT_display_cursor (1);	/* turn cursor back on */
3980  /* Clean up any mouse events that are waiting inside Emacs event queue.
3981     These events are likely to be generated before the menu was even
3982     displayed, probably because the user pressed and released the button
3983     (which invoked the menu) too quickly.  If we don't remove these events,
3984     Emacs will process them after we return and surprise the user.  */
3985  discard_mouse_events ();
3986  mouse_clear_clicks ();
3987  if (!kbd_buffer_events_waiting (1))
3988    clear_input_pending ();
3989  /* Allow mouse events generation by dos_rawgetc.  */
3990  mouse_preempted--;
3991  return result;
3992}
3993
3994/* Dispose of a menu.  */
3995
3996void
3997XMenuDestroy (Display *foo, XMenu *menu)
3998{
3999  int i;
4000  if (menu->allocated)
4001    {
4002      for (i = 0; i < menu->count; i++)
4003	if (menu->submenu[i])
4004	  XMenuDestroy (foo, menu->submenu[i]);
4005      xfree (menu->text);
4006      xfree (menu->submenu);
4007      xfree (menu->panenumber);
4008      xfree (menu->help_text);
4009    }
4010  xfree (menu);
4011  menu_help_message = prev_menu_help_message = NULL;
4012}
4013
4014int
4015x_pixel_width (struct frame *f)
4016{
4017  return FRAME_COLS (f);
4018}
4019
4020int
4021x_pixel_height (struct frame *f)
4022{
4023  return FRAME_LINES (f);
4024}
4025#endif /* !HAVE_X_WINDOWS */
4026
4027/* ----------------------- DOS / UNIX conversion --------------------- */
4028
4029void msdos_downcase_filename (unsigned char *);
4030
4031/* Destructively turn backslashes into slashes.  */
4032
4033void
4034dostounix_filename (p)
4035     register char *p;
4036{
4037  msdos_downcase_filename (p);
4038
4039  while (*p)
4040    {
4041      if (*p == '\\')
4042	*p = '/';
4043      p++;
4044    }
4045}
4046
4047/* Destructively turn slashes into backslashes.  */
4048
4049void
4050unixtodos_filename (p)
4051     register char *p;
4052{
4053  if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4054    {
4055      *p += 'a' - 'A';
4056      p += 2;
4057    }
4058
4059  while (*p)
4060    {
4061      if (*p == '/')
4062	*p = '\\';
4063      p++;
4064    }
4065}
4066
4067/* Get the default directory for a given drive.  0=def, 1=A, 2=B, ...  */
4068
4069int
4070getdefdir (drive, dst)
4071     int drive;
4072     char *dst;
4073{
4074  char in_path[4], *p = in_path, e = errno;;
4075
4076  /* Generate "X:." (when drive is X) or "." (when drive is 0).  */
4077  if (drive != 0)
4078    {
4079      *p++ = drive + 'A' - 1;
4080      *p++ = ':';
4081    }
4082
4083  *p++ = '.';
4084  *p = '\0';
4085  errno = 0;
4086  _fixpath (in_path, dst);
4087    /* _fixpath can set errno to ENOSYS on non-LFN systems because
4088       it queries the LFN support, so ignore that error.  */
4089  if ((errno && errno != ENOSYS) || *dst == '\0')
4090    return 0;
4091
4092  msdos_downcase_filename (dst);
4093
4094  errno = e;
4095  return 1;
4096}
4097
4098char *
4099emacs_root_dir (void)
4100{
4101  static char root_dir[4];
4102
4103  sprintf (root_dir, "%c:/", 'A' + getdisk ());
4104  root_dir[0] = tolower (root_dir[0]);
4105  return root_dir;
4106}
4107
4108/* Remove all CR's that are followed by a LF.  */
4109
4110int
4111crlf_to_lf (n, buf)
4112     register int n;
4113     register unsigned char *buf;
4114{
4115  unsigned char *np = buf, *startp = buf, *endp = buf + n;
4116
4117  if (n == 0)
4118    return n;
4119  while (buf < endp - 1)
4120    {
4121      if (*buf == 0x0d)
4122	{
4123	  if (*(++buf) != 0x0a)
4124	    *np++ = 0x0d;
4125	}
4126      else
4127	*np++ = *buf++;
4128    }
4129  if (buf < endp)
4130    *np++ = *buf++;
4131  return np - startp;
4132}
4133
4134#if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4135
4136/* In DJGPP v2.0, library `write' can call `malloc', which might
4137   cause relocation of the buffer whose address we get in ADDR.
4138   Here is a version of `write' that avoids calling `malloc',
4139   to serve us until such time as the library is fixed.
4140   Actually, what we define here is called `__write', because
4141   `write' is a stub that just jmp's to `__write' (to be
4142   POSIXLY-correct with respect to the global name-space).  */
4143
4144#include <io.h>		      /* for _write */
4145#include <libc/dosio.h>       /* for __file_handle_modes[] */
4146
4147static char xbuf[64 * 1024];  /* DOS cannot write more in one chunk */
4148
4149#define XBUF_END (xbuf + sizeof (xbuf) - 1)
4150
4151int
4152__write (int handle, const void *buffer, size_t count)
4153{
4154  if (count == 0)
4155    return 0;
4156
4157  if(__file_handle_modes[handle] & O_BINARY)
4158    return _write (handle, buffer, count);
4159  else
4160    {
4161      char *xbp = xbuf;
4162      const char *bp = buffer;
4163      int total_written = 0;
4164      int nmoved = 0, ncr = 0;
4165
4166      while (count)
4167	{
4168	  /* The next test makes sure there's space for at least 2 more
4169	     characters in xbuf[], so both CR and LF can be put there.  */
4170	  if (xbp < XBUF_END)
4171	    {
4172	      if (*bp == '\n')
4173		{
4174		  ncr++;
4175		  *xbp++ = '\r';
4176		}
4177	      *xbp++ = *bp++;
4178	      nmoved++;
4179	      count--;
4180	    }
4181	  if (xbp >= XBUF_END || !count)
4182	    {
4183	      size_t to_write = nmoved + ncr;
4184	      int written = _write (handle, xbuf, to_write);
4185
4186	      if (written == -1)
4187		return -1;
4188	      else
4189		total_written += nmoved;  /* CRs aren't counted in ret value */
4190
4191	      /* If some, but not all were written (disk full?), return
4192		 an estimate of the total written bytes not counting CRs.  */
4193	      if (written < to_write)
4194		return total_written - (to_write - written) * nmoved/to_write;
4195
4196	      nmoved = 0;
4197	      ncr = 0;
4198	      xbp = xbuf;
4199	    }
4200	}
4201      return total_written;
4202    }
4203}
4204
4205/* A low-level file-renaming function which works around Windows 95 bug.
4206   This is pulled directly out of DJGPP v2.01 library sources, and only
4207   used when you compile with DJGPP v2.0.  */
4208
4209#include <io.h>
4210
4211int _rename(const char *old, const char *new)
4212{
4213  __dpmi_regs r;
4214  int olen    = strlen(old) + 1;
4215  int i;
4216  int use_lfn = _USE_LFN;
4217  char tempfile[FILENAME_MAX];
4218  const char *orig = old;
4219  int lfn_fd = -1;
4220
4221  r.x.dx = __tb_offset;
4222  r.x.di = __tb_offset + olen;
4223  r.x.ds = r.x.es = __tb_segment;
4224
4225  if (use_lfn)
4226    {
4227      /* Windows 95 bug: for some filenames, when you rename
4228	 file -> file~ (as in Emacs, to leave a backup), the
4229	 short 8+3 alias doesn't change, which effectively
4230	 makes OLD and NEW the same file.  We must rename
4231	 through a temporary file to work around this.  */
4232
4233      char *pbase = 0, *p;
4234      static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
4235      int idx = sizeof(try_char) - 1;
4236
4237      /* Generate a temporary name.  Can't use `tmpnam', since $TMPDIR
4238	 might point to another drive, which will fail the DOS call.  */
4239      strcpy(tempfile, old);
4240      for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
4241	if (*p == '/' || *p == '\\' || *p == ':')
4242	  pbase = p;
4243      if (pbase)
4244	pbase++;
4245      else
4246	pbase = tempfile;
4247      strcpy(pbase, "X$$djren$$.$$temp$$");
4248
4249      do
4250	{
4251	  if (idx <= 0)
4252	    return -1;
4253	  *pbase = try_char[--idx];
4254	} while (_chmod(tempfile, 0) != -1);
4255
4256      r.x.ax = 0x7156;
4257      _put_path2(tempfile, olen);
4258      _put_path(old);
4259      __dpmi_int(0x21, &r);
4260      if (r.x.flags & 1)
4261	{
4262	  errno = __doserr_to_errno(r.x.ax);
4263	  return -1;
4264	}
4265
4266      /* Now create a file with the original name.  This will
4267	 ensure that NEW will always have a 8+3 alias
4268	 different from that of OLD.  (Seems to be required
4269	 when NameNumericTail in the Registry is set to 0.)  */
4270      lfn_fd = _creat(old, 0);
4271
4272      olen = strlen(tempfile) + 1;
4273      old  = tempfile;
4274      r.x.di = __tb_offset + olen;
4275    }
4276
4277  for (i=0; i<2; i++)
4278    {
4279      if(use_lfn)
4280	r.x.ax = 0x7156;
4281      else
4282	r.h.ah = 0x56;
4283      _put_path2(new, olen);
4284      _put_path(old);
4285      __dpmi_int(0x21, &r);
4286      if(r.x.flags & 1)
4287	{
4288	  if (r.x.ax == 5 && i == 0) /* access denied */
4289	    remove(new);		 /* and try again */
4290	  else
4291	    {
4292	      errno = __doserr_to_errno(r.x.ax);
4293
4294	      /* Restore to original name if we renamed it to temporary.  */
4295	      if (use_lfn)
4296		{
4297		  if (lfn_fd != -1)
4298		    {
4299		      _close (lfn_fd);
4300		      remove (orig);
4301		    }
4302		  _put_path2(orig, olen);
4303		  _put_path(tempfile);
4304		  r.x.ax = 0x7156;
4305		  __dpmi_int(0x21, &r);
4306		}
4307	      return -1;
4308	    }
4309	}
4310      else
4311	break;
4312    }
4313
4314  /* Success.  Delete the file possibly created to work
4315     around the Windows 95 bug.  */
4316  if (lfn_fd != -1)
4317    return (_close (lfn_fd) == 0) ? remove (orig) : -1;
4318  return 0;
4319}
4320
4321#endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4322
4323DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
4324       0, 0, 0,
4325       doc: /* Return non-nil if long file names are supported on MSDOS.  */)
4326     ()
4327{
4328  return (_USE_LFN ? Qt : Qnil);
4329}
4330
4331/* Convert alphabetic characters in a filename to lower-case.  */
4332
4333void
4334msdos_downcase_filename (p)
4335     register unsigned char *p;
4336{
4337  /* Always lower-case drive letters a-z, even if the filesystem
4338     preserves case in filenames.
4339     This is so MSDOS filenames could be compared by string comparison
4340     functions that are case-sensitive.  Even case-preserving filesystems
4341     do not distinguish case in drive letters.  */
4342  if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
4343    {
4344      *p += 'a' - 'A';
4345      p += 2;
4346    }
4347
4348  /* Under LFN we expect to get pathnames in their true case.  */
4349  if (NILP (Fmsdos_long_file_names ()))
4350    for ( ; *p; p++)
4351      if (*p >= 'A' && *p <= 'Z')
4352	*p += 'a' - 'A';
4353}
4354
4355DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
4356       1, 1, 0,
4357       doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
4358When long filenames are supported, doesn't change FILENAME.
4359If FILENAME is not a string, returns nil.
4360The argument object is never altered--the value is a copy.  */)
4361     (filename)
4362     Lisp_Object filename;
4363{
4364  Lisp_Object tem;
4365
4366  if (! STRINGP (filename))
4367    return Qnil;
4368
4369  tem = Fcopy_sequence (filename);
4370  msdos_downcase_filename (SDATA (tem));
4371  return tem;
4372}
4373
4374/* The Emacs root directory as determined by init_environment.  */
4375
4376static char emacsroot[MAXPATHLEN];
4377
4378char *
4379rootrelativepath (rel)
4380     char *rel;
4381{
4382  static char result[MAXPATHLEN + 10];
4383
4384  strcpy (result, emacsroot);
4385  strcat (result, "/");
4386  strcat (result, rel);
4387  return result;
4388}
4389
4390/* Define a lot of environment variables if not already defined.  Don't
4391   remove anything unless you know what you're doing -- lots of code will
4392   break if one or more of these are missing.  */
4393
4394void
4395init_environment (argc, argv, skip_args)
4396     int argc;
4397     char **argv;
4398     int skip_args;
4399{
4400  char *s, *t, *root;
4401  int len, i;
4402  static const char * const tempdirs[] = {
4403    "$TMPDIR", "$TEMP", "$TMP", "c:/"
4404  };
4405  const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4406
4407  /* Make sure they have a usable $TMPDIR.  Many Emacs functions use
4408     temporary files and assume "/tmp" if $TMPDIR is unset, which
4409     will break on DOS/Windows.  Refuse to work if we cannot find
4410     a directory, not even "c:/", usable for that purpose.  */
4411  for (i = 0; i < imax ; i++)
4412    {
4413      const char *tmp = tempdirs[i];
4414      char buf[FILENAME_MAX];
4415
4416      if (*tmp == '$')
4417	{
4418	  int tmp_len;
4419
4420	  tmp = getenv (tmp + 1);
4421	  if (!tmp)
4422	    continue;
4423
4424	  /* Some lusers set TMPDIR=e:, probably because some losing
4425	     programs cannot handle multiple slashes if they use e:/.
4426	     e: fails in `access' below, so we interpret e: as e:/.  */
4427	  tmp_len = strlen(tmp);
4428	  if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4429	    {
4430	      strcpy(buf, tmp);
4431	      buf[tmp_len++] = '/', buf[tmp_len] = 0;
4432	      tmp = buf;
4433	    }
4434	}
4435
4436      /* Note that `access' can lie to us if the directory resides on a
4437	 read-only filesystem, like CD-ROM or a write-protected floppy.
4438	 The only way to be really sure is to actually create a file and
4439	 see if it succeeds.  But I think that's too much to ask.  */
4440      if (tmp && access (tmp, D_OK) == 0)
4441	{
4442	  setenv ("TMPDIR", tmp, 1);
4443	  break;
4444	}
4445    }
4446  if (i >= imax)
4447    cmd_error_internal
4448      (Fcons (Qerror,
4449	      Fcons (build_string ("no usable temporary directories found!!"),
4450		     Qnil)),
4451       "While setting TMPDIR: ");
4452
4453  /* Note the startup time, so we know not to clear the screen if we
4454     exit immediately; see IT_reset_terminal_modes.
4455     (Yes, I know `clock' returns zero the first time it's called, but
4456     I do this anyway, in case some wiseguy changes that at some point.)  */
4457  startup_time = clock ();
4458
4459  /* Find our root from argv[0].  Assuming argv[0] is, say,
4460     "c:/emacs/bin/emacs.exe" our root will be "c:/emacs".  */
4461  root = alloca (MAXPATHLEN + 20);
4462  _fixpath (argv[0], root);
4463  msdos_downcase_filename (root);
4464  len = strlen (root);
4465  while (len > 0 && root[len] != '/' && root[len] != ':')
4466    len--;
4467  root[len] = '\0';
4468  if (len > 4
4469      && (strcmp (root + len - 4, "/bin") == 0
4470	  || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4471    root[len - 4] = '\0';
4472  else
4473    strcpy (root, "c:/emacs");  /* let's be defensive */
4474  len = strlen (root);
4475  strcpy (emacsroot, root);
4476
4477  /* We default HOME to our root.  */
4478  setenv ("HOME", root, 0);
4479
4480  /* We default EMACSPATH to root + "/bin".  */
4481  strcpy (root + len, "/bin");
4482  setenv ("EMACSPATH", root, 0);
4483
4484  /* I don't expect anybody to ever use other terminals so the internal
4485     terminal is the default.  */
4486  setenv ("TERM", "internal", 0);
4487
4488#ifdef HAVE_X_WINDOWS
4489  /* Emacs expects DISPLAY to be set.  */
4490  setenv ("DISPLAY", "unix:0.0", 0);
4491#endif
4492
4493  /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4494     downcase it and mirror the backslashes.  */
4495  s = getenv ("COMSPEC");
4496  if (!s) s = "c:/command.com";
4497  t = alloca (strlen (s) + 1);
4498  strcpy (t, s);
4499  dostounix_filename (t);
4500  setenv ("SHELL", t, 0);
4501
4502  /* PATH is also downcased and backslashes mirrored.  */
4503  s = getenv ("PATH");
4504  if (!s) s = "";
4505  t = alloca (strlen (s) + 3);
4506  /* Current directory is always considered part of MsDos's path but it is
4507     not normally mentioned.  Now it is.  */
4508  strcat (strcpy (t, ".;"), s);
4509  dostounix_filename (t); /* Not a single file name, but this should work.  */
4510  setenv ("PATH", t, 1);
4511
4512  /* In some sense all dos users have root privileges, so...  */
4513  setenv ("USER", "root", 0);
4514  setenv ("NAME", getenv ("USER"), 0);
4515
4516  /* Time zone determined from country code.  To make this possible, the
4517     country code may not span more than one time zone.  In other words,
4518     in the USA, you lose.  */
4519  if (!getenv ("TZ"))
4520    switch (dos_country_code)
4521      {
4522      case 31:			/* Belgium */
4523      case 32:			/* The Netherlands */
4524      case 33:			/* France */
4525      case 34:			/* Spain */
4526      case 36:			/* Hungary */
4527      case 38:			/* Yugoslavia (or what's left of it?) */
4528      case 39:			/* Italy */
4529      case 41:			/* Switzerland */
4530      case 42:			/* Tjekia */
4531      case 45:			/* Denmark */
4532      case 46:			/* Sweden */
4533      case 47:			/* Norway */
4534      case 48:			/* Poland */
4535      case 49:			/* Germany */
4536	/* Daylight saving from last Sunday in March to last Sunday in
4537	   September, both at 2AM.  */
4538	setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4539	break;
4540      case 44:			/* United Kingdom */
4541      case 351:			/* Portugal */
4542      case 354:			/* Iceland */
4543	setenv ("TZ", "GMT+00", 0);
4544	break;
4545      case 81:			/* Japan */
4546      case 82:			/* Korea */
4547	setenv ("TZ", "JST-09", 0);
4548	break;
4549      case 90:			/* Turkey */
4550      case 358:			/* Finland */
4551	setenv ("TZ", "EET-02", 0);
4552	break;
4553      case 972:			/* Israel */
4554	/* This is an approximation.  (For exact rules, use the
4555	   `zoneinfo/israel' file which comes with DJGPP, but you need
4556	   to install it in `/usr/share/zoneinfo/' directory first.)  */
4557	setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4558	break;
4559      }
4560  tzset ();
4561}
4562
4563
4564
4565static int break_stat;	 /* BREAK check mode status.	*/
4566static int stdin_stat;	 /* stdin IOCTL status.		*/
4567
4568#if __DJGPP__ < 2
4569
4570/* These must be global.  */
4571static _go32_dpmi_seginfo ctrl_break_vector;
4572static _go32_dpmi_registers ctrl_break_regs;
4573static int ctrlbreakinstalled = 0;
4574
4575/* Interrupt level detection of Ctrl-Break.  Don't do anything fancy here!  */
4576
4577void
4578ctrl_break_func (regs)
4579     _go32_dpmi_registers *regs;
4580{
4581  Vquit_flag = Qt;
4582}
4583
4584void
4585install_ctrl_break_check ()
4586{
4587  if (!ctrlbreakinstalled)
4588    {
4589      /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4590	 was compiler with Djgpp 1.11 maintenance level 5 or later!  */
4591      ctrlbreakinstalled = 1;
4592      ctrl_break_vector.pm_offset = (int) ctrl_break_func;
4593      _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
4594						   &ctrl_break_regs);
4595      _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
4596    }
4597}
4598
4599#endif /* __DJGPP__ < 2 */
4600
4601/* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4602   control chars by DOS.   Determine the keyboard type.  */
4603
4604int
4605dos_ttraw ()
4606{
4607  union REGS inregs, outregs;
4608  static int first_time = 1;
4609
4610  break_stat = getcbrk ();
4611  setcbrk (0);
4612#if __DJGPP__ < 2
4613  install_ctrl_break_check ();
4614#endif
4615
4616  if (first_time)
4617    {
4618      inregs.h.ah = 0xc0;
4619      int86 (0x15, &inregs, &outregs);
4620      extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4621
4622      have_mouse = 0;
4623
4624      if (internal_terminal
4625#ifdef HAVE_X_WINDOWS
4626	  && inhibit_window_system
4627#endif
4628	  )
4629	{
4630	  inregs.x.ax = 0x0021;
4631	  int86 (0x33, &inregs, &outregs);
4632	  have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4633	  if (!have_mouse)
4634	    {
4635	      /* Reportedly, the above doesn't work for some mouse drivers.  There
4636		 is an additional detection method that should work, but might be
4637		 a little slower.  Use that as an alternative.  */
4638	      inregs.x.ax = 0x0000;
4639	      int86 (0x33, &inregs, &outregs);
4640	      have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4641	    }
4642
4643	  if (have_mouse)
4644	    {
4645	      have_mouse = 1;	/* enable mouse */
4646	      mouse_visible = 0;
4647	      mouse_setup_buttons (outregs.x.bx);
4648	      mouse_position_hook = &mouse_get_pos;
4649	      mouse_init ();
4650	    }
4651
4652#ifndef HAVE_X_WINDOWS
4653#if __DJGPP__ >= 2
4654	  /* Save the cursor shape used outside Emacs.  */
4655	  outside_cursor = _farpeekw (_dos_ds, 0x460);
4656#endif
4657#endif
4658	}
4659
4660      first_time = 0;
4661
4662#if __DJGPP__ >= 2
4663
4664      stdin_stat = setmode (fileno (stdin), O_BINARY);
4665      return (stdin_stat != -1);
4666    }
4667  else
4668    return (setmode (fileno (stdin), O_BINARY) != -1);
4669
4670#else /* __DJGPP__ < 2 */
4671
4672    }
4673
4674  /* I think it is wrong to overwrite `stdin_stat' every time
4675     but the first one this function is called, but I don't
4676     want to change the way it used to work in v1.x.--EZ  */
4677
4678  inregs.x.ax = 0x4400;		/* Get IOCTL status. */
4679  inregs.x.bx = 0x00;		/* 0 = stdin. */
4680  intdos (&inregs, &outregs);
4681  stdin_stat = outregs.h.dl;
4682
4683  inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
4684  inregs.x.ax = 0x4401;		/* Set IOCTL status */
4685  intdos (&inregs, &outregs);
4686  return !outregs.x.cflag;
4687
4688#endif /* __DJGPP__ < 2 */
4689}
4690
4691/*  Restore status of standard input and Ctrl-C checking.  */
4692
4693int
4694dos_ttcooked ()
4695{
4696  union REGS inregs, outregs;
4697
4698  setcbrk (break_stat);
4699  mouse_off ();
4700
4701#if __DJGPP__ >= 2
4702
4703#ifndef HAVE_X_WINDOWS
4704  /* Restore the cursor shape we found on startup.  */
4705  if (outside_cursor)
4706    {
4707      inregs.h.ah = 1;
4708      inregs.x.cx = outside_cursor;
4709      int86 (0x10, &inregs, &outregs);
4710    }
4711#endif
4712
4713  return (setmode (fileno (stdin), stdin_stat) != -1);
4714
4715#else  /* not __DJGPP__ >= 2 */
4716
4717  inregs.x.ax = 0x4401;	/* Set IOCTL status.	*/
4718  inregs.x.bx = 0x00;	/* 0 = stdin.		*/
4719  inregs.x.dx = stdin_stat;
4720  intdos (&inregs, &outregs);
4721  return !outregs.x.cflag;
4722
4723#endif /* not __DJGPP__ >= 2 */
4724}
4725
4726
4727/* Run command as specified by ARGV in directory DIR.
4728   The command is run with input from TEMPIN, output to
4729   file TEMPOUT and stderr to TEMPERR.  */
4730
4731int
4732run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4733     unsigned char **argv;
4734     const char *working_dir;
4735     int tempin, tempout, temperr;
4736     char **envv;
4737{
4738  char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4739  char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
4740  int msshell, result = -1, inbak, outbak, errbak, x, y;
4741  Lisp_Object cmd;
4742
4743  /* Get current directory as MSDOS cwd is not per-process.  */
4744  getwd (oldwd);
4745
4746  /* If argv[0] is the shell, it might come in any lettercase.
4747     Since `Fmember' is case-sensitive, we need to downcase
4748     argv[0], even if we are on case-preserving filesystems.  */
4749  lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4750  for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4751    {
4752      *pl = *pa++;
4753      if (*pl >= 'A' && *pl <= 'Z')
4754	*pl += 'a' - 'A';
4755    }
4756  *pl = '\0';
4757
4758  cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4759  msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4760    && !strcmp ("-c", argv[1]);
4761  if (msshell)
4762    {
4763      saveargv1 = argv[1];
4764      saveargv2 = argv[2];
4765      argv[1] = "/c";
4766      /* We only need to mirror slashes if a DOS shell will be invoked
4767	 not via `system' (which does the mirroring itself).  Yes, that
4768	 means DJGPP v1.x will lose here.  */
4769      if (argv[2] && argv[3])
4770	{
4771	  char *p = alloca (strlen (argv[2]) + 1);
4772
4773	  strcpy (argv[2] = p, saveargv2);
4774	  while (*p && isspace (*p))
4775	    p++;
4776	  while (*p)
4777	    {
4778	      if (*p == '/')
4779		*p++ = '\\';
4780	      else
4781		p++;
4782	    }
4783	}
4784    }
4785
4786  chdir (working_dir);
4787  inbak = dup (0);
4788  outbak = dup (1);
4789  errbak = dup (2);
4790  if (inbak < 0 || outbak < 0 || errbak < 0)
4791    goto done; /* Allocation might fail due to lack of descriptors.  */
4792
4793  if (have_mouse > 0)
4794    mouse_get_xy (&x, &y);
4795
4796  dos_ttcooked ();	/* do it here while 0 = stdin */
4797
4798  dup2 (tempin, 0);
4799  dup2 (tempout, 1);
4800  dup2 (temperr, 2);
4801
4802#if __DJGPP__ > 1
4803
4804  if (msshell && !argv[3])
4805    {
4806      /* MS-DOS native shells are too restrictive.  For starters, they
4807	 cannot grok commands longer than 126 characters.  In DJGPP v2
4808	 and later, `system' is much smarter, so we'll call it instead.  */
4809
4810      const char *cmnd;
4811
4812      /* A shell gets a single argument--its full command
4813	 line--whose original was saved in `saveargv2'.  */
4814
4815      /* Don't let them pass empty command lines to `system', since
4816	 with some shells it will try to invoke an interactive shell,
4817	 which will hang Emacs.  */
4818      for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4819	;
4820      if (*cmnd)
4821	{
4822	  extern char **environ;
4823	  char **save_env = environ;
4824	  int save_system_flags = __system_flags;
4825
4826	  /* Request the most powerful version of `system'.  We need
4827	     all the help we can get to avoid calling stock DOS shells.  */
4828	  __system_flags =  (__system_redirect
4829			     | __system_use_shell
4830			     | __system_allow_multiple_cmds
4831			     | __system_allow_long_cmds
4832			     | __system_handle_null_commands
4833			     | __system_emulate_chdir);
4834
4835	  environ = envv;
4836	  result = system (cmnd);
4837	  __system_flags = save_system_flags;
4838	  environ = save_env;
4839	}
4840      else
4841	result = 0;	/* emulate Unixy shell behavior with empty cmd line */
4842    }
4843  else
4844
4845#endif /* __DJGPP__ > 1 */
4846
4847  result = spawnve (P_WAIT, argv[0], argv, envv);
4848
4849  dup2 (inbak, 0);
4850  dup2 (outbak, 1);
4851  dup2 (errbak, 2);
4852  emacs_close (inbak);
4853  emacs_close (outbak);
4854  emacs_close (errbak);
4855
4856  dos_ttraw ();
4857  if (have_mouse > 0)
4858    {
4859      mouse_init ();
4860      mouse_moveto (x, y);
4861    }
4862
4863  /* Some programs might change the meaning of the highest bit of the
4864     text attribute byte, so we get blinking characters instead of the
4865     bright background colors.  Restore that.  */
4866  bright_bg ();
4867
4868 done:
4869  chdir (oldwd);
4870  if (msshell)
4871    {
4872      argv[1] = saveargv1;
4873      argv[2] = saveargv2;
4874    }
4875  return result;
4876}
4877
4878void
4879croak (badfunc)
4880     char *badfunc;
4881{
4882  fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4883  reset_sys_modes ();
4884  exit (1);
4885}
4886
4887#if __DJGPP__ < 2
4888
4889/* ------------------------- Compatibility functions -------------------
4890 *	gethostname
4891 *	gettimeofday
4892 */
4893
4894/* Hostnames for a pc are not really funny,
4895   but they are used in change log so we emulate the best we can.  */
4896
4897gethostname (p, size)
4898     char *p;
4899     int size;
4900{
4901  char *q = egetenv ("HOSTNAME");
4902
4903  if (!q) q = "pc";
4904  strcpy (p, q);
4905  return 0;
4906}
4907
4908/* When time zones are set from Ms-Dos too many C-libraries are playing
4909   tricks with time values.  We solve this by defining our own version
4910   of `gettimeofday' bypassing GO32.  Our version needs to be initialized
4911   once and after each call to `tzset' with TZ changed.  That is
4912   accomplished by aliasing tzset to init_gettimeofday. */
4913
4914static struct tm time_rec;
4915
4916int
4917gettimeofday (struct timeval *tp, struct timezone *tzp)
4918{
4919  if (tp)
4920    {
4921      struct time t;
4922      struct tm tm;
4923
4924      gettime (&t);
4925      if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
4926	{
4927	  struct date d;
4928	  getdate (&d);
4929	  time_rec.tm_year = d.da_year - 1900;
4930	  time_rec.tm_mon = d.da_mon - 1;
4931	  time_rec.tm_mday = d.da_day;
4932	}
4933
4934      time_rec.tm_hour = t.ti_hour;
4935      time_rec.tm_min = t.ti_min;
4936      time_rec.tm_sec = t.ti_sec;
4937
4938      tm = time_rec;
4939      tm.tm_gmtoff = dos_timezone_offset;
4940
4941      tp->tv_sec = mktime (&tm);	/* may modify tm */
4942      tp->tv_usec = t.ti_hund * (1000000 / 100);
4943    }
4944  /* Ignore tzp; it's obsolescent.  */
4945  return 0;
4946}
4947
4948#endif /* __DJGPP__ < 2 */
4949
4950/*
4951 * A list of unimplemented functions that we silently ignore.
4952 */
4953
4954#if __DJGPP__ < 2
4955unsigned alarm (s) unsigned s; {}
4956fork () { return 0; }
4957int kill (x, y) int x, y; { return -1; }
4958nice (p) int p; {}
4959void volatile pause () {}
4960sigsetmask (x) int x; { return 0; }
4961sigblock (mask) int mask; { return 0; }
4962#endif
4963
4964void request_sigio (void) {}
4965setpgrp () {return 0; }
4966setpriority (x,y,z) int x,y,z; { return 0; }
4967void unrequest_sigio (void) {}
4968
4969#if __DJGPP__ > 1
4970#if __DJGPP_MINOR__ < 2
4971
4972#ifdef POSIX_SIGNALS
4973
4974/* Augment DJGPP library POSIX signal functions.  This is needed
4975   as of DJGPP v2.01, but might be in the library in later releases. */
4976
4977#include <libc/bss.h>
4978
4979/* A counter to know when to re-initialize the static sets.  */
4980static int sigprocmask_count = -1;
4981
4982/* Which signals are currently blocked (initially none).  */
4983static sigset_t current_mask;
4984
4985/* Which signals are pending (initially none).  */
4986static sigset_t pending_signals;
4987
4988/* Previous handlers to restore when the blocked signals are unblocked.  */
4989typedef void (*sighandler_t)(int);
4990static sighandler_t prev_handlers[320];
4991
4992/* A signal handler which just records that a signal occurred
4993   (it will be raised later, if and when the signal is unblocked).  */
4994static void
4995sig_suspender (signo)
4996     int signo;
4997{
4998  sigaddset (&pending_signals, signo);
4999}
5000
5001int
5002sigprocmask (how, new_set, old_set)
5003     int how;
5004     const sigset_t *new_set;
5005     sigset_t *old_set;
5006{
5007  int signo;
5008  sigset_t new_mask;
5009
5010  /* If called for the first time, initialize.  */
5011  if (sigprocmask_count != __bss_count)
5012    {
5013      sigprocmask_count = __bss_count;
5014      sigemptyset (&pending_signals);
5015      sigemptyset (&current_mask);
5016      for (signo = 0; signo < 320; signo++)
5017	prev_handlers[signo] = SIG_ERR;
5018    }
5019
5020  if (old_set)
5021    *old_set = current_mask;
5022
5023  if (new_set == 0)
5024    return 0;
5025
5026  if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
5027    {
5028      errno = EINVAL;
5029      return -1;
5030    }
5031
5032  sigemptyset (&new_mask);
5033
5034  /* DJGPP supports upto 320 signals.  */
5035  for (signo = 0; signo < 320; signo++)
5036    {
5037      if (sigismember (&current_mask, signo))
5038	sigaddset (&new_mask, signo);
5039      else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
5040	{
5041	  sigaddset (&new_mask, signo);
5042
5043	  /* SIGKILL is silently ignored, as on other platforms.  */
5044	  if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
5045	    prev_handlers[signo] = signal (signo, sig_suspender);
5046	}
5047      if ((   how == SIG_UNBLOCK
5048	      && sigismember (&new_mask, signo)
5049	      && sigismember (new_set, signo))
5050	  || (how == SIG_SETMASK
5051	      && sigismember (&new_mask, signo)
5052	      && !sigismember (new_set, signo)))
5053	{
5054	  sigdelset (&new_mask, signo);
5055	  if (prev_handlers[signo] != SIG_ERR)
5056	    {
5057	      signal (signo, prev_handlers[signo]);
5058	      prev_handlers[signo] = SIG_ERR;
5059	    }
5060	  if (sigismember (&pending_signals, signo))
5061	    {
5062	      sigdelset (&pending_signals, signo);
5063	      raise (signo);
5064	    }
5065	}
5066    }
5067  current_mask = new_mask;
5068  return 0;
5069}
5070
5071#else /* not POSIX_SIGNALS */
5072
5073sigsetmask (x) int x; { return 0; }
5074sigblock (mask) int mask; { return 0; }
5075
5076#endif /* not POSIX_SIGNALS */
5077#endif /* not __DJGPP_MINOR__ < 2 */
5078#endif /* __DJGPP__ > 1 */
5079
5080#ifndef HAVE_SELECT
5081#include "sysselect.h"
5082
5083#ifndef EMACS_TIME_ZERO_OR_NEG_P
5084#define EMACS_TIME_ZERO_OR_NEG_P(time)	\
5085  ((long)(time).tv_sec < 0		\
5086   || ((time).tv_sec == 0		\
5087       && (long)(time).tv_usec <= 0))
5088#endif
5089
5090/* This yields the rest of the current time slice to the task manager.
5091   It should be called by any code which knows that it has nothing
5092   useful to do except idle.
5093
5094   I don't use __dpmi_yield here, since versions of library before 2.02
5095   called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5096   on some versions of Windows 9X.  */
5097
5098void
5099dos_yield_time_slice (void)
5100{
5101  _go32_dpmi_registers r;
5102
5103  r.x.ax = 0x1680;
5104  r.x.ss = r.x.sp = r.x.flags = 0;
5105  _go32_dpmi_simulate_int (0x2f, &r);
5106  if (r.h.al == 0x80)
5107    errno = ENOSYS;
5108}
5109
5110/* Only event queue is checked.  */
5111/* We don't have to call timer_check here
5112   because wait_reading_process_output takes care of that.  */
5113int
5114sys_select (nfds, rfds, wfds, efds, timeout)
5115     int nfds;
5116     SELECT_TYPE *rfds, *wfds, *efds;
5117     EMACS_TIME *timeout;
5118{
5119  int check_input;
5120  struct time t;
5121
5122  check_input = 0;
5123  if (rfds)
5124    {
5125      check_input = FD_ISSET (0, rfds);
5126      FD_ZERO (rfds);
5127    }
5128  if (wfds)
5129    FD_ZERO (wfds);
5130  if (efds)
5131    FD_ZERO (efds);
5132
5133  if (nfds != 1)
5134    abort ();
5135
5136  /* If we are looking only for the terminal, with no timeout,
5137     just read it and wait -- that's more efficient.  */
5138  if (!timeout)
5139    {
5140      while (!detect_input_pending ())
5141	{
5142	  dos_yield_time_slice ();
5143	}
5144    }
5145  else
5146    {
5147      EMACS_TIME clnow, cllast, cldiff;
5148
5149      gettime (&t);
5150      EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
5151
5152      while (!check_input || !detect_input_pending ())
5153	{
5154	  gettime (&t);
5155	  EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
5156	  EMACS_SUB_TIME (cldiff, clnow, cllast);
5157
5158	  /* When seconds wrap around, we assume that no more than
5159	     1 minute passed since last `gettime'.  */
5160	  if (EMACS_TIME_NEG_P (cldiff))
5161	    EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
5162	  EMACS_SUB_TIME (*timeout, *timeout, cldiff);
5163
5164	  /* Stop when timeout value crosses zero.  */
5165	  if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
5166	    return 0;
5167	  cllast = clnow;
5168	  dos_yield_time_slice ();
5169	}
5170    }
5171
5172  FD_SET (0, rfds);
5173  return 1;
5174}
5175#endif
5176
5177/*
5178 * Define overlaid functions:
5179 *
5180 *	chdir -> sys_chdir
5181 *	tzset -> init_gettimeofday
5182 *	abort -> dos_abort
5183 */
5184
5185#ifdef chdir
5186#undef chdir
5187extern int chdir ();
5188
5189int
5190sys_chdir (path)
5191     const char* path;
5192{
5193  int len = strlen (path);
5194  char *tmp = (char *)path;
5195
5196  if (*tmp && tmp[1] == ':')
5197    {
5198      if (getdisk () != tolower (tmp[0]) - 'a')
5199	setdisk (tolower (tmp[0]) - 'a');
5200      tmp += 2;	/* strip drive: KFS 1995-07-06 */
5201      len -= 2;
5202    }
5203
5204  if (len > 1 && (tmp[len - 1] == '/'))
5205    {
5206      char *tmp1 = (char *) alloca (len + 1);
5207      strcpy (tmp1, tmp);
5208      tmp1[len - 1] = 0;
5209      tmp = tmp1;
5210    }
5211  return chdir (tmp);
5212}
5213#endif
5214
5215#ifdef tzset
5216#undef tzset
5217extern void tzset (void);
5218
5219void
5220init_gettimeofday ()
5221{
5222  time_t ltm, gtm;
5223  struct tm *lstm;
5224
5225  tzset ();
5226  ltm = gtm = time (NULL);
5227  ltm = mktime (lstm = localtime (&ltm));
5228  gtm = mktime (gmtime (&gtm));
5229  time_rec.tm_hour = 99;	/* force gettimeofday to get date */
5230  time_rec.tm_isdst = lstm->tm_isdst;
5231  dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
5232}
5233#endif
5234
5235#ifdef abort
5236#undef abort
5237void
5238dos_abort (file, line)
5239     char *file;
5240     int  line;
5241{
5242  char buffer1[200], buffer2[400];
5243  int i, j;
5244
5245  sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
5246  for (i = j = 0; buffer1[i]; i++) {
5247    buffer2[j++] = buffer1[i];
5248    buffer2[j++] = 0x70;
5249  }
5250  dosmemput (buffer2, j, (int)ScreenPrimary);
5251  ScreenSetCursor (2, 0);
5252  abort ();
5253}
5254#else
5255void
5256abort ()
5257{
5258  dos_ttcooked ();
5259  ScreenSetCursor (10, 0);
5260  cputs ("\r\n\nEmacs aborted!\r\n");
5261#if __DJGPP__ > 1
5262#if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5263  if (screen_virtual_segment)
5264    dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
5265  /* Generate traceback, so we could tell whodunit.  */
5266  signal (SIGINT, SIG_DFL);
5267  __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5268#else  /* __DJGPP_MINOR__ >= 2 */
5269  raise (SIGABRT);
5270#endif /* __DJGPP_MINOR__ >= 2 */
5271#endif
5272  exit (2);
5273}
5274#endif
5275
5276/* The following variables are required so that cus-start.el won't
5277   complain about unbound variables.  */
5278#ifndef subprocesses
5279/* Nonzero means delete a process right away if it exits (process.c).  */
5280static int delete_exited_processes;
5281#endif
5282
5283syms_of_msdos ()
5284{
5285  recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
5286  staticpro (&recent_doskeys);
5287
5288#ifndef HAVE_X_WINDOWS
5289
5290  /* The following two are from xfns.c:  */
5291  Qreverse = intern ("reverse");
5292  staticpro (&Qreverse);
5293
5294  DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
5295	       doc: /* *Glyph to display instead of chars not supported by current codepage.
5296This variable is used only by MSDOS terminals.  */);
5297  Vdos_unsupported_char_glyph = make_number ('\177');
5298
5299#endif
5300#ifndef subprocesses
5301  DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
5302	       doc: /* *Non-nil means delete processes immediately when they exit.
5303A value of nil means don't delete them until `list-processes' is run.  */);
5304  delete_exited_processes = 0;
5305#endif
5306
5307  defsubr (&Srecent_doskeys);
5308  defsubr (&Smsdos_long_file_names);
5309  defsubr (&Smsdos_downcase_filename);
5310  defsubr (&Smsdos_remember_default_colors);
5311  defsubr (&Smsdos_set_mouse_buttons);
5312}
5313
5314#endif /* MSDOS */
5315
5316/* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5317   (do not change this comment) */
5318