** Every manual should be under the GFDL. dired-x isn't.
[emacs.git] / src / w32console.c
blobd2f0e06a64ded8fa2b7a2a7fa5edcb277f1e8671
1 /* Terminal hooks for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1992, 1999, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
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 2, or (at your option)
10 any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
22 Tim Fleehart (apollo@online.com) 1-17-92
23 Geoff Voelker (voelker@cs.washington.edu) 9-12-93
27 #include <config.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <windows.h>
32 #include <string.h>
34 #include "lisp.h"
35 #include "charset.h"
36 #include "coding.h"
37 #include "disptab.h"
38 #include "termhooks.h"
39 #include "dispextern.h"
40 /* Disable features in frame.h that require a Window System. */
41 #undef HAVE_WINDOW_SYSTEM
42 #include "frame.h"
43 #include "w32inevt.h"
45 /* from window.c */
46 extern Lisp_Object Frecenter ();
48 /* from keyboard.c */
49 extern int detect_input_pending ();
51 /* from sysdep.c */
52 extern int read_input_pending ();
54 extern struct frame * updating_frame;
55 extern int meta_key;
57 static void w32con_move_cursor (int row, int col);
58 static void w32con_clear_to_end (void);
59 static void w32con_clear_frame (void);
60 static void w32con_clear_end_of_line (int);
61 static void w32con_ins_del_lines (int vpos, int n);
62 static void w32con_insert_glyphs (struct glyph *start, int len);
63 static void w32con_write_glyphs (struct glyph *string, int len);
64 static void w32con_delete_glyphs (int n);
65 void w32_sys_ring_bell (void);
66 static void w32con_reset_terminal_modes (void);
67 static void w32con_set_terminal_modes (void);
68 static void w32con_set_terminal_window (int size);
69 static void w32con_update_begin (struct frame * f);
70 static void w32con_update_end (struct frame * f);
71 static WORD w32_face_attributes (struct frame *f, int face_id);
73 static COORD cursor_coords;
74 static HANDLE prev_screen, cur_screen;
75 static WORD char_attr_normal;
76 static DWORD prev_console_mode;
78 #ifndef USE_SEPARATE_SCREEN
79 static CONSOLE_CURSOR_INFO prev_console_cursor;
80 #endif
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. */
86 int w32_use_full_screen_buffer;
87 HANDLE keyboard_handle;
90 /* Setting this as the ctrl handler prevents emacs from being killed when
91 someone hits ^C in a 'suspended' session (child shell).
92 Also ignore Ctrl-Break signals. */
94 BOOL
95 ctrl_c_handler (unsigned long type)
97 /* Only ignore "interrupt" events when running interactively. */
98 return (!noninteractive
99 && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
102 /* If we're updating a frame, use it as the current frame
103 Otherwise, use the selected frame. */
104 #define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())
106 /* Move the cursor to (row, col). */
107 static void
108 w32con_move_cursor (int row, int col)
110 cursor_coords.X = col;
111 cursor_coords.Y = row;
113 if (updating_frame == (struct frame *) NULL)
115 SetConsoleCursorPosition (cur_screen, cursor_coords);
119 /* Clear from cursor to end of screen. */
120 static void
121 w32con_clear_to_end (void)
123 struct frame * f = PICK_FRAME ();
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);
129 /* Clear the frame. */
130 static void
131 w32con_clear_frame (void)
133 struct frame * f = PICK_FRAME ();
134 COORD dest;
135 int n;
136 DWORD r;
137 CONSOLE_SCREEN_BUFFER_INFO info;
139 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
141 /* Remember that the screen buffer might be wider than the window. */
142 n = FRAME_LINES (f) * info.dwSize.X;
143 dest.X = dest.Y = 0;
145 FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
146 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
148 w32con_move_cursor (0, 0);
152 static struct glyph glyph_base[256];
153 static BOOL ceol_initialized = FALSE;
155 /* Clear from Cursor to end (what's "standout marker"?). */
156 static void
157 w32con_clear_end_of_line (int end)
159 if (!ceol_initialized)
161 int i;
162 for (i = 0; i < 256; i++)
164 memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
166 ceol_initialized = TRUE;
168 w32con_write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */
171 /* Insert n lines at vpos. if n is negative delete -n lines. */
172 static void
173 w32con_ins_del_lines (int vpos, int n)
175 int i, nb;
176 SMALL_RECT scroll;
177 COORD dest;
178 CHAR_INFO fill;
179 struct frame * f = PICK_FRAME ();
181 if (n < 0)
183 scroll.Top = vpos - n;
184 scroll.Bottom = FRAME_LINES (f);
185 dest.Y = vpos;
187 else
189 scroll.Top = vpos;
190 scroll.Bottom = FRAME_LINES (f) - n;
191 dest.Y = vpos + n;
193 scroll.Left = 0;
194 scroll.Right = FRAME_COLS (f);
196 dest.X = 0;
198 fill.Char.AsciiChar = 0x20;
199 fill.Attributes = char_attr_normal;
201 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
203 /* Here we have to deal with a w32 console flake: If the scroll
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. */
210 if (n > 0)
212 if (scroll.Bottom < dest.Y)
214 for (i = scroll.Bottom; i < dest.Y; i++)
216 w32con_move_cursor (i, 0);
217 w32con_clear_end_of_line (FRAME_COLS (f));
221 else
223 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
225 if (nb < scroll.Top)
227 for (i = nb; i < scroll.Top; i++)
229 w32con_move_cursor (i, 0);
230 w32con_clear_end_of_line (FRAME_COLS (f));
235 cursor_coords.X = 0;
236 cursor_coords.Y = vpos;
239 #undef LEFT
240 #undef RIGHT
241 #define LEFT 1
242 #define RIGHT 0
244 static void
245 scroll_line (int dist, int direction)
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;
252 struct frame * f = PICK_FRAME ();
254 scroll.Top = cursor_coords.Y;
255 scroll.Bottom = cursor_coords.Y;
257 if (direction == LEFT)
259 scroll.Left = cursor_coords.X + dist;
260 scroll.Right = FRAME_COLS (f) - 1;
262 else
264 scroll.Left = cursor_coords.X;
265 scroll.Right = FRAME_COLS (f) - dist - 1;
268 dest.X = cursor_coords.X;
269 dest.Y = cursor_coords.Y;
271 fill.Char.AsciiChar = 0x20;
272 fill.Attributes = char_attr_normal;
274 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
278 /* If start is zero insert blanks instead of a string at start ?. */
279 static void
280 w32con_insert_glyphs (register struct glyph *start, register int len)
282 scroll_line (len, RIGHT);
284 /* Move len chars to the right starting at cursor_coords, fill with blanks */
285 if (start)
287 /* Print the first len characters of start, cursor_coords.X adjusted
288 by write_glyphs. */
290 w32con_write_glyphs (start, len);
292 else
294 w32con_clear_end_of_line (cursor_coords.X + len);
298 extern unsigned char *encode_terminal_code P_ ((struct glyph *, int,
299 struct coding_system *));
301 static void
302 w32con_write_glyphs (register struct glyph *string, register int len)
304 int produced, consumed;
305 DWORD r;
306 struct frame * f = PICK_FRAME ();
307 WORD char_attr;
308 unsigned char *conversion_buffer;
309 struct coding_system *coding;
311 if (len <= 0)
312 return;
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);
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;
323 while (len > 0)
325 /* Identify a run of glyphs with the same face. */
326 int face_id = string->face_id;
327 int n;
329 for (n = 1; n < len; ++n)
330 if (string[n].face_id != face_id)
331 break;
333 /* Turn appearance modes of the face of the run on. */
334 char_attr = w32_face_attributes (f, face_id);
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)
342 /* Set the attribute for these characters. */
343 if (!FillConsoleOutputAttribute (cur_screen, char_attr,
344 coding->produced, cursor_coords,
345 &r))
347 printf ("Failed writing console attributes: %d\n",
348 GetLastError ());
349 fflush (stdout);
352 /* Write the characters. */
353 if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
354 coding->produced, cursor_coords,
355 &r))
357 printf ("Failed writing console characters: %d\n",
358 GetLastError ());
359 fflush (stdout);
362 cursor_coords.X += coding->produced;
363 w32con_move_cursor (cursor_coords.Y, cursor_coords.X);
365 len -= n;
366 string += n;
371 static void
372 w32con_delete_glyphs (int n)
374 /* delete chars means scroll chars from cursor_coords.X + n to
375 cursor_coords.X, anything beyond the edge of the screen should
376 come out empty... */
378 scroll_line (n, LEFT);
381 static unsigned int sound_type = 0xFFFFFFFF;
382 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
384 void
385 w32_sys_ring_bell (void)
387 if (sound_type == 0xFFFFFFFF)
389 Beep (666, 100);
391 else if (sound_type == MB_EMACS_SILENT)
393 /* Do nothing. */
395 else
396 MessageBeep (sound_type);
399 DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
400 doc: /* Set the sound generated when the bell is rung.
401 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
402 to use the corresponding system sound for the bell. The 'silent sound
403 prevents Emacs from making any sound at all.
404 SOUND is nil to use the normal beep. */)
405 (sound)
406 Lisp_Object sound;
408 CHECK_SYMBOL (sound);
410 if (NILP (sound))
411 sound_type = 0xFFFFFFFF;
412 else if (EQ (sound, intern ("asterisk")))
413 sound_type = MB_ICONASTERISK;
414 else if (EQ (sound, intern ("exclamation")))
415 sound_type = MB_ICONEXCLAMATION;
416 else if (EQ (sound, intern ("hand")))
417 sound_type = MB_ICONHAND;
418 else if (EQ (sound, intern ("question")))
419 sound_type = MB_ICONQUESTION;
420 else if (EQ (sound, intern ("ok")))
421 sound_type = MB_OK;
422 else if (EQ (sound, intern ("silent")))
423 sound_type = MB_EMACS_SILENT;
424 else
425 sound_type = 0xFFFFFFFF;
427 return sound;
430 static void
431 w32con_reset_terminal_modes (void)
433 #ifdef USE_SEPARATE_SCREEN
434 SetConsoleActiveScreenBuffer (prev_screen);
435 #else
436 SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
437 #endif
438 SetConsoleMode (keyboard_handle, prev_console_mode);
441 static void
442 w32con_set_terminal_modes (void)
444 CONSOLE_CURSOR_INFO cci;
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);
451 SetConsoleActiveScreenBuffer (cur_screen);
453 SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
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);
460 /* hmmm... perhaps these let us bracket screen changes so that we can flush
461 clumps rather than one-character-at-a-time...
463 we'll start with not moving the cursor while an update is in progress. */
464 static void
465 w32con_update_begin (struct frame * f)
469 static void
470 w32con_update_end (struct frame * f)
472 SetConsoleCursorPosition (cur_screen, cursor_coords);
475 static void
476 w32con_set_terminal_window (int size)
480 /***********************************************************************
481 Faces
482 ***********************************************************************/
485 /* Turn appearances of face FACE_ID on tty frame F on. */
487 static WORD
488 w32_face_attributes (f, face_id)
489 struct frame *f;
490 int face_id;
492 WORD char_attr;
493 struct face *face = FACE_FROM_ID (f, face_id);
495 xassert (face != NULL);
497 char_attr = char_attr_normal;
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);
503 if (face->background != FACE_TTY_DEFAULT_BG_COLOR
504 && face->background != FACE_TTY_DEFAULT_COLOR)
505 char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4);
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. */
511 if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
512 char_attr ^= 0x0007;
514 if (face->tty_reverse_p)
515 char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
516 + ((char_attr & 0x00f0) >> 4);
518 return char_attr;
522 /* Emulation of some X window features from xfns.c and xfaces.c. */
524 extern char unspecified_fg[], unspecified_bg[];
527 /* Given a color index, return its standard name. */
528 Lisp_Object
529 vga_stdcolor_name (int idx)
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"
539 extern Lisp_Object Qunspecified;
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 */
547 typedef int (*term_hook) ();
549 void
550 initialize_w32_display (void)
552 CONSOLE_SCREEN_BUFFER_INFO info;
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;
563 ring_bell_hook = w32_sys_ring_bell;
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;
570 read_socket_hook = w32_console_read_socket;
571 mouse_position_hook = w32_console_mouse_position;
573 /* Initialize interrupt_handle. */
574 init_crit ();
576 /* Remember original console settings. */
577 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
578 GetConsoleMode (keyboard_handle, &prev_console_mode);
580 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
582 #ifdef USE_SEPARATE_SCREEN
583 cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
584 0, NULL,
585 CONSOLE_TEXTMODE_BUFFER,
586 NULL);
588 if (cur_screen == INVALID_HANDLE_VALUE)
590 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
591 printf ("LastError = 0x%lx\n", GetLastError ());
592 fflush (stdout);
593 exit (0);
595 #else
596 cur_screen = prev_screen;
597 GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
598 #endif
600 /* Respect setting of LINES and COLUMNS environment variables. */
602 char * lines = getenv("LINES");
603 char * columns = getenv("COLUMNS");
605 if (lines != NULL && columns != NULL)
607 SMALL_RECT new_win_dims;
608 COORD new_size;
610 new_size.X = atoi (columns);
611 new_size.Y = atoi (lines);
613 GetConsoleScreenBufferInfo (cur_screen, &info);
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);
623 SetConsoleScreenBufferSize (cur_screen, new_size);
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);
634 GetConsoleScreenBufferInfo (cur_screen, &info);
636 meta_key = 1;
637 char_attr_normal = info.wAttributes;
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)))
652 FRAME_LINES (SELECTED_FRAME ()) = 25;
653 SET_FRAME_COLS (SELECTED_FRAME (), 80);
656 else if (w32_use_full_screen_buffer)
658 FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y; /* lines per page */
659 SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X); /* characters per line */
661 else
663 /* Lines per page. Use buffer coords instead of buffer size. */
664 FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
665 info.srWindow.Top;
666 /* Characters per line. Use buffer coords instead of buffer size. */
667 SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right -
668 info.srWindow.Left);
671 /* Setup w32_display_info structure for this frame. */
673 w32_initialize_display_info (build_string ("Console"));
677 DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
678 doc: /* Set screen colors. */)
679 (foreground, background)
680 Lisp_Object foreground;
681 Lisp_Object background;
683 char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
685 Frecenter (Qnil);
686 return Qt;
689 DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
690 doc: /* Set cursor size. */)
691 (size)
692 Lisp_Object size;
694 CONSOLE_CURSOR_INFO cci;
695 cci.dwSize = XFASTINT (size);
696 cci.bVisible = TRUE;
697 (void) SetConsoleCursorInfo (cur_screen, &cci);
699 return Qt;
702 void
703 syms_of_ntterm ()
705 DEFVAR_BOOL ("w32-use-full-screen-buffer",
706 &w32_use_full_screen_buffer,
707 doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
708 This is desirable when running Emacs over telnet.
709 A value of nil means use the current console window dimensions; this
710 may be preferrable when working directly at the console with a large
711 scroll-back buffer. */);
712 w32_use_full_screen_buffer = 0;
714 defsubr (&Sset_screen_color);
715 defsubr (&Sset_cursor_size);
716 defsubr (&Sset_message_beep);
719 /* arch-tag: a390a07f-f661-42bc-aeb4-e6d8bf860337
720 (do not change this comment) */