Merge from emacs-24; up to 2012-12-27T08:21:08Z!rgm@gnu.org
[bpt/emacs.git] / src / msdos.c
CommitLineData
d26e478e 1/* MS-DOS specific C utilities. -*- coding: cp850 -*-
95df8112 2
ab422c4d 3Copyright (C) 1993-1997, 1999-2013 Free Software Foundation, Inc.
1b94449f
RS
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
1b94449f 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
1b94449f
RS
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1b94449f 19
9da6e765 20/* Contributed by Morten Welinder */
f32d4091 21/* New display, keyboard, and mouse control by Kim F. Storm */
9da6e765 22
d26e478e
EZ
23/* Note: This file MUST use a unibyte encoding, to both display the
24 keys on the non-US keyboard layout as their respective labels, and
25 provide the correct byte values for the keyboard input to inject
26 into Emacs. See 'struct dos_keyboard_map' below. As long as there
27 are only European keyboard layouts here, we are OK with DOS
28 codepage 850 encoding. */
29
1b94449f
RS
30/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
31
48984716 32#include <config.h>
1b94449f
RS
33
34#ifdef MSDOS
d7306fe6 35#include <setjmp.h>
1b94449f
RS
36#include "lisp.h"
37#include <stdio.h>
06b1ea13 38#include <time.h>
1b94449f
RS
39#include <sys/param.h>
40#include <sys/time.h>
e3ac1281 41/* gettime and settime in dos.h clash with their namesakes from
0d23c240
EZ
42 gnulib, so we move out of our way the prototypes in dos.h. */
43#define gettime dos_h_gettime_
44#define settime dos_h_settime_
1b94449f 45#include <dos.h>
0d23c240
EZ
46#undef gettime
47#undef settime
d21e67b5
RS
48#include <errno.h>
49#include <sys/stat.h> /* for _fixpath */
a7cf9151 50#include <unistd.h> /* for chdir, dup, dup2, etc. */
bf794306 51#include <dir.h> /* for getdisk */
affa509c 52#pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
1bd7b2c7 53#include <fcntl.h>
a7cf9151 54#include <io.h> /* for setmode */
fc171623
KH
55#include <dpmi.h> /* for __dpmi_xxx stuff */
56#include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
d21e67b5 57#include <libc/dosio.h> /* for _USE_LFN */
a7cf9151 58#include <conio.h> /* for cputs */
1bd7b2c7 59
1b94449f
RS
60#include "msdos.h"
61#include "systime.h"
3e1944a3 62#include "frame.h"
1b94449f 63#include "termhooks.h"
aa9ce936 64#include "termchar.h"
87485d6f 65#include "dispextern.h"
c77f6f1b 66#include "dosfns.h"
87485d6f 67#include "termopts.h"
83be827a 68#include "character.h"
aa9ce936
EZ
69#include "coding.h"
70#include "disptab.h"
87485d6f 71#include "window.h"
fc171623
KH
72#include "buffer.h"
73#include "commands.h"
41ad069b 74#include "blockinput.h"
97dd288b 75#include "keyboard.h"
6b61353c 76#include "intervals.h"
1b94449f
RS
77#include <go32.h>
78#include <pc.h>
79#include <ctype.h>
80/* #include <process.h> */
891ef8f7
EZ
81/* Damn that local process.h! Instead we can define P_WAIT and
82 spawnve ourselves. */
1b94449f 83#define P_WAIT 1
891ef8f7 84extern int spawnve (int, const char *, char *const [], char *const []);
1b94449f 85
d21e67b5
RS
86#ifndef _USE_LFN
87#define _USE_LFN 0
88#endif
89
b36701cc
RS
90#ifndef _dos_ds
91#define _dos_ds _go32_info_block.selector_for_linear_memory
92#endif
93
8748735b 94#include <signal.h>
417a04bb 95#include "syssignal.h"
8748735b 96
7c106b1e
EZ
97#include "careadlinkat.h"
98#include "allocator.h"
99
1bd7b2c7
RS
100#ifndef SYSTEM_MALLOC
101
102#ifdef GNU_MALLOC
103
104/* If other `malloc' than ours is used, force our `sbrk' behave like
105 Unix programs expect (resize memory blocks to keep them contiguous).
106 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
107 because that's what `gmalloc' expects to get. */
108#include <crt0.h>
109
110#ifdef REL_ALLOC
111int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
112#else /* not REL_ALLOC */
113int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
114#endif /* not REL_ALLOC */
115#endif /* GNU_MALLOC */
116
117#endif /* not SYSTEM_MALLOC */
aee81730 118
0d23c240 119/* Return the current timestamp in milliseconds since midnight. */
aee81730 120static unsigned long
3a8ce822 121event_timestamp (void)
aee81730 122{
0d23c240 123 struct timespec t;
aee81730 124 unsigned long s;
56e19ec4 125
aee81730 126 gettime (&t);
0d23c240
EZ
127 s = t.tv_sec;
128 s %= 86400;
aee81730 129 s *= 1000;
0d23c240 130 s += t.tv_nsec * 1000000;
56e19ec4 131
aee81730
RS
132 return s;
133}
134
f32d4091
KS
135\f
136/* ------------------------ Mouse control ---------------------------
137 *
138 * Coordinates are in screen positions and zero based.
139 * Mouse buttons are numbered from left to right and also zero based.
140 */
1b94449f 141
0c3cfc51
EZ
142/* This used to be in termhooks.h, but mainstream Emacs code no longer
143 uses it, and it was removed... */
144#define NUM_MOUSE_BUTTONS (5)
145
f32d4091
KS
146int have_mouse; /* 0: no, 1: enabled, -1: disabled */
147static int mouse_visible;
1b94449f 148
f32d4091
KS
149static int mouse_last_x;
150static int mouse_last_y;
1b94449f 151
f32d4091
KS
152static int mouse_button_translate[NUM_MOUSE_BUTTONS];
153static int mouse_button_count;
1b94449f 154
f32d4091 155void
3a8ce822 156mouse_on (void)
1b94449f 157{
1b94449f 158 union REGS regs;
1b94449f 159
f32d4091 160 if (have_mouse > 0 && !mouse_visible)
1b94449f 161 {
3e1944a3
EZ
162 struct tty_display_info *tty = CURTTY ();
163
164 if (tty->termscript)
165 fprintf (tty->termscript, "<M_ON>");
f32d4091
KS
166 regs.x.ax = 0x0001;
167 int86 (0x33, &regs, &regs);
168 mouse_visible = 1;
1b94449f 169 }
1b94449f
RS
170}
171
f32d4091 172void
3a8ce822 173mouse_off (void)
1b94449f 174{
f32d4091 175 union REGS regs;
1b94449f 176
f32d4091 177 if (have_mouse > 0 && mouse_visible)
1b94449f 178 {
3e1944a3
EZ
179 struct tty_display_info *tty = CURTTY ();
180
181 if (tty->termscript)
182 fprintf (tty->termscript, "<M_OFF>");
f32d4091
KS
183 regs.x.ax = 0x0002;
184 int86 (0x33, &regs, &regs);
185 mouse_visible = 0;
1b94449f 186 }
1b94449f
RS
187}
188
8f190436
EZ
189static void
190mouse_setup_buttons (int n_buttons)
191{
192 if (n_buttons == 3)
193 {
194 mouse_button_count = 3;
195 mouse_button_translate[0] = 0; /* Left */
196 mouse_button_translate[1] = 2; /* Middle */
197 mouse_button_translate[2] = 1; /* Right */
198 }
199 else /* two, what else? */
200 {
201 mouse_button_count = 2;
202 mouse_button_translate[0] = 0;
203 mouse_button_translate[1] = 1;
204 }
205}
206
207DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
208 1, 1, "NSet number of mouse buttons to: ",
70da46c3
PJ
209 doc: /* Set the number of mouse buttons to use by Emacs.
210This is useful with mice that report the number of buttons inconsistently,
211e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
212them. This happens with wheeled mice on Windows 9X, for example. */)
5842a27b 213 (Lisp_Object nbuttons)
8f190436 214{
e7522695
EZ
215 int n;
216
b7826503 217 CHECK_NUMBER (nbuttons);
e7522695
EZ
218 n = XINT (nbuttons);
219 if (n < 2 || n > 3)
ebe061ca
KS
220 xsignal2 (Qargs_out_of_range,
221 build_string ("only 2 or 3 mouse buttons are supported"),
222 nbuttons);
e7522695 223 mouse_setup_buttons (n);
8f190436
EZ
224 return Qnil;
225}
226
211c7152
EZ
227static void
228mouse_get_xy (int *x, int *y)
229{
230 union REGS regs;
231
232 regs.x.ax = 0x0003;
233 int86 (0x33, &regs, &regs);
234 *x = regs.x.cx / 8;
235 *y = regs.x.dx / 8;
236}
237
f32d4091 238void
3a8ce822 239mouse_moveto (int x, int y)
1b94449f 240{
f32d4091 241 union REGS regs;
3e1944a3 242 struct tty_display_info *tty = CURTTY ();
1b94449f 243
3e1944a3
EZ
244 if (tty->termscript)
245 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
f32d4091
KS
246 regs.x.ax = 0x0004;
247 mouse_last_x = regs.x.cx = x * 8;
248 mouse_last_y = regs.x.dx = y * 8;
249 int86 (0x33, &regs, &regs);
1b94449f
RS
250}
251
f32d4091 252static int
3a8ce822 253mouse_pressed (int b, int *xp, int *yp)
1b94449f 254{
f32d4091 255 union REGS regs;
1b94449f 256
f32d4091
KS
257 if (b >= mouse_button_count)
258 return 0;
259 regs.x.ax = 0x0005;
260 regs.x.bx = mouse_button_translate[b];
261 int86 (0x33, &regs, &regs);
262 if (regs.x.bx)
263 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
264 return (regs.x.bx != 0);
1b94449f
RS
265}
266
f32d4091 267static int
3a8ce822 268mouse_released (int b, int *xp, int *yp)
1b94449f
RS
269{
270 union REGS regs;
271
f32d4091
KS
272 if (b >= mouse_button_count)
273 return 0;
274 regs.x.ax = 0x0006;
275 regs.x.bx = mouse_button_translate[b];
276 int86 (0x33, &regs, &regs);
277 if (regs.x.bx)
278 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
279 return (regs.x.bx != 0);
1b94449f
RS
280}
281
0c7bc1aa 282static int
3a8ce822 283mouse_button_depressed (int b, int *xp, int *yp)
0c7bc1aa
EZ
284{
285 union REGS regs;
286
287 if (b >= mouse_button_count)
288 return 0;
289 regs.x.ax = 0x0003;
290 int86 (0x33, &regs, &regs);
291 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
292 {
293 *xp = regs.x.cx / 8;
294 *yp = regs.x.dx / 8;
295 return 1;
296 }
297 return 0;
298}
299
f32d4091 300void
3a8ce822
EZ
301mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
302 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
9fbd6841 303 Time *time)
f32d4091
KS
304{
305 int ix, iy;
211c7152
EZ
306 Lisp_Object frame, tail;
307
308 /* Clear the mouse-moved flag for every frame on this display. */
309 FOR_EACH_FRAME (tail, frame)
310 XFRAME (frame)->mouse_moved = 0;
f32d4091 311
5e617bc2 312 *f = SELECTED_FRAME ();
f32d4091
KS
313 *bar_window = Qnil;
314 mouse_get_xy (&ix, &iy);
f32d4091 315 *time = event_timestamp ();
211c7152
EZ
316 *x = make_number (mouse_last_x = ix);
317 *y = make_number (mouse_last_y = iy);
f32d4091 318}
1b94449f 319
f32d4091 320static void
3a8ce822 321mouse_check_moved (void)
1b94449f 322{
aee81730 323 int x, y;
1b94449f 324
f32d4091 325 mouse_get_xy (&x, &y);
5e617bc2 326 SELECTED_FRAME ()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
f32d4091
KS
327 mouse_last_x = x;
328 mouse_last_y = y;
329}
1b94449f 330
97dd288b
EZ
331/* Force the mouse driver to ``forget'' about any button clicks until
332 now. */
333static void
334mouse_clear_clicks (void)
335{
336 int b;
337
338 for (b = 0; b < mouse_button_count; b++)
339 {
340 int dummy_x, dummy_y;
341
342 (void) mouse_pressed (b, &dummy_x, &dummy_y);
343 (void) mouse_released (b, &dummy_x, &dummy_y);
344 }
345}
346
f32d4091 347void
3a8ce822 348mouse_init (void)
f32d4091
KS
349{
350 union REGS regs;
3e1944a3 351 struct tty_display_info *tty = CURTTY ();
647c32eb 352
3e1944a3
EZ
353 if (tty->termscript)
354 fprintf (tty->termscript, "<M_INIT>");
1b94449f 355
f32d4091
KS
356 regs.x.ax = 0x0021;
357 int86 (0x33, &regs, &regs);
091d0bdf 358
0c7bc1aa
EZ
359 /* Reset the mouse last press/release info. It seems that Windows
360 doesn't do that automatically when function 21h is called, which
361 causes Emacs to ``remember'' the click that switched focus to the
362 window just before Emacs was started from that window. */
97dd288b 363 mouse_clear_clicks ();
0c7bc1aa 364
f32d4091
KS
365 regs.x.ax = 0x0007;
366 regs.x.cx = 0;
367 regs.x.dx = 8 * (ScreenCols () - 1);
368 int86 (0x33, &regs, &regs);
1b94449f 369
f32d4091
KS
370 regs.x.ax = 0x0008;
371 regs.x.cx = 0;
372 regs.x.dx = 8 * (ScreenRows () - 1);
373 int86 (0x33, &regs, &regs);
1b94449f 374
f32d4091
KS
375 mouse_moveto (0, 0);
376 mouse_visible = 0;
377}
3eb1dbb6 378\f
f32d4091
KS
379/* ------------------------- Screen control ----------------------
380 *
381 */
aee81730 382
f32d4091 383static int internal_terminal = 0;
aee81730 384
f32d4091
KS
385#ifndef HAVE_X_WINDOWS
386extern unsigned char ScreenAttrib;
387static int screen_face;
aee81730 388
f32d4091
KS
389static int screen_size_X;
390static int screen_size_Y;
391static int screen_size;
1b94449f 392
f32d4091
KS
393static int current_pos_X;
394static int current_pos_Y;
395static int new_pos_X;
396static int new_pos_Y;
1b94449f 397
f32d4091
KS
398static void *startup_screen_buffer;
399static int startup_screen_size_X;
400static int startup_screen_size_Y;
401static int startup_pos_X;
402static int startup_pos_Y;
c9adab25 403static unsigned char startup_screen_attrib;
1b94449f 404
06b1ea13
EZ
405static clock_t startup_time;
406
f32d4091 407static int term_setup_done;
1b94449f 408
8ba01a32
EZ
409static unsigned short outside_cursor;
410
f32d4091 411/* Similar to the_only_frame. */
3e1944a3 412struct tty_display_info the_only_display_info;
1b94449f 413
039274cf
EZ
414/* Support for DOS/V (allows Japanese characters to be displayed on
415 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
416
417/* Holds the address of the text-mode screen buffer. */
418static unsigned long screen_old_address = 0;
419/* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
420static unsigned short screen_virtual_segment = 0;
421static unsigned short screen_virtual_offset = 0;
6b61353c
KH
422extern Lisp_Object Qcursor_type;
423extern Lisp_Object Qbar, Qhbar;
8ba01a32 424
9ccf54e9 425/* The screen colors of the current frame, which serve as the default
deece6f5
EZ
426 colors for newly-created frames. */
427static int initial_screen_colors[2];
428
039274cf
EZ
429/* Update the screen from a part of relocated DOS/V screen buffer which
430 begins at OFFSET and includes COUNT characters. */
431static void
432dosv_refresh_virtual_screen (int offset, int count)
433{
434 __dpmi_regs regs;
435
9ab8560d 436 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
40437cf5
EZ
437 return;
438
039274cf
EZ
439 regs.h.ah = 0xff; /* update relocated screen */
440 regs.x.es = screen_virtual_segment;
441 regs.x.di = screen_virtual_offset + offset;
442 regs.x.cx = count;
443 __dpmi_int (0x10, &regs);
444}
039274cf 445
d1d5dc19 446static void
3a8ce822 447dos_direct_output (int y, int x, char *buf, int len)
1b94449f 448{
40437cf5
EZ
449 int t0 = 2 * (x + y * screen_size_X);
450 int t = t0 + (int) ScreenPrimary;
039274cf 451 int l0 = len;
fc171623 452
fc171623
KH
453 /* This is faster. */
454 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
455 _farnspokeb (t, *buf);
039274cf
EZ
456
457 if (screen_virtual_segment)
458 dosv_refresh_virtual_screen (t0, l0);
f32d4091
KS
459}
460#endif
461
462#ifndef HAVE_X_WINDOWS
463
b36701cc
RS
464static int blink_bit = -1; /* the state of the blink bit at startup */
465
76ac1508
RS
466/* Enable bright background colors. */
467static void
468bright_bg (void)
469{
470 union REGS regs;
471
b36701cc
RS
472 /* Remember the original state of the blink/bright-background bit.
473 It is stored at 0040:0065h in the BIOS data area. */
474 if (blink_bit == -1)
475 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
476
76ac1508
RS
477 regs.h.bl = 0;
478 regs.x.ax = 0x1003;
479 int86 (0x10, &regs, &regs);
480}
481
b36701cc
RS
482/* Disable bright background colors (and enable blinking) if we found
483 the video system in that state at startup. */
484static void
485maybe_enable_blinking (void)
486{
487 if (blink_bit == 1)
488 {
489 union REGS regs;
490
491 regs.h.bl = 1;
492 regs.x.ax = 0x1003;
493 int86 (0x10, &regs, &regs);
494 }
495}
496
8ba01a32
EZ
497/* Return non-zero if the system has a VGA adapter. */
498static int
499vga_installed (void)
500{
501 union REGS regs;
502
503 regs.x.ax = 0x1a00;
504 int86 (0x10, &regs, &regs);
505 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
506 return 1;
507 return 0;
508}
509
4a96d4d2
KH
510/* Set the screen dimensions so that it can show no less than
511 ROWS x COLS frame. */
48ffe371 512
4a96d4d2 513void
3a8ce822 514dos_set_window_size (int *rows, int *cols)
4a96d4d2
KH
515{
516 char video_name[30];
4a96d4d2 517 union REGS regs;
56e19ec4
EZ
518 Lisp_Object video_mode;
519 int video_mode_value, have_vga = 0;
4a96d4d2
KH
520 int current_rows = ScreenRows (), current_cols = ScreenCols ();
521
522 if (*rows == current_rows && *cols == current_cols)
523 return;
524
4a96d4d2 525 mouse_off ();
8ba01a32 526 have_vga = vga_installed ();
4a96d4d2 527
48ffe371 528 /* If the user specified a special video mode for these dimensions,
4a96d4d2 529 use that mode. */
15dbb4d6
PE
530 video_mode
531 = Fsymbol_value (Fintern_soft (make_formatted_string
a8290ec3
DA
532 (video_name, "screen-dimensions-%dx%d",
533 *rows, *cols), Qnil));
4a96d4d2
KH
534
535 if (INTEGERP (video_mode)
536 && (video_mode_value = XINT (video_mode)) > 0)
537 {
538 regs.x.ax = video_mode_value;
539 int86 (0x10, &regs, &regs);
48ffe371
RS
540
541 if (have_mouse)
542 {
543 /* Must hardware-reset the mouse, or else it won't update
544 its notion of screen dimensions for some non-standard
545 video modes. This is *painfully* slow... */
546 regs.x.ax = 0;
547 int86 (0x33, &regs, &regs);
548 }
4a96d4d2
KH
549 }
550
551 /* Find one of the dimensions supported by standard EGA/VGA
552 which gives us at least the required dimensions. */
4a96d4d2
KH
553 else
554 {
555 static struct {
56e19ec4 556 int rows, need_vga;
4a96d4d2
KH
557 } std_dimension[] = {
558 {25, 0},
559 {28, 1},
560 {35, 0},
561 {40, 1},
562 {43, 0},
563 {50, 1}
564 };
565 int i = 0;
566
567 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
568 {
569 if (std_dimension[i].need_vga <= have_vga
570 && std_dimension[i].rows >= *rows)
571 {
572 if (std_dimension[i].rows != current_rows
573 || *cols != current_cols)
48ffe371 574 _set_screen_lines (std_dimension[i].rows);
4a96d4d2
KH
575 break;
576 }
48ffe371 577 i++;
4a96d4d2
KH
578 }
579 }
580
4a96d4d2
KH
581
582 if (have_mouse)
583 {
4a96d4d2
KH
584 mouse_init ();
585 mouse_on ();
586 }
587
588 /* Tell the caller what dimensions have been REALLY set. */
589 *rows = ScreenRows ();
590 *cols = ScreenCols ();
76ac1508 591
bed43f1d
EZ
592 /* Update Emacs' notion of screen dimensions. */
593 screen_size_X = *cols;
594 screen_size_Y = *rows;
595 screen_size = *cols * *rows;
596
41ad069b
EZ
597 /* If the dimensions changed, the mouse highlight info is invalid. */
598 if (current_rows != *rows || current_cols != *cols)
599 {
5e617bc2 600 struct frame *f = SELECTED_FRAME ();
34574c02
EZ
601 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
602 Lisp_Object window = hlinfo->mouse_face_window;
41ad069b 603
d3d50620 604 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
41ad069b 605 {
34574c02
EZ
606 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
607 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
608 hlinfo->mouse_face_window = Qnil;
41ad069b
EZ
609 }
610 }
41ad069b 611
76ac1508
RS
612 /* Enable bright background colors. */
613 bright_bg ();
039274cf
EZ
614
615 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
616 be defensive anyway. */
617 if (screen_virtual_segment)
618 dosv_refresh_virtual_screen (0, *cols * *rows);
4a96d4d2
KH
619}
620
48ffe371
RS
621/* If we write a character in the position where the mouse is,
622 the mouse cursor may need to be refreshed. */
09e2ac30
RS
623
624static void
3a8ce822 625mouse_off_maybe (void)
09e2ac30 626{
f32d4091 627 int x, y;
56e19ec4 628
f32d4091
KS
629 if (!mouse_visible)
630 return;
56e19ec4 631
f32d4091
KS
632 mouse_get_xy (&x, &y);
633 if (y != new_pos_Y || x < new_pos_X)
634 return;
56e19ec4 635
f32d4091
KS
636 mouse_off ();
637}
638
8ba01a32
EZ
639#define DEFAULT_CURSOR_START (-1)
640#define DEFAULT_CURSOR_WIDTH (-1)
641#define BOX_CURSOR_WIDTH (-32)
642
643/* Set cursor to begin at scan line START_LINE in the character cell
644 and extend for WIDTH scan lines. Scan lines are counted from top
645 of the character cell, starting from zero. */
646static void
647msdos_set_cursor_shape (struct frame *f, int start_line, int width)
648{
8ba01a32
EZ
649 unsigned desired_cursor;
650 __dpmi_regs regs;
651 int max_line, top_line, bot_line;
3e1944a3 652 struct tty_display_info *tty = FRAME_TTY (f);
8ba01a32
EZ
653
654 /* Avoid the costly BIOS call if F isn't the currently selected
655 frame. Allow for NULL as unconditionally meaning the selected
656 frame. */
5e617bc2 657 if (f && f != SELECTED_FRAME ())
8ba01a32
EZ
658 return;
659
3e1944a3
EZ
660 if (tty->termscript)
661 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
b106731c 662
8ba01a32
EZ
663 /* The character cell size in scan lines is stored at 40:85 in the
664 BIOS data area. */
665 max_line = _farpeekw (_dos_ds, 0x485) - 1;
666 switch (max_line)
667 {
668 default: /* this relies on CGA cursor emulation being ON! */
669 case 7:
670 bot_line = 7;
671 break;
672 case 9:
673 bot_line = 9;
674 break;
675 case 13:
676 bot_line = 12;
677 break;
678 case 15:
679 bot_line = 14;
680 break;
681 }
682
683 if (width < 0)
684 {
685 if (width == BOX_CURSOR_WIDTH)
686 {
687 top_line = 0;
688 bot_line = max_line;
689 }
690 else if (start_line != DEFAULT_CURSOR_START)
691 {
692 top_line = start_line;
693 bot_line = top_line - width - 1;
694 }
695 else if (width != DEFAULT_CURSOR_WIDTH)
696 {
697 top_line = 0;
698 bot_line = -1 - width;
699 }
700 else
701 top_line = bot_line + 1;
702 }
703 else if (width == 0)
704 {
705 /* [31, 0] seems to DTRT for all screen sizes. */
706 top_line = 31;
707 bot_line = 0;
708 }
709 else /* WIDTH is positive */
710 {
711 if (start_line != DEFAULT_CURSOR_START)
712 bot_line = start_line;
713 top_line = bot_line - (width - 1);
714 }
715
716 /* If the current cursor shape is already what they want, we are
717 history here. */
718 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
719 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
720 return;
721
722 regs.h.ah = 1;
723 regs.x.cx = desired_cursor;
724 __dpmi_int (0x10, &regs);
8ba01a32
EZ
725}
726
727static void
728IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
729{
a0738471 730 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
8ba01a32
EZ
731 {
732 /* Just BAR means the normal EGA/VGA cursor. */
733 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
734 }
a0738471
EZ
735 else if (CONSP (cursor_type)
736 && (EQ (XCAR (cursor_type), Qbar)
737 || EQ (XCAR (cursor_type), Qhbar)))
8ba01a32
EZ
738 {
739 Lisp_Object bar_parms = XCDR (cursor_type);
740 int width;
741
742 if (INTEGERP (bar_parms))
743 {
744 /* Feature: negative WIDTH means cursor at the top
745 of the character cell, zero means invisible cursor. */
746 width = XINT (bar_parms);
747 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
748 width);
749 }
750 else if (CONSP (bar_parms)
751 && INTEGERP (XCAR (bar_parms))
752 && INTEGERP (XCDR (bar_parms)))
753 {
754 int start_line = XINT (XCDR (bar_parms));
755
756 width = XINT (XCAR (bar_parms));
757 msdos_set_cursor_shape (f, start_line, width);
758 }
759 }
760 else
b106731c
EZ
761 {
762 /* Treat anything unknown as "box cursor". This includes nil, so
763 that a frame which doesn't specify a cursor type gets a box,
764 which is the default in Emacs. */
765 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
766 }
8ba01a32
EZ
767}
768
71f65669 769static void
3e1944a3 770IT_ring_bell (struct frame *f)
f32d4091
KS
771{
772 if (visible_bell)
aee81730 773 {
f32d4091
KS
774 mouse_off ();
775 ScreenVisualBell ();
aee81730 776 }
f32d4091 777 else
3635be47
RS
778 {
779 union REGS inregs, outregs;
780 inregs.h.ah = 2;
781 inregs.h.dl = 7;
782 intdos (&inregs, &outregs);
783 }
09e2ac30
RS
784}
785
c77f6f1b
EZ
786/* Given a face id FACE, extract the face parameters to be used for
787 display until the face changes. The face parameters (actually, its
788 color) are used to construct the video attribute byte for each
789 glyph during the construction of the buffer that is then blitted to
790 the video RAM. */
f32d4091
KS
791static void
792IT_set_face (int face)
793{
5e617bc2 794 struct frame *sf = SELECTED_FRAME ();
546701f5
EZ
795 struct face *fp = FACE_FROM_ID (sf, face);
796 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
797 unsigned long fg, bg, dflt_fg, dflt_bg;
3e1944a3 798 struct tty_display_info *tty = FRAME_TTY (sf);
f32d4091 799
c77f6f1b 800 if (!fp)
e30aee93 801 {
546701f5 802 fp = dfp;
e30aee93
EZ
803 /* The default face for the frame should always be realized and
804 cached. */
805 if (!fp)
1088b922 806 emacs_abort ();
e30aee93 807 }
f32d4091 808 screen_face = face;
c77f6f1b
EZ
809 fg = fp->foreground;
810 bg = fp->background;
546701f5
EZ
811 dflt_fg = dfp->foreground;
812 dflt_bg = dfp->background;
c77f6f1b 813
abcce93a
MB
814 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
815 mean use the colors of the default face. Note that we assume all
816 16 colors to be available for the background, since Emacs switches
817 on this mode (and loses the blinking attribute) at startup. */
f9d2fdc4 818 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
3b620731 819 fg = FRAME_FOREGROUND_PIXEL (sf);
f9d2fdc4 820 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
3b620731
EZ
821 fg = FRAME_BACKGROUND_PIXEL (sf);
822 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
823 bg = FRAME_BACKGROUND_PIXEL (sf);
f9d2fdc4 824 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
3b620731
EZ
825 bg = FRAME_FOREGROUND_PIXEL (sf);
826
827 /* Make sure highlighted lines really stand out, come what may. */
abcce93a 828 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
3b620731
EZ
829 {
830 unsigned long tem = fg;
831
832 fg = bg;
833 bg = tem;
834 }
76648534
EZ
835 /* If the user requested inverse video, obey. */
836 if (inverse_video)
837 {
838 unsigned long tem2 = fg;
839
840 fg = bg;
841 bg = tem2;
842 }
3e1944a3 843 if (tty->termscript)
891ef8f7 844 fprintf (tty->termscript, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face,
abcce93a 845 fp->foreground, fp->background, fg, bg);
c77f6f1b
EZ
846 if (fg >= 0 && fg < 16)
847 {
848 ScreenAttrib &= 0xf0;
849 ScreenAttrib |= fg;
850 }
851 if (bg >= 0 && bg < 16)
852 {
853 ScreenAttrib &= 0x0f;
854 ScreenAttrib |= ((bg & 0x0f) << 4);
855 }
f32d4091
KS
856}
857
aff01dd9
EZ
858/* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
859 width of a DOS display in any known text mode. We multiply by 2 to
7ee6a1d3 860 accommodate the screen attribute byte. */
aff01dd9
EZ
861#define MAX_SCREEN_BUF 160*2
862
3e1944a3
EZ
863extern unsigned char *encode_terminal_code (struct glyph *, int,
864 struct coding_system *);
7ef4b50c 865
71f65669 866static void
3e1944a3 867IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
f32d4091 868{
aff01dd9 869 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
039274cf 870 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
aa9ce936 871 register int sl = str_len;
3e1944a3 872 struct tty_display_info *tty = FRAME_TTY (f);
2d764c78 873 struct frame *sf;
3e1944a3 874 unsigned char *conversion_buffer;
87485d6f 875
3e1944a3
EZ
876 /* If terminal_coding does any conversion, use it, otherwise use
877 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
878 because it always returns 1 if terminal_coding.src_multibyte is 1. */
879 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
880
881 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
882 coding = &safe_terminal_coding;
648648a9 883
3b620731 884 if (str_len <= 0) return;
56e19ec4 885
5e617bc2 886 sf = SELECTED_FRAME ();
e30aee93
EZ
887
888 /* Since faces get cached and uncached behind our back, we can't
889 rely on their indices in the cache being consistent across
890 invocations. So always reset the screen face to the default
891 face of the frame, before writing glyphs, and let the glyphs
892 set the right face if it's different from the default. */
893 IT_set_face (DEFAULT_FACE_ID);
56e19ec4 894
aa9ce936
EZ
895 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
896 the tail. */
3e1944a3 897 coding->mode &= ~CODING_MODE_LAST_BLOCK;
aff01dd9 898 screen_bp = &screen_buf[0];
3e1944a3 899 while (sl > 0)
aa9ce936 900 {
3e1944a3 901 int cf;
aff01dd9 902 int n;
aa9ce936 903
aff01dd9
EZ
904 /* If the face of this glyph is different from the current
905 screen face, update the screen attribute byte. */
906 cf = str->face_id;
907 if (cf != screen_face)
908 IT_set_face (cf); /* handles invalid faces gracefully */
909
910 /* Identify a run of glyphs with the same face. */
911 for (n = 1; n < sl; ++n)
912 if (str[n].face_id != cf)
913 break;
914
915 if (n >= sl)
916 /* This is the last glyph. */
917 coding->mode |= CODING_MODE_LAST_BLOCK;
918
919 conversion_buffer = encode_terminal_code (str, n, coding);
920 if (coding->produced > 0)
aa9ce936 921 {
aff01dd9
EZ
922 /* Copy the encoded bytes to the screen buffer. */
923 for (bp = conversion_buffer; coding->produced--; bp++)
aa9ce936 924 {
aff01dd9
EZ
925 /* Paranoia: discard bytes that would overrun the end of
926 the screen buffer. */
927 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
aa9ce936 928 {
aff01dd9
EZ
929 *screen_bp++ = (unsigned char)*bp;
930 *screen_bp++ = ScreenAttrib;
aa9ce936 931 }
aff01dd9
EZ
932 if (tty->termscript)
933 fputc (*bp, tty->termscript);
aa9ce936
EZ
934 }
935 }
aff01dd9
EZ
936 /* Update STR and its remaining length. */
937 str += n;
938 sl -= n;
aee81730
RS
939 }
940
aff01dd9 941 /* Dump whatever we have in the screen buffer. */
f32d4091 942 mouse_off_maybe ();
aa9ce936 943 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
039274cf 944 if (screen_virtual_segment)
aa9ce936
EZ
945 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
946 new_pos_X += (screen_bp - screen_buf) / 2;
f32d4091 947}
aee81730 948
41ad069b
EZ
949/************************************************************************
950 Mouse Highlight (and friends..)
951 ************************************************************************/
952
ee8ceff8 953/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
9005a471
EZ
954static Lisp_Object last_mouse_window;
955
41ad069b
EZ
956static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
957
d009ae66
EZ
958int
959popup_activated (void)
41ad069b 960{
d009ae66 961 return mouse_preempted;
41ad069b
EZ
962}
963
d009ae66 964/* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
28118eb6
EZ
965 window W. X is relative to TEXT_AREA in W. HL is a face override
966 for drawing the glyphs. */
d009ae66 967void
28118eb6
EZ
968tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
969 int start_hpos, int end_hpos,
970 enum draw_glyphs_face hl)
41ad069b 971{
41ad069b 972 struct frame *f = XFRAME (WINDOW_FRAME (w));
3e1944a3 973 struct tty_display_info *tty = FRAME_TTY (f);
34574c02 974 Mouse_HLInfo *hlinfo = &tty->mouse_highlight;
41ad069b 975
d009ae66 976 if (hl == DRAW_MOUSE_FACE)
41ad069b 977 {
d009ae66
EZ
978 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
979 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
980 int nglyphs = end_hpos - start_hpos;
981 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
982 int start_offset = offset;
41ad069b 983
d009ae66
EZ
984 if (tty->termscript)
985 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
986 kstart, kstart + nglyphs - 1, vpos);
56e19ec4 987
d009ae66 988 mouse_off ();
34574c02 989 IT_set_face (hlinfo->mouse_face_face_id);
d009ae66
EZ
990 /* Since we are going to change only the _colors_ of already
991 displayed text, there's no need to go through all the pain of
992 generating and encoding the text from the glyphs. Instead,
993 we simply poke the attribute byte of each affected position
994 in video memory with the colors computed by IT_set_face! */
995 _farsetsel (_dos_ds);
996 while (nglyphs--)
41ad069b 997 {
d009ae66
EZ
998 _farnspokeb (offset, ScreenAttrib);
999 offset += 2;
41ad069b 1000 }
d009ae66
EZ
1001 if (screen_virtual_segment)
1002 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1003 mouse_on ();
41ad069b 1004 }
d009ae66 1005 else if (hl == DRAW_NORMAL_TEXT)
41ad069b 1006 {
d009ae66
EZ
1007 /* We are removing a previously-drawn mouse highlight. The
1008 safest way to do so is to redraw the glyphs anew, since all
1009 kinds of faces and display tables could have changed behind
1010 our back. */
1011 int nglyphs = end_hpos - start_hpos;
1012 int save_x = new_pos_X, save_y = new_pos_Y;
1013
1014 if (end_hpos >= row->used[TEXT_AREA])
1015 nglyphs = row->used[TEXT_AREA] - start_hpos;
1016
1017 /* IT_write_glyphs writes at cursor position, so we need to
1018 temporarily move cursor coordinates to the beginning of
1019 the highlight region. */
1020 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1021 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
41ad069b 1022
d009ae66
EZ
1023 if (tty->termscript)
1024 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1025 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1026 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1027 if (tty->termscript)
1028 fputs ("\n", tty->termscript);
1029 new_pos_X = save_x;
1030 new_pos_Y = save_y;
41ad069b
EZ
1031 }
1032}
1033
71f65669 1034static void
3e1944a3 1035IT_clear_end_of_line (struct frame *f, int first_unused)
f32d4091
KS
1036{
1037 char *spaces, *sp;
56e19ec4 1038 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
3e1944a3 1039 struct tty_display_info *tty = FRAME_TTY (f);
aa9ce936 1040
2d764c78 1041 if (new_pos_X >= first_unused || fatal_error_in_progress)
aa9ce936 1042 return;
f32d4091
KS
1043
1044 IT_set_face (0);
2d764c78 1045 i = (j = first_unused - new_pos_X) * 2;
3e1944a3
EZ
1046 if (tty->termscript)
1047 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
f32d4091 1048 spaces = sp = alloca (i);
56e19ec4 1049
f32d4091 1050 while (--j >= 0)
aee81730 1051 {
f32d4091
KS
1052 *sp++ = ' ';
1053 *sp++ = ScreenAttrib;
aee81730
RS
1054 }
1055
f32d4091 1056 mouse_off_maybe ();
039274cf
EZ
1057 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1058 if (screen_virtual_segment)
1059 dosv_refresh_virtual_screen (offset, i / 2);
2d764c78
EZ
1060
1061 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1062 Let's follow their lead, in case someone relies on this. */
1063 new_pos_X = first_unused;
aee81730
RS
1064}
1065
71f65669 1066static void
3e1944a3 1067IT_clear_screen (struct frame *f)
f32d4091 1068{
3e1944a3
EZ
1069 struct tty_display_info *tty = FRAME_TTY (f);
1070
1071 if (tty->termscript)
1072 fprintf (tty->termscript, "<CLR:SCR>");
deece6f5
EZ
1073 /* We are sometimes called (from clear_garbaged_frames) when a new
1074 frame is being created, but its faces are not yet realized. In
1075 such a case we cannot call IT_set_face, since it will fail to find
1076 any valid faces and will abort. Instead, use the initial screen
1077 colors; that should mimic what a Unix tty does, which simply clears
1078 the screen with whatever default colors are in use. */
1079 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1080 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1081 else
1082 IT_set_face (0);
f32d4091
KS
1083 mouse_off ();
1084 ScreenClear ();
039274cf
EZ
1085 if (screen_virtual_segment)
1086 dosv_refresh_virtual_screen (0, screen_size);
f32d4091
KS
1087 new_pos_X = new_pos_Y = 0;
1088}
1089
71f65669 1090static void
3e1944a3 1091IT_clear_to_end (struct frame *f)
f32d4091 1092{
3e1944a3
EZ
1093 struct tty_display_info *tty = FRAME_TTY (f);
1094
1095 if (tty->termscript)
1096 fprintf (tty->termscript, "<CLR:EOS>");
f32d4091
KS
1097
1098 while (new_pos_Y < screen_size_Y) {
1099 new_pos_X = 0;
3e1944a3 1100 IT_clear_end_of_line (f, screen_size_X);
f32d4091
KS
1101 new_pos_Y++;
1102 }
1103}
1104
71f65669 1105static void
3e1944a3 1106IT_cursor_to (struct frame *f, int y, int x)
f32d4091 1107{
3e1944a3
EZ
1108 struct tty_display_info *tty = FRAME_TTY (f);
1109
1110 if (tty->termscript)
1111 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
f32d4091
KS
1112 new_pos_X = x;
1113 new_pos_Y = y;
1114}
1115
fc171623
KH
1116static int cursor_cleared;
1117
d1d5dc19 1118static void
fc171623
KH
1119IT_display_cursor (int on)
1120{
3e1944a3
EZ
1121 struct tty_display_info *tty = CURTTY ();
1122
fc171623
KH
1123 if (on && cursor_cleared)
1124 {
1125 ScreenSetCursor (current_pos_Y, current_pos_X);
1126 cursor_cleared = 0;
b04021eb 1127 if (tty->termscript)
cb4545ad
EZ
1128 fprintf (tty->termscript, "\nCURSOR ON (%dx%d)",
1129 current_pos_Y, current_pos_X);
fc171623
KH
1130 }
1131 else if (!on && !cursor_cleared)
1132 {
1133 ScreenSetCursor (-1, -1);
1134 cursor_cleared = 1;
b04021eb 1135 if (tty->termscript)
cb4545ad
EZ
1136 fprintf (tty->termscript, "\nCURSOR OFF (%dx%d)",
1137 current_pos_Y, current_pos_X);
fc171623
KH
1138 }
1139}
1140
1141/* Emacs calls cursor-movement functions a lot when it updates the
1142 display (probably a legacy of old terminals where you cannot
1143 update a screen line without first moving the cursor there).
1144 However, cursor movement is expensive on MSDOS (it calls a slow
1145 BIOS function and requires 2 mode switches), while actual screen
1146 updates access the video memory directly and don't depend on
1147 cursor position. To avoid slowing down the redisplay, we cheat:
1148 all functions that move the cursor only set internal variables
1149 which record the cursor position, whereas the cursor is only
1150 moved to its final position whenever screen update is complete.
1151
1152 `IT_cmgoto' is called from the keyboard reading loop and when the
1153 frame update is complete. This means that we are ready for user
1154 input, so we update the cursor position to show where the point is,
1155 and also make the mouse pointer visible.
1156
1157 Special treatment is required when the cursor is in the echo area,
1158 to put the cursor at the end of the text displayed there. */
1159
71f65669
EZ
1160static void
1161IT_cmgoto (FRAME_PTR f)
fc171623
KH
1162{
1163 /* Only set the cursor to where it should be if the display is
1164 already in sync with the window contents. */
2d764c78 1165 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
3e1944a3 1166 struct tty_display_info *tty = FRAME_TTY (f);
2d764c78
EZ
1167
1168 /* FIXME: This needs to be rewritten for the new redisplay, or
1169 removed. */
1170#if 0
06da1de1
EZ
1171 static int previous_pos_X = -1;
1172
2d764c78
EZ
1173 update_cursor_pos = 1; /* temporary!!! */
1174
06da1de1
EZ
1175 /* If the display is in sync, forget any previous knowledge about
1176 cursor position. This is primarily for unexpected events like
1177 C-g in the minibuffer. */
1178 if (update_cursor_pos && previous_pos_X >= 0)
1179 previous_pos_X = -1;
1180 /* If we are in the echo area, put the cursor at the
1181 end of the echo area message. */
fc171623 1182 if (!update_cursor_pos
c655f6fd 1183 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
fc171623 1184 {
06da1de1
EZ
1185 int tem_X = current_pos_X, dummy;
1186
1187 if (echo_area_glyphs)
1188 {
1189 tem_X = echo_area_glyphs_length;
1190 /* Save current cursor position, to be restored after the
1191 echo area message is erased. Only remember one level
1192 of previous cursor position. */
1193 if (previous_pos_X == -1)
1194 ScreenGetCursor (&dummy, &previous_pos_X);
1195 }
1196 else if (previous_pos_X >= 0)
1197 {
1198 /* We wind up here after the echo area message is erased.
1199 Restore the cursor position we remembered above. */
1200 tem_X = previous_pos_X;
1201 previous_pos_X = -1;
1202 }
9a599a60 1203
06da1de1 1204 if (current_pos_X != tem_X)
9a599a60
EZ
1205 {
1206 new_pos_X = tem_X;
1207 update_cursor_pos = 1;
1208 }
fc171623 1209 }
2d764c78 1210#endif
fc171623
KH
1211
1212 if (update_cursor_pos
1213 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1214 {
1215 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
3e1944a3
EZ
1216 if (tty->termscript)
1217 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
fc171623
KH
1218 }
1219
1220 /* Maybe cursor is invisible, so make it visible. */
1221 IT_display_cursor (1);
1222
1223 /* Mouse pointer should be always visible if we are waiting for
1224 keyboard input. */
1225 if (!mouse_visible)
1226 mouse_on ();
1227}
1228
71f65669 1229static void
41ad069b 1230IT_update_begin (struct frame *f)
f32d4091 1231{
3e1944a3 1232 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
34574c02
EZ
1233 Mouse_HLInfo *hlinfo = &display_info->mouse_highlight;
1234 struct frame *mouse_face_frame = hlinfo->mouse_face_mouse_frame;
41ad069b 1235
7ccd1daf
EZ
1236 if (display_info->termscript)
1237 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1238
4d7e6e51 1239 block_input ();
41ad069b 1240
b9f80d41 1241 if (f && f == mouse_face_frame)
41ad069b
EZ
1242 {
1243 /* Don't do highlighting for mouse motion during the update. */
34574c02 1244 hlinfo->mouse_face_defer = 1;
41ad069b
EZ
1245
1246 /* If F needs to be redrawn, simply forget about any prior mouse
1247 highlighting. */
1248 if (FRAME_GARBAGED_P (f))
34574c02 1249 hlinfo->mouse_face_window = Qnil;
41ad069b
EZ
1250
1251 /* Can we tell that this update does not affect the window
1252 where the mouse highlight is? If so, no need to turn off.
48c14970
EZ
1253 Likewise, don't do anything if none of the enabled rows
1254 contains glyphs highlighted in mouse face. */
34574c02
EZ
1255 if (!NILP (hlinfo->mouse_face_window)
1256 && WINDOWP (hlinfo->mouse_face_window))
41ad069b 1257 {
34574c02 1258 struct window *w = XWINDOW (hlinfo->mouse_face_window);
41ad069b
EZ
1259 int i;
1260
8ccb9a54
EZ
1261 /* If the mouse highlight is in the window that was deleted
1262 (e.g., if it was popped by completion), clear highlight
1263 unconditionally. */
e74aeda8 1264 if (NILP (w->contents))
34574c02 1265 hlinfo->mouse_face_window = Qnil;
8ccb9a54
EZ
1266 else
1267 {
1268 for (i = 0; i < w->desired_matrix->nrows; ++i)
48c14970
EZ
1269 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1270 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
8ccb9a54
EZ
1271 break;
1272 }
41ad069b 1273
e74aeda8 1274 if (NILP (w->contents) || i < w->desired_matrix->nrows)
34574c02 1275 clear_mouse_face (hlinfo);
41ad069b
EZ
1276 }
1277 }
b9f80d41 1278 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
41ad069b
EZ
1279 {
1280 /* If the frame with mouse highlight was deleted, invalidate the
1281 highlight info. */
34574c02
EZ
1282 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1283 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1284 hlinfo->mouse_face_window = Qnil;
34574c02 1285 hlinfo->mouse_face_mouse_frame = NULL;
41ad069b
EZ
1286 }
1287
4d7e6e51 1288 unblock_input ();
f32d4091
KS
1289}
1290
71f65669 1291static void
41ad069b 1292IT_update_end (struct frame *f)
f32d4091 1293{
7ccd1daf
EZ
1294 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1295
1296 if (dpyinfo->termscript)
1297 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
34574c02 1298 dpyinfo->mouse_highlight.mouse_face_defer = 0;
41ad069b
EZ
1299}
1300
1301static void
1302IT_frame_up_to_date (struct frame *f)
1303{
0c3cfc51
EZ
1304 Lisp_Object new_cursor, frame_desired_cursor;
1305 struct window *sw;
41ad069b 1306
5c747675 1307 FRAME_MOUSE_UPDATE (f);
41ad069b 1308
0c3cfc51
EZ
1309 /* Set the cursor type to whatever they wanted. In a minibuffer
1310 window, we want the cursor to appear only if we are reading input
1311 from this window, and we want the cursor to be taken from the
1312 frame parameters. For the selected window, we use either its
1313 buffer-local value or the value from the frame parameters if the
1314 buffer doesn't define its local value for the cursor type. */
e69b0960
DA
1315 sw = XWINDOW (f->selected_window);
1316 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
0c3cfc51
EZ
1317 if (cursor_in_echo_area
1318 && FRAME_HAS_MINIBUF_P (f)
1319 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1320 && sw == XWINDOW (echo_area_window))
1321 new_cursor = frame_desired_cursor;
1322 else
1323 {
e74aeda8 1324 struct buffer *b = XBUFFER (sw->contents);
0c3cfc51 1325
4b4deea2 1326 if (EQ (BVAR (b,cursor_type), Qt))
0c3cfc51 1327 new_cursor = frame_desired_cursor;
4b4deea2 1328 else if (NILP (BVAR (b, cursor_type))) /* nil means no cursor */
0c3cfc51
EZ
1329 new_cursor = Fcons (Qbar, make_number (0));
1330 else
4b4deea2 1331 new_cursor = BVAR (b, cursor_type);
0c3cfc51
EZ
1332 }
1333
1334 IT_set_cursor_type (f, new_cursor);
8ba01a32 1335
41ad069b 1336 IT_cmgoto (f); /* position cursor when update is done */
f32d4091 1337}
1b94449f 1338
c77f6f1b
EZ
1339/* Copy LEN glyphs displayed on a single line whose vertical position
1340 is YPOS, beginning at horizontal position XFROM to horizontal
1341 position XTO, by moving blocks in the video memory. Used by
1342 functions that insert and delete glyphs. */
1343static void
1344IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1345{
1346 /* The offsets of source and destination relative to the
53964682 1347 conventional memory selector. */
c77f6f1b
EZ
1348 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1349 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1350
1351 if (from == to || len <= 0)
1352 return;
1353
1354 _farsetsel (_dos_ds);
1355
1356 /* The source and destination might overlap, so we need to move
1357 glyphs non-destructively. */
1358 if (from > to)
1359 {
1360 for ( ; len; from += 2, to += 2, len--)
1361 _farnspokew (to, _farnspeekw (from));
1362 }
1363 else
1364 {
1365 from += (len - 1) * 2;
1366 to += (len - 1) * 2;
1367 for ( ; len; from -= 2, to -= 2, len--)
1368 _farnspokew (to, _farnspeekw (from));
1369 }
1370 if (screen_virtual_segment)
1371 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1372}
1373
1374/* Insert and delete glyphs. */
aa9ce936 1375static void
3a8ce822 1376IT_insert_glyphs (struct frame *f, struct glyph *start, int len)
aa9ce936 1377{
c77f6f1b
EZ
1378 int shift_by_width = screen_size_X - (new_pos_X + len);
1379
1380 /* Shift right the glyphs from the nominal cursor position to the
1381 end of this line. */
1382 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1383
1384 /* Now write the glyphs to be inserted. */
3e1944a3 1385 IT_write_glyphs (f, start, len);
aa9ce936
EZ
1386}
1387
1388static void
3a8ce822 1389IT_delete_glyphs (struct frame *f, int n)
aa9ce936 1390{
1088b922 1391 emacs_abort ();
aa9ce936
EZ
1392}
1393
211c7152 1394/* set-window-configuration on window.c needs this. */
3bb1f22f 1395void
3a8ce822 1396x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
3bb1f22f 1397{
211c7152
EZ
1398 set_menu_bar_lines (f, value, oldval);
1399}
3bb1f22f 1400
984f5aaa 1401/* This was copied from xfaces.c */
3bb1f22f 1402
984f5aaa
EZ
1403extern Lisp_Object Qbackground_color;
1404extern Lisp_Object Qforeground_color;
8ba01a32 1405Lisp_Object Qreverse;
211c7152 1406extern Lisp_Object Qtitle;
3bb1f22f 1407
48ffe371
RS
1408/* IT_set_terminal_modes is called when emacs is started,
1409 resumed, and whenever the screen is redrawn! */
f32d4091 1410
71f65669 1411static void
3e1944a3 1412IT_set_terminal_modes (struct terminal *term)
f32d4091 1413{
3e1944a3
EZ
1414 struct tty_display_info *tty;
1415
1416 /* If called with initial terminal, it's too early to do anything
1417 useful. */
1418 if (term->type == output_initial)
1419 return;
1420
1421 tty = term->display_info.tty;
1422
1423 if (tty->termscript)
1424 fprintf (tty->termscript, "\n<SET_TERM>");
f32d4091
KS
1425
1426 screen_size_X = ScreenCols ();
1427 screen_size_Y = ScreenRows ();
1428 screen_size = screen_size_X * screen_size_Y;
56e19ec4 1429
f32d4091
KS
1430 new_pos_X = new_pos_Y = 0;
1431 current_pos_X = current_pos_Y = -1;
1432
1433 if (term_setup_done)
1434 return;
1435 term_setup_done = 1;
56e19ec4 1436
f32d4091
KS
1437 startup_screen_size_X = screen_size_X;
1438 startup_screen_size_Y = screen_size_Y;
c9adab25 1439 startup_screen_attrib = ScreenAttrib;
f32d4091 1440
039274cf
EZ
1441 /* Is DOS/V (or any other RSIS software which relocates
1442 the screen) installed? */
1443 {
1444 unsigned short es_value;
1445 __dpmi_regs regs;
1446
1447 regs.h.ah = 0xfe; /* get relocated screen address */
1448 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1449 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1450 else if (screen_old_address) /* already switched to Japanese mode once */
1451 regs.x.es = (screen_old_address >> 4) & 0xffff;
1452 else
1453 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1454 regs.x.di = 0;
1455 es_value = regs.x.es;
1456 __dpmi_int (0x10, &regs);
1457
d1d5dc19 1458 if (regs.x.es != es_value)
039274cf 1459 {
d1d5dc19
EZ
1460 /* screen_old_address is only set if ScreenPrimary does NOT
1461 already point to the relocated buffer address returned by
1462 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1463 ScreenPrimary to that address at startup under DOS/V. */
891ef8f7 1464 if (regs.x.es != ((ScreenPrimary >> 4) & 0xffff))
d1d5dc19 1465 screen_old_address = ScreenPrimary;
039274cf
EZ
1466 screen_virtual_segment = regs.x.es;
1467 screen_virtual_offset = regs.x.di;
1468 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1469 }
1470 }
039274cf 1471
f32d4091
KS
1472 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1473 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1474
76ac1508 1475 bright_bg ();
f32d4091
KS
1476}
1477
48ffe371
RS
1478/* IT_reset_terminal_modes is called when emacs is
1479 suspended or killed. */
f32d4091 1480
71f65669 1481static void
3e1944a3 1482IT_reset_terminal_modes (struct terminal *term)
f32d4091 1483{
c9adab25
KH
1484 int display_row_start = (int) ScreenPrimary;
1485 int saved_row_len = startup_screen_size_X * 2;
56e19ec4 1486 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
c9adab25
KH
1487 int to_next_row = update_row_len;
1488 unsigned char *saved_row = startup_screen_buffer;
56e19ec4 1489 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
3e1944a3 1490 struct tty_display_info *tty = term->display_info.tty;
c9adab25 1491
3e1944a3
EZ
1492 if (tty->termscript)
1493 fprintf (tty->termscript, "\n<RESET_TERM>");
f32d4091 1494
f32d4091
KS
1495 if (!term_setup_done)
1496 return;
56e19ec4 1497
c9adab25 1498 mouse_off ();
b36701cc
RS
1499
1500 /* Leave the video system in the same state as we found it,
1501 as far as the blink/bright-background bit is concerned. */
1502 maybe_enable_blinking ();
06b1ea13 1503
c9adab25
KH
1504 /* We have a situation here.
1505 We cannot just do ScreenUpdate(startup_screen_buffer) because
1506 the luser could have changed screen dimensions inside Emacs
1507 and failed (or didn't want) to restore them before killing
1508 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1509 thus will happily use memory outside what was allocated for
1510 `startup_screen_buffer'.
1511 Thus we only restore as much as the current screen dimensions
1512 can hold, and clear the rest (if the saved screen is smaller than
1513 the current) with the color attribute saved at startup. The cursor
1514 is also restored within the visible dimensions. */
1515
1516 ScreenAttrib = startup_screen_attrib;
c9adab25 1517
06b1ea13
EZ
1518 /* Don't restore the screen if we are exiting less than 2 seconds
1519 after startup: we might be crashing, and the screen might show
1520 some vital clues to what's wrong. */
1521 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
c9adab25 1522 {
06b1ea13 1523 ScreenClear ();
039274cf 1524 if (screen_virtual_segment)
06b1ea13
EZ
1525 dosv_refresh_virtual_screen (0, screen_size);
1526
1527 if (update_row_len > saved_row_len)
1528 update_row_len = saved_row_len;
1529 if (current_rows > startup_screen_size_Y)
1530 current_rows = startup_screen_size_Y;
1531
3e1944a3
EZ
1532 if (tty->termscript)
1533 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
06b1ea13
EZ
1534 update_row_len / 2, current_rows);
1535
1536 while (current_rows--)
1537 {
1538 dosmemput (saved_row, update_row_len, display_row_start);
1539 if (screen_virtual_segment)
1540 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1541 update_row_len / 2);
1542 saved_row += saved_row_len;
1543 display_row_start += to_next_row;
1544 }
c9adab25
KH
1545 }
1546 if (startup_pos_X < cursor_pos_X)
1547 cursor_pos_X = startup_pos_X;
1548 if (startup_pos_Y < cursor_pos_Y)
1549 cursor_pos_Y = startup_pos_Y;
1550
1551 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1552 xfree (startup_screen_buffer);
3e1944a3 1553 startup_screen_buffer = NULL;
f32d4091
KS
1554
1555 term_setup_done = 0;
1556}
1557
71f65669 1558static void
3e1944a3 1559IT_set_terminal_window (struct frame *f, int foo)
f32d4091
KS
1560{
1561}
1562
20db1522 1563/* Remember the screen colors of the current frame, to serve as the
2d764c78 1564 default colors for newly-created frames. */
2d764c78
EZ
1565DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1566 Smsdos_remember_default_colors, 1, 1, 0,
70da46c3 1567 doc: /* Remember the screen colors of the current frame. */)
5842a27b 1568 (Lisp_Object frame)
2d764c78 1569{
2d764c78
EZ
1570 struct frame *f;
1571
b7826503 1572 CHECK_FRAME (frame);
f12dae2f 1573 f = XFRAME (frame);
2d764c78 1574
ff12cd1d
EZ
1575 /* This function is called after applying default-frame-alist to the
1576 initial frame. At that time, if reverse-colors option was
1577 specified in default-frame-alist, it was already applied, and
f12dae2f
EZ
1578 frame colors are reversed. */
1579 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
1580 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
891ef8f7
EZ
1581
1582 return Qnil;
2d764c78
EZ
1583}
1584
f32d4091 1585void
3a8ce822 1586IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
f32d4091
KS
1587{
1588 Lisp_Object tail;
56e19ec4 1589 int i, j, length = XINT (Flength (alist));
db722735 1590 Lisp_Object *parms
663e2b3f 1591 = (Lisp_Object *) alloca (length * word_size);
db722735 1592 Lisp_Object *values
663e2b3f 1593 = (Lisp_Object *) alloca (length * word_size);
2d764c78 1594 /* Do we have to reverse the foreground and background colors? */
e69b0960 1595 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2d764c78 1596 int redraw = 0, fg_set = 0, bg_set = 0;
56e19ec4 1597 unsigned long orig_fg, orig_bg;
3e1944a3 1598 struct tty_display_info *tty = FRAME_TTY (f);
2d764c78
EZ
1599
1600 /* If we are creating a new frame, begin with the original screen colors
1601 used for the initial frame. */
76ea4cc9 1602 if (!f->default_face_done_p
2d764c78
EZ
1603 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1604 {
1605 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1606 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
f12dae2f 1607 init_frame_faces (f);
76ea4cc9 1608 f->default_face_done_p = 1;
2d764c78 1609 }
76ea4cc9
EZ
1610 orig_fg = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1611 orig_bg = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
db722735
RS
1612
1613 /* Extract parm names and values into those vectors. */
1614 i = 0;
7d7bbefd 1615 for (tail = alist; CONSP (tail); tail = XCDR (tail))
f32d4091 1616 {
34348bd4 1617 Lisp_Object elt = XCAR (tail);
db722735 1618 parms[i] = Fcar (elt);
b7826503 1619 CHECK_SYMBOL (parms[i]);
db722735
RS
1620 values[i] = Fcdr (elt);
1621 i++;
1622 }
1623
2d764c78 1624 j = i;
db722735 1625
2d764c78
EZ
1626 for (i = 0; i < j; i++)
1627 {
1e21fe48
EZ
1628 Lisp_Object prop, val;
1629
1630 prop = parms[i];
1631 val = values[i];
2d764c78 1632
8ba01a32 1633 if (EQ (prop, Qreverse))
2d764c78
EZ
1634 reverse = EQ (val, Qt);
1635 }
546701f5 1636
76ea4cc9 1637 if (tty->termscript && reverse)
3e1944a3 1638 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2d764c78
EZ
1639
1640 /* Now process the alist elements in reverse of specified order. */
db722735
RS
1641 for (i--; i >= 0; i--)
1642 {
76ea4cc9 1643 Lisp_Object prop, val;
1e21fe48
EZ
1644
1645 prop = parms[i];
1646 val = values[i];
f32d4091 1647
4e825084 1648 if (EQ (prop, Qforeground_color))
f32d4091 1649 {
76ea4cc9 1650 unsigned long new_color = load_color (f, NULL, val, reverse
2d764c78
EZ
1651 ? LFACE_BACKGROUND_INDEX
1652 : LFACE_FOREGROUND_INDEX);
3b620731
EZ
1653 if (new_color != FACE_TTY_DEFAULT_COLOR
1654 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1655 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
f32d4091 1656 {
76ea4cc9
EZ
1657 if (!reverse)
1658 {
1659 FRAME_FOREGROUND_PIXEL (f) = new_color;
1660 /* Make sure the foreground of the default face for
1661 this frame is changed as well. */
1662 update_face_from_frame_parameter (f, Qforeground_color, val);
1663 fg_set = 1;
1664 if (tty->termscript)
1665 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1666 }
1667 else
1668 {
1669 FRAME_BACKGROUND_PIXEL (f) = new_color;
1670 update_face_from_frame_parameter (f, Qbackground_color, val);
1671 bg_set = 1;
1672 if (tty->termscript)
1673 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1674 }
f32d4091
KS
1675 redraw = 1;
1676 }
1677 }
4e825084 1678 else if (EQ (prop, Qbackground_color))
f32d4091 1679 {
76ea4cc9 1680 unsigned long new_color = load_color (f, NULL, val, reverse
2d764c78
EZ
1681 ? LFACE_FOREGROUND_INDEX
1682 : LFACE_BACKGROUND_INDEX);
3b620731
EZ
1683 if (new_color != FACE_TTY_DEFAULT_COLOR
1684 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1685 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
f32d4091 1686 {
76ea4cc9
EZ
1687 if (!reverse)
1688 {
1689 FRAME_BACKGROUND_PIXEL (f) = new_color;
1690 /* Make sure the background of the default face for
1691 this frame is changed as well. */
1692 bg_set = 1;
1693 update_face_from_frame_parameter (f, Qbackground_color, val);
1694 if (tty->termscript)
1695 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1696 }
1697 else
1698 {
1699 FRAME_FOREGROUND_PIXEL (f) = new_color;
1700 fg_set = 1;
1701 update_face_from_frame_parameter (f, Qforeground_color, val);
1702 if (tty->termscript)
1703 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1704 }
f32d4091
KS
1705 redraw = 1;
1706 }
1707 }
211c7152
EZ
1708 else if (EQ (prop, Qtitle))
1709 {
1710 x_set_title (f, val);
3e1944a3
EZ
1711 if (tty->termscript)
1712 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
211c7152 1713 }
8ba01a32
EZ
1714 else if (EQ (prop, Qcursor_type))
1715 {
1716 IT_set_cursor_type (f, val);
3e1944a3
EZ
1717 if (tty->termscript)
1718 fprintf (tty->termscript, "<CTYPE: %s>\n",
891ef8f7
EZ
1719 EQ (val, Qbar)
1720 || EQ (val, Qhbar)
1721 || (CONSP (val) && (EQ (XCAR (val), Qbar)
1722 || EQ (XCAR (val), Qhbar)))
8ba01a32
EZ
1723 ? "bar" : "box");
1724 }
3e1944a3
EZ
1725 else if (EQ (prop, Qtty_type))
1726 {
1727 internal_terminal_init ();
1728 if (tty->termscript)
1729 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1730 SBYTES (val), SDATA (val));
1731 }
db722735 1732 store_frame_param (f, prop, val);
2d764c78 1733 }
db722735 1734
2d764c78
EZ
1735 /* If they specified "reverse", but not the colors, we need to swap
1736 the current frame colors. */
76ea4cc9 1737 if (reverse)
2d764c78
EZ
1738 {
1739 if (!fg_set)
1740 {
76ea4cc9
EZ
1741 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1742 update_face_from_frame_parameter (f, Qforeground_color,
1743 tty_color_name (f, orig_bg));
2d764c78
EZ
1744 redraw = 1;
1745 }
1746 if (!bg_set)
1747 {
76ea4cc9
EZ
1748 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1749 update_face_from_frame_parameter (f, Qbackground_color,
1750 tty_color_name (f, orig_fg));
2d764c78
EZ
1751 redraw = 1;
1752 }
f32d4091
KS
1753 }
1754
1755 if (redraw)
1756 {
2d764c78 1757 face_change_count++; /* forces xdisp.c to recompute basic faces */
5e617bc2 1758 if (f == SELECTED_FRAME ())
3bb1f22f 1759 redraw_frame (f);
f32d4091
KS
1760 }
1761}
1762
a7cf9151
EZ
1763extern void init_frame_faces (FRAME_PTR);
1764
f32d4091
KS
1765#endif /* !HAVE_X_WINDOWS */
1766
1767
48ffe371
RS
1768/* Do we need the internal terminal? */
1769
f32d4091 1770void
3a8ce822 1771internal_terminal_init (void)
f32d4091 1772{
2306a735 1773 static int init_needed = 1;
56e19ec4 1774 char *term = getenv ("TERM"), *colors;
5e617bc2 1775 struct frame *sf = SELECTED_FRAME ();
3e1944a3 1776 struct tty_display_info *tty;
f32d4091
KS
1777
1778#ifdef HAVE_X_WINDOWS
1779 if (!inhibit_window_system)
1780 return;
1781#endif
1782
3e1944a3
EZ
1783 /* If this is the initial terminal, we are done here. */
1784 if (sf->output_method == output_initial)
1785 return;
1786
f32d4091
KS
1787 internal_terminal
1788 = (!noninteractive) && term && !strcmp (term, "internal");
1789
f32d4091
KS
1790#ifndef HAVE_X_WINDOWS
1791 if (!internal_terminal || inhibit_window_system)
1792 {
2d764c78 1793 sf->output_method = output_termcap;
f32d4091
KS
1794 return;
1795 }
1796
3e1944a3 1797 tty = FRAME_TTY (sf);
15dbb4d6 1798 kset_window_system (current_kboard, Qpc);
f12dae2f 1799 sf->output_method = output_msdos_raw;
2306a735 1800 if (init_needed)
3e1944a3 1801 {
2306a735
EZ
1802 if (!tty->termscript && getenv ("EMACSTEST"))
1803 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
1804 if (tty->termscript)
1805 {
1806 time_t now = time (NULL);
1807 struct tm *tnow = localtime (&now);
1808 char tbuf[100];
3e1944a3 1809
2306a735
EZ
1810 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
1811 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
1812 fprintf (tty->termscript, "=====================\n\n");
1813 }
3e1944a3 1814
2306a735 1815 Vinitial_window_system = Qpc;
23415acf 1816 Vwindow_system_version = make_number (24); /* RE Emacs version */
2306a735 1817 tty->terminal->type = output_msdos_raw;
039274cf 1818
2306a735
EZ
1819 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1820 address. */
1821 screen_old_address = 0;
039274cf 1822
2306a735
EZ
1823 /* Forget the stale screen colors as well. */
1824 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2d764c78 1825
2306a735
EZ
1826 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1827 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1828 bright_bg ();
1829 colors = getenv ("EMACSCOLORS");
1830 if (colors && strlen (colors) >= 2)
1831 {
1832 /* The colors use 4 bits each (we enable bright background). */
1833 if (isdigit (colors[0]))
1834 colors[0] -= '0';
1835 else if (isxdigit (colors[0]))
1836 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1837 if (colors[0] >= 0 && colors[0] < 16)
1838 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
1839 if (isdigit (colors[1]))
1840 colors[1] -= '0';
1841 else if (isxdigit (colors[1]))
1842 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1843 if (colors[1] >= 0 && colors[1] < 16)
1844 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
1845 }
34574c02 1846 the_only_display_info.mouse_highlight.mouse_face_mouse_frame = NULL;
34574c02
EZ
1847 the_only_display_info.mouse_highlight.mouse_face_beg_row =
1848 the_only_display_info.mouse_highlight.mouse_face_beg_col = -1;
1849 the_only_display_info.mouse_highlight.mouse_face_end_row =
1850 the_only_display_info.mouse_highlight.mouse_face_end_col = -1;
1851 the_only_display_info.mouse_highlight.mouse_face_face_id = DEFAULT_FACE_ID;
1852 the_only_display_info.mouse_highlight.mouse_face_window = Qnil;
1853 the_only_display_info.mouse_highlight.mouse_face_mouse_x =
1854 the_only_display_info.mouse_highlight.mouse_face_mouse_y = 0;
1855 the_only_display_info.mouse_highlight.mouse_face_defer = 0;
1856 the_only_display_info.mouse_highlight.mouse_face_hidden = 0;
2306a735
EZ
1857
1858 if (have_mouse) /* detected in dos_ttraw, which see */
1859 {
1860 have_mouse = 1; /* enable mouse */
1861 mouse_visible = 0;
1862 mouse_setup_buttons (mouse_button_count);
1863 tty->terminal->mouse_position_hook = &mouse_get_pos;
1864 mouse_init ();
1865 }
f32d4091 1866
2306a735
EZ
1867 if (tty->termscript && screen_size)
1868 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1869 screen_size_X, screen_size_Y);
f32d4091 1870
f12dae2f 1871 init_frame_faces (sf);
2306a735
EZ
1872 init_needed = 0;
1873 }
f32d4091
KS
1874#endif
1875}
1876
3e1944a3
EZ
1877void
1878initialize_msdos_display (struct terminal *term)
1879{
1880 term->rif = 0; /* we don't support window-based display */
1881 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
1882 term->clear_to_end_hook = IT_clear_to_end;
1883 term->clear_frame_hook = IT_clear_screen;
1884 term->clear_end_of_line_hook = IT_clear_end_of_line;
1885 term->ins_del_lines_hook = 0;
1886 term->insert_glyphs_hook = IT_insert_glyphs;
1887 term->write_glyphs_hook = IT_write_glyphs;
1888 term->delete_glyphs_hook = IT_delete_glyphs;
1889 term->ring_bell_hook = IT_ring_bell;
1890 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
1891 term->set_terminal_modes_hook = IT_set_terminal_modes;
1892 term->set_terminal_window_hook = IT_set_terminal_window;
1893 term->update_begin_hook = IT_update_begin;
1894 term->update_end_hook = IT_update_end;
1895 term->frame_up_to_date_hook = IT_frame_up_to_date;
1896 term->mouse_position_hook = 0; /* set later by dos_ttraw */
1897 term->frame_rehighlight_hook = 0;
1898 term->frame_raise_lower_hook = 0;
1899 term->set_vertical_scroll_bar_hook = 0;
1900 term->condemn_scroll_bars_hook = 0;
1901 term->redeem_scroll_bar_hook = 0;
1902 term->judge_scroll_bars_hook = 0;
1903 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
1904}
1905
3a8ce822
EZ
1906int
1907dos_get_saved_screen (char **screen, int *rows, int *cols)
f32d4091
KS
1908{
1909#ifndef HAVE_X_WINDOWS
1910 *screen = startup_screen_buffer;
1911 *cols = startup_screen_size_X;
1912 *rows = startup_screen_size_Y;
039274cf 1913 return *screen != (char *)0;
f32d4091
KS
1914#else
1915 return 0;
56e19ec4 1916#endif
f32d4091 1917}
3bb1f22f
RS
1918
1919#ifndef HAVE_X_WINDOWS
1920
1921/* We are not X, but we can emulate it well enough for our needs... */
1922void
73931ad1 1923check_window_system (void)
3bb1f22f 1924{
5e617bc2 1925 if (! FRAME_MSDOS_P (SELECTED_FRAME ()))
2d764c78 1926 error ("Not running under a window system");
3bb1f22f
RS
1927}
1928
1929#endif
1930
5063b150 1931\f
f32d4091
KS
1932/* ----------------------- Keyboard control ----------------------
1933 *
1934 * Keymaps reflect the following keyboard layout:
1935 *
1936 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1937 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1938 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1939 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1940 * SPACE
1941 */
1942
d1d5dc19
EZ
1943#define Ignore 0x0000
1944#define Normal 0x0000 /* normal key - alt changes scan-code */
1945#define FctKey 0x1000 /* func key if c == 0, else c */
1946#define Special 0x2000 /* func key even if c != 0 */
1947#define ModFct 0x3000 /* special if mod-keys, else 'c' */
1948#define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1949#define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1950#define Grey 0x6000 /* Grey keypad key */
1951
1952#define Alt 0x0100 /* alt scan-code */
1953#define Ctrl 0x0200 /* ctrl scan-code */
1954#define Shift 0x0400 /* shift scan-code */
1955
db9cd97a 1956static int extended_kbd; /* 101 (102) keyboard present. */
f32d4091 1957
d1d5dc19
EZ
1958struct kbd_translate {
1959 unsigned char sc;
1960 unsigned char ch;
1961 unsigned short code;
1962};
1963
f32d4091
KS
1964struct dos_keyboard_map
1965{
1966 char *unshifted;
1967 char *shifted;
1968 char *alt_gr;
d1d5dc19 1969 struct kbd_translate *translate_table;
f32d4091
KS
1970};
1971
1972
1973static struct dos_keyboard_map us_keyboard = {
1974/* 0 1 2 3 4 5 */
d26e478e
EZ
1975/* 01234567890123456789012345678901234567890 123 45678901234 */
1976 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ \\zxcvbnm,./ ",
f32d4091 1977/* 0123456789012345678901234567890123456789 012345678901234 */
d26e478e 1978 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| |ZXCVBNM<>? ",
d1d5dc19
EZ
1979 0, /* no Alt-Gr key */
1980 0 /* no translate table */
f32d4091
KS
1981};
1982
1983static struct dos_keyboard_map fr_keyboard = {
1984/* 0 1 2 3 4 5 */
1985/* 012 3456789012345678901234567890123456789012345678901234 */
d26e478e 1986