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 ();
126 CONSOLE_SCREEN_BUFFER_INFO info
;
128 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
132 /* Remember that the screen buffer might be wider than the window. */
133 n
= FRAME_HEIGHT (f
) * info
.dwSize
.X
;
136 FillConsoleOutputAttribute (cur_screen
, char_attr
, n
, dest
, &r
);
137 FillConsoleOutputCharacter (cur_screen
, ' ', n
, dest
, &r
);
143 static GLYPH glyph_base
[256];
144 static BOOL ceol_initialized
= FALSE
;
146 /* Clear from Cursor to end (what's "standout marker"?). */
148 clear_end_of_line (int end
)
150 if (!ceol_initialized
)
153 for (i
= 0; i
< 256; i
++)
155 glyph_base
[i
] = SPACEGLYPH
; /* empty space */
157 ceol_initialized
= TRUE
;
159 write_glyphs (glyph_base
, end
- cursor_coords
.X
); /* fencepost ? */
162 /* Insert n lines at vpos. if n is negative delete -n lines. */
164 ins_del_lines (int vpos
, int n
)
166 int i
, nb
, save_highlight
;
170 FRAME_PTR f
= PICK_FRAME ();
174 scroll
.Top
= vpos
- n
;
175 scroll
.Bottom
= FRAME_HEIGHT (f
);
181 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
185 scroll
.Right
= FRAME_WIDTH (f
);
189 save_highlight
= hl_mode (0);
191 fill
.Char
.AsciiChar
= 0x20;
192 fill
.Attributes
= char_attr
;
194 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
196 /* Here we have to deal with a w32 console flake: If the scroll
197 region looks like abc and we scroll c to a and fill with d we get
198 cbd... if we scroll block c one line at a time to a, we get cdd...
199 Emacs expects cdd consistently... So we have to deal with that
200 here... (this also occurs scrolling the same way in the other
205 if (scroll
.Bottom
< dest
.Y
)
207 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
210 clear_end_of_line (FRAME_WIDTH (f
));
216 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
220 for (i
= nb
; i
< scroll
.Top
; i
++)
223 clear_end_of_line (FRAME_WIDTH (f
));
229 cursor_coords
.Y
= vpos
;
231 hl_mode (save_highlight
);
234 /* Changes attribute to use when drawing characters to control. */
236 hl_mode (int new_highlight
)
238 static int highlight
= 0;
241 old_highlight
= highlight
;
242 highlight
= (new_highlight
!= 0);
245 char_attr
= char_attr_reverse
;
249 char_attr
= char_attr_normal
;
251 return old_highlight
;
254 /* Call this when about to modify line at position VPOS and change whether it
257 change_line_highlight (int new_highlight
, int vpos
, int first_unused_hpos
)
259 hl_mode (new_highlight
);
260 move_cursor (vpos
, 0);
261 clear_end_of_line (first_unused_hpos
);
264 /* External interface to control of standout mode. Call this when about to
265 * modify line at position VPOS and not change whether it is highlighted. */
267 reassert_line_highlight (int highlight
, int vpos
)
270 vpos
; /* pedantic compiler silencer */
279 scroll_line (int dist
, int direction
)
281 /* The idea here is to implement a horizontal scroll in one line to
282 implement delete and half of insert. */
286 FRAME_PTR f
= PICK_FRAME ();
288 scroll
.Top
= cursor_coords
.Y
;
289 scroll
.Bottom
= cursor_coords
.Y
;
291 if (direction
== LEFT
)
293 scroll
.Left
= cursor_coords
.X
+ dist
;
294 scroll
.Right
= FRAME_WIDTH (f
) - 1;
298 scroll
.Left
= cursor_coords
.X
;
299 scroll
.Right
= FRAME_WIDTH (f
) - dist
- 1;
302 dest
.X
= cursor_coords
.X
;
303 dest
.Y
= cursor_coords
.Y
;
305 fill
.Char
.AsciiChar
= 0x20;
306 fill
.Attributes
= char_attr
;
308 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
312 /* If start is zero insert blanks instead of a string at start ?. */
314 insert_glyphs (register GLYPH
*start
, register int len
)
316 scroll_line (len
, RIGHT
);
318 /* Move len chars to the right starting at cursor_coords, fill with blanks */
321 /* Print the first len characters of start, cursor_coords.X adjusted
324 write_glyphs (start
, len
);
328 clear_end_of_line (cursor_coords
.X
+ len
);
333 write_glyphs (register GLYPH
*string
, register int len
)
335 register unsigned int glyph_len
= GLYPH_TABLE_LENGTH
;
336 Lisp_Object
*glyph_table
= GLYPH_TABLE_BASE
;
337 FRAME_PTR f
= PICK_FRAME ();
346 chars
= alloca (len
* sizeof (*chars
));
349 printf ("alloca failed in write_glyphs\n");
353 /* We have to deal with the glyph indirection...go over the glyph
354 buffer and extract the characters. */
360 if (glyph
> glyph_len
)
362 *ptr
++ = glyph
& 0xFF;
365 GLYPH_FOLLOW_ALIASES (glyph_table
, glyph_len
, glyph
);
367 if (GLYPH_FACE (fixfix
, glyph
) != 0)
368 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix
, glyph
));
369 #endif /* !HAVE_NTGUI */
370 if (GLYPH_SIMPLE_P (glyph_table
, glyph_len
, glyph
))
372 *ptr
++ = glyph
& 0xFF;
375 for (i
= 0; i
< GLYPH_LENGTH (glyph_table
, glyph
); i
++)
377 *ptr
++ = (GLYPH_STRING (glyph_table
, glyph
))[i
];
381 /* Number of characters we have in the buffer. */
384 /* Set the attribute for these characters. */
385 if (!FillConsoleOutputAttribute (cur_screen
, char_attr
, len
, cursor_coords
, &i
))
387 printf ("Failed writing console attributes: %d\n", GetLastError ());
391 /* Write the characters. */
392 if (!WriteConsoleOutputCharacter (cur_screen
, chars
, len
, cursor_coords
, &i
))
394 printf ("Failed writing console characters: %d\n", GetLastError ());
398 cursor_coords
.X
+= len
;
399 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
403 delete_glyphs (int n
)
405 /* delete chars means scroll chars from cursor_coords.X + n to
406 cursor_coords.X, anything beyond the edge of the screen should
409 scroll_line (n
, LEFT
);
412 static unsigned int sound_type
= 0xFFFFFFFF;
413 #define MB_EMACS_SILENT (0xFFFFFFFF - 1)
416 w32_sys_ring_bell (void)
418 if (sound_type
== 0xFFFFFFFF)
422 else if (sound_type
== MB_EMACS_SILENT
)
427 MessageBeep (sound_type
);
430 DEFUN ("set-message-beep", Fset_message_beep
, Sset_message_beep
, 1, 1, 0,
431 "Set the sound generated when the bell is rung.\n\
432 SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent\n\
433 to use the corresponding system sound for the bell. The 'silent sound\n\
434 prevents Emacs from making any sound at all.\n\
435 SOUND is nil to use the normal beep.")
439 CHECK_SYMBOL (sound
, 0);
442 sound_type
= 0xFFFFFFFF;
443 else if (EQ (sound
, intern ("asterisk")))
444 sound_type
= MB_ICONASTERISK
;
445 else if (EQ (sound
, intern ("exclamation")))
446 sound_type
= MB_ICONEXCLAMATION
;
447 else if (EQ (sound
, intern ("hand")))
448 sound_type
= MB_ICONHAND
;
449 else if (EQ (sound
, intern ("question")))
450 sound_type
= MB_ICONQUESTION
;
451 else if (EQ (sound
, intern ("ok")))
453 else if (EQ (sound
, intern ("silent")))
454 sound_type
= MB_EMACS_SILENT
;
456 sound_type
= 0xFFFFFFFF;
462 reset_terminal_modes (void)
464 #ifdef USE_SEPARATE_SCREEN
465 SetConsoleActiveScreenBuffer (prev_screen
);
467 SetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
469 SetConsoleMode (keyboard_handle
, prev_console_mode
);
473 set_terminal_modes (void)
475 CONSOLE_CURSOR_INFO cci
;
477 /* make cursor big and visible (100 on Win95 makes it disappear) */
480 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
482 SetConsoleActiveScreenBuffer (cur_screen
);
484 SetConsoleMode (keyboard_handle
, ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
);
486 /* Initialize input mode: interrupt_input off, no flow control, allow
487 8 bit character input, standard quit char. */
488 Fset_input_mode (Qnil
, Qnil
, make_number (2), Qnil
);
491 /* hmmm... perhaps these let us bracket screen changes so that we can flush
492 clumps rather than one-character-at-a-time...
494 we'll start with not moving the cursor while an update is in progress. */
496 update_begin (FRAME_PTR f
)
501 update_end (FRAME_PTR f
)
503 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
507 set_terminal_window (int size
)
511 typedef int (*term_hook
) ();
514 initialize_w32_display (void)
516 CONSOLE_SCREEN_BUFFER_INFO info
;
518 cursor_to_hook
= move_cursor
;
519 raw_cursor_to_hook
= move_cursor
;
520 clear_to_end_hook
= clear_to_end
;
521 clear_frame_hook
= clear_frame
;
522 clear_end_of_line_hook
= clear_end_of_line
;
523 ins_del_lines_hook
= ins_del_lines
;
524 change_line_highlight_hook
= change_line_highlight
;
525 reassert_line_highlight_hook
= reassert_line_highlight
;
526 insert_glyphs_hook
= insert_glyphs
;
527 write_glyphs_hook
= write_glyphs
;
528 delete_glyphs_hook
= delete_glyphs
;
529 ring_bell_hook
= w32_sys_ring_bell
;
530 reset_terminal_modes_hook
= reset_terminal_modes
;
531 set_terminal_modes_hook
= set_terminal_modes
;
532 set_terminal_window_hook
= set_terminal_window
;
533 update_begin_hook
= update_begin
;
534 update_end_hook
= update_end
;
536 read_socket_hook
= w32_console_read_socket
;
537 mouse_position_hook
= w32_console_mouse_position
;
539 /* Initialize interrupt_handle. */
542 /* Remember original console settings. */
543 keyboard_handle
= GetStdHandle (STD_INPUT_HANDLE
);
544 GetConsoleMode (keyboard_handle
, &prev_console_mode
);
546 prev_screen
= GetStdHandle (STD_OUTPUT_HANDLE
);
548 #ifdef USE_SEPARATE_SCREEN
549 cur_screen
= CreateConsoleScreenBuffer (GENERIC_READ
| GENERIC_WRITE
,
551 CONSOLE_TEXTMODE_BUFFER
,
554 if (cur_screen
== INVALID_HANDLE_VALUE
)
556 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
557 printf ("LastError = 0x%lx\n", GetLastError ());
562 cur_screen
= prev_screen
;
563 GetConsoleCursorInfo (prev_screen
, &prev_console_cursor
);
566 GetConsoleScreenBufferInfo (cur_screen
, &info
);
569 char_attr
= info
.wAttributes
& 0xFF;
570 char_attr_normal
= char_attr
;
571 char_attr_reverse
= ((char_attr
& 0xf) << 4) + ((char_attr
& 0xf0) >> 4);
573 /* Lines per page. Use buffer coords instead of buffer size. */
574 FRAME_HEIGHT (selected_frame
) = 1 + info
.srWindow
.Bottom
-
576 /* Characters per line. Use buffer coords instead of buffer size. */
577 SET_FRAME_WIDTH (selected_frame
, 1 + info
.srWindow
.Right
-
581 DEFUN ("set-screen-color", Fset_screen_color
, Sset_screen_color
, 2, 2, 0,
582 "Set screen colors.")
583 (foreground
, background
)
584 Lisp_Object foreground
;
585 Lisp_Object background
;
587 char_attr_normal
= XFASTINT (foreground
) + (XFASTINT (background
) << 4);
588 char_attr_reverse
= XFASTINT (background
) + (XFASTINT (foreground
) << 4);
594 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
599 CONSOLE_CURSOR_INFO cci
;
600 cci
.dwSize
= XFASTINT (size
);
602 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
609 pixel_to_glyph_coords (FRAME_PTR f
, int pix_x
, int pix_y
, int *x
, int *y
,
610 void *bounds
, int noclip
)
617 glyph_to_pixel_coords (FRAME_PTR f
, int x
, int y
, int *pix_x
, int *pix_y
)
622 #endif /* !HAVE_NTGUI */
627 defsubr (&Sset_screen_color
);
628 defsubr (&Sset_cursor_size
);
629 defsubr (&Sset_message_beep
);