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 #include "dispextern.h"
39 /* Disable features in frame.h that require a Window System. */
40 #undef HAVE_WINDOW_SYSTEM
44 #define min(a, b) ((a) < (b) ? (a) : (b))
47 extern Lisp_Object
Frecenter ();
50 extern int detect_input_pending ();
53 extern int read_input_pending ();
55 extern struct frame
* updating_frame
;
58 static void move_cursor (int row
, int col
);
59 static void clear_to_end (void);
60 static void clear_frame (void);
61 static void clear_end_of_line (int);
62 static void ins_del_lines (int vpos
, int n
);
63 static void change_line_highlight (int, int, int, int);
64 static void reassert_line_highlight (int, int);
65 static void insert_glyphs (struct glyph
*start
, int len
);
66 static void write_glyphs (struct glyph
*string
, int len
);
67 static void delete_glyphs (int n
);
68 void w32_sys_ring_bell (void);
69 static void reset_terminal_modes (void);
70 static void set_terminal_modes (void);
71 static void set_terminal_window (int size
);
72 static void update_begin (struct frame
* f
);
73 static void update_end (struct frame
* f
);
74 static WORD
w32_face_attributes (struct frame
*f
, int face_id
);
75 static int hl_mode (int new_highlight
);
77 static COORD cursor_coords
;
78 static HANDLE prev_screen
, cur_screen
;
79 static WORD char_attr_normal
;
80 static DWORD prev_console_mode
;
82 #ifndef USE_SEPARATE_SCREEN
83 static CONSOLE_CURSOR_INFO prev_console_cursor
;
86 /* Determine whether to make frame dimensions match the screen buffer,
87 or the current window size. The former is desirable when running
88 over telnet, while the latter is more useful when working directly at
89 the console with a large scroll-back buffer. */
90 int w32_use_full_screen_buffer
;
91 HANDLE keyboard_handle
;
94 /* Setting this as the ctrl handler prevents emacs from being killed when
95 someone hits ^C in a 'suspended' session (child shell).
96 Also ignore Ctrl-Break signals. */
99 ctrl_c_handler (unsigned long type
)
101 /* Only ignore "interrupt" events when running interactively. */
102 return (!noninteractive
103 && (type
== CTRL_C_EVENT
|| type
== CTRL_BREAK_EVENT
));
106 /* If we're updating a frame, use it as the current frame
107 Otherwise, use the selected frame. */
108 #define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ())
110 /* Move the cursor to (row, col). */
112 move_cursor (int row
, int col
)
114 cursor_coords
.X
= col
;
115 cursor_coords
.Y
= row
;
117 if (updating_frame
== (struct frame
*) NULL
)
119 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
123 /* Clear from cursor to end of screen. */
127 struct frame
* f
= PICK_FRAME ();
129 clear_end_of_line (FRAME_WIDTH (f
) - 1);
130 ins_del_lines (cursor_coords
.Y
, FRAME_HEIGHT (f
) - cursor_coords
.Y
- 1);
133 /* Clear the frame. */
137 struct frame
* f
= PICK_FRAME ();
141 CONSOLE_SCREEN_BUFFER_INFO info
;
143 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
147 /* Remember that the screen buffer might be wider than the window. */
148 n
= FRAME_HEIGHT (f
) * info
.dwSize
.X
;
151 FillConsoleOutputAttribute (cur_screen
, char_attr_normal
, n
, dest
, &r
);
152 FillConsoleOutputCharacter (cur_screen
, ' ', n
, dest
, &r
);
158 static struct glyph glyph_base
[256];
159 static BOOL ceol_initialized
= FALSE
;
161 /* Clear from Cursor to end (what's "standout marker"?). */
163 clear_end_of_line (int end
)
165 if (!ceol_initialized
)
168 for (i
= 0; i
< 256; i
++)
170 memcpy (&glyph_base
[i
], &space_glyph
, sizeof (struct glyph
));
172 ceol_initialized
= TRUE
;
174 write_glyphs (glyph_base
, end
- cursor_coords
.X
); /* fencepost ? */
177 /* Insert n lines at vpos. if n is negative delete -n lines. */
179 ins_del_lines (int vpos
, int n
)
181 int i
, nb
, save_highlight
;
185 struct frame
* f
= PICK_FRAME ();
189 scroll
.Top
= vpos
- n
;
190 scroll
.Bottom
= FRAME_HEIGHT (f
);
196 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
200 scroll
.Right
= FRAME_WIDTH (f
);
204 save_highlight
= hl_mode (0);
206 fill
.Char
.AsciiChar
= 0x20;
207 fill
.Attributes
= char_attr_normal
;
209 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
211 /* Here we have to deal with a w32 console flake: If the scroll
212 region looks like abc and we scroll c to a and fill with d we get
213 cbd... if we scroll block c one line at a time to a, we get cdd...
214 Emacs expects cdd consistently... So we have to deal with that
215 here... (this also occurs scrolling the same way in the other
220 if (scroll
.Bottom
< dest
.Y
)
222 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
225 clear_end_of_line (FRAME_WIDTH (f
));
231 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
235 for (i
= nb
; i
< scroll
.Top
; i
++)
238 clear_end_of_line (FRAME_WIDTH (f
));
244 cursor_coords
.Y
= vpos
;
246 hl_mode (save_highlight
);
249 /* Changes attribute to use when drawing characters to control. */
251 hl_mode (int new_highlight
)
253 static int highlight
= 0;
256 old_highlight
= highlight
;
257 highlight
= (new_highlight
!= 0);
259 return old_highlight
;
262 /* Call this when about to modify line at position VPOS and change whether it
265 change_line_highlight (int new_highlight
, int vpos
, int y
,
266 int first_unused_hpos
)
268 hl_mode (new_highlight
);
269 move_cursor (vpos
, 0);
270 clear_end_of_line (first_unused_hpos
);
273 /* External interface to control of standout mode. Call this when about to
274 * modify line at position VPOS and not change whether it is highlighted. */
276 reassert_line_highlight (int highlight
, int vpos
)
279 vpos
; /* pedantic compiler silencer */
288 scroll_line (int dist
, int direction
)
290 /* The idea here is to implement a horizontal scroll in one line to
291 implement delete and half of insert. */
295 struct frame
* f
= PICK_FRAME ();
297 scroll
.Top
= cursor_coords
.Y
;
298 scroll
.Bottom
= cursor_coords
.Y
;
300 if (direction
== LEFT
)
302 scroll
.Left
= cursor_coords
.X
+ dist
;
303 scroll
.Right
= FRAME_WIDTH (f
) - 1;
307 scroll
.Left
= cursor_coords
.X
;
308 scroll
.Right
= FRAME_WIDTH (f
) - dist
- 1;
311 dest
.X
= cursor_coords
.X
;
312 dest
.Y
= cursor_coords
.Y
;
314 fill
.Char
.AsciiChar
= 0x20;
315 fill
.Attributes
= char_attr_normal
;
317 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
321 /* If start is zero insert blanks instead of a string at start ?. */
323 insert_glyphs (register struct glyph
*start
, register int len
)
325 scroll_line (len
, RIGHT
);
327 /* Move len chars to the right starting at cursor_coords, fill with blanks */
330 /* Print the first len characters of start, cursor_coords.X adjusted
333 write_glyphs (start
, len
);
337 clear_end_of_line (cursor_coords
.X
+ len
);
342 write_glyphs (register struct glyph
*string
, register int len
)
344 int produced
, consumed
;
346 struct frame
* f
= PICK_FRAME ();
348 unsigned char conversion_buffer
[1024];
349 int conversion_buffer_size
= sizeof conversion_buffer
;
354 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
356 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
360 /* Identify a run of glyphs with the same face. */
361 int face_id
= string
->face_id
;
364 for (n
= 1; n
< len
; ++n
)
365 if (string
[n
].face_id
!= face_id
)
368 /* Turn appearance modes of the face of the run on. */
369 char_attr
= w32_face_attributes (f
, face_id
);
373 /* We use a fixed size (1024 bytes) of conversion buffer.
374 Usually it is sufficient, but if not, we just repeat the
376 produced
= encode_terminal_code (string
, conversion_buffer
,
377 n
, conversion_buffer_size
,
381 /* Set the attribute for these characters. */
382 if (!FillConsoleOutputAttribute (cur_screen
, char_attr
,
383 produced
, cursor_coords
, &r
))
385 printf ("Failed writing console attributes: %d\n",
390 /* Write the characters. */
391 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
392 produced
, cursor_coords
, &r
))
394 printf ("Failed writing console characters: %d\n",
399 cursor_coords
.X
+= produced
;
400 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
408 /* We may have to output some codes to terminate the writing. */
409 if (CODING_REQUIRE_FLUSHING (&terminal_coding
))
411 terminal_coding
.mode
|= CODING_MODE_LAST_BLOCK
;
412 encode_coding (&terminal_coding
, "", conversion_buffer
,
413 0, conversion_buffer_size
);
414 if (terminal_coding
.produced
> 0)
416 if (!FillConsoleOutputAttribute (cur_screen
, char_attr_normal
,
417 terminal_coding
.produced
,
420 printf ("Failed writing console attributes: %d\n",
425 /* Write the characters. */
426 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
427 produced
, cursor_coords
, &r
))
429 printf ("Failed writing console characters: %d\n",
439 delete_glyphs (int n
)
441 /* delete chars means scroll chars from cursor_coords.X + n to
442 cursor_coords.X, anything beyond the edge of the screen should
445 scroll_line (n
, LEFT
);
448 static unsigned int sound_type
= 0xFFFFFFFF;
449 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
452 w32_sys_ring_bell (void)
454 if (sound_type
== 0xFFFFFFFF)
458 else if (sound_type
== MB_EMACS_SILENT
)
463 MessageBeep (sound_type
);
466 DEFUN ("set-message-beep", Fset_message_beep
, Sset_message_beep
, 1, 1, 0,
467 "Set the sound generated when the bell is rung.\n\
468 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
469 to use the corresponding system sound for the bell. The 'silent sound\n\
470 prevents Emacs from making any sound at all.\n\
471 SOUND is nil to use the normal beep.")
475 CHECK_SYMBOL (sound
, 0);
478 sound_type
= 0xFFFFFFFF;
479 else if (EQ (sound
, intern ("asterisk")))
480 sound_type
= MB_ICONASTERISK
;
481 else if (EQ (sound
, intern ("exclamation")))
482 sound_type
= MB_ICONEXCLAMATION
;
483 else if (EQ (sound
, intern ("hand")))
484 sound_type
= MB_ICONHAND
;
485 else if (EQ (sound
, intern ("question")))
486 sound_type
= MB_ICONQUESTION
;
487 else if (EQ (sound
, intern ("ok")))
489 else if (EQ (sound
, intern ("silent")))
490 sound_type
= MB_EMACS_SILENT
;
492 sound_type
= 0xFFFFFFFF;
498 reset_terminal_modes (void)
502 #ifdef USE_SEPARATE_SCREEN
503 SetConsoleActiveScreenBuffer (prev_screen
);
505 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
507 SetConsoleMode (keyboard_handle
, prev_console_mode
);
511 set_terminal_modes (void)
513 CONSOLE_CURSOR_INFO cci
;
517 /* make cursor big and visible (100 on Win95 makes it disappear) */
520 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
522 SetConsoleActiveScreenBuffer (cur_screen
);
524 SetConsoleMode (keyboard_handle
, ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
);
526 /* Initialize input mode: interrupt_input off, no flow control, allow
527 8 bit character input, standard quit char. */
528 Fset_input_mode (Qnil
, Qnil
, make_number (2), Qnil
);
531 /* hmmm... perhaps these let us bracket screen changes so that we can flush
532 clumps rather than one-character-at-a-time...
534 we'll start with not moving the cursor while an update is in progress. */
536 update_begin (struct frame
* f
)
542 update_end (struct frame
* f
)
545 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
549 set_terminal_window (int size
)
553 /***********************************************************************
555 ***********************************************************************/
558 /* Turn appearances of face FACE_ID on tty frame F on. */
561 w32_face_attributes (f
, face_id
)
567 struct face
*face
= FACE_FROM_ID (f
, face_id
);
569 highlight_on_p
= hl_mode (0);
570 hl_mode (highlight_on_p
);
572 xassert (face
!= NULL
);
574 char_attr
= char_attr_normal
;
576 if (face
->foreground
!= FACE_TTY_DEFAULT_FG_COLOR
577 && face
->foreground
!= FACE_TTY_DEFAULT_COLOR
)
578 char_attr
= (char_attr
& 0xfff0) + (face
->foreground
% 16);
580 if (face
->background
!= FACE_TTY_DEFAULT_BG_COLOR
581 && face
->background
!= FACE_TTY_DEFAULT_COLOR
)
582 char_attr
= (char_attr
& 0xff0f) + ((face
->background
% 16) << 4);
585 /* NTEMACS_TODO: Faces defined during startup get both foreground
586 and background of 0. Need a better way around this - for now detect
587 the problem and invert one of the faces to make the text readable. */
588 if (((char_attr
& 0x00f0) >> 4) == (char_attr
& 0x000f))
591 if (face
->tty_reverse_p
|| highlight_on_p
)
592 char_attr
= (char_attr
& 0xff00) + ((char_attr
& 0x000f) << 4)
593 + ((char_attr
& 0x00f0) >> 4);
599 /* Emulation of some X window features from xfns.c and xfaces.c. */
601 extern char unspecified_fg
[], unspecified_bg
[];
604 /* Given a color index, return its standard name. */
606 vga_stdcolor_name (int idx
)
608 /* Standard VGA colors, in the order of their standard numbering
609 in the default VGA palette. */
610 static char *vga_colors
[16] = {
611 "black", "blue", "green", "cyan", "red", "magenta", "brown",
612 "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
613 "lightred", "lightmagenta", "yellow", "white"
616 extern Lisp_Object Qunspecified
;
618 if (idx
>= 0 && idx
< sizeof (vga_colors
) / sizeof (vga_colors
[0]))
619 return build_string (vga_colors
[idx
]);
621 return Qunspecified
; /* meaning the default */
624 typedef int (*term_hook
) ();
627 initialize_w32_display (void)
629 CONSOLE_SCREEN_BUFFER_INFO info
;
631 cursor_to_hook
= move_cursor
;
632 raw_cursor_to_hook
= move_cursor
;
633 clear_to_end_hook
= clear_to_end
;
634 clear_frame_hook
= clear_frame
;
635 clear_end_of_line_hook
= clear_end_of_line
;
636 ins_del_lines_hook
= ins_del_lines
;
637 change_line_highlight_hook
= change_line_highlight
;
638 reassert_line_highlight_hook
= reassert_line_highlight
;
639 insert_glyphs_hook
= insert_glyphs
;
640 write_glyphs_hook
= write_glyphs
;
641 delete_glyphs_hook
= delete_glyphs
;
642 ring_bell_hook
= w32_sys_ring_bell
;
643 reset_terminal_modes_hook
= reset_terminal_modes
;
644 set_terminal_modes_hook
= set_terminal_modes
;
645 set_terminal_window_hook
= set_terminal_window
;
646 update_begin_hook
= update_begin
;
647 update_end_hook
= update_end
;
649 read_socket_hook
= w32_console_read_socket
;
650 mouse_position_hook
= w32_console_mouse_position
;
651 estimate_mode_line_height_hook
= 0;
653 /* Initialize interrupt_handle. */
656 /* Remember original console settings. */
657 keyboard_handle
= GetStdHandle (STD_INPUT_HANDLE
);
658 GetConsoleMode (keyboard_handle
, &prev_console_mode
);
660 prev_screen
= GetStdHandle (STD_OUTPUT_HANDLE
);
662 #ifdef USE_SEPARATE_SCREEN
663 cur_screen
= CreateConsoleScreenBuffer (GENERIC_READ
| GENERIC_WRITE
,
665 CONSOLE_TEXTMODE_BUFFER
,
668 if (cur_screen
== INVALID_HANDLE_VALUE
)
670 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
671 printf ("LastError = 0x%lx\n", GetLastError ());
676 cur_screen
= prev_screen
;
677 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
680 /* Respect setting of LINES and COLUMNS environment variables. */
682 char * lines
= getenv("LINES");
683 char * columns
= getenv("COLUMNS");
685 if (lines
!= NULL
&& columns
!= NULL
)
687 SMALL_RECT new_win_dims
;
690 new_size
.X
= atoi (columns
);
691 new_size
.Y
= atoi (lines
);
693 GetConsoleScreenBufferInfo (cur_screen
, &info
);
695 /* Shrink the window first, so the buffer dimensions can be
696 reduced if necessary. */
697 new_win_dims
.Top
= 0;
698 new_win_dims
.Left
= 0;
699 new_win_dims
.Bottom
= min (new_size
.Y
, info
.dwSize
.Y
) - 1;
700 new_win_dims
.Right
= min (new_size
.X
, info
.dwSize
.X
) - 1;
701 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
703 SetConsoleScreenBufferSize (cur_screen
, new_size
);
705 /* Set the window size to match the buffer dimension. */
706 new_win_dims
.Top
= 0;
707 new_win_dims
.Left
= 0;
708 new_win_dims
.Bottom
= new_size
.Y
- 1;
709 new_win_dims
.Right
= new_size
.X
- 1;
710 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
714 GetConsoleScreenBufferInfo (cur_screen
, &info
);
717 char_attr_normal
= info
.wAttributes
;
720 if (w32_use_full_screen_buffer
)
722 FRAME_HEIGHT (SELECTED_FRAME ()) = info
.dwSize
.Y
; /* lines per page */
723 SET_FRAME_WIDTH (SELECTED_FRAME (), info
.dwSize
.X
); /* characters per line */
727 /* Lines per page. Use buffer coords instead of buffer size. */
728 FRAME_HEIGHT (SELECTED_FRAME ()) = 1 + info
.srWindow
.Bottom
-
730 /* Characters per line. Use buffer coords instead of buffer size. */
731 SET_FRAME_WIDTH (SELECTED_FRAME (), 1 + info
.srWindow
.Right
-
735 /* Setup w32_display_info structure for this frame. */
737 w32_initialize_display_info (build_string ("Console"));
741 DEFUN ("set-screen-color", Fset_screen_color
, Sset_screen_color
, 2, 2, 0,
742 "Set screen colors.")
743 (foreground
, background
)
744 Lisp_Object foreground
;
745 Lisp_Object background
;
747 char_attr_normal
= XFASTINT (foreground
) + (XFASTINT (background
) << 4);
753 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
758 CONSOLE_CURSOR_INFO cci
;
759 cci
.dwSize
= XFASTINT (size
);
761 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
768 pixel_to_glyph_coords (struct frame
* f
, int pix_x
, int pix_y
, int *x
, int *y
,
769 void *bounds
, int noclip
)
776 glyph_to_pixel_coords (struct window
* f
, int x
, int y
, int *pix_x
, int *pix_y
)
781 #endif /* !HAVE_NTGUI */
786 DEFVAR_BOOL ("w32-use-full-screen-buffer",
787 &w32_use_full_screen_buffer
,
788 "Non-nil means make terminal frames use the full screen buffer dimensions.\n\
789 This is desirable when running Emacs over telnet, and is the default.\n\
790 A value of nil means use the current console window dimensions; this\n\
791 may be preferrable when working directly at the console with a large\n\
792 scroll-back buffer.");
793 w32_use_full_screen_buffer
= 1;
795 defsubr (&Sset_screen_color
);
796 defsubr (&Sset_cursor_size
);
797 defsubr (&Sset_message_beep
);