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)
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
37 #include "termhooks.h"
38 /* Disable features in dispextern.h that require a Window System. */
39 #undef HAVE_WINDOW_SYSTEM
42 #include "dispextern.h"
45 extern Lisp_Object
Frecenter ();
48 extern int detect_input_pending ();
51 extern int read_input_pending ();
53 extern struct frame
* updating_frame
;
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
;
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. */
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). */
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. */
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. */
135 struct frame
* f
= PICK_FRAME ();
138 CONSOLE_SCREEN_BUFFER_INFO info
;
140 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
144 /* Remember that the screen buffer might be wider than the window. */
145 n
= FRAME_HEIGHT (f
) * info
.dwSize
.X
;
148 FillConsoleOutputAttribute (cur_screen
, char_attr_normal
, n
, dest
, &r
);
149 FillConsoleOutputCharacter (cur_screen
, ' ', n
, dest
, &r
);
155 static struct glyph glyph_base
[256];
156 static BOOL ceol_initialized
= FALSE
;
158 /* Clear from Cursor to end (what's "standout marker"?). */
160 clear_end_of_line (int end
)
162 if (!ceol_initialized
)
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. */
176 ins_del_lines (int vpos
, int n
)
178 int i
, nb
, save_highlight
;
182 struct frame
* f
= PICK_FRAME ();
186 scroll
.Top
= vpos
- n
;
187 scroll
.Bottom
= FRAME_HEIGHT (f
);
193 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
197 scroll
.Right
= FRAME_WIDTH (f
);
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
217 if (scroll
.Bottom
< dest
.Y
)
219 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
222 clear_end_of_line (FRAME_WIDTH (f
));
228 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
232 for (i
= nb
; i
< scroll
.Top
; i
++)
235 clear_end_of_line (FRAME_WIDTH (f
));
241 cursor_coords
.Y
= vpos
;
243 hl_mode (save_highlight
);
246 /* Changes attribute to use when drawing characters to control. */
248 hl_mode (int new_highlight
)
250 static int highlight
= 0;
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
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. */
273 reassert_line_highlight (int highlight
, int vpos
)
276 vpos
; /* pedantic compiler silencer */
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. */
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;
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 ?. */
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 */
327 /* Print the first len characters of start, cursor_coords.X adjusted
330 write_glyphs (start
, len
);
334 clear_end_of_line (cursor_coords
.X
+ len
);
339 write_glyphs (register struct glyph
*string
, register int len
)
341 int produced
, consumed
, i
;
342 struct frame
* f
= PICK_FRAME ();
344 unsigned char conversion_buffer
[1024];
345 int conversion_buffer_size
= sizeof conversion_buffer
;
350 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
352 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
356 /* Identify a run of glyphs with the same face. */
357 int face_id
= string
->face_id
;
360 for (n
= 1; n
< len
; ++n
)
361 if (string
[n
].face_id
!= face_id
)
364 /* Turn appearance modes of the face of the run on. */
365 char_attr
= w32_face_attributes (f
, face_id
);
369 /* We use a fixed size (1024 bytes) of conversion buffer.
370 Usually it is sufficient, but if not, we just repeat the
372 produced
= encode_terminal_code (string
, conversion_buffer
,
373 n
, conversion_buffer_size
,
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",
386 /* Write the characters. */
387 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
388 produced
, cursor_coords
, &i
))
390 printf ("Failed writing console characters: %d\n",
395 cursor_coords
.X
+= produced
;
396 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
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
,
416 printf ("Failed writing console attributes: %d\n",
421 /* Write the characters. */
422 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
423 produced
, cursor_coords
, &i
))
425 printf ("Failed writing console characters: %d\n",
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
441 scroll_line (n
, LEFT
);
444 static unsigned int sound_type
= 0xFFFFFFFF;
445 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
448 w32_sys_ring_bell (void)
450 if (sound_type
== 0xFFFFFFFF)
454 else if (sound_type
== MB_EMACS_SILENT
)
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.")
471 CHECK_SYMBOL (sound
, 0);
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")))
485 else if (EQ (sound
, intern ("silent")))
486 sound_type
= MB_EMACS_SILENT
;
488 sound_type
= 0xFFFFFFFF;
494 reset_terminal_modes (void)
498 #ifdef USE_SEPARATE_SCREEN
499 SetConsoleActiveScreenBuffer (prev_screen
);
501 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
503 SetConsoleMode (keyboard_handle
, prev_console_mode
);
507 set_terminal_modes (void)
509 CONSOLE_CURSOR_INFO cci
;
513 /* make cursor big and visible (100 on Win95 makes it disappear) */
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. */
532 update_begin (struct frame
* f
)
538 update_end (struct frame
* f
)
541 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
545 set_terminal_window (int size
)
549 /***********************************************************************
551 ***********************************************************************/
554 /* Turn appearances of face FACE_ID on tty frame F on. */
557 w32_face_attributes (f
, face_id
)
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))
585 if (face
->tty_reverse_p
|| highlight_on_p
)
586 char_attr
= (char_attr
& 0xff00) + ((char_attr
& 0x000f) << 4)
587 + ((char_attr
& 0x00f0) >> 4);
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. */
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
]);
615 return Qunspecified
; /* meaning the default */
618 typedef int (*term_hook
) ();
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. */
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
,
659 CONSOLE_TEXTMODE_BUFFER
,
662 if (cur_screen
== INVALID_HANDLE_VALUE
)
664 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
665 printf ("LastError = 0x%lx\n", GetLastError ());
670 cur_screen
= prev_screen
;
671 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
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
;
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
);
711 char_attr_normal
= info
.wAttributes
;
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 */
721 /* Lines per page. Use buffer coords instead of buffer size. */
722 FRAME_HEIGHT (SELECTED_FRAME ()) = 1 + info
.srWindow
.Bottom
-
724 /* Characters per line. Use buffer coords instead of buffer size. */
725 SET_FRAME_WIDTH (SELECTED_FRAME (), 1 + info
.srWindow
.Right
-
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);
747 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
752 CONSOLE_CURSOR_INFO cci
;
753 cci
.dwSize
= XFASTINT (size
);
755 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
762 pixel_to_glyph_coords (struct frame
* f
, int pix_x
, int pix_y
, int *x
, int *y
,
763 void *bounds
, int noclip
)
770 glyph_to_pixel_coords (struct window
* f
, int x
, int y
, int *pix_x
, int *pix_y
)
775 #endif /* !HAVE_NTGUI */
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
);