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