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