(command-line-1): Rearrange initial screen.
[emacs.git] / src / w32console.c
blob67886590714925ddd6ff49b97b78a28fc618c430
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;
83 DWORD prev_console_mode;
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. */
90 BOOL
91 ctrl_c_handler (unsigned long type)
93 return (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT);
96 /* If we're updating a frame, use it as the current frame
97 Otherwise, use the selected frame. */
98 #define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
100 /* Move the cursor to (row, col). */
101 void
102 move_cursor (int row, int col)
104 cursor_coords.X = col;
105 cursor_coords.Y = row;
107 if (updating_frame == (FRAME_PTR) NULL)
109 SetConsoleCursorPosition (cur_screen, cursor_coords);
113 /* Clear from cursor to end of screen. */
114 void
115 clear_to_end (void)
117 FRAME_PTR f = PICK_FRAME ();
119 clear_end_of_line (FRAME_WIDTH (f) - 1);
120 ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1);
123 /* Clear the frame. */
124 void
125 clear_frame (void)
127 FRAME_PTR f = PICK_FRAME ();
128 COORD dest;
129 int n, r;
131 hl_mode (0);
133 n = FRAME_HEIGHT (f) * FRAME_WIDTH (f);
134 dest.X = dest.Y = 0;
136 FillConsoleOutputAttribute (cur_screen, char_attr, n, dest, &r);
137 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
139 move_cursor (0, 0);
143 static GLYPH glyph_base[256];
144 static BOOL ceol_initialized = FALSE;
146 /* Clear from Cursor to end (what's "standout marker"?). */
147 void
148 clear_end_of_line (int end)
150 if (!ceol_initialized)
152 int i;
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. */
163 void
164 ins_del_lines (int vpos, int n)
166 int i, nb, save_highlight;
167 SMALL_RECT scroll;
168 COORD dest;
169 CHAR_INFO fill;
170 FRAME_PTR f = PICK_FRAME ();
172 if (n < 0)
174 scroll.Top = vpos - n;
175 scroll.Bottom = FRAME_HEIGHT (f);
176 dest.Y = vpos;
178 else
180 scroll.Top = vpos;
181 scroll.Bottom = FRAME_HEIGHT (f) - n;
182 dest.Y = vpos + n;
184 scroll.Left = 0;
185 scroll.Right = FRAME_WIDTH (f);
187 dest.X = 0;
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 win32 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
201 direction. */
203 if (n > 0)
205 if (scroll.Bottom < dest.Y)
207 for (i = scroll.Bottom; i < dest.Y; i++)
209 move_cursor (i, 0);
210 clear_end_of_line (FRAME_WIDTH (f));
214 else
216 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
218 if (nb < scroll.Top)
220 for (i = nb; i < scroll.Top; i++)
222 move_cursor (i, 0);
223 clear_end_of_line (FRAME_WIDTH (f));
228 cursor_coords.X = 0;
229 cursor_coords.Y = vpos;
231 hl_mode (save_highlight);
234 /* Changes attribute to use when drawing characters to control. */
235 static int
236 hl_mode (int new_highlight)
238 static int highlight = 0;
239 int old_highlight;
241 old_highlight = highlight;
242 highlight = (new_highlight != 0);
243 if (highlight)
245 char_attr = char_attr_reverse;
247 else
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
255 is highlighted. */
256 void
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. */
266 void
267 reassert_line_highlight (int highlight, int vpos)
269 hl_mode (highlight);
270 vpos; /* pedantic compiler silencer */
273 #undef LEFT
274 #undef RIGHT
275 #define LEFT 1
276 #define RIGHT 0
278 void
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. */
283 SMALL_RECT scroll;
284 COORD dest;
285 CHAR_INFO fill;
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;
296 else
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 ?. */
313 void
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 */
319 if (start)
321 /* Print the first len characters of start, cursor_coords.X adjusted
322 by write_glyphs. */
324 write_glyphs (start, len);
326 else
328 clear_end_of_line (cursor_coords.X + len);
332 void
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 ();
338 register char *ptr;
339 GLYPH glyph;
340 WORD *attrs;
341 char *chars;
342 int i;
344 if (len <= 0)
345 return;
347 attrs = alloca (len * sizeof (*attrs));
348 chars = alloca (len * sizeof (*chars));
349 if (attrs == NULL || chars == NULL)
351 printf ("alloca failed in write_glyphs\n");
352 return;
355 /* We have to deal with the glyph indirection...go over the glyph
356 buffer and extract the characters. */
357 ptr = chars;
358 while (--len >= 0)
360 glyph = *string++;
362 if (glyph > glyph_len)
364 *ptr++ = glyph & 0xFF;
365 continue;
367 GLYPH_FOLLOW_ALIASES (glyph_table, glyph_len, glyph);
368 #ifndef HAVE_NTGUI
369 if (GLYPH_FACE (fixfix, glyph) != 0)
370 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix, glyph));
371 #endif /* !HAVE_NTGUI */
372 if (GLYPH_SIMPLE_P (glyph_table, glyph_len, glyph))
374 *ptr++ = glyph & 0xFF;
375 continue;
377 for (i = 0; i < GLYPH_LENGTH (glyph_table, glyph); i++)
379 *ptr++ = (GLYPH_STRING (glyph_table, glyph))[i];
383 /* Number of characters we have in the buffer. */
384 len = ptr-chars;
386 /* Fill in the attributes for these characters. */
387 for (i = 0; i < len; i++)
388 attrs[i] = char_attr;
390 /* Write the attributes. */
391 if (!WriteConsoleOutputAttribute (cur_screen, attrs, len, cursor_coords, &i))
393 printf ("Failed writing console attributes: %d\n", GetLastError ());
394 fflush (stdout);
397 /* Write the characters. */
398 if (!WriteConsoleOutputCharacter (cur_screen, chars, len, cursor_coords, &i))
400 printf ("Failed writing console characters: %d\n", GetLastError ());
401 fflush (stdout);
404 cursor_coords.X += len;
405 move_cursor (cursor_coords.Y, cursor_coords.X);
408 void
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
413 come out empty... */
415 scroll_line (n, LEFT);
418 static unsigned int sound_type = 0xFFFFFFFF;
420 void
421 nt_ring_bell (void)
423 if (sound_type == 0xFFFFFFFF)
424 Beep (666, 100);
425 else
426 MessageBeep (sound_type);
429 DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
430 "Set the sound generated when the bell is rung.\n\
431 SOUND is 'asterisk, 'exclamation, 'hand, 'question, or 'ok\n\
432 to use the corresponding system sound for the bell.\n\
433 SOUND is nil to use the normal beep.")
434 (sound)
435 Lisp_Object sound;
437 CHECK_SYMBOL (sound, 0);
439 if (NILP (sound))
440 sound_type = 0xFFFFFFFF;
441 else if (EQ (sound, intern ("asterisk")))
442 sound_type = MB_ICONASTERISK;
443 else if (EQ (sound, intern ("exclamation")))
444 sound_type = MB_ICONEXCLAMATION;
445 else if (EQ (sound, intern ("hand")))
446 sound_type = MB_ICONHAND;
447 else if (EQ (sound, intern ("question")))
448 sound_type = MB_ICONQUESTION;
449 else if (EQ (sound, intern ("ok")))
450 sound_type = MB_OK;
451 else
452 sound_type = 0xFFFFFFFF;
454 return sound;
457 /* Put our console back up, for ending a suspended session. */
458 void
459 take_console (void)
461 reset_kbd ();
462 SetConsoleActiveScreenBuffer (cur_screen);
465 void
466 reset_terminal_modes (void)
468 unset_kbd ();
469 SetConsoleActiveScreenBuffer (prev_screen);
472 void
473 set_terminal_modes (void)
475 CONSOLE_CURSOR_INFO cci;
477 if (cur_screen == NULL)
479 reset_kbd ();
480 cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
481 0, NULL,
482 CONSOLE_TEXTMODE_BUFFER,
483 NULL);
485 if (cur_screen == INVALID_HANDLE_VALUE)
487 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
488 printf ("LastError = 0x%lx\n", GetLastError ());
489 fflush (stdout);
490 exit (0);
493 SetConsoleActiveScreenBuffer (cur_screen);
495 /* make cursor big and visible (100 on Win95 makes it disappear) */
496 cci.dwSize = 99;
497 cci.bVisible = TRUE;
498 (void) SetConsoleCursorInfo (cur_screen, &cci);
502 /* hmmm... perhaps these let us bracket screen changes so that we can flush
503 clumps rather than one-character-at-a-time...
505 we'll start with not moving the cursor while an update is in progress. */
506 void
507 update_begin (FRAME_PTR f)
511 void
512 update_end (FRAME_PTR f)
514 SetConsoleCursorPosition (cur_screen, cursor_coords);
517 void
518 set_terminal_window (int size)
522 void
523 unset_kbd (void)
525 SetConsoleMode (keyboard_handle, prev_console_mode);
528 void
529 reset_kbd (void)
531 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
532 GetConsoleMode (keyboard_handle, &prev_console_mode);
533 SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
535 /* Try to use interrupt input; if we can't, then start polling. */
536 Fset_input_mode (Qt, Qnil, Qt, Qnil);
539 typedef int (*term_hook) ();
541 void
542 initialize_win_nt_display (void)
544 CONSOLE_SCREEN_BUFFER_INFO info;
546 cursor_to_hook = (term_hook) move_cursor;
547 raw_cursor_to_hook = (term_hook) move_cursor;
548 clear_to_end_hook = (term_hook) clear_to_end;
549 clear_frame_hook = (term_hook) clear_frame;
550 clear_end_of_line_hook = (term_hook) clear_end_of_line;
551 ins_del_lines_hook = (term_hook) ins_del_lines;
552 change_line_highlight_hook = (term_hook) change_line_highlight;
553 reassert_line_highlight_hook = (term_hook) reassert_line_highlight;
554 insert_glyphs_hook = (term_hook) insert_glyphs;
555 write_glyphs_hook = (term_hook) write_glyphs;
556 delete_glyphs_hook = (term_hook) delete_glyphs;
557 ring_bell_hook = (term_hook) nt_ring_bell;
558 reset_terminal_modes_hook = (term_hook) reset_terminal_modes;
559 set_terminal_modes_hook = (term_hook) set_terminal_modes;
560 set_terminal_window_hook = (term_hook) set_terminal_window;
561 update_begin_hook = (term_hook) update_begin;
562 update_end_hook = (term_hook) update_end;
564 read_socket_hook = win32_read_socket;
565 mouse_position_hook = win32_mouse_position;
567 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
569 set_terminal_modes ();
571 GetConsoleScreenBufferInfo (cur_screen, &info);
573 meta_key = 1;
574 char_attr = info.wAttributes & 0xFF;
575 char_attr_normal = char_attr;
576 char_attr_reverse = ((char_attr & 0xf) << 4) + ((char_attr & 0xf0) >> 4);
578 FRAME_HEIGHT (selected_frame) = info.dwSize.Y; /* lines per page */
579 FRAME_WIDTH (selected_frame) = info.dwSize.X; /* characters per line */
581 move_cursor (0, 0);
583 clear_frame ();
586 DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
587 "Set screen colors.")
588 (foreground, background)
589 Lisp_Object foreground;
590 Lisp_Object background;
592 char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
593 char_attr_reverse = XFASTINT (background) + (XFASTINT (foreground) << 4);
595 Frecenter (Qnil);
596 return Qt;
599 DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
600 "Set cursor size.")
601 (size)
602 Lisp_Object size;
604 CONSOLE_CURSOR_INFO cci;
605 cci.dwSize = XFASTINT (size);
606 cci.bVisible = TRUE;
607 (void) SetConsoleCursorInfo (cur_screen, &cci);
609 return Qt;
612 #ifndef HAVE_NTGUI
613 void
614 pixel_to_glyph_coords (FRAME_PTR f, int pix_x, int pix_y, int *x, int *y,
615 void *bounds, int noclip)
617 *x = pix_x;
618 *y = pix_y;
621 void
622 glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y)
624 *pix_x = x;
625 *pix_y = y;
627 #endif /* !HAVE_NTGUI */
629 void
630 syms_of_ntterm ()
632 defsubr (&Sset_screen_color);
633 defsubr (&Sset_cursor_size);
634 defsubr (&Sset_message_beep);