w32console.c 24 KB
Newer Older
1
/* Terminal hooks for GNU Emacs on the Microsoft W32 API.
2
   Copyright (C) 1992, 1999, 2001-2012  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
#include "window.h"
37 38 39
#include "termhooks.h"
#include "termchar.h"
#include "dispextern.h"
Geoff Voelker's avatar
Geoff Voelker committed
40
#include "w32inevt.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
41

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

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

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

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

69
HANDLE  keyboard_handle;
70

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

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

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


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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

      if (nb < scroll.Top)
202
        {
Richard M. Stallman's avatar
Richard M. Stallman committed
203 204
	  for (i = nb; i < scroll.Top; 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

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

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

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

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

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

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


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

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

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

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

  if (len <= 0)
    return;
286

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

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

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

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

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

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

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

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
/* Used for mouse highlight.  */
static void
w32con_write_glyphs_with_face (struct frame *f, register int x, register int y,
			       register struct glyph *string, register int len,
			       register int face_id)
{
  unsigned char *conversion_buffer;
  struct coding_system *coding;

  if (len <= 0)
    return;

  /* 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 = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
  /* We are going to write the entire block of glyphs in one go, as
     they all have the same face.  So this _is_ the last block.  */
  coding->mode |= CODING_MODE_LAST_BLOCK;

  conversion_buffer = encode_terminal_code (string, len, coding);
  if (coding->produced > 0)
    {
      DWORD filled, written;
      /* Compute the character attributes corresponding to the face.  */
      DWORD char_attr = w32_face_attributes (f, face_id);
      COORD start_coords;

      start_coords.X = x;
      start_coords.Y = y;
      /* Set the attribute for these characters.  */
      if (!FillConsoleOutputAttribute (cur_screen, char_attr,
				       coding->produced, start_coords,
				       &filled))
	DebPrint (("Failed writing console attributes: %d\n", GetLastError ()));
      else
	{
	  /* Write the characters.  */
	  if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
					    filled, start_coords, &written))
	    DebPrint (("Failed writing console characters: %d\n",
		       GetLastError ()));
	}
    }
}

/* Implementation of draw_row_with_mouse_face for W32 console.  */
void
tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
			      int start_hpos, int end_hpos,
			      enum draw_glyphs_face draw)
{
  int nglyphs = end_hpos - start_hpos;
  struct frame *f = XFRAME (WINDOW_FRAME (w));
  struct tty_display_info *tty = FRAME_TTY (f);
  int face_id = tty->mouse_highlight.mouse_face_face_id;
  int pos_x, pos_y;

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

  pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
  pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);

  if (draw == DRAW_MOUSE_FACE)
    w32con_write_glyphs_with_face (f, pos_x, pos_y,
				   row->glyphs[TEXT_AREA] + start_hpos,
				   nglyphs, face_id);
  else if (draw == DRAW_NORMAL_TEXT)
    {
      COORD save_coords = cursor_coords;

      w32con_move_cursor (f, pos_y, pos_x);
      write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
      w32con_move_cursor (f, save_coords.Y, save_coords.X);
    }
}
421

422
static void
423
w32con_delete_glyphs (struct frame *f, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
424
{
425 426
  /* 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
427 428
     come out empty...  */

429
  scroll_line (f, n, LEFT);
Richard M. Stallman's avatar
Richard M. Stallman committed
430 431
}

Karl Heuer's avatar
Karl Heuer committed
432
static unsigned int sound_type = 0xFFFFFFFF;
433
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
Karl Heuer's avatar
Karl Heuer committed
434

Richard M. Stallman's avatar
Richard M. Stallman committed
435
void
436
w32_sys_ring_bell (struct frame *f)
Richard M. Stallman's avatar
Richard M. Stallman committed
437
{
438
  if (sound_type == 0xFFFFFFFF)
439
    {
Karl Heuer's avatar
Karl Heuer committed
440
      Beep (666, 100);
441 442 443 444 445
    }
  else if (sound_type == MB_EMACS_SILENT)
    {
      /* Do nothing.  */
    }
Karl Heuer's avatar
Karl Heuer committed
446
  else
447
    MessageBeep (sound_type);
Richard M. Stallman's avatar
Richard M. Stallman committed
448 449
}

Karl Heuer's avatar
Karl Heuer committed
450
DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
451 452 453 454 455
       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
456
  (Lisp_Object sound)
Richard M. Stallman's avatar
Richard M. Stallman committed
457
{
458
  CHECK_SYMBOL (sound);
Karl Heuer's avatar
Karl Heuer committed
459

460
  if (NILP (sound))
Karl Heuer's avatar
Karl Heuer committed
461 462 463
      sound_type = 0xFFFFFFFF;
  else if (EQ (sound, intern ("asterisk")))
      sound_type = MB_ICONASTERISK;
464
  else if (EQ (sound, intern ("exclamation")))
Karl Heuer's avatar
Karl Heuer committed
465
      sound_type = MB_ICONEXCLAMATION;
466
  else if (EQ (sound, intern ("hand")))
Karl Heuer's avatar
Karl Heuer committed
467
      sound_type = MB_ICONHAND;
468
  else if (EQ (sound, intern ("question")))
Karl Heuer's avatar
Karl Heuer committed
469
      sound_type = MB_ICONQUESTION;
470
  else if (EQ (sound, intern ("ok")))
Karl Heuer's avatar
Karl Heuer committed
471
      sound_type = MB_OK;
472 473
  else if (EQ (sound, intern ("silent")))
      sound_type = MB_EMACS_SILENT;
Karl Heuer's avatar
Karl Heuer committed
474 475 476 477
  else
      sound_type = 0xFFFFFFFF;

  return sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
478
}
479

480
static void
481
w32con_reset_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
482
{
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
  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);
501

502
#ifdef USE_SEPARATE_SCREEN
Richard M. Stallman's avatar
Richard M. Stallman committed
503
  SetConsoleActiveScreenBuffer (prev_screen);
504 505 506
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
507

508
  SetConsoleMode (keyboard_handle, prev_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
509 510
}

511
static void
512
w32con_set_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
513 514 515
{
  CONSOLE_CURSOR_INFO cci;

516 517 518 519
  /* 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
520

521
  SetConsoleActiveScreenBuffer (cur_screen);
Richard M. Stallman's avatar
Richard M. Stallman committed
522

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

525 526 527
  /* 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
528 529 530 531
}

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

Richard M. Stallman's avatar
Richard M. Stallman committed
533
   we'll start with not moving the cursor while an update is in progress.  */
534 535
static void
w32con_update_begin (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
536 537 538
{
}

539 540
static void
w32con_update_end (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
541 542 543 544
{
  SetConsoleCursorPosition (cur_screen, cursor_coords);
}

545
static void
546
w32con_set_terminal_window (struct frame *f, int size)
Richard M. Stallman's avatar
Richard M. Stallman committed
547 548 549
{
}

550 551 552 553 554
/***********************************************************************
			stubs from termcap.c
 ***********************************************************************/

void
555
sys_tputs (char *str, int nlines, int (*outfun) (int))
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
{
}

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


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

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

int
574
evalcost (int c)
575 576 577 578 579
{
  return c;
}

int
580
cmputc (int c)
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
{
  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)
{
}


606 607 608 609 610 611 612
/***********************************************************************
				Faces
 ***********************************************************************/


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

613
static WORD
614
w32_face_attributes (struct frame *f, int face_id)
615
{
616
  WORD char_attr;
617 618 619 620 621 622
  struct face *face = FACE_FROM_ID (f, face_id);

  xassert (face != NULL);

  char_attr = char_attr_normal;

623 624
  /* Reverse the default color if requested. If background and
     foreground are specified, then they have been reversed already.  */
625
  if (face->tty_reverse_p)
626 627
    char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
      + ((char_attr & 0x00f0) >> 4);
628

629
  /* Before the terminal is properly initialized, all colors map to 0.
630
     Don't try to resolve them.  */
631
  if (NILP (Vtty_defined_color_alist))
632
    return char_attr;
633

634 635 636 637 638 639
  /* 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)
640
    char_attr = (char_attr & 0xfff0) + face->foreground;
641

642
  if (face->background >= 0 && face->background < 16)
643
    char_attr = (char_attr & 0xff0f) + (face->background << 4);
644

645
  return char_attr;
646 647
}

Richard M. Stallman's avatar
Richard M. Stallman committed
648
void
Jason Rumney's avatar
Jason Rumney committed
649
initialize_w32_display (struct terminal *term)
Richard M. Stallman's avatar
Richard M. Stallman committed
650 651
{
  CONSOLE_SCREEN_BUFFER_INFO	info;
652
  Mouse_HLInfo *hlinfo;
653

654
  term->rif = 0; /* No window based redisplay on the console.  */
655
  term->cursor_to_hook		= w32con_move_cursor;
656 657 658
  term->raw_cursor_to_hook	= w32con_move_cursor;
  term->clear_to_end_hook	= w32con_clear_to_end;
  term->clear_frame_hook	= w32con_clear_frame;
659
  term->clear_end_of_line_hook	= w32con_clear_end_of_line;
660 661 662 663
  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;
664
  term->ring_bell_hook		= w32_sys_ring_bell;
665
  term->reset_terminal_modes_hook = w32con_reset_terminal_modes;
666
  term->set_terminal_modes_hook	= w32con_set_terminal_modes;
667 668
  term->set_terminal_window_hook = w32con_set_terminal_window;
  term->update_begin_hook	= w32con_update_begin;
669 670 671 672
  term->update_end_hook		= w32con_update_end;

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

674 675 676 677 678 679 680 681
  /* 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;
682

683 684 685 686 687 688 689 690 691
  /* Initialize the mouse-highlight data.  */
  hlinfo = &term->display_info.tty->mouse_highlight;
  hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
  hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
  hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
  hlinfo->mouse_face_mouse_frame = NULL;
  hlinfo->mouse_face_window = Qnil;
  hlinfo->mouse_face_hidden = 0;

692 693 694
  /* Initialize interrupt_handle.  */
  init_crit ();

695 696 697 698
  /* 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
699
  prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
700

701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
#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

719 720
  /* Respect setting of LINES and COLUMNS environment variables.  */
  {
721 722
    char * lines = getenv ("LINES");
    char * columns = getenv ("COLUMNS");
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752

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

755
  char_attr_normal = info.wAttributes;
756

757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
  /* 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)
775
    {
776 777
      FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;	/* lines per page */
      SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
778 779 780 781
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
782
      FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
783
	info.srWindow.Top;
784
      /* Characters per line.  Use buffer coords instead of buffer size.  */
785
      SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
786 787
		       info.srWindow.Left);
    }
788 789 790 791 792

  /* Setup w32_display_info structure for this frame. */

  w32_initialize_display_info (build_string ("Console"));

Richard M. Stallman's avatar
Richard M. Stallman committed
793 794
}

795

Richard M. Stallman's avatar
Richard M. Stallman committed
796
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
797 798 799
       doc: /* Set screen foreground and background colors.

Arguments should be indices between 0 and 15, see w32console.el.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
800
  (Lisp_Object foreground, Lisp_Object background)
Richard M. Stallman's avatar
Richard M. Stallman committed
801 802 803 804 805 806 807
{
  char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);

  Frecenter (Qnil);
  return Qt;
}

808 809 810 811 812 813 814 815 816 817 818 819
DEFUN ("get-screen-color", Fget_screen_color, Sget_screen_color, 0, 0, 0,
       doc: /* Get color indices of the current screen foreground and background.

The colors are returned as a list of 2 indices (FOREGROUND BACKGROUND).
See w32console.el and `tty-defined-color-alist' for mapping of indices
to colors.  */)
  (void)
{
  return Fcons (make_number (char_attr_normal & 0x000f),
		Fcons (make_number ((char_attr_normal >> 4) & 0x000f), Qnil));
}

Richard M. Stallman's avatar
Richard M. Stallman committed
820
DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
821
       doc: /* Set cursor size.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
822
  (Lisp_Object size)
Richard M. Stallman's avatar
Richard M. Stallman committed
823 824 825 826 827
{
  CONSOLE_CURSOR_INFO cci;
  cci.dwSize = XFASTINT (size);
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
828

Richard M. Stallman's avatar
Richard M. Stallman committed
829 830 831
  return Qt;
}

Karl Heuer's avatar
Karl Heuer committed
832
void
833
syms_of_ntterm (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
834
{
835
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
836
               w32_use_full_screen_buffer,
837
	       doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
838
This is desirable when running Emacs over telnet.
839
A value of nil means use the current console window dimensions; this
Paul Eggert's avatar
Paul Eggert committed
840
may be preferable when working directly at the console with a large
841
scroll-back buffer.  */);
842
  w32_use_full_screen_buffer = 0;
843

Richard M. Stallman's avatar
Richard M. Stallman committed
844
  defsubr (&Sset_screen_color);
845
  defsubr (&Sget_screen_color);
Richard M. Stallman's avatar
Richard M. Stallman committed
846
  defsubr (&Sset_cursor_size);
Karl Heuer's avatar
Karl Heuer committed
847
  defsubr (&Sset_message_beep);
Richard M. Stallman's avatar
Richard M. Stallman committed
848
}