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 ();
348 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
350 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
354 /* Identify a run of glyphs with the same face. */
355 int face_id
= string
->face_id
;
358 for (n
= 1; n
< len
; ++n
)
359 if (string
[n
].face_id
!= face_id
)
362 /* Turn appearance modes of the face of the run on. */
363 char_attr
= w32_face_attributes (f
, face_id
);
367 /* We use a shared conversion buffer of the current size
368 (1024 bytes at least). Usually it is sufficient, but if
369 not, we just repeat the loop. */
370 produced
= encode_terminal_code (string
, conversion_buffer
,
371 n
, conversion_buffer_size
,
375 /* Set the attribute for these characters. */
376 if (!FillConsoleOutputAttribute (cur_screen
, char_attr
,
377 produced
, cursor_coords
, &i
))
379 printf ("Failed writing console attributes: %d\n",
384 /* Write the characters. */
385 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
386 produced
, cursor_coords
, &i
))
388 printf ("Failed writing console characters: %d\n",
393 cursor_coords
.X
+= produced
;
394 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
402 /* We may have to output some codes to terminate the writing. */
403 if (CODING_REQUIRE_FLUSHING (&terminal_coding
))
405 terminal_coding
.mode
|= CODING_MODE_LAST_BLOCK
;
406 encode_coding (&terminal_coding
, "", conversion_buffer
,
407 0, conversion_buffer_size
);
408 if (terminal_coding
.produced
> 0)
410 if (!FillConsoleOutputAttribute (cur_screen
, char_attr_normal
,
411 terminal_coding
.produced
,
414 printf ("Failed writing console attributes: %d\n",
419 /* Write the characters. */
420 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
421 produced
, cursor_coords
, &i
))
423 printf ("Failed writing console characters: %d\n",
433 delete_glyphs (int n
)
435 /* delete chars means scroll chars from cursor_coords.X + n to
436 cursor_coords.X, anything beyond the edge of the screen should
439 scroll_line (n
, LEFT
);
442 static unsigned int sound_type
= 0xFFFFFFFF;
443 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
446 w32_sys_ring_bell (void)
448 if (sound_type
== 0xFFFFFFFF)
452 else if (sound_type
== MB_EMACS_SILENT
)
457 MessageBeep (sound_type
);
460 DEFUN ("set-message-beep", Fset_message_beep
, Sset_message_beep
, 1, 1, 0,
461 "Set the sound generated when the bell is rung.\n\
462 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
463 to use the corresponding system sound for the bell. The 'silent sound\n\
464 prevents Emacs from making any sound at all.\n\
465 SOUND is nil to use the normal beep.")
469 CHECK_SYMBOL (sound
, 0);
472 sound_type
= 0xFFFFFFFF;
473 else if (EQ (sound
, intern ("asterisk")))
474 sound_type
= MB_ICONASTERISK
;
475 else if (EQ (sound
, intern ("exclamation")))
476 sound_type
= MB_ICONEXCLAMATION
;
477 else if (EQ (sound
, intern ("hand")))
478 sound_type
= MB_ICONHAND
;
479 else if (EQ (sound
, intern ("question")))
480 sound_type
= MB_ICONQUESTION
;
481 else if (EQ (sound
, intern ("ok")))
483 else if (EQ (sound
, intern ("silent")))
484 sound_type
= MB_EMACS_SILENT
;
486 sound_type
= 0xFFFFFFFF;
492 reset_terminal_modes (void)
496 #ifdef USE_SEPARATE_SCREEN
497 SetConsoleActiveScreenBuffer (prev_screen
);
499 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
501 SetConsoleMode (keyboard_handle
, prev_console_mode
);
505 set_terminal_modes (void)
507 CONSOLE_CURSOR_INFO cci
;
511 /* make cursor big and visible (100 on Win95 makes it disappear) */
514 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
516 SetConsoleActiveScreenBuffer (cur_screen
);
518 SetConsoleMode (keyboard_handle
, ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
);
520 /* Initialize input mode: interrupt_input off, no flow control, allow
521 8 bit character input, standard quit char. */
522 Fset_input_mode (Qnil
, Qnil
, make_number (2), Qnil
);
525 /* hmmm... perhaps these let us bracket screen changes so that we can flush
526 clumps rather than one-character-at-a-time...
528 we'll start with not moving the cursor while an update is in progress. */
530 update_begin (struct frame
* f
)
536 update_end (struct frame
* f
)
539 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
543 set_terminal_window (int size
)
547 /***********************************************************************
549 ***********************************************************************/
552 /* Turn appearances of face FACE_ID on tty frame F on. */
555 w32_face_attributes (f
, face_id
)
561 struct face
*face
= FACE_FROM_ID (f
, face_id
);
563 highlight_on_p
= hl_mode (0);
564 hl_mode (highlight_on_p
);
566 xassert (face
!= NULL
);
568 char_attr
= char_attr_normal
;
570 if (face
->foreground
!= FACE_TTY_DEFAULT_FG_COLOR
571 && face
->foreground
!= FACE_TTY_DEFAULT_COLOR
)
572 char_attr
= (char_attr
& 0xfff0) + (face
->foreground
% 16);
574 if (face
->background
!= FACE_TTY_DEFAULT_BG_COLOR
575 && face
->background
!= FACE_TTY_DEFAULT_COLOR
)
576 char_attr
= (char_attr
& 0xff0f) + ((face
->background
% 16) * 16);
579 /* Ensure readability (temporary measure until this all works) */
580 if (((char_attr
& 0x00f0) >> 4) == (char_attr
& 0x000f))
583 if (face
->tty_reverse_p
|| highlight_on_p
)
584 char_attr
= (char_attr
& 0xff00) + ((char_attr
& 0x000f) << 4)
585 + ((char_attr
& 0x00f0) >> 4);
591 /* Emulation of some X window features from xfns.c and xfaces.c. */
593 extern char unspecified_fg
[], unspecified_bg
[];
596 /* Given a color index, return its standard name. */
598 vga_stdcolor_name (int idx
)
600 /* Standard VGA colors, in the order of their standard numbering
601 in the default VGA palette. */
602 static char *vga_colors
[16] = {
603 "black", "blue", "green", "cyan", "red", "magenta", "brown",
604 "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan",
605 "lightred", "lightmagenta", "yellow", "white"
608 extern Lisp_Object Qunspecified
;
610 if (idx
>= 0 && idx
< sizeof (vga_colors
) / sizeof (vga_colors
[0]))
611 return build_string (vga_colors
[idx
]);
613 return Qunspecified
; /* meaning the default */
616 typedef int (*term_hook
) ();
619 initialize_w32_display (void)
621 CONSOLE_SCREEN_BUFFER_INFO info
;
623 cursor_to_hook
= move_cursor
;
624 raw_cursor_to_hook
= move_cursor
;
625 clear_to_end_hook
= clear_to_end
;
626 clear_frame_hook
= clear_frame
;
627 clear_end_of_line_hook
= clear_end_of_line
;
628 ins_del_lines_hook
= ins_del_lines
;
629 change_line_highlight_hook
= change_line_highlight
;
630 reassert_line_highlight_hook
= reassert_line_highlight
;
631 insert_glyphs_hook
= insert_glyphs
;
632 write_glyphs_hook
= write_glyphs
;
633 delete_glyphs_hook
= delete_glyphs
;
634 ring_bell_hook
= w32_sys_ring_bell
;
635 reset_terminal_modes_hook
= reset_terminal_modes
;
636 set_terminal_modes_hook
= set_terminal_modes
;
637 set_terminal_window_hook
= set_terminal_window
;
638 update_begin_hook
= update_begin
;
639 update_end_hook
= update_end
;
641 read_socket_hook
= w32_console_read_socket
;
642 mouse_position_hook
= w32_console_mouse_position
;
643 estimate_mode_line_height_hook
= 0;
645 /* Initialize interrupt_handle. */
648 /* Remember original console settings. */
649 keyboard_handle
= GetStdHandle (STD_INPUT_HANDLE
);
650 GetConsoleMode (keyboard_handle
, &prev_console_mode
);
652 prev_screen
= GetStdHandle (STD_OUTPUT_HANDLE
);
654 #ifdef USE_SEPARATE_SCREEN
655 cur_screen
= CreateConsoleScreenBuffer (GENERIC_READ
| GENERIC_WRITE
,
657 CONSOLE_TEXTMODE_BUFFER
,
660 if (cur_screen
== INVALID_HANDLE_VALUE
)
662 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
663 printf ("LastError = 0x%lx\n", GetLastError ());
668 cur_screen
= prev_screen
;
669 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
672 /* Respect setting of LINES and COLUMNS environment variables. */
674 char * lines
= getenv("LINES");
675 char * columns
= getenv("COLUMNS");
677 if (lines
!= NULL
&& columns
!= NULL
)
679 SMALL_RECT new_win_dims
;
682 new_size
.X
= atoi (columns
);
683 new_size
.Y
= atoi (lines
);
685 GetConsoleScreenBufferInfo (cur_screen
, &info
);
687 /* Shrink the window first, so the buffer dimensions can be
688 reduced if necessary. */
689 new_win_dims
.Top
= 0;
690 new_win_dims
.Left
= 0;
691 new_win_dims
.Bottom
= min (new_size
.Y
, info
.dwSize
.Y
) - 1;
692 new_win_dims
.Right
= min (new_size
.X
, info
.dwSize
.X
) - 1;
693 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
695 SetConsoleScreenBufferSize (cur_screen
, new_size
);
697 /* Set the window size to match the buffer dimension. */
698 new_win_dims
.Top
= 0;
699 new_win_dims
.Left
= 0;
700 new_win_dims
.Bottom
= new_size
.Y
- 1;
701 new_win_dims
.Right
= new_size
.X
- 1;
702 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
706 GetConsoleScreenBufferInfo (cur_screen
, &info
);
709 char_attr_normal
= info
.wAttributes
;
712 if (w32_use_full_screen_buffer
)
714 FRAME_HEIGHT (SELECTED_FRAME ()) = info
.dwSize
.Y
; /* lines per page */
715 SET_FRAME_WIDTH (SELECTED_FRAME (), info
.dwSize
.X
); /* characters per line */
719 /* Lines per page. Use buffer coords instead of buffer size. */
720 FRAME_HEIGHT (SELECTED_FRAME ()) = 1 + info
.srWindow
.Bottom
-
722 /* Characters per line. Use buffer coords instead of buffer size. */
723 SET_FRAME_WIDTH (SELECTED_FRAME (), 1 + info
.srWindow
.Right
-
727 /* Setup w32_display_info structure for this frame. */
729 w32_initialize_display_info (build_string ("Console"));
733 DEFUN ("set-screen-color", Fset_screen_color
, Sset_screen_color
, 2, 2, 0,
734 "Set screen colors.")
735 (foreground
, background
)
736 Lisp_Object foreground
;
737 Lisp_Object background
;
739 char_attr_normal
= XFASTINT (foreground
) + (XFASTINT (background
) << 4);
745 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
750 CONSOLE_CURSOR_INFO cci
;
751 cci
.dwSize
= XFASTINT (size
);
753 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
760 pixel_to_glyph_coords (struct frame
* f
, int pix_x
, int pix_y
, int *x
, int *y
,
761 void *bounds
, int noclip
)
768 glyph_to_pixel_coords (struct window
* f
, int x
, int y
, int *pix_x
, int *pix_y
)
773 #endif /* !HAVE_NTGUI */
778 DEFVAR_BOOL ("w32-use-full-screen-buffer",
779 &w32_use_full_screen_buffer
,
780 "Non-nil means make terminal frames use the full screen buffer dimensions.\n\
781 This is desirable when running Emacs over telnet, and is the default.\n\
782 A value of nil means use the current console window dimensions; this\n\
783 may be preferrable when working directly at the console with a large\n\
784 scroll-back buffer.");
785 w32_use_full_screen_buffer
= 1;
787 defsubr (&Sset_screen_color
);
788 defsubr (&Sset_cursor_size
);
789 defsubr (&Sset_message_beep
);