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