(run-with-idle-timer): New function.
[emacs.git] / src / w32console.c
blob31ec93635692fdf0a0cecbcb78fb12391a6fb671
1 /* Terminal hooks for Windows NT port of GNU Emacs.
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)
9 any later version.
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
26 #include <config.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <windows.h>
32 #include "lisp.h"
33 #include "frame.h"
34 #include "disptab.h"
35 #include "termhooks.h"
37 #include "ntinevt.h"
39 /* from window.c */
40 extern Lisp_Object Frecenter ();
42 /* from keyboard.c */
43 extern int detect_input_pending ();
45 /* from sysdep.c */
46 extern int read_input_pending ();
48 extern FRAME_PTR updating_frame;
49 extern int meta_key;
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 nt_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 void reset_kbd (void);
68 static void unset_kbd (void);
69 static int hl_mode (int new_highlight);
71 void
72 DebPrint ()
76 /* Init hook called in init_keyboard. */
77 void (*keyboard_init_hook)(void) = reset_kbd;
79 COORD cursor_coords;
80 HANDLE prev_screen, cur_screen;
81 UCHAR char_attr, char_attr_normal, char_attr_reverse;
82 HANDLE keyboard_handle;
85 /* Setting this as the ctrl handler prevents emacs from being killed when
86 someone hits ^C in a 'suspended' session (child shell).
87 Also ignore Ctrl-Break signals. */
89 BOOL
90 ctrl_c_handler (unsigned long type)
92 return (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT);
95 /* If we're updating a frame, use it as the current frame
96 Otherwise, use the selected frame. */
97 #define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
99 /* Move the cursor to (row, col). */
100 void
101 move_cursor (int row, int col)
103 cursor_coords.X = col;
104 cursor_coords.Y = row;
106 if (updating_frame == (FRAME_PTR) NULL)
108 SetConsoleCursorPosition (cur_screen, cursor_coords);
112 /* Clear from cursor to end of screen. */
113 void
114 clear_to_end (void)
116 FRAME_PTR f = PICK_FRAME ();
118 clear_end_of_line (FRAME_WIDTH (f) - 1);
119 ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1);
122 /* Clear the frame. */
123 void
124 clear_frame (void)
126 FRAME_PTR f = PICK_FRAME ();
127 COORD dest;
128 int n, r;
130 hl_mode (0);
132 n = FRAME_HEIGHT (f) * FRAME_WIDTH (f);
133 dest.X = dest.Y = 0;
135 FillConsoleOutputAttribute (cur_screen, char_attr, n, dest, &r);
136 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
138 move_cursor (0, 0);
142 static GLYPH glyph_base[256];
143 static BOOL ceol_initialized = FALSE;
145 /* Clear from Cursor to end (what's "standout marker"?). */
146 void
147 clear_end_of_line (int end)
149 if (!ceol_initialized)
151 int i;
152 for (i = 0; i < 256; i++)
154 glyph_base[i] = SPACEGLYPH; /* empty space */
156 ceol_initialized = TRUE;
158 write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */
161 /* Insert n lines at vpos. if n is negative delete -n lines. */
162 void
163 ins_del_lines (int vpos, int n)
165 int i, nb, save_highlight;
166 SMALL_RECT scroll;
167 COORD dest;
168 CHAR_INFO fill;
169 FRAME_PTR f = PICK_FRAME ();
171 if (n < 0)
173 scroll.Top = vpos - n;
174 scroll.Bottom = FRAME_HEIGHT (f);
175 dest.Y = vpos;
177 else
179 scroll.Top = vpos;
180 scroll.Bottom = FRAME_HEIGHT (f) - n;
181 dest.Y = vpos + n;
183 scroll.Left = 0;
184 scroll.Right = FRAME_WIDTH (f);
186 dest.X = 0;
188 save_highlight = hl_mode (0);
190 fill.Char.AsciiChar = 0x20;
191 fill.Attributes = char_attr;
193 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
195 /* Here we have to deal with a win32 console flake: If the scroll
196 region looks like abc and we scroll c to a and fill with d we get
197 cbd... if we scroll block c one line at a time to a, we get cdd...
198 Emacs expects cdd consistently... So we have to deal with that
199 here... (this also occurs scrolling the same way in the other
200 direction. */
202 if (n > 0)
204 if (scroll.Bottom < dest.Y)
206 for (i = scroll.Bottom; i < dest.Y; i++)
208 move_cursor (i, 0);
209 clear_end_of_line (FRAME_WIDTH (f));
213 else
215 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
217 if (nb < scroll.Top)
219 for (i = nb; i < scroll.Top; i++)
221 move_cursor (i, 0);
222 clear_end_of_line (FRAME_WIDTH (f));
227 cursor_coords.X = 0;
228 cursor_coords.Y = vpos;
230 hl_mode (save_highlight);
233 /* Changes attribute to use when drawing characters to control. */
234 static int
235 hl_mode (int new_highlight)
237 static int highlight = 0;
238 int old_highlight;
240 old_highlight = highlight;
241 highlight = (new_highlight != 0);
242 if (highlight)
244 char_attr = char_attr_reverse;
246 else
248 char_attr = char_attr_normal;
250 return old_highlight;
253 /* Call this when about to modify line at position VPOS and change whether it
254 is highlighted. */
255 void
256 change_line_highlight (int new_highlight, int vpos, int first_unused_hpos)
258 hl_mode (new_highlight);
259 move_cursor (vpos, 0);
260 clear_end_of_line (first_unused_hpos);
263 /* External interface to control of standout mode. Call this when about to
264 * modify line at position VPOS and not change whether it is highlighted. */
265 void
266 reassert_line_highlight (int highlight, int vpos)
268 hl_mode (highlight);
269 vpos; /* pedantic compiler silencer */
272 #undef LEFT
273 #undef RIGHT
274 #define LEFT 1
275 #define RIGHT 0
277 void
278 scroll_line (int dist, int direction)
280 /* The idea here is to implement a horizontal scroll in one line to
281 implement delete and half of insert. */
282 SMALL_RECT scroll;
283 COORD dest;
284 CHAR_INFO fill;
285 FRAME_PTR f = PICK_FRAME ();
287 scroll.Top = cursor_coords.Y;
288 scroll.Bottom = cursor_coords.Y;
290 if (direction == LEFT)
292 scroll.Left = cursor_coords.X + dist;
293 scroll.Right = FRAME_WIDTH (f) - 1;
295 else
297 scroll.Left = cursor_coords.X;
298 scroll.Right = FRAME_WIDTH (f) - dist - 1;
301 dest.X = cursor_coords.X;
302 dest.Y = cursor_coords.Y;
304 fill.Char.AsciiChar = 0x20;
305 fill.Attributes = char_attr;
307 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
311 /* If start is zero insert blanks instead of a string at start ?. */
312 void
313 insert_glyphs (register GLYPH *start, register int len)
315 scroll_line (len, RIGHT);
317 /* Move len chars to the right starting at cursor_coords, fill with blanks */
318 if (start)
320 /* Print the first len characters of start, cursor_coords.X adjusted
321 by write_glyphs. */
323 write_glyphs (start, len);
325 else
327 clear_end_of_line (cursor_coords.X + len);
331 void
332 write_glyphs (register GLYPH *string, register int len)
334 register unsigned int glyph_len = GLYPH_TABLE_LENGTH;
335 Lisp_Object *glyph_table = GLYPH_TABLE_BASE;
336 FRAME_PTR f = PICK_FRAME ();
337 register char *ptr;
338 GLYPH glyph;
339 WORD *attrs;
340 char *chars;
341 int i;
343 if (len <= 0)
344 return;
346 attrs = alloca (len * sizeof (*attrs));
347 chars = alloca (len * sizeof (*chars));
348 if (attrs == NULL || chars == NULL)
350 printf ("alloca failed in write_glyphs\n");
351 return;
354 /* We have to deal with the glyph indirection...go over the glyph
355 buffer and extract the characters. */
356 ptr = chars;
357 while (--len >= 0)
359 glyph = *string++;
361 if (glyph > glyph_len)
363 *ptr++ = glyph & 0xFF;
364 continue;
366 GLYPH_FOLLOW_ALIASES (glyph_table, glyph_len, glyph);
367 #ifndef HAVE_NTGUI
368 if (GLYPH_FACE (fixfix, glyph) != 0)
369 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix, glyph));
370 #endif /* !HAVE_NTGUI */
371 if (GLYPH_SIMPLE_P (glyph_table, glyph_len, glyph))
373 *ptr++ = glyph & 0xFF;
374 continue;
376 for (i = 0; i < GLYPH_LENGTH (glyph_table, glyph); i++)
378 *ptr++ = (GLYPH_STRING (glyph_table, glyph))[i];
382 /* Number of characters we have in the buffer. */
383 len = ptr-chars;
385 /* Fill in the attributes for these characters. */
386 for (i = 0; i < len; i++)
387 attrs[i] = char_attr;
389 /* Write the attributes. */
390 if (!WriteConsoleOutputAttribute (cur_screen, attrs, len, cursor_coords, &i))
392 printf ("Failed writing console attributes: %d\n", GetLastError ());
393 fflush (stdout);
396 /* Write the characters. */
397 if (!WriteConsoleOutputCharacter (cur_screen, chars, len, cursor_coords, &i))
399 printf ("Failed writing console characters: %d\n", GetLastError ());
400 fflush (stdout);
403 cursor_coords.X += len;
404 move_cursor (cursor_coords.Y, cursor_coords.X);
407 void
408 delete_glyphs (int n)
410 /* delete chars means scroll chars from cursor_coords.X + n to
411 cursor_coords.X, anything beyond the edge of the screen should
412 come out empty... */
414 scroll_line (n, LEFT);
417 static unsigned int sound_type = 0xFFFFFFFF;
419 void
420 nt_ring_bell (void)
422 if (sound_type == 0xFFFFFFFF)
423 Beep (666, 100);
424 else
425 MessageBeep (sound_type);
428 DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
429 "Set the sound generated when the bell is rung.\n\
430 SOUND is 'asterisk, 'exclamation, 'hand, 'question, or 'ok\n\
431 to use the corresponding system sound for the bell.\n\
432 SOUND is nil to use the normal beep.")
433 (sound)
434 Lisp_Object sound;
436 CHECK_SYMBOL (sound, 0);
438 if (NILP (sound))
439 sound_type = 0xFFFFFFFF;
440 else if (EQ (sound, intern ("asterisk")))
441 sound_type = MB_ICONASTERISK;
442 else if (EQ (sound, intern ("exclamation")))
443 sound_type = MB_ICONEXCLAMATION;
444 else if (EQ (sound, intern ("hand")))
445 sound_type = MB_ICONHAND;
446 else if (EQ (sound, intern ("question")))
447 sound_type = MB_ICONQUESTION;
448 else if (EQ (sound, intern ("ok")))
449 sound_type = MB_OK;
450 else
451 sound_type = 0xFFFFFFFF;
453 return sound;
456 /* Put our console back up, for ending a suspended session. */
457 void
458 take_console (void)
460 reset_kbd ();
461 SetConsoleActiveScreenBuffer (cur_screen);
464 void
465 reset_terminal_modes (void)
467 unset_kbd ();
468 SetConsoleActiveScreenBuffer (prev_screen);
471 void
472 set_terminal_modes (void)
474 CONSOLE_CURSOR_INFO cci;
476 if (cur_screen == NULL)
478 reset_kbd ();
479 cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
480 0, NULL,
481 CONSOLE_TEXTMODE_BUFFER,
482 NULL);
484 if (cur_screen == INVALID_HANDLE_VALUE)
486 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
487 printf ("LastError = 0x%lx\n", GetLastError ());
488 fflush (stdout);
489 exit (0);
492 SetConsoleActiveScreenBuffer (cur_screen);
494 /* make cursor big and visible (100 on Win95 makes it disappear) */
495 cci.dwSize = 99;
496 cci.bVisible = TRUE;
497 (void) SetConsoleCursorInfo (cur_screen, &cci);
501 /* hmmm... perhaps these let us bracket screen changes so that we can flush
502 clumps rather than one-character-at-a-time...
504 we'll start with not moving the cursor while an update is in progress. */
505 void
506 update_begin (FRAME_PTR f)
510 void
511 update_end (FRAME_PTR f)
513 SetConsoleCursorPosition (cur_screen, cursor_coords);
516 void
517 set_terminal_window (int size)
521 void
522 unset_kbd (void)
524 SetConsoleMode (keyboard_handle, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
525 ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT);
528 void
529 reset_kbd (void)
531 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
532 SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
535 typedef int (*term_hook) ();
537 void
538 initialize_win_nt_display (void)
540 CONSOLE_SCREEN_BUFFER_INFO info;
542 cursor_to_hook = (term_hook) move_cursor;
543 raw_cursor_to_hook = (term_hook) move_cursor;
544 clear_to_end_hook = (term_hook) clear_to_end;
545 clear_frame_hook = (term_hook) clear_frame;
546 clear_end_of_line_hook = (term_hook) clear_end_of_line;
547 ins_del_lines_hook = (term_hook) ins_del_lines;
548 change_line_highlight_hook = (term_hook) change_line_highlight;
549 reassert_line_highlight_hook = (term_hook) reassert_line_highlight;
550 insert_glyphs_hook = (term_hook) insert_glyphs;
551 write_glyphs_hook = (term_hook) write_glyphs;
552 delete_glyphs_hook = (term_hook) delete_glyphs;
553 ring_bell_hook = (term_hook) nt_ring_bell;
554 reset_terminal_modes_hook = (term_hook) reset_terminal_modes;
555 set_terminal_modes_hook = (term_hook) set_terminal_modes;
556 set_terminal_window_hook = (term_hook) set_terminal_window;
557 update_begin_hook = (term_hook) update_begin;
558 update_end_hook = (term_hook) update_end;
560 read_socket_hook = win32_read_socket;
561 mouse_position_hook = win32_mouse_position;
563 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
565 set_terminal_modes ();
567 GetConsoleScreenBufferInfo (cur_screen, &info);
569 meta_key = 1;
570 char_attr = info.wAttributes & 0xFF;
571 char_attr_normal = char_attr;
572 char_attr_reverse = ((char_attr & 0xf) << 4) + ((char_attr & 0xf0) >> 4);
574 FRAME_HEIGHT (selected_frame) = info.dwSize.Y; /* lines per page */
575 FRAME_WIDTH (selected_frame) = info.dwSize.X; /* characters per line */
577 move_cursor (0, 0);
579 clear_frame ();
582 DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
583 "Set screen colors.")
584 (foreground, background)
585 Lisp_Object foreground;
586 Lisp_Object background;
588 char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
589 char_attr_reverse = XFASTINT (background) + (XFASTINT (foreground) << 4);
591 Frecenter (Qnil);
592 return Qt;
595 DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
596 "Set cursor size.")
597 (size)
598 Lisp_Object size;
600 CONSOLE_CURSOR_INFO cci;
601 cci.dwSize = XFASTINT (size);
602 cci.bVisible = TRUE;
603 (void) SetConsoleCursorInfo (cur_screen, &cci);
605 return Qt;
608 #ifndef HAVE_NTGUI
609 void
610 pixel_to_glyph_coords (FRAME_PTR f, int pix_x, int pix_y, int *x, int *y,
611 void *bounds, int noclip)
613 *x = pix_x;
614 *y = pix_y;
617 void
618 glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y)
620 *pix_x = x;
621 *pix_y = y;
623 #endif /* !HAVE_NTGUI */
625 void
626 syms_of_ntterm ()
628 defsubr (&Sset_screen_color);
629 defsubr (&Sset_cursor_size);
630 defsubr (&Sset_message_beep);