w32console.c 21.8 KB
Newer Older
1
/* Terminal hooks for GNU Emacs on the Microsoft W32 API.
2
   Copyright (C) 1992, 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
Glenn Morris's avatar
Glenn Morris committed
3
                 2008, 2009, 2010  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
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.
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
/*
Richard M. Stallman's avatar
Richard M. Stallman committed
21 22 23 24 25
   Tim Fleehart (apollo@online.com)		1-17-92
   Geoff Voelker (voelker@cs.washington.edu)	9-12-93
*/


26 27
#include <config.h>

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

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

Karl Heuer's avatar
Karl Heuer committed
44
/* from window.c */
45
extern Lisp_Object Frecenter (Lisp_Object);
Richard M. Stallman's avatar
Richard M. Stallman committed
46 47

/* from keyboard.c */
48
extern int detect_input_pending (void);
Richard M. Stallman's avatar
Richard M. Stallman committed
49 50

/* from sysdep.c */
51
extern int read_input_pending (void);
Richard M. Stallman's avatar
Richard M. Stallman committed
52

53 54 55 56 57 58 59 60 61 62 63
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);
64 65
static void w32con_update_begin (struct frame * f);
static void w32con_update_end (struct frame * f);
66
static WORD w32_face_attributes (struct frame *f, int face_id);
Richard M. Stallman's avatar
Richard M. Stallman committed
67

68 69 70
static COORD	cursor_coords;
static HANDLE	prev_screen, cur_screen;
static WORD	char_attr_normal;
71
static DWORD	prev_console_mode;
Richard M. Stallman's avatar
Richard M. Stallman committed
72

73
#ifndef USE_SEPARATE_SCREEN
74
static CONSOLE_CURSOR_INFO prev_console_cursor;
75 76
#endif

77 78
extern Lisp_Object Vtty_defined_color_alist;

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
  SMALL_RECT scroll;
167
  SMALL_RECT clip;
Richard M. Stallman's avatar
Richard M. Stallman committed
168 169 170 171 172 173
  COORD	     dest;
  CHAR_INFO  fill;

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

Richard M. Stallman's avatar
Richard M. Stallman committed
187
  dest.X = 0;
188

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

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

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

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

Richard M. Stallman's avatar
Richard M. Stallman committed
226 227 228 229 230 231 232 233 234
  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
235
static void
236
scroll_line (struct frame *f, int dist, int direction)
Richard M. Stallman's avatar
Richard M. Stallman committed
237 238 239
{
  /* The idea here is to implement a horizontal scroll in one line to
     implement delete and half of insert.  */
240
  SMALL_RECT scroll, clip;
Richard M. Stallman's avatar
Richard M. Stallman committed
241 242
  COORD	     dest;
  CHAR_INFO  fill;
243

244 245 246
  clip.Top = scroll.Top = clip.Bottom = scroll.Bottom = cursor_coords.Y;
  clip.Left = 0;
  clip.Right = FRAME_COLS (f);
247

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

Richard M. Stallman's avatar
Richard M. Stallman committed
259 260
  dest.X = cursor_coords.X;
  dest.Y = cursor_coords.Y;
261

Richard M. Stallman's avatar
Richard M. Stallman committed
262
  fill.Char.AsciiChar = 0x20;
263 264
  fill.Attributes = char_attr_normal;

265
  ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
Richard M. Stallman's avatar
Richard M. Stallman committed
266 267 268 269
}


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

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

282
      w32con_write_glyphs (f, start, len);
Richard M. Stallman's avatar
Richard M. Stallman committed
283 284 285
    }
  else
    {
286
      w32con_clear_end_of_line (f, cursor_coords.X + len);
Richard M. Stallman's avatar
Richard M. Stallman committed
287 288 289
    }
}

290
extern unsigned char *encode_terminal_code (struct glyph *, int,
291
                                            struct coding_system *);
292

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

  if (len <= 0)
    return;
304

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

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

320 321 322 323 324
      for (n = 1; n < len; ++n)
	if (string[n].face_id != face_id)
	  break;

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

327 328 329 330 331 332 333 334 335 336
      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))
337
	    {
338 339 340 341 342 343
	      printf ("Failed writing console attributes: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  /* Write the characters.  */
344
	  if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
345 346 347 348 349 350 351 352 353
					    coding->produced, cursor_coords,
					    &r))
	    {
	      printf ("Failed writing console characters: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  cursor_coords.X += coding->produced;
354
	  w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X);
355 356 357
	}
      len -= n;
      string += n;
Richard M. Stallman's avatar
Richard M. Stallman committed
358 359 360
    }
}

361

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

369
  scroll_line (f, n, LEFT);
Richard M. Stallman's avatar
Richard M. Stallman committed
370 371
}

Karl Heuer's avatar
Karl Heuer committed
372
static unsigned int sound_type = 0xFFFFFFFF;
373
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
Karl Heuer's avatar
Karl Heuer committed
374

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

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

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

  return sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
419
}
420

421
static void
422
w32con_reset_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
423
{
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
  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);
442

443
#ifdef USE_SEPARATE_SCREEN
Richard M. Stallman's avatar
Richard M. Stallman committed
444
  SetConsoleActiveScreenBuffer (prev_screen);
445 446 447
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
448

449
  SetConsoleMode (keyboard_handle, prev_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
450 451
}

452
static void
453
w32con_set_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
454 455 456
{
  CONSOLE_CURSOR_INFO cci;

457 458 459 460
  /* 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
461

462
  SetConsoleActiveScreenBuffer (cur_screen);
Richard M. Stallman's avatar
Richard M. Stallman committed
463

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

466 467 468
  /* 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
469 470 471 472
}

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

Richard M. Stallman's avatar
Richard M. Stallman committed
474
   we'll start with not moving the cursor while an update is in progress.  */
475 476
static void
w32con_update_begin (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
477 478 479
{
}

480 481
static void
w32con_update_end (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
482 483 484 485
{
  SetConsoleCursorPosition (cur_screen, cursor_coords);
}

486
static void
487
w32con_set_terminal_window (struct frame *f, int size)
Richard M. Stallman's avatar
Richard M. Stallman committed
488 489 490
{
}

491 492 493 494 495
/***********************************************************************
			stubs from termcap.c
 ***********************************************************************/

void
496
sys_tputs (char *str, int nlines, int (*outfun) (int))
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
{
}

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


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

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

int
515
evalcost (int c)
516 517 518 519 520
{
  return c;
}

int
521
cmputc (int c)
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
{
  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)
{
}


547 548 549 550 551 552 553
/***********************************************************************
				Faces
 ***********************************************************************/


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

554
static WORD
555
w32_face_attributes (struct frame *f, int face_id)
556
{
557
  WORD char_attr;
558 559 560 561 562 563
  struct face *face = FACE_FROM_ID (f, face_id);

  xassert (face != NULL);

  char_attr = char_attr_normal;

564 565
  /* Reverse the default color if requested. If background and
     foreground are specified, then they have been reversed already.  */
566
  if (face->tty_reverse_p)
567 568
    char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
      + ((char_attr & 0x00f0) >> 4);
569

570
  /* Before the terminal is properly initialized, all colors map to 0.
571
     Don't try to resolve them.  */
572
  if (NILP (Vtty_defined_color_alist))
573
    return char_attr;
574

575 576 577 578 579 580
  /* 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)
581
    char_attr = (char_attr & 0xfff0) + face->foreground;
582

583
  if (face->background >= 0 && face->background < 16)
584
    char_attr = (char_attr & 0xff0f) + (face->background << 4);
585

586
  return char_attr;
587 588
}

589 590 591 592 593


/* Given a color index, return its standard name.  */
Lisp_Object
vga_stdcolor_name (int idx)
594
{
595 596 597 598 599 600 601 602 603 604 605 606 607 608
  /* 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 */
609
}
610

Richard M. Stallman's avatar
Richard M. Stallman committed
611
void
Jason Rumney's avatar
Jason Rumney committed
612
initialize_w32_display (struct terminal *term)
Richard M. Stallman's avatar
Richard M. Stallman committed
613 614
{
  CONSOLE_SCREEN_BUFFER_INFO	info;
615

616
  term->rif = 0; /* No window based redisplay on the console.  */
617
  term->cursor_to_hook		= w32con_move_cursor;
618 619 620
  term->raw_cursor_to_hook	= w32con_move_cursor;
  term->clear_to_end_hook	= w32con_clear_to_end;
  term->clear_frame_hook	= w32con_clear_frame;
621
  term->clear_end_of_line_hook	= w32con_clear_end_of_line;
622 623 624 625
  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;
626
  term->ring_bell_hook		= w32_sys_ring_bell;
627
  term->reset_terminal_modes_hook = w32con_reset_terminal_modes;
628
  term->set_terminal_modes_hook	= w32con_set_terminal_modes;
629 630
  term->set_terminal_window_hook = w32con_set_terminal_window;
  term->update_begin_hook	= w32con_update_begin;
631 632 633 634
  term->update_end_hook		= w32con_update_end;

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

636 637 638 639 640 641 642 643
  /* 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;
644

645 646 647
  /* Initialize interrupt_handle.  */
  init_crit ();

648 649 650 651
  /* 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
652
  prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
653

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
#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

672 673
  /* Respect setting of LINES and COLUMNS environment variables.  */
  {
674 675
    char * lines = getenv ("LINES");
    char * columns = getenv ("COLUMNS");
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

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

708
  char_attr_normal = info.wAttributes;
709

710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
  /* 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)
728
    {
729 730
      FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;	/* lines per page */
      SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
731 732 733 734
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
735
      FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
736
	info.srWindow.Top;
737
      /* Characters per line.  Use buffer coords instead of buffer size.  */
738
      SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
739 740
		       info.srWindow.Left);
    }
741 742 743 744 745

  /* Setup w32_display_info structure for this frame. */

  w32_initialize_display_info (build_string ("Console"));

Richard M. Stallman's avatar
Richard M. Stallman committed
746 747
}

748

Richard M. Stallman's avatar
Richard M. Stallman committed
749
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
750
       doc: /* Set screen colors.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
751 752 753 754 755 756 757 758 759 760 761
    (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,
762
       doc: /* Set cursor size.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
763 764 765 766 767 768 769
    (size)
    Lisp_Object size;
{
  CONSOLE_CURSOR_INFO cci;
  cci.dwSize = XFASTINT (size);
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
770

Richard M. Stallman's avatar
Richard M. Stallman committed
771 772 773
  return Qt;
}

Karl Heuer's avatar
Karl Heuer committed
774
void
775
syms_of_ntterm (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
776
{
777 778
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
               &w32_use_full_screen_buffer,
779
	       doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
780
This is desirable when running Emacs over telnet.
781 782 783
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.  */);
784
  w32_use_full_screen_buffer = 0;
785

Richard M. Stallman's avatar
Richard M. Stallman committed
786 787
  defsubr (&Sset_screen_color);
  defsubr (&Sset_cursor_size);
Karl Heuer's avatar
Karl Heuer committed
788
  defsubr (&Sset_message_beep);
Richard M. Stallman's avatar
Richard M. Stallman committed
789
}
Kenichi Handa's avatar
Kenichi Handa committed
790 791 792

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