Define ALLOCA to an empty string.
[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
9ab8560d 375 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
40437cf5
EZ
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
e023fb27
EZ
893 /* If terminal_coding does any conversion, use it, otherwise use
894 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
895 because it always returns 1 if terminal_coding.src_multibyte is 1. */
896 struct coding_system *coding =
897 (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
898 ? &terminal_coding
899 : &safe_terminal_coding);
2d764c78 900 struct frame *sf;
87485d6f 901
52d38ab2
EZ
902 /* Do we need to consider conversion of unibyte characters to
903 multibyte? */
904 int convert_unibyte_characters
e16bf494
AI
905 = (NILP (current_buffer->enable_multibyte_characters)
906 && unibyte_display_via_language_environment);
52d38ab2 907
3b620731 908 if (str_len <= 0) return;
aee81730 909
aa9ce936
EZ
910 screen_buf = screen_bp = alloca (str_len * 2);
911 screen_buf_end = screen_buf + str_len * 2;
2d764c78 912 sf = SELECTED_FRAME();
e30aee93
EZ
913
914 /* Since faces get cached and uncached behind our back, we can't
915 rely on their indices in the cache being consistent across
916 invocations. So always reset the screen face to the default
917 face of the frame, before writing glyphs, and let the glyphs
918 set the right face if it's different from the default. */
919 IT_set_face (DEFAULT_FACE_ID);
aee81730 920
aa9ce936
EZ
921 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
922 the tail. */
923 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
924 while (sl)
925 {
c77f6f1b 926 int cf, chlen, enclen;
3b620731 927 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
c77f6f1b 928 unsigned ch;
aa9ce936
EZ
929
930 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
931 only for the redisplay code to know how many columns does
932 this character occupy on the screen. Skip padding glyphs. */
c77f6f1b 933 if (CHAR_GLYPH_PADDING_P (*str))
aa9ce936
EZ
934 {
935 str++;
936 sl--;
937 }
938 else
939 {
04ee4f45
EZ
940 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
941 int glyph_not_in_table = 0;
942
943 if (g < 0 || g >= tlen)
944 {
945 /* This glyph doesn't have an entry in Vglyph_table. */
946 ch = str->u.ch;
947 glyph_not_in_table = 1;
948 }
949 else
950 {
951 /* This glyph has an entry in Vglyph_table, so process
952 any aliases before testing for simpleness. */
953 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
954 ch = FAST_GLYPH_CHAR (g);
955 }
956
aa9ce936 957 /* Convert the character code to multibyte, if they
04ee4f45
EZ
958 requested display via language environment. We only want
959 to convert unibyte characters to multibyte in unibyte
960 buffers! Otherwise, the 8-bit value in CH came from the
961 display table set up to display foreign characters. */
52d38ab2 962 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
f0dd4c35
EZ
963 && (ch >= 0240
964 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
aa9ce936
EZ
965 ch = unibyte_char_to_multibyte (ch);
966
967 /* Invalid characters are displayed with a special glyph. */
04ee4f45 968 if (! CHAR_VALID_P (ch, 0))
aa9ce936
EZ
969 {
970 g = !NILP (Vdos_unsupported_char_glyph)
971 ? Vdos_unsupported_char_glyph
2d764c78 972 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
aa9ce936
EZ
973 ch = FAST_GLYPH_CHAR (g);
974 }
aa9ce936
EZ
975
976 /* If the face of this glyph is different from the current
977 screen face, update the screen attribute byte. */
978 cf = FAST_GLYPH_FACE (g);
979 if (cf != screen_face)
980 IT_set_face (cf); /* handles invalid faces gracefully */
981
04ee4f45 982 if (glyph_not_in_table || GLYPH_SIMPLE_P (tbase, tlen, g))
3b620731
EZ
983 {
984 /* We generate the multi-byte form of CH in WORKBUF. */
985 chlen = CHAR_STRING (ch, workbuf);
986 buf = workbuf;
987 }
aa9ce936
EZ
988 else
989 {
990 /* We have a string in Vglyph_table. */
991 chlen = GLYPH_LENGTH (tbase, g);
992 buf = GLYPH_STRING (tbase, g);
993 }
994
c77f6f1b 995 /* If the character is not multibyte, don't bother converting it. */
aa9ce936
EZ
996 if (chlen == 1)
997 {
998 *conversion_buffer = (unsigned char)ch;
999 chlen = 0;
1000 enclen = 1;
1001 }
1002 else
1003 {
55a17202 1004 coding->src_multibyte = 1;
aa9ce936
EZ
1005 encode_coding (coding, buf, conversion_buffer, chlen,
1006 conversion_buffer_size);
1007 chlen -= coding->consumed;
1008 enclen = coding->produced;
1009
1010 /* Replace glyph codes that cannot be converted by
1011 terminal_coding with Vdos_unsupported_char_glyph. */
1012 if (*conversion_buffer == '?')
1013 {
1014 char *cbp = conversion_buffer;
1015
1016 while (cbp < conversion_buffer + enclen && *cbp == '?')
1017 *cbp++ = unsupported_char;
1018 if (unsupported_face != screen_face)
1019 IT_set_face (unsupported_face);
1020 }
1021 }
1022
1023 if (enclen + chlen > screen_buf_end - screen_bp)
1024 {
1025 /* The allocated buffer for screen writes is too small.
1026 Flush it and loop again without incrementing STR, so
1027 that the next loop will begin with the same glyph. */
1028 int nbytes = screen_bp - screen_buf;
1029
1030 mouse_off_maybe ();
1031 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1032 if (screen_virtual_segment)
1033 dosv_refresh_virtual_screen (offset, nbytes / 2);
1034 new_pos_X += nbytes / 2;
1035 offset += nbytes;
1036
1037 /* Prepare to reuse the same buffer again. */
1038 screen_bp = screen_buf;
1039 }
1040 else
1041 {
1042 /* There's enough place in the allocated buffer to add
1043 the encoding of this glyph. */
1044
1045 /* First, copy the encoded bytes. */
1046 for (bp = conversion_buffer; enclen--; bp++)
1047 {
1048 *screen_bp++ = (unsigned char)*bp;
1049 *screen_bp++ = ScreenAttrib;
1050 if (termscript)
1051 fputc (*bp, termscript);
1052 }
1053
1054 /* Now copy the bytes not consumed by the encoding. */
1055 if (chlen > 0)
1056 {
1057 buf += coding->consumed;
1058 while (chlen--)
1059 {
1060 if (termscript)
1061 fputc (*buf, termscript);
1062 *screen_bp++ = (unsigned char)*buf++;
1063 *screen_bp++ = ScreenAttrib;
1064 }
1065 }
1066
1067 /* Update STR and its remaining length. */
1068 str++;
1069 sl--;
1070 }
1071 }
aee81730
RS
1072 }
1073
aa9ce936 1074 /* Dump whatever is left in the screen buffer. */
f32d4091 1075 mouse_off_maybe ();
aa9ce936 1076 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
039274cf 1077 if (screen_virtual_segment)
aa9ce936
EZ
1078 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1079 new_pos_X += (screen_bp - screen_buf) / 2;
1080
1081 /* We may have to output some codes to terminate the writing. */
1082 if (CODING_REQUIRE_FLUSHING (coding))
1083 {
1084 coding->mode |= CODING_MODE_LAST_BLOCK;
1085 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
1086 if (coding->produced > 0)
1087 {
241424da 1088 screen_buf = alloca (coding->produced * 2);
aa9ce936
EZ
1089 for (screen_bp = screen_buf, bp = conversion_buffer;
1090 coding->produced--; bp++)
1091 {
1092 *screen_bp++ = (unsigned char)*bp;
1093 *screen_bp++ = ScreenAttrib;
1094 if (termscript)
1095 fputc (*bp, termscript);
1096 }
1097 offset += screen_bp - screen_buf;
1098 mouse_off_maybe ();
1099 dosmemput (screen_buf, screen_bp - screen_buf,
1100 (int)ScreenPrimary + offset);
1101 if (screen_virtual_segment)
1102 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1103 new_pos_X += (screen_bp - screen_buf) / 2;
1104 }
1105 }
f32d4091 1106}
aee81730 1107
41ad069b
EZ
1108/************************************************************************
1109 Mouse Highlight (and friends..)
1110 ************************************************************************/
1111
1112/* This is used for debugging, to turn off note_mouse_highlight. */
1113int disable_mouse_highlight;
1114
48c14970
EZ
1115/* If non-nil, dos_rawgetc generates an event to display that string.
1116 (The display is done in keyboard.c:read_char, by calling
1117 show_help_echo.) */
41ad069b
EZ
1118static Lisp_Object help_echo;
1119static Lisp_Object previous_help_echo; /* a helper temporary variable */
1120
48c14970
EZ
1121/* These record the window, the object and the position where the help
1122 echo string was generated. */
1123static Lisp_Object help_echo_window;
1124static Lisp_Object help_echo_object;
1125static int help_echo_pos;
1126
41ad069b
EZ
1127static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1128
1129/* Set the mouse pointer shape according to whether it is in the
1130 area where the mouse highlight is in effect. */
1131static void
1132IT_set_mouse_pointer (int mode)
1133{
1134 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1135 many possibilities to change its shape, and the available
1136 functionality pretty much sucks (e.g., almost every reasonable
1137 shape will conceal the character it is on). Since the color of
1138 the pointer changes in the highlighted area, it is not clear to
1139 me whether anything else is required, anyway. */
1140}
1141
1142/* Display the active region described by mouse_face_*
1143 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1144static void
1145show_mouse_face (struct display_info *dpyinfo, int hl)
1146{
1147 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1148 struct frame *f = XFRAME (WINDOW_FRAME (w));
1149 int i;
1150 struct face *fp;
1151
1152
1153 /* If window is in the process of being destroyed, don't bother
1154 doing anything. */
1155 if (w->current_matrix == NULL)
1156 goto set_cursor_shape;
1157
1158 /* Recognize when we are called to operate on rows that don't exist
1159 anymore. This can happen when a window is split. */
1160 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1161 goto set_cursor_shape;
1162
1163 /* There's no sense to do anything if the mouse face isn't realized. */
1164 if (hl > 0)
1165 {
1166 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1167 if (!fp)
1168 goto set_cursor_shape;
1169 }
1170
1171 /* Note that mouse_face_beg_row etc. are window relative. */
1172 for (i = dpyinfo->mouse_face_beg_row;
1173 i <= dpyinfo->mouse_face_end_row;
1174 i++)
1175 {
1176 int start_hpos, end_hpos;
1177 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1178
1179 /* Don't do anything if row doesn't have valid contents. */
1180 if (!row->enabled_p)
1181 continue;
1182
1183 /* For all but the first row, the highlight starts at column 0. */
1184 if (i == dpyinfo->mouse_face_beg_row)
1185 start_hpos = dpyinfo->mouse_face_beg_col;
1186 else
1187 start_hpos = 0;
1188
1189 if (i == dpyinfo->mouse_face_end_row)
1190 end_hpos = dpyinfo->mouse_face_end_col;
1191 else
1192 end_hpos = row->used[TEXT_AREA];
1193
1194 if (end_hpos <= start_hpos)
1195 continue;
48c14970
EZ
1196 /* Record that some glyphs of this row are displayed in
1197 mouse-face. */
1198 row->mouse_face_p = hl > 0;
41ad069b
EZ
1199 if (hl > 0)
1200 {
1201 int vpos = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1202 int kstart = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1203 int nglyphs = end_hpos - start_hpos;
1204 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1205 int start_offset = offset;
1206
1207 if (termscript)
1208 fprintf (termscript, "\n<MH+ %d-%d:%d>",
1209 kstart, kstart + nglyphs - 1, vpos);
1210
1211 mouse_off ();
1212 IT_set_face (dpyinfo->mouse_face_face_id);
1213 /* Since we are going to change only the _colors_ of the
1214 displayed text, there's no need to go through all the
1215 pain of generating and encoding the text from the glyphs.
1216 Instead, we simply poke the attribute byte of each
1217 affected position in video memory with the colors
1218 computed by IT_set_face! */
1219 _farsetsel (_dos_ds);
1220 while (nglyphs--)
1221 {
1222 _farnspokeb (offset, ScreenAttrib);
1223 offset += 2;
1224 }
1225 if (screen_virtual_segment)
1226 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1227 mouse_on ();
1228 }
1229 else
1230 {
1231 /* We are removing a previously-drawn mouse highlight. The
1232 safest way to do so is to redraw the glyphs anew, since
1233 all kinds of faces and display tables could have changed
1234 behind our back. */
1235 int nglyphs = end_hpos - start_hpos;
1236 int save_x = new_pos_X, save_y = new_pos_Y;
1237
1238 if (end_hpos >= row->used[TEXT_AREA])
1239 nglyphs = row->used[TEXT_AREA] - start_hpos;
1240
1241 /* IT_write_glyphs writes at cursor position, so we need to
1242 temporarily move cursor coordinates to the beginning of
1243 the highlight region. */
1244 new_pos_X = start_hpos + WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1245 new_pos_Y = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1246
1247 if (termscript)
1248 fprintf (termscript, "<MH- %d-%d:%d>",
1249 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1250 IT_write_glyphs (row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1251 if (termscript)
1252 fputs ("\n", termscript);
1253 new_pos_X = save_x;
1254 new_pos_Y = save_y;
1255 }
1256 }
1257
1258 set_cursor_shape:
1259
1260 /* Change the mouse pointer shape. */
1261 IT_set_mouse_pointer (hl);
1262}
1263
1264/* Clear out the mouse-highlighted active region.
1265 Redraw it un-highlighted first. */
1266static void
1267clear_mouse_face (struct display_info *dpyinfo)
1268{
1269 if (! NILP (dpyinfo->mouse_face_window))
1270 show_mouse_face (dpyinfo, 0);
1271
1272 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1273 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1274 dpyinfo->mouse_face_window = Qnil;
1275}
1276
1277/* Find the glyph matrix position of buffer position POS in window W.
1278 *HPOS and *VPOS are set to the positions found. W's current glyphs
1279 must be up to date. If POS is above window start return (0, 0).
1280 If POS is after end of W, return end of last line in W. */
1281static int
1282fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1283{
1284 int i;
1285 int lastcol;
1286 int maybe_next_line_p = 0;
1287 int line_start_position;
1288 int yb = window_text_bottom_y (w);
1289 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
1290 struct glyph_row *best_row = row;
1291
1292 while (row->y < yb)
1293 {
1294 if (row->used[TEXT_AREA])
1295 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1296 else
1297 line_start_position = 0;
1298
1299 if (line_start_position > pos)
1300 break;
1301 /* If the position sought is the end of the buffer,
1302 don't include the blank lines at the bottom of the window. */
1303 else if (line_start_position == pos
1304 && pos == BUF_ZV (XBUFFER (w->buffer)))
1305 {
1306 maybe_next_line_p = 1;
1307 break;
1308 }
1309 else if (line_start_position > 0)
1310 best_row = row;
1311
1312 ++row;
1313 }
1314
1315 /* Find the right column within BEST_ROW. */
1316 lastcol = 0;
1317 row = best_row;
1318 for (i = 0; i < row->used[TEXT_AREA]; i++)
1319 {
1320 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1321 int charpos;
1322
1323 charpos = glyph->charpos;
1324 if (charpos == pos)
1325 {
1326 *hpos = i;
1327 *vpos = row->y;
1328 return 1;
1329 }
1330 else if (charpos > pos)
1331 break;
1332 else if (charpos > 0)
1333 lastcol = i;
1334 }
1335
1336 /* If we're looking for the end of the buffer,
1337 and we didn't find it in the line we scanned,
1338 use the start of the following line. */
1339 if (maybe_next_line_p)
1340 {
1341 ++row;
1342 lastcol = 0;
1343 }
1344
1345 *vpos = row->y;
1346 *hpos = lastcol + 1;
1347 return 0;
1348}
1349
1350/* Take proper action when mouse has moved to the mode or top line of
1351 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1352 mode line. X is relative to the start of the text display area of
1353 W, so the width of bitmap areas and scroll bars must be subtracted
1354 to get a position relative to the start of the mode line. */
1355static void
1356IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1357{
1358 struct frame *f = XFRAME (w->frame);
1359 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1360 struct glyph_row *row;
1361
1362 if (mode_line_p)
1363 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1364 else
1365 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1366
1367 if (row->enabled_p)
1368 {
1369 extern Lisp_Object Qhelp_echo;
1370 struct glyph *glyph, *end;
1371 Lisp_Object help, map;
1372
1373 /* Find the glyph under X. */
1374 glyph = row->glyphs[TEXT_AREA]
1375 + x - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
1376 end = glyph + row->used[TEXT_AREA];
1377 if (glyph < end
1378 && STRINGP (glyph->object)
1379 && XSTRING (glyph->object)->intervals
1380 && glyph->charpos >= 0
1381 && glyph->charpos < XSTRING (glyph->object)->size)
1382 {
1383 /* If we're on a string with `help-echo' text property,
1384 arrange for the help to be displayed. This is done by
1385 setting the global variable help_echo to the help string. */
1386 help = Fget_text_property (make_number (glyph->charpos),
1387 Qhelp_echo, glyph->object);
b7e80413 1388 if (!NILP (help))
48c14970
EZ
1389 {
1390 help_echo = help;
1391 XSETWINDOW (help_echo_window, w);
1392 help_echo_object = glyph->object;
1393 help_echo_pos = glyph->charpos;
1394 }
41ad069b
EZ
1395 }
1396 }
1397}
1398
1399/* Take proper action when the mouse has moved to position X, Y on
1400 frame F as regards highlighting characters that have mouse-face
1401 properties. Also de-highlighting chars where the mouse was before.
1402 X and Y can be negative or out of range. */
1403static void
1404IT_note_mouse_highlight (struct frame *f, int x, int y)
1405{
1406 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1407 int portion;
1408 Lisp_Object window;
1409 struct window *w;
1410
1411 /* When a menu is active, don't highlight because this looks odd. */
1412 if (mouse_preempted)
1413 return;
1414
515d0d0e
EZ
1415 if (disable_mouse_highlight
1416 || !f->glyphs_initialized_p)
41ad069b
EZ
1417 return;
1418
1419 dpyinfo->mouse_face_mouse_x = x;
1420 dpyinfo->mouse_face_mouse_y = y;
1421 dpyinfo->mouse_face_mouse_frame = f;
1422
1423 if (dpyinfo->mouse_face_defer)
1424 return;
1425
1426 if (gc_in_progress)
1427 {
1428 dpyinfo->mouse_face_deferred_gc = 1;
1429 return;
1430 }
1431
1432 /* Which window is that in? */
1433 window = window_from_coordinates (f, x, y, &portion, 0);
1434
1435 /* If we were displaying active text in another window, clear that. */
1436 if (! EQ (window, dpyinfo->mouse_face_window))
1437 clear_mouse_face (dpyinfo);
1438
1439 /* Not on a window -> return. */
1440 if (!WINDOWP (window))
1441 return;
1442
1443 /* Convert to window-relative coordinates. */
1444 w = XWINDOW (window);
1445 x -= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
1446 y -= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
1447
1448 if (portion == 1 || portion == 3)
1449 {
1450 /* Mouse is on the mode or top line. */
1451 IT_note_mode_line_highlight (w, x, portion == 1);
1452 return;
1453 }
1454 else
1455 IT_set_mouse_pointer (0);
1456
1457 /* Are we in a window whose display is up to date?
1458 And verify the buffer's text has not changed. */
1459 if (/* Within text portion of the window. */
1460 portion == 0
1461 && EQ (w->window_end_valid, w->buffer)
1462 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1463 && (XFASTINT (w->last_overlay_modified)
1464 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1465 {
1466 int pos, i, area;
1467 struct glyph_row *row;
1468 struct glyph *glyph;
1469
1470 /* Find the glyph under X/Y. */
1471 glyph = NULL;
1472 if (y < w->current_matrix->nrows)
1473 {
1474 row = MATRIX_ROW (w->current_matrix, y);
1475 if (row->enabled_p
1476 && row->displays_text_p
1477 && x < window_box_width (w, TEXT_AREA))
1478 {
1479 glyph = row->glyphs[TEXT_AREA];
1480 if (x >= row->used[TEXT_AREA])
1481 glyph = NULL;
1482 else
1483 {
1484 glyph += x;
1485 if (!BUFFERP (glyph->object))
1486 glyph = NULL;
1487 }
1488 }
1489 }
1490
1491 /* Clear mouse face if X/Y not over text. */
1492 if (glyph == NULL)
1493 {
1494 clear_mouse_face (dpyinfo);
1495 return;
1496 }
1497
1498 if (!BUFFERP (glyph->object))
1499 abort ();
1500 pos = glyph->charpos;
1501
1502 /* Check for mouse-face and help-echo. */
1503 {
1504 extern Lisp_Object Qmouse_face;
1505 Lisp_Object mouse_face, overlay, position;
1506 Lisp_Object *overlay_vec;
1507 int len, noverlays;
1508 struct buffer *obuf;
1509 int obegv, ozv;
1510
1511 /* If we get an out-of-range value, return now; avoid an error. */
1512 if (pos > BUF_Z (XBUFFER (w->buffer)))
1513 return;
1514
1515 /* Make the window's buffer temporarily current for
1516 overlays_at and compute_char_face. */
1517 obuf = current_buffer;
1518 current_buffer = XBUFFER (w->buffer);
1519 obegv = BEGV;
1520 ozv = ZV;
1521 BEGV = BEG;
1522 ZV = Z;
1523
1524 /* Is this char mouse-active or does it have help-echo? */
1525 XSETINT (position, pos);
1526
1527 /* Put all the overlays we want in a vector in overlay_vec.
1528 Store the length in len. If there are more than 10, make
1529 enough space for all, and try again. */
1530 len = 10;
1531 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1532 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1533 if (noverlays > len)
1534 {
1535 len = noverlays;
1536 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1537 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
1538 }
1539
1540 noverlays = sort_overlays (overlay_vec, noverlays, w);
1541
1542 /* Check mouse-face highlighting. */
1543 if (! (EQ (window, dpyinfo->mouse_face_window)
1544 && y >= dpyinfo->mouse_face_beg_row
1545 && y <= dpyinfo->mouse_face_end_row
1546 && (y > dpyinfo->mouse_face_beg_row
1547 || x >= dpyinfo->mouse_face_beg_col)
1548 && (y < dpyinfo->mouse_face_end_row
1549 || x < dpyinfo->mouse_face_end_col
1550 || dpyinfo->mouse_face_past_end)))
1551 {
1552 /* Clear the display of the old active region, if any. */
1553 clear_mouse_face (dpyinfo);
1554
1555 /* Find highest priority overlay that has a mouse-face prop. */
1556 overlay = Qnil;
1557 for (i = 0; i < noverlays; i++)
1558 {
1559 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1560 if (!NILP (mouse_face))
1561 {
1562 overlay = overlay_vec[i];
1563 break;
1564 }
1565 }
1566
1567 /* If no overlay applies, get a text property. */
1568 if (NILP (overlay))
1569 mouse_face = Fget_text_property (position, Qmouse_face,
1570 w->buffer);
1571
1572 /* Handle the overlay case. */
1573 if (! NILP (overlay))
1574 {
1575 /* Find the range of text around this char that
1576 should be active. */
1577 Lisp_Object before, after;
1578 int ignore;
1579
1580 before = Foverlay_start (overlay);
1581 after = Foverlay_end (overlay);
1582 /* Record this as the current active region. */
1583 fast_find_position (w, XFASTINT (before),
1584 &dpyinfo->mouse_face_beg_col,
1585 &dpyinfo->mouse_face_beg_row);
1586 dpyinfo->mouse_face_past_end
1587 = !fast_find_position (w, XFASTINT (after),
1588 &dpyinfo->mouse_face_end_col,
1589 &dpyinfo->mouse_face_end_row);
1590 dpyinfo->mouse_face_window = window;
1591 dpyinfo->mouse_face_face_id
1592 = face_at_buffer_position (w, pos, 0, 0,
1593 &ignore, pos + 1, 1);
1594
1595 /* Display it as active. */
1596 show_mouse_face (dpyinfo, 1);
1597 }
1598 /* Handle the text property case. */
1599 else if (! NILP (mouse_face))
1600 {
1601 /* Find the range of text around this char that
1602 should be active. */
1603 Lisp_Object before, after, beginning, end;
1604 int ignore;
1605
1606 beginning = Fmarker_position (w->start);
1607 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1608 - XFASTINT (w->window_end_pos)));
1609 before
1610 = Fprevious_single_property_change (make_number (pos + 1),
1611 Qmouse_face,
1612 w->buffer, beginning);
1613 after
1614 = Fnext_single_property_change (position, Qmouse_face,
1615 w->buffer, end);
1616 /* Record this as the current active region. */
1617 fast_find_position (w, XFASTINT (before),
1618 &dpyinfo->mouse_face_beg_col,
1619 &dpyinfo->mouse_face_beg_row);
1620 dpyinfo->mouse_face_past_end
1621 = !fast_find_position (w, XFASTINT (after),
1622 &dpyinfo->mouse_face_end_col,
1623 &dpyinfo->mouse_face_end_row);
1624 dpyinfo->mouse_face_window = window;
1625 dpyinfo->mouse_face_face_id
1626 = face_at_buffer_position (w, pos, 0, 0,
1627 &ignore, pos + 1, 1);
1628
1629 /* Display it as active. */
1630 show_mouse_face (dpyinfo, 1);
1631 }
1632 }
1633
1634 /* Look for a `help-echo' property. */
1635 {
1636 Lisp_Object help;
1637 extern Lisp_Object Qhelp_echo;
1638
1639 /* Check overlays first. */
1640 help = Qnil;
b7e80413 1641 for (i = 0; i < noverlays && NILP (help); ++i)
41ad069b
EZ
1642 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
1643
b7e80413 1644 if (!NILP (help))
48c14970
EZ
1645 {
1646 help_echo = help;
1647 help_echo_window = window;
1648 help_echo_object = w->buffer;
1649 help_echo_pos = pos;
1650 }
1651 /* Try text properties. */
1652 else if (NILP (help)
1653 && ((STRINGP (glyph->object)
1654 && glyph->charpos >= 0
1655 && glyph->charpos < XSTRING (glyph->object)->size)
1656 || (BUFFERP (glyph->object)
1657 && glyph->charpos >= BEGV
1658 && glyph->charpos < ZV)))
1659 {
1660 help = Fget_text_property (make_number (glyph->charpos),
1661 Qhelp_echo, glyph->object);
1662 if (!NILP (help))
1663 {
1664 help_echo = help;
1665 help_echo_window = window;
1666 help_echo_object = glyph->object;
1667 help_echo_pos = glyph->charpos;
1668 }
1669 }
41ad069b
EZ
1670 }
1671
1672 BEGV = obegv;
1673 ZV = ozv;
1674 current_buffer = obuf;
1675 }
1676 }
1677}
1678
71f65669
EZ
1679static void
1680IT_clear_end_of_line (int first_unused)
f32d4091
KS
1681{
1682 char *spaces, *sp;
1683 int i, j;
039274cf 1684 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
aa9ce936
EZ
1685 extern int fatal_error_in_progress;
1686
2d764c78 1687 if (new_pos_X >= first_unused || fatal_error_in_progress)
aa9ce936 1688 return;
f32d4091
KS
1689
1690 IT_set_face (0);
2d764c78 1691 i = (j = first_unused - new_pos_X) * 2;
e25d9653
EZ
1692 if (termscript)
1693 fprintf (termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
f32d4091 1694 spaces = sp = alloca (i);
aee81730 1695
f32d4091 1696 while (--j >= 0)
aee81730 1697 {
f32d4091
KS
1698 *sp++ = ' ';
1699 *sp++ = ScreenAttrib;
aee81730
RS
1700 }
1701
f32d4091 1702 mouse_off_maybe ();
039274cf
EZ
1703 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1704 if (screen_virtual_segment)
1705 dosv_refresh_virtual_screen (offset, i / 2);
2d764c78
EZ
1706
1707 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1708 Let's follow their lead, in case someone relies on this. */
1709 new_pos_X = first_unused;
aee81730
RS
1710}
1711
71f65669 1712static void
f32d4091
KS
1713IT_clear_screen (void)
1714{
1715 if (termscript)
1716 fprintf (termscript, "<CLR:SCR>");
1717 IT_set_face (0);
1718 mouse_off ();
1719 ScreenClear ();
039274cf
EZ
1720 if (screen_virtual_segment)
1721 dosv_refresh_virtual_screen (0, screen_size);
f32d4091
KS
1722 new_pos_X = new_pos_Y = 0;
1723}
1724
71f65669 1725static void
f32d4091
KS
1726IT_clear_to_end (void)
1727{
1728 if (termscript)
1729 fprintf (termscript, "<CLR:EOS>");
1730
1731 while (new_pos_Y < screen_size_Y) {
1732 new_pos_X = 0;
e25d9653 1733 IT_clear_end_of_line (screen_size_X);
f32d4091
KS
1734 new_pos_Y++;
1735 }
1736}
1737
71f65669 1738static void
f32d4091
KS
1739IT_cursor_to (int y, int x)
1740{
1741 if (termscript)
1742 fprintf (termscript, "\n<XY=%dx%d>", x, y);
1743 new_pos_X = x;
1744 new_pos_Y = y;
1745}
1746
fc171623
KH
1747static int cursor_cleared;
1748
d1d5dc19 1749static void
fc171623
KH
1750IT_display_cursor (int on)
1751{
1752 if (on && cursor_cleared)
1753 {
1754 ScreenSetCursor (current_pos_Y, current_pos_X);
1755 cursor_cleared = 0;
1756 }
1757 else if (!on && !cursor_cleared)
1758 {
1759 ScreenSetCursor (-1, -1);
1760 cursor_cleared = 1;
1761 }
1762}
1763
1764/* Emacs calls cursor-movement functions a lot when it updates the
1765 display (probably a legacy of old terminals where you cannot
1766 update a screen line without first moving the cursor there).
1767 However, cursor movement is expensive on MSDOS (it calls a slow
1768 BIOS function and requires 2 mode switches), while actual screen
1769 updates access the video memory directly and don't depend on
1770 cursor position. To avoid slowing down the redisplay, we cheat:
1771 all functions that move the cursor only set internal variables
1772 which record the cursor position, whereas the cursor is only
1773 moved to its final position whenever screen update is complete.
1774
1775 `IT_cmgoto' is called from the keyboard reading loop and when the
1776 frame update is complete. This means that we are ready for user
1777 input, so we update the cursor position to show where the point is,
1778 and also make the mouse pointer visible.
1779
1780 Special treatment is required when the cursor is in the echo area,
1781 to put the cursor at the end of the text displayed there. */
1782
71f65669
EZ
1783static void
1784IT_cmgoto (FRAME_PTR f)
fc171623
KH
1785{
1786 /* Only set the cursor to where it should be if the display is
1787 already in sync with the window contents. */
2d764c78
EZ
1788 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1789
1790 /* FIXME: This needs to be rewritten for the new redisplay, or
1791 removed. */
1792#if 0
06da1de1
EZ
1793 static int previous_pos_X = -1;
1794
2d764c78
EZ
1795 update_cursor_pos = 1; /* temporary!!! */
1796
06da1de1
EZ
1797 /* If the display is in sync, forget any previous knowledge about
1798 cursor position. This is primarily for unexpected events like
1799 C-g in the minibuffer. */
1800 if (update_cursor_pos && previous_pos_X >= 0)
1801 previous_pos_X = -1;
1802 /* If we are in the echo area, put the cursor at the
1803 end of the echo area message. */
fc171623
KH
1804 if (!update_cursor_pos
1805 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1806 {
06da1de1
EZ
1807 int tem_X = current_pos_X, dummy;
1808
1809 if (echo_area_glyphs)
1810 {
1811 tem_X = echo_area_glyphs_length;
1812 /* Save current cursor position, to be restored after the
1813 echo area message is erased. Only remember one level
1814 of previous cursor position. */
1815 if (previous_pos_X == -1)
1816 ScreenGetCursor (&dummy, &previous_pos_X);
1817 }
1818 else if (previous_pos_X >= 0)
1819 {
1820 /* We wind up here after the echo area message is erased.
1821 Restore the cursor position we remembered above. */
1822 tem_X = previous_pos_X;
1823 previous_pos_X = -1;
1824 }
9a599a60 1825
06da1de1 1826 if (current_pos_X != tem_X)
9a599a60
EZ
1827 {
1828 new_pos_X = tem_X;
1829 update_cursor_pos = 1;
1830 }
fc171623 1831 }
2d764c78 1832#endif
fc171623
KH
1833
1834 if (update_cursor_pos
1835 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1836 {
1837 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1838 if (termscript)
1839 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1840 }
1841
1842 /* Maybe cursor is invisible, so make it visible. */
1843 IT_display_cursor (1);
1844
1845 /* Mouse pointer should be always visible if we are waiting for
1846 keyboard input. */
1847 if (!mouse_visible)
1848 mouse_on ();
1849}
1850
71f65669
EZ
1851static void
1852IT_reassert_line_highlight (int new, int vpos)
f32d4091
KS
1853{
1854 highlight = new;
f32d4091
KS
1855}
1856
71f65669 1857static void
c77f6f1b 1858IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1b94449f 1859{
f32d4091 1860 highlight = new_highlight;
f32d4091
KS
1861 IT_cursor_to (vpos, 0);
1862 IT_clear_end_of_line (first_unused_hpos);
1863}
1864
71f65669 1865static void
41ad069b 1866IT_update_begin (struct frame *f)
f32d4091 1867{
41ad069b
EZ
1868 struct display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1869
f32d4091 1870 highlight = 0;
41ad069b
EZ
1871
1872 BLOCK_INPUT;
1873
1874 if (f == display_info->mouse_face_mouse_frame)
1875 {
1876 /* Don't do highlighting for mouse motion during the update. */
1877 display_info->mouse_face_defer = 1;
1878
1879 /* If F needs to be redrawn, simply forget about any prior mouse
1880 highlighting. */
1881 if (FRAME_GARBAGED_P (f))
1882 display_info->mouse_face_window = Qnil;
1883
1884 /* Can we tell that this update does not affect the window
1885 where the mouse highlight is? If so, no need to turn off.
48c14970
EZ
1886 Likewise, don't do anything if none of the enabled rows
1887 contains glyphs highlighted in mouse face. */
8ccb9a54
EZ
1888 if (!NILP (display_info->mouse_face_window)
1889 && WINDOWP (display_info->mouse_face_window))
41ad069b
EZ
1890 {
1891 struct window *w = XWINDOW (display_info->mouse_face_window);
1892 int i;
1893
8ccb9a54
EZ
1894 /* If the mouse highlight is in the window that was deleted
1895 (e.g., if it was popped by completion), clear highlight
1896 unconditionally. */
1897 if (NILP (w->buffer))
1898 display_info->mouse_face_window = Qnil;
1899 else
1900 {
1901 for (i = 0; i < w->desired_matrix->nrows; ++i)
48c14970
EZ
1902 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1903 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
8ccb9a54
EZ
1904 break;
1905 }
41ad069b 1906
8ccb9a54 1907 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
41ad069b
EZ
1908 clear_mouse_face (display_info);
1909 }
1910 }
1911 else if (!FRAME_LIVE_P (display_info->mouse_face_mouse_frame))
1912 {
1913 /* If the frame with mouse highlight was deleted, invalidate the
1914 highlight info. */
1915 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1916 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1917 display_info->mouse_face_window = Qnil;
1918 display_info->mouse_face_deferred_gc = 0;
1919 display_info->mouse_face_mouse_frame = NULL;
1920 }
1921
1922 UNBLOCK_INPUT;
f32d4091
KS
1923}
1924
71f65669 1925static void
41ad069b 1926IT_update_end (struct frame *f)
f32d4091 1927{
41ad069b
EZ
1928 highlight = 0;
1929 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
1930}
1931
8ba01a32
EZ
1932Lisp_Object Qcursor_type;
1933
41ad069b
EZ
1934static void
1935IT_frame_up_to_date (struct frame *f)
1936{
1937 struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
0c3cfc51
EZ
1938 Lisp_Object new_cursor, frame_desired_cursor;
1939 struct window *sw;
41ad069b
EZ
1940
1941 if (dpyinfo->mouse_face_deferred_gc
1942 || f == dpyinfo->mouse_face_mouse_frame)
1943 {
1944 BLOCK_INPUT;
1945 if (dpyinfo->mouse_face_mouse_frame)
1946 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1947 dpyinfo->mouse_face_mouse_x,
1948 dpyinfo->mouse_face_mouse_y);
1949 dpyinfo->mouse_face_deferred_gc = 0;
1950 UNBLOCK_INPUT;
1951 }
1952
0c3cfc51
EZ
1953 /* Set the cursor type to whatever they wanted. In a minibuffer
1954 window, we want the cursor to appear only if we are reading input
1955 from this window, and we want the cursor to be taken from the
1956 frame parameters. For the selected window, we use either its
1957 buffer-local value or the value from the frame parameters if the
1958 buffer doesn't define its local value for the cursor type. */
1959 sw = XWINDOW (f->selected_window);
1960 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1961 if (cursor_in_echo_area
1962 && FRAME_HAS_MINIBUF_P (f)
1963 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1964 && sw == XWINDOW (echo_area_window))
1965 new_cursor = frame_desired_cursor;
1966 else
1967 {
1968 struct buffer *b = XBUFFER (sw->buffer);
1969
1970 if (EQ (b->cursor_type, Qt))
1971 new_cursor = frame_desired_cursor;
1972 else if (NILP (b->cursor_type)) /* nil means no cursor */
1973 new_cursor = Fcons (Qbar, make_number (0));
1974 else
1975 new_cursor = b->cursor_type;
1976 }
1977
1978 IT_set_cursor_type (f, new_cursor);
8ba01a32 1979
41ad069b 1980 IT_cmgoto (f); /* position cursor when update is done */
f32d4091 1981}
1b94449f 1982
c77f6f1b
EZ
1983/* Copy LEN glyphs displayed on a single line whose vertical position
1984 is YPOS, beginning at horizontal position XFROM to horizontal
1985 position XTO, by moving blocks in the video memory. Used by
1986 functions that insert and delete glyphs. */
1987static void
1988IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1989{
1990 /* The offsets of source and destination relative to the
1991 conventional memorty selector. */
1992 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1993 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1994
1995 if (from == to || len <= 0)
1996 return;
1997
1998 _farsetsel (_dos_ds);
1999
2000 /* The source and destination might overlap, so we need to move
2001 glyphs non-destructively. */
2002 if (from > to)
2003 {
2004 for ( ; len; from += 2, to += 2, len--)
2005 _farnspokew (to, _farnspeekw (from));
2006 }
2007 else
2008 {
2009 from += (len - 1) * 2;
2010 to += (len - 1) * 2;
2011 for ( ; len; from -= 2, to -= 2, len--)
2012 _farnspokew (to, _farnspeekw (from));
2013 }
2014 if (screen_virtual_segment)
2015 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
2016}
2017
2018/* Insert and delete glyphs. */
aa9ce936
EZ
2019static void
2020IT_insert_glyphs (start, len)
c77f6f1b 2021 register struct glyph *start;
aa9ce936
EZ
2022 register int len;
2023{
c77f6f1b
EZ
2024 int shift_by_width = screen_size_X - (new_pos_X + len);
2025
2026 /* Shift right the glyphs from the nominal cursor position to the
2027 end of this line. */
2028 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
2029
2030 /* Now write the glyphs to be inserted. */
2031 IT_write_glyphs (start, len);
aa9ce936
EZ
2032}
2033
2034static void
2035IT_delete_glyphs (n)
2036 register int n;
2037{
2038 abort ();
2039}
2040
211c7152 2041/* set-window-configuration on window.c needs this. */
3bb1f22f
RS
2042void
2043x_set_menu_bar_lines (f, value, oldval)
2044 struct frame *f;
2045 Lisp_Object value, oldval;
2046{
211c7152
EZ
2047 set_menu_bar_lines (f, value, oldval);
2048}
3bb1f22f 2049
211c7152 2050/* This was copied from xfns.c */
3bb1f22f 2051
211c7152
EZ
2052Lisp_Object Qbackground_color;
2053Lisp_Object Qforeground_color;
8ba01a32 2054Lisp_Object Qreverse;
211c7152 2055extern Lisp_Object Qtitle;
3bb1f22f 2056
48ffe371
RS
2057/* IT_set_terminal_modes is called when emacs is started,
2058 resumed, and whenever the screen is redrawn! */
f32d4091 2059
71f65669 2060static void
f32d4091
KS
2061IT_set_terminal_modes (void)
2062{
aee81730 2063 if (termscript)
f32d4091
KS
2064 fprintf (termscript, "\n<SET_TERM>");
2065 highlight = 0;
2066
2067 screen_size_X = ScreenCols ();
2068 screen_size_Y = ScreenRows ();
2069 screen_size = screen_size_X * screen_size_Y;
aee81730 2070
f32d4091
KS
2071 new_pos_X = new_pos_Y = 0;
2072 current_pos_X = current_pos_Y = -1;
2073
2074 if (term_setup_done)
2075 return;
2076 term_setup_done = 1;
aee81730 2077
f32d4091
KS
2078 startup_screen_size_X = screen_size_X;
2079 startup_screen_size_Y = screen_size_Y;
c9adab25 2080 startup_screen_attrib = ScreenAttrib;
f32d4091 2081
039274cf
EZ
2082#if __DJGPP__ > 1
2083 /* Is DOS/V (or any other RSIS software which relocates
2084 the screen) installed? */
2085 {
2086 unsigned short es_value;
2087 __dpmi_regs regs;
2088
2089 regs.h.ah = 0xfe; /* get relocated screen address */
2090 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2091 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2092 else if (screen_old_address) /* already switched to Japanese mode once */
2093 regs.x.es = (screen_old_address >> 4) & 0xffff;
2094 else
2095 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2096 regs.x.di = 0;
2097 es_value = regs.x.es;
2098 __dpmi_int (0x10, &regs);
2099
d1d5dc19 2100 if (regs.x.es != es_value)
039274cf 2101 {
d1d5dc19
EZ
2102 /* screen_old_address is only set if ScreenPrimary does NOT
2103 already point to the relocated buffer address returned by
2104 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2105 ScreenPrimary to that address at startup under DOS/V. */
2106 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2107 screen_old_address = ScreenPrimary;
039274cf
EZ
2108 screen_virtual_segment = regs.x.es;
2109 screen_virtual_offset = regs.x.di;
2110 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2111 }
2112 }
2113#endif /* __DJGPP__ > 1 */
2114
f32d4091
KS
2115 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2116 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2117
2118 if (termscript)
c9adab25 2119 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
039274cf 2120 screen_size_X, screen_size_Y);
76ac1508
RS
2121
2122 bright_bg ();
f32d4091
KS
2123}
2124
48ffe371
RS
2125/* IT_reset_terminal_modes is called when emacs is
2126 suspended or killed. */
f32d4091 2127
71f65669 2128static void
f32d4091
KS
2129IT_reset_terminal_modes (void)
2130{
c9adab25
KH
2131 int display_row_start = (int) ScreenPrimary;
2132 int saved_row_len = startup_screen_size_X * 2;
2133 int update_row_len = ScreenCols () * 2;
2134 int current_rows = ScreenRows ();
2135 int to_next_row = update_row_len;
2136 unsigned char *saved_row = startup_screen_buffer;
2137 int cursor_pos_X = ScreenCols () - 1;
2138 int cursor_pos_Y = ScreenRows () - 1;
2139
f32d4091 2140 if (termscript)
5063b150 2141 fprintf (termscript, "\n<RESET_TERM>");
f32d4091
KS
2142
2143 highlight = 0;
2144
2145 if (!term_setup_done)
2146 return;
2147
c9adab25 2148 mouse_off ();
b36701cc
RS
2149
2150 /* Leave the video system in the same state as we found it,
2151 as far as the blink/bright-background bit is concerned. */
2152 maybe_enable_blinking ();
06b1ea13 2153
c9adab25
KH
2154 /* We have a situation here.
2155 We cannot just do ScreenUpdate(startup_screen_buffer) because
2156 the luser could have changed screen dimensions inside Emacs
2157 and failed (or didn't want) to restore them before killing
2158 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2159 thus will happily use memory outside what was allocated for
2160 `startup_screen_buffer'.
2161 Thus we only restore as much as the current screen dimensions
2162 can hold, and clear the rest (if the saved screen is smaller than
2163 the current) with the color attribute saved at startup. The cursor
2164 is also restored within the visible dimensions. */
2165
2166 ScreenAttrib = startup_screen_attrib;
c9adab25 2167
06b1ea13
EZ
2168 /* Don't restore the screen if we are exiting less than 2 seconds
2169 after startup: we might be crashing, and the screen might show
2170 some vital clues to what's wrong. */
2171 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
c9adab25 2172 {
06b1ea13 2173 ScreenClear ();
039274cf 2174 if (screen_virtual_segment)
06b1ea13
EZ
2175 dosv_refresh_virtual_screen (0, screen_size);
2176
2177 if (update_row_len > saved_row_len)
2178 update_row_len = saved_row_len;
2179 if (current_rows > startup_screen_size_Y)
2180 current_rows = startup_screen_size_Y;
2181
2182 if (termscript)
2183 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2184 update_row_len / 2, current_rows);
2185
2186 while (current_rows--)
2187 {
2188 dosmemput (saved_row, update_row_len, display_row_start);
2189 if (screen_virtual_segment)
2190 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2191 update_row_len / 2);
2192 saved_row += saved_row_len;
2193 display_row_start += to_next_row;
2194 }
c9adab25
KH
2195 }
2196 if (startup_pos_X < cursor_pos_X)
2197 cursor_pos_X = startup_pos_X;
2198 if (startup_pos_Y < cursor_pos_Y)
2199 cursor_pos_Y = startup_pos_Y;
2200
2201 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2202 xfree (startup_screen_buffer);
f32d4091
KS
2203
2204 term_setup_done = 0;
2205}
2206
71f65669
EZ
2207static void
2208IT_set_terminal_window (int foo)
f32d4091
KS
2209{
2210}
2211
2d764c78
EZ
2212/* Remember the screen colors of the curent frame, to serve as the
2213 default colors for newly-created frames. */
2214
2215static int initial_screen_colors[2];
2216
2217DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2218 Smsdos_remember_default_colors, 1, 1, 0,
2219 "Remember the screen colors of the current frame.")
2220 (frame)
2221 Lisp_Object frame;
2222{
2223 int reverse;
2224 struct frame *f;
2225
2226 CHECK_FRAME (frame, 0);
2227 f= XFRAME (frame);
2228 reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
2229
2230 initial_screen_colors[0]
2231 = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
2232 initial_screen_colors[1]
2233 = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
2234}
2235
f32d4091 2236void
3bb1f22f 2237IT_set_frame_parameters (f, alist)
c77f6f1b 2238 struct frame *f;
f32d4091
KS
2239 Lisp_Object alist;
2240{
2241 Lisp_Object tail;
db722735 2242 int length = XINT (Flength (alist));
2d764c78 2243 int i, j;
db722735
RS
2244 Lisp_Object *parms
2245 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2246 Lisp_Object *values
2247 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2d764c78 2248 /* Do we have to reverse the foreground and background colors? */
8ba01a32 2249 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2d764c78
EZ
2250 int was_reverse = reverse;
2251 int redraw = 0, fg_set = 0, bg_set = 0;
2252 unsigned long orig_fg;
2253 unsigned long orig_bg;
2254
2255 /* If we are creating a new frame, begin with the original screen colors
2256 used for the initial frame. */
2257 if (alist == Vdefault_frame_alist
2258 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2259 {
2260 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2261 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2262 }
2263 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2264 orig_bg = FRAME_BACKGROUND_PIXEL (f);
db722735
RS
2265
2266 /* Extract parm names and values into those vectors. */
2267 i = 0;
f32d4091
KS
2268 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2269 {
db722735 2270 Lisp_Object elt;
f32d4091
KS
2271
2272 elt = Fcar (tail);
db722735
RS
2273 parms[i] = Fcar (elt);
2274 CHECK_SYMBOL (parms[i], 1);
2275 values[i] = Fcdr (elt);
2276 i++;
2277 }
2278
2d764c78 2279 j = i;
db722735 2280
2d764c78
EZ
2281 for (i = 0; i < j; i++)
2282 {
2283 Lisp_Object prop = parms[i];
2284 Lisp_Object val = values[i];
2285
8ba01a32 2286 if (EQ (prop, Qreverse))
2d764c78
EZ
2287 reverse = EQ (val, Qt);
2288 }
2289
2290 if (termscript && reverse && !was_reverse)
2291 fprintf (termscript, "<INVERSE-VIDEO>\n");
2292
2293 /* Now process the alist elements in reverse of specified order. */
db722735
RS
2294 for (i--; i >= 0; i--)
2295 {
2296 Lisp_Object prop = parms[i];
2297 Lisp_Object val = values[i];
f32d4091 2298
4e825084 2299 if (EQ (prop, Qforeground_color))
f32d4091 2300 {
2d764c78
EZ
2301 unsigned long new_color = load_color (f, NULL, val, reverse
2302 ? LFACE_BACKGROUND_INDEX
2303 : LFACE_FOREGROUND_INDEX);
3b620731
EZ
2304 if (new_color != FACE_TTY_DEFAULT_COLOR
2305 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2306 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
f32d4091 2307 {
2d764c78
EZ
2308 if (reverse)
2309 /* FIXME: should the fore-/background of the default
2310 face change here as well? */
2311 FRAME_BACKGROUND_PIXEL (f) = new_color;
2312 else
2313 FRAME_FOREGROUND_PIXEL (f) = new_color;
f32d4091 2314 redraw = 1;
2d764c78 2315 fg_set = 1;
76ac1508 2316 if (termscript)
a7cf9151 2317 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
f32d4091
KS
2318 }
2319 }
4e825084 2320 else if (EQ (prop, Qbackground_color))
f32d4091 2321 {
2d764c78
EZ
2322 unsigned long new_color = load_color (f, NULL, val, reverse
2323 ? LFACE_FOREGROUND_INDEX
2324 : LFACE_BACKGROUND_INDEX);
3b620731
EZ
2325 if (new_color != FACE_TTY_DEFAULT_COLOR
2326 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2327 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
f32d4091 2328 {
2d764c78
EZ
2329 if (reverse)
2330 FRAME_FOREGROUND_PIXEL (f) = new_color;
2331 else
2332 FRAME_BACKGROUND_PIXEL (f) = new_color;
f32d4091 2333 redraw = 1;
2d764c78 2334 bg_set = 1;
76ac1508 2335 if (termscript)
a7cf9151 2336 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
f32d4091
KS
2337 }
2338 }
211c7152
EZ
2339 else if (EQ (prop, Qtitle))
2340 {
2341 x_set_title (f, val);
2342 if (termscript)
2343 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
2344 }
8ba01a32
EZ
2345 else if (EQ (prop, Qcursor_type))
2346 {
2347 IT_set_cursor_type (f, val);
2348 if (termscript)
2349 fprintf (termscript, "<CTYPE: %s>\n",
2350 EQ (val, Qbar) || CONSP (val) && EQ (XCAR (val), Qbar)
2351 ? "bar" : "box");
2352 }
db722735 2353 store_frame_param (f, prop, val);
2d764c78 2354 }
db722735 2355
2d764c78
EZ
2356 /* If they specified "reverse", but not the colors, we need to swap
2357 the current frame colors. */
2358 if (reverse && !was_reverse)
2359 {
2360 if (!fg_set)
2361 {
2362 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
2363 redraw = 1;
2364 }
2365 if (!bg_set)
2366 {
2367 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
2368 redraw = 1;
2369 }
f32d4091
KS
2370 }
2371
2372 if (redraw)
2373 {
2d764c78
EZ
2374 face_change_count++; /* forces xdisp.c to recompute basic faces */
2375 if (f == SELECTED_FRAME())
3bb1f22f 2376 redraw_frame (f);
f32d4091
KS
2377 }
2378}
2379
a7cf9151
EZ
2380extern void init_frame_faces (FRAME_PTR);
2381
f32d4091
KS
2382#endif /* !HAVE_X_WINDOWS */
2383
2384
48ffe371
RS
2385/* Do we need the internal terminal? */
2386
f32d4091
KS
2387void
2388internal_terminal_init ()
2389{
2390 char *term = getenv ("TERM");
2391 char *colors;
2d764c78 2392 struct frame *sf = SELECTED_FRAME();
f32d4091
KS
2393
2394#ifdef HAVE_X_WINDOWS
2395 if (!inhibit_window_system)
2396 return;
2397#endif
2398
2399 internal_terminal
2400 = (!noninteractive) && term && !strcmp (term, "internal");
2401
2402 if (getenv ("EMACSTEST"))
5063b150 2403 termscript = fopen (getenv ("EMACSTEST"), "wt");
f32d4091
KS
2404
2405#ifndef HAVE_X_WINDOWS
2406 if (!internal_terminal || inhibit_window_system)
2407 {
2d764c78 2408 sf->output_method = output_termcap;
f32d4091
KS
2409 return;
2410 }
2411
2412 Vwindow_system = intern ("pc");
2413 Vwindow_system_version = make_number (1);
2d764c78 2414 sf->output_method = output_msdos_raw;
039274cf
EZ
2415
2416 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2417 screen_old_address = 0;
2418
2d764c78
EZ
2419 /* Forget the stale screen colors as well. */
2420 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2421
f32d4091
KS
2422 bzero (&the_only_x_display, sizeof the_only_x_display);
2423 the_only_x_display.background_pixel = 7; /* White */
2424 the_only_x_display.foreground_pixel = 0; /* Black */
76ac1508 2425 bright_bg ();
5063b150 2426 colors = getenv ("EMACSCOLORS");
f32d4091
KS
2427 if (colors && strlen (colors) >= 2)
2428 {
76ac1508
RS
2429 /* The colors use 4 bits each (we enable bright background). */
2430 if (isdigit (colors[0]))
2431 colors[0] -= '0';
2432 else if (isxdigit (colors[0]))
2433 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1bd7b2c7
RS
2434 if (colors[0] >= 0 && colors[0] < 16)
2435 the_only_x_display.foreground_pixel = colors[0];
76ac1508
RS
2436 if (isdigit (colors[1]))
2437 colors[1] -= '0';
2438 else if (isxdigit (colors[1]))
2439 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2440 if (colors[1] >= 0 && colors[1] < 16)
1bd7b2c7 2441 the_only_x_display.background_pixel = colors[1];
f32d4091
KS
2442 }
2443 the_only_x_display.line_height = 1;
64ec6a02 2444 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
41ad069b
EZ
2445 the_only_x_display.display_info.mouse_face_mouse_frame = NULL;
2446 the_only_x_display.display_info.mouse_face_deferred_gc = 0;
2447 the_only_x_display.display_info.mouse_face_beg_row =
2448 the_only_x_display.display_info.mouse_face_beg_col = -1;
2449 the_only_x_display.display_info.mouse_face_end_row =
2450 the_only_x_display.display_info.mouse_face_end_col = -1;
2451 the_only_x_display.display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2452 the_only_x_display.display_info.mouse_face_window = Qnil;
2453 the_only_x_display.display_info.mouse_face_mouse_x =
2454 the_only_x_display.display_info.mouse_face_mouse_y = 0;
2455 the_only_x_display.display_info.mouse_face_defer = 0;
f32d4091 2456
2d764c78 2457 init_frame_faces (sf);
f32d4091
KS
2458
2459 ring_bell_hook = IT_ring_bell;
aa9ce936
EZ
2460 insert_glyphs_hook = IT_insert_glyphs;
2461 delete_glyphs_hook = IT_delete_glyphs;
f32d4091
KS
2462 write_glyphs_hook = IT_write_glyphs;
2463 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
2464 clear_to_end_hook = IT_clear_to_end;
2465 clear_end_of_line_hook = IT_clear_end_of_line;
2466 clear_frame_hook = IT_clear_screen;
2467 change_line_highlight_hook = IT_change_line_highlight;
2468 update_begin_hook = IT_update_begin;
2469 update_end_hook = IT_update_end;
2470 reassert_line_highlight_hook = IT_reassert_line_highlight;
41ad069b 2471 frame_up_to_date_hook = IT_frame_up_to_date;
f32d4091
KS
2472
2473 /* These hooks are called by term.c without being checked. */
2474 set_terminal_modes_hook = IT_set_terminal_modes;
2475 reset_terminal_modes_hook = IT_reset_terminal_modes;
2476 set_terminal_window_hook = IT_set_terminal_window;
c77f6f1b 2477 char_ins_del_ok = 0;
f32d4091
KS
2478#endif
2479}
2480
2481dos_get_saved_screen (screen, rows, cols)
2482 char **screen;
2483 int *rows;
2484 int *cols;
2485{
2486#ifndef HAVE_X_WINDOWS
2487 *screen = startup_screen_buffer;
2488 *cols = startup_screen_size_X;
2489 *rows = startup_screen_size_Y;
039274cf 2490 return *screen != (char *)0;
f32d4091
KS
2491#else
2492 return 0;
2493#endif
2494}
3bb1f22f
RS
2495
2496#ifndef HAVE_X_WINDOWS
2497
2498/* We are not X, but we can emulate it well enough for our needs... */
2499void
2500check_x (void)
2501{
2d764c78
EZ
2502 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2503 error ("Not running under a window system");
3bb1f22f
RS
2504}
2505
2506#endif
2507
5063b150 2508\f
f32d4091
KS
2509/* ----------------------- Keyboard control ----------------------
2510 *
2511 * Keymaps reflect the following keyboard layout:
2512 *
2513 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2514 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2515 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2516 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2517 * SPACE
2518 */
2519
d1d5dc19
EZ
2520#define Ignore 0x0000
2521#define Normal 0x0000 /* normal key - alt changes scan-code */
2522#define FctKey 0x1000 /* func key if c == 0, else c */
2523#define Special 0x2000 /* func key even if c != 0 */
2524#define ModFct 0x3000 /* special if mod-keys, else 'c' */
2525#define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2526#define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2527#define Grey 0x6000 /* Grey keypad key */
2528
2529#define Alt 0x0100 /* alt scan-code */
2530#define Ctrl 0x0200 /* ctrl scan-code */
2531#define Shift 0x0400 /* shift scan-code */
2532
f32d4091
KS
2533static int extended_kbd; /* 101 (102) keyboard present. */
2534
d1d5dc19
EZ
2535struct kbd_translate {
2536 unsigned char sc;
2537 unsigned char ch;
2538 unsigned short code;
2539};
2540
f32d4091
KS
2541struct dos_keyboard_map
2542{
2543 char *unshifted;
2544 char *shifted;
2545 char *alt_gr;
d1d5dc19 2546 struct kbd_translate *translate_table;
f32d4091
KS
2547};
2548
2549
2550static struct dos_keyboard_map us_keyboard = {
2551/* 0 1 2 3 4 5 */
2552/* 01234567890123456789012345678901234567890 12345678901234 */
2553 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2554/* 0123456789012345678901234567890123456789 012345678901234 */
2555 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
d1d5dc19
EZ
2556 0, /* no Alt-Gr key */
2557 0 /* no translate table */
f32d4091
KS
2558};
2559
2560static struct dos_keyboard_map fr_keyboard = {
2561/* 0 1 2 3 4 5 */
2562/* 012 3456789012345678901234567890123456789012345678901234 */
2563