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
;
80 /* Setting this as the ctrl handler prevents emacs from being killed when
81 someone hits ^C in a 'suspended' session (child shell).
82 Also ignore Ctrl-Break signals. */
85 ctrl_c_handler (unsigned long type
)
87 /* Only ignore "interrupt" events when running interactively. */
88 return (!noninteractive
89 && (type
== CTRL_C_EVENT
|| type
== CTRL_BREAK_EVENT
));
92 /* If we're updating a frame, use it as the current frame
93 Otherwise, use the selected frame. */
94 #define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
96 /* Move the cursor to (row, col). */
98 move_cursor (int row
, int col
)
100 cursor_coords
.X
= col
;
101 cursor_coords
.Y
= row
;
103 if (updating_frame
== (FRAME_PTR
) NULL
)
105 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
109 /* Clear from cursor to end of screen. */
113 FRAME_PTR f
= PICK_FRAME ();
115 clear_end_of_line (FRAME_WIDTH (f
) - 1);
116 ins_del_lines (cursor_coords
.Y
, FRAME_HEIGHT (f
) - cursor_coords
.Y
- 1);
119 /* Clear the frame. */
123 FRAME_PTR f
= PICK_FRAME ();
129 n
= FRAME_HEIGHT (f
) * FRAME_WIDTH (f
);
132 FillConsoleOutputAttribute (cur_screen
, char_attr
, n
, dest
, &r
);
133 FillConsoleOutputCharacter (cur_screen
, ' ', n
, dest
, &r
);
139 static GLYPH glyph_base
[256];
140 static BOOL ceol_initialized
= FALSE
;
142 /* Clear from Cursor to end (what's "standout marker"?). */
144 clear_end_of_line (int end
)
146 if (!ceol_initialized
)
149 for (i
= 0; i
< 256; i
++)
151 glyph_base
[i
] = SPACEGLYPH
; /* empty space */
153 ceol_initialized
= TRUE
;
155 write_glyphs (glyph_base
, end
- cursor_coords
.X
); /* fencepost ? */
158 /* Insert n lines at vpos. if n is negative delete -n lines. */
160 ins_del_lines (int vpos
, int n
)
162 int i
, nb
, save_highlight
;
166 FRAME_PTR f
= PICK_FRAME ();
170 scroll
.Top
= vpos
- n
;
171 scroll
.Bottom
= FRAME_HEIGHT (f
);
177 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
181 scroll
.Right
= FRAME_WIDTH (f
);
185 save_highlight
= hl_mode (0);
187 fill
.Char
.AsciiChar
= 0x20;
188 fill
.Attributes
= char_attr
;
190 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
192 /* Here we have to deal with a w32 console flake: If the scroll
193 region looks like abc and we scroll c to a and fill with d we get
194 cbd... if we scroll block c one line at a time to a, we get cdd...
195 Emacs expects cdd consistently... So we have to deal with that
196 here... (this also occurs scrolling the same way in the other
201 if (scroll
.Bottom
< dest
.Y
)
203 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
206 clear_end_of_line (FRAME_WIDTH (f
));
212 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
216 for (i
= nb
; i
< scroll
.Top
; i
++)
219 clear_end_of_line (FRAME_WIDTH (f
));
225 cursor_coords
.Y
= vpos
;
227 hl_mode (save_highlight
);
230 /* Changes attribute to use when drawing characters to control. */
232 hl_mode (int new_highlight
)
234 static int highlight
= 0;
237 old_highlight
= highlight
;
238 highlight
= (new_highlight
!= 0);
241 char_attr
= char_attr_reverse
;
245 char_attr
= char_attr_normal
;
247 return old_highlight
;
250 /* Call this when about to modify line at position VPOS and change whether it
253 change_line_highlight (int new_highlight
, int vpos
, int first_unused_hpos
)
255 hl_mode (new_highlight
);
256 move_cursor (vpos
, 0);
257 clear_end_of_line (first_unused_hpos
);
260 /* External interface to control of standout mode. Call this when about to
261 * modify line at position VPOS and not change whether it is highlighted. */
263 reassert_line_highlight (int highlight
, int vpos
)
266 vpos
; /* pedantic compiler silencer */
275 scroll_line (int dist
, int direction
)
277 /* The idea here is to implement a horizontal scroll in one line to
278 implement delete and half of insert. */
282 FRAME_PTR f
= PICK_FRAME ();
284 scroll
.Top
= cursor_coords
.Y
;
285 scroll
.Bottom
= cursor_coords
.Y
;
287 if (direction
== LEFT
)
289 scroll
.Left
= cursor_coords
.X
+ dist
;
290 scroll
.Right
= FRAME_WIDTH (f
) - 1;
294 scroll
.Left
= cursor_coords
.X
;
295 scroll
.Right
= FRAME_WIDTH (f
) - dist
- 1;
298 dest
.X
= cursor_coords
.X
;
299 dest
.Y
= cursor_coords
.Y
;
301 fill
.Char
.AsciiChar
= 0x20;
302 fill
.Attributes
= char_attr
;
304 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
308 /* If start is zero insert blanks instead of a string at start ?. */
310 insert_glyphs (register GLYPH
*start
, register int len
)
312 scroll_line (len
, RIGHT
);
314 /* Move len chars to the right starting at cursor_coords, fill with blanks */
317 /* Print the first len characters of start, cursor_coords.X adjusted
320 write_glyphs (start
, len
);
324 clear_end_of_line (cursor_coords
.X
+ len
);
329 write_glyphs (register GLYPH
*string
, register int len
)
331 register unsigned int glyph_len
= GLYPH_TABLE_LENGTH
;
332 Lisp_Object
*glyph_table
= GLYPH_TABLE_BASE
;
333 FRAME_PTR f
= PICK_FRAME ();
343 attrs
= alloca (len
* sizeof (*attrs
));
344 chars
= alloca (len
* sizeof (*chars
));
345 if (attrs
== NULL
|| chars
== NULL
)
347 printf ("alloca failed in write_glyphs\n");
351 /* We have to deal with the glyph indirection...go over the glyph
352 buffer and extract the characters. */
358 if (glyph
> glyph_len
)
360 *ptr
++ = glyph
& 0xFF;
363 GLYPH_FOLLOW_ALIASES (glyph_table
, glyph_len
, glyph
);
365 if (GLYPH_FACE (fixfix
, glyph
) != 0)
366 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix
, glyph
));
367 #endif /* !HAVE_NTGUI */
368 if (GLYPH_SIMPLE_P (glyph_table
, glyph_len
, glyph
))
370 *ptr
++ = glyph
& 0xFF;
373 for (i
= 0; i
< GLYPH_LENGTH (glyph_table
, glyph
); i
++)
375 *ptr
++ = (GLYPH_STRING (glyph_table
, glyph
))[i
];
379 /* Number of characters we have in the buffer. */
382 /* Fill in the attributes for these characters. */
383 for (i
= 0; i
< len
; i
++)
384 attrs
[i
] = char_attr
;
386 /* Write the attributes. */
387 if (!WriteConsoleOutputAttribute (cur_screen
, attrs
, len
, cursor_coords
, &i
))
389 printf ("Failed writing console attributes: %d\n", GetLastError ());
393 /* Write the characters. */
394 if (!WriteConsoleOutputCharacter (cur_screen
, chars
, len
, cursor_coords
, &i
))
396 printf ("Failed writing console characters: %d\n", GetLastError ());
400 cursor_coords
.X
+= len
;
401 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
405 delete_glyphs (int n
)
407 /* delete chars means scroll chars from cursor_coords.X + n to
408 cursor_coords.X, anything beyond the edge of the screen should
411 scroll_line (n
, LEFT
);
414 static unsigned int sound_type
= 0xFFFFFFFF;
415 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
418 w32_sys_ring_bell (void)
420 if (sound_type
== 0xFFFFFFFF)
424 else if (sound_type
== MB_EMACS_SILENT
)
429 MessageBeep (sound_type
);
432 DEFUN ("set-message-beep", Fset_message_beep
, Sset_message_beep
, 1, 1, 0,
433 "Set the sound generated when the bell is rung.\n\
434 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
435 to use the corresponding system sound for the bell. The 'silent sound\n\
436 prevents Emacs from making any sound at all.\n\
437 SOUND is nil to use the normal beep.")
441 CHECK_SYMBOL (sound
, 0);
444 sound_type
= 0xFFFFFFFF;
445 else if (EQ (sound
, intern ("asterisk")))
446 sound_type
= MB_ICONASTERISK
;
447 else if (EQ (sound
, intern ("exclamation")))
448 sound_type
= MB_ICONEXCLAMATION
;
449 else if (EQ (sound
, intern ("hand")))
450 sound_type
= MB_ICONHAND
;
451 else if (EQ (sound
, intern ("question")))
452 sound_type
= MB_ICONQUESTION
;
453 else if (EQ (sound
, intern ("ok")))
455 else if (EQ (sound
, intern ("silent")))
456 sound_type
= MB_EMACS_SILENT
;
458 sound_type
= 0xFFFFFFFF;
464 reset_terminal_modes (void)
466 #ifdef USE_SEPARATE_SCREEN
467 SetConsoleActiveScreenBuffer (prev_screen
);
469 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
471 SetConsoleMode (keyboard_handle
, prev_console_mode
);
475 set_terminal_modes (void)
477 CONSOLE_CURSOR_INFO cci
;
479 /* make cursor big and visible (100 on Win95 makes it disappear) */
482 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
484 SetConsoleActiveScreenBuffer (cur_screen
);
486 SetConsoleMode (keyboard_handle
, ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
);
488 /* Initialize input mode: interrupt_input off, no flow control, allow
489 8 bit character input, standard quit char. */
490 Fset_input_mode (Qnil
, Qnil
, make_number (2), Qnil
);
493 /* hmmm... perhaps these let us bracket screen changes so that we can flush
494 clumps rather than one-character-at-a-time...
496 we'll start with not moving the cursor while an update is in progress. */
498 update_begin (FRAME_PTR f
)
503 update_end (FRAME_PTR f
)
505 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
509 set_terminal_window (int size
)
513 typedef int (*term_hook
) ();
516 initialize_w32_display (void)
518 CONSOLE_SCREEN_BUFFER_INFO info
;
520 cursor_to_hook
= move_cursor
;
521 raw_cursor_to_hook
= move_cursor
;
522 clear_to_end_hook
= clear_to_end
;
523 clear_frame_hook
= clear_frame
;
524 clear_end_of_line_hook
= clear_end_of_line
;
525 ins_del_lines_hook
= ins_del_lines
;
526 change_line_highlight_hook
= change_line_highlight
;
527 reassert_line_highlight_hook
= reassert_line_highlight
;
528 insert_glyphs_hook
= insert_glyphs
;
529 write_glyphs_hook
= write_glyphs
;
530 delete_glyphs_hook
= delete_glyphs
;
531 ring_bell_hook
= w32_sys_ring_bell
;
532 reset_terminal_modes_hook
= reset_terminal_modes
;
533 set_terminal_modes_hook
= set_terminal_modes
;
534 set_terminal_window_hook
= set_terminal_window
;
535 update_begin_hook
= update_begin
;
536 update_end_hook
= update_end
;
538 read_socket_hook
= w32_console_read_socket
;
539 mouse_position_hook
= w32_console_mouse_position
;
541 /* Initialize interrupt_handle. */
544 /* Remember original console settings. */
545 keyboard_handle
= GetStdHandle (STD_INPUT_HANDLE
);
546 GetConsoleMode (keyboard_handle
, &prev_console_mode
);
548 prev_screen
= GetStdHandle (STD_OUTPUT_HANDLE
);
550 #ifdef USE_SEPARATE_SCREEN
551 cur_screen
= CreateConsoleScreenBuffer (GENERIC_READ
| GENERIC_WRITE
,
553 CONSOLE_TEXTMODE_BUFFER
,
556 if (cur_screen
== INVALID_HANDLE_VALUE
)
558 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
559 printf ("LastError = 0x%lx\n", GetLastError ());
564 cur_screen
= prev_screen
;
565 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
568 GetConsoleScreenBufferInfo (cur_screen
, &info
);
571 char_attr
= info
.wAttributes
& 0xFF;
572 char_attr_normal
= char_attr
;
573 char_attr_reverse
= ((char_attr
& 0xf) << 4) + ((char_attr
& 0xf0) >> 4);
575 /* Lines per page. Use buffer coords instead of buffer size. */
576 FRAME_HEIGHT (selected_frame
) = 1 + info
.srWindow
.Bottom
-
578 /* Characters per line. Use buffer coords instead of buffer size. */
579 SET_FRAME_WIDTH (selected_frame
, 1 + info
.srWindow
.Right
-
583 DEFUN ("set-screen-color", Fset_screen_color
, Sset_screen_color
, 2, 2, 0,
584 "Set screen colors.")
585 (foreground
, background
)
586 Lisp_Object foreground
;
587 Lisp_Object background
;
589 char_attr_normal
= XFASTINT (foreground
) + (XFASTINT (background
) << 4);
590 char_attr_reverse
= XFASTINT (background
) + (XFASTINT (foreground
) << 4);
596 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
601 CONSOLE_CURSOR_INFO cci
;
602 cci
.dwSize
= XFASTINT (size
);
604 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
611 pixel_to_glyph_coords (FRAME_PTR f
, int pix_x
, int pix_y
, int *x
, int *y
,
612 void *bounds
, int noclip
)
619 glyph_to_pixel_coords (FRAME_PTR f
, int x
, int y
, int *pix_x
, int *pix_y
)
624 #endif /* !HAVE_NTGUI */
629 defsubr (&Sset_screen_color
);
630 defsubr (&Sset_cursor_size
);
631 defsubr (&Sset_message_beep
);