(NUM_MOUSE_BUTTONS): Define.
[bpt/emacs.git] / src / msdos.c
CommitLineData
c6a6499f 1/* MS-DOS specific C utilities. -*- coding: raw-text -*-
68c45bf0 2 Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
1b94449f
RS
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
edfc0d45 8the Free Software Foundation; either version 2, or (at your option)
1b94449f
RS
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
1b94449f 20
9da6e765 21/* Contributed by Morten Welinder */
f32d4091 22/* New display, keyboard, and mouse control by Kim F. Storm */
9da6e765 23
1b94449f
RS
24/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
25
48984716 26#include <config.h>
1b94449f
RS
27
28#ifdef MSDOS
29#include "lisp.h"
30#include <stdio.h>
31#include <stdlib.h>
06b1ea13 32#include <time.h>
1b94449f
RS
33#include <sys/param.h>
34#include <sys/time.h>
35#include <dos.h>
d21e67b5 36#include <errno.h>
a7cf9151 37#include <string.h> /* for bzero and string functions */
d21e67b5 38#include <sys/stat.h> /* for _fixpath */
a7cf9151 39#include <unistd.h> /* for chdir, dup, dup2, etc. */
1bd7b2c7
RS
40#if __DJGPP__ >= 2
41#include <fcntl.h>
a7cf9151 42#include <io.h> /* for setmode */
fc171623
KH
43#include <dpmi.h> /* for __dpmi_xxx stuff */
44#include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
d21e67b5 45#include <libc/dosio.h> /* for _USE_LFN */
a7cf9151 46#include <conio.h> /* for cputs */
1bd7b2c7
RS
47#endif
48
1b94449f
RS
49#include "msdos.h"
50#include "systime.h"
51#include "termhooks.h"
aa9ce936 52#include "termchar.h"
87485d6f 53#include "dispextern.h"
c77f6f1b 54#include "dosfns.h"
87485d6f 55#include "termopts.h"
aa9ce936
EZ
56#include "charset.h"
57#include "coding.h"
58#include "disptab.h"
1b94449f 59#include "frame.h"
87485d6f 60#include "window.h"
fc171623
KH
61#include "buffer.h"
62#include "commands.h"
41ad069b 63#include "blockinput.h"
1b94449f
RS
64#include <go32.h>
65#include <pc.h>
66#include <ctype.h>
67/* #include <process.h> */
68/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
69#define P_WAIT 1
70
d21e67b5
RS
71#ifndef _USE_LFN
72#define _USE_LFN 0
73#endif
74
b36701cc
RS
75#ifndef _dos_ds
76#define _dos_ds _go32_info_block.selector_for_linear_memory
77#endif
78
1bd7b2c7
RS
79#if __DJGPP__ > 1
80
8748735b 81#include <signal.h>
417a04bb 82#include "syssignal.h"
8748735b 83
1bd7b2c7
RS
84#ifndef SYSTEM_MALLOC
85
86#ifdef GNU_MALLOC
87
88/* If other `malloc' than ours is used, force our `sbrk' behave like
89 Unix programs expect (resize memory blocks to keep them contiguous).
90 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
91 because that's what `gmalloc' expects to get. */
92#include <crt0.h>
93
94#ifdef REL_ALLOC
95int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
96#else /* not REL_ALLOC */
97int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
98#endif /* not REL_ALLOC */
99#endif /* GNU_MALLOC */
100
101#endif /* not SYSTEM_MALLOC */
102#endif /* __DJGPP__ > 1 */
aee81730
RS
103
104static unsigned long
105event_timestamp ()
106{
107 struct time t;
108 unsigned long s;
f32d4091 109
aee81730
RS
110 gettime (&t);
111 s = t.ti_min;
112 s *= 60;
113 s += t.ti_sec;
114 s *= 1000;
115 s += t.ti_hund * 10;
f32d4091 116
aee81730
RS
117 return s;
118}
119
f32d4091
KS
120\f
121/* ------------------------ Mouse control ---------------------------
122 *
123 * Coordinates are in screen positions and zero based.
124 * Mouse buttons are numbered from left to right and also zero based.
125 */
1b94449f 126
0c3cfc51
EZ
127/* This used to be in termhooks.h, but mainstream Emacs code no longer
128 uses it, and it was removed... */
129#define NUM_MOUSE_BUTTONS (5)
130
f32d4091
KS
131int have_mouse; /* 0: no, 1: enabled, -1: disabled */
132static int mouse_visible;
1b94449f 133
f32d4091
KS
134static int mouse_last_x;
135static int mouse_last_y;
1b94449f 136
f32d4091
KS
137static int mouse_button_translate[NUM_MOUSE_BUTTONS];
138static int mouse_button_count;
1b94449f 139
f32d4091
KS
140void
141mouse_on ()
1b94449f 142{
1b94449f 143 union REGS regs;
1b94449f 144
f32d4091 145 if (have_mouse > 0 && !mouse_visible)
1b94449f 146 {
f32d4091
KS
147 if (termscript)
148 fprintf (termscript, "<M_ON>");
149 regs.x.ax = 0x0001;
150 int86 (0x33, &regs, &regs);
151 mouse_visible = 1;
1b94449f 152 }
1b94449f
RS
153}
154
f32d4091
KS
155void
156mouse_off ()
1b94449f 157{
f32d4091 158 union REGS regs;
1b94449f 159
f32d4091 160 if (have_mouse > 0 && mouse_visible)
1b94449f 161 {
f32d4091
KS
162 if (termscript)
163 fprintf (termscript, "<M_OFF>");
164 regs.x.ax = 0x0002;
165 int86 (0x33, &regs, &regs);
166 mouse_visible = 0;
1b94449f 167 }
1b94449f
RS
168}
169
211c7152
EZ
170static void
171mouse_get_xy (int *x, int *y)
172{
173 union REGS regs;
174
175 regs.x.ax = 0x0003;
176 int86 (0x33, &regs, &regs);
177 *x = regs.x.cx / 8;
178 *y = regs.x.dx / 8;
179}
180
f32d4091
KS
181void
182mouse_moveto (x, y)
183 int x, y;
1b94449f 184{
f32d4091 185 union REGS regs;
1b94449f 186
f32d4091
KS
187 if (termscript)
188 fprintf (termscript, "<M_XY=%dx%d>", x, y);
189 regs.x.ax = 0x0004;
190 mouse_last_x = regs.x.cx = x * 8;
191 mouse_last_y = regs.x.dx = y * 8;
192 int86 (0x33, &regs, &regs);
1b94449f
RS
193}
194
f32d4091
KS
195static int
196mouse_pressed (b, xp, yp)
197 int b, *xp, *yp;
1b94449f 198{
f32d4091 199 union REGS regs;
1b94449f 200
f32d4091
KS
201 if (b >= mouse_button_count)
202 return 0;
203 regs.x.ax = 0x0005;
204 regs.x.bx = mouse_button_translate[b];
205 int86 (0x33, &regs, &regs);
206 if (regs.x.bx)
207 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
208 return (regs.x.bx != 0);
1b94449f
RS
209}
210
f32d4091
KS
211static int
212mouse_released (b, xp, yp)
213 int b, *xp, *yp;
1b94449f
RS
214{
215 union REGS regs;
216
f32d4091
KS
217 if (b >= mouse_button_count)
218 return 0;
219 regs.x.ax = 0x0006;
220 regs.x.bx = mouse_button_translate[b];
221 int86 (0x33, &regs, &regs);
222 if (regs.x.bx)
223 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
224 return (regs.x.bx != 0);
1b94449f
RS
225}
226
0c7bc1aa
EZ
227static int
228mouse_button_depressed (b, xp, yp)
229 int b, *xp, *yp;
230{
231 union REGS regs;
232
233 if (b >= mouse_button_count)
234 return 0;
235 regs.x.ax = 0x0003;
236 int86 (0x33, &regs, &regs);
237 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
238 {
239 *xp = regs.x.cx / 8;
240 *yp = regs.x.dx / 8;
241 return 1;
242 }
243 return 0;
244}
245
f32d4091
KS
246void
247mouse_get_pos (f, insist, bar_window, part, x, y, time)
248 FRAME_PTR *f;
249 int insist;
250 Lisp_Object *bar_window, *x, *y;
251 enum scroll_bar_part *part;
252 unsigned long *time;
253{
254 int ix, iy;
211c7152
EZ
255 Lisp_Object frame, tail;
256
257 /* Clear the mouse-moved flag for every frame on this display. */
258 FOR_EACH_FRAME (tail, frame)
259 XFRAME (frame)->mouse_moved = 0;
f32d4091 260
2d764c78 261 *f = SELECTED_FRAME();
f32d4091
KS
262 *bar_window = Qnil;
263 mouse_get_xy (&ix, &iy);
f32d4091 264 *time = event_timestamp ();
211c7152
EZ
265 *x = make_number (mouse_last_x = ix);
266 *y = make_number (mouse_last_y = iy);
f32d4091 267}
1b94449f 268
f32d4091
KS
269static void
270mouse_check_moved ()
1b94449f 271{
aee81730 272 int x, y;
1b94449f 273
f32d4091 274 mouse_get_xy (&x, &y);
2d764c78 275 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
f32d4091
KS
276 mouse_last_x = x;
277 mouse_last_y = y;
278}
1b94449f 279
f32d4091
KS
280void
281mouse_init ()
282{
283 union REGS regs;
0c7bc1aa 284 int b;
647c32eb 285
f32d4091
KS
286 if (termscript)
287 fprintf (termscript, "<M_INIT>");
1b94449f 288
f32d4091
KS
289 regs.x.ax = 0x0021;
290 int86 (0x33, &regs, &regs);
091d0bdf 291
0c7bc1aa
EZ
292 /* Reset the mouse last press/release info. It seems that Windows
293 doesn't do that automatically when function 21h is called, which
294 causes Emacs to ``remember'' the click that switched focus to the
295 window just before Emacs was started from that window. */
296 for (b = 0; b < mouse_button_count; b++)
297 {
298 int dummy_x, dummy_y;
299
300 (void) mouse_pressed (b, &dummy_x, &dummy_y);
301 (void) mouse_released (b, &dummy_x, &dummy_y);
302 }
303
f32d4091
KS
304 regs.x.ax = 0x0007;
305 regs.x.cx = 0;
306 regs.x.dx = 8 * (ScreenCols () - 1);
307 int86 (0x33, &regs, &regs);
1b94449f 308
f32d4091
KS
309 regs.x.ax = 0x0008;
310 regs.x.cx = 0;
311 regs.x.dx = 8 * (ScreenRows () - 1);
312 int86 (0x33, &regs, &regs);
1b94449f 313
f32d4091
KS
314 mouse_moveto (0, 0);
315 mouse_visible = 0;
316}
3eb1dbb6 317\f
f32d4091
KS
318/* ------------------------- Screen control ----------------------
319 *
320 */
aee81730 321
f32d4091 322static int internal_terminal = 0;
aee81730 323
f32d4091
KS
324#ifndef HAVE_X_WINDOWS
325extern unsigned char ScreenAttrib;
326static int screen_face;
327static int highlight;
aee81730 328
f32d4091
KS
329static int screen_size_X;
330static int screen_size_Y;
331static int screen_size;
1b94449f 332
f32d4091
KS
333static int current_pos_X;
334static int current_pos_Y;
335static int new_pos_X;
336static int new_pos_Y;
1b94449f 337
f32d4091
KS
338static void *startup_screen_buffer;
339static int startup_screen_size_X;
340static int startup_screen_size_Y;
341static int startup_pos_X;
342static int startup_pos_Y;
c9adab25 343static unsigned char startup_screen_attrib;
1b94449f 344
06b1ea13
EZ
345static clock_t startup_time;
346
f32d4091 347static int term_setup_done;
1b94449f 348
8ba01a32
EZ
349static unsigned short outside_cursor;
350
f32d4091 351/* Similar to the_only_frame. */
f6816f88 352struct x_output the_only_x_display;
1b94449f 353
039274cf
EZ
354/* Support for DOS/V (allows Japanese characters to be displayed on
355 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
356
357/* Holds the address of the text-mode screen buffer. */
358static unsigned long screen_old_address = 0;
359/* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
360static unsigned short screen_virtual_segment = 0;
361static unsigned short screen_virtual_offset = 0;
68026917
AI
362/* A flag to control how to display unibyte 8-bit characters. */
363extern int unibyte_display_via_language_environment;
039274cf 364
8ba01a32
EZ
365Lisp_Object Qbar;
366
039274cf
EZ
367#if __DJGPP__ > 1
368/* Update the screen from a part of relocated DOS/V screen buffer which
369 begins at OFFSET and includes COUNT characters. */
370static void
371dosv_refresh_virtual_screen (int offset, int count)
372{
373 __dpmi_regs regs;
374
40437cf5
EZ
375 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
376 return;
377
039274cf
EZ
378 regs.h.ah = 0xff; /* update relocated screen */
379 regs.x.es = screen_virtual_segment;
380 regs.x.di = screen_virtual_offset + offset;
381 regs.x.cx = count;
382 __dpmi_int (0x10, &regs);
383}
384#endif
385
d1d5dc19 386static void
f32d4091
KS
387dos_direct_output (y, x, buf, len)
388 int y;
389 int x;
390 char *buf;
391 int len;
1b94449f 392{
40437cf5
EZ
393 int t0 = 2 * (x + y * screen_size_X);
394 int t = t0 + (int) ScreenPrimary;
039274cf 395 int l0 = len;
fc171623
KH
396
397#if (__DJGPP__ < 2)
f32d4091
KS
398 while (--len >= 0) {
399 dosmemput (buf++, 1, t);
400 t += 2;
401 }
fc171623
KH
402#else
403 /* This is faster. */
404 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
405 _farnspokeb (t, *buf);
039274cf
EZ
406
407 if (screen_virtual_segment)
408 dosv_refresh_virtual_screen (t0, l0);
fc171623 409#endif
1b94449f 410}
aee81730 411#endif
1b94449f 412
1b94449f
RS
413/* Flash the screen as a substitute for BEEPs. */
414
f32d4091 415#if (__DJGPP__ < 2)
49a09c76 416static void
fcea9cd4 417do_visible_bell (xorattr)
1b94449f
RS
418 unsigned char xorattr;
419{
49a09c76 420 asm volatile
ca986694 421 (" movb $1,%%dl
1b94449f 422visible_bell_0:
ca986694 423 movl _ScreenPrimary,%%eax
49a09c76 424 call dosmemsetup
ca986694
RS
425 movl %%eax,%%ebx
426 movl %1,%%ecx
427 movb %0,%%al
428 incl %%ebx
1b94449f 429visible_bell_1:
ca986694
RS
430 xorb %%al,%%gs:(%%ebx)
431 addl $2,%%ebx
432 decl %%ecx
49a09c76 433 jne visible_bell_1
ca986694 434 decb %%dl
49a09c76 435 jne visible_bell_3
1b94449f 436visible_bell_2:
ca986694
RS
437 movzwl %%ax,%%eax
438 movzwl %%ax,%%eax
439 movzwl %%ax,%%eax
440 movzwl %%ax,%%eax
441 decw %%cx
49a09c76
RS
442 jne visible_bell_2
443 jmp visible_bell_0
ca986694
RS
444visible_bell_3:"
445 : /* no output */
f32d4091 446 : "m" (xorattr), "g" (screen_size)
ca986694 447 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
448}
449
f32d4091
KS
450static void
451ScreenVisualBell (void)
452{
453 /* This creates an xor-mask that will swap the default fore- and
454 background colors. */
455 do_visible_bell (((the_only_x_display.foreground_pixel
456 ^ the_only_x_display.background_pixel)
457 * 0x11) & 0x7f);
458}
459#endif
460
461#ifndef HAVE_X_WINDOWS
462
b36701cc
RS
463static int blink_bit = -1; /* the state of the blink bit at startup */
464
76ac1508
RS
465/* Enable bright background colors. */
466static void
467bright_bg (void)
468{
469 union REGS regs;
470
b36701cc
RS
471 /* Remember the original state of the blink/bright-background bit.
472 It is stored at 0040:0065h in the BIOS data area. */
473 if (blink_bit == -1)
474 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
475
76ac1508
RS
476 regs.h.bl = 0;
477 regs.x.ax = 0x1003;
478 int86 (0x10, &regs, &regs);
479}
480
b36701cc
RS
481/* Disable bright background colors (and enable blinking) if we found
482 the video system in that state at startup. */
483static void
484maybe_enable_blinking (void)
485{
486 if (blink_bit == 1)
487 {
488 union REGS regs;
489
490 regs.h.bl = 1;
491 regs.x.ax = 0x1003;
492 int86 (0x10, &regs, &regs);
493 }
494}
495
8ba01a32
EZ
496/* Return non-zero if the system has a VGA adapter. */
497static int
498vga_installed (void)
499{
500 union REGS regs;
501
502 regs.x.ax = 0x1a00;
503 int86 (0x10, &regs, &regs);
504 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
505 return 1;
506 return 0;
507}
508
4a96d4d2
KH
509/* Set the screen dimensions so that it can show no less than
510 ROWS x COLS frame. */
48ffe371 511
4a96d4d2
KH
512void
513dos_set_window_size (rows, cols)
514 int *rows, *cols;
515{
516 char video_name[30];
517 Lisp_Object video_mode;
518 int video_mode_value;
519 int have_vga = 0;
520 union REGS regs;
521 int current_rows = ScreenRows (), current_cols = ScreenCols ();
522
523 if (*rows == current_rows && *cols == current_cols)
524 return;
525
4a96d4d2 526 mouse_off ();
8ba01a32 527 have_vga = vga_installed ();
4a96d4d2 528
48ffe371 529 /* If the user specified a special video mode for these dimensions,
4a96d4d2
KH
530 use that mode. */
531 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
532 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
533 Qnil))-> value;
534
535 if (INTEGERP (video_mode)
536 && (video_mode_value = XINT (video_mode)) > 0)
537 {
538 regs.x.ax = video_mode_value;
539 int86 (0x10, &regs, &regs);
48ffe371
RS
540
541 if (have_mouse)
542 {
543 /* Must hardware-reset the mouse, or else it won't update
544 its notion of screen dimensions for some non-standard
545 video modes. This is *painfully* slow... */
546 regs.x.ax = 0;
547 int86 (0x33, &regs, &regs);
548 }
4a96d4d2
KH
549 }
550
551 /* Find one of the dimensions supported by standard EGA/VGA
552 which gives us at least the required dimensions. */
553
554#if __DJGPP__ > 1
555
556 else
557 {
558 static struct {
559 int rows;
560 int need_vga;
561 } std_dimension[] = {
562 {25, 0},
563 {28, 1},
564 {35, 0},
565 {40, 1},
566 {43, 0},
567 {50, 1}
568 };
569 int i = 0;
570
571 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
572 {
573 if (std_dimension[i].need_vga <= have_vga
574 && std_dimension[i].rows >= *rows)
575 {
576 if (std_dimension[i].rows != current_rows
577 || *cols != current_cols)
48ffe371 578 _set_screen_lines (std_dimension[i].rows);
4a96d4d2
KH
579 break;
580 }
48ffe371 581 i++;
4a96d4d2
KH
582 }
583 }
584
585#else /* not __DJGPP__ > 1 */
586
587 else if (*rows <= 25)
588 {
589 if (current_rows != 25 || current_cols != 80)
590 {
591 regs.x.ax = 3;
592 int86 (0x10, &regs, &regs);
593 regs.x.ax = 0x1101;
594 regs.h.bl = 0;
595 int86 (0x10, &regs, &regs);
596 regs.x.ax = 0x1200;
597 regs.h.bl = 32;
598 int86 (0x10, &regs, &regs);
599 regs.x.ax = 3;
600 int86 (0x10, &regs, &regs);
601 }
602 }
603 else if (*rows <= 50)
604 if (have_vga && (current_rows != 50 || current_cols != 80)
605 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
606 {
607 regs.x.ax = 3;
608 int86 (0x10, &regs, &regs);
609 regs.x.ax = 0x1112;
610 regs.h.bl = 0;
611 int86 (0x10, &regs, &regs);
612 regs.x.ax = 0x1200;
613 regs.h.bl = 32;
614 int86 (0x10, &regs, &regs);
615 regs.x.ax = 0x0100;
616 regs.x.cx = 7;
617 int86 (0x10, &regs, &regs);
618 }
619#endif /* not __DJGPP__ > 1 */
620
621 if (have_mouse)
622 {
4a96d4d2
KH
623 mouse_init ();
624 mouse_on ();
625 }
626
627 /* Tell the caller what dimensions have been REALLY set. */
628 *rows = ScreenRows ();
629 *cols = ScreenCols ();
76ac1508 630
41ad069b
EZ
631#if __DJGPP__ > 1
632 /* If the dimensions changed, the mouse highlight info is invalid. */
633 if (current_rows != *rows || current_cols != *cols)
634 {
635 struct frame *f = SELECTED_FRAME();
636 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
637 Lisp_Object window = dpyinfo->mouse_face_window;
638
639 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
640 {
641 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
642 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
643 dpyinfo->mouse_face_window = Qnil;
644 }
645 }
646#endif
647
76ac1508
RS
648 /* Enable bright background colors. */
649 bright_bg ();
039274cf
EZ
650
651 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
652 be defensive anyway. */
653 if (screen_virtual_segment)
654 dosv_refresh_virtual_screen (0, *cols * *rows);
4a96d4d2
KH
655}
656
48ffe371
RS
657/* If we write a character in the position where the mouse is,
658 the mouse cursor may need to be refreshed. */
09e2ac30
RS
659
660static void
f32d4091 661mouse_off_maybe ()
09e2ac30 662{
f32d4091
KS
663 int x, y;
664
665 if (!mouse_visible)
666 return;
667
668 mouse_get_xy (&x, &y);
669 if (y != new_pos_Y || x < new_pos_X)
670 return;
671
672 mouse_off ();
673}
674
8ba01a32
EZ
675#define DEFAULT_CURSOR_START (-1)
676#define DEFAULT_CURSOR_WIDTH (-1)
677#define BOX_CURSOR_WIDTH (-32)
678
679/* Set cursor to begin at scan line START_LINE in the character cell
680 and extend for WIDTH scan lines. Scan lines are counted from top
681 of the character cell, starting from zero. */
682static void
683msdos_set_cursor_shape (struct frame *f, int start_line, int width)
684{
685#if __DJGPP__ > 1
686 unsigned desired_cursor;
687 __dpmi_regs regs;
688 int max_line, top_line, bot_line;
689
690 /* Avoid the costly BIOS call if F isn't the currently selected
691 frame. Allow for NULL as unconditionally meaning the selected
692 frame. */
693 if (f && f != SELECTED_FRAME())
694 return;
695
696 /* The character cell size in scan lines is stored at 40:85 in the
697 BIOS data area. */
698 max_line = _farpeekw (_dos_ds, 0x485) - 1;
699 switch (max_line)
700 {
701 default: /* this relies on CGA cursor emulation being ON! */
702 case 7:
703 bot_line = 7;
704 break;
705 case 9:
706 bot_line = 9;
707 break;
708 case 13:
709 bot_line = 12;
710 break;
711 case 15:
712 bot_line = 14;
713 break;
714 }
715
716 if (width < 0)
717 {
718 if (width == BOX_CURSOR_WIDTH)
719 {
720 top_line = 0;
721 bot_line = max_line;
722 }
723 else if (start_line != DEFAULT_CURSOR_START)
724 {
725 top_line = start_line;
726 bot_line = top_line - width - 1;
727 }
728 else if (width != DEFAULT_CURSOR_WIDTH)
729 {
730 top_line = 0;
731 bot_line = -1 - width;
732 }
733 else
734 top_line = bot_line + 1;
735 }
736 else if (width == 0)
737 {
738 /* [31, 0] seems to DTRT for all screen sizes. */
739 top_line = 31;
740 bot_line = 0;
741 }
742 else /* WIDTH is positive */
743 {
744 if (start_line != DEFAULT_CURSOR_START)
745 bot_line = start_line;
746 top_line = bot_line - (width - 1);
747 }
748
749 /* If the current cursor shape is already what they want, we are
750 history here. */
751 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
752 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
753 return;
754
755 regs.h.ah = 1;
756 regs.x.cx = desired_cursor;
757 __dpmi_int (0x10, &regs);
758#endif /* __DJGPP__ > 1 */
759}
760
761static void
762IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
763{
764 if (EQ (cursor_type, Qbar))
765 {
766 /* Just BAR means the normal EGA/VGA cursor. */
767 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
768 }
769 else if (CONSP (cursor_type) && EQ (XCAR (cursor_type), Qbar))
770 {
771 Lisp_Object bar_parms = XCDR (cursor_type);
772 int width;
773
774 if (INTEGERP (bar_parms))
775 {
776 /* Feature: negative WIDTH means cursor at the top
777 of the character cell, zero means invisible cursor. */
778 width = XINT (bar_parms);
779 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
780 width);
781 }
782 else if (CONSP (bar_parms)
783 && INTEGERP (XCAR (bar_parms))
784 && INTEGERP (XCDR (bar_parms)))
785 {
786 int start_line = XINT (XCDR (bar_parms));
787
788 width = XINT (XCAR (bar_parms));
789 msdos_set_cursor_shape (f, start_line, width);
790 }
791 }
792 else
793 /* Treat anything unknown as "box cursor". This includes nil, so
794 that a frame which doesn't specify a cursor type gets a box,
795 which is the default in Emacs. */
796 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
797}
798
71f65669
EZ
799static void
800IT_ring_bell (void)
f32d4091
KS
801{
802 if (visible_bell)
aee81730 803 {
f32d4091
KS
804 mouse_off ();
805 ScreenVisualBell ();
aee81730 806 }
f32d4091 807 else
3635be47
RS
808 {
809 union REGS inregs, outregs;
810 inregs.h.ah = 2;
811 inregs.h.dl = 7;
812 intdos (&inregs, &outregs);
813 }
09e2ac30
RS
814}
815
c77f6f1b
EZ
816/* Given a face id FACE, extract the face parameters to be used for
817 display until the face changes. The face parameters (actually, its
818 color) are used to construct the video attribute byte for each
819 glyph during the construction of the buffer that is then blitted to
820 the video RAM. */
f32d4091
KS
821static void
822IT_set_face (int face)
823{
2d764c78
EZ
824 struct frame *sf = SELECTED_FRAME();
825 struct face *fp = FACE_FROM_ID (sf, face);
c77f6f1b 826 unsigned long fg, bg;
f32d4091 827
c77f6f1b 828 if (!fp)
e30aee93 829 {
2d764c78 830 fp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
e30aee93
EZ
831 /* The default face for the frame should always be realized and
832 cached. */
833 if (!fp)
834 abort ();
835 }
f32d4091 836 screen_face = face;
c77f6f1b
EZ
837 fg = fp->foreground;
838 bg = fp->background;
839
3b620731
EZ
840 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
841 colors mean use the colors of the default face, except that if
842 highlight is on, invert the foreground and the background. Note
843 that we assume all 16 colors to be available for the background,
844 since Emacs switches on this mode (and loses the blinking
845 attribute) at startup. */
f9d2fdc4 846 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
3b620731 847 fg = FRAME_FOREGROUND_PIXEL (sf);
f9d2fdc4 848 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
3b620731
EZ
849 fg = FRAME_BACKGROUND_PIXEL (sf);
850 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
851 bg = FRAME_BACKGROUND_PIXEL (sf);
f9d2fdc4 852 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
3b620731
EZ
853 bg = FRAME_FOREGROUND_PIXEL (sf);
854
855 /* Make sure highlighted lines really stand out, come what may. */
856 if ((highlight || fp->tty_reverse_p)
857 && (fg == FRAME_FOREGROUND_PIXEL (sf)
858 && bg == FRAME_BACKGROUND_PIXEL (sf)))
859 {
860 unsigned long tem = fg;
861
862 fg = bg;
863 bg = tem;
864 }
c77f6f1b 865 if (termscript)
3b620731
EZ
866 fprintf (termscript, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face,
867 highlight ? "H" : "", fp->foreground, fp->background, fg, bg);
c77f6f1b
EZ
868 if (fg >= 0 && fg < 16)
869 {
870 ScreenAttrib &= 0xf0;
871 ScreenAttrib |= fg;
872 }
873 if (bg >= 0 && bg < 16)
874 {
875 ScreenAttrib &= 0x0f;
876 ScreenAttrib |= ((bg & 0x0f) << 4);
877 }
f32d4091
KS
878}
879
aa9ce936
EZ
880Lisp_Object Vdos_unsupported_char_glyph;
881
71f65669 882static void
c77f6f1b 883IT_write_glyphs (struct glyph *str, int str_len)
f32d4091 884{
aa9ce936
EZ
885 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
886 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
887 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
039274cf 888 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
aa9ce936
EZ
889 register int sl = str_len;
890 register int tlen = GLYPH_TABLE_LENGTH;
891 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
892
e16bf494
AI
893 struct coding_system *coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
894 ? &terminal_coding
895 : &safe_terminal_coding);
2d764c78 896 struct frame *sf;
87485d6f 897
52d38ab2
EZ
898 /* Do we need to consider conversion of unibyte characters to
899 multibyte? */
900 int convert_unibyte_characters
e16bf494
AI
901 = (NILP (current_buffer->enable_multibyte_characters)
902 && unibyte_display_via_language_environment);
52d38ab2 903
3b620731 904 if (str_len <= 0) return;
aee81730 905
aa9ce936
EZ
906 screen_buf = screen_bp = alloca (str_len * 2);
907 screen_buf_end = screen_buf + str_len * 2;
2d764c78 908 sf = SELECTED_FRAME();
e30aee93
EZ
909
910 /* Since faces get cached and uncached behind our back, we can't
911 rely on their indices in the cache being consistent across
912 invocations. So always reset the screen face to the default
913 face of the frame, before writing glyphs, and let the glyphs
914 set the right face if it's different from the default. */
915 IT_set_face (DEFAULT_FACE_ID);
aee81730 916
aa9ce936
EZ
917 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
918 the tail. */
919 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
920 while (sl)
921 {
c77f6f1b 922 int cf, chlen, enclen;
3b620731 923 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
c77f6f1b 924 unsigned ch;
aa9ce936
EZ
925
926 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
927 only for the redisplay code to know how many columns does
928 this character occupy on the screen. Skip padding glyphs. */
c77f6f1b 929 if (CHAR_GLYPH_PADDING_P (*str))
aa9ce936
EZ
930 {
931 str++;
932 sl--;
933 }
934 else
935 {
04ee4f45
EZ
936 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
937 int glyph_not_in_table = 0;
938
939 if (g < 0 || g >= tlen)
940 {
941 /* This glyph doesn't have an entry in Vglyph_table. */
942 ch = str->u.ch;
943 glyph_not_in_table = 1;
944 }
945 else
946 {
947 /* This glyph has an entry in Vglyph_table, so process
948 any aliases before testing for simpleness. */
949 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
950 ch = FAST_GLYPH_CHAR (g);
951 }
952
aa9ce936 953 /* Convert the character code to multibyte, if they
04ee4f45
EZ
954 requested display via language environment. We only want
955 to convert unibyte characters to multibyte in unibyte
956 buffers! Otherwise, the 8-bit value in CH came from the
957 display table set up to display foreign characters. */
52d38ab2 958 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
f0dd4c35
EZ
959 && (ch >= 0240
960 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
aa9ce936
EZ
961 ch = unibyte_char_to_multibyte (ch);
962
963 /* Invalid characters are displayed with a special glyph. */
04ee4f45 964 if (! CHAR_VALID_P (ch, 0))
aa9ce936
EZ
965 {
966 g = !NILP (Vdos_unsupported_char_glyph)
967 ? Vdos_unsupported_char_glyph
2d764c78 968 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
aa9ce936
EZ
969 ch = FAST_GLYPH_CHAR (g);
970 }
aa9ce936
EZ
971
972 /* If the face of this glyph is different from the current
973 screen face, update the screen attribute byte. */
974 cf = FAST_GLYPH_FACE (g);
975 if (cf != screen_face)
976 IT_set_face (cf); /* handles invalid faces gracefully */
977
04ee4f45 978 if (glyph_not_in_table || GLYPH_SIMPLE_P (tbase, tlen, g))
3b620731
EZ
979 {
980 /* We generate the multi-byte form of CH in WORKBUF. */
981 chlen = CHAR_STRING (ch, workbuf);
982 buf = workbuf;
983 }
aa9ce936
EZ
984 else
985 {
986 /* We have a string in Vglyph_table. */
987 chlen = GLYPH_LENGTH (tbase, g);
988 buf = GLYPH_STRING (tbase, g);
989 }
990
c77f6f1b 991 /* If the character is not multibyte, don't bother converting it. */
aa9ce936
EZ
992 if (chlen == 1)
993 {
994 *conversion_buffer = (unsigned char)ch;
995 chlen = 0;
996 enclen = 1;
997 }
998 else
999 {
1000 encode_coding (coding, buf, conversion_buffer, chlen,
1001 conversion_buffer_size);
1002 chlen -= coding->consumed;
1003 enclen = coding->produced;
1004
1005 /* Replace glyph codes that cannot be converted by
1006 terminal_coding with Vdos_unsupported_char_glyph. */
1007 if (*conversion_buffer == '?')
1008 {
1009 char *cbp = conversion_buffer;
1010
1011 while (cbp < conversion_buffer + enclen && *cbp == '?')
1012 *cbp++ = unsupported_char;
1013 if (unsupported_face != screen_face)
1014 IT_set_face (unsupported_face);
1015 }
1016 }
1017
1018 if (enclen + chlen > screen_buf_end - screen_bp)
1019 {
1020 /* The allocated buffer for screen writes is too small.
1021 Flush it and loop again without incrementing STR, so
1022 that the next loop will begin with the same glyph. */
1023 int nbytes = screen_bp - screen_buf;
1024
1025 mouse_off_maybe ();
1026 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1027 if (screen_virtual_segment)
1028 dosv_refresh_virtual_screen (offset, nbytes / 2);
1029 new_pos_X += nbytes / 2;
1030 offset += nbytes;
1031
1032 /* Prepare to reuse the same buffer again. */
1033 screen_bp = screen_buf;
1034 }
1035 else
1036 {
1037 /* There's enough place in the allocated buffer to add
1038 the encoding of this glyph. */
1039
1040 /* First, copy the encoded bytes. */
1041 for (bp = conversion_buffer; enclen--; bp++)
1042 {
1043 *screen_bp++ = (unsigned char)*bp;
1044 *screen_bp++ = ScreenAttrib;
1045 if (termscript)
1046 fputc (*bp, termscript);
1047 }
1048
1049 /* Now copy the bytes not consumed by the encoding. */
1050 if (chlen > 0)
1051 {
1052 buf += coding->consumed;
1053 while (chlen--)
1054 {
1055 if (termscript)
1056 fputc (*buf, termscript);
1057 *screen_bp++ = (unsigned char)*buf++;
1058 *screen_bp++ = ScreenAttrib;
1059 }
1060 }
1061
1062 /* Update STR and its remaining length. */
1063 str++;
1064 sl--;
1065 }
1066 }
aee81730
RS
1067 }
1068
aa9ce936 1069 /* Dump whatever is left in the screen buffer. */
f32d4091 1070 mouse_off_maybe ();
aa9ce936 1071 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
039274cf 1072 if (screen_virtual_segment)
aa9ce936
EZ
1073 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1074 new_pos_X += (screen_bp - screen_buf) / 2;
1075
1076 /* We may have to output some codes to terminate the writing. */
1077 if (CODING_REQUIRE_FLUSHING (coding))
1078 {
1079 coding->mode |= CODING_MODE_LAST_BLOCK;
1080 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
1081 if (coding->produced > 0)
1082 {
241424da 1083 screen_buf = alloca (coding->produced * 2);
aa9ce936
EZ
1084 for (screen_bp = screen_buf, bp = conversion_buffer;
1085 coding->produced--; bp++)
1086 {
1087 *screen_bp++ = (unsigned char)*bp;
1088 *screen_bp++ = ScreenAttrib;
1089 if (termscript)
1090 fputc (*bp, termscript);
1091 }
1092 offset += screen_bp - screen_buf;
1093 mouse_off_maybe ();
1094 dosmemput (screen_buf, screen_bp - screen_buf,
1095 (int)ScreenPrimary + offset);
1096 if (screen_virtual_segment)
1097 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1098 new_pos_X += (screen_bp - screen_buf) / 2;
1099 }
1100 }
f32d4091 1101}
aee81730 1102
41ad069b
EZ
1103/************************************************************************
1104 Mouse Highlight (and friends..)
1105 ************************************************************************/
1106
1107/* This is used for debugging, to turn off note_mouse_highlight. */
1108int disable_mouse_highlight;
1109
1110/* If a string, dos_rawgetc generates an event to display that string.
1111 (The display is done in keyboard.c:read_char.) */
1112static Lisp_Object help_echo;
1113static Lisp_Object previous_help_echo; /* a helper temporary variable */
1114
1115static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1116
1117/* Set the mouse pointer shape according to whether it is in the
1118 area where the mouse highlight is in effect. */
1119static void
1120IT_set_mouse_pointer (int mode)
1121{
1122 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1123 many possibilities to change its shape, and the available
1124 functionality pretty much sucks (e.g., almost every reasonable
1125 shape will conceal the character it is on). Since the color of
1126 the pointer changes in the highlighted area, it is not clear to
1127 me whether anything else is required, anyway. */
1128}
1129
1130/* Display the active region described by mouse_face_*
1131 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1132static void
1133show_mouse_face (struct display_info *dpyinfo, int hl)
1134{
1135 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1136 struct frame *f = XFRAME (WINDOW_FRAME (w));
1137 int i;
1138 struct face *fp;
1139
1140
1141 /* If window is in the process of being destroyed, don't bother
1142 doing anything. */
1143 if (w->current_matrix == NULL)
1144 goto set_cursor_shape;
1145
1146 /* Recognize when we are called to operate on rows that don't exist
1147 anymore. This can happen when a window is split. */
1148 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1149 goto set_cursor_shape;
1150
1151 /* There's no sense to do anything if the mouse face isn't realized. */
1152 if (hl > 0)
1153 {
1154 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1155 if (!fp)
1156 goto set_cursor_shape;
1157 }
1158
1159 /* Note that mouse_face_beg_row etc. are window relative. */
1160 for (i = dpyinfo->mouse_face_beg_row;
1161 i <= dpyinfo->mouse_face_end_row;
1162 i++)
1163 {
1164 int start_hpos, end_hpos;
1165 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1166
1167 /* Don't do anything if row doesn't have valid contents. */
1168 if (!row->enabled_p)
1169 continue;
1170
1171 /* For all but the first row, the highlight starts at column 0. */
1172 if (i == dpyinfo->mouse_face_beg_row)
1173 start_hpos = dpyinfo->mouse_face_beg_col;
1174 else
1175 start_hpos = 0;
1176
1177 if (i == dpyinfo->mouse_face_end_row)
1178 end_hpos = dpyinfo->mouse_face_end_col;
1179 else
1180 end_hpos = row->used[TEXT_AREA];
1181
1182 if (end_hpos <= start_hpos)
1183 continue;
1184 if (hl > 0)
1185 {
1186 int vpos = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1187 int kstart = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1188 int nglyphs = end_hpos - start_hpos;
1189 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1190 int start_offset = offset;
1191
1192 if (termscript)
1193 fprintf (termscript, "\n<MH+ %d-%d:%d>",
1194 kstart, kstart + nglyphs - 1, vpos);
1195
1196 mouse_off ();
1197 IT_set_face (dpyinfo->mouse_face_face_id);
1198 /* Since we are going to change only the _colors_ of the
1199 displayed text, there's no need to go through all the
1200 pain of generating and encoding the text from the glyphs.
1201 Instead, we simply poke the attribute byte of each
1202 affected position in video memory with the colors
1203 computed by IT_set_face! */
1204 _farsetsel (_dos_ds);
1205 while (nglyphs--)
1206 {
1207 _farnspokeb (offset, ScreenAttrib);
1208 offset += 2;
1209 }
1210 if (screen_virtual_segment)
1211 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1212 mouse_on ();
1213 }
1214 else
1215 {
1216 /* We are removing a previously-drawn mouse highlight. The
1217 safest way to do so is to redraw the glyphs anew, since
1218 all kinds of faces and display tables could have changed
1219 behind our back. */
1220 int nglyphs = end_hpos - start_hpos;
1221 int save_x = new_pos_X, save_y = new_pos_Y;
1222
1223 if (end_hpos >= row->used[TEXT_AREA])
1224 nglyphs = row->used[TEXT_AREA] - start_hpos;
1225
1226 /* IT_write_glyphs writes at cursor position, so we need to
1227 temporarily move cursor coordinates to the beginning of
1228 the highlight region. */
1229 new_pos_X = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1230 new_pos_Y = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1231
1232 if (termscript)
1233 fprintf (termscript, "<MH- %d-%d:%d>",
1234 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1235 IT_write_glyphs (row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1236 if (termscript)
1237 fputs ("\n", termscript);
1238 new_pos_X = save_x;
1239 new_pos_Y = save_y;
1240 }
1241 }
1242
1243 set_cursor_shape:
1244
1245 /* Change the mouse pointer shape. */
1246 IT_set_mouse_pointer (hl);
1247}
1248
1249/* Clear out the mouse-highlighted active region.
1250 Redraw it un-highlighted first. */
1251static void
1252clear_mouse_face (struct display_info *dpyinfo)
1253{
1254 if (! NILP (dpyinfo->mouse_face_window))
1255 show_mouse_face (dpyinfo, 0);
1256
1257 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1258 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1259 dpyinfo->mouse_face_window = Qnil;
1260}
1261
1262/* Find the glyph matrix position of buffer position POS in window W.
1263 *HPOS and *VPOS are set to the positions found. W's current glyphs
1264 must be up to date. If POS is above window start return (0, 0).
1265 If POS is after end of W, return end of last line in W. */
1266static int
1267fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1268{
1269 int i;
1270 int lastcol;
1271 int maybe_next_line_p = 0;
1272 int line_start_position;
1273 int yb = window_text_bottom_y (w);
1274 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
1275 struct glyph_row *best_row = row;
1276
1277 while (row->y < yb)
1278 {
1279 if (row->used[TEXT_AREA])
1280 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1281 else
1282 line_start_position = 0;
1283
1284 if (line_start_position > pos)
1285 break;
1286 /* If the position sought is the end of the buffer,
1287 don't include the blank lines at the bottom of the window. */
1288 else if (line_start_position == pos
1289 && pos == BUF_ZV (XBUFFER (w->buffer)))
1290 {
1291 maybe_next_line_p = 1;
1292 break;
1293 }
1294 else if (line_start_position > 0)
1295 best_row = row;
1296
1297 ++row;
1298 }
1299
1300 /* Find the right column within BEST_ROW. */
1301 lastcol = 0;
1302 row = best_row;
1303 for (i = 0; i < row->used[TEXT_AREA]; i++)
1304 {
1305 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1306 int charpos;
1307
1308 charpos = glyph->charpos;
1309 if (charpos == pos)
1310 {
1311 *hpos = i;
1312 *vpos = row->y;
1313 return 1;
1314 }
1315 else if (charpos > pos)
1316 break;
1317 else if (charpos > 0)
1318 lastcol = i;
1319 }
1320
1321 /* If we're looking for the end of the buffer,
1322 and we didn't find it in the line we scanned,
1323 use the start of the following line. */
1324 if (maybe_next_line_p)
1325 {
1326 ++row;
1327 lastcol = 0;
1328 }
1329
1330 *vpos = row->y;
1331 *hpos = lastcol + 1;
1332 return 0;
1333}
1334
1335/* Take proper action when mouse has moved to the mode or top line of
1336 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1337 mode line. X is relative to the start of the text display area of
1338 W, so the width of bitmap areas and scroll bars must be subtracted
1339 to get a position relative to the start of the mode line. */
1340static void
1341IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1342{
1343 struct frame *f = XFRAME (w->frame);
1344 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1345 struct glyph_row *row;
1346
1347 if (mode_line_p)
1348 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1349 else
1350 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1351
1352 if (row->enabled_p)
1353 {
1354 extern Lisp_Object Qhelp_echo;
1355 struct glyph *glyph, *end;
1356 Lisp_Object help, map;
1357
1358 /* Find the glyph under X. */
1359 glyph = row->glyphs[TEXT_AREA]
1360 + x - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
1361 end = glyph + row->used[TEXT_AREA];
1362 if (glyph < end
1363 && STRINGP (glyph->object)
1364 && XSTRING (glyph->object)->intervals
1365 && glyph->charpos >= 0
1366 && glyph->charpos < XSTRING (glyph->object)->size)
1367 {
1368 /* If we're on a string with `help-echo' text property,
1369 arrange for the help to be displayed. This is done by
1370 setting the global variable help_echo to the help string. */
1371 help = Fget_text_property (make_number (glyph->charpos),
1372 Qhelp_echo, glyph->object);
1373 if (STRINGP (help))
1374 help_echo = help;
1375 }
1376 }
1377}
1378
1379/* Take proper action when the mouse has moved to position X, Y on
1380 frame F as regards highlighting characters that have mouse-face
1381 properties. Also de-highlighting chars where the mouse was before.
1382 X and Y can be negative or out of range. */
1383static void
1384IT_note_mouse_highlight (struct frame *f, int x, int y)
1385{
1386 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1387 int portion;
1388 Lisp_Object window;
1389 struct window *w;
1390
1391 /* When a menu is active, don't highlight because this looks odd. */
1392 if (mouse_preempted)
1393 return;
1394
515d0d0e
EZ
1395 if (disable_mouse_highlight
1396 || !f->glyphs_initialized_p)
41ad069b
EZ
1397 return;
1398
1399 dpyinfo->mouse_face_mouse_x = x;
1400 dpyinfo->mouse_face_mouse_y = y;
1401 dpyinfo->mouse_face_mouse_frame = f;
1402
1403 if (dpyinfo->mouse_face_defer)
1404 return;
1405
1406 if (gc_in_progress)
1407 {
1408 dpyinfo->mouse_face_deferred_gc = 1;
1409 return;
1410 }
1411
1412 /* Which window is that in? */
1413 window = window_from_coordinates (f, x, y, &portion, 0);
1414
1415 /* If we were displaying active text in another window, clear that. */
1416 if (! EQ (window, dpyinfo->mouse_face_window))
1417 clear_mouse_face (dpyinfo);
1418
1419 /* Not on a window -> return. */
1420 if (!WINDOWP (window))
1421 return;
1422
1423 /* Convert to window-relative coordinates. */
1424 w = XWINDOW (window);
1425 x -= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1426 y -= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1427
1428 if (portion == 1 || portion == 3)
1429 {
1430 /* Mouse is on the mode or top line. */
1431 IT_note_mode_line_highlight (w, x, portion == 1);
1432 return;
1433 }
1434 else
1435 IT_set_mouse_pointer (0);
1436
1437 /* Are we in a window whose display is up to date?
1438 And verify the buffer's text has not changed. */
1439 if (/* Within text portion of the window. */
1440 portion == 0
1441 && EQ (w->window_end_valid, w->buffer)
1442 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1443 && (XFASTINT (w->last_overlay_modified)
1444 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1445 {
1446 int pos, i, area;
1447 struct glyph_row *row;
1448 struct glyph *glyph;
1449
1450 /* Find the glyph under X/Y. */
1451 glyph = NULL;
1452 if (y < w->current_matrix->nrows)
1453 {
1454 row = MATRIX_ROW (w->current_matrix, y);
1455 if (row->enabled_p
1456 && row->displays_text_p
1457 && x < window_box_width (w, TEXT_AREA))
1458 {
1459 glyph = row->glyphs[TEXT_AREA];
1460 if (x >= row->used[TEXT_AREA])
1461 glyph = NULL;
1462 else
1463 {
1464 glyph += x;
1465 if (!BUFFERP (glyph->object))
1466 glyph = NULL;
1467 }
1468 }
1469 }
1470
1471 /* Clear mouse face if X/Y not over text. */
1472 if (glyph == NULL)
1473 {
1474 clear_mouse_face (dpyinfo);
1475 return;
1476 }
1477
1478 if (!BUFFERP (glyph->object))
1479 abort ();
1480 pos = glyph->charpos;
1481
1482 /* Check for mouse-face and help-echo. */
1483 {
1484 extern Lisp_Object Qmouse_face;
1485 Lisp_Object mouse_face, overlay, position;
1486 Lisp_Object *overlay_vec;
1487 int len, noverlays;
1488 struct buffer *obuf;
1489 int obegv, ozv;
1490
1491 /* If we get an out-of-range value, return now; avoid an error. */
1492 if (pos > BUF_Z (XBUFFER (w->buffer)))
1493 return;
1494
1495 /* Make the window's buffer temporarily current for
1496 overlays_at and compute_char_face. */
1497 obuf = current_buffer;
1498 current_buffer = XBUFFER (w->buffer);
1499 obegv = BEGV;
1500 ozv = ZV;
1501 BEGV = BEG;
1502 ZV = Z;
1503
1504 /* Is this char mouse-active or does it have help-echo? */
1505 XSETINT (position, pos);
1506
1507 /* Put all the overlays we want in a vector in overlay_vec.
1508 Store the length in len. If there are more than 10, make
1509 enough space for all, and try again. */
1510 len = 10;
1511 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1512 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1513 if (noverlays > len)
1514 {
1515 len = noverlays;
1516 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1517 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1518 }
1519
1520 noverlays = sort_overlays (overlay_vec, noverlays, w);
1521
1522 /* Check mouse-face highlighting. */
1523 if (! (EQ (window, dpyinfo->mouse_face_window)
1524 && y >= dpyinfo->mouse_face_beg_row
1525 && y <= dpyinfo->mouse_face_end_row
1526 && (y > dpyinfo->mouse_face_beg_row
1527 || x >= dpyinfo->mouse_face_beg_col)
1528 && (y < dpyinfo->mouse_face_end_row
1529 || x < dpyinfo->mouse_face_end_col
1530 || dpyinfo->mouse_face_past_end)))
1531 {
1532 /* Clear the display of the old active region, if any. */
1533 clear_mouse_face (dpyinfo);
1534
1535 /* Find highest priority overlay that has a mouse-face prop. */
1536 overlay = Qnil;
1537 for (i = 0; i < noverlays; i++)
1538 {
1539 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1540 if (!NILP (mouse_face))
1541 {
1542 overlay = overlay_vec[i];
1543 break;
1544 }
1545 }
1546
1547 /* If no overlay applies, get a text property. */
1548 if (NILP (overlay))
1549 mouse_face = Fget_text_property (position, Qmouse_face,
1550 w->buffer);
1551
1552 /* Handle the overlay case. */
1553 if (! NILP (overlay))
1554 {
1555 /* Find the range of text around this char that
1556 should be active. */
1557 Lisp_Object before, after;
1558 int ignore;
1559
1560 before = Foverlay_start (overlay);
1561 after = Foverlay_end (overlay);
1562 /* Record this as the current active region. */
1563 fast_find_position (w, XFASTINT (before),
1564 &dpyinfo->mouse_face_beg_col,
1565 &dpyinfo->mouse_face_beg_row);
1566 dpyinfo->mouse_face_past_end
1567 = !fast_find_position (w, XFASTINT (after),
1568 &dpyinfo->mouse_face_end_col,
1569 &dpyinfo->mouse_face_end_row);
1570 dpyinfo->mouse_face_window = window;
1571 dpyinfo->mouse_face_face_id
1572 = face_at_buffer_position (w, pos, 0, 0,
1573 &ignore, pos + 1, 1);
1574
1575 /* Display it as active. */
1576 show_mouse_face (dpyinfo, 1);
1577 }
1578 /* Handle the text property case. */
1579 else if (! NILP (mouse_face))
1580 {
1581 /* Find the range of text around this char that
1582 should be active. */
1583 Lisp_Object before, after, beginning, end;
1584 int ignore;
1585
1586 beginning = Fmarker_position (w->start);
1587 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1588 - XFASTINT (w->window_end_pos)));
1589 before
1590 = Fprevious_single_property_change (make_number (pos + 1),
1591 Qmouse_face,
1592 w->buffer, beginning);
1593 after
1594 = Fnext_single_property_change (position, Qmouse_face,
1595 w->buffer, end);
1596 /* Record this as the current active region. */
1597 fast_find_position (w, XFASTINT (before),
1598 &dpyinfo->mouse_face_beg_col,
1599 &dpyinfo->mouse_face_beg_row);
1600 dpyinfo->mouse_face_past_end
1601 = !fast_find_position (w, XFASTINT (after),
1602 &dpyinfo->mouse_face_end_col,
1603 &dpyinfo->mouse_face_end_row);
1604 dpyinfo->mouse_face_window = window;
1605 dpyinfo->mouse_face_face_id
1606 = face_at_buffer_position (w, pos, 0, 0,
1607 &ignore, pos + 1, 1);
1608
1609 /* Display it as active. */
1610 show_mouse_face (dpyinfo, 1);
1611 }
1612 }
1613
1614 /* Look for a `help-echo' property. */
1615 {
1616 Lisp_Object help;
1617 extern Lisp_Object Qhelp_echo;
1618
1619 /* Check overlays first. */
1620 help = Qnil;
1621 for (i = 0; i < noverlays && !STRINGP (help); ++i)
1622 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
1623
1624 /* Try text properties. */
1625 if (!STRINGP (help)
1626 && ((STRINGP (glyph->object)
1627 && glyph->charpos >= 0
1628 && glyph->charpos < XSTRING (glyph->object)->size)
1629 || (BUFFERP (glyph->object)
1630 && glyph->charpos >= BEGV
1631 && glyph->charpos < ZV)))
1632 help = Fget_text_property (make_number (glyph->charpos),
1633 Qhelp_echo, glyph->object);
1634
1635 if (STRINGP (help))
1636 help_echo = help;
1637 }
1638
1639 BEGV = obegv;
1640 ZV = ozv;
1641 current_buffer = obuf;
1642 }
1643 }
1644}
1645
71f65669
EZ
1646static void
1647IT_clear_end_of_line (int first_unused)
f32d4091
KS
1648{
1649 char *spaces, *sp;
1650 int i, j;
039274cf 1651 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
aa9ce936
EZ
1652 extern int fatal_error_in_progress;
1653
2d764c78 1654 if (new_pos_X >= first_unused || fatal_error_in_progress)
aa9ce936 1655 return;
f32d4091
KS
1656
1657 IT_set_face (0);
2d764c78 1658 i = (j = first_unused - new_pos_X) * 2;
e25d9653
EZ
1659 if (termscript)
1660 fprintf (termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
f32d4091 1661 spaces = sp = alloca (i);
aee81730 1662
f32d4091 1663 while (--j >= 0)
aee81730 1664 {
f32d4091
KS
1665 *sp++ = ' ';
1666 *sp++ = ScreenAttrib;
aee81730
RS
1667 }
1668
f32d4091 1669 mouse_off_maybe ();
039274cf
EZ
1670 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1671 if (screen_virtual_segment)
1672 dosv_refresh_virtual_screen (offset, i / 2);
2d764c78
EZ
1673
1674 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1675 Let's follow their lead, in case someone relies on this. */
1676 new_pos_X = first_unused;
aee81730
RS
1677}
1678
71f65669 1679static void
f32d4091
KS
1680IT_clear_screen (void)
1681{
1682 if (termscript)
1683 fprintf (termscript, "<CLR:SCR>");
1684 IT_set_face (0);
1685 mouse_off ();
1686 ScreenClear ();
039274cf
EZ
1687 if (screen_virtual_segment)
1688 dosv_refresh_virtual_screen (0, screen_size);
f32d4091
KS
1689 new_pos_X = new_pos_Y = 0;
1690}
1691
71f65669 1692static void
f32d4091
KS
1693IT_clear_to_end (void)
1694{
1695 if (termscript)
1696 fprintf (termscript, "<CLR:EOS>");
1697
1698 while (new_pos_Y < screen_size_Y) {
1699 new_pos_X = 0;
e25d9653 1700 IT_clear_end_of_line (screen_size_X);
f32d4091
KS
1701 new_pos_Y++;
1702 }
1703}
1704
71f65669 1705static void
f32d4091
KS
1706IT_cursor_to (int y, int x)
1707{
1708 if (termscript)
1709 fprintf (termscript, "\n<XY=%dx%d>", x, y);
1710 new_pos_X = x;
1711 new_pos_Y = y;
1712}
1713
fc171623
KH
1714static int cursor_cleared;
1715
d1d5dc19 1716static void
fc171623
KH
1717IT_display_cursor (int on)
1718{
1719 if (on && cursor_cleared)
1720 {
1721 ScreenSetCursor (current_pos_Y, current_pos_X);
1722 cursor_cleared = 0;
1723 }
1724 else if (!on && !cursor_cleared)
1725 {
1726 ScreenSetCursor (-1, -1);
1727 cursor_cleared = 1;
1728 }
1729}
1730
1731/* Emacs calls cursor-movement functions a lot when it updates the
1732 display (probably a legacy of old terminals where you cannot
1733 update a screen line without first moving the cursor there).
1734 However, cursor movement is expensive on MSDOS (it calls a slow
1735 BIOS function and requires 2 mode switches), while actual screen
1736 updates access the video memory directly and don't depend on
1737 cursor position. To avoid slowing down the redisplay, we cheat:
1738 all functions that move the cursor only set internal variables
1739 which record the cursor position, whereas the cursor is only
1740 moved to its final position whenever screen update is complete.
1741
1742 `IT_cmgoto' is called from the keyboard reading loop and when the
1743 frame update is complete. This means that we are ready for user
1744 input, so we update the cursor position to show where the point is,
1745 and also make the mouse pointer visible.
1746
1747 Special treatment is required when the cursor is in the echo area,
1748 to put the cursor at the end of the text displayed there. */
1749
71f65669
EZ
1750static void
1751IT_cmgoto (FRAME_PTR f)
fc171623
KH
1752{
1753 /* Only set the cursor to where it should be if the display is
1754 already in sync with the window contents. */
2d764c78
EZ
1755 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1756
1757 /* FIXME: This needs to be rewritten for the new redisplay, or
1758 removed. */
1759#if 0
06da1de1
EZ
1760 static int previous_pos_X = -1;
1761
2d764c78
EZ
1762 update_cursor_pos = 1; /* temporary!!! */
1763
06da1de1
EZ
1764 /* If the display is in sync, forget any previous knowledge about
1765 cursor position. This is primarily for unexpected events like
1766 C-g in the minibuffer. */
1767 if (update_cursor_pos && previous_pos_X >= 0)
1768 previous_pos_X = -1;
1769 /* If we are in the echo area, put the cursor at the
1770 end of the echo area message. */
fc171623
KH
1771 if (!update_cursor_pos
1772 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1773 {
06da1de1
EZ
1774 int tem_X = current_pos_X, dummy;
1775
1776 if (echo_area_glyphs)
1777 {
1778 tem_X = echo_area_glyphs_length;
1779 /* Save current cursor position, to be restored after the
1780 echo area message is erased. Only remember one level
1781 of previous cursor position. */
1782 if (previous_pos_X == -1)
1783 ScreenGetCursor (&dummy, &previous_pos_X);
1784 }
1785 else if (previous_pos_X >= 0)
1786 {
1787 /* We wind up here after the echo area message is erased.
1788 Restore the cursor position we remembered above. */
1789 tem_X = previous_pos_X;
1790 previous_pos_X = -1;
1791 }
9a599a60 1792
06da1de1 1793 if (current_pos_X != tem_X)
9a599a60
EZ
1794 {
1795 new_pos_X = tem_X;
1796 update_cursor_pos = 1;
1797 }
fc171623 1798 }
2d764c78 1799#endif
fc171623
KH
1800
1801 if (update_cursor_pos
1802 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1803 {
1804 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1805 if (termscript)
1806 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1807 }
1808
1809 /* Maybe cursor is invisible, so make it visible. */
1810 IT_display_cursor (1);
1811
1812 /* Mouse pointer should be always visible if we are waiting for
1813 keyboard input. */
1814 if (!mouse_visible)
1815 mouse_on ();
1816}
1817
71f65669
EZ
1818static void
1819IT_reassert_line_highlight (int new, int vpos)
f32d4091
KS
1820{
1821 highlight = new;
f32d4091
KS
1822}
1823
71f65669 1824static void
c77f6f1b 1825IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1b94449f 1826{
f32d4091 1827 highlight = new_highlight;
f32d4091
KS
1828 IT_cursor_to (vpos, 0);
1829 IT_clear_end_of_line (first_unused_hpos);
1830}
1831
71f65669 1832static void
41ad069b 1833IT_update_begin (struct frame *f)
f32d4091 1834{
41ad069b
EZ
1835 struct display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1836
f32d4091 1837 highlight = 0;
41ad069b
EZ
1838
1839 BLOCK_INPUT;
1840
1841 if (f == display_info->mouse_face_mouse_frame)
1842 {
1843 /* Don't do highlighting for mouse motion during the update. */
1844 display_info->mouse_face_defer = 1;
1845
1846 /* If F needs to be redrawn, simply forget about any prior mouse
1847 highlighting. */
1848 if (FRAME_GARBAGED_P (f))
1849 display_info->mouse_face_window = Qnil;
1850
1851 /* Can we tell that this update does not affect the window
1852 where the mouse highlight is? If so, no need to turn off.
1853 Likewise, don't do anything if the frame is garbaged;
1854 in that case, the frame's current matrix that we would use
1855 is all wrong, and we will redisplay that line anyway. */
8ccb9a54
EZ
1856 if (!NILP (display_info->mouse_face_window)
1857 && WINDOWP (display_info->mouse_face_window))
41ad069b
EZ
1858 {
1859 struct window *w = XWINDOW (display_info->mouse_face_window);
1860 int i;
1861
8ccb9a54
EZ
1862 /* If the mouse highlight is in the window that was deleted
1863 (e.g., if it was popped by completion), clear highlight
1864 unconditionally. */
1865 if (NILP (w->buffer))
1866 display_info->mouse_face_window = Qnil;
1867 else
1868 {
1869 for (i = 0; i < w->desired_matrix->nrows; ++i)
1870 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
1871 break;
1872 }
41ad069b 1873
8ccb9a54 1874 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
41ad069b
EZ
1875 clear_mouse_face (display_info);
1876 }
1877 }
1878 else if (!FRAME_LIVE_P (display_info->mouse_face_mouse_frame))
1879 {
1880 /* If the frame with mouse highlight was deleted, invalidate the
1881 highlight info. */
1882 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1883 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1884 display_info->mouse_face_window = Qnil;
1885 display_info->mouse_face_deferred_gc = 0;
1886 display_info->mouse_face_mouse_frame = NULL;
1887 }
1888
1889 UNBLOCK_INPUT;
f32d4091
KS
1890}
1891
71f65669 1892static void
41ad069b 1893IT_update_end (struct frame *f)
f32d4091 1894{
41ad069b
EZ
1895 highlight = 0;
1896 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
1897}
1898
8ba01a32
EZ
1899Lisp_Object Qcursor_type;
1900
41ad069b
EZ
1901static void
1902IT_frame_up_to_date (struct frame *f)
1903{
1904 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
0c3cfc51
EZ
1905 Lisp_Object new_cursor, frame_desired_cursor;
1906 struct window *sw;
41ad069b
EZ
1907
1908 if (dpyinfo->mouse_face_deferred_gc
1909 || f == dpyinfo->mouse_face_mouse_frame)
1910 {
1911 BLOCK_INPUT;
1912 if (dpyinfo->mouse_face_mouse_frame)
1913 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1914 dpyinfo->mouse_face_mouse_x,
1915 dpyinfo->mouse_face_mouse_y);
1916 dpyinfo->mouse_face_deferred_gc = 0;
1917 UNBLOCK_INPUT;
1918 }
1919
0c3cfc51
EZ
1920 /* Set the cursor type to whatever they wanted. In a minibuffer
1921 window, we want the cursor to appear only if we are reading input
1922 from this window, and we want the cursor to be taken from the
1923 frame parameters. For the selected window, we use either its
1924 buffer-local value or the value from the frame parameters if the
1925 buffer doesn't define its local value for the cursor type. */
1926 sw = XWINDOW (f->selected_window);
1927 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1928 if (cursor_in_echo_area
1929 && FRAME_HAS_MINIBUF_P (f)
1930 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1931 && sw == XWINDOW (echo_area_window))
1932 new_cursor = frame_desired_cursor;
1933 else
1934 {
1935 struct buffer *b = XBUFFER (sw->buffer);
1936
1937 if (EQ (b->cursor_type, Qt))
1938 new_cursor = frame_desired_cursor;
1939 else if (NILP (b->cursor_type)) /* nil means no cursor */
1940 new_cursor = Fcons (Qbar, make_number (0));
1941 else
1942 new_cursor = b->cursor_type;
1943 }
1944
1945 IT_set_cursor_type (f, new_cursor);
8ba01a32 1946
41ad069b 1947 IT_cmgoto (f); /* position cursor when update is done */
f32d4091 1948}
1b94449f 1949
c77f6f1b
EZ
1950/* Copy LEN glyphs displayed on a single line whose vertical position
1951 is YPOS, beginning at horizontal position XFROM to horizontal
1952 position XTO, by moving blocks in the video memory. Used by
1953 functions that insert and delete glyphs. */
1954static void
1955IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1956{
1957 /* The offsets of source and destination relative to the
1958 conventional memorty selector. */
1959 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1960 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1961
1962 if (from == to || len <= 0)
1963 return;
1964
1965 _farsetsel (_dos_ds);
1966
1967 /* The source and destination might overlap, so we need to move
1968 glyphs non-destructively. */
1969 if (from > to)
1970 {
1971 for ( ; len; from += 2, to += 2, len--)
1972 _farnspokew (to, _farnspeekw (from));
1973 }
1974 else
1975 {
1976 from += (len - 1) * 2;
1977 to += (len - 1) * 2;
1978 for ( ; len; from -= 2, to -= 2, len--)
1979 _farnspokew (to, _farnspeekw (from));
1980 }
1981 if (screen_virtual_segment)
1982 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1983}
1984
1985/* Insert and delete glyphs. */
aa9ce936
EZ
1986static void
1987IT_insert_glyphs (start, len)
c77f6f1b 1988 register struct glyph *start;
aa9ce936
EZ
1989 register int len;
1990{
c77f6f1b
EZ
1991 int shift_by_width = screen_size_X - (new_pos_X + len);
1992
1993 /* Shift right the glyphs from the nominal cursor position to the
1994 end of this line. */
1995 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1996
1997 /* Now write the glyphs to be inserted. */
1998 IT_write_glyphs (start, len);
aa9ce936
EZ
1999}
2000
2001static void
2002IT_delete_glyphs (n)
2003 register int n;
2004{
2005 abort ();
2006}
2007
211c7152 2008/* set-window-configuration on window.c needs this. */
3bb1f22f
RS
2009void
2010x_set_menu_bar_lines (f, value, oldval)
2011 struct frame *f;
2012 Lisp_Object value, oldval;
2013{
211c7152
EZ
2014 set_menu_bar_lines (f, value, oldval);
2015}
3bb1f22f 2016
211c7152 2017/* This was copied from xfns.c */
3bb1f22f 2018
211c7152
EZ
2019Lisp_Object Qbackground_color;
2020Lisp_Object Qforeground_color;
8ba01a32 2021Lisp_Object Qreverse;
211c7152 2022extern Lisp_Object Qtitle;
3bb1f22f 2023
48ffe371
RS
2024/* IT_set_terminal_modes is called when emacs is started,
2025 resumed, and whenever the screen is redrawn! */
f32d4091 2026
71f65669 2027static void
f32d4091
KS
2028IT_set_terminal_modes (void)
2029{
aee81730 2030 if (termscript)
f32d4091
KS
2031 fprintf (termscript, "\n<SET_TERM>");
2032 highlight = 0;
2033
2034 screen_size_X = ScreenCols ();
2035 screen_size_Y = ScreenRows ();
2036 screen_size = screen_size_X * screen_size_Y;
aee81730 2037
f32d4091
KS
2038 new_pos_X = new_pos_Y = 0;
2039 current_pos_X = current_pos_Y = -1;
2040
2041 if (term_setup_done)
2042 return;
2043 term_setup_done = 1;
aee81730 2044
f32d4091
KS
2045 startup_screen_size_X = screen_size_X;
2046 startup_screen_size_Y = screen_size_Y;
c9adab25 2047 startup_screen_attrib = ScreenAttrib;
f32d4091 2048
039274cf
EZ
2049#if __DJGPP__ > 1
2050 /* Is DOS/V (or any other RSIS software which relocates
2051 the screen) installed? */
2052 {
2053 unsigned short es_value;
2054 __dpmi_regs regs;
2055
2056 regs.h.ah = 0xfe; /* get relocated screen address */
2057 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2058 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2059 else if (screen_old_address) /* already switched to Japanese mode once */
2060 regs.x.es = (screen_old_address >> 4) & 0xffff;
2061 else
2062 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2063 regs.x.di = 0;
2064 es_value = regs.x.es;
2065 __dpmi_int (0x10, &regs);
2066
d1d5dc19 2067 if (regs.x.es != es_value)
039274cf 2068 {
d1d5dc19
EZ
2069 /* screen_old_address is only set if ScreenPrimary does NOT
2070 already point to the relocated buffer address returned by
2071 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2072 ScreenPrimary to that address at startup under DOS/V. */
2073 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2074 screen_old_address = ScreenPrimary;
039274cf
EZ
2075 screen_virtual_segment = regs.x.es;
2076 screen_virtual_offset = regs.x.di;
2077 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2078 }
2079 }
2080#endif /* __DJGPP__ > 1 */
2081
f32d4091
KS
2082 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2083 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2084
2085 if (termscript)
c9adab25 2086 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
039274cf 2087 screen_size_X, screen_size_Y);
76ac1508
RS
2088
2089 bright_bg ();
f32d4091
KS
2090}
2091
48ffe371
RS
2092/* IT_reset_terminal_modes is called when emacs is
2093 suspended or killed. */
f32d4091 2094
71f65669 2095static void
f32d4091
KS
2096IT_reset_terminal_modes (void)
2097{
c9adab25
KH
2098 int display_row_start = (int) ScreenPrimary;
2099 int saved_row_len = startup_screen_size_X * 2;
2100 int update_row_len = ScreenCols () * 2;
2101 int current_rows = ScreenRows ();
2102 int to_next_row = update_row_len;
2103 unsigned char *saved_row = startup_screen_buffer;
2104 int cursor_pos_X = ScreenCols () - 1;
2105 int cursor_pos_Y = ScreenRows () - 1;
2106
f32d4091 2107 if (termscript)
5063b150 2108 fprintf (termscript, "\n<RESET_TERM>");
f32d4091
KS
2109
2110 highlight = 0;
2111
2112 if (!term_setup_done)
2113 return;
2114
c9adab25 2115 mouse_off ();
b36701cc
RS
2116
2117 /* Leave the video system in the same state as we found it,
2118 as far as the blink/bright-background bit is concerned. */
2119 maybe_enable_blinking ();
06b1ea13 2120
c9adab25
KH
2121 /* We have a situation here.
2122 We cannot just do ScreenUpdate(startup_screen_buffer) because
2123 the luser could have changed screen dimensions inside Emacs
2124 and failed (or didn't want) to restore them before killing
2125 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2126 thus will happily use memory outside what was allocated for
2127 `startup_screen_buffer'.
2128 Thus we only restore as much as the current screen dimensions
2129 can hold, and clear the rest (if the saved screen is smaller than
2130 the current) with the color attribute saved at startup. The cursor
2131 is also restored within the visible dimensions. */
2132
2133 ScreenAttrib = startup_screen_attrib;
c9adab25 2134
06b1ea13
EZ
2135 /* Don't restore the screen if we are exiting less than 2 seconds
2136 after startup: we might be crashing, and the screen might show
2137 some vital clues to what's wrong. */
2138 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
c9adab25 2139 {
06b1ea13 2140 ScreenClear ();
039274cf 2141 if (screen_virtual_segment)
06b1ea13
EZ
2142 dosv_refresh_virtual_screen (0, screen_size);
2143
2144 if (update_row_len > saved_row_len)
2145 update_row_len = saved_row_len;
2146 if (current_rows > startup_screen_size_Y)
2147 current_rows = startup_screen_size_Y;
2148
2149 if (termscript)
2150 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2151 update_row_len / 2, current_rows);
2152
2153 while (current_rows--)
2154 {
2155 dosmemput (saved_row, update_row_len, display_row_start);
2156 if (screen_virtual_segment)
2157 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2158 update_row_len / 2);
2159 saved_row += saved_row_len;
2160 display_row_start += to_next_row;
2161 }
c9adab25
KH
2162 }
2163 if (startup_pos_X < cursor_pos_X)
2164 cursor_pos_X = startup_pos_X;
2165 if (startup_pos_Y < cursor_pos_Y)
2166 cursor_pos_Y = startup_pos_Y;
2167
2168 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2169 xfree (startup_screen_buffer);
f32d4091
KS
2170
2171 term_setup_done = 0;
2172}
2173
71f65669
EZ
2174static void
2175IT_set_terminal_window (int foo)
f32d4091
KS
2176{
2177}
2178
2d764c78
EZ
2179/* Remember the screen colors of the curent frame, to serve as the
2180 default colors for newly-created frames. */
2181
2182static int initial_screen_colors[2];
2183
2184DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2185 Smsdos_remember_default_colors, 1, 1, 0,
2186 "Remember the screen colors of the current frame.")
2187 (frame)
2188 Lisp_Object frame;
2189{
2190 int reverse;
2191 struct frame *f;
2192
2193 CHECK_FRAME (frame, 0);
2194 f= XFRAME (frame);
2195 reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
2196
2197 initial_screen_colors[0]
2198 = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
2199 initial_screen_colors[1]
2200 = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
2201}
2202
f32d4091 2203void
3bb1f22f 2204IT_set_frame_parameters (f, alist)
c77f6f1b 2205 struct frame *f;
f32d4091
KS
2206 Lisp_Object alist;
2207{
2208 Lisp_Object tail;
db722735 2209 int length = XINT (Flength (alist));
2d764c78 2210 int i, j;
db722735
RS
2211 Lisp_Object *parms
2212 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2213 Lisp_Object *values
2214 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2d764c78 2215 /* Do we have to reverse the foreground and background colors? */
8ba01a32 2216 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2d764c78
EZ
2217 int was_reverse = reverse;
2218 int redraw = 0, fg_set = 0, bg_set = 0;
2219 unsigned long orig_fg;
2220 unsigned long orig_bg;
2221
2222 /* If we are creating a new frame, begin with the original screen colors
2223 used for the initial frame. */
2224 if (alist == Vdefault_frame_alist
2225 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2226 {
2227 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2228 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2229 }
2230 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2231 orig_bg = FRAME_BACKGROUND_PIXEL (f);
db722735
RS
2232
2233 /* Extract parm names and values into those vectors. */
2234 i = 0;
f32d4091
KS
2235 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2236 {
db722735 2237 Lisp_Object elt;
f32d4091
KS
2238
2239 elt = Fcar (tail);
db722735
RS
2240 parms[i] = Fcar (elt);
2241 CHECK_SYMBOL (parms[i], 1);
2242 values[i] = Fcdr (elt);
2243 i++;
2244 }
2245
2d764c78 2246 j = i;
db722735 2247
2d764c78
EZ
2248 for (i = 0; i < j; i++)
2249 {
2250 Lisp_Object prop = parms[i];
2251 Lisp_Object val = values[i];
2252
8ba01a32 2253 if (EQ (prop, Qreverse))
2d764c78
EZ
2254 reverse = EQ (val, Qt);
2255 }
2256
2257 if (termscript && reverse && !was_reverse)
2258 fprintf (termscript, "<INVERSE-VIDEO>\n");
2259
2260 /* Now process the alist elements in reverse of specified order. */
db722735
RS
2261 for (i--; i >= 0; i--)
2262 {
2263 Lisp_Object prop = parms[i];
2264 Lisp_Object val = values[i];
f32d4091 2265
4e825084 2266 if (EQ (prop, Qforeground_color))
f32d4091 2267 {
2d764c78
EZ
2268 unsigned long new_color = load_color (f, NULL, val, reverse
2269 ? LFACE_BACKGROUND_INDEX
2270 : LFACE_FOREGROUND_INDEX);
3b620731
EZ
2271 if (new_color != FACE_TTY_DEFAULT_COLOR
2272 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2273 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
f32d4091 2274 {
2d764c78
EZ
2275 if (reverse)
2276 /* FIXME: should the fore-/background of the default
2277 face change here as well? */
2278 FRAME_BACKGROUND_PIXEL (f) = new_color;
2279 else
2280 FRAME_FOREGROUND_PIXEL (f) = new_color;
f32d4091 2281 redraw = 1;
2d764c78 2282 fg_set = 1;
76ac1508 2283 if (termscript)
a7cf9151 2284 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
f32d4091
KS
2285 }
2286 }
4e825084 2287 else if (EQ (prop, Qbackground_color))
f32d4091 2288 {
2d764c78
EZ
2289 unsigned long new_color = load_color (f, NULL, val, reverse
2290 ? LFACE_FOREGROUND_INDEX
2291 : LFACE_BACKGROUND_INDEX);
3b620731
EZ
2292 if (new_color != FACE_TTY_DEFAULT_COLOR
2293 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2294 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
f32d4091 2295 {
2d764c78
EZ
2296 if (reverse)
2297 FRAME_FOREGROUND_PIXEL (f) = new_color;
2298 else
2299 FRAME_BACKGROUND_PIXEL (f) = new_color;
f32d4091 2300 redraw = 1;
2d764c78 2301 bg_set = 1;
76ac1508 2302 if (termscript)
a7cf9151 2303 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
f32d4091
KS
2304 }
2305 }
211c7152
EZ
2306 else if (EQ (prop, Qtitle))
2307 {
2308 x_set_title (f, val);
2309 if (termscript)
2310 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
2311 }
8ba01a32
EZ
2312 else if (EQ (prop, Qcursor_type))
2313 {
2314 IT_set_cursor_type (f, val);
2315 if (termscript)
2316 fprintf (termscript, "<CTYPE: %s>\n",
2317 EQ (val, Qbar) || CONSP (val) && EQ (XCAR (val), Qbar)
2318 ? "bar" : "box");
2319 }
db722735 2320 store_frame_param (f, prop, val);
2d764c78 2321 }
db722735 2322
2d764c78
EZ
2323 /* If they specified "reverse", but not the colors, we need to swap
2324 the current frame colors. */
2325 if (reverse && !was_reverse)
2326 {
2327 if (!fg_set)
2328 {
2329 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
2330 redraw = 1;
2331 }
2332 if (!bg_set)
2333 {
2334 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
2335 redraw = 1;
2336 }
f32d4091
KS
2337 }
2338
2339 if (redraw)
2340 {
2d764c78
EZ
2341 face_change_count++; /* forces xdisp.c to recompute basic faces */
2342 if (f == SELECTED_FRAME())
3bb1f22f 2343 redraw_frame (f);
f32d4091
KS
2344 }
2345}
2346
a7cf9151
EZ
2347extern void init_frame_faces (FRAME_PTR);
2348
f32d4091
KS
2349#endif /* !HAVE_X_WINDOWS */
2350
2351
48ffe371
RS
2352/* Do we need the internal terminal? */
2353
f32d4091
KS
2354void
2355internal_terminal_init ()
2356{
2357 char *term = getenv ("TERM");
2358 char *colors;
2d764c78 2359 struct frame *sf = SELECTED_FRAME();
f32d4091
KS
2360
2361#ifdef HAVE_X_WINDOWS
2362 if (!inhibit_window_system)
2363 return;
2364#endif
2365
2366 internal_terminal
2367 = (!noninteractive) && term && !strcmp (term, "internal");
2368
2369 if (getenv ("EMACSTEST"))
5063b150 2370 termscript = fopen (getenv ("EMACSTEST"), "wt");
f32d4091
KS
2371
2372#ifndef HAVE_X_WINDOWS
2373 if (!internal_terminal || inhibit_window_system)
2374 {
2d764c78 2375 sf->output_method = output_termcap;
f32d4091
KS
2376 return;
2377 }
2378
2379 Vwindow_system = intern ("pc");
2380 Vwindow_system_version = make_number (1);
2d764c78 2381 sf->output_method = output_msdos_raw;
039274cf
EZ
2382
2383 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2384 screen_old_address = 0;
2385
2d764c78
EZ
2386 /* Forget the stale screen colors as well. */
2387 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2388
f32d4091
KS
2389 bzero (&the_only_x_display, sizeof the_only_x_display);
2390 the_only_x_display.background_pixel = 7; /* White */
2391 the_only_x_display.foreground_pixel = 0; /* Black */
76ac1508 2392 bright_bg ();
5063b150 2393 colors = getenv ("EMACSCOLORS");
f32d4091
KS
2394 if (colors && strlen (colors) >= 2)
2395 {
76ac1508
RS
2396 /* The colors use 4 bits each (we enable bright background). */
2397 if (isdigit (colors[0]))
2398 colors[0] -= '0';
2399 else if (isxdigit (colors[0]))
2400 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1bd7b2c7
RS
2401 if (colors[0] >= 0 && colors[0] < 16)
2402 the_only_x_display.foreground_pixel = colors[0];
76ac1508
RS
2403 if (isdigit (colors[1]))
2404 colors[1] -= '0';
2405 else if (isxdigit (colors[1]))
2406 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2407 if (colors[1] >= 0 && colors[1] < 16)
1bd7b2c7 2408 the_only_x_display.background_pixel = colors[1];
f32d4091
KS
2409 }
2410 the_only_x_display.line_height = 1;
64ec6a02 2411 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
41ad069b
EZ
2412 the_only_x_display.display_info.mouse_face_mouse_frame = NULL;
2413 the_only_x_display.display_info.mouse_face_deferred_gc = 0;
2414 the_only_x_display.display_info.mouse_face_beg_row =
2415 the_only_x_display.display_info.mouse_face_beg_col = -1;
2416 the_only_x_display.display_info.mouse_face_end_row =
2417 the_only_x_display.display_info.mouse_face_end_col = -1;
2418 the_only_x_display.display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2419 the_only_x_display.display_info.mouse_face_window = Qnil;
2420 the_only_x_display.display_info.mouse_face_mouse_x =
2421 the_only_x_display.display_info.mouse_face_mouse_y = 0;
2422 the_only_x_display.display_info.mouse_face_defer = 0;
f32d4091 2423
2d764c78 2424 init_frame_faces (sf);
f32d4091
KS
2425
2426 ring_bell_hook = IT_ring_bell;
aa9ce936
EZ
2427 insert_glyphs_hook = IT_insert_glyphs;
2428 delete_glyphs_hook = IT_delete_glyphs;
f32d4091
KS
2429 write_glyphs_hook = IT_write_glyphs;
2430 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
2431 clear_to_end_hook = IT_clear_to_end;
2432 clear_end_of_line_hook = IT_clear_end_of_line;
2433 clear_frame_hook = IT_clear_screen;
2434 change_line_highlight_hook = IT_change_line_highlight;
2435 update_begin_hook = IT_update_begin;
2436 update_end_hook = IT_update_end;
2437 reassert_line_highlight_hook = IT_reassert_line_highlight;
41ad069b 2438 frame_up_to_date_hook = IT_frame_up_to_date;
f32d4091
KS
2439
2440 /* These hooks are called by term.c without being checked. */
2441 set_terminal_modes_hook = IT_set_terminal_modes;
2442 reset_terminal_modes_hook = IT_reset_terminal_modes;
2443 set_terminal_window_hook = IT_set_terminal_window;
c77f6f1b 2444 char_ins_del_ok = 0;
f32d4091
KS
2445#endif
2446}
2447
2448dos_get_saved_screen (screen, rows, cols)
2449 char **screen;
2450 int *rows;
2451 int *cols;
2452{
2453#ifndef HAVE_X_WINDOWS
2454 *screen = startup_screen_buffer;
2455 *cols = startup_screen_size_X;
2456 *rows = startup_screen_size_Y;
039274cf 2457 return *screen != (char *)0;
f32d4091
KS
2458#else
2459 return 0;
2460#endif
2461}
3bb1f22f
RS
2462
2463#ifndef HAVE_X_WINDOWS
2464
2465/* We are not X, but we can emulate it well enough for our needs... */
2466void
2467check_x (void)
2468{
2d764c78
EZ
2469 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2470 error ("Not running under a window system");
3bb1f22f
RS
2471}
2472
2473#endif
2474
5063b150 2475\f
f32d4091
KS
2476/* ----------------------- Keyboard control ----------------------
2477 *
2478 * Keymaps reflect the following keyboard layout:
2479 *
2480 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2481 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2482 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2483 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2484 * SPACE
2485 */
2486
d1d5dc19
EZ
2487#define Ignore 0x0000
2488#define Normal 0x0000 /* normal key - alt changes scan-code */
2489#define FctKey 0x1000 /* func key if c == 0, else c */
2490#define Special 0x2000 /* func key even if c != 0 */
2491#define ModFct 0x3000 /* special if mod-keys, else 'c' */
2492#define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2493#define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2494#define Grey 0x6000 /* Grey keypad key */
2495
2496#define Alt 0x0100 /* alt scan-code */
2497#define Ctrl 0x0200 /* ctrl scan-code */
2498#define Shift 0x0400 /* shift scan-code */
2499
f32d4091
KS
2500static int extended_kbd; /* 101 (102) keyboard present. */
2501
d1d5dc19
EZ
2502struct kbd_translate {
2503 unsigned char sc;
2504 unsigned char ch;
2505 unsigned short code;
2506};
2507
f32d4091
KS
2508struct dos_keyboard_map
2509{
2510 char *unshifted;
2511 char *shifted;
2512 char *alt_gr;
d1d5dc19 2513 struct kbd_translate *translate_table;
f32d4091
KS
2514};
2515
2516
2517static struct dos_keyboard_map us_keyboard = {
2518/* 0 1 2 3 4 5 */
2519/* 01234567890123456789012345678901234567890 12345678901234 */
2520 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2521/* 0123456789012345678901234567890123456789 012345678901234 */
2522 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
d1d5dc19
EZ
2523 0, /* no Alt-Gr key */
2524 0 /* no translate table */
f32d4091
KS
2525};
2526
2527static struct dos_keyboard_map fr_keyboard = {
2528/* 0 1 2 3 4 5 */
2529/* 012 3456789012345678901234567890123456789012345678901234 */
2530