(Fpropertize): Doc fix.
[emacs.git] / src / w32console.c
blobf067501f71be4d0a036928adf51c0fba63e0a1c6
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 /* Disable features in headers that require a Window System for
34 console mode. */
35 #undef HAVE_WINDOW_SYSTEM
36 #include "lisp.h"
37 #include "charset.h"
38 #include "coding.h"
39 #include "frame.h"
40 #include "disptab.h"
41 #include "termhooks.h"
42 #include "w32inevt.h"
43 #include "dispextern.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 move_cursor (int row, int col);
58 static void clear_to_end (void);
59 static void clear_frame (void);
60 static void clear_end_of_line (int);
61 static void ins_del_lines (int vpos, int n);
62 static void change_line_highlight (int, int, int, int);
63 static void reassert_line_highlight (int, int);
64 static void insert_glyphs (struct glyph *start, int len);
65 static void write_glyphs (struct glyph *string, int len);
66 static void delete_glyphs (int n);
67 void w32_sys_ring_bell (void);
68 static void reset_terminal_modes (void);
69 static void set_terminal_modes (void);
70 static void set_terminal_window (int size);
71 static void update_begin (struct frame * f);
72 static void update_end (struct frame * f);
73 static WORD w32_face_attributes (struct frame *f, int face_id);
74 static int hl_mode (int new_highlight);
76 static COORD cursor_coords;
77 static HANDLE prev_screen, cur_screen;
78 static WORD char_attr_normal;
79 static DWORD prev_console_mode;
81 #ifndef USE_SEPARATE_SCREEN
82 static CONSOLE_CURSOR_INFO prev_console_cursor;
83 #endif
85 /* Determine whether to make frame dimensions match the screen buffer,
86 or the current window size. The former is desirable when running
87 over telnet, while the latter is more useful when working directly at
88 the console with a large scroll-back buffer. */
89 int w32_use_full_screen_buffer;
90 HANDLE keyboard_handle;
93 /* Setting this as the ctrl handler prevents emacs from being killed when
94 someone hits ^C in a 'suspended' session (child shell).
95 Also ignore Ctrl-Break signals. */
97 BOOL
98 ctrl_c_handler (unsigned long type)
100 /* Only ignore "interrupt" events when running interactively. */
101 return (!noninteractive
102 && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
105 /* If we're updating a frame, use it as the current frame
106 Otherwise, use the selected frame. */
107 #define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())
109 /* Move the cursor to (row, col). */
110 void
111 move_cursor (int row, int col)
113 cursor_coords.X = col;
114 cursor_coords.Y = row;
116 if (updating_frame == (struct frame *) NULL)
118 SetConsoleCursorPosition (cur_screen, cursor_coords);
122 /* Clear from cursor to end of screen. */
123 void
124 clear_to_end (void)
126 struct frame * f = PICK_FRAME ();
128 clear_end_of_line (FRAME_WIDTH (f) - 1);
129 ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1);
132 /* Clear the frame. */
133 void
134 clear_frame (void)
136 struct frame * f = PICK_FRAME ();
137 COORD dest;
138 int n, r;
139 CONSOLE_SCREEN_BUFFER_INFO info;
141 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
143 hl_mode (0);
145 /* Remember that the screen buffer might be wider than the window. */
146 n = FRAME_HEIGHT (f) * info.dwSize.X;
147 dest.X = dest.Y = 0;
149 FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
150 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
152 move_cursor (0, 0);
156 static struct glyph glyph_base[256];
157 static BOOL ceol_initialized = FALSE;
159 /* Clear from Cursor to end (what's "standout marker"?). */
160 void
161 clear_end_of_line (int end)
163 if (!ceol_initialized)
165 int i;
166 for (i = 0; i < 256; i++)
168 memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph));
170 ceol_initialized = TRUE;
172 write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */
175 /* Insert n lines at vpos. if n is negative delete -n lines. */
176 void
177 ins_del_lines (int vpos, int n)
179 int i, nb, save_highlight;
180 SMALL_RECT scroll;
181 COORD dest;
182 CHAR_INFO fill;
183 struct frame * f = PICK_FRAME ();
185 if (n < 0)
187 scroll.Top = vpos - n;
188 scroll.Bottom = FRAME_HEIGHT (f);
189 dest.Y = vpos;
191 else
193 scroll.Top = vpos;
194 scroll.Bottom = FRAME_HEIGHT (f) - n;
195 dest.Y = vpos + n;
197 scroll.Left = 0;
198 scroll.Right = FRAME_WIDTH (f);
200 dest.X = 0;
202 save_highlight = hl_mode (0);
204 fill.Char.AsciiChar = 0x20;
205 fill.Attributes = char_attr_normal;
207 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
209 /* Here we have to deal with a w32 console flake: If the scroll
210 region looks like abc and we scroll c to a and fill with d we get
211 cbd... if we scroll block c one line at a time to a, we get cdd...
212 Emacs expects cdd consistently... So we have to deal with that
213 here... (this also occurs scrolling the same way in the other
214 direction. */
216 if (n > 0)
218 if (scroll.Bottom < dest.Y)
220 for (i = scroll.Bottom; i < dest.Y; i++)
222 move_cursor (i, 0);
223 clear_end_of_line (FRAME_WIDTH (f));
227 else
229 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
231 if (nb < scroll.Top)
233 for (i = nb; i < scroll.Top; i++)
235 move_cursor (i, 0);
236 clear_end_of_line (FRAME_WIDTH (f));
241 cursor_coords.X = 0;
242 cursor_coords.Y = vpos;
244 hl_mode (save_highlight);
247 /* Changes attribute to use when drawing characters to control. */
248 static int
249 hl_mode (int new_highlight)
251 static int highlight = 0;
252 int old_highlight;
254 old_highlight = highlight;
255 highlight = (new_highlight != 0);
257 return old_highlight;
260 /* Call this when about to modify line at position VPOS and change whether it
261 is highlighted. */
262 void
263 change_line_highlight (int new_highlight, int vpos, int y,
264 int first_unused_hpos)
266 hl_mode (new_highlight);
267 move_cursor (vpos, 0);
268 clear_end_of_line (first_unused_hpos);
271 /* External interface to control of standout mode. Call this when about to
272 * modify line at position VPOS and not change whether it is highlighted. */
273 void
274 reassert_line_highlight (int highlight, int vpos)
276 hl_mode (highlight);
277 vpos; /* pedantic compiler silencer */
280 #undef LEFT
281 #undef RIGHT
282 #define LEFT 1
283 #define RIGHT 0
285 void
286 scroll_line (int dist, int direction)
288 /* The idea here is to implement a horizontal scroll in one line to
289 implement delete and half of insert. */
290 SMALL_RECT scroll;
291 COORD dest;
292 CHAR_INFO fill;
293 struct frame * f = PICK_FRAME ();
295 scroll.Top = cursor_coords.Y;
296 scroll.Bottom = cursor_coords.Y;
298 if (direction == LEFT)
300 scroll.Left = cursor_coords.X + dist;
301 scroll.Right = FRAME_WIDTH (f) - 1;
303 else
305 scroll.Left = cursor_coords.X;
306 scroll.Right = FRAME_WIDTH (f) - dist - 1;
309 dest.X = cursor_coords.X;
310 dest.Y = cursor_coords.Y;
312 fill.Char.AsciiChar = 0x20;
313 fill.Attributes = char_attr_normal;
315 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
319 /* If start is zero insert blanks instead of a string at start ?. */
320 void
321 insert_glyphs (register struct glyph *start, register int len)
323 scroll_line (len, RIGHT);
325 /* Move len chars to the right starting at cursor_coords, fill with blanks */
326 if (start)
328 /* Print the first len characters of start, cursor_coords.X adjusted
329 by write_glyphs. */
331 write_glyphs (start, len);
333 else
335 clear_end_of_line (cursor_coords.X + len);
339 void
340 write_glyphs (register struct glyph *string, register int len)
342 int produced, consumed, i;
343 struct frame * f = PICK_FRAME ();
344 WORD char_attr;
346 if (len <= 0)
347 return;
349 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
350 the tail. */
351 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
353 while (len > 0)
355 /* Identify a run of glyphs with the same face. */
356 int face_id = string->face_id;
357 int n;
359 for (n = 1; n < len; ++n)
360 if (string[n].face_id != face_id)
361 break;
363 /* Turn appearance modes of the face of the run on. */
364 char_attr = w32_face_attributes (f, face_id);
366 while (n > 0)
368 /* We use a shared conversion buffer of the current size
369 (1024 bytes at least). Usually it is sufficient, but if
370 not, we just repeat the loop. */
371 produced = encode_terminal_code (string, conversion_buffer,
372 n, conversion_buffer_size,
373 &consumed);
374 if (produced > 0)
376 /* Set the attribute for these characters. */
377 if (!FillConsoleOutputAttribute (cur_screen, char_attr,
378 produced, cursor_coords, &i))
380 printf ("Failed writing console attributes: %d\n",
381 GetLastError ());
382 fflush (stdout);
385 /* Write the characters. */
386 if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
387 produced, cursor_coords, &i))
389 printf ("Failed writing console characters: %d\n",
390 GetLastError ());
391 fflush (stdout);
394 cursor_coords.X += produced;
395 move_cursor (cursor_coords.Y, cursor_coords.X);
397 len -= consumed;
398 n -= consumed;
399 string += consumed;
403 /* We may have to output some codes to terminate the writing. */
404 if (CODING_REQUIRE_FLUSHING (&terminal_coding))
406 terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
407 encode_coding (&terminal_coding, "", conversion_buffer,
408 0, conversion_buffer_size);
409 if (terminal_coding.produced > 0)
411 if (!FillConsoleOutputAttribute (cur_screen, char_attr_normal,
412 terminal_coding.produced,
413 cursor_coords, &i))
415 printf ("Failed writing console attributes: %d\n",
416 GetLastError ());
417 fflush (stdout);
420 /* Write the characters. */
421 if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
422 produced, cursor_coords, &i))
424 printf ("Failed writing console characters: %d\n",
425 GetLastError ());
426 fflush (stdout);
433 void
434 delete_glyphs (int n)
436 /* delete chars means scroll chars from cursor_coords.X + n to
437 cursor_coords.X, anything beyond the edge of the screen should
438 come out empty... */
440 scroll_line (n, LEFT);
443 static unsigned int sound_type = 0xFFFFFFFF;
444 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
446 void
447 w32_sys_ring_bell (void)
449 if (sound_type == 0xFFFFFFFF)
451 Beep (666, 100);
453 else if (sound_type == MB_EMACS_SILENT)
455 /* Do nothing. */
457 else
458 MessageBeep (sound_type);
461 DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
462 "Set the sound generated when the bell is rung.\n\
463 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
464 to use the corresponding system sound for the bell. The 'silent sound\n\
465 prevents Emacs from making any sound at all.\n\
466 SOUND is nil to use the normal beep.")
467 (sound)
468 Lisp_Object sound;
470 CHECK_SYMBOL (sound, 0);
472 if (NILP (sound))
473 sound_type = 0xFFFFFFFF;
474 else if (EQ (sound, intern ("asterisk")))
475 sound_type = MB_ICONASTERISK;
476 else if (EQ (sound, intern ("exclamation")))
477 sound_type = MB_ICONEXCLAMATION;
478 else if (EQ (sound, intern ("hand")))
479 sound_type = MB_ICONHAND;
480 else if (EQ (sound, intern ("question")))
481 sound_type = MB_ICONQUESTION;
482 else if (EQ (sound, intern ("ok")))
483 sound_type = MB_OK;
484 else if (EQ (sound, intern ("silent")))
485 sound_type = MB_EMACS_SILENT;
486 else
487 sound_type = 0xFFFFFFFF;
489 return sound;
492 void
493 reset_terminal_modes (void)
495 hl_mode (0);
497 #ifdef USE_SEPARATE_SCREEN
498 SetConsoleActiveScreenBuffer (prev_screen);
499 #else
500 SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
501 #endif
502 SetConsoleMode (keyboard_handle, prev_console_mode);
505 void
506 set_terminal_modes (void)
508 CONSOLE_CURSOR_INFO cci;
510 hl_mode (0);
512 /* make cursor big and visible (100 on Win95 makes it disappear) */
513 cci.dwSize = 99;
514 cci.bVisible = TRUE;
515 (void) SetConsoleCursorInfo (cur_screen, &cci);
517 SetConsoleActiveScreenBuffer (cur_screen);
519 SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
521 /* Initialize input mode: interrupt_input off, no flow control, allow
522 8 bit character input, standard quit char. */
523 Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
526 /* hmmm... perhaps these let us bracket screen changes so that we can flush
527 clumps rather than one-character-at-a-time...
529 we'll start with not moving the cursor while an update is in progress. */
530 void
531 update_begin (struct frame * f)
533 hl_mode (0);
536 void
537 update_end (struct frame * f)
539 hl_mode (0);
540 SetConsoleCursorPosition (cur_screen, cursor_coords);
543 void
544 set_terminal_window (int size)
548 /***********************************************************************
549 Faces
550 ***********************************************************************/
553 /* Turn appearances of face FACE_ID on tty frame F on. */
555 static WORD
556 w32_face_attributes (f, face_id)
557 struct frame *f;
558 int face_id;
560 WORD char_attr;
561 int highlight_on_p;
562 struct face *face = FACE_FROM_ID (f, face_id);
564 highlight_on_p = hl_mode (0);
565 hl_mode (highlight_on_p);
567 xassert (face != NULL);
569 char_attr = char_attr_normal;
571 if (face->foreground != FACE_TTY_DEFAULT_FG_COLOR
572 && face->foreground != FACE_TTY_DEFAULT_COLOR)
573 char_attr = (char_attr & 0xfff0) + (face->foreground % 16);
575 if (face->background != FACE_TTY_DEFAULT_BG_COLOR
576 && face->background != FACE_TTY_DEFAULT_COLOR)
577 char_attr = (char_attr & 0xff0f) + ((face->background % 16) * 16);
580 /* Ensure readability (temporary measure until this all works) */
581 if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f))
582 char_attr ^= 0x0007;
584 if (face->tty_reverse_p || highlight_on_p)
585 char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
586 + ((char_attr & 0x00f0) >> 4);
588 return char_attr;
592 /* Emulation of some X window features from xfns.c and xfaces.c. */
594 extern char unspecified_fg[], unspecified_bg[];
597 /* Given a color index, return its standard name. */
598 Lisp_Object
599 vga_stdcolor_name (int idx)
601 /* Standard VGA colors, in the order of their standard numbering
602 in the default VGA palette. */
603 static char *vga_colors[16] = {
604 "black", "blue", "green", "cyan", "red", "magenta", "brown",
605 "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
606 "lightred", "lightmagenta", "yellow", "white"
609 extern Lisp_Object Qunspecified;
611 if (idx >= 0 && idx < sizeof (vga_colors) / sizeof (vga_colors[0]))
612 return build_string (vga_colors[idx]);
613 else
614 return Qunspecified; /* meaning the default */
617 typedef int (*term_hook) ();
619 void
620 initialize_w32_display (void)
622 CONSOLE_SCREEN_BUFFER_INFO info;
624 cursor_to_hook = move_cursor;
625 raw_cursor_to_hook = move_cursor;
626 clear_to_end_hook = clear_to_end;
627 clear_frame_hook = clear_frame;
628 clear_end_of_line_hook = clear_end_of_line;
629 ins_del_lines_hook = ins_del_lines;
630 change_line_highlight_hook = change_line_highlight;
631 reassert_line_highlight_hook = reassert_line_highlight;
632 insert_glyphs_hook = insert_glyphs;
633 write_glyphs_hook = write_glyphs;
634 delete_glyphs_hook = delete_glyphs;
635 ring_bell_hook = w32_sys_ring_bell;
636 reset_terminal_modes_hook = reset_terminal_modes;
637 set_terminal_modes_hook = set_terminal_modes;
638 set_terminal_window_hook = set_terminal_window;
639 update_begin_hook = update_begin;
640 update_end_hook = update_end;
642 read_socket_hook = w32_console_read_socket;
643 mouse_position_hook = w32_console_mouse_position;
644 estimate_mode_line_height_hook = 0;
646 /* Initialize interrupt_handle. */
647 init_crit ();
649 /* Remember original console settings. */
650 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
651 GetConsoleMode (keyboard_handle, &prev_console_mode);
653 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
655 #ifdef USE_SEPARATE_SCREEN
656 cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
657 0, NULL,
658 CONSOLE_TEXTMODE_BUFFER,
659 NULL);
661 if (cur_screen == INVALID_HANDLE_VALUE)
663 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
664 printf ("LastError = 0x%lx\n", GetLastError ());
665 fflush (stdout);
666 exit (0);
668 #else
669 cur_screen = prev_screen;
670 GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
671 #endif
673 /* Respect setting of LINES and COLUMNS environment variables. */
675 char * lines = getenv("LINES");
676 char * columns = getenv("COLUMNS");
678 if (lines != NULL && columns != NULL)
680 SMALL_RECT new_win_dims;
681 COORD new_size;
683 new_size.X = atoi (columns);
684 new_size.Y = atoi (lines);
686 GetConsoleScreenBufferInfo (cur_screen, &info);
688 /* Shrink the window first, so the buffer dimensions can be
689 reduced if necessary. */
690 new_win_dims.Top = 0;
691 new_win_dims.Left = 0;
692 new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1;
693 new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1;
694 SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
696 SetConsoleScreenBufferSize (cur_screen, new_size);
698 /* Set the window size to match the buffer dimension. */
699 new_win_dims.Top = 0;
700 new_win_dims.Left = 0;
701 new_win_dims.Bottom = new_size.Y - 1;
702 new_win_dims.Right = new_size.X - 1;
703 SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
707 GetConsoleScreenBufferInfo (cur_screen, &info);
709 meta_key = 1;
710 char_attr_normal = info.wAttributes;
711 hl_mode (0);
713 if (w32_use_full_screen_buffer)
715 FRAME_HEIGHT (SELECTED_FRAME ()) = info.dwSize.Y; /* lines per page */
716 SET_FRAME_WIDTH (SELECTED_FRAME (), info.dwSize.X); /* characters per line */
718 else
720 /* Lines per page. Use buffer coords instead of buffer size. */
721 FRAME_HEIGHT (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom -
722 info.srWindow.Top;
723 /* Characters per line. Use buffer coords instead of buffer size. */
724 SET_FRAME_WIDTH (SELECTED_FRAME (), 1 + info.srWindow.Right -
725 info.srWindow.Left);
729 DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
730 "Set screen colors.")
731 (foreground, background)
732 Lisp_Object foreground;
733 Lisp_Object background;
735 char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
737 Frecenter (Qnil);
738 return Qt;
741 DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
742 "Set cursor size.")
743 (size)
744 Lisp_Object size;
746 CONSOLE_CURSOR_INFO cci;
747 cci.dwSize = XFASTINT (size);
748 cci.bVisible = TRUE;
749 (void) SetConsoleCursorInfo (cur_screen, &cci);
751 return Qt;
754 #ifndef HAVE_NTGUI
755 void
756 pixel_to_glyph_coords (struct frame * f, int pix_x, int pix_y, int *x, int *y,
757 void *bounds, int noclip)
759 *x = pix_x;
760 *y = pix_y;
763 void
764 glyph_to_pixel_coords (struct frame * f, int x, int y, int *pix_x, int *pix_y)
766 *pix_x = x;
767 *pix_y = y;
769 #endif /* !HAVE_NTGUI */
771 void
772 syms_of_ntterm ()
774 DEFVAR_BOOL ("w32-use-full-screen-buffer",
775 &w32_use_full_screen_buffer,
776 "Non-nil means make terminal frames use the full screen buffer dimensions.\n\
777 This is desirable when running Emacs over telnet, and is the default.\n\
778 A value of nil means use the current console window dimensions; this\n\
779 may be preferrable when working directly at the console with a large\n\
780 scroll-back buffer.");
781 w32_use_full_screen_buffer = 1;
783 defsubr (&Sset_screen_color);
784 defsubr (&Sset_cursor_size);
785 defsubr (&Sset_message_beep);