(File Shadowing): New.
[emacs.git] / src / w32console.c
blob2f94985367b80cde0b5792a5a7551553c5f83a70
1 /* Terminal hooks for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1992, 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Tim Fleehart (apollo@online.com) 1-17-92
22 Geoff Voelker (voelker@cs.washington.edu) 9-12-93
26 #include <config.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <windows.h>
31 #include <string.h>
33 #include "lisp.h"
34 #include "charset.h"
35 #include "coding.h"
36 #include "disptab.h"
37 #include "termhooks.h"
38 /* Disable features in dispextern.h that require a Window System. */
39 #undef HAVE_WINDOW_SYSTEM
40 #include "frame.h"
41 #include "w32inevt.h"
42 #include "dispextern.h"
44 /* from window.c */
45 extern Lisp_Object Frecenter ();
47 /* from keyboard.c */
48 extern int detect_input_pending ();
50 /* from sysdep.c */
51 extern int read_input_pending ();
53 extern struct frame * updating_frame;
54 extern int meta_key;
56 static void move_cursor (int row, int col);
57 static void clear_to_end (void);
58 static void clear_frame (void);
59 static void clear_end_of_line (int);
60 static void ins_del_lines (int vpos, int n);
61 static void change_line_highlight (int, int, int, int);
62 static void reassert_line_highlight (int, int);
63 static void insert_glyphs (struct glyph *start, int len);
64 static void write_glyphs (struct glyph *string, int len);
65 static void delete_glyphs (int n);
66 void w32_sys_ring_bell (void);
67 static void reset_terminal_modes (void);
68 static void set_terminal_modes (void);
69 static void set_terminal_window (int size);
70 static void update_begin (struct frame * f);
71 static void update_end (struct frame * f);
72 static WORD w32_face_attributes (struct frame *f, int face_id);
73 static int hl_mode (int new_highlight);
75 static COORD cursor_coords;
76 static HANDLE prev_screen, cur_screen;
77 static WORD char_attr_normal;
78 static DWORD prev_console_mode;
80 #ifndef USE_SEPARATE_SCREEN
81 static CONSOLE_CURSOR_INFO prev_console_cursor;
82 #endif
84 /* Determine whether to make frame dimensions match the screen buffer,
85 or the current window size. The former is desirable when running
86 over telnet, while the latter is more useful when working directly at
87 the console with a large scroll-back buffer. */
88 int w32_use_full_screen_buffer;
89 HANDLE keyboard_handle;
92 /* Setting this as the ctrl handler prevents emacs from being killed when
93 someone hits ^C in a 'suspended' session (child shell).
94 Also ignore Ctrl-Break signals. */
96 BOOL
97 ctrl_c_handler (unsigned long type)
99 /* Only ignore "interrupt" events when running interactively. */
100 return (!noninteractive
101 && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
104 /* If we're updating a frame, use it as the current frame
105 Otherwise, use the selected frame. */
106 #define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())
108 /* Move the cursor to (row, col). */
109 void
110 move_cursor (int row, int col)
112 cursor_coords.X = col;
113 cursor_coords.Y = row;
115 if (updating_frame == (struct frame *) NULL)
117 SetConsoleCursorPosition (cur_screen, cursor_coords);
121 /* Clear from cursor to end of screen. */
122 void
123 clear_to_end (void)
125 struct frame * f = PICK_FRAME ();
127 clear_end_of_line (FRAME_WIDTH (f) - 1);
128 ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1);
131 /* Clear the frame. */
132 void
133 clear_frame (void)
135 struct frame * f = PICK_FRAME ();
136 COORD dest;
137 int n, r;
138 CONSOLE_SCREEN_BUFFER_INFO info;
140 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
142 hl_mode (0);
144 /* Remember that the screen buffer might be wider than the window. */
145 n = FRAME_HEIGHT (f) * info.dwSize.X;
146 dest.X = dest.Y = 0;
148 FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
149 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
151 move_cursor (0, 0);
155 static struct glyph glyph_base[256];
156 static BOOL ceol_initialized = FALSE;
158 /* Clear from Cursor to end (what's "standout marker"?). */
159 void
160 clear_end_of_line (int end)
162 if (!ceol_initialized)
164 int i;
165 for (i = 0; i < 256; i++)
167 memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
169 ceol_initialized = TRUE;
171 write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */
174 /* Insert n lines at vpos. if n is negative delete -n lines. */
175 void
176 ins_del_lines (int vpos, int n)
178 int i, nb, save_highlight;
179 SMALL_RECT scroll;
180 COORD dest;
181 CHAR_INFO fill;
182 struct frame * f = PICK_FRAME ();
184 if (n < 0)
186 scroll.Top = vpos - n;
187 scroll.Bottom = FRAME_HEIGHT (f);
188 dest.Y = vpos;
190 else
192 scroll.Top = vpos;
193 scroll.Bottom = FRAME_HEIGHT (f) - n;
194 dest.Y = vpos + n;
196 scroll.Left = 0;
197 scroll.Right = FRAME_WIDTH (f);
199 dest.X = 0;
201 save_highlight = hl_mode (0);
203 fill.Char.AsciiChar = 0x20;
204 fill.Attributes = char_attr_normal;
206 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
208 /* Here we have to deal with a w32 console flake: If the scroll
209 region looks like abc and we scroll c to a and fill with d we get
210 cbd... if we scroll block c one line at a time to a, we get cdd...
211 Emacs expects cdd consistently... So we have to deal with that
212 here... (this also occurs scrolling the same way in the other
213 direction. */
215 if (n > 0)
217 if (scroll.Bottom < dest.Y)
219 for (i = scroll.Bottom; i < dest.Y; i++)
221 move_cursor (i, 0);
222 clear_end_of_line (FRAME_WIDTH (f));
226 else
228 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
230 if (nb < scroll.Top)
232 for (i = nb; i < scroll.Top; i++)
234 move_cursor (i, 0);
235 clear_end_of_line (FRAME_WIDTH (f));
240 cursor_coords.X = 0;
241 cursor_coords.Y = vpos;
243 hl_mode (save_highlight);
246 /* Changes attribute to use when drawing characters to control. */
247 static int
248 hl_mode (int new_highlight)
250 static int highlight = 0;
251 int old_highlight;
253 old_highlight = highlight;
254 highlight = (new_highlight != 0);
256 return old_highlight;
259 /* Call this when about to modify line at position VPOS and change whether it
260 is highlighted. */
261 void
262 change_line_highlight (int new_highlight, int vpos, int y,
263 int first_unused_hpos)
265 hl_mode (new_highlight);
266 move_cursor (vpos, 0);
267 clear_end_of_line (first_unused_hpos);
270 /* External interface to control of standout mode. Call this when about to
271 * modify line at position VPOS and not change whether it is highlighted. */
272 void
273 reassert_line_highlight (int highlight, int vpos)
275 hl_mode (highlight);
276 vpos; /* pedantic compiler silencer */
279 #undef LEFT
280 #undef RIGHT
281 #define LEFT 1
282 #define RIGHT 0
284 void
285 scroll_line (int dist, int direction)
287 /* The idea here is to implement a horizontal scroll in one line to
288 implement delete and half of insert. */
289 SMALL_RECT scroll;
290 COORD dest;
291 CHAR_INFO fill;
292 struct frame * f = PICK_FRAME ();
294 scroll.Top = cursor_coords.Y;
295 scroll.Bottom = cursor_coords.Y;
297 if (direction == LEFT)
299 scroll.Left = cursor_coords.X + dist;
300 scroll.Right = FRAME_WIDTH (f) - 1;
302 else
304 scroll.Left = cursor_coords.X;
305 scroll.Right = FRAME_WIDTH (f) - dist - 1;
308 dest.X = cursor_coords.X;
309 dest.Y = cursor_coords.Y;
311 fill.Char.AsciiChar = 0x20;
312 fill.Attributes = char_attr_normal;
314 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
318 /* If start is zero insert blanks instead of a string at start ?. */
319 void
320 insert_glyphs (register struct glyph *start, register int len)
322 scroll_line (len, RIGHT);
324 /* Move len chars to the right starting at cursor_coords, fill with blanks */
325 if (start)
327 /* Print the first len characters of start, cursor_coords.X adjusted
328 by write_glyphs. */
330 write_glyphs (start, len);
332 else
334 clear_end_of_line (cursor_coords.X + len);
338 void
339 write_glyphs (register struct glyph *string, register int len)
341 int produced, consumed, i;
342 struct frame * f = PICK_FRAME ();
343 WORD char_attr;
344 unsigned char conversion_buffer[1024];
345 int conversion_buffer_size = sizeof conversion_buffer;
347 if (len <= 0)
348 return;
350 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
351 the tail. */
352 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
354 while (len > 0)
356 /* Identify a run of glyphs with the same face. */
357 int face_id = string->face_id;
358 int n;
360 for (n = 1; n < len; ++n)
361 if (string[n].face_id != face_id)
362 break;
364 /* Turn appearance modes of the face of the run on. */
365 char_attr = w32_face_attributes (f, face_id);
367 while (n > 0)
369 /* We use a fixed size (1024 bytes) of conversion buffer.
370 Usually it is sufficient, but if not, we just repeat the
371 loop. */
372 produced = encode_terminal_code (string, conversion_buffer,
373 n, conversion_buffer_size,
374 &consumed);
375 if (produced > 0)
377 /* Set the attribute for these characters. */
378 if (!FillConsoleOutputAttribute (cur_screen, char_attr,
379 produced, cursor_coords, &i))
381 printf ("Failed writing console attributes: %d\n",
382 GetLastError ());
383 fflush (stdout);
386 /* Write the characters. */
387 if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
388 produced, cursor_coords, &i))
390 printf ("Failed writing console characters: %d\n",
391 GetLastError ());
392 fflush (stdout);
395 cursor_coords.X += produced;
396 move_cursor (cursor_coords.Y, cursor_coords.X);
398 len -= consumed;
399 n -= consumed;
400 string += consumed;
404 /* We may have to output some codes to terminate the writing. */
405 if (CODING_REQUIRE_FLUSHING (&terminal_coding))
407 terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
408 encode_coding (&terminal_coding, "", conversion_buffer,
409 0, conversion_buffer_size);
410 if (terminal_coding.produced > 0)
412 if (!FillConsoleOutputAttribute (cur_screen, char_attr_normal,
413 terminal_coding.produced,
414 cursor_coords, &i))
416 printf ("Failed writing console attributes: %d\n",
417 GetLastError ());
418 fflush (stdout);
421 /* Write the characters. */
422 if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
423 produced, cursor_coords, &i))
425 printf ("Failed writing console characters: %d\n",
426 GetLastError ());
427 fflush (stdout);
434 void
435 delete_glyphs (int n)
437 /* delete chars means scroll chars from cursor_coords.X + n to
438 cursor_coords.X, anything beyond the edge of the screen should
439 come out empty... */
441 scroll_line (n, LEFT);
444 static unsigned int sound_type = 0xFFFFFFFF;
445 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
447 void
448 w32_sys_ring_bell (void)
450 if (sound_type == 0xFFFFFFFF)
452 Beep (666, 100);
454 else if (sound_type == MB_EMACS_SILENT)
456 /* Do nothing. */
458 else
459 MessageBeep (sound_type);
462 DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
463 "Set the sound generated when the bell is rung.\n\
464 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
465 to use the corresponding system sound for the bell. The 'silent sound\n\
466 prevents Emacs from making any sound at all.\n\
467 SOUND is nil to use the normal beep.")
468 (sound)
469 Lisp_Object sound;
471 CHECK_SYMBOL (sound, 0);
473 if (NILP (sound))
474 sound_type = 0xFFFFFFFF;
475 else if (EQ (sound, intern ("asterisk")))
476 sound_type = MB_ICONASTERISK;
477 else if (EQ (sound, intern ("exclamation")))
478 sound_type = MB_ICONEXCLAMATION;
479 else if (EQ (sound, intern ("hand")))
480 sound_type = MB_ICONHAND;
481 else if (EQ (sound, intern ("question")))
482 sound_type = MB_ICONQUESTION;
483 else if (EQ (sound, intern ("ok")))
484 sound_type = MB_OK;
485 else if (EQ (sound, intern ("silent")))
486 sound_type = MB_EMACS_SILENT;
487 else
488 sound_type = 0xFFFFFFFF;
490 return sound;
493 void
494 reset_terminal_modes (void)
496 hl_mode (0);
498 #ifdef USE_SEPARATE_SCREEN
499 SetConsoleActiveScreenBuffer (prev_screen);
500 #else
501 SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
502 #endif
503 SetConsoleMode (keyboard_handle, prev_console_mode);
506 void
507 set_terminal_modes (void)
509 CONSOLE_CURSOR_INFO cci;
511 hl_mode (0);
513 /* make cursor big and visible (100 on Win95 makes it disappear) */
514 cci.dwSize = 99;
515 cci.bVisible = TRUE;
516 (void) SetConsoleCursorInfo (cur_screen, &cci);
518 SetConsoleActiveScreenBuffer (cur_screen);
520 SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
522 /* Initialize input mode: interrupt_input off, no flow control, allow
523 8 bit character input, standard quit char. */
524 Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
527 /* hmmm... perhaps these let us bracket screen changes so that we can flush
528 clumps rather than one-character-at-a-time...
530 we'll start with not moving the cursor while an update is in progress. */
531 void
532 update_begin (struct frame * f)
534 hl_mode (0);
537 void
538 update_end (struct frame * f)
540 hl_mode (0);
541 SetConsoleCursorPosition (cur_screen, cursor_coords);
544 void
545 set_terminal_window (int size)
549 /***********************************************************************
550 Faces
551 ***********************************************************************/
554 /* Turn appearances of face FACE_ID on tty frame F on. */
556 static WORD
557 w32_face_attributes (f, face_id)
558 struct frame *f;
559 int face_id;
561 WORD char_attr;
562 int highlight_on_p;
563 struct face *face = FACE_FROM_ID (f, face_id);
565 highlight_on_p = hl_mode (0);
566 hl_mode (highlight_on_p);
568 xassert (face != NULL);
570 char_attr = char_attr_normal;
572 if (face->foreground != FACE_TTY_DEFAULT_FG_COLOR
573 && face->foreground != FACE_TTY_DEFAULT_COLOR)
574 char_attr = (char_attr & 0xfff0) + (face->foreground % 16);
576 if (face->background != FACE_TTY_DEFAULT_BG_COLOR
577 && face->background != FACE_TTY_DEFAULT_COLOR)
578 char_attr = (char_attr & 0xff0f) + ((face->background % 16) * 16);
581 /* Ensure readability (temporary measure until this all works) */
582 if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
583 char_attr ^= 0x0007;
585 if (face->tty_reverse_p || highlight_on_p)
586 char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
587 + ((char_attr & 0x00f0) >> 4);
589 return char_attr;
593 /* Emulation of some X window features from xfns.c and xfaces.c. */
595 extern char unspecified_fg[], unspecified_bg[];
598 /* Given a color index, return its standard name. */
599 Lisp_Object
600 vga_stdcolor_name (int idx)
602 /* Standard VGA colors, in the order of their standard numbering
603 in the default VGA palette. */
604 static char *vga_colors[16] = {
605 "black", "blue", "green", "cyan", "red", "magenta", "brown",
606 "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
607 "lightred", "lightmagenta", "yellow", "white"
610 extern Lisp_Object Qunspecified;
612 if (idx >= 0 && idx < sizeof (vga_colors) / sizeof (vga_colors[0]))
613 return build_string (vga_colors[idx]);
614 else
615 return Qunspecified; /* meaning the default */
618 typedef int (*term_hook) ();
620 void
621 initialize_w32_display (void)
623 CONSOLE_SCREEN_BUFFER_INFO info;
625 cursor_to_hook = move_cursor;
626 raw_cursor_to_hook = move_cursor;
627 clear_to_end_hook = clear_to_end;
628 clear_frame_hook = clear_frame;
629 clear_end_of_line_hook = clear_end_of_line;
630 ins_del_lines_hook = ins_del_lines;
631 change_line_highlight_hook = change_line_highlight;
632 reassert_line_highlight_hook = reassert_line_highlight;
633 insert_glyphs_hook = insert_glyphs;
634 write_glyphs_hook = write_glyphs;
635 delete_glyphs_hook = delete_glyphs;
636 ring_bell_hook = w32_sys_ring_bell;
637 reset_terminal_modes_hook = reset_terminal_modes;
638 set_terminal_modes_hook = set_terminal_modes;
639 set_terminal_window_hook = set_terminal_window;
640 update_begin_hook = update_begin;
641 update_end_hook = update_end;
643 read_socket_hook = w32_console_read_socket;
644 mouse_position_hook = w32_console_mouse_position;
645 estimate_mode_line_height_hook = 0;
647 /* Initialize interrupt_handle. */
648 init_crit ();
650 /* Remember original console settings. */
651 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
652 GetConsoleMode (keyboard_handle, &prev_console_mode);
654 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
656 #ifdef USE_SEPARATE_SCREEN
657 cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
658 0, NULL,
659 CONSOLE_TEXTMODE_BUFFER,
660 NULL);
662 if (cur_screen == INVALID_HANDLE_VALUE)
664 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
665 printf ("LastError = 0x%lx\n", GetLastError ());
666 fflush (stdout);
667 exit (0);
669 #else
670 cur_screen = prev_screen;
671 GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
672 #endif
674 /* Respect setting of LINES and COLUMNS environment variables. */
676 char * lines = getenv("LINES");
677 char * columns = getenv("COLUMNS");
679 if (lines != NULL && columns != NULL)
681 SMALL_RECT new_win_dims;
682 COORD new_size;
684 new_size.X = atoi (columns);
685 new_size.Y = atoi (lines);
687 GetConsoleScreenBufferInfo (cur_screen, &info);
689 /* Shrink the window first, so the buffer dimensions can be
690 reduced if necessary. */
691 new_win_dims.Top = 0;
692 new_win_dims.Left = 0;
693 new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1;
694 new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1;
695 SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
697 SetConsoleScreenBufferSize (cur_screen, new_size);
699 /* Set the window size to match the buffer dimension. */
700 new_win_dims.Top = 0;
701 new_win_dims.Left = 0;
702 new_win_dims.Bottom = new_size.Y - 1;
703 new_win_dims.Right = new_size.X - 1;
704 SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
708 GetConsoleScreenBufferInfo (cur_screen, &info);
710 meta_key = 1;
711 char_attr_normal = info.wAttributes;
712 hl_mode (0);
714 if (w32_use_full_screen_buffer)
716 FRAME_HEIGHT (SELECTED_FRAME ()) = info.dwSize.Y; /* lines per page */
717 SET_FRAME_WIDTH (SELECTED_FRAME (), info.dwSize.X); /* characters per line */
719 else
721 /* Lines per page. Use buffer coords instead of buffer size. */
722 FRAME_HEIGHT (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
723 info.srWindow.Top;
724 /* Characters per line. Use buffer coords instead of buffer size. */
725 SET_FRAME_WIDTH (SELECTED_FRAME (), 1 + info.srWindow.Right -
726 info.srWindow.Left);
729 /* Setup w32_display_info structure for this frame. */
731 w32_initialize_display_info (build_string ("Console"));
735 DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
736 "Set screen colors.")
737 (foreground, background)
738 Lisp_Object foreground;
739 Lisp_Object background;
741 char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
743 Frecenter (Qnil);
744 return Qt;
747 DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
748 "Set cursor size.")
749 (size)
750 Lisp_Object size;
752 CONSOLE_CURSOR_INFO cci;
753 cci.dwSize = XFASTINT (size);
754 cci.bVisible = TRUE;
755 (void) SetConsoleCursorInfo (cur_screen, &cci);
757 return Qt;
760 #ifndef HAVE_NTGUI
761 void
762 pixel_to_glyph_coords (struct frame * f, int pix_x, int pix_y, int *x, int *y,
763 void *bounds, int noclip)
765 *x = pix_x;
766 *y = pix_y;
769 void
770 glyph_to_pixel_coords (struct window * f, int x, int y, int *pix_x, int *pix_y)
772 *pix_x = x;
773 *pix_y = y;
775 #endif /* !HAVE_NTGUI */
777 void
778 syms_of_ntterm ()
780 DEFVAR_BOOL ("w32-use-full-screen-buffer",
781 &w32_use_full_screen_buffer,
782 "Non-nil means make terminal frames use the full screen buffer dimensions.\n\
783 This is desirable when running Emacs over telnet, and is the default.\n\
784 A value of nil means use the current console window dimensions; this\n\
785 may be preferrable when working directly at the console with a large\n\
786 scroll-back buffer.");
787 w32_use_full_screen_buffer = 1;
789 defsubr (&Sset_screen_color);
790 defsubr (&Sset_cursor_size);
791 defsubr (&Sset_message_beep);