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
32 /* Disable features in headers that require a Window System for
34 #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 int hl_mode (int new_highlight
);
74 static void turn_on_face
P_ ((struct frame
*, int face_id
));
75 static void turn_off_face
P_ ((struct frame
*, int face_id
));
78 HANDLE prev_screen
, cur_screen
;
79 UCHAR char_attr
, char_attr_normal
, char_attr_reverse
;
80 HANDLE keyboard_handle
;
81 DWORD prev_console_mode
;
83 #ifndef USE_SEPARATE_SCREEN
84 CONSOLE_CURSOR_INFO prev_console_cursor
;
87 /* Determine whether to make frame dimensions match the screen buffer,
88 or the current window size. The former is desirable when running
89 over telnet, while the latter is more useful when working directly at
90 the console with a large scroll-back buffer. */
91 int w32_use_full_screen_buffer
;
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 ();
140 CONSOLE_SCREEN_BUFFER_INFO info
;
142 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
146 /* Remember that the screen buffer might be wider than the window. */
147 n
= FRAME_HEIGHT (f
) * info
.dwSize
.X
;
150 FillConsoleOutputAttribute (cur_screen
, char_attr
, n
, dest
, &r
);
151 FillConsoleOutputCharacter (cur_screen
, ' ', n
, dest
, &r
);
157 static struct glyph glyph_base
[256];
158 static BOOL ceol_initialized
= FALSE
;
160 /* Clear from Cursor to end (what's "standout marker"?). */
162 clear_end_of_line (int end
)
164 if (!ceol_initialized
)
167 for (i
= 0; i
< 256; i
++)
169 memcpy (&glyph_base
[i
], &space_glyph
, sizeof (struct glyph
));
171 ceol_initialized
= TRUE
;
173 write_glyphs (glyph_base
, end
- cursor_coords
.X
); /* fencepost ? */
176 /* Insert n lines at vpos. if n is negative delete -n lines. */
178 ins_del_lines (int vpos
, int n
)
180 int i
, nb
, save_highlight
;
184 struct frame
* f
= PICK_FRAME ();
188 scroll
.Top
= vpos
- n
;
189 scroll
.Bottom
= FRAME_HEIGHT (f
);
195 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
199 scroll
.Right
= FRAME_WIDTH (f
);
203 save_highlight
= hl_mode (0);
205 fill
.Char
.AsciiChar
= 0x20;
206 fill
.Attributes
= char_attr
;
208 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
210 /* Here we have to deal with a w32 console flake: If the scroll
211 region looks like abc and we scroll c to a and fill with d we get
212 cbd... if we scroll block c one line at a time to a, we get cdd...
213 Emacs expects cdd consistently... So we have to deal with that
214 here... (this also occurs scrolling the same way in the other
219 if (scroll
.Bottom
< dest
.Y
)
221 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
224 clear_end_of_line (FRAME_WIDTH (f
));
230 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
234 for (i
= nb
; i
< scroll
.Top
; i
++)
237 clear_end_of_line (FRAME_WIDTH (f
));
243 cursor_coords
.Y
= vpos
;
245 hl_mode (save_highlight
);
248 /* Changes attribute to use when drawing characters to control. */
250 hl_mode (int new_highlight
)
252 static int highlight
= 0;
255 old_highlight
= highlight
;
256 highlight
= (new_highlight
!= 0);
259 char_attr
= char_attr_reverse
;
263 char_attr
= char_attr_normal
;
265 return old_highlight
;
268 /* Call this when about to modify line at position VPOS and change whether it
271 change_line_highlight (int new_highlight
, int vpos
, int y
,
272 int first_unused_hpos
)
274 hl_mode (new_highlight
);
275 move_cursor (vpos
, 0);
276 clear_end_of_line (first_unused_hpos
);
279 /* External interface to control of standout mode. Call this when about to
280 * modify line at position VPOS and not change whether it is highlighted. */
282 reassert_line_highlight (int highlight
, int vpos
)
285 vpos
; /* pedantic compiler silencer */
294 scroll_line (int dist
, int direction
)
296 /* The idea here is to implement a horizontal scroll in one line to
297 implement delete and half of insert. */
301 struct frame
* f
= PICK_FRAME ();
303 scroll
.Top
= cursor_coords
.Y
;
304 scroll
.Bottom
= cursor_coords
.Y
;
306 if (direction
== LEFT
)
308 scroll
.Left
= cursor_coords
.X
+ dist
;
309 scroll
.Right
= FRAME_WIDTH (f
) - 1;
313 scroll
.Left
= cursor_coords
.X
;
314 scroll
.Right
= FRAME_WIDTH (f
) - dist
- 1;
317 dest
.X
= cursor_coords
.X
;
318 dest
.Y
= cursor_coords
.Y
;
320 fill
.Char
.AsciiChar
= 0x20;
321 fill
.Attributes
= char_attr
;
323 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
327 /* If start is zero insert blanks instead of a string at start ?. */
329 insert_glyphs (register struct glyph
*start
, register int len
)
331 scroll_line (len
, RIGHT
);
333 /* Move len chars to the right starting at cursor_coords, fill with blanks */
336 /* Print the first len characters of start, cursor_coords.X adjusted
339 write_glyphs (start
, len
);
343 clear_end_of_line (cursor_coords
.X
+ len
);
348 write_glyphs (register struct glyph
*string
, register int len
)
350 int produced
, consumed
, i
;
351 struct frame
* f
= PICK_FRAME ();
353 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
355 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
359 /* Identify a run of glyphs with the same face. */
360 int face_id
= string
->face_id
;
363 for (n
= 1; n
< len
; ++n
)
364 if (string
[n
].face_id
!= face_id
)
367 /* Turn appearance modes of the face of the run on. */
368 turn_on_face (f
, face_id
);
372 /* We use a shared conversion buffer of the current size
373 (1024 bytes at least). Usually it is sufficient, but if
374 not, we just repeat the loop. */
375 produced
= encode_terminal_code (string
, conversion_buffer
,
376 n
, conversion_buffer_size
,
380 /* Set the attribute for these characters. */
381 if (!FillConsoleOutputAttribute (cur_screen
, char_attr
,
382 produced
, cursor_coords
, &i
))
384 printf ("Failed writing console attributes: %d\n",
389 /* Write the characters. */
390 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
391 produced
, cursor_coords
, &i
))
393 printf ("Failed writing console characters: %d\n",
398 cursor_coords
.X
+= produced
;
399 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
406 /* Turn appearance modes off. */
407 turn_off_face (f
, face_id
);
410 /* We may have to output some codes to terminate the writing. */
411 if (CODING_REQUIRE_FLUSHING (&terminal_coding
))
413 terminal_coding
.mode
|= CODING_MODE_LAST_BLOCK
;
414 encode_coding (&terminal_coding
, "", conversion_buffer
,
415 0, conversion_buffer_size
);
416 if (terminal_coding
.produced
> 0)
418 if (!FillConsoleOutputAttribute (cur_screen
, char_attr
,
419 terminal_coding
.produced
,
422 printf ("Failed writing console attributes: %d\n",
427 /* Write the characters. */
428 if (!WriteConsoleOutputCharacter (cur_screen
, conversion_buffer
,
429 produced
, cursor_coords
, &i
))
431 printf ("Failed writing console characters: %d\n",
441 delete_glyphs (int n
)
443 /* delete chars means scroll chars from cursor_coords.X + n to
444 cursor_coords.X, anything beyond the edge of the screen should
447 scroll_line (n
, LEFT
);
450 static unsigned int sound_type
= 0xFFFFFFFF;
451 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
454 w32_sys_ring_bell (void)
456 if (sound_type
== 0xFFFFFFFF)
460 else if (sound_type
== MB_EMACS_SILENT
)
465 MessageBeep (sound_type
);
468 DEFUN ("set-message-beep", Fset_message_beep
, Sset_message_beep
, 1, 1, 0,
469 "Set the sound generated when the bell is rung.\n\
470 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
471 to use the corresponding system sound for the bell. The 'silent sound\n\
472 prevents Emacs from making any sound at all.\n\
473 SOUND is nil to use the normal beep.")
477 CHECK_SYMBOL (sound
, 0);
480 sound_type
= 0xFFFFFFFF;
481 else if (EQ (sound
, intern ("asterisk")))
482 sound_type
= MB_ICONASTERISK
;
483 else if (EQ (sound
, intern ("exclamation")))
484 sound_type
= MB_ICONEXCLAMATION
;
485 else if (EQ (sound
, intern ("hand")))
486 sound_type
= MB_ICONHAND
;
487 else if (EQ (sound
, intern ("question")))
488 sound_type
= MB_ICONQUESTION
;
489 else if (EQ (sound
, intern ("ok")))
491 else if (EQ (sound
, intern ("silent")))
492 sound_type
= MB_EMACS_SILENT
;
494 sound_type
= 0xFFFFFFFF;
500 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
;
515 /* make cursor big and visible (100 on Win95 makes it disappear) */
518 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
520 SetConsoleActiveScreenBuffer (cur_screen
);
522 SetConsoleMode (keyboard_handle
, ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
);
524 /* Initialize input mode: interrupt_input off, no flow control, allow
525 8 bit character input, standard quit char. */
526 Fset_input_mode (Qnil
, Qnil
, make_number (2), Qnil
);
529 /* hmmm... perhaps these let us bracket screen changes so that we can flush
530 clumps rather than one-character-at-a-time...
532 we'll start with not moving the cursor while an update is in progress. */
534 update_begin (struct frame
* f
)
539 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 turn_on_face (f
, face_id
)
561 struct face
*face
= FACE_FROM_ID (f
, face_id
);
563 xassert (face
!= NULL
);
565 char_attr
= char_attr_normal
;
567 if (face
->foreground
!= FACE_TTY_DEFAULT_COLOR
)
568 char_attr
= (char_attr
& 0xf0) + face
->foreground
;
570 if (face
->background
!= FACE_TTY_DEFAULT_COLOR
)
571 char_attr
= (face
->background
<< 4) + char_attr
& 0x0f;
573 if (face
->tty_reverse_p
)
574 char_attr
= ((char_attr
& 0x0f) << 4) + ((char_attr
& 0xf0) >> 4);
576 /* Ensure readability */
577 if (((char_attr
& 0xf0) >> 4) == (char_attr
* 0x0f))
582 /* Turn off appearances of face FACE_ID on tty frame F. */
585 turn_off_face (f
, face_id
)
593 typedef int (*term_hook
) ();
596 initialize_w32_display (void)
598 CONSOLE_SCREEN_BUFFER_INFO info
;
600 cursor_to_hook
= move_cursor
;
601 raw_cursor_to_hook
= move_cursor
;
602 clear_to_end_hook
= clear_to_end
;
603 clear_frame_hook
= clear_frame
;
604 clear_end_of_line_hook
= clear_end_of_line
;
605 ins_del_lines_hook
= ins_del_lines
;
606 change_line_highlight_hook
= change_line_highlight
;
607 reassert_line_highlight_hook
= reassert_line_highlight
;
608 insert_glyphs_hook
= insert_glyphs
;
609 write_glyphs_hook
= write_glyphs
;
610 delete_glyphs_hook
= delete_glyphs
;
611 ring_bell_hook
= w32_sys_ring_bell
;
612 reset_terminal_modes_hook
= reset_terminal_modes
;
613 set_terminal_modes_hook
= set_terminal_modes
;
614 set_terminal_window_hook
= set_terminal_window
;
615 update_begin_hook
= update_begin
;
616 update_end_hook
= update_end
;
618 read_socket_hook
= w32_console_read_socket
;
619 mouse_position_hook
= w32_console_mouse_position
;
620 estimate_mode_line_height_hook
= 0;
622 /* Initialize interrupt_handle. */
625 /* Remember original console settings. */
626 keyboard_handle
= GetStdHandle (STD_INPUT_HANDLE
);
627 GetConsoleMode (keyboard_handle
, &prev_console_mode
);
629 prev_screen
= GetStdHandle (STD_OUTPUT_HANDLE
);
631 #ifdef USE_SEPARATE_SCREEN
632 cur_screen
= CreateConsoleScreenBuffer (GENERIC_READ
| GENERIC_WRITE
,
634 CONSOLE_TEXTMODE_BUFFER
,
637 if (cur_screen
== INVALID_HANDLE_VALUE
)
639 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
640 printf ("LastError = 0x%lx\n", GetLastError ());
645 cur_screen
= prev_screen
;
646 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
649 /* Respect setting of LINES and COLUMNS environment variables. */
651 char * lines
= getenv("LINES");
652 char * columns
= getenv("COLUMNS");
654 if (lines
!= NULL
&& columns
!= NULL
)
656 SMALL_RECT new_win_dims
;
659 new_size
.X
= atoi (columns
);
660 new_size
.Y
= atoi (lines
);
662 GetConsoleScreenBufferInfo (cur_screen
, &info
);
664 /* Shrink the window first, so the buffer dimensions can be
665 reduced if necessary. */
666 new_win_dims
.Top
= 0;
667 new_win_dims
.Left
= 0;
668 new_win_dims
.Bottom
= min (new_size
.Y
, info
.dwSize
.Y
) - 1;
669 new_win_dims
.Right
= min (new_size
.X
, info
.dwSize
.X
) - 1;
670 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
672 SetConsoleScreenBufferSize (cur_screen
, new_size
);
674 /* Set the window size to match the buffer dimension. */
675 new_win_dims
.Top
= 0;
676 new_win_dims
.Left
= 0;
677 new_win_dims
.Bottom
= new_size
.Y
- 1;
678 new_win_dims
.Right
= new_size
.X
- 1;
679 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
683 GetConsoleScreenBufferInfo (cur_screen
, &info
);
686 char_attr
= info
.wAttributes
& 0xFF;
687 char_attr_normal
= char_attr
;
688 char_attr_reverse
= ((char_attr
& 0xf) << 4) + ((char_attr
& 0xf0) >> 4);
690 if (w32_use_full_screen_buffer
)
692 FRAME_HEIGHT (SELECTED_FRAME ()) = info
.dwSize
.Y
; /* lines per page */
693 SET_FRAME_WIDTH (SELECTED_FRAME (), info
.dwSize
.X
); /* characters per line */
697 /* Lines per page. Use buffer coords instead of buffer size. */
698 FRAME_HEIGHT (SELECTED_FRAME ()) = 1 + info
.srWindow
.Bottom
-
700 /* Characters per line. Use buffer coords instead of buffer size. */
701 SET_FRAME_WIDTH (SELECTED_FRAME (), 1 + info
.srWindow
.Right
-
706 DEFUN ("set-screen-color", Fset_screen_color
, Sset_screen_color
, 2, 2, 0,
707 "Set screen colors.")
708 (foreground
, background
)
709 Lisp_Object foreground
;
710 Lisp_Object background
;
712 char_attr_normal
= XFASTINT (foreground
) + (XFASTINT (background
) << 4);
713 char_attr_reverse
= XFASTINT (background
) + (XFASTINT (foreground
) << 4);
719 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
724 CONSOLE_CURSOR_INFO cci
;
725 cci
.dwSize
= XFASTINT (size
);
727 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
734 pixel_to_glyph_coords (struct frame
* f
, int pix_x
, int pix_y
, int *x
, int *y
,
735 void *bounds
, int noclip
)
742 glyph_to_pixel_coords (struct frame
* f
, int x
, int y
, int *pix_x
, int *pix_y
)
747 #endif /* !HAVE_NTGUI */
752 DEFVAR_BOOL ("w32-use-full-screen-buffer",
753 &w32_use_full_screen_buffer
,
754 "Non-nil means make terminal frames use the full screen buffer dimensions.\n\
755 This is desirable when running Emacs over telnet, and is the default.\n\
756 A value of nil means use the current console window dimensions; this\n\
757 may be preferrable when working directly at the console with a large\n\
758 scroll-back buffer.");
759 w32_use_full_screen_buffer
= 1;
761 defsubr (&Sset_screen_color
);
762 defsubr (&Sset_cursor_size
);
763 defsubr (&Sset_message_beep
);