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