msdos.c 117 KB
Newer Older
1
/* MS-DOS specific C utilities.          -*- coding: raw-text -*-
2 3

Copyright (C) 1993-1997, 1999-2011  Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
4 5 6

This file is part of GNU Emacs.

7
GNU Emacs is free software: you can redistribute it and/or modify
Richard M. Stallman's avatar
Richard M. Stallman committed
8
it under the terms of the GNU General Public License as published by
9 10
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Richard M. Stallman's avatar
Richard M. Stallman committed
11 12 13 14 15 16 17

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
18
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
19

20
/* Contributed by Morten Welinder */
Kim F. Storm's avatar
Kim F. Storm committed
21
/* New display, keyboard, and mouse control by Kim F. Storm */
22

Richard M. Stallman's avatar
Richard M. Stallman committed
23 24
/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */

Richard M. Stallman's avatar
Richard M. Stallman committed
25
#include <config.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
26 27

#ifdef MSDOS
28
#include <setjmp.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
29 30
#include "lisp.h"
#include <stdio.h>
31
#include <time.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
32 33 34
#include <sys/param.h>
#include <sys/time.h>
#include <dos.h>
35 36
#include <errno.h>
#include <sys/stat.h>    /* for _fixpath */
37
#include <unistd.h>	 /* for chdir, dup, dup2, etc. */
38
#include <dir.h>	 /* for getdisk */
39
#pragma pack(0)		 /* dir.h does a pack(4), which isn't GCC's default */
40
#include <fcntl.h>
41
#include <io.h>		 /* for setmode */
42 43
#include <dpmi.h>	 /* for __dpmi_xxx stuff */
#include <sys/farptr.h>	 /* for _farsetsel, _farnspokeb */
44
#include <libc/dosio.h>  /* for _USE_LFN */
45
#include <conio.h>	 /* for cputs */
46

Richard M. Stallman's avatar
Richard M. Stallman committed
47 48
#include "msdos.h"
#include "systime.h"
49
#include "frame.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
50
#include "termhooks.h"
51
#include "termchar.h"
Morten Welinder's avatar
Morten Welinder committed
52
#include "dispextern.h"
53
#include "dosfns.h"
Morten Welinder's avatar
Morten Welinder committed
54
#include "termopts.h"
55
#include "character.h"
56 57
#include "coding.h"
#include "disptab.h"
Morten Welinder's avatar
Morten Welinder committed
58
#include "window.h"
59 60
#include "buffer.h"
#include "commands.h"
61
#include "blockinput.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
62
#include "keyboard.h"
Kenichi Handa's avatar
Kenichi Handa committed
63
#include "intervals.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
64 65 66 67
#include <go32.h>
#include <pc.h>
#include <ctype.h>
/* #include <process.h> */
68 69
/* Damn that local process.h!  Instead we can define P_WAIT and
   spawnve ourselves.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
70
#define P_WAIT 1
71
extern int spawnve (int, const char *, char *const [], char *const []);
Richard M. Stallman's avatar
Richard M. Stallman committed
72

73 74 75 76
#ifndef _USE_LFN
#define _USE_LFN 0
#endif

77 78 79 80
#ifndef _dos_ds
#define _dos_ds _go32_info_block.selector_for_linear_memory
#endif

Richard M. Stallman's avatar
Richard M. Stallman committed
81
#include <signal.h>
82
#include "syssignal.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
83

84 85 86
#include "careadlinkat.h"
#include "allocator.h"

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
#ifndef SYSTEM_MALLOC

#ifdef GNU_MALLOC

/* If other `malloc' than ours is used, force our `sbrk' behave like
   Unix programs expect (resize memory blocks to keep them contiguous).
   If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
   because that's what `gmalloc' expects to get.  */
#include <crt0.h>

#ifdef REL_ALLOC
int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
#else  /* not REL_ALLOC */
int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
#endif /* not REL_ALLOC */
#endif /* GNU_MALLOC */

#endif /* not SYSTEM_MALLOC */
105 106

static unsigned long
107
event_timestamp (void)
108 109 110
{
  struct time t;
  unsigned long s;
Eli Zaretskii's avatar
Eli Zaretskii committed
111

112 113 114 115 116 117
  gettime (&t);
  s = t.ti_min;
  s *= 60;
  s += t.ti_sec;
  s *= 1000;
  s += t.ti_hund * 10;
Eli Zaretskii's avatar
Eli Zaretskii committed
118

119 120 121
  return s;
}

Kim F. Storm's avatar
Kim F. Storm committed
122 123 124 125 126 127

/* ------------------------ Mouse control ---------------------------
 *
 * Coordinates are in screen positions and zero based.
 * Mouse buttons are numbered from left to right and also zero based.
 */
Richard M. Stallman's avatar
Richard M. Stallman committed
128

Eli Zaretskii's avatar
Eli Zaretskii committed
129 130 131 132
/* This used to be in termhooks.h, but mainstream Emacs code no longer
   uses it, and it was removed...  */
#define NUM_MOUSE_BUTTONS (5)

Kim F. Storm's avatar
Kim F. Storm committed
133 134
int have_mouse;          /* 0: no, 1: enabled, -1: disabled */
static int mouse_visible;
Richard M. Stallman's avatar
Richard M. Stallman committed
135

Kim F. Storm's avatar
Kim F. Storm committed
136 137
static int mouse_last_x;
static int mouse_last_y;
Richard M. Stallman's avatar
Richard M. Stallman committed
138

Kim F. Storm's avatar
Kim F. Storm committed
139 140
static int mouse_button_translate[NUM_MOUSE_BUTTONS];
static int mouse_button_count;
Richard M. Stallman's avatar
Richard M. Stallman committed
141

Kim F. Storm's avatar
Kim F. Storm committed
142
void
143
mouse_on (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
144 145 146
{
  union REGS regs;

Kim F. Storm's avatar
Kim F. Storm committed
147
  if (have_mouse > 0 && !mouse_visible)
Richard M. Stallman's avatar
Richard M. Stallman committed
148
    {
149 150 151 152
      struct tty_display_info *tty = CURTTY ();

      if (tty->termscript)
	fprintf (tty->termscript, "<M_ON>");
Kim F. Storm's avatar
Kim F. Storm committed
153 154 155
      regs.x.ax = 0x0001;
      int86 (0x33, &regs, &regs);
      mouse_visible = 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
156 157 158
    }
}

Kim F. Storm's avatar
Kim F. Storm committed
159
void
160
mouse_off (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
161
{
Kim F. Storm's avatar
Kim F. Storm committed
162
  union REGS regs;
Richard M. Stallman's avatar
Richard M. Stallman committed
163

Kim F. Storm's avatar
Kim F. Storm committed
164
  if (have_mouse > 0 && mouse_visible)
Richard M. Stallman's avatar
Richard M. Stallman committed
165
    {
166 167 168 169
      struct tty_display_info *tty = CURTTY ();

      if (tty->termscript)
	fprintf (tty->termscript, "<M_OFF>");
Kim F. Storm's avatar
Kim F. Storm committed
170 171 172
      regs.x.ax = 0x0002;
      int86 (0x33, &regs, &regs);
      mouse_visible = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
173 174 175
    }
}

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
static void
mouse_setup_buttons (int n_buttons)
{
  if (n_buttons == 3)
    {
      mouse_button_count = 3;
      mouse_button_translate[0] = 0; /* Left */
      mouse_button_translate[1] = 2; /* Middle */
      mouse_button_translate[2] = 1; /* Right */
    }
  else	/* two, what else? */
    {
      mouse_button_count = 2;
      mouse_button_translate[0] = 0;
      mouse_button_translate[1] = 1;
    }
}

DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
       1, 1, "NSet number of mouse buttons to: ",
196 197 198 199
       doc: /* Set the number of mouse buttons to use by Emacs.
This is useful with mice that report the number of buttons inconsistently,
e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
them.  This happens with wheeled mice on Windows 9X, for example.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
200
  (Lisp_Object nbuttons)
201
{
202 203
  int n;

204
  CHECK_NUMBER (nbuttons);
205 206
  n = XINT (nbuttons);
  if (n < 2 || n > 3)
207 208 209
    xsignal2 (Qargs_out_of_range,
	      build_string ("only 2 or 3 mouse buttons are supported"),
	      nbuttons);
210
  mouse_setup_buttons (n);
211 212 213
  return Qnil;
}

214 215 216 217 218 219 220 221 222 223 224
static void
mouse_get_xy (int *x, int *y)
{
  union REGS regs;

  regs.x.ax = 0x0003;
  int86 (0x33, &regs, &regs);
  *x = regs.x.cx / 8;
  *y = regs.x.dx / 8;
}

Kim F. Storm's avatar
Kim F. Storm committed
225
void
226
mouse_moveto (int x, int y)
Richard M. Stallman's avatar
Richard M. Stallman committed
227
{
Kim F. Storm's avatar
Kim F. Storm committed
228
  union REGS regs;
229
  struct tty_display_info *tty = CURTTY ();
Richard M. Stallman's avatar
Richard M. Stallman committed
230

231 232
  if (tty->termscript)
    fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
Kim F. Storm's avatar
Kim F. Storm committed
233 234 235 236
  regs.x.ax = 0x0004;
  mouse_last_x = regs.x.cx = x * 8;
  mouse_last_y = regs.x.dx = y * 8;
  int86 (0x33, &regs, &regs);
Richard M. Stallman's avatar
Richard M. Stallman committed
237 238
}

Kim F. Storm's avatar
Kim F. Storm committed
239
static int
240
mouse_pressed (int b, int *xp, int *yp)
Richard M. Stallman's avatar
Richard M. Stallman committed
241
{
Kim F. Storm's avatar
Kim F. Storm committed
242
  union REGS regs;
Richard M. Stallman's avatar
Richard M. Stallman committed
243

Kim F. Storm's avatar
Kim F. Storm committed
244 245 246 247 248 249 250 251
  if (b >= mouse_button_count)
    return 0;
  regs.x.ax = 0x0005;
  regs.x.bx = mouse_button_translate[b];
  int86 (0x33, &regs, &regs);
  if (regs.x.bx)
    *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
  return (regs.x.bx != 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
252 253
}

Kim F. Storm's avatar
Kim F. Storm committed
254
static int
255
mouse_released (int b, int *xp, int *yp)
Richard M. Stallman's avatar
Richard M. Stallman committed
256 257 258
{
  union REGS regs;

Kim F. Storm's avatar
Kim F. Storm committed
259 260 261 262 263 264 265 266
  if (b >= mouse_button_count)
    return 0;
  regs.x.ax = 0x0006;
  regs.x.bx = mouse_button_translate[b];
  int86 (0x33, &regs, &regs);
  if (regs.x.bx)
    *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
  return (regs.x.bx != 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
267 268
}

269
static int
270
mouse_button_depressed (int b, int *xp, int *yp)
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
{
  union REGS regs;

  if (b >= mouse_button_count)
    return 0;
  regs.x.ax = 0x0003;
  int86 (0x33, &regs, &regs);
  if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
    {
      *xp = regs.x.cx / 8;
      *yp = regs.x.dx / 8;
      return 1;
    }
  return 0;
}

Kim F. Storm's avatar
Kim F. Storm committed
287
void
288 289
mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
	       enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
290
	       Time *time)
Kim F. Storm's avatar
Kim F. Storm committed
291 292
{
  int ix, iy;
293 294 295 296 297
  Lisp_Object frame, tail;

  /* Clear the mouse-moved flag for every frame on this display.  */
  FOR_EACH_FRAME (tail, frame)
    XFRAME (frame)->mouse_moved = 0;
Kim F. Storm's avatar
Kim F. Storm committed
298

299
  *f = SELECTED_FRAME();
Kim F. Storm's avatar
Kim F. Storm committed
300 301 302
  *bar_window = Qnil;
  mouse_get_xy (&ix, &iy);
  *time = event_timestamp ();
303 304
  *x = make_number (mouse_last_x = ix);
  *y = make_number (mouse_last_y = iy);
Kim F. Storm's avatar
Kim F. Storm committed
305
}
Richard M. Stallman's avatar
Richard M. Stallman committed
306

Kim F. Storm's avatar
Kim F. Storm committed
307
static void
308
mouse_check_moved (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
309
{
310
  int x, y;
Richard M. Stallman's avatar
Richard M. Stallman committed
311

Kim F. Storm's avatar
Kim F. Storm committed
312
  mouse_get_xy (&x, &y);
313
  SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
Kim F. Storm's avatar
Kim F. Storm committed
314 315 316
  mouse_last_x = x;
  mouse_last_y = y;
}
Richard M. Stallman's avatar
Richard M. Stallman committed
317

Eli Zaretskii's avatar
Eli Zaretskii committed
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
/* Force the mouse driver to ``forget'' about any button clicks until
   now.  */
static void
mouse_clear_clicks (void)
{
  int b;

  for (b = 0; b < mouse_button_count; b++)
    {
      int dummy_x, dummy_y;

      (void) mouse_pressed (b, &dummy_x, &dummy_y);
      (void) mouse_released (b, &dummy_x, &dummy_y);
    }
}

Kim F. Storm's avatar
Kim F. Storm committed
334
void
335
mouse_init (void)
Kim F. Storm's avatar
Kim F. Storm committed
336 337
{
  union REGS regs;
338
  struct tty_display_info *tty = CURTTY ();
339

340 341
  if (tty->termscript)
    fprintf (tty->termscript, "<M_INIT>");
Richard M. Stallman's avatar
Richard M. Stallman committed
342

Kim F. Storm's avatar
Kim F. Storm committed
343 344
  regs.x.ax = 0x0021;
  int86 (0x33, &regs, &regs);
345

346 347 348 349
  /* Reset the mouse last press/release info.  It seems that Windows
     doesn't do that automatically when function 21h is called, which
     causes Emacs to ``remember'' the click that switched focus to the
     window just before Emacs was started from that window.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
350
  mouse_clear_clicks ();
351

Kim F. Storm's avatar
Kim F. Storm committed
352 353 354 355
  regs.x.ax = 0x0007;
  regs.x.cx = 0;
  regs.x.dx = 8 * (ScreenCols () - 1);
  int86 (0x33, &regs, &regs);
Richard M. Stallman's avatar
Richard M. Stallman committed
356

Kim F. Storm's avatar
Kim F. Storm committed
357 358 359 360
  regs.x.ax = 0x0008;
  regs.x.cx = 0;
  regs.x.dx = 8 * (ScreenRows () - 1);
  int86 (0x33, &regs, &regs);
Richard M. Stallman's avatar
Richard M. Stallman committed
361

Kim F. Storm's avatar
Kim F. Storm committed
362 363 364
  mouse_moveto (0, 0);
  mouse_visible = 0;
}
Richard M. Stallman's avatar
Richard M. Stallman committed
365

Kim F. Storm's avatar
Kim F. Storm committed
366 367 368
/* ------------------------- Screen control ----------------------
 *
 */
369

Kim F. Storm's avatar
Kim F. Storm committed
370
static int internal_terminal = 0;
371

Kim F. Storm's avatar
Kim F. Storm committed
372 373 374
#ifndef HAVE_X_WINDOWS
extern unsigned char ScreenAttrib;
static int screen_face;
375

Kim F. Storm's avatar
Kim F. Storm committed
376 377 378
static int screen_size_X;
static int screen_size_Y;
static int screen_size;
Richard M. Stallman's avatar
Richard M. Stallman committed
379

Kim F. Storm's avatar
Kim F. Storm committed
380 381 382 383
static int current_pos_X;
static int current_pos_Y;
static int new_pos_X;
static int new_pos_Y;
Richard M. Stallman's avatar
Richard M. Stallman committed
384

Kim F. Storm's avatar
Kim F. Storm committed
385 386 387 388 389
static void *startup_screen_buffer;
static int startup_screen_size_X;
static int startup_screen_size_Y;
static int startup_pos_X;
static int startup_pos_Y;
390
static unsigned char startup_screen_attrib;
Richard M. Stallman's avatar
Richard M. Stallman committed
391

392 393
static clock_t startup_time;

Kim F. Storm's avatar
Kim F. Storm committed
394
static int term_setup_done;
Richard M. Stallman's avatar
Richard M. Stallman committed
395

396 397
static unsigned short outside_cursor;

Kim F. Storm's avatar
Kim F. Storm committed
398
/* Similar to the_only_frame.  */
399
struct tty_display_info the_only_display_info;
Richard M. Stallman's avatar
Richard M. Stallman committed
400

401 402 403 404 405 406 407 408
/* Support for DOS/V (allows Japanese characters to be displayed on
   standard, non-Japanese, ATs).  Only supported for DJGPP v2 and later.  */

/* Holds the address of the text-mode screen buffer.  */
static unsigned long screen_old_address = 0;
/* Segment and offset of the virtual screen.  If 0, DOS/V is NOT loaded.  */
static unsigned short screen_virtual_segment = 0;
static unsigned short screen_virtual_offset = 0;
Kenichi Handa's avatar
Kenichi Handa committed
409 410
extern Lisp_Object Qcursor_type;
extern Lisp_Object Qbar, Qhbar;
411

Juanma Barranquero's avatar
Juanma Barranquero committed
412
/* The screen colors of the current frame, which serve as the default
413 414 415
   colors for newly-created frames.  */
static int initial_screen_colors[2];

416 417 418 419 420 421 422
/* Update the screen from a part of relocated DOS/V screen buffer which
   begins at OFFSET and includes COUNT characters.  */
static void
dosv_refresh_virtual_screen (int offset, int count)
{
  __dpmi_regs regs;

423
  if (offset < 0 || count < 0)	/* paranoia; invalid values crash DOS/V */
424 425
    return;

426 427 428 429 430 431 432
  regs.h.ah = 0xff;	/* update relocated screen */
  regs.x.es = screen_virtual_segment;
  regs.x.di = screen_virtual_offset + offset;
  regs.x.cx = count;
  __dpmi_int (0x10, &regs);
}

433
static void
434
dos_direct_output (int y, int x, char *buf, int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
435
{
436 437
  int t0 = 2 * (x + y * screen_size_X);
  int t = t0 + (int) ScreenPrimary;
438
  int l0 = len;
439 440 441 442

  /* This is faster.  */
  for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
    _farnspokeb (t, *buf);
443 444 445

  if (screen_virtual_segment)
    dosv_refresh_virtual_screen (t0, l0);
Kim F. Storm's avatar
Kim F. Storm committed
446 447 448 449 450
}
#endif

#ifndef HAVE_X_WINDOWS

451 452
static int blink_bit = -1;	/* the state of the blink bit at startup */

453 454 455 456 457 458
/* Enable bright background colors.  */
static void
bright_bg (void)
{
  union REGS regs;

459 460 461 462 463
  /* Remember the original state of the blink/bright-background bit.
     It is stored at 0040:0065h in the BIOS data area.  */
  if (blink_bit == -1)
    blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;

464 465 466 467 468
  regs.h.bl = 0;
  regs.x.ax = 0x1003;
  int86 (0x10, &regs, &regs);
}

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
/* Disable bright background colors (and enable blinking) if we found
   the video system in that state at startup.  */
static void
maybe_enable_blinking (void)
{
  if (blink_bit == 1)
    {
      union REGS regs;

      regs.h.bl = 1;
      regs.x.ax = 0x1003;
      int86 (0x10, &regs, &regs);
    }
}

484 485 486 487 488 489 490 491 492 493 494 495 496
/* Return non-zero if the system has a VGA adapter.  */
static int
vga_installed (void)
{
  union REGS regs;

  regs.x.ax = 0x1a00;
  int86 (0x10, &regs, &regs);
  if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
    return 1;
  return 0;
}

497 498
/* Set the screen dimensions so that it can show no less than
   ROWS x COLS frame.  */
499

500
void
501
dos_set_window_size (int *rows, int *cols)
502 503 504
{
  char video_name[30];
  union REGS regs;
Eli Zaretskii's avatar
Eli Zaretskii committed
505 506
  Lisp_Object video_mode;
  int video_mode_value, have_vga = 0;
507 508 509 510 511 512
  int current_rows = ScreenRows (), current_cols = ScreenCols ();

  if (*rows == current_rows && *cols == current_cols)
    return;

  mouse_off ();
513
  have_vga = vga_installed ();
514

515
  /* If the user specified a special video mode for these dimensions,
516 517
     use that mode.  */
  sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
518
  video_mode = Fsymbol_value (Fintern_soft (build_string (video_name), Qnil));
519 520 521 522 523 524

  if (INTEGERP (video_mode)
      && (video_mode_value = XINT (video_mode)) > 0)
    {
      regs.x.ax = video_mode_value;
      int86 (0x10, &regs, &regs);
525 526 527 528 529 530 531 532 533

      if (have_mouse)
	{
	  /* Must hardware-reset the mouse, or else it won't update
	     its notion of screen dimensions for some non-standard
	     video modes.  This is *painfully* slow...  */
	  regs.x.ax = 0;
	  int86 (0x33, &regs, &regs);
	}
534 535 536 537 538 539 540
    }

  /* Find one of the dimensions supported by standard EGA/VGA
     which gives us at least the required dimensions.  */
  else
    {
      static struct {
Eli Zaretskii's avatar
Eli Zaretskii committed
541
	int rows, need_vga;
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
      }	std_dimension[] = {
	  {25, 0},
	  {28, 1},
	  {35, 0},
	  {40, 1},
	  {43, 0},
	  {50, 1}
      };
      int i = 0;

      while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
	{
	 if (std_dimension[i].need_vga <= have_vga
	     && std_dimension[i].rows >= *rows)
	   {
	     if (std_dimension[i].rows != current_rows
		 || *cols != current_cols)
559
	       _set_screen_lines (std_dimension[i].rows);
560 561
	     break;
	   }
562
	 i++;
563 564 565 566 567 568 569 570 571 572 573 574 575
	}
    }


  if (have_mouse)
    {
      mouse_init ();
      mouse_on ();
    }

  /* Tell the caller what dimensions have been REALLY set.  */
  *rows = ScreenRows ();
  *cols = ScreenCols ();
576

577 578 579 580 581
  /* Update Emacs' notion of screen dimensions.  */
  screen_size_X = *cols;
  screen_size_Y = *rows;
  screen_size = *cols * *rows;

582 583 584 585
  /* If the dimensions changed, the mouse highlight info is invalid.  */
  if (current_rows != *rows || current_cols != *cols)
    {
      struct frame *f = SELECTED_FRAME();
586 587
      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
      Lisp_Object window = hlinfo->mouse_face_window;
588 589 590

      if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
	{
591 592 593
	  hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
	  hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
	  hlinfo->mouse_face_window = Qnil;
594 595 596
	}
    }

597 598
  /* Enable bright background colors.  */
  bright_bg ();
599 600 601 602 603

  /* FIXME: I'm not sure the above will run at all on DOS/V.  But let's
     be defensive anyway.  */
  if (screen_virtual_segment)
    dosv_refresh_virtual_screen (0, *cols * *rows);
604 605
}

606 607
/* If we write a character in the position where the mouse is,
   the mouse cursor may need to be refreshed.  */
608 609

static void
610
mouse_off_maybe (void)
611
{
Kim F. Storm's avatar
Kim F. Storm committed
612
  int x, y;
Eli Zaretskii's avatar
Eli Zaretskii committed
613

Kim F. Storm's avatar
Kim F. Storm committed
614 615
  if (!mouse_visible)
    return;
Eli Zaretskii's avatar
Eli Zaretskii committed
616

Kim F. Storm's avatar
Kim F. Storm committed
617 618 619
  mouse_get_xy (&x, &y);
  if (y != new_pos_Y || x < new_pos_X)
    return;
Eli Zaretskii's avatar
Eli Zaretskii committed
620

Kim F. Storm's avatar
Kim F. Storm committed
621 622 623
  mouse_off ();
}

624 625 626 627 628 629 630 631 632 633 634 635 636
#define DEFAULT_CURSOR_START (-1)
#define DEFAULT_CURSOR_WIDTH (-1)
#define BOX_CURSOR_WIDTH     (-32)

/* Set cursor to begin at scan line START_LINE in the character cell
   and extend for WIDTH scan lines.  Scan lines are counted from top
   of the character cell, starting from zero.  */
static void
msdos_set_cursor_shape (struct frame *f, int start_line, int width)
{
  unsigned desired_cursor;
  __dpmi_regs regs;
  int max_line, top_line, bot_line;
637
  struct tty_display_info *tty = FRAME_TTY (f);
638 639 640 641 642 643 644

  /* Avoid the costly BIOS call if F isn't the currently selected
     frame.  Allow for NULL as unconditionally meaning the selected
     frame.  */
  if (f && f != SELECTED_FRAME())
    return;

645 646
  if (tty->termscript)
    fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
647

648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
  /* The character cell size in scan lines is stored at 40:85 in the
     BIOS data area.  */
  max_line = _farpeekw (_dos_ds, 0x485) - 1;
  switch (max_line)
    {
      default:	/* this relies on CGA cursor emulation being ON! */
      case 7:
	bot_line = 7;
	break;
      case 9:
	bot_line = 9;
	break;
      case 13:
	bot_line = 12;
	break;
      case 15:
	bot_line = 14;
	break;
    }

  if (width < 0)
    {
      if (width == BOX_CURSOR_WIDTH)
	{
	  top_line = 0;
	  bot_line = max_line;
	}
      else if (start_line != DEFAULT_CURSOR_START)
	{
	  top_line = start_line;
	  bot_line = top_line - width - 1;
	}
      else if (width != DEFAULT_CURSOR_WIDTH)
	{
	  top_line = 0;
	  bot_line = -1 - width;
	}
      else
	top_line = bot_line + 1;
    }
  else if (width == 0)
    {
      /* [31, 0] seems to DTRT for all screen sizes.  */
      top_line = 31;
      bot_line = 0;
    }
  else	/* WIDTH is positive */
    {
      if (start_line != DEFAULT_CURSOR_START)
	bot_line = start_line;
      top_line = bot_line - (width - 1);
    }

  /* If the current cursor shape is already what they want, we are
     history here.  */
  desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
  if (desired_cursor == _farpeekw (_dos_ds, 0x460))
    return;

  regs.h.ah = 1;
  regs.x.cx = desired_cursor;
  __dpmi_int (0x10, &regs);
}

static void
IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
{
Eli Zaretskii's avatar
Eli Zaretskii committed
715
  if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
716 717 718 719
    {
      /* Just BAR means the normal EGA/VGA cursor.  */
      msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
    }
Eli Zaretskii's avatar
Eli Zaretskii committed
720 721 722
  else if (CONSP (cursor_type)
	   && (EQ (XCAR (cursor_type), Qbar)
	       || EQ (XCAR (cursor_type), Qhbar)))
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
    {
      Lisp_Object bar_parms = XCDR (cursor_type);
      int width;

      if (INTEGERP (bar_parms))
	{
	  /* Feature: negative WIDTH means cursor at the top
	     of the character cell, zero means invisible cursor.  */
	  width = XINT (bar_parms);
	  msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
				  width);
	}
      else if (CONSP (bar_parms)
	       && INTEGERP (XCAR (bar_parms))
	       && INTEGERP (XCDR (bar_parms)))
	{
	  int start_line = XINT (XCDR (bar_parms));

	  width = XINT (XCAR (bar_parms));
	  msdos_set_cursor_shape (f, start_line, width);
	}
    }
  else
746 747 748 749 750 751
    {
      /* Treat anything unknown as "box cursor".  This includes nil, so
	 that a frame which doesn't specify a cursor type gets a box,
	 which is the default in Emacs.  */
      msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
    }
752 753
}

754
static void
755
IT_ring_bell (struct frame *f)
Kim F. Storm's avatar
Kim F. Storm committed
756 757
{
  if (visible_bell)
758
    {
Kim F. Storm's avatar
Kim F. Storm committed
759 760
      mouse_off ();
      ScreenVisualBell ();
761
    }
Kim F. Storm's avatar
Kim F. Storm committed
762
  else
763 764 765 766 767 768
    {
      union REGS inregs, outregs;
      inregs.h.ah = 2;
      inregs.h.dl = 7;
      intdos (&inregs, &outregs);
    }
769 770
}

771 772 773 774 775
/* Given a face id FACE, extract the face parameters to be used for
   display until the face changes.  The face parameters (actually, its
   color) are used to construct the video attribute byte for each
   glyph during the construction of the buffer that is then blitted to
   the video RAM.  */
Kim F. Storm's avatar
Kim F. Storm committed
776 777 778
static void
IT_set_face (int face)
{
779
  struct frame *sf = SELECTED_FRAME();
780 781 782
  struct face *fp  = FACE_FROM_ID (sf, face);
  struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
  unsigned long fg, bg, dflt_fg, dflt_bg;
783
  struct tty_display_info *tty = FRAME_TTY (sf);
Kim F. Storm's avatar
Kim F. Storm committed
784

785
  if (!fp)
786
    {
787
      fp = dfp;
788 789 790 791 792
      /* The default face for the frame should always be realized and
	 cached.  */
      if (!fp)
	abort ();
    }
Kim F. Storm's avatar
Kim F. Storm committed
793
  screen_face = face;
794 795
  fg = fp->foreground;
  bg = fp->background;
796 797
  dflt_fg = dfp->foreground;
  dflt_bg = dfp->background;
798

799 800 801 802
  /* Don't use invalid colors.  In particular, FACE_TTY_DEFAULT_* colors
     mean use the colors of the default face.  Note that we assume all
     16 colors to be available for the background, since Emacs switches
     on this mode (and loses the blinking attribute) at startup.  */
803
  if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
804
    fg = FRAME_FOREGROUND_PIXEL (sf);
805
  else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
806 807 808
    fg = FRAME_BACKGROUND_PIXEL (sf);
  if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
    bg = FRAME_BACKGROUND_PIXEL (sf);
809
  else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
810 811 812
    bg = FRAME_FOREGROUND_PIXEL (sf);

  /* Make sure highlighted lines really stand out, come what may.  */
813
  if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
814 815 816 817 818 819
    {
      unsigned long tem = fg;

      fg = bg;
      bg = tem;
    }
820 821 822 823 824 825 826 827
  /* If the user requested inverse video, obey.  */
  if (inverse_video)
    {
      unsigned long tem2 = fg;

      fg = bg;
      bg = tem2;
    }
828
  if (tty->termscript)
829
    fprintf (tty->termscript, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face,
830
	     fp->foreground, fp->background, fg, bg);
831 832 833 834 835 836 837 838 839 840
  if (fg >= 0 && fg < 16)
    {
      ScreenAttrib &= 0xf0;
      ScreenAttrib |= fg;
    }
  if (bg >= 0 && bg < 16)
    {
      ScreenAttrib &= 0x0f;
      ScreenAttrib |= ((bg & 0x0f) << 4);
    }
Kim F. Storm's avatar
Kim F. Storm committed
841 842
}

Eli Zaretskii's avatar
Eli Zaretskii committed
843 844
/* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
   width of a DOS display in any known text mode.  We multiply by 2 to
Juanma Barranquero's avatar
Juanma Barranquero committed
845
   accommodate the screen attribute byte.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
846 847
#define MAX_SCREEN_BUF 160*2

848 849
extern unsigned char *encode_terminal_code (struct glyph *, int,
					    struct coding_system *);
850

851
static void
852
IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
Kim F. Storm's avatar
Kim F. Storm committed
853
{
Eli Zaretskii's avatar
Eli Zaretskii committed
854
  unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
855
  int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
856
  register int sl = str_len;
857
  struct tty_display_info *tty = FRAME_TTY (f);
858
  struct frame *sf;
859
  unsigned char *conversion_buffer;
Morten Welinder's avatar
Morten Welinder committed
860

861 862 863 864 865 866 867
  /* If terminal_coding does any conversion, use it, otherwise use
     safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
     because it always returns 1 if terminal_coding.src_multibyte is 1.  */
  struct coding_system *coding = FRAME_TERMINAL_CODING (f);

  if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
    coding = &safe_terminal_coding;
868

869
  if (str_len <= 0) return;
Eli Zaretskii's avatar
Eli Zaretskii committed
870

871
  sf = SELECTED_FRAME();
872 873 874 875 876 877 878

  /* Since faces get cached and uncached behind our back, we can't
     rely on their indices in the cache being consistent across
     invocations.  So always reset the screen face to the default
     face of the frame, before writing glyphs, and let the glyphs
     set the right face if it's different from the default.  */
  IT_set_face (DEFAULT_FACE_ID);
Eli Zaretskii's avatar
Eli Zaretskii committed
879

880 881
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
882
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
Eli Zaretskii's avatar
Eli Zaretskii committed
883
  screen_bp = &screen_buf[0];
884
  while (sl > 0)
885
    {
886
      int cf;
Eli Zaretskii's avatar
Eli Zaretskii committed
887
      int n;
888

Eli Zaretskii's avatar
Eli Zaretskii committed
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
      /* If the face of this glyph is different from the current
	 screen face, update the screen attribute byte.  */
      cf = str->face_id;
      if (cf != screen_face)
	IT_set_face (cf);	/* handles invalid faces gracefully */

      /* Identify a run of glyphs with the same face.  */
      for (n = 1; n < sl; ++n)
	if (str[n].face_id != cf)
	  break;

      if (n >= sl)
	/* This is the last glyph.  */
	coding->mode |= CODING_MODE_LAST_BLOCK;

      conversion_buffer = encode_terminal_code (str, n, coding);
      if (coding->produced > 0)
906
	{
Eli Zaretskii's avatar
Eli Zaretskii committed
907 908
	  /* Copy the encoded bytes to the screen buffer.  */
	  for (bp = conversion_buffer; coding->produced--; bp++)
909
	    {
Eli Zaretskii's avatar
Eli Zaretskii committed
910 911 912
	      /* Paranoia: discard bytes that would overrun the end of
		 the screen buffer.  */
	      if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
913
		{
Eli Zaretskii's avatar
Eli Zaretskii committed
914 915
		  *screen_bp++ = (unsigned char)*bp;
		  *screen_bp++ = ScreenAttrib;
916
		}
Eli Zaretskii's avatar
Eli Zaretskii committed
917 918
	      if (tty->termscript)
		fputc (*bp, tty->termscript);
919 920
	    }
	}
Eli Zaretskii's avatar
Eli Zaretskii committed
921 922 923
      /* Update STR and its remaining length.  */
      str += n;
      sl -= n;
924 925
    }

Eli Zaretskii's avatar
Eli Zaretskii committed
926
  /* Dump whatever we have in the screen buffer.  */
Kim F. Storm's avatar
Kim F. Storm committed
927
  mouse_off_maybe ();
928
  dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
929
  if (screen_virtual_segment)
930 931
    dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
  new_pos_X += (screen_bp - screen_buf) / 2;
Kim F. Storm's avatar
Kim F. Storm committed
932
}
933

934 935 936 937
/************************************************************************
			  Mouse Highlight (and friends..)
 ************************************************************************/

938
/* Last window where we saw the mouse.  Used by mouse-autoselect-window.  */
939 940
static Lisp_Object last_mouse_window;

941 942
static int mouse_preempted = 0;	/* non-zero when XMenu gobbles mouse events */

943 944
int
popup_activated (void)
945
{
946
  return mouse_preempted;
947 948
}

949
/* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
950 951
   window W.  X is relative to TEXT_AREA in W.  HL is a face override
   for drawing the glyphs.  */
952
void
953 954 955
tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
			      int start_hpos, int end_hpos,
			      enum draw_glyphs_face hl)
956 957
{
  struct frame *f = XFRAME (WINDOW_FRAME (w));
958
  struct tty_display_info *tty = FRAME_TTY (f);
959
  Mouse_HLInfo *hlinfo = &tty->mouse_highlight;
960

961
  if (hl == DRAW_MOUSE_FACE)
962
    {
963 964 965 966 967
      int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
      int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
      int nglyphs = end_hpos - start_hpos;
      int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
      int start_offset = offset;
968

969 970 971
      if (tty->termscript)
	fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
		 kstart, kstart + nglyphs - 1, vpos);
Eli Zaretskii's avatar
Eli Zaretskii committed
972

973
      mouse_off ();
974
      IT_set_face (hlinfo->mouse_face_face_id);
975 976 977 978 979 980 981
      /* Since we are going to change only the _colors_ of already
	 displayed text, there's no need to go through all the pain of
	 generating and encoding the text from the glyphs.  Instead,
	 we simply poke the attribute byte of each affected position
	 in video memory with the colors computed by IT_set_face!  */
      _farsetsel (_dos_ds);
      while (nglyphs--)
982
	{
983 984
	  _farnspokeb (offset, ScreenAttrib);
	  offset += 2;
985
	}
986 987 988
      if (screen_virtual_segment)
	dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
      mouse_on ();
989
    }
990
  else if (hl == DRAW_NORMAL_TEXT)
991
    {
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
      /* We are removing a previously-drawn mouse highlight.  The
	 safest way to do so is to redraw the glyphs anew, since all
	 kinds of faces and display tables could have changed behind
	 our back.  */
      int nglyphs = end_hpos - start_hpos;
      int save_x = new_pos_X, save_y = new_pos_Y;

      if (end_hpos >= row->used[TEXT_AREA])
	nglyphs = row->used[TEXT_AREA] - start_hpos;

      /* IT_write_glyphs writes at cursor position, so we need to
	 temporarily move cursor coordinates to the beginning of
	 the highlight region.  */
      new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
      new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1007

1008 1009 1010 1011 1012 1013 1014 1015
      if (tty->termscript)
	fprintf (tty->termscript, "<MH- %d-%d:%d>",
		 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
      IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
      if (tty->termscript)
	fputs ("\n", tty->termscript);
      new_pos_X = save_x;
      new_pos_Y = save_y;
1016 1017 1018
    }
}

1019
static void
1020
IT_clear_end_of_line (struct frame *f, int first_unused)
Kim F. Storm's avatar
Kim F. Storm committed
1021 1022
{
  char *spaces, *sp;
Eli Zaretskii's avatar
Eli Zaretskii committed
1023
  int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1024
  extern int fatal_error_in_progress;
1025
  struct tty_display_info *tty = FRAME_TTY (f);
1026

1027