w32console.c 19.6 KB
Newer Older
1
/* Terminal hooks for GNU Emacs on the Microsoft W32 API.
2
   Copyright (C) 1992, 1999, 2002, 2003, 2004,
3
                 2005, 2006 Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
4

5 6 7 8 9 10 11 12 13 14 15 16 17 18
This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

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
along with GNU Emacs; see the file COPYING.  If not, write to
Lute Kamstra's avatar
Lute Kamstra committed
19 20
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
Richard M. Stallman's avatar
Richard M. Stallman committed
21 22 23 24 25 26

   Tim Fleehart (apollo@online.com)		1-17-92
   Geoff Voelker (voelker@cs.washington.edu)	9-12-93
*/


27 28
#include <config.h>

Richard M. Stallman's avatar
Richard M. Stallman committed
29 30 31
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
32
#include <string.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
33 34

#include "lisp.h"
Geoff Voelker's avatar
Geoff Voelker committed
35
#include "charset.h"
36
#include "coding.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
37 38
#include "disptab.h"
#include "termhooks.h"
39 40
#include "dispextern.h"
/* Disable features in frame.h that require a Window System.  */
41 42
#undef HAVE_WINDOW_SYSTEM
#include "frame.h"
Geoff Voelker's avatar
Geoff Voelker committed
43
#include "w32inevt.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
44

Karl Heuer's avatar
Karl Heuer committed
45
/* from window.c */
Richard M. Stallman's avatar
Richard M. Stallman committed
46 47 48 49 50 51 52 53
extern Lisp_Object Frecenter ();

/* from keyboard.c */
extern int detect_input_pending ();

/* from sysdep.c */
extern int read_input_pending ();

54
extern struct frame * updating_frame;
Richard M. Stallman's avatar
Richard M. Stallman committed
55 56
extern int meta_key;

57 58 59 60 61 62 63 64
static void w32con_move_cursor (int row, int col);
static void w32con_clear_to_end (void);
static void w32con_clear_frame (void);
static void w32con_clear_end_of_line (int);
static void w32con_ins_del_lines (int vpos, int n);
static void w32con_insert_glyphs (struct glyph *start, int len);
static void w32con_write_glyphs (struct glyph *string, int len);
static void w32con_delete_glyphs (int n);
65
void w32_sys_ring_bell (void);
66 67 68 69 70
static void w32con_reset_terminal_modes (void);
static void w32con_set_terminal_modes (void);
static void w32con_set_terminal_window (int size);
static void w32con_update_begin (struct frame * f);
static void w32con_update_end (struct frame * f);
71
static WORD w32_face_attributes (struct frame *f, int face_id);
Richard M. Stallman's avatar
Richard M. Stallman committed
72

73 74 75 76
static COORD	cursor_coords;
static HANDLE	prev_screen, cur_screen;
static WORD	char_attr_normal;
static DWORD   prev_console_mode;
Richard M. Stallman's avatar
Richard M. Stallman committed
77

78
#ifndef USE_SEPARATE_SCREEN
79
static CONSOLE_CURSOR_INFO prev_console_cursor;
80 81
#endif

82 83 84 85 86
/* Determine whether to make frame dimensions match the screen buffer,
   or the current window size.  The former is desirable when running
   over telnet, while the latter is more useful when working directly at
   the console with a large scroll-back buffer.  */
int w32_use_full_screen_buffer;
87
HANDLE  keyboard_handle;
88

Richard M. Stallman's avatar
Richard M. Stallman committed
89 90

/* Setting this as the ctrl handler prevents emacs from being killed when
91 92 93
   someone hits ^C in a 'suspended' session (child shell).
   Also ignore Ctrl-Break signals.  */

Richard M. Stallman's avatar
Richard M. Stallman committed
94 95 96
BOOL
ctrl_c_handler (unsigned long type)
{
97 98 99
  /* Only ignore "interrupt" events when running interactively.  */
  return (!noninteractive
	  && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
Richard M. Stallman's avatar
Richard M. Stallman committed
100 101 102 103
}

/* If we're updating a frame, use it as the current frame
   Otherwise, use the selected frame.  */
104
#define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())
Richard M. Stallman's avatar
Richard M. Stallman committed
105 106

/* Move the cursor to (row, col).  */
Jason Rumney's avatar
Jason Rumney committed
107
static void
108
w32con_move_cursor (int row, int col)
Richard M. Stallman's avatar
Richard M. Stallman committed
109 110 111
{
  cursor_coords.X = col;
  cursor_coords.Y = row;
112

113
  if (updating_frame == (struct frame *) NULL)
Richard M. Stallman's avatar
Richard M. Stallman committed
114 115 116 117 118 119
    {
      SetConsoleCursorPosition (cur_screen, cursor_coords);
    }
}

/* Clear from cursor to end of screen.  */
Jason Rumney's avatar
Jason Rumney committed
120
static void
121
w32con_clear_to_end (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
122
{
123
  struct frame * f = PICK_FRAME ();
124

125 126
  w32con_clear_end_of_line (FRAME_COLS (f) - 1);
  w32con_ins_del_lines (cursor_coords.Y, FRAME_LINES (f) - cursor_coords.Y - 1);
Richard M. Stallman's avatar
Richard M. Stallman committed
127 128 129
}

/* Clear the frame.  */
130 131
static void
w32con_clear_frame (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
132
{
133
  struct frame *  f = PICK_FRAME ();
134
  COORD	     dest;
Andrew Innes's avatar
Andrew Innes committed
135 136
  int        n;
  DWORD      r;
137 138 139
  CONSOLE_SCREEN_BUFFER_INFO info;

  GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
140

141
  /* Remember that the screen buffer might be wider than the window.  */
142
  n = FRAME_LINES (f) * info.dwSize.X;
143 144
  dest.X = dest.Y = 0;

145
  FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
146 147
  FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);

148
  w32con_move_cursor (0, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
149 150 151
}


152
static struct glyph glyph_base[256];
Richard M. Stallman's avatar
Richard M. Stallman committed
153 154 155
static BOOL  ceol_initialized = FALSE;

/* Clear from Cursor to end (what's "standout marker"?).  */
156 157
static void
w32con_clear_end_of_line (int end)
Richard M. Stallman's avatar
Richard M. Stallman committed
158 159 160 161 162 163
{
  if (!ceol_initialized)
    {
      int i;
      for (i = 0; i < 256; i++)
        {
164
	  memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
Richard M. Stallman's avatar
Richard M. Stallman committed
165 166 167
        }
      ceol_initialized = TRUE;
    }
168
  w32con_write_glyphs (glyph_base, end - cursor_coords.X);	/* fencepost ?	*/
Richard M. Stallman's avatar
Richard M. Stallman committed
169 170 171
}

/* Insert n lines at vpos. if n is negative delete -n lines.  */
172 173
static void
w32con_ins_del_lines (int vpos, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
174
{
175
  int	     i, nb;
Richard M. Stallman's avatar
Richard M. Stallman committed
176 177 178
  SMALL_RECT scroll;
  COORD	     dest;
  CHAR_INFO  fill;
179
  struct frame *  f = PICK_FRAME ();
Richard M. Stallman's avatar
Richard M. Stallman committed
180 181 182 183

  if (n < 0)
    {
      scroll.Top = vpos - n;
184
      scroll.Bottom = FRAME_LINES (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
185 186 187 188 189
      dest.Y = vpos;
    }
  else
    {
      scroll.Top = vpos;
190
      scroll.Bottom = FRAME_LINES (f) - n;
Richard M. Stallman's avatar
Richard M. Stallman committed
191 192 193
      dest.Y = vpos + n;
    }
  scroll.Left = 0;
194
  scroll.Right = FRAME_COLS (f);
195

Richard M. Stallman's avatar
Richard M. Stallman committed
196
  dest.X = 0;
197

Richard M. Stallman's avatar
Richard M. Stallman committed
198
  fill.Char.AsciiChar = 0x20;
199
  fill.Attributes = char_attr_normal;
200

Richard M. Stallman's avatar
Richard M. Stallman committed
201 202
  ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);

203
  /* Here we have to deal with a w32 console flake: If the scroll
Richard M. Stallman's avatar
Richard M. Stallman committed
204 205 206 207 208 209 210 211 212 213 214 215
     region looks like abc and we scroll c to a and fill with d we get
     cbd... if we scroll block c one line at a time to a, we get cdd...
     Emacs expects cdd consistently... So we have to deal with that
     here... (this also occurs scrolling the same way in the other
     direction.  */

  if (n > 0)
    {
      if (scroll.Bottom < dest.Y)
        {
	  for (i = scroll.Bottom; i < dest.Y; i++)
            {
216 217
	      w32con_move_cursor (i, 0);
	      w32con_clear_end_of_line (FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
218 219 220 221 222 223 224 225
            }
        }
    }
  else
    {
      nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;

      if (nb < scroll.Top)
226
        {
Richard M. Stallman's avatar
Richard M. Stallman committed
227 228
	  for (i = nb; i < scroll.Top; i++)
            {
229 230
	      w32con_move_cursor (i, 0);
	      w32con_clear_end_of_line (FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
231 232 233
            }
        }
    }
234

Richard M. Stallman's avatar
Richard M. Stallman committed
235 236 237 238 239 240 241 242 243
  cursor_coords.X = 0;
  cursor_coords.Y = vpos;
}

#undef	LEFT
#undef	RIGHT
#define	LEFT	1
#define	RIGHT	0

Jason Rumney's avatar
Jason Rumney committed
244
static void
Richard M. Stallman's avatar
Richard M. Stallman committed
245 246 247 248 249 250 251
scroll_line (int dist, int direction)
{
  /* The idea here is to implement a horizontal scroll in one line to
     implement delete and half of insert.  */
  SMALL_RECT scroll;
  COORD	     dest;
  CHAR_INFO  fill;
252
  struct frame *  f = PICK_FRAME ();
253

Richard M. Stallman's avatar
Richard M. Stallman committed
254 255
  scroll.Top = cursor_coords.Y;
  scroll.Bottom = cursor_coords.Y;
256

Richard M. Stallman's avatar
Richard M. Stallman committed
257 258 259
  if (direction == LEFT)
    {
      scroll.Left = cursor_coords.X + dist;
260
      scroll.Right = FRAME_COLS (f) - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
261 262 263 264
    }
  else
    {
      scroll.Left = cursor_coords.X;
265
      scroll.Right = FRAME_COLS (f) - dist - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
266
    }
267

Richard M. Stallman's avatar
Richard M. Stallman committed
268 269
  dest.X = cursor_coords.X;
  dest.Y = cursor_coords.Y;
270

Richard M. Stallman's avatar
Richard M. Stallman committed
271
  fill.Char.AsciiChar = 0x20;
272 273
  fill.Attributes = char_attr_normal;

Richard M. Stallman's avatar
Richard M. Stallman committed
274 275 276 277 278
  ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
}


/* If start is zero insert blanks instead of a string at start ?. */
279 280
static void
w32con_insert_glyphs (register struct glyph *start, register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
281 282 283 284 285 286 287 288
{
  scroll_line (len, RIGHT);

  /* Move len chars to the right starting at cursor_coords, fill with blanks */
  if (start)
    {
      /* Print the first len characters of start, cursor_coords.X adjusted
	 by write_glyphs.  */
289

290
      w32con_write_glyphs (start, len);
Richard M. Stallman's avatar
Richard M. Stallman committed
291 292 293
    }
  else
    {
294
      w32con_clear_end_of_line (cursor_coords.X + len);
Richard M. Stallman's avatar
Richard M. Stallman committed
295 296 297
    }
}

298
extern unsigned char *encode_terminal_code P_ ((struct glyph *, int, 
299
						struct coding_system *));
300

301 302
static void
w32con_write_glyphs (register struct glyph *string, register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
303
{
Andrew Innes's avatar
Andrew Innes committed
304 305
  int produced, consumed;
  DWORD r;
306
  struct frame * f = PICK_FRAME ();
307
  WORD char_attr;
308 309
  unsigned char *conversion_buffer;
  struct coding_system *coding;
310 311 312

  if (len <= 0)
    return;
313

314 315 316 317 318
  /* If terminal_coding does any conversion, use it, otherwise use
     safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
     because it always return 1 if the member src_multibyte is 1.  */
  coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? &terminal_coding : &safe_terminal_coding);
319 320 321
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
Richard M. Stallman's avatar
Richard M. Stallman committed
322

323
  while (len > 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
324
    {
325 326 327
      /* Identify a run of glyphs with the same face.  */
      int face_id = string->face_id;
      int n;
328

329 330 331 332 333
      for (n = 1; n < len; ++n)
	if (string[n].face_id != face_id)
	  break;

      /* Turn appearance modes of the face of the run on.  */
334
      char_attr = w32_face_attributes (f, face_id);
335

336 337 338 339 340 341 342 343 344 345
      if (n == len)
	/* This is the last run.  */
	coding->mode |= CODING_MODE_LAST_BLOCK;
      conversion_buffer = encode_terminal_code (string, n, coding);
      if (coding->produced > 0)
	{
	  /* Set the attribute for these characters.  */
	  if (!FillConsoleOutputAttribute (cur_screen, char_attr,
					   coding->produced, cursor_coords,
					   &r))
346
	    {
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
	      printf ("Failed writing console attributes: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  /* Write the characters.  */
	  if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
					    coding->produced, cursor_coords,
					    &r))
	    {
	      printf ("Failed writing console characters: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  cursor_coords.X += coding->produced;
	  w32con_move_cursor (cursor_coords.Y, cursor_coords.X);
	}
      len -= n;
      string += n;
Richard M. Stallman's avatar
Richard M. Stallman committed
367 368 369
    }
}

370

371 372
static void
w32con_delete_glyphs (int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
373
{
374 375
  /* delete chars means scroll chars from cursor_coords.X + n to
     cursor_coords.X, anything beyond the edge of the screen should
Richard M. Stallman's avatar
Richard M. Stallman committed
376 377 378 379 380
     come out empty...  */

  scroll_line (n, LEFT);
}

Karl Heuer's avatar
Karl Heuer committed
381
static unsigned int sound_type = 0xFFFFFFFF;
382
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
Karl Heuer's avatar
Karl Heuer committed
383

Richard M. Stallman's avatar
Richard M. Stallman committed
384
void
385
w32_sys_ring_bell (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
386
{
387
  if (sound_type == 0xFFFFFFFF)
388
    {
Karl Heuer's avatar
Karl Heuer committed
389
      Beep (666, 100);
390 391 392 393 394
    }
  else if (sound_type == MB_EMACS_SILENT)
    {
      /* Do nothing.  */
    }
Karl Heuer's avatar
Karl Heuer committed
395
  else
396
    MessageBeep (sound_type);
Richard M. Stallman's avatar
Richard M. Stallman committed
397 398
}

Karl Heuer's avatar
Karl Heuer committed
399
DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
400 401 402 403 404
       doc: /* Set the sound generated when the bell is rung.
SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
to use the corresponding system sound for the bell.  The 'silent sound
prevents Emacs from making any sound at all.
SOUND is nil to use the normal beep.  */)
Karl Heuer's avatar
Karl Heuer committed
405 406
     (sound)
     Lisp_Object sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
407
{
408
  CHECK_SYMBOL (sound);
Karl Heuer's avatar
Karl Heuer committed
409

410
  if (NILP (sound))
Karl Heuer's avatar
Karl Heuer committed
411 412 413
      sound_type = 0xFFFFFFFF;
  else if (EQ (sound, intern ("asterisk")))
      sound_type = MB_ICONASTERISK;
414
  else if (EQ (sound, intern ("exclamation")))
Karl Heuer's avatar
Karl Heuer committed
415
      sound_type = MB_ICONEXCLAMATION;
416
  else if (EQ (sound, intern ("hand")))
Karl Heuer's avatar
Karl Heuer committed
417
      sound_type = MB_ICONHAND;
418
  else if (EQ (sound, intern ("question")))
Karl Heuer's avatar
Karl Heuer committed
419
      sound_type = MB_ICONQUESTION;
420
  else if (EQ (sound, intern ("ok")))
Karl Heuer's avatar
Karl Heuer committed
421
      sound_type = MB_OK;
422 423
  else if (EQ (sound, intern ("silent")))
      sound_type = MB_EMACS_SILENT;
Karl Heuer's avatar
Karl Heuer committed
424 425 426 427
  else
      sound_type = 0xFFFFFFFF;

  return sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
428
}
429

430 431
static void
w32con_reset_terminal_modes (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
432
{
433
#ifdef USE_SEPARATE_SCREEN
Richard M. Stallman's avatar
Richard M. Stallman committed
434
  SetConsoleActiveScreenBuffer (prev_screen);
435 436 437 438
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
  SetConsoleMode (keyboard_handle, prev_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
439 440
}

441 442
static void
w32con_set_terminal_modes (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
443 444 445
{
  CONSOLE_CURSOR_INFO cci;

446 447 448 449
  /* make cursor big and visible (100 on Win95 makes it disappear)  */
  cci.dwSize = 99;
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
Richard M. Stallman's avatar
Richard M. Stallman committed
450

451
  SetConsoleActiveScreenBuffer (cur_screen);
Richard M. Stallman's avatar
Richard M. Stallman committed
452

453
  SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
Richard M. Stallman's avatar
Richard M. Stallman committed
454

455 456 457
  /* Initialize input mode: interrupt_input off, no flow control, allow
     8 bit character input, standard quit char.  */
  Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
Richard M. Stallman's avatar
Richard M. Stallman committed
458 459 460 461
}

/* hmmm... perhaps these let us bracket screen changes so that we can flush
   clumps rather than one-character-at-a-time...
462

Richard M. Stallman's avatar
Richard M. Stallman committed
463
   we'll start with not moving the cursor while an update is in progress.  */
464 465
static void
w32con_update_begin (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
466 467 468
{
}

469 470
static void
w32con_update_end (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
471 472 473 474
{
  SetConsoleCursorPosition (cur_screen, cursor_coords);
}

475 476
static void
w32con_set_terminal_window (int size)
Richard M. Stallman's avatar
Richard M. Stallman committed
477 478 479
{
}

480 481 482 483 484 485 486
/***********************************************************************
				Faces
 ***********************************************************************/


/* Turn appearances of face FACE_ID on tty frame F on.  */

487 488
static WORD
w32_face_attributes (f, face_id)
489 490 491
     struct frame *f;
     int face_id;
{
492
  WORD char_attr;
493 494 495 496 497 498
  struct face *face = FACE_FROM_ID (f, face_id);

  xassert (face != NULL);

  char_attr = char_attr_normal;

499 500 501 502 503 504
  if (face->foreground != FACE_TTY_DEFAULT_FG_COLOR
      && face->foreground != FACE_TTY_DEFAULT_COLOR)
    char_attr = (char_attr & 0xfff0) + (face->foreground % 16);

  if (face->background != FACE_TTY_DEFAULT_BG_COLOR
      && face->background != FACE_TTY_DEFAULT_COLOR)
505
    char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4);
506

507

508 509 510
  /* NTEMACS_TODO: Faces defined during startup get both foreground
     and background of 0. Need a better way around this - for now detect
     the problem and invert one of the faces to make the text readable. */
511 512
  if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
    char_attr ^= 0x0007;
513

514
  if (face->tty_reverse_p)
515 516
    char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
      + ((char_attr & 0x00f0) >> 4);
517

518
  return char_attr;
519 520 521
}


522
/* Emulation of some X window features from xfns.c and xfaces.c.  */
523

524 525 526 527 528 529
extern char unspecified_fg[], unspecified_bg[];


/* Given a color index, return its standard name.  */
Lisp_Object
vga_stdcolor_name (int idx)
530
{
531 532 533 534 535 536 537 538 539 540 541 542 543 544
  /* Standard VGA colors, in the order of their standard numbering
     in the default VGA palette.  */
  static char *vga_colors[16] = {
    "black", "blue", "green", "cyan", "red", "magenta", "brown",
    "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
    "lightred", "lightmagenta", "yellow", "white"
  };

  extern Lisp_Object Qunspecified;

  if (idx >= 0 && idx < sizeof (vga_colors) / sizeof (vga_colors[0]))
    return build_string (vga_colors[idx]);
  else
    return Qunspecified;	/* meaning the default */
545
}
546

Richard M. Stallman's avatar
Richard M. Stallman committed
547 548 549
typedef int (*term_hook) ();

void
550
initialize_w32_display (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
551 552
{
  CONSOLE_SCREEN_BUFFER_INFO	info;
553

554 555 556 557 558 559 560 561 562
  cursor_to_hook		= w32con_move_cursor;
  raw_cursor_to_hook		= w32con_move_cursor;
  clear_to_end_hook		= w32con_clear_to_end;
  clear_frame_hook		= w32con_clear_frame;
  clear_end_of_line_hook	= w32con_clear_end_of_line;
  ins_del_lines_hook		= w32con_ins_del_lines;
  insert_glyphs_hook		= w32con_insert_glyphs;
  write_glyphs_hook		= w32con_write_glyphs;
  delete_glyphs_hook		= w32con_delete_glyphs;
563
  ring_bell_hook		= w32_sys_ring_bell;
564 565 566 567 568
  reset_terminal_modes_hook	= w32con_reset_terminal_modes;
  set_terminal_modes_hook	= w32con_set_terminal_modes;
  set_terminal_window_hook	= w32con_set_terminal_window;
  update_begin_hook		= w32con_update_begin;
  update_end_hook		= w32con_update_end;
569

570
  read_socket_hook = w32_console_read_socket;
571
  mouse_position_hook = w32_console_mouse_position;
572

573 574 575
  /* Initialize interrupt_handle.  */
  init_crit ();

576 577 578 579
  /* Remember original console settings.  */
  keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
  GetConsoleMode (keyboard_handle, &prev_console_mode);

Richard M. Stallman's avatar
Richard M. Stallman committed
580
  prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
581

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
#ifdef USE_SEPARATE_SCREEN
  cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
					  0, NULL,
					  CONSOLE_TEXTMODE_BUFFER,
					  NULL);

  if (cur_screen == INVALID_HANDLE_VALUE)
    {
      printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
      printf ("LastError = 0x%lx\n", GetLastError ());
      fflush (stdout);
      exit (0);
    }
#else
  cur_screen = prev_screen;
  GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
  /* Respect setting of LINES and COLUMNS environment variables.  */
  {
    char * lines = getenv("LINES");
    char * columns = getenv("COLUMNS");

    if (lines != NULL && columns != NULL)
      {
	SMALL_RECT new_win_dims;
	COORD new_size;

	new_size.X = atoi (columns);
	new_size.Y = atoi (lines);

	GetConsoleScreenBufferInfo (cur_screen, &info);

	/* Shrink the window first, so the buffer dimensions can be
           reduced if necessary.  */
	new_win_dims.Top = 0;
	new_win_dims.Left = 0;
	new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1;
	new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1;
	SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);

	SetConsoleScreenBufferSize (cur_screen, new_size);

	/* Set the window size to match the buffer dimension.  */
	new_win_dims.Top = 0;
	new_win_dims.Left = 0;
	new_win_dims.Bottom = new_size.Y - 1;
	new_win_dims.Right = new_size.X - 1;
	SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
      }
  }

Richard M. Stallman's avatar
Richard M. Stallman committed
634
  GetConsoleScreenBufferInfo (cur_screen, &info);
635

Richard M. Stallman's avatar
Richard M. Stallman committed
636
  meta_key = 1;
637
  char_attr_normal = info.wAttributes;
638

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
  /* Determine if the info returned by GetConsoleScreenBufferInfo
     is realistic.  Old MS Telnet servers used to only fill out
     the dwSize portion, even modern one fill the whole struct with
     garbage when using non-MS telnet clients.  */
  if ((w32_use_full_screen_buffer
       && (info.dwSize.Y < 20 || info.dwSize.Y > 100
	   || info.dwSize.X < 40 || info.dwSize.X > 200))
      || (!w32_use_full_screen_buffer
	  && (info.srWindow.Bottom - info.srWindow.Top < 20
	      || info.srWindow.Bottom - info.srWindow.Top > 100
	      || info.srWindow.Right - info.srWindow.Left < 40
	      || info.srWindow.Right - info.srWindow.Left > 100)))
    {
      FRAME_LINES (SELECTED_FRAME ()) = 25;
      SET_FRAME_COLS (SELECTED_FRAME (), 80);
    }

  else if (w32_use_full_screen_buffer)
657
    {
658 659
      FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;	/* lines per page */
      SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
660 661 662 663
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
664
      FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
665
	info.srWindow.Top;
666
      /* Characters per line.  Use buffer coords instead of buffer size.  */
667
      SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
668 669
		       info.srWindow.Left);
    }
670 671 672 673 674

  /* Setup w32_display_info structure for this frame. */

  w32_initialize_display_info (build_string ("Console"));

Richard M. Stallman's avatar
Richard M. Stallman committed
675 676 677
}

DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
678
       doc: /* Set screen colors.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
679 680 681 682 683 684 685 686 687 688 689
    (foreground, background)
    Lisp_Object foreground;
    Lisp_Object background;
{
  char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);

  Frecenter (Qnil);
  return Qt;
}

DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
690
       doc: /* Set cursor size.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
691 692 693 694 695 696 697
    (size)
    Lisp_Object size;
{
  CONSOLE_CURSOR_INFO cci;
  cci.dwSize = XFASTINT (size);
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
698

Richard M. Stallman's avatar
Richard M. Stallman committed
699 700 701
  return Qt;
}

Karl Heuer's avatar
Karl Heuer committed
702
void
Richard M. Stallman's avatar
Richard M. Stallman committed
703 704
syms_of_ntterm ()
{
705 706
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
               &w32_use_full_screen_buffer,
707 708 709 710 711
	       doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
This is desirable when running Emacs over telnet, and is the default.
A value of nil means use the current console window dimensions; this
may be preferrable when working directly at the console with a large
scroll-back buffer.  */);
712
  w32_use_full_screen_buffer = 0;
713

Richard M. Stallman's avatar
Richard M. Stallman committed
714 715
  defsubr (&Sset_screen_color);
  defsubr (&Sset_cursor_size);
Karl Heuer's avatar
Karl Heuer committed
716
  defsubr (&Sset_message_beep);
Richard M. Stallman's avatar
Richard M. Stallman committed
717
}
Miles Bader's avatar
Miles Bader committed
718 719 720

/* arch-tag: a390a07f-f661-42bc-aeb4-e6d8bf860337
   (do not change this comment) */