1 /* Terminal hooks for GNU Emacs on the Microsoft W32 API.
  2    Copyright (C) 1992, 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
  3                  2008, 2009, 2010  Free Software Foundation, Inc.
  4 
  5 This file is part of GNU Emacs.
  6 
  7 GNU Emacs is free software: you can redistribute it and/or modify
  8 it under the terms of the GNU General Public License as published by
  9 the Free Software Foundation, either version 3 of the License, or
 10 (at your option) any later version.
 11 
 12 GNU Emacs is distributed in the hope that it will be useful,
 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 GNU General Public License for more details.
 16 
 17 You should have received a copy of the GNU General Public License
 18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 19 
 20 /*
 21    Tim Fleehart (apollo@online.com)             1-17-92
 22    Geoff Voelker (voelker@cs.washington.edu)    9-12-93
 23 */
 24 
 25 
 26 #include <config.h>
 27 
 28 #include <stdlib.h>
 29 #include <stdio.h>
 30 #include <windows.h>
 31 #include <string.h>
 32 #include <setjmp.h>
 33 
 34 #include "lisp.h"
 35 #include "character.h"
 36 #include "coding.h"
 37 #include "disptab.h"
 38 #include "frame.h"
 39 #include "termhooks.h"
 40 #include "termchar.h"
 41 #include "dispextern.h"
 42 #include "w32inevt.h"
 43 
 44 /* from window.c */
 45 extern Lisp_Object Frecenter ();
 46 
 47 /* from keyboard.c */
 48 extern int detect_input_pending ();
 49 
 50 /* from sysdep.c */
 51 extern int read_input_pending ();
 52 
 53 static void w32con_move_cursor (struct frame *f, int row, int col);
 54 static void w32con_clear_to_end (struct frame *f);
 55 static void w32con_clear_frame (struct frame *f);
 56 static void w32con_clear_end_of_line (struct frame *f, int);
 57 static void w32con_ins_del_lines (struct frame *f, int vpos, int n);
 58 static void w32con_insert_glyphs (struct frame *f, struct glyph *start, int len);
 59 static void w32con_write_glyphs (struct frame *f, struct glyph *string, int len);
 60 static void w32con_delete_glyphs (struct frame *f, int n);
 61 static void w32con_reset_terminal_modes (struct terminal *t);
 62 static void w32con_set_terminal_modes (struct terminal *t);
 63 static void w32con_set_terminal_window (struct frame *f, int size);
 64 static void w32con_update_begin (struct frame * f);
 65 static void w32con_update_end (struct frame * f);
 66 static WORD w32_face_attributes (struct frame *f, int face_id);
 67 
 68 static COORD    cursor_coords;
 69 static HANDLE   prev_screen, cur_screen;
 70 static WORD     char_attr_normal;
 71 static DWORD   prev_console_mode;
 72 
 73 #ifndef USE_SEPARATE_SCREEN
 74 static CONSOLE_CURSOR_INFO prev_console_cursor;
 75 #endif
 76 
 77 extern Lisp_Object Vtty_defined_color_alist;
 78 
 79 /* Determine whether to make frame dimensions match the screen buffer,
 80    or the current window size.  The former is desirable when running
 81    over telnet, while the latter is more useful when working directly at
 82    the console with a large scroll-back buffer.  */
 83 int w32_use_full_screen_buffer;
 84 HANDLE  keyboard_handle;
 85 
 86 
 87 /* Setting this as the ctrl handler prevents emacs from being killed when
 88    someone hits ^C in a 'suspended' session (child shell).
 89    Also ignore Ctrl-Break signals.  */
 90 
 91 BOOL
 92 ctrl_c_handler (unsigned long type)
 93 {
 94   /* Only ignore "interrupt" events when running interactively.  */
 95   return (!noninteractive
 96           && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
 97 }
 98 
 99 
100 /* Move the cursor to (ROW, COL) on FRAME.  */
101 static void
102 w32con_move_cursor (struct frame *f, int row, int col)
103 {
104   cursor_coords.X = col;
105   cursor_coords.Y = row;
106 
107   /* TODO: for multi-tty support, cur_screen should be replaced with a
108      reference to the terminal for this frame.  */
109   SetConsoleCursorPosition (cur_screen, cursor_coords);
110 }
111 
112 /* Clear from cursor to end of screen.  */
113 static void
114 w32con_clear_to_end (struct frame *f)
115 {
116   w32con_clear_end_of_line (f, FRAME_COLS (f) - 1);
117   w32con_ins_del_lines (f, cursor_coords.Y, FRAME_LINES (f) - cursor_coords.Y - 1);
118 }
119 
120 /* Clear the frame.  */
121 static void
122 w32con_clear_frame (struct frame *f)
123 {
124   COORD      dest;
125   int        n;
126   DWORD      r;
127   CONSOLE_SCREEN_BUFFER_INFO info;
128 
129   GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
130 
131   /* Remember that the screen buffer might be wider than the window.  */
132   n = FRAME_LINES (f) * info.dwSize.X;
133   dest.X = dest.Y = 0;
134 
135   FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
136   FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
137 
138   w32con_move_cursor (f, 0, 0);
139 }
140 
141 
142 static struct glyph glyph_base[256];
143 static BOOL  ceol_initialized = FALSE;
144 
145 /* Clear from Cursor to end (what's "standout marker"?).  */
146 static void
147 w32con_clear_end_of_line (struct frame *f, int end)
148 {
149   if (!ceol_initialized)
150     {
151       int i;
152       for (i = 0; i < 256; i++)
153         {
154           memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
155         }
156       ceol_initialized = TRUE;
157     }
158   w32con_write_glyphs (f, glyph_base, end - cursor_coords.X);   /* fencepost ?  */
159 }
160 
161 /* Insert n lines at vpos. if n is negative delete -n lines.  */
162 static void
163 w32con_ins_del_lines (struct frame *f, int vpos, int n)
164 {
165   int        i, nb;
166   SMALL_RECT scroll;
167   SMALL_RECT clip;
168   COORD      dest;
169   CHAR_INFO  fill;
170 
171   if (n < 0)
172     {
173       scroll.Top = vpos - n;
174       scroll.Bottom = FRAME_LINES (f);
175       dest.Y = vpos;
176     }
177   else
178     {
179       scroll.Top = vpos;
180       scroll.Bottom = FRAME_LINES (f) - n;
181       dest.Y = vpos + n;
182     }
183   clip.Top = clip.Left = scroll.Left = 0;
184   clip.Right = scroll.Right = FRAME_COLS (f);
185   clip.Bottom = FRAME_LINES (f);
186 
187   dest.X = 0;
188 
189   fill.Char.AsciiChar = 0x20;
190   fill.Attributes = char_attr_normal;
191 
192   ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
193 
194   /* Here we have to deal with a w32 console flake: If the scroll
195      region looks like abc and we scroll c to a and fill with d we get
196      cbd... if we scroll block c one line at a time to a, we get cdd...
197      Emacs expects cdd consistently... So we have to deal with that
198      here... (this also occurs scrolling the same way in the other
199      direction.  */
200 
201   if (n > 0)
202     {
203       if (scroll.Bottom < dest.Y)
204         {
205           for (i = scroll.Bottom; i < dest.Y; i++)
206             {
207               w32con_move_cursor (f, i, 0);
208               w32con_clear_end_of_line (f, FRAME_COLS (f));
209             }
210         }
211     }
212   else
213     {
214       nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
215 
216       if (nb < scroll.Top)
217         {
218           for (i = nb; i < scroll.Top; i++)
219             {
220               w32con_move_cursor (f, i, 0);
221               w32con_clear_end_of_line (f, FRAME_COLS (f));
222             }
223         }
224     }
225 
226   cursor_coords.X = 0;
227   cursor_coords.Y = vpos;
228 }
229 
230 #undef  LEFT
231 #undef  RIGHT
232 #define LEFT    1
233 #define RIGHT   0
234 
235 static void
236 scroll_line (struct frame *f, int dist, int direction)
237 {
238   /* The idea here is to implement a horizontal scroll in one line to
239      implement delete and half of insert.  */
240   SMALL_RECT scroll, clip;
241   COORD      dest;
242   CHAR_INFO  fill;
243 
244   clip.Top = scroll.Top = clip.Bottom = scroll.Bottom = cursor_coords.Y;
245   clip.Left = 0;
246   clip.Right = FRAME_COLS (f);
247 
248   if (direction == LEFT)
249     {
250       scroll.Left = cursor_coords.X + dist;
251       scroll.Right = FRAME_COLS (f) - 1;
252     }
253   else
254     {
255       scroll.Left = cursor_coords.X;
256       scroll.Right = FRAME_COLS (f) - dist - 1;
257     }
258 
259   dest.X = cursor_coords.X;
260   dest.Y = cursor_coords.Y;
261 
262   fill.Char.AsciiChar = 0x20;
263   fill.Attributes = char_attr_normal;
264 
265   ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
266 }
267 
268 
269 /* If start is zero insert blanks instead of a string at start ?. */
270 static void
271 w32con_insert_glyphs (struct frame *f, register struct glyph *start, register int len)
272 {
273   scroll_line (f, len, RIGHT);
274 
275   /* Move len chars to the right starting at cursor_coords, fill with blanks */
276   if (start)
277     {
278       /* Print the first len characters of start, cursor_coords.X adjusted
279          by write_glyphs.  */
280 
281       w32con_write_glyphs (f, start, len);
282     }
283   else
284     {
285       w32con_clear_end_of_line (f, cursor_coords.X + len);
286     }
287 }
288 
289 extern unsigned char *encode_terminal_code P_ ((struct glyph *, int, 
290                                                 struct coding_system *));
291 
292 static void
293 w32con_write_glyphs (struct frame *f, register struct glyph *string,
294                      register int len)
295 {
296   DWORD r;
297   WORD char_attr;
298   unsigned char *conversion_buffer;
299   struct coding_system *coding;
300 
301   if (len <= 0)
302     return;
303 
304   /* If terminal_coding does any conversion, use it, otherwise use
305      safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
306      because it always return 1 if the member src_multibyte is 1.  */
307   coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
308             ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
309   /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
310      the tail.  */
311   coding->mode &= ~CODING_MODE_LAST_BLOCK;
312 
313   while (len > 0)
314     {
315       /* Identify a run of glyphs with the same face.  */
316       int face_id = string->face_id;
317       int n;
318 
319       for (n = 1; n < len; ++n)
320         if (string[n].face_id != face_id)
321           break;
322 
323       /* Turn appearance modes of the face of the run on.  */
324       char_attr = w32_face_attributes (f, face_id);
325 
326       if (n == len)
327         /* This is the last run.  */
328         coding->mode |= CODING_MODE_LAST_BLOCK;
329       conversion_buffer = encode_terminal_code (string, n, coding);
330       if (coding->produced > 0)
331         {
332           /* Set the attribute for these characters.  */
333           if (!FillConsoleOutputAttribute (cur_screen, char_attr,
334                                            coding->produced, cursor_coords,
335                                            &r))
336             {
337               printf ("Failed writing console attributes: %d\n",
338                       GetLastError ());
339               fflush (stdout);
340             }
341 
342           /* Write the characters.  */
343           if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
344                                             coding->produced, cursor_coords,
345                                             &r))
346             {
347               printf ("Failed writing console characters: %d\n",
348                       GetLastError ());
349               fflush (stdout);
350             }
351 
352           cursor_coords.X += coding->produced;
353           w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X);
354         }
355       len -= n;
356       string += n;
357     }
358 }
359 
360 
361 static void
362 w32con_delete_glyphs (struct frame *f, int n)
363 {
364   /* delete chars means scroll chars from cursor_coords.X + n to
365      cursor_coords.X, anything beyond the edge of the screen should
366      come out empty...  */
367 
368   scroll_line (f, n, LEFT);
369 }
370 
371 static unsigned int sound_type = 0xFFFFFFFF;
372 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
373 
374 void
375 w32_sys_ring_bell (struct frame *f)
376 {
377   if (sound_type == 0xFFFFFFFF)
378     {
379       Beep (666, 100);
380     }
381   else if (sound_type == MB_EMACS_SILENT)
382     {
383       /* Do nothing.  */
384     }
385   else
386     MessageBeep (sound_type);
387 }
388 
389 DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
390        doc: /* Set the sound generated when the bell is rung.
391 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
392 to use the corresponding system sound for the bell.  The 'silent sound
393 prevents Emacs from making any sound at all.
394 SOUND is nil to use the normal beep.  */)
395      (sound)
396      Lisp_Object sound;
397 {
398   CHECK_SYMBOL (sound);
399 
400   if (NILP (sound))
401       sound_type = 0xFFFFFFFF;
402   else if (EQ (sound, intern ("asterisk")))
403       sound_type = MB_ICONASTERISK;
404   else if (EQ (sound, intern ("exclamation")))
405       sound_type = MB_ICONEXCLAMATION;
406   else if (EQ (sound, intern ("hand")))
407       sound_type = MB_ICONHAND;
408   else if (EQ (sound, intern ("question")))
409       sound_type = MB_ICONQUESTION;
410   else if (EQ (sound, intern ("ok")))
411       sound_type = MB_OK;
412   else if (EQ (sound, intern ("silent")))
413       sound_type = MB_EMACS_SILENT;
414   else
415       sound_type = 0xFFFFFFFF;
416 
417   return sound;
418 }
419 
420 static void
421 w32con_reset_terminal_modes (struct terminal *t)
422 {
423   COORD dest;
424   CONSOLE_SCREEN_BUFFER_INFO info;
425   int n;
426   DWORD r;
427 
428   /* Clear the complete screen buffer.  This is required because Emacs
429      sets the cursor position to the top of the buffer, but there might
430      be other output below the bottom of the Emacs frame if the screen buffer
431      is larger than the window size.  */
432   GetConsoleScreenBufferInfo (cur_screen, &info);
433   dest.X = 0;
434   dest.Y = 0;
435   n = info.dwSize.X * info.dwSize.Y;
436 
437   FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
438   FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
439   /* Now that the screen is clear, put the cursor at the top.  */
440   SetConsoleCursorPosition (cur_screen, dest);
441   
442 #ifdef USE_SEPARATE_SCREEN
443   SetConsoleActiveScreenBuffer (prev_screen);
444 #else
445   SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
446 #endif
447 
448   SetConsoleMode (keyboard_handle, prev_console_mode);
449 }
450 
451 static void
452 w32con_set_terminal_modes (struct terminal *t)
453 {
454   CONSOLE_CURSOR_INFO cci;
455 
456   /* make cursor big and visible (100 on Win95 makes it disappear)  */
457   cci.dwSize = 99;
458   cci.bVisible = TRUE;
459   (void) SetConsoleCursorInfo (cur_screen, &cci);
460 
461   SetConsoleActiveScreenBuffer (cur_screen);
462 
463   SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
464 
465   /* Initialize input mode: interrupt_input off, no flow control, allow
466      8 bit character input, standard quit char.  */
467   Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
468 }
469 
470 /* hmmm... perhaps these let us bracket screen changes so that we can flush
471    clumps rather than one-character-at-a-time...
472 
473    we'll start with not moving the cursor while an update is in progress.  */
474 static void
475 w32con_update_begin (struct frame * f)
476 {
477 }
478 
479 static void
480 w32con_update_end (struct frame * f)
481 {
482   SetConsoleCursorPosition (cur_screen, cursor_coords);
483 }
484 
485 static void
486 w32con_set_terminal_window (struct frame *f, int size)
487 {
488 }
489 
490 /***********************************************************************
491                         stubs from termcap.c
492  ***********************************************************************/
493 
494 void
495 sys_tputs (char *str, int nlines, int (*outfun)())
496 {
497 }
498 
499 char *
500 sys_tgetstr (char *cap, char **area)
501 {
502   return NULL;
503 }
504 
505 
506 /***********************************************************************
507                         stubs from cm.c
508  ***********************************************************************/
509 
510 struct tty_display_info *current_tty = NULL;
511 int cost = 0;
512 
513 int
514 evalcost (char c)
515 {
516   return c;
517 }
518 
519 int
520 cmputc (char c)
521 {
522   return c;
523 }
524 
525 void
526 cmcheckmagic (struct tty_display_info *tty)
527 {
528 }
529 
530 void
531 cmcostinit (struct tty_display_info *tty)
532 {
533 }
534 
535 void
536 cmgoto (struct tty_display_info *tty, int row, int col)
537 {
538 }
539 
540 void
541 Wcm_clear (struct tty_display_info *tty)
542 {
543 }
544 
545 
546 /***********************************************************************
547                                 Faces
548  ***********************************************************************/
549 
550 
551 /* Turn appearances of face FACE_ID on tty frame F on.  */
552 
553 static WORD
554 w32_face_attributes (f, face_id)
555      struct frame *f;
556      int face_id;
557 {
558   WORD char_attr;
559   struct face *face = FACE_FROM_ID (f, face_id);
560 
561   xassert (face != NULL);
562 
563   char_attr = char_attr_normal;
564 
565   /* Reverse the default color if requested. If background and
566      foreground are specified, then they have been reversed already.  */
567   if (face->tty_reverse_p)
568     char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
569       + ((char_attr & 0x00f0) >> 4);
570 
571   /* Before the terminal is properly initialized, all colors map to 0.
572      Don't try to resolve them.  */
573   if (NILP (Vtty_defined_color_alist))
574     return char_attr;
575 
576   /* Colors should be in the range 0...15 unless they are one of
577      FACE_TTY_DEFAULT_COLOR, FACE_TTY_DEFAULT_FG_COLOR or
578      FACE_TTY_DEFAULT_BG_COLOR.  Other out of range colors are
579      invalid, so it is better to use the default color if they ever
580      get through to here.  */
581   if (face->foreground >= 0 && face->foreground < 16)
582     char_attr = (char_attr & 0xfff0) + face->foreground;
583 
584   if (face->background >= 0 && face->background < 16)
585     char_attr = (char_attr & 0xff0f) + (face->background << 4);
586 
587   return char_attr;
588 }
589 
590 
591 
592 /* Given a color index, return its standard name.  */
593 Lisp_Object
594 vga_stdcolor_name (int idx)
595 {
596   /* Standard VGA colors, in the order of their standard numbering
597      in the default VGA palette.  */
598   static char *vga_colors[16] = {
599     "black", "blue", "green", "cyan", "red", "magenta", "brown",
600     "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
601     "lightred", "lightmagenta", "yellow", "white"
602   };
603 
604   extern Lisp_Object Qunspecified;
605 
606   if (idx >= 0 && idx < sizeof (vga_colors) / sizeof (vga_colors[0]))
607     return build_string (vga_colors[idx]);
608   else
609     return Qunspecified;        /* meaning the default */
610 }
611 
612 typedef int (*term_hook) ();
613 
614 void
615 initialize_w32_display (struct terminal *term)
616 {
617   CONSOLE_SCREEN_BUFFER_INFO    info;
618 
619   term->rif = 0; /* No window based redisplay on the console.  */
620   term->cursor_to_hook          = w32con_move_cursor;
621   term->raw_cursor_to_hook              = w32con_move_cursor;
622   term->clear_to_end_hook               = w32con_clear_to_end;
623   term->clear_frame_hook                = w32con_clear_frame;
624   term->clear_end_of_line_hook  = w32con_clear_end_of_line;
625   term->ins_del_lines_hook              = w32con_ins_del_lines;
626   term->insert_glyphs_hook              = w32con_insert_glyphs;
627   term->write_glyphs_hook               = w32con_write_glyphs;
628   term->delete_glyphs_hook              = w32con_delete_glyphs;
629   term->ring_bell_hook          = w32_sys_ring_bell;
630   term->reset_terminal_modes_hook       = w32con_reset_terminal_modes;
631   term->set_terminal_modes_hook = w32con_set_terminal_modes;
632   term->set_terminal_window_hook        = w32con_set_terminal_window;
633   term->update_begin_hook               = w32con_update_begin;
634   term->update_end_hook         = w32con_update_end;
635 
636   term->read_socket_hook = w32_console_read_socket;
637   term->mouse_position_hook = w32_console_mouse_position;
638 
639   /* The following are not used on the console.  */
640   term->frame_rehighlight_hook = 0;
641   term->frame_raise_lower_hook = 0;
642   term->set_vertical_scroll_bar_hook = 0;
643   term->condemn_scroll_bars_hook = 0;
644   term->redeem_scroll_bar_hook = 0;
645   term->judge_scroll_bars_hook = 0;
646   term->frame_up_to_date_hook = 0;
647 
648   /* Initialize interrupt_handle.  */
649   init_crit ();
650 
651   /* Remember original console settings.  */
652   keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
653   GetConsoleMode (keyboard_handle, &prev_console_mode);
654 
655   prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
656 
657 #ifdef USE_SEPARATE_SCREEN
658   cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
659                                           0, NULL,
660                                           CONSOLE_TEXTMODE_BUFFER,
661                                           NULL);
662 
663   if (cur_screen == INVALID_HANDLE_VALUE)
664     {
665       printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
666       printf ("LastError = 0x%lx\n", GetLastError ());
667       fflush (stdout);
668       exit (0);
669     }
670 #else
671   cur_screen = prev_screen;
672   GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
673 #endif
674 
675   /* Respect setting of LINES and COLUMNS environment variables.  */
676   {
677     char * lines = getenv("LINES");
678     char * columns = getenv("COLUMNS");
679 
680     if (lines != NULL && columns != NULL)
681       {
682         SMALL_RECT new_win_dims;
683         COORD new_size;
684 
685         new_size.X = atoi (columns);
686         new_size.Y = atoi (lines);
687 
688         GetConsoleScreenBufferInfo (cur_screen, &info);
689 
690         /* Shrink the window first, so the buffer dimensions can be
691            reduced if necessary.  */
692         new_win_dims.Top = 0;
693         new_win_dims.Left = 0;
694         new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1;
695         new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1;
696         SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
697 
698         SetConsoleScreenBufferSize (cur_screen, new_size);
699 
700         /* Set the window size to match the buffer dimension.  */
701         new_win_dims.Top = 0;
702         new_win_dims.Left = 0;
703         new_win_dims.Bottom = new_size.Y - 1;
704         new_win_dims.Right = new_size.X - 1;
705         SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
706       }
707   }
708 
709   GetConsoleScreenBufferInfo (cur_screen, &info);
710 
711   char_attr_normal = info.wAttributes;
712 
713   /* Determine if the info returned by GetConsoleScreenBufferInfo
714      is realistic.  Old MS Telnet servers used to only fill out
715      the dwSize portion, even modern one fill the whole struct with
716      garbage when using non-MS telnet clients.  */
717   if ((w32_use_full_screen_buffer
718        && (info.dwSize.Y < 20 || info.dwSize.Y > 100
719            || info.dwSize.X < 40 || info.dwSize.X > 200))
720       || (!w32_use_full_screen_buffer
721           && (info.srWindow.Bottom - info.srWindow.Top < 20
722               || info.srWindow.Bottom - info.srWindow.Top > 100
723               || info.srWindow.Right - info.srWindow.Left < 40
724               || info.srWindow.Right - info.srWindow.Left > 100)))
725     {
726       FRAME_LINES (SELECTED_FRAME ()) = 25;
727       SET_FRAME_COLS (SELECTED_FRAME (), 80);
728     }
729 
730   else if (w32_use_full_screen_buffer)
731     {
732       FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y;  /* lines per page */
733       SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X);  /* characters per line */
734     }
735   else
736     {
737       /* Lines per page.  Use buffer coords instead of buffer size.  */
738       FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
739         info.srWindow.Top;
740       /* Characters per line.  Use buffer coords instead of buffer size.  */
741       SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
742                        info.srWindow.Left);
743     }
744 
745   /* Setup w32_display_info structure for this frame. */
746 
747   w32_initialize_display_info (build_string ("Console"));
748 
749 }
750 
751 
752 DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
753        doc: /* Set screen colors.  */)
754     (foreground, background)
755     Lisp_Object foreground;
756     Lisp_Object background;
757 {
758   char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
759 
760   Frecenter (Qnil);
761   return Qt;
762 }
763 
764 DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
765        doc: /* Set cursor size.  */)
766     (size)
767     Lisp_Object size;
768 {
769   CONSOLE_CURSOR_INFO cci;
770   cci.dwSize = XFASTINT (size);
771   cci.bVisible = TRUE;
772   (void) SetConsoleCursorInfo (cur_screen, &cci);
773 
774   return Qt;
775 }
776 
777 void
778 syms_of_ntterm ()
779 {
780   DEFVAR_BOOL ("w32-use-full-screen-buffer",
781                &w32_use_full_screen_buffer,
782                doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
783 This is desirable when running Emacs over telnet.
784 A value of nil means use the current console window dimensions; this
785 may be preferrable when working directly at the console with a large
786 scroll-back buffer.  */);
787   w32_use_full_screen_buffer = 0;
788 
789   defsubr (&Sset_screen_color);
790   defsubr (&Sset_cursor_size);
791   defsubr (&Sset_message_beep);
792 }
793 
794 /* arch-tag: a390a07f-f661-42bc-aeb4-e6d8bf860337
795    (do not change this comment) */