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