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

5 6 7 8
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
9
the Free Software Foundation; either version 3, or (at your option)
10 11 12 13 14 15 16 17 18
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
#include "disptab.h"
38
/* Disable features in frame.h that require a Window System.  */
39 40
#undef HAVE_WINDOW_SYSTEM
#include "frame.h"
41 42 43
#include "termhooks.h"
#include "termchar.h"
#include "dispextern.h"
Geoff Voelker's avatar
Geoff Voelker committed
44
#include "w32inevt.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
45

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

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

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

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

70 71 72 73
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
74

75
#ifndef USE_SEPARATE_SCREEN
76
static CONSOLE_CURSOR_INFO prev_console_cursor;
77 78
#endif

79 80 81 82 83
/* 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;
84
HANDLE  keyboard_handle;
85

Richard M. Stallman's avatar
Richard M. Stallman committed
86 87

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

Richard M. Stallman's avatar
Richard M. Stallman committed
91 92 93
BOOL
ctrl_c_handler (unsigned long type)
{
94 95 96
  /* 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
97 98 99
}


100
/* Move the cursor to (ROW, COL) on FRAME.  */
Jason Rumney's avatar
Jason Rumney committed
101
static void
102
w32con_move_cursor (struct frame *f, int row, int col)
Richard M. Stallman's avatar
Richard M. Stallman committed
103 104 105
{
  cursor_coords.X = col;
  cursor_coords.Y = row;
106

107 108 109
  /* TODO: for multi-tty support, cur_screen should be replaced with a
     reference to the terminal for this frame.  */
  SetConsoleCursorPosition (cur_screen, cursor_coords);
Richard M. Stallman's avatar
Richard M. Stallman committed
110 111 112
}

/* Clear from cursor to end of screen.  */
Jason Rumney's avatar
Jason Rumney committed
113
static void
114
w32con_clear_to_end (struct frame *f)
Richard M. Stallman's avatar
Richard M. Stallman committed
115
{
116 117
  w32con_clear_end_of_line (f, FRAME_COLS (f) - 1);
  w32con_ins_del_lines (f, cursor_coords.Y, FRAME_LINES (f) - cursor_coords.Y - 1);
Richard M. Stallman's avatar
Richard M. Stallman committed
118 119 120
}

/* Clear the frame.  */
121
static void
122
w32con_clear_frame (struct frame *f)
Richard M. Stallman's avatar
Richard M. Stallman committed
123
{
124
  COORD	     dest;
Andrew Innes's avatar
Andrew Innes committed
125 126
  int        n;
  DWORD      r;
127 128 129
  CONSOLE_SCREEN_BUFFER_INFO info;

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

131
  /* Remember that the screen buffer might be wider than the window.  */
132
  n = FRAME_LINES (f) * info.dwSize.X;
133 134
  dest.X = dest.Y = 0;

135
  FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
136 137
  FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);

138
  w32con_move_cursor (f, 0, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
139 140 141
}


142
static struct glyph glyph_base[256];
Richard M. Stallman's avatar
Richard M. Stallman committed
143 144 145
static BOOL  ceol_initialized = FALSE;

/* Clear from Cursor to end (what's "standout marker"?).  */
146
static void
147
w32con_clear_end_of_line (struct frame *f, int end)
Richard M. Stallman's avatar
Richard M. Stallman committed
148 149 150 151 152 153
{
  if (!ceol_initialized)
    {
      int i;
      for (i = 0; i < 256; i++)
        {
154
	  memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
Richard M. Stallman's avatar
Richard M. Stallman committed
155 156 157
        }
      ceol_initialized = TRUE;
    }
158
  w32con_write_glyphs (f, glyph_base, end - cursor_coords.X);	/* fencepost ?	*/
Richard M. Stallman's avatar
Richard M. Stallman committed
159 160 161
}

/* Insert n lines at vpos. if n is negative delete -n lines.  */
162
static void
163
w32con_ins_del_lines (struct frame *f, int vpos, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
164
{
165
  int	     i, nb;
Richard M. Stallman's avatar
Richard M. Stallman committed
166 167 168 169 170 171 172
  SMALL_RECT scroll;
  COORD	     dest;
  CHAR_INFO  fill;

  if (n < 0)
    {
      scroll.Top = vpos - n;
173
      scroll.Bottom = FRAME_LINES (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
174 175 176 177 178
      dest.Y = vpos;
    }
  else
    {
      scroll.Top = vpos;
179
      scroll.Bottom = FRAME_LINES (f) - n;
Richard M. Stallman's avatar
Richard M. Stallman committed
180 181 182
      dest.Y = vpos + n;
    }
  scroll.Left = 0;
183
  scroll.Right = FRAME_COLS (f);
184

Richard M. Stallman's avatar
Richard M. Stallman committed
185
  dest.X = 0;
186

Richard M. Stallman's avatar
Richard M. Stallman committed
187
  fill.Char.AsciiChar = 0x20;
188
  fill.Attributes = char_attr_normal;
189

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

192
  /* Here we have to deal with a w32 console flake: If the scroll
Richard M. Stallman's avatar
Richard M. Stallman committed
193 194 195 196 197 198 199 200 201 202 203 204
     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++)
            {
205 206
	      w32con_move_cursor (f, i, 0);
	      w32con_clear_end_of_line (f, FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
207 208 209 210 211 212 213 214
            }
        }
    }
  else
    {
      nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;

      if (nb < scroll.Top)
215
        {
Richard M. Stallman's avatar
Richard M. Stallman committed
216 217
	  for (i = nb; i < scroll.Top; i++)
            {
218 219
	      w32con_move_cursor (f, i, 0);
	      w32con_clear_end_of_line (f, FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
220 221 222
            }
        }
    }
223

Richard M. Stallman's avatar
Richard M. Stallman committed
224 225 226 227 228 229 230 231 232
  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
233
static void
234
scroll_line (struct frame *f, int dist, int direction)
Richard M. Stallman's avatar
Richard M. Stallman committed
235 236 237 238 239 240
{
  /* 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;
241

Richard M. Stallman's avatar
Richard M. Stallman committed
242 243
  scroll.Top = cursor_coords.Y;
  scroll.Bottom = cursor_coords.Y;
244

Richard M. Stallman's avatar
Richard M. Stallman committed
245 246 247
  if (direction == LEFT)
    {
      scroll.Left = cursor_coords.X + dist;
248
      scroll.Right = FRAME_COLS (f) - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
249 250 251 252
    }
  else
    {
      scroll.Left = cursor_coords.X;
253
      scroll.Right = FRAME_COLS (f) - dist - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
254
    }
255

Richard M. Stallman's avatar
Richard M. Stallman committed
256 257
  dest.X = cursor_coords.X;
  dest.Y = cursor_coords.Y;
258

Richard M. Stallman's avatar
Richard M. Stallman committed
259
  fill.Char.AsciiChar = 0x20;
260 261
  fill.Attributes = char_attr_normal;

Richard M. Stallman's avatar
Richard M. Stallman committed
262 263 264 265 266
  ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
}


/* If start is zero insert blanks instead of a string at start ?. */
267
static void
268
w32con_insert_glyphs (struct frame *f, register struct glyph *start, register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
269
{
270
  scroll_line (f, len, RIGHT);
Richard M. Stallman's avatar
Richard M. Stallman committed
271 272 273 274 275 276

  /* 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.  */
277

278
      w32con_write_glyphs (f, start, len);
Richard M. Stallman's avatar
Richard M. Stallman committed
279 280 281
    }
  else
    {
282
      w32con_clear_end_of_line (f, cursor_coords.X + len);
Richard M. Stallman's avatar
Richard M. Stallman committed
283 284 285
    }
}

286
extern unsigned char *encode_terminal_code P_ ((struct glyph *, int, 
287
						struct coding_system *));
288

289
static void
290 291
w32con_write_glyphs (struct frame *f, register struct glyph *string,
                     register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
292
{
Andrew Innes's avatar
Andrew Innes committed
293 294
  int produced, consumed;
  DWORD r;
295
  WORD char_attr;
296 297
  unsigned char *conversion_buffer;
  struct coding_system *coding;
298 299 300

  if (len <= 0)
    return;
301

302 303 304
  /* 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.  */
305 306
  coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
307 308
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
309
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
Richard M. Stallman's avatar
Richard M. Stallman committed
310

311
  while (len > 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
312
    {
313 314 315
      /* Identify a run of glyphs with the same face.  */
      int face_id = string->face_id;
      int n;
316

317 318 319 320 321
      for (n = 1; n < len; ++n)
	if (string[n].face_id != face_id)
	  break;

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

324 325 326 327 328 329 330 331 332 333
      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))
334
	    {
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
	      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;
351
	  w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X);
352 353 354
	}
      len -= n;
      string += n;
Richard M. Stallman's avatar
Richard M. Stallman committed
355 356 357
    }
}

358

359
static void
360
w32con_delete_glyphs (struct frame *f, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
361
{
362 363
  /* 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
364 365
     come out empty...  */

366
  scroll_line (f, n, LEFT);
Richard M. Stallman's avatar
Richard M. Stallman committed
367 368
}

Karl Heuer's avatar
Karl Heuer committed
369
static unsigned int sound_type = 0xFFFFFFFF;
370
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
Karl Heuer's avatar
Karl Heuer committed
371

Richard M. Stallman's avatar
Richard M. Stallman committed
372
void
373
w32_sys_ring_bell (struct frame *f)
Richard M. Stallman's avatar
Richard M. Stallman committed
374
{
375
  if (sound_type == 0xFFFFFFFF)
376
    {
Karl Heuer's avatar
Karl Heuer committed
377
      Beep (666, 100);
378 379 380 381 382
    }
  else if (sound_type == MB_EMACS_SILENT)
    {
      /* Do nothing.  */
    }
Karl Heuer's avatar
Karl Heuer committed
383
  else
384
    MessageBeep (sound_type);
Richard M. Stallman's avatar
Richard M. Stallman committed
385 386
}

Karl Heuer's avatar
Karl Heuer committed
387
DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
388 389 390 391 392
       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
393 394
     (sound)
     Lisp_Object sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
395
{
396
  CHECK_SYMBOL (sound);
Karl Heuer's avatar
Karl Heuer committed
397

398
  if (NILP (sound))
Karl Heuer's avatar
Karl Heuer committed
399 400 401
      sound_type = 0xFFFFFFFF;
  else if (EQ (sound, intern ("asterisk")))
      sound_type = MB_ICONASTERISK;
402
  else if (EQ (sound, intern ("exclamation")))
Karl Heuer's avatar
Karl Heuer committed
403
      sound_type = MB_ICONEXCLAMATION;
404
  else if (EQ (sound, intern ("hand")))
Karl Heuer's avatar
Karl Heuer committed
405
      sound_type = MB_ICONHAND;
406
  else if (EQ (sound, intern ("question")))
Karl Heuer's avatar
Karl Heuer committed
407
      sound_type = MB_ICONQUESTION;
408
  else if (EQ (sound, intern ("ok")))
Karl Heuer's avatar
Karl Heuer committed
409
      sound_type = MB_OK;
410 411
  else if (EQ (sound, intern ("silent")))
      sound_type = MB_EMACS_SILENT;
Karl Heuer's avatar
Karl Heuer committed
412 413 414 415
  else
      sound_type = 0xFFFFFFFF;

  return sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
416
}
417

418
static void
419
w32con_reset_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
420
{
421
#ifdef USE_SEPARATE_SCREEN
Richard M. Stallman's avatar
Richard M. Stallman committed
422
  SetConsoleActiveScreenBuffer (prev_screen);
423 424 425 426
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
  SetConsoleMode (keyboard_handle, prev_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
427 428
}

429
static void
430
w32con_set_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
431 432 433
{
  CONSOLE_CURSOR_INFO cci;

434 435 436 437
  /* 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
438

439
  SetConsoleActiveScreenBuffer (cur_screen);
Richard M. Stallman's avatar
Richard M. Stallman committed
440

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

443 444 445
  /* 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
446 447 448 449
}

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

Richard M. Stallman's avatar
Richard M. Stallman committed
451
   we'll start with not moving the cursor while an update is in progress.  */
452 453
static void
w32con_update_begin (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
454 455 456
{
}

457 458
static void
w32con_update_end (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
459 460 461 462
{
  SetConsoleCursorPosition (cur_screen, cursor_coords);
}

463
static void
464
w32con_set_terminal_window (struct frame *f, int size)
Richard M. Stallman's avatar
Richard M. Stallman committed
465 466 467
{
}

468 469 470 471 472 473 474
/***********************************************************************
				Faces
 ***********************************************************************/


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

475 476
static WORD
w32_face_attributes (f, face_id)
477 478 479
     struct frame *f;
     int face_id;
{
480
  WORD char_attr;
481 482 483 484 485 486
  struct face *face = FACE_FROM_ID (f, face_id);

  xassert (face != NULL);

  char_attr = char_attr_normal;

487 488 489 490 491 492
  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)
493
    char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4);
494

495

496 497 498
  /* 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. */
499 500
  if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
    char_attr ^= 0x0007;
501

502
  if (face->tty_reverse_p)
503 504
    char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
      + ((char_attr & 0x00f0) >> 4);
505

506
  return char_attr;
507 508 509
}


510
/* Emulation of some X window features from xfns.c and xfaces.c.  */
511

512 513 514 515 516 517
extern char unspecified_fg[], unspecified_bg[];


/* Given a color index, return its standard name.  */
Lisp_Object
vga_stdcolor_name (int idx)
518
{
519 520 521 522 523 524 525 526 527 528 529 530 531 532
  /* 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 */
533
}
534

Richard M. Stallman's avatar
Richard M. Stallman committed
535 536
typedef int (*term_hook) ();

537 538 539 540
/* TEMPORARY HACK to get w32console compiling. To support multiple consoles,
   this needs to go! */
struct terminal one_and_only_w32cons;

Richard M. Stallman's avatar
Richard M. Stallman committed
541
void
542
initialize_w32_display (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
543 544
{
  CONSOLE_SCREEN_BUFFER_INFO	info;
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
  struct terminal *term = &one_and_only_w32cons;

  term->cursor_to_hook		= w32con_move_cursor;
  term->raw_cursor_to_hook		= w32con_move_cursor;
  term->clear_to_end_hook		= w32con_clear_to_end;
  term->clear_frame_hook		= w32con_clear_frame;
  term->clear_end_of_line_hook	= w32con_clear_end_of_line;
  term->ins_del_lines_hook		= w32con_ins_del_lines;
  term->insert_glyphs_hook		= w32con_insert_glyphs;
  term->write_glyphs_hook		= w32con_write_glyphs;
  term->delete_glyphs_hook		= w32con_delete_glyphs;
  term->ring_bell_hook		= w32_sys_ring_bell;
  term->reset_terminal_modes_hook	= w32con_reset_terminal_modes;
  term->set_terminal_modes_hook	= w32con_set_terminal_modes;
  term->set_terminal_window_hook	= w32con_set_terminal_window;
  term->update_begin_hook		= w32con_update_begin;
  term->update_end_hook		= w32con_update_end;

  term->read_socket_hook = w32_console_read_socket;
  term->mouse_position_hook = w32_console_mouse_position;
565

566 567 568
  /* Initialize interrupt_handle.  */
  init_crit ();

569 570 571 572
  /* 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
573
  prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
574

575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
#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

593 594 595 596 597 598 599 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
  /* 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
627
  GetConsoleScreenBufferInfo (cur_screen, &info);
628

629
  char_attr_normal = info.wAttributes;
630

631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
  /* 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)
649
    {
650 651
      FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;	/* lines per page */
      SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
652 653 654 655
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
656
      FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
657
	info.srWindow.Top;
658
      /* Characters per line.  Use buffer coords instead of buffer size.  */
659
      SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
660 661
		       info.srWindow.Left);
    }
662 663 664 665 666

  /* Setup w32_display_info structure for this frame. */

  w32_initialize_display_info (build_string ("Console"));

Richard M. Stallman's avatar
Richard M. Stallman committed
667 668
}

669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
/* Initialize the tty-dependent part of frame F.  The frame must
   already have its device initialized. */
void
create_w32cons_output(struct frame *f)
{
  struct tty_output *tty;

  if (! FRAME_TERMCAP_P (f))
    abort ();

  tty = xmalloc (sizeof (struct tty_output));
  bzero (tty, sizeof (struct tty_output));

  tty->display_info = FRAME_TERMINAL (f)->display_info.tty;
  tty->display_info->meta_key = 1;

  f->output_data.tty = tty;
}

Richard M. Stallman's avatar
Richard M. Stallman committed
688
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
689
       doc: /* Set screen colors.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
690 691 692 693 694 695 696 697 698 699 700
    (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,
701
       doc: /* Set cursor size.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
702 703 704 705 706 707 708
    (size)
    Lisp_Object size;
{
  CONSOLE_CURSOR_INFO cci;
  cci.dwSize = XFASTINT (size);
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
709

Richard M. Stallman's avatar
Richard M. Stallman committed
710 711 712
  return Qt;
}

Karl Heuer's avatar
Karl Heuer committed
713
void
Richard M. Stallman's avatar
Richard M. Stallman committed
714 715
syms_of_ntterm ()
{
716 717
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
               &w32_use_full_screen_buffer,
718
	       doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
719
This is desirable when running Emacs over telnet.
720 721 722
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.  */);
723
  w32_use_full_screen_buffer = 0;
724

Richard M. Stallman's avatar
Richard M. Stallman committed
725 726
  defsubr (&Sset_screen_color);
  defsubr (&Sset_cursor_size);
Karl Heuer's avatar
Karl Heuer committed
727
  defsubr (&Sset_message_beep);
Richard M. Stallman's avatar
Richard M. Stallman committed
728
}
Miles Bader's avatar
Miles Bader committed
729 730 731

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