w32console.c 24.6 KB
Newer Older
1
/* Terminal hooks for GNU Emacs on the Microsoft Windows API.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1992, 1999, 2001-2020 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 <https://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 29 30
#include <stdio.h>
#include <windows.h>

#include "lisp.h"
31
#include "coding.h"
32
#include "termchar.h"	/* for FRAME_TTY */
33
#include "dispextern.h"	/* for tty_defined_color */
34
#include "menu.h"	/* for tty_menu_show */
Daniel Colascione's avatar
Daniel Colascione committed
35
#include "w32term.h"
36
#include "w32common.h"	/* for os_subtype */
Geoff Voelker's avatar
Geoff Voelker committed
37
#include "w32inevt.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
38

39 40 41 42
#ifdef WINDOWSNT
#include "w32.h"	/* for syms_of_ntterm */
#endif

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

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

62
static CONSOLE_CURSOR_INFO console_cursor_info;
63
#ifndef USE_SEPARATE_SCREEN
64
static CONSOLE_CURSOR_INFO prev_console_cursor;
65 66
#endif

67
HANDLE  keyboard_handle;
68
int w32_console_unicode_input;
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.  */

75 76
BOOL ctrl_c_handler (unsigned long);

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


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

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

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
void
w32con_hide_cursor (void)
{
  GetConsoleCursorInfo (cur_screen, &console_cursor_info);
  console_cursor_info.bVisible = FALSE;
  SetConsoleCursorInfo (cur_screen, &console_cursor_info);
}

void
w32con_show_cursor (void)
{
  GetConsoleCursorInfo (cur_screen, &console_cursor_info);
  console_cursor_info.bVisible = TRUE;
  SetConsoleCursorInfo (cur_screen, &console_cursor_info);
}

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

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

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

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

137
  FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
138 139
  FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);

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


144 145 146
static struct glyph glyph_base[80];
static struct glyph *glyphs = glyph_base;
static size_t glyphs_len = ARRAYELTS (glyph_base);
Richard M. Stallman's avatar
Richard M. Stallman committed
147 148 149
static BOOL  ceol_initialized = FALSE;

/* Clear from Cursor to end (what's "standout marker"?).  */
150
static void
151
w32con_clear_end_of_line (struct frame *f, int end)
Richard M. Stallman's avatar
Richard M. Stallman committed
152
{
153 154 155 156 157 158 159 160 161 162 163
  /* Time to reallocate our "empty row"?  With today's large screens,
     it is not unthinkable to see TTY frames well in excess of
     80-character width.  */
  if (end - cursor_coords.X > glyphs_len)
    {
      if (glyphs == glyph_base)
	glyphs = NULL;
      glyphs = xrealloc (glyphs, FRAME_COLS (f) * sizeof (struct glyph));
      glyphs_len = FRAME_COLS (f);
      ceol_initialized = FALSE;
    }
Richard M. Stallman's avatar
Richard M. Stallman committed
164 165 166
  if (!ceol_initialized)
    {
      int i;
167
      for (i = 0; i < glyphs_len; i++)
Richard M. Stallman's avatar
Richard M. Stallman committed
168
        {
169
	  memcpy (&glyphs[i], &space_glyph, sizeof (struct glyph));
Richard M. Stallman's avatar
Richard M. Stallman committed
170 171 172
        }
      ceol_initialized = TRUE;
    }
173
  w32con_write_glyphs (f, glyphs, end - cursor_coords.X);
Richard M. Stallman's avatar
Richard M. Stallman committed
174 175 176
}

/* Insert n lines at vpos. if n is negative delete -n lines.  */
177
static void
178
w32con_ins_del_lines (struct frame *f, int vpos, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
179
{
180
  int	     i, nb;
Richard M. Stallman's avatar
Richard M. Stallman committed
181
  SMALL_RECT scroll;
182
  SMALL_RECT clip;
Richard M. Stallman's avatar
Richard M. Stallman committed
183 184 185 186 187 188
  COORD	     dest;
  CHAR_INFO  fill;

  if (n < 0)
    {
      scroll.Top = vpos - n;
189
      scroll.Bottom = FRAME_TOTAL_LINES (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
190 191 192 193 194
      dest.Y = vpos;
    }
  else
    {
      scroll.Top = vpos;
195
      scroll.Bottom = FRAME_TOTAL_LINES (f) - n;
Richard M. Stallman's avatar
Richard M. Stallman committed
196 197
      dest.Y = vpos + n;
    }
198 199
  clip.Top = clip.Left = scroll.Left = 0;
  clip.Right = scroll.Right = FRAME_COLS (f);
200
  clip.Bottom = FRAME_TOTAL_LINES (f);
201

Richard M. Stallman's avatar
Richard M. Stallman committed
202
  dest.X = 0;
203

Richard M. Stallman's avatar
Richard M. Stallman committed
204
  fill.Char.AsciiChar = 0x20;
205
  fill.Attributes = char_attr_normal;
206

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

209
  /* Here we have to deal with a w32 console flake: If the scroll
Richard M. Stallman's avatar
Richard M. Stallman committed
210 211 212 213 214 215 216 217 218 219 220 221
     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++)
            {
222 223
	      w32con_move_cursor (f, i, 0);
	      w32con_clear_end_of_line (f, FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
224 225 226 227 228 229 230 231
            }
        }
    }
  else
    {
      nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;

      if (nb < scroll.Top)
232
        {
Richard M. Stallman's avatar
Richard M. Stallman committed
233 234
	  for (i = nb; i < scroll.Top; i++)
            {
235 236
	      w32con_move_cursor (f, i, 0);
	      w32con_clear_end_of_line (f, FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
237 238 239
            }
        }
    }
240

Richard M. Stallman's avatar
Richard M. Stallman committed
241 242 243 244 245 246 247 248 249
  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
250
static void
251
scroll_line (struct frame *f, int dist, int direction)
Richard M. Stallman's avatar
Richard M. Stallman committed
252 253 254
{
  /* The idea here is to implement a horizontal scroll in one line to
     implement delete and half of insert.  */
255
  SMALL_RECT scroll, clip;
Richard M. Stallman's avatar
Richard M. Stallman committed
256 257
  COORD	     dest;
  CHAR_INFO  fill;
258

259 260 261
  clip.Top = scroll.Top = clip.Bottom = scroll.Bottom = cursor_coords.Y;
  clip.Left = 0;
  clip.Right = FRAME_COLS (f);
262

Richard M. Stallman's avatar
Richard M. Stallman committed
263 264 265
  if (direction == LEFT)
    {
      scroll.Left = cursor_coords.X + dist;
266
      scroll.Right = FRAME_COLS (f) - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
267 268 269 270
    }
  else
    {
      scroll.Left = cursor_coords.X;
271
      scroll.Right = FRAME_COLS (f) - dist - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
272
    }
273

Richard M. Stallman's avatar
Richard M. Stallman committed
274 275
  dest.X = cursor_coords.X;
  dest.Y = cursor_coords.Y;
276

Richard M. Stallman's avatar
Richard M. Stallman committed
277
  fill.Char.AsciiChar = 0x20;
278 279
  fill.Attributes = char_attr_normal;

280
  ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
Richard M. Stallman's avatar
Richard M. Stallman committed
281 282 283 284
}


/* If start is zero insert blanks instead of a string at start ?. */
285
static void
286 287
w32con_insert_glyphs (struct frame *f, register struct glyph *start,
		      register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
288
{
289
  scroll_line (f, len, RIGHT);
Richard M. Stallman's avatar
Richard M. Stallman committed
290 291 292 293 294 295

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

297
      w32con_write_glyphs (f, start, len);
Richard M. Stallman's avatar
Richard M. Stallman committed
298 299 300
    }
  else
    {
301
      w32con_clear_end_of_line (f, cursor_coords.X + len);
Richard M. Stallman's avatar
Richard M. Stallman committed
302 303 304
    }
}

305
static void
306 307
w32con_write_glyphs (struct frame *f, register struct glyph *string,
                     register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
308
{
Andrew Innes's avatar
Andrew Innes committed
309
  DWORD r;
310
  WORD char_attr;
311
  LPCSTR conversion_buffer;
312
  struct coding_system *coding;
313 314 315

  if (len <= 0)
    return;
316

317 318 319
  /* 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.  */
320 321
  coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
322 323
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
324
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
Richard M. Stallman's avatar
Richard M. Stallman committed
325

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

332 333 334 335 336
      for (n = 1; n < len; ++n)
	if (string[n].face_id != face_id)
	  break;

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

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

	  /* Write the characters.  */
356
	  if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
357 358 359
					    coding->produced, cursor_coords,
					    &r))
	    {
360
	      printf ("Failed writing console characters: %lu\n",
361 362 363 364 365
		      GetLastError ());
	      fflush (stdout);
	    }

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

373 374 375 376 377 378
/* 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)
{
379
  LPCSTR conversion_buffer;
380 381 382 383 384 385 386 387 388 389 390 391 392 393
  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;

394
  conversion_buffer = (LPCSTR) encode_terminal_code (string, len, coding);
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 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
  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);
    }
}
451

452
static void
453
w32con_delete_glyphs (struct frame *f, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
454
{
455 456
  /* 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
457 458
     come out empty...  */

459
  scroll_line (f, n, LEFT);
Richard M. Stallman's avatar
Richard M. Stallman committed
460 461
}

462

463
static void
464
w32con_reset_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
465
{
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
  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);
484

485
#ifdef USE_SEPARATE_SCREEN
Richard M. Stallman's avatar
Richard M. Stallman committed
486
  SetConsoleActiveScreenBuffer (prev_screen);
487 488 489
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
490

491
  SetConsoleMode (keyboard_handle, prev_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
492 493
}

494
static void
495
w32con_set_terminal_modes (struct terminal *t)
Richard M. Stallman's avatar
Richard M. Stallman committed
496 497 498
{
  CONSOLE_CURSOR_INFO cci;

499
  /* make cursor big and visible (100 on Windows 95 makes it disappear)  */
500 501 502
  cci.dwSize = 99;
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
Richard M. Stallman's avatar
Richard M. Stallman committed
503

504
  SetConsoleActiveScreenBuffer (cur_screen);
Richard M. Stallman's avatar
Richard M. Stallman committed
505

506 507 508 509 510 511 512 513
  /* If Quick Edit is enabled for the console, it will get in the way
     of receiving mouse events, so we disable it.  But leave the
     Insert Mode as it was set by the user.  */
  DWORD new_console_mode
    = ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_EXTENDED_FLAGS;
  if ((prev_console_mode & ENABLE_INSERT_MODE) != 0)
    new_console_mode |= ENABLE_INSERT_MODE;
  SetConsoleMode (keyboard_handle, new_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
514

515 516
  /* Initialize input mode: interrupt_input off, no flow control, allow
     8 bit character input, standard quit char.  */
517
  Fset_input_mode (Qnil, Qnil, make_fixnum (2), Qnil);
Richard M. Stallman's avatar
Richard M. Stallman committed
518 519 520 521
}

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

Richard M. Stallman's avatar
Richard M. Stallman committed
523
   we'll start with not moving the cursor while an update is in progress.  */
524 525
static void
w32con_update_begin (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
526 527 528
{
}

529 530
static void
w32con_update_end (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
531 532 533 534
{
  SetConsoleCursorPosition (cur_screen, cursor_coords);
}

535 536 537 538
/***********************************************************************
			stubs from termcap.c
 ***********************************************************************/

539 540
void sys_tputs (char *, int, int (*) (int));

541
void
542
sys_tputs (char *str, int nlines, int (*outfun) (int))
543 544 545
{
}

546 547
char *sys_tgetstr (char *, char **);

548 549 550 551 552 553 554 555 556 557 558 559 560 561
char *
sys_tgetstr (char *cap, char **area)
{
  return NULL;
}


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

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

562 563
int evalcost (int);

564
int
565
evalcost (int c)
566 567 568 569
{
  return c;
}

570 571
int cmputc (int);

572
int
573
cmputc (int c)
574 575 576 577
{
  return c;
}

578 579
void cmcheckmagic (struct tty_display_info *);

580 581 582 583 584
void
cmcheckmagic (struct tty_display_info *tty)
{
}

585 586
void cmcostinit (struct tty_display_info *);

587 588 589 590 591
void
cmcostinit (struct tty_display_info *tty)
{
}

592 593
void cmgoto (struct tty_display_info *, int, int);

594 595 596 597 598
void
cmgoto (struct tty_display_info *tty, int row, int col)
{
}

599 600
void Wcm_clear (struct tty_display_info *);

601 602 603 604 605 606
void
Wcm_clear (struct tty_display_info *tty)
{
}


607
/* Report the current cursor position.  The following two functions
608 609
   are used in term.c's tty menu code, so they are not really
   "stubs".  */
610
int
611
cursorX (struct tty_display_info *tty)
612 613 614 615 616
{
  return cursor_coords.X;
}

int
617
cursorY (struct tty_display_info *tty)
618 619 620 621
{
  return cursor_coords.Y;
}

622 623 624 625 626 627 628
/***********************************************************************
				Faces
 ***********************************************************************/


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

629
static WORD
630
w32_face_attributes (struct frame *f, int face_id)
631
{
632
  WORD char_attr;
633 634 635 636
  struct face *face = FACE_FROM_ID (f, face_id);

  char_attr = char_attr_normal;

637 638
  /* Reverse the default color if requested. If background and
     foreground are specified, then they have been reversed already.  */
639
  if (face->tty_reverse_p)
640 641
    char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
      + ((char_attr & 0x00f0) >> 4);
642

643
  /* Before the terminal is properly initialized, all colors map to 0.
644
     Don't try to resolve them.  */
645
  if (NILP (Vtty_defined_color_alist))
646
    return char_attr;
647

648 649 650 651 652 653
  /* 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)
654
    char_attr = (char_attr & 0xfff0) + face->foreground;
655

656
  if (face->background >= 0 && face->background < 16)
657
    char_attr = (char_attr & 0xff0f) + (face->background << 4);
658

659
  return char_attr;
660 661
}

Richard M. Stallman's avatar
Richard M. Stallman committed
662
void
663
initialize_w32_display (struct terminal *term, int *width, int *height)
Richard M. Stallman's avatar
Richard M. Stallman committed
664 665
{
  CONSOLE_SCREEN_BUFFER_INFO	info;
666

667
  term->rif = 0; /* No window based redisplay on the console.  */
668
  term->cursor_to_hook		= w32con_move_cursor;
669 670 671
  term->raw_cursor_to_hook	= w32con_move_cursor;
  term->clear_to_end_hook	= w32con_clear_to_end;
  term->clear_frame_hook	= w32con_clear_frame;
672
  term->clear_end_of_line_hook	= w32con_clear_end_of_line;
673 674 675 676
  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;
677
  term->ring_bell_hook		= w32_sys_ring_bell;
678
  term->reset_terminal_modes_hook = w32con_reset_terminal_modes;
679
  term->set_terminal_modes_hook	= w32con_set_terminal_modes;
680
  term->set_terminal_window_hook = NULL;
681
  term->update_begin_hook	= w32con_update_begin;
682 683
  term->update_end_hook		= w32con_update_end;

684
  term->defined_color_hook = &tty_defined_color; /* xfaces.c */
685 686
  term->read_socket_hook = w32_console_read_socket;
  term->mouse_position_hook = w32_console_mouse_position;
687
  term->menu_show_hook = tty_menu_show;
688

689 690 691 692
  /* 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;
693
  term->set_horizontal_scroll_bar_hook = 0;
694 695 696 697
  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;
698

699
  /* Initialize the mouse-highlight data.  */
700
  reset_mouse_highlight (&term->display_info.tty->mouse_highlight);
701

702 703 704
  /* Initialize interrupt_handle.  */
  init_crit ();

705 706 707 708
  /* 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
709
  prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
710

711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
#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

729 730
  /* Respect setting of LINES and COLUMNS environment variables.  */
  {
731 732
    char * lines = getenv ("LINES");
    char * columns = getenv ("COLUMNS");
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762

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

765
  char_attr_normal = info.wAttributes;
766

767 768 769 770 771 772 773 774 775 776 777 778 779
  /* 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)))
    {
780 781
      *height = 25;
      *width = 80;
782 783 784
    }

  else if (w32_use_full_screen_buffer)
785
    {
786 787
      *height = info.dwSize.Y;	/* lines per page */
      *width = info.dwSize.X;	/* characters per line */
788 789 790 791
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
792
      *height = 1 + info.srWindow.Bottom - info.srWindow.Top;
793
      /* Characters per line.  Use buffer coords instead of buffer size.  */
794
      *width = 1 + info.srWindow.Right - info.srWindow.Left;
795
    }
796

797 798 799 800 801 802 803 804 805
  /* Force reinitialization of the "empty row" buffer, in case they
     dumped from a running session.  */
  if (glyphs != glyph_base)
    {
      glyphs = NULL;
      glyphs_len = 0;
      ceol_initialized = FALSE;
    }

806 807 808 809 810
  if (os_subtype == OS_NT)
    w32_console_unicode_input = 1;
  else
    w32_console_unicode_input = 0;

811 812
  /* Setup w32_display_info structure for this frame. */
  w32_initialize_display_info (build_string ("Console"));
813 814 815

  /* Set up the keyboard hook.  */
  setup_w32_kbdhook ();
Richard M. Stallman's avatar
Richard M. Stallman committed
816 817
}

818

Richard M. Stallman's avatar
Richard M. Stallman committed
819
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
820 821 822
       doc: /* Set screen foreground and background colors.

Arguments should be indices between 0 and 15, see w32console.el.  */)
823
  (Lisp_Object foreground, Lisp_Object background)
Richard M. Stallman's avatar
Richard M. Stallman committed
824
{
Tom Tromey's avatar
Tom Tromey committed
825
  char_attr_normal = XFIXNAT (foreground) + (XFIXNAT (background) << 4);
Richard M. Stallman's avatar
Richard M. Stallman committed
826

Eli Zaretskii's avatar
Eli Zaretskii committed
827
  Frecenter (Qnil, Qt);
Richard M. Stallman's avatar
Richard M. Stallman committed
828 829 830
  return Qt;
}

831 832 833 834 835 836 837 838
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)
{
839 840
  return Fcons (make_fixnum (char_attr_normal & 0x000f),
		Fcons (make_fixnum ((char_attr_normal >> 4) & 0x000f), Qnil));
841 842
}

Richard M. Stallman's avatar
Richard M. Stallman committed
843
DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
844
       doc: /* Set cursor size.  */)
845
  (Lisp_Object size)
Richard M. Stallman's avatar
Richard M. Stallman committed
846 847
{
  CONSOLE_CURSOR_INFO cci;
Tom Tromey's avatar
Tom Tromey committed
848
  cci.dwSize = XFIXNAT (size);
Richard M. Stallman's avatar
Richard M. Stallman committed
849 850
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
851

Richard M. Stallman's avatar
Richard M. Stallman committed
852 853 854
  return Qt;
}

Karl Heuer's avatar
Karl Heuer committed
855
void
856
syms_of_ntterm (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
857
{
858
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
859
               w32_use_full_screen_buffer,
860
	       doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
861
This is desirable when running Emacs over telnet.
862
A value of nil means use the current console window dimensions; this
Paul Eggert's avatar
Paul Eggert committed
863
may be preferable when working directly at the console with a large
864
scroll-back buffer.  */);
865
  w32_use_full_screen_buffer = 0;
866

Richard M. Stallman's avatar
Richard M. Stallman committed
867
  defsubr (&Sset_screen_color);
868
  defsubr (&Sget_screen_color);
Richard M. Stallman's avatar
Richard M. Stallman committed
869 870
  defsubr (&Sset_cursor_size);
}