w32console.c 20.3 KB
Newer Older
1
/* Terminal hooks for GNU Emacs on the Microsoft W32 API.
2
   Copyright (C) 1992, 1999, 2001-2011  Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
3

4 5
This file is part of GNU Emacs.

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

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
17
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
18

19
/*
Richard M. Stallman's avatar
Richard M. Stallman committed
20 21 22 23 24
   Tim Fleehart (apollo@online.com)		1-17-92
   Geoff Voelker (voelker@cs.washington.edu)	9-12-93
*/


25 26
#include <config.h>

Richard M. Stallman's avatar
Richard M. Stallman committed
27 28
#include <stdio.h>
#include <windows.h>
29
#include <setjmp.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
30 31

#include "lisp.h"
32
#include "character.h"
33
#include "coding.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
34
#include "disptab.h"
35
#include "frame.h"
36 37 38
#include "termhooks.h"
#include "termchar.h"
#include "dispextern.h"
Geoff Voelker's avatar
Geoff Voelker committed
39
#include "w32inevt.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
40

Karl Heuer's avatar
Karl Heuer committed
41
/* from window.c */
42
extern Lisp_Object Frecenter (Lisp_Object);
Richard M. Stallman's avatar
Richard M. Stallman committed
43

44 45 46 47 48 49 50 51 52 53 54
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);
55 56
static void w32con_update_begin (struct frame * f);
static void w32con_update_end (struct frame * f);
57
static WORD w32_face_attributes (struct frame *f, int face_id);
Richard M. Stallman's avatar
Richard M. Stallman committed
58

59 60 61
static COORD	cursor_coords;
static HANDLE	prev_screen, cur_screen;
static WORD	char_attr_normal;
62
static DWORD	prev_console_mode;
Richard M. Stallman's avatar
Richard M. Stallman committed
63

64
#ifndef USE_SEPARATE_SCREEN
65
static CONSOLE_CURSOR_INFO prev_console_cursor;
66 67
#endif

68
HANDLE  keyboard_handle;
69

Richard M. Stallman's avatar
Richard M. Stallman committed
70 71

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

Richard M. Stallman's avatar
Richard M. Stallman committed
75 76 77
BOOL
ctrl_c_handler (unsigned long type)
{
78 79 80
  /* 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
81 82 83
}


84
/* Move the cursor to (ROW, COL) on FRAME.  */
Jason Rumney's avatar
Jason Rumney committed
85
static void
86
w32con_move_cursor (struct frame *f, int row, int col)
Richard M. Stallman's avatar
Richard M. Stallman committed
87 88 89
{
  cursor_coords.X = col;
  cursor_coords.Y = row;
90

91 92 93
  /* 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
94 95 96
}

/* Clear from cursor to end of screen.  */
Jason Rumney's avatar
Jason Rumney committed
97
static void
98
w32con_clear_to_end (struct frame *f)
Richard M. Stallman's avatar
Richard M. Stallman committed
99
{
100 101
  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
102 103 104
}

/* Clear the frame.  */
105
static void
106
w32con_clear_frame (struct frame *f)
Richard M. Stallman's avatar
Richard M. Stallman committed
107
{
108
  COORD	     dest;
Andrew Innes's avatar
Andrew Innes committed
109 110
  int        n;
  DWORD      r;
111 112 113
  CONSOLE_SCREEN_BUFFER_INFO info;

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

115
  /* Remember that the screen buffer might be wider than the window.  */
116
  n = FRAME_LINES (f) * info.dwSize.X;
117 118
  dest.X = dest.Y = 0;

119
  FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
120 121
  FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);

122
  w32con_move_cursor (f, 0, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
123 124 125
}


126
static struct glyph glyph_base[256];
Richard M. Stallman's avatar
Richard M. Stallman committed
127 128 129
static BOOL  ceol_initialized = FALSE;

/* Clear from Cursor to end (what's "standout marker"?).  */
130
static void
131
w32con_clear_end_of_line (struct frame *f, int end)
Richard M. Stallman's avatar
Richard M. Stallman committed
132 133 134 135 136 137
{
  if (!ceol_initialized)
    {
      int i;
      for (i = 0; i < 256; i++)
        {
138
	  memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
Richard M. Stallman's avatar
Richard M. Stallman committed
139 140 141
        }
      ceol_initialized = TRUE;
    }
142
  w32con_write_glyphs (f, glyph_base, end - cursor_coords.X);	/* fencepost ?	*/
Richard M. Stallman's avatar
Richard M. Stallman committed
143 144 145
}

/* Insert n lines at vpos. if n is negative delete -n lines.  */
146
static void
147
w32con_ins_del_lines (struct frame *f, int vpos, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
148
{
149
  int	     i, nb;
Richard M. Stallman's avatar
Richard M. Stallman committed
150
  SMALL_RECT scroll;
151
  SMALL_RECT clip;
Richard M. Stallman's avatar
Richard M. Stallman committed
152 153 154 155 156 157
  COORD	     dest;
  CHAR_INFO  fill;

  if (n < 0)
    {
      scroll.Top = vpos - n;
158
      scroll.Bottom = FRAME_LINES (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
159 160 161 162 163
      dest.Y = vpos;
    }
  else
    {
      scroll.Top = vpos;
164
      scroll.Bottom = FRAME_LINES (f) - n;
Richard M. Stallman's avatar
Richard M. Stallman committed
165 166
      dest.Y = vpos + n;
    }
167 168 169
  clip.Top = clip.Left = scroll.Left = 0;
  clip.Right = scroll.Right = FRAME_COLS (f);
  clip.Bottom = FRAME_LINES (f);
170

Richard M. Stallman's avatar
Richard M. Stallman committed
171
  dest.X = 0;
172

Richard M. Stallman's avatar
Richard M. Stallman committed
173
  fill.Char.AsciiChar = 0x20;
174
  fill.Attributes = char_attr_normal;
175

176
  ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
Richard M. Stallman's avatar
Richard M. Stallman committed
177

178
  /* Here we have to deal with a w32 console flake: If the scroll
Richard M. Stallman's avatar
Richard M. Stallman committed
179 180 181 182 183 184 185 186 187 188 189 190
     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++)
            {
191 192
	      w32con_move_cursor (f, i, 0);
	      w32con_clear_end_of_line (f, FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
193 194 195 196 197 198 199 200
            }
        }
    }
  else
    {
      nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;

      if (nb < scroll.Top)
201
        {
Richard M. Stallman's avatar
Richard M. Stallman committed
202 203
	  for (i = nb; i < scroll.Top; i++)
            {
204 205
	      w32con_move_cursor (f, i, 0);
	      w32con_clear_end_of_line (f, FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
206 207 208
            }
        }
    }
209

Richard M. Stallman's avatar
Richard M. Stallman committed
210 211 212 213 214 215 216 217 218
  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
219
static void
220
scroll_line (struct frame *f, int dist, int direction)
Richard M. Stallman's avatar
Richard M. Stallman committed
221 222 223
{
  /* The idea here is to implement a horizontal scroll in one line to
     implement delete and half of insert.  */
224
  SMALL_RECT scroll, clip;
Richard M. Stallman's avatar
Richard M. Stallman committed
225 226
  COORD	     dest;
  CHAR_INFO  fill;
227

228 229 230
  clip.Top = scroll.Top = clip.Bottom = scroll.Bottom = cursor_coords.Y;
  clip.Left = 0;
  clip.Right = FRAME_COLS (f);
231

Richard M. Stallman's avatar
Richard M. Stallman committed
232 233 234
  if (direction == LEFT)
    {
      scroll.Left = cursor_coords.X + dist;
235
      scroll.Right = FRAME_COLS (f) - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
236 237 238 239
    }
  else
    {
      scroll.Left = cursor_coords.X;
240
      scroll.Right = FRAME_COLS (f) - dist - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
241
    }
242

Richard M. Stallman's avatar
Richard M. Stallman committed
243 244
  dest.X = cursor_coords.X;
  dest.Y = cursor_coords.Y;
245

Richard M. Stallman's avatar
Richard M. Stallman committed
246
  fill.Char.AsciiChar = 0x20;
247 248
  fill.Attributes = char_attr_normal;

249
  ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
Richard M. Stallman's avatar
Richard M. Stallman committed
250 251 252 253
}


/* If start is zero insert blanks instead of a string at start ?. */
254
static void
255 256
w32con_insert_glyphs (struct frame *f, register struct glyph *start,
		      register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
257
{
258
  scroll_line (f, len, RIGHT);
Richard M. Stallman's avatar
Richard M. Stallman committed
259 260 261 262 263 264

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

266
      w32con_write_glyphs (f, start, len);
Richard M. Stallman's avatar
Richard M. Stallman committed
267 268 269
    }
  else
    {
270
      w32con_clear_end_of_line (f, cursor_coords.X + len);
Richard M. Stallman's avatar
Richard M. Stallman committed
271 272 273
    }
}

274
static void
275 276
w32con_write_glyphs (struct frame *f, register struct glyph *string,
                     register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
277
{
Andrew Innes's avatar
Andrew Innes committed
278
  DWORD r;
279
  WORD char_attr;
280 281
  unsigned char *conversion_buffer;
  struct coding_system *coding;
282 283 284

  if (len <= 0)
    return;
285

286 287 288
  /* 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.  */
289 290
  coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
291 292
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
293
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
Richard M. Stallman's avatar
Richard M. Stallman committed
294

295
  while (len > 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
296
    {
297 298 299
      /* Identify a run of glyphs with the same face.  */
      int face_id = string->face_id;
      int n;
300

301 302 303 304 305
      for (n = 1; n < len; ++n)
	if (string[n].face_id != face_id)
	  break;

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

308 309 310 311 312 313 314 315 316 317
      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))
318
	    {
319 320 321 322 323 324
	      printf ("Failed writing console attributes: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  /* Write the characters.  */
325
	  if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
326 327 328 329 330 331 332 333 334
					    coding->produced, cursor_coords,
					    &r))
	    {
	      printf ("Failed writing console characters: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  cursor_coords.X += coding->produced;
335
	  w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X);
336 337 338
	}
      len -= n;
      string += n;
Richard M. Stallman's avatar
Richard M. Stallman committed
339 340 341
    }
}

342

343
static void
344
w32con_delete_glyphs (struct frame *f, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
345
{
346 347
  /* 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
348 349
     come out empty...  */

350
  scroll_line (f, n, LEFT);
Richard M. Stallman's avatar
Richard M. Stallman committed
351 352
}

Karl Heuer's avatar
Karl Heuer committed
353
static unsigned int sound_type = 0xFFFFFFFF;
354
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
Karl Heuer's avatar
Karl Heuer committed
355

Richard M. Stallman's avatar
Richard M. Stallman committed
356
void
357
w32_sys_ring_bell (struct frame *f)
Richard M. Stallman's avatar
Richard M. Stallman committed
358
{
359
  if (sound_type == 0xFFFFFFFF)
360
    {
Karl Heuer's avatar
Karl Heuer committed
361
      Beep (666, 100);
362 363 364 365 366
    }
  else if (sound_type == MB_EMACS_SILENT)
    {
      /* Do nothing.  */
    }
Karl Heuer's avatar
Karl Heuer committed
367
  else
368
    MessageBeep (sound_type);
Richard M. Stallman's avatar
Richard M. Stallman committed
369 370
}

Karl Heuer's avatar
Karl Heuer committed
371
DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
372 373 374 375 376
       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.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
377
  (Lisp_Object sound)
Richard M. Stallman's avatar
Richard M. Stallman committed
378
{
379
  CHECK_SYMBOL (sound);
Karl Heuer's avatar
Karl Heuer committed
380

381
  if (NILP (sound))
Karl Heuer's avatar
Karl Heuer committed
382 383 384
      sound_type = 0xFFFFFFFF;
  else if (EQ (sound, intern ("asterisk")))
      sound_type = MB_ICONASTERISK;
385
  else if (EQ (sound, intern ("exclamation")))
Karl Heuer's avatar
Karl Heuer committed
386
      sound_type = MB_ICONEXCLAMATION;
387
  else if (EQ (sound, intern ("hand")))
Karl Heuer's avatar
Karl Heuer committed
388
      sound_type = MB_ICONHAND;
389
  else if (EQ (sound, intern ("question")))
Karl Heuer's avatar
Karl Heuer committed
390
      sound_type = MB_ICONQUESTION;
391
  else if (EQ (sound, intern ("ok")))
Karl Heuer's avatar
Karl Heuer committed
392
      sound_type = MB_OK;
393 394
  else if (EQ (sound, intern ("silent")))
      sound_type = MB_EMACS_SILENT;
Karl Heuer's avatar
Karl Heuer committed
395 396 397 398
  else
      sound_type = 0xFFFFFFFF;

  return sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
399
}
400

401
static void
402
w32con_reset_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
403
{
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
  COORD dest;
  CONSOLE_SCREEN_BUFFER_INFO info;
  int n;
  DWORD r;

  /* Clear the complete screen buffer.  This is required because Emacs
     sets the cursor position to the top of the buffer, but there might
     be other output below the bottom of the Emacs frame if the screen buffer
     is larger than the window size.  */
  GetConsoleScreenBufferInfo (cur_screen, &info);
  dest.X = 0;
  dest.Y = 0;
  n = info.dwSize.X * info.dwSize.Y;

  FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
  FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
  /* Now that the screen is clear, put the cursor at the top.  */
  SetConsoleCursorPosition (cur_screen, dest);
422

423
#ifdef USE_SEPARATE_SCREEN
Richard M. Stallman's avatar
Richard M. Stallman committed
424
  SetConsoleActiveScreenBuffer (prev_screen);
425 426 427
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
428

429
  SetConsoleMode (keyboard_handle, prev_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
430 431
}

432
static void
433
w32con_set_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
434 435 436
{
  CONSOLE_CURSOR_INFO cci;

437 438 439 440
  /* 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
441

442
  SetConsoleActiveScreenBuffer (cur_screen);
Richard M. Stallman's avatar
Richard M. Stallman committed
443

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

446 447 448
  /* 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
449 450 451 452
}

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

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

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

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

471 472 473 474 475
/***********************************************************************
			stubs from termcap.c
 ***********************************************************************/

void
476
sys_tputs (char *str, int nlines, int (*outfun) (int))
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
{
}

char *
sys_tgetstr (char *cap, char **area)
{
  return NULL;
}


/***********************************************************************
			stubs from cm.c
 ***********************************************************************/

struct tty_display_info *current_tty = NULL;
int cost = 0;

int
495
evalcost (int c)
496 497 498 499 500
{
  return c;
}

int
501
cmputc (int c)
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
{
  return c;
}

void
cmcheckmagic (struct tty_display_info *tty)
{
}

void
cmcostinit (struct tty_display_info *tty)
{
}

void
cmgoto (struct tty_display_info *tty, int row, int col)
{
}

void
Wcm_clear (struct tty_display_info *tty)
{
}


527 528 529 530 531 532 533
/***********************************************************************
				Faces
 ***********************************************************************/


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

534
static WORD
535
w32_face_attributes (struct frame *f, int face_id)
536
{
537
  WORD char_attr;
538 539 540 541 542 543
  struct face *face = FACE_FROM_ID (f, face_id);

  xassert (face != NULL);

  char_attr = char_attr_normal;

544 545
  /* Reverse the default color if requested. If background and
     foreground are specified, then they have been reversed already.  */
546
  if (face->tty_reverse_p)
547 548
    char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
      + ((char_attr & 0x00f0) >> 4);
549

550
  /* Before the terminal is properly initialized, all colors map to 0.
551
     Don't try to resolve them.  */
552
  if (NILP (Vtty_defined_color_alist))
553
    return char_attr;
554

555 556 557 558 559 560
  /* Colors should be in the range 0...15 unless they are one of
     FACE_TTY_DEFAULT_COLOR, FACE_TTY_DEFAULT_FG_COLOR or
     FACE_TTY_DEFAULT_BG_COLOR.  Other out of range colors are
     invalid, so it is better to use the default color if they ever
     get through to here.  */
  if (face->foreground >= 0 && face->foreground < 16)
561
    char_attr = (char_attr & 0xfff0) + face->foreground;
562

563
  if (face->background >= 0 && face->background < 16)
564
    char_attr = (char_attr & 0xff0f) + (face->background << 4);
565

566
  return char_attr;
567 568
}

Richard M. Stallman's avatar
Richard M. Stallman committed
569
void
Jason Rumney's avatar
Jason Rumney committed
570
initialize_w32_display (struct terminal *term)
Richard M. Stallman's avatar
Richard M. Stallman committed
571 572
{
  CONSOLE_SCREEN_BUFFER_INFO	info;
573

574
  term->rif = 0; /* No window based redisplay on the console.  */
575
  term->cursor_to_hook		= w32con_move_cursor;
576 577 578
  term->raw_cursor_to_hook	= w32con_move_cursor;
  term->clear_to_end_hook	= w32con_clear_to_end;
  term->clear_frame_hook	= w32con_clear_frame;
579
  term->clear_end_of_line_hook	= w32con_clear_end_of_line;
580 581 582 583
  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;
584
  term->ring_bell_hook		= w32_sys_ring_bell;
585
  term->reset_terminal_modes_hook = w32con_reset_terminal_modes;
586
  term->set_terminal_modes_hook	= w32con_set_terminal_modes;
587 588
  term->set_terminal_window_hook = w32con_set_terminal_window;
  term->update_begin_hook	= w32con_update_begin;
589 590 591 592
  term->update_end_hook		= w32con_update_end;

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

594 595 596 597 598 599 600 601
  /* The following are not used on the console.  */
  term->frame_rehighlight_hook = 0;
  term->frame_raise_lower_hook = 0;
  term->set_vertical_scroll_bar_hook = 0;
  term->condemn_scroll_bars_hook = 0;
  term->redeem_scroll_bar_hook = 0;
  term->judge_scroll_bars_hook = 0;
  term->frame_up_to_date_hook = 0;
602

603 604 605
  /* Initialize interrupt_handle.  */
  init_crit ();

606 607 608 609
  /* 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
610
  prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
611

612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
#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

630 631
  /* Respect setting of LINES and COLUMNS environment variables.  */
  {
632 633
    char * lines = getenv ("LINES");
    char * columns = getenv ("COLUMNS");
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663

    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
664
  GetConsoleScreenBufferInfo (cur_screen, &info);
665

666
  char_attr_normal = info.wAttributes;
667

668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
  /* 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)
686
    {
687 688
      FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;	/* lines per page */
      SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
689 690 691 692
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
693
      FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
694
	info.srWindow.Top;
695
      /* Characters per line.  Use buffer coords instead of buffer size.  */
696
      SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
697 698
		       info.srWindow.Left);
    }
699 700 701 702 703

  /* Setup w32_display_info structure for this frame. */

  w32_initialize_display_info (build_string ("Console"));

Richard M. Stallman's avatar
Richard M. Stallman committed
704 705
}

706

Richard M. Stallman's avatar
Richard M. Stallman committed
707
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
708
       doc: /* Set screen colors.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
709
  (Lisp_Object foreground, Lisp_Object background)
Richard M. Stallman's avatar
Richard M. Stallman committed
710 711 712 713 714 715 716 717
{
  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,
718
       doc: /* Set cursor size.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
719
  (Lisp_Object size)
Richard M. Stallman's avatar
Richard M. Stallman committed
720 721 722 723 724
{
  CONSOLE_CURSOR_INFO cci;
  cci.dwSize = XFASTINT (size);
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
725

Richard M. Stallman's avatar
Richard M. Stallman committed
726 727 728
  return Qt;
}

Karl Heuer's avatar
Karl Heuer committed
729
void
730
syms_of_ntterm (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
731
{
732
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
733
               w32_use_full_screen_buffer,
734
	       doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
735
This is desirable when running Emacs over telnet.
736 737 738
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.  */);
739
  w32_use_full_screen_buffer = 0;
740

Richard M. Stallman's avatar
Richard M. Stallman committed
741 742
  defsubr (&Sset_screen_color);
  defsubr (&Sset_cursor_size);
Karl Heuer's avatar
Karl Heuer committed
743
  defsubr (&Sset_message_beep);
Richard M. Stallman's avatar
Richard M. Stallman committed
744
}
Kenichi Handa's avatar
Kenichi Handa committed
745