1 /* Terminal hooks for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1992 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
36 #include "termhooks.h"
40 extern Lisp_Object
Frecenter ();
43 extern int detect_input_pending ();
46 extern int read_input_pending ();
48 extern FRAME_PTR updating_frame
;
51 static void move_cursor (int row
, int col
);
52 static void clear_to_end (void);
53 static void clear_frame (void);
54 static void clear_end_of_line (int);
55 static void ins_del_lines (int vpos
, int n
);
56 static void change_line_highlight (int, int, int);
57 static void reassert_line_highlight (int, int);
58 static void insert_glyphs (GLYPH
*start
, int len
);
59 static void write_glyphs (GLYPH
*string
, int len
);
60 static void delete_glyphs (int n
);
61 void w32_sys_ring_bell (void);
62 static void reset_terminal_modes (void);
63 static void set_terminal_modes (void);
64 static void set_terminal_window (int size
);
65 static void update_begin (FRAME_PTR f
);
66 static void update_end (FRAME_PTR f
);
67 static int hl_mode (int new_highlight
);
70 HANDLE prev_screen
, cur_screen
;
71 UCHAR char_attr
, char_attr_normal
, char_attr_reverse
;
72 HANDLE keyboard_handle
;
73 DWORD prev_console_mode
;
75 #ifndef USE_SEPARATE_SCREEN
76 CONSOLE_CURSOR_INFO prev_console_cursor
;
79 /* Determine whether to make frame dimensions match the screen buffer,
80 or the current window size. The former is desirable when running
81 over telnet, while the latter is more useful when working directly at
82 the console with a large scroll-back buffer. */
83 int w32_use_full_screen_buffer
;
86 /* Setting this as the ctrl handler prevents emacs from being killed when
87 someone hits ^C in a 'suspended' session (child shell).
88 Also ignore Ctrl-Break signals. */
91 ctrl_c_handler (unsigned long type
)
93 /* Only ignore "interrupt" events when running interactively. */
94 return (!noninteractive
95 && (type
== CTRL_C_EVENT
|| type
== CTRL_BREAK_EVENT
));
98 /* If we're updating a frame, use it as the current frame
99 Otherwise, use the selected frame. */
100 #define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
102 /* Move the cursor to (row, col). */
104 move_cursor (int row
, int col
)
106 cursor_coords
.X
= col
;
107 cursor_coords
.Y
= row
;
109 if (updating_frame
== (FRAME_PTR
) NULL
)
111 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
115 /* Clear from cursor to end of screen. */
119 FRAME_PTR f
= PICK_FRAME ();
121 clear_end_of_line (FRAME_WIDTH (f
) - 1);
122 ins_del_lines (cursor_coords
.Y
, FRAME_HEIGHT (f
) - cursor_coords
.Y
- 1);
125 /* Clear the frame. */
129 FRAME_PTR f
= PICK_FRAME ();
132 CONSOLE_SCREEN_BUFFER_INFO info
;
134 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
138 /* Remember that the screen buffer might be wider than the window. */
139 n
= FRAME_HEIGHT (f
) * info
.dwSize
.X
;
142 FillConsoleOutputAttribute (cur_screen
, char_attr
, n
, dest
, &r
);
143 FillConsoleOutputCharacter (cur_screen
, ' ', n
, dest
, &r
);
149 static GLYPH glyph_base
[256];
150 static BOOL ceol_initialized
= FALSE
;
152 /* Clear from Cursor to end (what's "standout marker"?). */
154 clear_end_of_line (int end
)
156 if (!ceol_initialized
)
159 for (i
= 0; i
< 256; i
++)
161 glyph_base
[i
] = SPACEGLYPH
; /* empty space */
163 ceol_initialized
= TRUE
;
165 write_glyphs (glyph_base
, end
- cursor_coords
.X
); /* fencepost ? */
168 /* Insert n lines at vpos. if n is negative delete -n lines. */
170 ins_del_lines (int vpos
, int n
)
172 int i
, nb
, save_highlight
;
176 FRAME_PTR f
= PICK_FRAME ();
180 scroll
.Top
= vpos
- n
;
181 scroll
.Bottom
= FRAME_HEIGHT (f
);
187 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
191 scroll
.Right
= FRAME_WIDTH (f
);
195 save_highlight
= hl_mode (0);
197 fill
.Char
.AsciiChar
= 0x20;
198 fill
.Attributes
= char_attr
;
200 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
202 /* Here we have to deal with a w32 console flake: If the scroll
203 region looks like abc and we scroll c to a and fill with d we get
204 cbd... if we scroll block c one line at a time to a, we get cdd...
205 Emacs expects cdd consistently... So we have to deal with that
206 here... (this also occurs scrolling the same way in the other
211 if (scroll
.Bottom
< dest
.Y
)
213 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
216 clear_end_of_line (FRAME_WIDTH (f
));
222 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
226 for (i
= nb
; i
< scroll
.Top
; i
++)
229 clear_end_of_line (FRAME_WIDTH (f
));
235 cursor_coords
.Y
= vpos
;
237 hl_mode (save_highlight
);
240 /* Changes attribute to use when drawing characters to control. */
242 hl_mode (int new_highlight
)
244 static int highlight
= 0;
247 old_highlight
= highlight
;
248 highlight
= (new_highlight
!= 0);
251 char_attr
= char_attr_reverse
;
255 char_attr
= char_attr_normal
;
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 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 FRAME_PTR 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
;
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 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 GLYPH
*string
, register int len
)
341 register unsigned int glyph_len
= GLYPH_TABLE_LENGTH
;
342 Lisp_Object
*glyph_table
= GLYPH_TABLE_BASE
;
343 FRAME_PTR f
= PICK_FRAME ();
352 chars
= alloca (len
* sizeof (*chars
));
355 printf ("alloca failed in write_glyphs\n");
359 /* We have to deal with the glyph indirection...go over the glyph
360 buffer and extract the characters. */
366 if (glyph
> glyph_len
)
368 *ptr
++ = glyph
& 0xFF;
371 GLYPH_FOLLOW_ALIASES (glyph_table
, glyph_len
, glyph
);
373 if (GLYPH_FACE (fixfix
, glyph
) != 0)
374 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix
, glyph
));
375 #endif /* !HAVE_NTGUI */
376 if (GLYPH_SIMPLE_P (glyph_table
, glyph_len
, glyph
))
378 *ptr
++ = glyph
& 0xFF;
381 for (i
= 0; i
< GLYPH_LENGTH (glyph_table
, glyph
); i
++)
383 *ptr
++ = (GLYPH_STRING (glyph_table
, glyph
))[i
];
387 /* Number of characters we have in the buffer. */
390 /* Set the attribute for these characters. */
391 if (!FillConsoleOutputAttribute (cur_screen
, char_attr
, len
, cursor_coords
, &i
))
393 printf ("Failed writing console attributes: %d\n", GetLastError ());
397 /* Write the characters. */
398 if (!WriteConsoleOutputCharacter (cur_screen
, chars
, len
, cursor_coords
, &i
))
400 printf ("Failed writing console characters: %d\n", GetLastError ());
404 cursor_coords
.X
+= len
;
405 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
409 delete_glyphs (int n
)
411 /* delete chars means scroll chars from cursor_coords.X + n to
412 cursor_coords.X, anything beyond the edge of the screen should
415 scroll_line (n
, LEFT
);
418 static unsigned int sound_type
= 0xFFFFFFFF;
419 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
422 w32_sys_ring_bell (void)
424 if (sound_type
== 0xFFFFFFFF)
428 else if (sound_type
== MB_EMACS_SILENT
)
433 MessageBeep (sound_type
);
436 DEFUN ("set-message-beep", Fset_message_beep
, Sset_message_beep
, 1, 1, 0,
437 "Set the sound generated when the bell is rung.\n\
438 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
439 to use the corresponding system sound for the bell. The 'silent sound\n\
440 prevents Emacs from making any sound at all.\n\
441 SOUND is nil to use the normal beep.")
445 CHECK_SYMBOL (sound
, 0);
448 sound_type
= 0xFFFFFFFF;
449 else if (EQ (sound
, intern ("asterisk")))
450 sound_type
= MB_ICONASTERISK
;
451 else if (EQ (sound
, intern ("exclamation")))
452 sound_type
= MB_ICONEXCLAMATION
;
453 else if (EQ (sound
, intern ("hand")))
454 sound_type
= MB_ICONHAND
;
455 else if (EQ (sound
, intern ("question")))
456 sound_type
= MB_ICONQUESTION
;
457 else if (EQ (sound
, intern ("ok")))
459 else if (EQ (sound
, intern ("silent")))
460 sound_type
= MB_EMACS_SILENT
;
462 sound_type
= 0xFFFFFFFF;
468 reset_terminal_modes (void)
470 #ifdef USE_SEPARATE_SCREEN
471 SetConsoleActiveScreenBuffer (prev_screen
);
473 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
475 SetConsoleMode (keyboard_handle
, prev_console_mode
);
479 set_terminal_modes (void)
481 CONSOLE_CURSOR_INFO cci
;
483 /* make cursor big and visible (100 on Win95 makes it disappear) */
486 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
488 SetConsoleActiveScreenBuffer (cur_screen
);
490 SetConsoleMode (keyboard_handle
, ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
);
492 /* Initialize input mode: interrupt_input off, no flow control, allow
493 8 bit character input, standard quit char. */
494 Fset_input_mode (Qnil
, Qnil
, make_number (2), Qnil
);
497 /* hmmm... perhaps these let us bracket screen changes so that we can flush
498 clumps rather than one-character-at-a-time...
500 we'll start with not moving the cursor while an update is in progress. */
502 update_begin (FRAME_PTR f
)
507 update_end (FRAME_PTR f
)
509 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
513 set_terminal_window (int size
)
517 typedef int (*term_hook
) ();
520 initialize_w32_display (void)
522 CONSOLE_SCREEN_BUFFER_INFO info
;
524 cursor_to_hook
= move_cursor
;
525 raw_cursor_to_hook
= move_cursor
;
526 clear_to_end_hook
= clear_to_end
;
527 clear_frame_hook
= clear_frame
;
528 clear_end_of_line_hook
= clear_end_of_line
;
529 ins_del_lines_hook
= ins_del_lines
;
530 change_line_highlight_hook
= change_line_highlight
;
531 reassert_line_highlight_hook
= reassert_line_highlight
;
532 insert_glyphs_hook
= insert_glyphs
;
533 write_glyphs_hook
= write_glyphs
;
534 delete_glyphs_hook
= delete_glyphs
;
535 ring_bell_hook
= w32_sys_ring_bell
;
536 reset_terminal_modes_hook
= reset_terminal_modes
;
537 set_terminal_modes_hook
= set_terminal_modes
;
538 set_terminal_window_hook
= set_terminal_window
;
539 update_begin_hook
= update_begin
;
540 update_end_hook
= update_end
;
542 read_socket_hook
= w32_console_read_socket
;
543 mouse_position_hook
= w32_console_mouse_position
;
545 /* Initialize interrupt_handle. */
548 /* Remember original console settings. */
549 keyboard_handle
= GetStdHandle (STD_INPUT_HANDLE
);
550 GetConsoleMode (keyboard_handle
, &prev_console_mode
);
552 prev_screen
= GetStdHandle (STD_OUTPUT_HANDLE
);
554 #ifdef USE_SEPARATE_SCREEN
555 cur_screen
= CreateConsoleScreenBuffer (GENERIC_READ
| GENERIC_WRITE
,
557 CONSOLE_TEXTMODE_BUFFER
,
560 if (cur_screen
== INVALID_HANDLE_VALUE
)
562 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
563 printf ("LastError = 0x%lx\n", GetLastError ());
568 cur_screen
= prev_screen
;
569 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
572 /* Respect setting of LINES and COLUMNS environment variables. */
574 char * lines
= getenv("LINES");
575 char * columns
= getenv("COLUMNS");
577 if (lines
!= NULL
&& columns
!= NULL
)
579 SMALL_RECT new_win_dims
;
582 new_size
.X
= atoi (columns
);
583 new_size
.Y
= atoi (lines
);
585 GetConsoleScreenBufferInfo (cur_screen
, &info
);
587 /* Shrink the window first, so the buffer dimensions can be
588 reduced if necessary. */
589 new_win_dims
.Top
= 0;
590 new_win_dims
.Left
= 0;
591 new_win_dims
.Bottom
= min (new_size
.Y
, info
.dwSize
.Y
) - 1;
592 new_win_dims
.Right
= min (new_size
.X
, info
.dwSize
.X
) - 1;
593 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
595 SetConsoleScreenBufferSize (cur_screen
, new_size
);
597 /* Set the window size to match the buffer dimension. */
598 new_win_dims
.Top
= 0;
599 new_win_dims
.Left
= 0;
600 new_win_dims
.Bottom
= new_size
.Y
- 1;
601 new_win_dims
.Right
= new_size
.X
- 1;
602 SetConsoleWindowInfo (cur_screen
, TRUE
, &new_win_dims
);
606 GetConsoleScreenBufferInfo (cur_screen
, &info
);
609 char_attr
= info
.wAttributes
& 0xFF;
610 char_attr_normal
= char_attr
;
611 char_attr_reverse
= ((char_attr
& 0xf) << 4) + ((char_attr
& 0xf0) >> 4);
613 if (w32_use_full_screen_buffer
)
615 FRAME_HEIGHT (selected_frame
) = info
.dwSize
.Y
; /* lines per page */
616 SET_FRAME_WIDTH (selected_frame
, info
.dwSize
.X
); /* characters per line */
620 /* Lines per page. Use buffer coords instead of buffer size. */
621 FRAME_HEIGHT (selected_frame
) = 1 + info
.srWindow
.Bottom
-
623 /* Characters per line. Use buffer coords instead of buffer size. */
624 SET_FRAME_WIDTH (selected_frame
, 1 + info
.srWindow
.Right
-
629 DEFUN ("set-screen-color", Fset_screen_color
, Sset_screen_color
, 2, 2, 0,
630 "Set screen colors.")
631 (foreground
, background
)
632 Lisp_Object foreground
;
633 Lisp_Object background
;
635 char_attr_normal
= XFASTINT (foreground
) + (XFASTINT (background
) << 4);
636 char_attr_reverse
= XFASTINT (background
) + (XFASTINT (foreground
) << 4);
642 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
647 CONSOLE_CURSOR_INFO cci
;
648 cci
.dwSize
= XFASTINT (size
);
650 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
657 pixel_to_glyph_coords (FRAME_PTR f
, int pix_x
, int pix_y
, int *x
, int *y
,
658 void *bounds
, int noclip
)
665 glyph_to_pixel_coords (FRAME_PTR f
, int x
, int y
, int *pix_x
, int *pix_y
)
670 #endif /* !HAVE_NTGUI */
675 DEFVAR_BOOL ("w32-use-full-screen-buffer",
676 &w32_use_full_screen_buffer
,
677 "Non-nil means make terminal frames use the full screen buffer dimensions.\n\
678 This is desirable when running Emacs over telnet, and is the default.\n\
679 A value of nil means use the current console window dimensions; this\n\
680 may be preferrable when working directly at the console with a large\n\
681 scroll-back buffer.");
682 w32_use_full_screen_buffer
= 1;
684 defsubr (&Sset_screen_color
);
685 defsubr (&Sset_cursor_size
);
686 defsubr (&Sset_message_beep
);