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

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Richard M. Stallman's avatar
Richard M. Stallman committed
20 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>
Richard M. Stallman's avatar
Richard M. Stallman committed
32 33

#include "lisp.h"
34
#include "character.h"
35
#include "coding.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
36 37
#include "disptab.h"
#include "termhooks.h"
38 39
#include "dispextern.h"
/* Disable features in frame.h that require a Window System.  */
40 41
#undef HAVE_WINDOW_SYSTEM
#include "frame.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 */
Richard M. Stallman's avatar
Richard M. Stallman committed
45 46 47 48 49 50 51 52
extern Lisp_Object Frecenter ();

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

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

53
extern struct frame * updating_frame;
Richard M. Stallman's avatar
Richard M. Stallman committed
54 55
extern int meta_key;

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

72 73 74 75
static COORD	cursor_coords;
static HANDLE	prev_screen, cur_screen;
static WORD	char_attr_normal;
static DWORD   prev_console_mode;
Richard M. Stallman's avatar
Richard M. Stallman committed
76

77
#ifndef USE_SEPARATE_SCREEN
78
static CONSOLE_CURSOR_INFO prev_console_cursor;
79 80
#endif

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

Richard M. Stallman's avatar
Richard M. Stallman committed
88 89

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

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

/* If we're updating a frame, use it as the current frame
   Otherwise, use the selected frame.  */
103
#define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())
Richard M. Stallman's avatar
Richard M. Stallman committed
104 105

/* Move the cursor to (row, col).  */
Jason Rumney's avatar
Jason Rumney committed
106
static void
107
w32con_move_cursor (int row, int col)
Richard M. Stallman's avatar
Richard M. Stallman committed
108 109 110
{
  cursor_coords.X = col;
  cursor_coords.Y = row;
111

112
  if (updating_frame == (struct frame *) NULL)
Richard M. Stallman's avatar
Richard M. Stallman committed
113 114 115 116 117 118
    {
      SetConsoleCursorPosition (cur_screen, cursor_coords);
    }
}

/* Clear from cursor to end of screen.  */
Jason Rumney's avatar
Jason Rumney committed
119
static void
120
w32con_clear_to_end (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
121
{
122
  struct frame * f = PICK_FRAME ();
123

124 125
  w32con_clear_end_of_line (FRAME_COLS (f) - 1);
  w32con_ins_del_lines (cursor_coords.Y, FRAME_LINES (f) - cursor_coords.Y - 1);
Richard M. Stallman's avatar
Richard M. Stallman committed
126 127 128
}

/* Clear the frame.  */
129 130
static void
w32con_clear_frame (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
131
{
132
  struct frame *  f = PICK_FRAME ();
133
  COORD	     dest;
Andrew Innes's avatar
Andrew Innes committed
134 135
  int        n;
  DWORD      r;
136 137 138
  CONSOLE_SCREEN_BUFFER_INFO info;

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

140
  /* Remember that the screen buffer might be wider than the window.  */
141
  n = FRAME_LINES (f) * info.dwSize.X;
142 143
  dest.X = dest.Y = 0;

144
  FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
145 146
  FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);

147
  w32con_move_cursor (0, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
148 149 150
}


151
static struct glyph glyph_base[256];
Richard M. Stallman's avatar
Richard M. Stallman committed
152 153 154
static BOOL  ceol_initialized = FALSE;

/* Clear from Cursor to end (what's "standout marker"?).  */
155 156
static void
w32con_clear_end_of_line (int end)
Richard M. Stallman's avatar
Richard M. Stallman committed
157 158 159 160 161 162
{
  if (!ceol_initialized)
    {
      int i;
      for (i = 0; i < 256; i++)
        {
163
	  memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
Richard M. Stallman's avatar
Richard M. Stallman committed
164 165 166
        }
      ceol_initialized = TRUE;
    }
167
  w32con_write_glyphs (glyph_base, end - cursor_coords.X);	/* fencepost ?	*/
Richard M. Stallman's avatar
Richard M. Stallman committed
168 169 170
}

/* Insert n lines at vpos. if n is negative delete -n lines.  */
171 172
static void
w32con_ins_del_lines (int vpos, int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
173
{
174
  int	     i, nb;
Richard M. Stallman's avatar
Richard M. Stallman committed
175 176 177
  SMALL_RECT scroll;
  COORD	     dest;
  CHAR_INFO  fill;
178
  struct frame *  f = PICK_FRAME ();
Richard M. Stallman's avatar
Richard M. Stallman committed
179 180 181 182

  if (n < 0)
    {
      scroll.Top = vpos - n;
183
      scroll.Bottom = FRAME_LINES (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
184 185 186 187 188
      dest.Y = vpos;
    }
  else
    {
      scroll.Top = vpos;
189
      scroll.Bottom = FRAME_LINES (f) - n;
Richard M. Stallman's avatar
Richard M. Stallman committed
190 191 192
      dest.Y = vpos + n;
    }
  scroll.Left = 0;
193
  scroll.Right = FRAME_COLS (f);
194

Richard M. Stallman's avatar
Richard M. Stallman committed
195
  dest.X = 0;
196

Richard M. Stallman's avatar
Richard M. Stallman committed
197
  fill.Char.AsciiChar = 0x20;
198
  fill.Attributes = char_attr_normal;
199

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

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

      if (nb < scroll.Top)
225
        {
Richard M. Stallman's avatar
Richard M. Stallman committed
226 227
	  for (i = nb; i < scroll.Top; i++)
            {
228 229
	      w32con_move_cursor (i, 0);
	      w32con_clear_end_of_line (FRAME_COLS (f));
Richard M. Stallman's avatar
Richard M. Stallman committed
230 231 232
            }
        }
    }
233

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

Richard M. Stallman's avatar
Richard M. Stallman committed
253 254
  scroll.Top = cursor_coords.Y;
  scroll.Bottom = cursor_coords.Y;
255

Richard M. Stallman's avatar
Richard M. Stallman committed
256 257 258
  if (direction == LEFT)
    {
      scroll.Left = cursor_coords.X + dist;
259
      scroll.Right = FRAME_COLS (f) - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
260 261 262 263
    }
  else
    {
      scroll.Left = cursor_coords.X;
264
      scroll.Right = FRAME_COLS (f) - dist - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
265
    }
266

Richard M. Stallman's avatar
Richard M. Stallman committed
267 268
  dest.X = cursor_coords.X;
  dest.Y = cursor_coords.Y;
269

Richard M. Stallman's avatar
Richard M. Stallman committed
270
  fill.Char.AsciiChar = 0x20;
271 272
  fill.Attributes = char_attr_normal;

Richard M. Stallman's avatar
Richard M. Stallman committed
273 274 275 276 277
  ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
}


/* If start is zero insert blanks instead of a string at start ?. */
278 279
static void
w32con_insert_glyphs (register struct glyph *start, register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
280 281 282 283 284 285 286 287
{
  scroll_line (len, RIGHT);

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

289
      w32con_write_glyphs (start, len);
Richard M. Stallman's avatar
Richard M. Stallman committed
290 291 292
    }
  else
    {
293
      w32con_clear_end_of_line (cursor_coords.X + len);
Richard M. Stallman's avatar
Richard M. Stallman committed
294 295 296
    }
}

297 298
extern unsigned char *terminal_encode_buffer;

299
extern unsigned char *encode_terminal_code P_ ((struct glyph *, int, 
300
						struct coding_system *));
301

302 303
static void
w32con_write_glyphs (register struct glyph *string, register int len)
Richard M. Stallman's avatar
Richard M. Stallman committed
304
{
Andrew Innes's avatar
Andrew Innes committed
305 306
  int produced, consumed;
  DWORD r;
307
  struct frame * f = PICK_FRAME ();
308 309 310 311
  WORD char_attr;

  if (len <= 0)
    return;
312

313 314 315
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
Richard M. Stallman's avatar
Richard M. Stallman committed
316

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

323 324 325 326 327
      for (n = 1; n < len; ++n)
	if (string[n].face_id != face_id)
	  break;

      /* Turn appearance modes of the face of the run on.  */
328
      char_attr = w32_face_attributes (f, face_id);
329 330 331

      while (n > 0)
        {
332 333
	  produced = encode_terminal_code (string,
					   n,
334 335 336 337 338
					   &consumed);
	  if (produced > 0)
	    {
              /* Set the attribute for these characters.  */
              if (!FillConsoleOutputAttribute (cur_screen, char_attr,
339
                                               produced, cursor_coords, &r))
340 341 342 343 344 345 346
                {
                  printf ("Failed writing console attributes: %d\n",
                          GetLastError ());
                  fflush (stdout);
                }

              /* Write the characters.  */
347
              if (!WriteConsoleOutputCharacter (cur_screen, terminal_encode_buffer,
Andrew Innes's avatar
Andrew Innes committed
348
                                                produced, cursor_coords, &r))
349 350 351 352 353 354 355
                {
                  printf ("Failed writing console characters: %d\n",
                          GetLastError ());
                  fflush (stdout);
                }

              cursor_coords.X += produced;
356
              w32con_move_cursor (cursor_coords.Y, cursor_coords.X);
357
            }
358 359 360 361
          len -= consumed;
          n -= consumed;
          string += consumed;
        }
Richard M. Stallman's avatar
Richard M. Stallman committed
362 363
    }

364 365
  /* We may have to output some codes to terminate the writing.  */
  if (CODING_REQUIRE_FLUSHING (&terminal_coding))
Richard M. Stallman's avatar
Richard M. Stallman committed
366
    {
367 368 369
      Lisp_Object blank_string = build_string ("");
      int conversion_buffer_size = 1024;

370
      terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
371 372 373
      terminal_coding.destination = (unsigned char *) xmalloc (conversion_buffer_size);
      encode_coding_object (&terminal_coding, blank_string, 0, 0,
			    0, conversion_buffer_size, Qnil);
374 375
      if (terminal_coding.produced > 0)
        {
376
          if (!FillConsoleOutputAttribute (cur_screen, char_attr_normal,
377
                                           terminal_coding.produced,
378
                                           cursor_coords, &r))
379 380 381 382 383 384 385
            {
              printf ("Failed writing console attributes: %d\n",
                      GetLastError ());
              fflush (stdout);
            }

          /* Write the characters.  */
386
          if (!WriteConsoleOutputCharacter (cur_screen, terminal_coding.destination,
Andrew Innes's avatar
Andrew Innes committed
387
                                            produced, cursor_coords, &r))
388 389 390 391 392 393
            {
              printf ("Failed writing console characters: %d\n",
                      GetLastError ());
              fflush (stdout);
            }
        }
394
      xfree (terminal_coding.destination);
Richard M. Stallman's avatar
Richard M. Stallman committed
395 396 397
    }
}

398

399 400
static void
w32con_delete_glyphs (int n)
Richard M. Stallman's avatar
Richard M. Stallman committed
401
{
402 403
  /* 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
404 405 406 407 408
     come out empty...  */

  scroll_line (n, LEFT);
}

Karl Heuer's avatar
Karl Heuer committed
409
static unsigned int sound_type = 0xFFFFFFFF;
410
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
Karl Heuer's avatar
Karl Heuer committed
411

Richard M. Stallman's avatar
Richard M. Stallman committed
412
void
413
w32_sys_ring_bell (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
414
{
415
  if (sound_type == 0xFFFFFFFF)
416
    {
Karl Heuer's avatar
Karl Heuer committed
417
      Beep (666, 100);
418 419 420 421 422
    }
  else if (sound_type == MB_EMACS_SILENT)
    {
      /* Do nothing.  */
    }
Karl Heuer's avatar
Karl Heuer committed
423
  else
424
    MessageBeep (sound_type);
Richard M. Stallman's avatar
Richard M. Stallman committed
425 426
}

Karl Heuer's avatar
Karl Heuer committed
427
DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
428 429 430 431 432
       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
433 434
     (sound)
     Lisp_Object sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
435
{
436
  CHECK_SYMBOL (sound);
Karl Heuer's avatar
Karl Heuer committed
437

438
  if (NILP (sound))
Karl Heuer's avatar
Karl Heuer committed
439 440 441
      sound_type = 0xFFFFFFFF;
  else if (EQ (sound, intern ("asterisk")))
      sound_type = MB_ICONASTERISK;
442
  else if (EQ (sound, intern ("exclamation")))
Karl Heuer's avatar
Karl Heuer committed
443
      sound_type = MB_ICONEXCLAMATION;
444
  else if (EQ (sound, intern ("hand")))
Karl Heuer's avatar
Karl Heuer committed
445
      sound_type = MB_ICONHAND;
446
  else if (EQ (sound, intern ("question")))
Karl Heuer's avatar
Karl Heuer committed
447
      sound_type = MB_ICONQUESTION;
448
  else if (EQ (sound, intern ("ok")))
Karl Heuer's avatar
Karl Heuer committed
449
      sound_type = MB_OK;
450 451
  else if (EQ (sound, intern ("silent")))
      sound_type = MB_EMACS_SILENT;
Karl Heuer's avatar
Karl Heuer committed
452 453 454 455
  else
      sound_type = 0xFFFFFFFF;

  return sound;
Richard M. Stallman's avatar
Richard M. Stallman committed
456
}
457

458 459
static void
w32con_reset_terminal_modes (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
460
{
461
#ifdef USE_SEPARATE_SCREEN
Richard M. Stallman's avatar
Richard M. Stallman committed
462
  SetConsoleActiveScreenBuffer (prev_screen);
463 464 465 466
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
  SetConsoleMode (keyboard_handle, prev_console_mode);
Richard M. Stallman's avatar
Richard M. Stallman committed
467 468
}

469 470
static void
w32con_set_terminal_modes (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
471 472 473
{
  CONSOLE_CURSOR_INFO cci;

474 475 476 477
  /* 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
478

479
  SetConsoleActiveScreenBuffer (cur_screen);
Richard M. Stallman's avatar
Richard M. Stallman committed
480

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

483 484 485
  /* 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
486 487 488 489
}

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

Richard M. Stallman's avatar
Richard M. Stallman committed
491
   we'll start with not moving the cursor while an update is in progress.  */
492 493
static void
w32con_update_begin (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
494 495 496
{
}

497 498
static void
w32con_update_end (struct frame * f)
Richard M. Stallman's avatar
Richard M. Stallman committed
499 500 501 502
{
  SetConsoleCursorPosition (cur_screen, cursor_coords);
}

503 504
static void
w32con_set_terminal_window (int size)
Richard M. Stallman's avatar
Richard M. Stallman committed
505 506 507
{
}

508 509 510 511 512 513 514
/***********************************************************************
				Faces
 ***********************************************************************/


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

515 516
static WORD
w32_face_attributes (f, face_id)
517 518 519
     struct frame *f;
     int face_id;
{
520
  WORD char_attr;
521 522 523 524 525 526
  struct face *face = FACE_FROM_ID (f, face_id);

  xassert (face != NULL);

  char_attr = char_attr_normal;

527 528 529 530 531 532
  if (face->foreground != FACE_TTY_DEFAULT_FG_COLOR
      && face->foreground != FACE_TTY_DEFAULT_COLOR)
    char_attr = (char_attr & 0xfff0) + (face->foreground % 16);

  if (face->background != FACE_TTY_DEFAULT_BG_COLOR
      && face->background != FACE_TTY_DEFAULT_COLOR)
533
    char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4);
534

535

536 537 538
  /* NTEMACS_TODO: Faces defined during startup get both foreground
     and background of 0. Need a better way around this - for now detect
     the problem and invert one of the faces to make the text readable. */
539 540
  if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
    char_attr ^= 0x0007;
541

542
  if (face->tty_reverse_p)
543 544
    char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
      + ((char_attr & 0x00f0) >> 4);
545

546
  return char_attr;
547 548 549
}


550
/* Emulation of some X window features from xfns.c and xfaces.c.  */
551

552 553 554 555 556 557
extern char unspecified_fg[], unspecified_bg[];


/* Given a color index, return its standard name.  */
Lisp_Object
vga_stdcolor_name (int idx)
558
{
559 560 561 562 563 564 565 566 567 568 569 570 571 572
  /* 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 */
573
}
574

Richard M. Stallman's avatar
Richard M. Stallman committed
575 576 577
typedef int (*term_hook) ();

void
578
initialize_w32_display (void)
Richard M. Stallman's avatar
Richard M. Stallman committed
579 580
{
  CONSOLE_SCREEN_BUFFER_INFO	info;
581

582 583 584 585 586 587 588 589 590
  cursor_to_hook		= w32con_move_cursor;
  raw_cursor_to_hook		= w32con_move_cursor;
  clear_to_end_hook		= w32con_clear_to_end;
  clear_frame_hook		= w32con_clear_frame;
  clear_end_of_line_hook	= w32con_clear_end_of_line;
  ins_del_lines_hook		= w32con_ins_del_lines;
  insert_glyphs_hook		= w32con_insert_glyphs;
  write_glyphs_hook		= w32con_write_glyphs;
  delete_glyphs_hook		= w32con_delete_glyphs;
591
  ring_bell_hook		= w32_sys_ring_bell;
592 593 594 595 596
  reset_terminal_modes_hook	= w32con_reset_terminal_modes;
  set_terminal_modes_hook	= w32con_set_terminal_modes;
  set_terminal_window_hook	= w32con_set_terminal_window;
  update_begin_hook		= w32con_update_begin;
  update_end_hook		= w32con_update_end;
597

598
  read_socket_hook = w32_console_read_socket;
599
  mouse_position_hook = w32_console_mouse_position;
600

601 602 603
  /* Initialize interrupt_handle.  */
  init_crit ();

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

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

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

    if (lines != NULL && columns != NULL)
      {
	SMALL_RECT new_win_dims;
	COORD new_size;

	new_size.X = atoi (columns);
	new_size.Y = atoi (lines);

	GetConsoleScreenBufferInfo (cur_screen, &info);

	/* Shrink the window first, so the buffer dimensions can be
           reduced if necessary.  */
	new_win_dims.Top = 0;
	new_win_dims.Left = 0;
	new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1;
	new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1;
	SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);

	SetConsoleScreenBufferSize (cur_screen, new_size);

	/* Set the window size to match the buffer dimension.  */
	new_win_dims.Top = 0;
	new_win_dims.Left = 0;
	new_win_dims.Bottom = new_size.Y - 1;
	new_win_dims.Right = new_size.X - 1;
	SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
      }
  }

Richard M. Stallman's avatar
Richard M. Stallman committed
662
  GetConsoleScreenBufferInfo (cur_screen, &info);
663

Richard M. Stallman's avatar
Richard M. Stallman committed
664
  meta_key = 1;
665
  char_attr_normal = info.wAttributes;
666

667 668
  if (w32_use_full_screen_buffer)
    {
669 670
      FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;	/* lines per page */
      SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
671 672 673 674
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
675
      FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
676
	info.srWindow.Top;
677
      /* Characters per line.  Use buffer coords instead of buffer size.  */
678
      SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
679 680
		       info.srWindow.Left);
    }
681 682 683 684 685

  /* Setup w32_display_info structure for this frame. */

  w32_initialize_display_info (build_string ("Console"));

Richard M. Stallman's avatar
Richard M. Stallman committed
686 687 688
}

DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
689
       doc: /* Set screen colors.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
690 691 692 693 694 695 696 697 698 699 700
    (foreground, background)
    Lisp_Object foreground;
    Lisp_Object background;
{
  char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);

  Frecenter (Qnil);
  return Qt;
}

DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
701
       doc: /* Set cursor size.  */)
Richard M. Stallman's avatar
Richard M. Stallman committed
702 703 704 705 706 707 708
    (size)
    Lisp_Object size;
{
  CONSOLE_CURSOR_INFO cci;
  cci.dwSize = XFASTINT (size);
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);
709

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

Karl Heuer's avatar
Karl Heuer committed
713
void
Richard M. Stallman's avatar
Richard M. Stallman committed
714 715
syms_of_ntterm ()
{
716 717
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
               &w32_use_full_screen_buffer,
718 719 720 721 722
	       doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
This is desirable when running Emacs over telnet, and is the default.
A value of nil means use the current console window dimensions; this
may be preferrable when working directly at the console with a large
scroll-back buffer.  */);
723 724
  w32_use_full_screen_buffer = 1;

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

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