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
33 /* Disable features in headers that require a Window System for
35 #undef HAVE_WINDOW_SYSTEM
41 #include "termhooks.h"
43 #include "dispextern.h"
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 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
;
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. */
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). */
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. */
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. */
136 struct frame
* f
= PICK_FRAME ();
139 CONSOLE_SCREEN_BUFFER_INFO info
;
141 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
145 /* Remember that the screen buffer might be wider than the window. */
146 n
= FRAME_HEIGHT (f
) * info
.dwSize
.X
;
149 FillConsoleOutputAttribute (cur_screen
, char_attr_normal
, n
, dest
, &r
);
150 FillConsoleOutputCharacter (cur_screen
, ' ', n
, dest
, &r
);
156 static struct glyph glyph_base
[256];
157 static BOOL ceol_initialized
= FALSE
;
159 /* Clear from Cursor to end (what's "standout marker"?). */
161 clear_end_of_line (int end
)
163 if (!ceol_initialized
)
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. */
177 ins_del_lines (int vpos
, int n
)
179 int i
, nb
, save_highlight
;
183 struct frame
* f
= PICK_FRAME ();
187 scroll
.Top
= vpos
- n
;
188 scroll
.Bottom
= FRAME_HEIGHT (f
);
194 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
198 scroll
.Right
= FRAME_WIDTH (f
);
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
218 if (scroll
.Bottom
< dest
.Y
)
220 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
223 clear_end_of_line (FRAME_WIDTH (f
));
229 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
233 for (i
= nb
; i
< scroll
.Top
; i
++)
236 clear_end_of_line (FRAME_WIDTH (f
));
242 cursor_coords
.Y
= vpos
;
244 hl_mode (save_highlight
);
247 /* Changes attribute to use when drawing characters to control. */
249 hl_mode (int new_highlight
)
251 static int highlight
= 0;
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
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. */
274 reassert_line_highlight (int highlight
, int vpos
)
277 vpos
; /* pedantic compiler silencer */
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. */
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;
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 ?. */
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 */
328 /* Print the first len characters of start, cursor_coords.X adjusted
331 write_glyphs (start
, len
);
335 clear_end_of_line (cursor_coords
.X
+ len
);
340 write_glyphs (register struct glyph
*string
, register int len
)
342 int produced
, consumed
, i
;
343 struct frame
* f
= PICK_FRAME ();
349 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
351 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
355 /* Identify a run of glyphs with the same face. */
356 int face_id
= string
->face_id
;
359 for (n
= 1; n
< len
; ++n
)
360 if (string
[n
].face_id
!= face_id
)
363 /* Turn appearance modes of the face of the run on. */
364 char_attr
= w32_face_attributes (f
, face_id
);
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
,
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",
385 /* Write the characters. */
386 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
387 produced
, cursor_coords
, &i
))
389 printf ("Failed writing console characters: %d\n",
394 cursor_coords
.X
+= produced
;
395 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
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
,
415 printf ("Failed writing console attributes: %d\n",
420 /* Write the characters. */
421 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
422 produced
, cursor_coords
, &i
))
424 printf ("Failed writing console characters: %d\n",
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
440 scroll_line (n
, LEFT
);
443 static unsigned int sound_type
= 0xFFFFFFFF;
444 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
447 w32_sys_ring_bell (void)
449 if (sound_type
== 0xFFFFFFFF)
453 else if (sound_type
== MB_EMACS_SILENT
)
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.")
470 CHECK_SYMBOL (sound
, 0);
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")))
484 else if (EQ (sound
, intern ("silent")))
485 sound_type
= MB_EMACS_SILENT
;
487 sound_type
= 0xFFFFFFFF;
493 reset_terminal_modes (void)
497 #ifdef USE_SEPARATE_SCREEN
498 SetConsoleActiveScreenBuffer (prev_screen
);
500 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
502 SetConsoleMode (keyboard_handle
, prev_console_mode
);
506 set_terminal_modes (void)
508 CONSOLE_CURSOR_INFO cci
;
512 /* make cursor big and visible (100 on Win95 makes it disappear) */
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. */
531 update_begin (struct frame
* f
)
537 update_end (struct frame
* f
)
540 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
544 set_terminal_window (int size
)
548 /***********************************************************************
550 ***********************************************************************/
553 /* Turn appearances of face FACE_ID on tty frame F on. */
556 w32_face_attributes (f
, face_id
)
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))
584 if (face
->tty_reverse_p
|| highlight_on_p
)
585 char_attr
= (char_attr
& 0xff00) + ((char_attr
& 0x000f) << 4)
586 + ((char_attr
& 0x00f0) >> 4);
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. */
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
]);
614 return Qunspecified
; /* meaning the default */
617 typedef int (*term_hook
) ();
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. */
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
,
658 CONSOLE_TEXTMODE_BUFFER
,
661 if (cur_screen
== INVALID_HANDLE_VALUE
)
663 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
664 printf ("LastError = 0x%lx\n", GetLastError ());
669 cur_screen
= prev_screen
;
670 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
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
;
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
);
710 char_attr_normal
= info
.wAttributes
;
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 */
720 /* Lines per page. Use buffer coords instead of buffer size. */
721 FRAME_HEIGHT (SELECTED_FRAME ()) = 1 + info
.srWindow
.Bottom
-
723 /* Characters per line. Use buffer coords instead of buffer size. */
724 SET_FRAME_WIDTH (SELECTED_FRAME (), 1 + info
.srWindow
.Right
-
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);
741 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
746 CONSOLE_CURSOR_INFO cci
;
747 cci
.dwSize
= XFASTINT (size
);
749 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
756 pixel_to_glyph_coords (struct frame
* f
, int pix_x
, int pix_y
, int *x
, int *y
,
757 void *bounds
, int noclip
)
764 glyph_to_pixel_coords (struct frame
* f
, int x
, int y
, int *pix_x
, int *pix_y
)
769 #endif /* !HAVE_NTGUI */
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
);