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 3, or (at your option)
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
38 #include "termhooks.h"
39 #include "dispextern.h"
40 /* Disable features in frame.h that require a Window System. */
41 #undef HAVE_WINDOW_SYSTEM
46 extern Lisp_Object
Frecenter ();
49 extern int detect_input_pending ();
52 extern int read_input_pending ();
54 extern struct frame
* updating_frame
;
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
;
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. */
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). */
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. */
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. */
131 w32con_clear_frame (void)
133 struct frame
* f
= PICK_FRAME ();
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
;
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"?). */
157 w32con_clear_end_of_line (int end
)
159 if (!ceol_initialized
)
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. */
173 w32con_ins_del_lines (int vpos
, int n
)
179 struct frame
* f
= PICK_FRAME ();
183 scroll
.Top
= vpos
- n
;
184 scroll
.Bottom
= FRAME_LINES (f
);
190 scroll
.Bottom
= FRAME_LINES (f
) - n
;
194 scroll
.Right
= FRAME_COLS (f
);
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
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
));
223 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
227 for (i
= nb
; i
< scroll
.Top
; i
++)
229 w32con_move_cursor (i
, 0);
230 w32con_clear_end_of_line (FRAME_COLS (f
));
236 cursor_coords
.Y
= vpos
;
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. */
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;
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 ?. */
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 */
287 /* Print the first len characters of start, cursor_coords.X adjusted
290 w32con_write_glyphs (start
, len
);
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
*));
302 w32con_write_glyphs (register struct glyph
*string
, register int len
)
304 int produced
, consumed
;
306 struct frame
* f
= PICK_FRAME ();
308 unsigned char *conversion_buffer
;
309 struct coding_system
*coding
;
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
321 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
325 /* Identify a run of glyphs with the same face. */
326 int face_id
= string
->face_id
;
329 for (n
= 1; n
< len
; ++n
)
330 if (string
[n
].face_id
!= face_id
)
333 /* Turn appearance modes of the face of the run on. */
334 char_attr
= w32_face_attributes (f
, face_id
);
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
,
347 printf ("Failed writing console attributes: %d\n",
352 /* Write the characters. */
353 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
354 coding
->produced
, cursor_coords
,
357 printf ("Failed writing console characters: %d\n",
362 cursor_coords
.X
+= coding
->produced
;
363 w32con_move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
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
378 scroll_line (n
, LEFT
);
381 static unsigned int sound_type
= 0xFFFFFFFF;
382 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
385 w32_sys_ring_bell (void)
387 if (sound_type
== 0xFFFFFFFF)
391 else if (sound_type
== MB_EMACS_SILENT
)
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. */)
408 CHECK_SYMBOL (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")))
422 else if (EQ (sound
, intern ("silent")))
423 sound_type
= MB_EMACS_SILENT
;
425 sound_type
= 0xFFFFFFFF;
431 w32con_reset_terminal_modes (void)
433 #ifdef USE_SEPARATE_SCREEN
434 SetConsoleActiveScreenBuffer (prev_screen
);
436 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
438 SetConsoleMode (keyboard_handle
, prev_console_mode
);
442 w32con_set_terminal_modes (void)
444 CONSOLE_CURSOR_INFO cci
;
446 /* make cursor big and visible (100 on Win95 makes it disappear) */
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. */
465 w32con_update_begin (struct frame
* f
)
470 w32con_update_end (struct frame
* f
)
472 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
476 w32con_set_terminal_window (int size
)
480 /***********************************************************************
482 ***********************************************************************/
485 /* Turn appearances of face FACE_ID on tty frame F on. */
488 w32_face_attributes (f
, face_id
)
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))
514 if (face
->tty_reverse_p
)
515 char_attr
= (char_attr
& 0xff00) + ((char_attr
& 0x000f) << 4)
516 + ((char_attr
& 0x00f0) >> 4);
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. */
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
]);
544 return Qunspecified
; /* meaning the default */
547 typedef int (*term_hook
) ();
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. */
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
,
585 CONSOLE_TEXTMODE_BUFFER
,
588 if (cur_screen
== INVALID_HANDLE_VALUE
)
590 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
591 printf ("LastError = 0x%lx\n", GetLastError ());
596 cur_screen
= prev_screen
;
597 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
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
;
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
);
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 */
663 /* Lines per page. Use buffer coords instead of buffer size. */
664 FRAME_LINES (SELECTED_FRAME ()) = 1 + info
.srWindow
.Bottom
-
666 /* Characters per line. Use buffer coords instead of buffer size. */
667 SET_FRAME_COLS (SELECTED_FRAME (), 1 + info
.srWindow
.Right
-
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);
689 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
690 doc
: /* Set cursor size. */)
694 CONSOLE_CURSOR_INFO cci
;
695 cci
.dwSize
= XFASTINT (size
);
697 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
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) */