view src/w32console.c @ 59146:9bde7721ad0f

* dispextern.h: Change HAVE_CARBON to MAC_OS. (struct glyph_string): Likewise. * emacs.c (main) [MAC_OS8]: Call mac_term_init instead of mac_initialize. * fileio.c (Fnext_read_file_uses_dialog_p, Fread_file_name): Change TARGET_API_MAC_CARBON to HAVE_CARBON. * fns.c (vector): Change MAC_OSX to MAC_OS. * frame.c (x_set_frame_parameters, x_report_frame_params) (x_set_fullscreen): Remove #ifndef HAVE_CARBON. (x_set_border_width, Vdefault_frame_scroll_bars): Change HAVE_CARBON to MAC_OS. * image.c [MAC_OS]: Include sys/stat.h. [MAC_OS && !MAC_OSX]: Include sys/param.h, ImageCompression.h, and QuickTimeComponents.h. * mac.c [!MAC_OSX] (mac_wait_next_event): Add extern. [!MAC_OSX] (select): Use mac_wait_next_event. [!MAC_OSX] (run_mac_command): Change EXEC_SUFFIXES to Vexec_suffixes. [!MAC_OSX] (select, run_mac_command): Change `#ifdef TARGET_API_MAC_CARBON' to `#if TARGET_API_MAC_CARBON'. (mac_clear_font_name_table): Add extern. (Fmac_clear_font_name_table): New defun. (syms_of_mac): Defsubr it. [MAC_OSX] (SELECT_POLLING_PERIOD_USEC): New define. [MAC_OSX] (select_and_poll_event): New function. [MAC_OSX] (sys_select): Use it. [MAC_OSX && SELECT_USE_CFSOCKET] (socket_callback): New function. [MAC_OSX && SELECT_USE_CFSOCKET] (SELECT_TIMEOUT_THRESHOLD_RUNLOOP, EVENT_CLASS_SOCK): New defines. [MAC_OSX] (sys_select) [SELECT_USE_CFSOCKET]: Use CFSocket and RunLoop for simultaneously monitoring two kinds of inputs, window events and process outputs, without periodically polling. * macfns.c (mac_initialized): Remove extern. (stricmp): Put in #if 0. All callers changed to use xstricmp in xfaces.c. (strnicmp): Decrement `n' at the end of each loop, not the beginning. (check_mac): Use the term "Mac native windows" instead of "Mac OS". (check_x_display_info, x_display_info_for_name): Sync with xfns.c. (mac_get_rdb_resource): New function (from w32reg.c). (x_get_string_resource): Use it. (install_window_handler): Add extern. (mac_window): New function. (Fx_create_frame): Use it instead of make_mac_frame. Set parameter for Qfullscreen. Call x_wm_set_size_hint. (Fx_open_connection, Fx_close_connection): New defuns. (syms_of_macfns): Defsubr them. (x_create_tip_frame) [TARGET_API_MAC_CARBON]: Add kWindowNoUpdatesAttribute to the window attribute. (x_create_tip_frame) [!TARGET_API_MAC_CARBON]: Use NewCWindow. (x_create_tip_frame): Don't call ShowWindow. (Fx_show_tip): Call ShowWindow. (Fx_file_dialog): Change `#ifdef TARGET_API_MAC_CARBON' to `#if TARGET_API_MAC_CARBON'. (mac_frame_parm_handlers): Set handlers for Qfullscreen. (syms_of_macfns) [MAC_OSX]: Initialize mac_in_use to 0. * macgui.h [!MAC_OSX]: Don't include Controls.h. Include Windows.h. (Window): Typedef to WindowPtr and move outside `#if TARGET_API_MAC_CARBON'. (XSizeHints): New struct. * macterm.c (x_update_begin, x_update_end) [TARGET_API_MAC_CARBON]: Disable screen updates during update of a frame. (x_draw_glyph_string_background, x_draw_glyph_string_foreground) [MAC_OS8]: Use XDrawImageString/XDrawImageString16. (construct_mouse_click): Put in #if 0. (x_check_fullscreen, x_check_fullscreen_move): Remove decls. (x_scroll_bar_create, x_scroll_bar_handle_click): Change `#ifdef TARGET_API_MAC_CARBON' to `#if TARGET_API_MAC_CARBON'. (activate_scroll_bars, deactivate_scroll_bars) [!TARGET_API_MAC_CARBON]: Use ActivateControl/DeactivateControl. (x_make_frame_visible) [TARGET_API_MAC_CARBON]: Reposition window if the position is neither user-specified nor program-specified. (x_free_frame_resources): Free size_hints. (x_wm_set_size_hint): Allocate size_hints if needed. Set size_hints. (mac_clear_font_name_table): New function. (mac_do_list_fonts): Initialize font_name_table if needed. (x_list_fonts): Don't initialize font_name_table. Add BLOCK_INPUT around mac_do_list_fonts. (mac_unload_font): New function. (x_load_font): Add BLOCK_INPUT around XLoadQueryFont. (init_mac_drag_n_drop, mac_do_receive_drag): Enclose declarations and definitions with #if TARGET_API_MAC_CARBON. [USE_CARBON_EVENTS] (mac_handle_window_event): Add decl. (install_window_handler): Add decl. (do_window_update): Add BeginUpdate/EndUpdate for the tooltip window. Use UpdateControls. Get the rectangle that should be updated and restrict the target of expose_frame to it. (do_grow_window): Set minimum height/width according to size_hints. (do_grow_window) [TARGET_API_MAC_CARBON]: Use ResizeWindow. (do_zoom_window): Don't use x_set_window_size. [USE_CARBON_EVENTS] (mac_handle_window_event): New function. (install_window_handler): New function. [!USE_CARBON_EVENTS] (mouse_region): New variable. [!USE_CARBON_EVENTS] (mac_wait_next_event): New function. (XTread_socket) [USE_CARBON_EVENTS]: Move call to GetEventDispatcherTarget inside BLOCK_INPUT. (XTread_socket) [!USE_CARBON_EVENTS]: Use mac_wait_next_event. Update mouse_region when mouse is moved. (make_mac_frame): Remove. (make_mac_terminal_frame): Put in #ifdef MAC_OS8. Initialize mouse pointer shapes. Change values of f->left_pos and f->top_pos. Don't use make_mac_frame. Use NewCWindow. Don't call ShowWindow. (mac_initialize_display_info) [MAC_OSX]: Create mac_id_name from Vinvocation_name and Vsystem_name. (mac_make_rdb): New function (from w32term.c). (mac_term_init): Use it. Add BLOCK_INPUT. Error if display has already been opened. Don't pass argument to mac_initialize_display_info. Don't set dpyinfo->height/width. Add entries to x_display_list and x_display_name_list. (x_delete_display): New function. (mac_initialize): Don't call mac_initialize_display_info. (syms_of_macterm) [!MAC_OSX]: Don't call Fprovide. * macterm.h (check_mac): Add extern. (struct mac_output): New member size_hints. (FRAME_SIZE_HINTS): New macro. (mac_unload_font): Add extern. * xdisp.c (expose_window, expose_frame): Remove kludges for Mac. * xfaces.c (clear_font_table) [MAC_OS]: call mac_unload_font.
author Steven Tamm <steventamm@mac.com>
date Mon, 27 Dec 2004 17:27:30 +0000
parents 65309f66a561
children a8fa7c632ee4 f2ebccfa87d4
line wrap: on
line source

/* Terminal hooks for GNU Emacs on the Microsoft W32 API.
   Copyright (C) 1992, 1999 Free Software Foundation, Inc.

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.

   Tim Fleehart (apollo@online.com)		1-17-92
   Geoff Voelker (voelker@cs.washington.edu)	9-12-93
*/


#include <config.h>

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>

#include "lisp.h"
#include "charset.h"
#include "coding.h"
#include "disptab.h"
#include "termhooks.h"
#include "dispextern.h"
/* Disable features in frame.h that require a Window System.  */
#undef HAVE_WINDOW_SYSTEM
#include "frame.h"
#include "w32inevt.h"

/* from window.c */
extern Lisp_Object Frecenter ();

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

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

extern struct frame * updating_frame;
extern int meta_key;

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);
void w32_sys_ring_bell (void);
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);
static WORD w32_face_attributes (struct frame *f, int face_id);

static COORD	cursor_coords;
static HANDLE	prev_screen, cur_screen;
static WORD	char_attr_normal;
static DWORD   prev_console_mode;

#ifndef USE_SEPARATE_SCREEN
static CONSOLE_CURSOR_INFO prev_console_cursor;
#endif

/* 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;
HANDLE  keyboard_handle;


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

BOOL
ctrl_c_handler (unsigned long type)
{
  /* Only ignore "interrupt" events when running interactively.  */
  return (!noninteractive
	  && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
}

/* If we're updating a frame, use it as the current frame
   Otherwise, use the selected frame.  */
#define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())

/* Move the cursor to (row, col).  */
static void
w32con_move_cursor (int row, int col)
{
  cursor_coords.X = col;
  cursor_coords.Y = row;

  if (updating_frame == (struct frame *) NULL)
    {
      SetConsoleCursorPosition (cur_screen, cursor_coords);
    }
}

/* Clear from cursor to end of screen.  */
static void
w32con_clear_to_end (void)
{
  struct frame * f = PICK_FRAME ();

  w32con_clear_end_of_line (FRAME_COLS (f) - 1);
  w32con_ins_del_lines (cursor_coords.Y, FRAME_LINES (f) - cursor_coords.Y - 1);
}

/* Clear the frame.  */
static void
w32con_clear_frame (void)
{
  struct frame *  f = PICK_FRAME ();
  COORD	     dest;
  int        n;
  DWORD      r;
  CONSOLE_SCREEN_BUFFER_INFO info;

  GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);

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

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

  w32con_move_cursor (0, 0);
}


static struct glyph glyph_base[256];
static BOOL  ceol_initialized = FALSE;

/* Clear from Cursor to end (what's "standout marker"?).  */
static void
w32con_clear_end_of_line (int end)
{
  if (!ceol_initialized)
    {
      int i;
      for (i = 0; i < 256; i++)
        {
	  memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
        }
      ceol_initialized = TRUE;
    }
  w32con_write_glyphs (glyph_base, end - cursor_coords.X);	/* fencepost ?	*/
}

/* Insert n lines at vpos. if n is negative delete -n lines.  */
static void
w32con_ins_del_lines (int vpos, int n)
{
  int	     i, nb;
  SMALL_RECT scroll;
  COORD	     dest;
  CHAR_INFO  fill;
  struct frame *  f = PICK_FRAME ();

  if (n < 0)
    {
      scroll.Top = vpos - n;
      scroll.Bottom = FRAME_LINES (f);
      dest.Y = vpos;
    }
  else
    {
      scroll.Top = vpos;
      scroll.Bottom = FRAME_LINES (f) - n;
      dest.Y = vpos + n;
    }
  scroll.Left = 0;
  scroll.Right = FRAME_COLS (f);

  dest.X = 0;

  fill.Char.AsciiChar = 0x20;
  fill.Attributes = char_attr_normal;

  ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);

  /* Here we have to deal with a w32 console flake: If the scroll
     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++)
            {
	      w32con_move_cursor (i, 0);
	      w32con_clear_end_of_line (FRAME_COLS (f));
            }
        }
    }
  else
    {
      nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;

      if (nb < scroll.Top)
        {
	  for (i = nb; i < scroll.Top; i++)
            {
	      w32con_move_cursor (i, 0);
	      w32con_clear_end_of_line (FRAME_COLS (f));
            }
        }
    }

  cursor_coords.X = 0;
  cursor_coords.Y = vpos;
}

#undef	LEFT
#undef	RIGHT
#define	LEFT	1
#define	RIGHT	0

static void
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;
  struct frame *  f = PICK_FRAME ();

  scroll.Top = cursor_coords.Y;
  scroll.Bottom = cursor_coords.Y;

  if (direction == LEFT)
    {
      scroll.Left = cursor_coords.X + dist;
      scroll.Right = FRAME_COLS (f) - 1;
    }
  else
    {
      scroll.Left = cursor_coords.X;
      scroll.Right = FRAME_COLS (f) - dist - 1;
    }

  dest.X = cursor_coords.X;
  dest.Y = cursor_coords.Y;

  fill.Char.AsciiChar = 0x20;
  fill.Attributes = char_attr_normal;

  ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
}


/* If start is zero insert blanks instead of a string at start ?. */
static void
w32con_insert_glyphs (register struct glyph *start, register int len)
{
  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.  */

      w32con_write_glyphs (start, len);
    }
  else
    {
      w32con_clear_end_of_line (cursor_coords.X + len);
    }
}

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

static void
w32con_write_glyphs (register struct glyph *string, register int len)
{
  int produced, consumed;
  DWORD r;
  struct frame * f = PICK_FRAME ();
  WORD char_attr;
  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 = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? &terminal_coding : &safe_terminal_coding);
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;

  while (len > 0)
    {
      /* Identify a run of glyphs with the same face.  */
      int face_id = string->face_id;
      int n;

      for (n = 1; n < len; ++n)
	if (string[n].face_id != face_id)
	  break;

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

      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))
	    {
	      printf ("Failed writing console attributes: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  /* Write the characters.  */
	  if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
					    coding->produced, cursor_coords,
					    &r))
	    {
	      printf ("Failed writing console characters: %d\n",
		      GetLastError ());
	      fflush (stdout);
	    }

	  cursor_coords.X += coding->produced;
	  w32con_move_cursor (cursor_coords.Y, cursor_coords.X);
	}
      len -= n;
      string += n;
    }
}


static void
w32con_delete_glyphs (int n)
{
  /* delete chars means scroll chars from cursor_coords.X + n to
     cursor_coords.X, anything beyond the edge of the screen should
     come out empty...  */

  scroll_line (n, LEFT);
}

static unsigned int sound_type = 0xFFFFFFFF;
#define MB_EMACS_SILENT (0xFFFFFFFF - 1)

void
w32_sys_ring_bell (void)
{
  if (sound_type == 0xFFFFFFFF)
    {
      Beep (666, 100);
    }
  else if (sound_type == MB_EMACS_SILENT)
    {
      /* Do nothing.  */
    }
  else
    MessageBeep (sound_type);
}

DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
       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.  */)
     (sound)
     Lisp_Object sound;
{
  CHECK_SYMBOL (sound);

  if (NILP (sound))
      sound_type = 0xFFFFFFFF;
  else if (EQ (sound, intern ("asterisk")))
      sound_type = MB_ICONASTERISK;
  else if (EQ (sound, intern ("exclamation")))
      sound_type = MB_ICONEXCLAMATION;
  else if (EQ (sound, intern ("hand")))
      sound_type = MB_ICONHAND;
  else if (EQ (sound, intern ("question")))
      sound_type = MB_ICONQUESTION;
  else if (EQ (sound, intern ("ok")))
      sound_type = MB_OK;
  else if (EQ (sound, intern ("silent")))
      sound_type = MB_EMACS_SILENT;
  else
      sound_type = 0xFFFFFFFF;

  return sound;
}

static void
w32con_reset_terminal_modes (void)
{
#ifdef USE_SEPARATE_SCREEN
  SetConsoleActiveScreenBuffer (prev_screen);
#else
  SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
#endif
  SetConsoleMode (keyboard_handle, prev_console_mode);
}

static void
w32con_set_terminal_modes (void)
{
  CONSOLE_CURSOR_INFO cci;

  /* make cursor big and visible (100 on Win95 makes it disappear)  */
  cci.dwSize = 99;
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);

  SetConsoleActiveScreenBuffer (cur_screen);

  SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);

  /* 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);
}

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

   we'll start with not moving the cursor while an update is in progress.  */
static void
w32con_update_begin (struct frame * f)
{
}

static void
w32con_update_end (struct frame * f)
{
  SetConsoleCursorPosition (cur_screen, cursor_coords);
}

static void
w32con_set_terminal_window (int size)
{
}

/***********************************************************************
				Faces
 ***********************************************************************/


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

static WORD
w32_face_attributes (f, face_id)
     struct frame *f;
     int face_id;
{
  WORD char_attr;
  struct face *face = FACE_FROM_ID (f, face_id);

  xassert (face != NULL);

  char_attr = char_attr_normal;

  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)
    char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4);


  /* 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. */
  if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
    char_attr ^= 0x0007;

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

  return char_attr;
}


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

extern char unspecified_fg[], unspecified_bg[];


/* Given a color index, return its standard name.  */
Lisp_Object
vga_stdcolor_name (int idx)
{
  /* 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 */
}

typedef int (*term_hook) ();

void
initialize_w32_display (void)
{
  CONSOLE_SCREEN_BUFFER_INFO	info;

  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;
  ring_bell_hook		= w32_sys_ring_bell;
  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;

  read_socket_hook = w32_console_read_socket;
  mouse_position_hook = w32_console_mouse_position;

  /* Initialize interrupt_handle.  */
  init_crit ();

  /* Remember original console settings.  */
  keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
  GetConsoleMode (keyboard_handle, &prev_console_mode);

  prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);

#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

  /* 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);
      }
  }

  GetConsoleScreenBufferInfo (cur_screen, &info);

  meta_key = 1;
  char_attr_normal = info.wAttributes;

  if (w32_use_full_screen_buffer)
    {
      FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;	/* lines per page */
      SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
    }
  else
    {
      /* Lines per page.  Use buffer coords instead of buffer size.  */
      FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
	info.srWindow.Top;
      /* Characters per line.  Use buffer coords instead of buffer size.  */
      SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
		       info.srWindow.Left);
    }

  /* Setup w32_display_info structure for this frame. */

  w32_initialize_display_info (build_string ("Console"));

}

DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
       doc: /* Set screen colors.  */)
    (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,
       doc: /* Set cursor size.  */)
    (size)
    Lisp_Object size;
{
  CONSOLE_CURSOR_INFO cci;
  cci.dwSize = XFASTINT (size);
  cci.bVisible = TRUE;
  (void) SetConsoleCursorInfo (cur_screen, &cci);

  return Qt;
}

void
syms_of_ntterm ()
{
  DEFVAR_BOOL ("w32-use-full-screen-buffer",
               &w32_use_full_screen_buffer,
	       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.  */);
  w32_use_full_screen_buffer = 1;

  defsubr (&Sset_screen_color);
  defsubr (&Sset_cursor_size);
  defsubr (&Sset_message_beep);
}

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