[!MULTI_FRAME] (Factive_minibuffer_window): New function.
[bpt/emacs.git] / src / w32console.c
CommitLineData
6cdfb6e6
RS
1/* Terminal hooks for Windows NT port of GNU Emacs.
2 Copyright (C) 1992 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 GNU Emacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU General Public License along
17 with GNU Emacs; see the file COPYING. If not, write to the Free Software
18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 Tim Fleehart (apollo@online.com) 1-17-92
21 Geoff Voelker (voelker@cs.washington.edu) 9-12-93
22*/
23
24
6816efce
GV
25#include <config.h>
26
6cdfb6e6
RS
27#include <stdlib.h>
28#include <stdio.h>
6cdfb6e6
RS
29#include <windows.h>
30
31#include "lisp.h"
32#include "frame.h"
33#include "disptab.h"
34#include "termhooks.h"
35
36#include "ntinevt.h"
37
0534d577 38/* from window.c */
6cdfb6e6
RS
39extern Lisp_Object Frecenter ();
40
41/* from keyboard.c */
42extern int detect_input_pending ();
43
44/* from sysdep.c */
45extern int read_input_pending ();
46
47extern FRAME_PTR updating_frame;
48extern int meta_key;
49
50static void move_cursor (int row, int col);
51static void clear_to_end (void);
52static void clear_frame (void);
53static void clear_end_of_line (int);
54static void ins_del_lines (int vpos, int n);
55static void change_line_highlight (int, int, int);
56static void reassert_line_highlight (int, int);
57static void insert_glyphs (GLYPH *start, int len);
58static void write_glyphs (GLYPH *string, int len);
59static void delete_glyphs (int n);
60static void ring_bell (void);
61static void reset_terminal_modes (void);
62static void set_terminal_modes (void);
63static void set_terminal_window (int size);
64static void update_begin (FRAME_PTR f);
65static void update_end (FRAME_PTR f);
66static void reset_kbd (void);
67static void unset_kbd (void);
68static int hl_mode (int new_highlight);
69
70void
71DebPrint ()
72{
73}
74
75/* Init hook called in init_keyboard. */
76void (*keyboard_init_hook)(void) = reset_kbd;
77
78COORD cursor_coords;
79HANDLE prev_screen, cur_screen;
80UCHAR char_attr, char_attr_normal, char_attr_reverse;
81HANDLE keyboard_handle;
82
83
84/* Setting this as the ctrl handler prevents emacs from being killed when
40d578c9
RS
85 someone hits ^C in a 'suspended' session (child shell).
86 Also ignore Ctrl-Break signals. */
87
6cdfb6e6
RS
88BOOL
89ctrl_c_handler (unsigned long type)
90{
40d578c9 91 return (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT);
6cdfb6e6
RS
92}
93
94/* If we're updating a frame, use it as the current frame
95 Otherwise, use the selected frame. */
96#define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
97
98/* Move the cursor to (row, col). */
99void
100move_cursor (int row, int col)
101{
102 cursor_coords.X = col;
103 cursor_coords.Y = row;
104
0534d577 105 if (updating_frame == (FRAME_PTR) NULL)
6cdfb6e6
RS
106 {
107 SetConsoleCursorPosition (cur_screen, cursor_coords);
108 }
109}
110
111/* Clear from cursor to end of screen. */
112void
113clear_to_end (void)
114{
115 FRAME_PTR f = PICK_FRAME ();
116
117 clear_end_of_line (FRAME_WIDTH (f) - 1);
118 ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1);
119}
120
121/* Clear the frame. */
122void
123clear_frame (void)
124{
125 SMALL_RECT scroll;
126 COORD dest;
127 CHAR_INFO fill;
128 FRAME_PTR f = PICK_FRAME ();
129
130 hl_mode (0);
131
132 scroll.Top = 0;
133 scroll.Bottom = FRAME_HEIGHT (f) - 1;
134 scroll.Left = 0;
135 scroll.Right = FRAME_WIDTH (f) - 1;
136
137 dest.Y = FRAME_HEIGHT (f);
138 dest.X = 0;
139
140 fill.Char.AsciiChar = 0x20;
141 fill.Attributes = char_attr;
142
143 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
144 move_cursor (0, 0);
145}
146
147
148static GLYPH glyph_base[256];
149static BOOL ceol_initialized = FALSE;
150
151/* Clear from Cursor to end (what's "standout marker"?). */
152void
153clear_end_of_line (int end)
154{
155 if (!ceol_initialized)
156 {
157 int i;
158 for (i = 0; i < 256; i++)
159 {
160 glyph_base[i] = SPACEGLYPH; /* empty space */
161 }
162 ceol_initialized = TRUE;
163 }
164 write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */
165}
166
167/* Insert n lines at vpos. if n is negative delete -n lines. */
168void
169ins_del_lines (int vpos, int n)
170{
171 int i, nb, save_highlight;
172 SMALL_RECT scroll;
173 COORD dest;
174 CHAR_INFO fill;
175 FRAME_PTR f = PICK_FRAME ();
176
177 if (n < 0)
178 {
179 scroll.Top = vpos - n;
180 scroll.Bottom = FRAME_HEIGHT (f);
181 dest.Y = vpos;
182 }
183 else
184 {
185 scroll.Top = vpos;
186 scroll.Bottom = FRAME_HEIGHT (f) - n;
187 dest.Y = vpos + n;
188 }
189 scroll.Left = 0;
190 scroll.Right = FRAME_WIDTH (f);
191
192 dest.X = 0;
193
194 save_highlight = hl_mode (0);
195
196 fill.Char.AsciiChar = 0x20;
197 fill.Attributes = char_attr;
198
199 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
200
201 /* Here we have to deal with a win32 console flake: If the scroll
202 region looks like abc and we scroll c to a and fill with d we get
203 cbd... if we scroll block c one line at a time to a, we get cdd...
204 Emacs expects cdd consistently... So we have to deal with that
205 here... (this also occurs scrolling the same way in the other
206 direction. */
207
208 if (n > 0)
209 {
210 if (scroll.Bottom < dest.Y)
211 {
212 for (i = scroll.Bottom; i < dest.Y; i++)
213 {
214 move_cursor (i, 0);
215 clear_end_of_line (FRAME_WIDTH (f));
216 }
217 }
218 }
219 else
220 {
221 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
222
223 if (nb < scroll.Top)
224 {
225 for (i = nb; i < scroll.Top; i++)
226 {
227 move_cursor (i, 0);
228 clear_end_of_line (FRAME_WIDTH (f));
229 }
230 }
231 }
232
233 cursor_coords.X = 0;
234 cursor_coords.Y = vpos;
235
236 hl_mode (save_highlight);
237}
238
239/* Changes attribute to use when drawing characters to control. */
240static int
241hl_mode (int new_highlight)
242{
243 static int highlight = 0;
244 int old_highlight;
245
246 old_highlight = highlight;
247 highlight = (new_highlight != 0);
248 if (highlight)
249 {
250 char_attr = char_attr_reverse;
251 }
252 else
253 {
254 char_attr = char_attr_normal;
255 }
256 return old_highlight;
257}
258
259/* Call this when about to modify line at position VPOS and change whether it
260 is highlighted. */
261void
262change_line_highlight (int new_highlight, int vpos, int first_unused_hpos)
263{
264 hl_mode (new_highlight);
265 move_cursor (vpos, 0);
266 clear_end_of_line (first_unused_hpos);
267}
268
269/* External interface to control of standout mode. Call this when about to
270 * modify line at position VPOS and not change whether it is highlighted. */
271void
272reassert_line_highlight (int highlight, int vpos)
273{
274 hl_mode (highlight);
275 vpos; /* pedantic compiler silencer */
276}
277
278#undef LEFT
279#undef RIGHT
280#define LEFT 1
281#define RIGHT 0
282
283void
284scroll_line (int dist, int direction)
285{
286 /* The idea here is to implement a horizontal scroll in one line to
287 implement delete and half of insert. */
288 SMALL_RECT scroll;
289 COORD dest;
290 CHAR_INFO fill;
291 FRAME_PTR f = PICK_FRAME ();
292
293 scroll.Top = cursor_coords.Y;
294 scroll.Bottom = cursor_coords.Y;
295
296 if (direction == LEFT)
297 {
298 scroll.Left = cursor_coords.X + dist;
299 scroll.Right = FRAME_WIDTH (f) - 1;
300 }
301 else
302 {
303 scroll.Left = cursor_coords.X;
304 scroll.Right = FRAME_WIDTH (f) - dist - 1;
305 }
306
307 dest.X = cursor_coords.X;
308 dest.Y = cursor_coords.Y;
309
310 fill.Char.AsciiChar = 0x20;
311 fill.Attributes = char_attr;
312
313 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
314}
315
316
317/* If start is zero insert blanks instead of a string at start ?. */
318void
319insert_glyphs (register GLYPH *start, register int len)
320{
321 scroll_line (len, RIGHT);
322
323 /* Move len chars to the right starting at cursor_coords, fill with blanks */
324 if (start)
325 {
326 /* Print the first len characters of start, cursor_coords.X adjusted
327 by write_glyphs. */
328
329 write_glyphs (start, len);
330 }
331 else
332 {
333 clear_end_of_line (cursor_coords.X + len);
334 }
335}
336
337void
338write_glyphs (register GLYPH *string, register int len)
339{
340 register unsigned int glyph_len = GLYPH_TABLE_LENGTH;
341 Lisp_Object *glyph_table = GLYPH_TABLE_BASE;
342 FRAME_PTR f = PICK_FRAME ();
343 register char *ptr;
344 GLYPH glyph;
345 WORD *attrs;
346 char *chars;
347 int i;
348
349 attrs = alloca (len * sizeof (*attrs));
350 chars = alloca (len * sizeof (*chars));
351 if (attrs == NULL || chars == NULL)
352 {
353 printf ("alloca failed in write_glyphs\n");
354 return;
355 }
356
357 /* We have to deal with the glyph indirection...go over the glyph
358 buffer and extract the characters. */
359 ptr = chars;
360 while (--len >= 0)
361 {
362 glyph = *string++;
363
364 if (glyph > glyph_len)
365 {
366 *ptr++ = glyph & 0xFF;
367 continue;
368 }
369 GLYPH_FOLLOW_ALIASES (glyph_table, glyph_len, glyph);
370 if (GLYPH_FACE (fixfix, glyph) != 0)
371 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix, glyph));
372 if (GLYPH_SIMPLE_P (glyph_table, glyph_len, glyph))
373 {
374 *ptr++ = glyph & 0xFF;
375 continue;
376 }
377 for (i = 0; i < GLYPH_LENGTH (glyph_table, glyph); i++)
378 {
379 *ptr++ = (GLYPH_STRING (glyph_table, glyph))[i];
380 }
381 }
382
383 /* Number of characters we have in the buffer. */
384 len = ptr-chars;
385
386 /* Fill in the attributes for these characters. */
e312961b
GV
387 for (i = 0; i < len; i++)
388 attrs[i] = char_attr;
6cdfb6e6
RS
389
390 /* Write the attributes. */
391 if (!WriteConsoleOutputAttribute (cur_screen, attrs, len, cursor_coords, &i))
392 {
0534d577 393 printf ("Failed writing console attributes: %d\n", GetLastError ());
6cdfb6e6
RS
394 fflush (stdout);
395 }
396
397 /* Write the characters. */
398 if (!WriteConsoleOutputCharacter (cur_screen, chars, len, cursor_coords, &i))
399 {
0534d577 400 printf ("Failed writing console characters: %d\n", GetLastError ());
6cdfb6e6
RS
401 fflush (stdout);
402 }
403
404 cursor_coords.X += len;
405 move_cursor (cursor_coords.Y, cursor_coords.X);
406}
407
408void
409delete_glyphs (int n)
410{
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... */
414
415 scroll_line (n, LEFT);
416}
417
0534d577
KH
418static unsigned int sound_type = 0xFFFFFFFF;
419
6cdfb6e6
RS
420void
421ring_bell (void)
422{
0534d577
KH
423 if (sound_type == 0xFFFFFFFF)
424 Beep (666, 100);
425 else
426 MessageBeep (sound_type);
6cdfb6e6
RS
427}
428
0534d577
KH
429DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
430 "Set the sound generated when the bell is rung.\n\
431SOUND is 'asterisk, 'exclamation, 'hand, 'question, or 'ok\n\
432to use the corresponding system sound for the bell.\n\
433SOUND is nil to use the normal beep.")
434 (sound)
435 Lisp_Object sound;
6cdfb6e6 436{
0534d577
KH
437 CHECK_SYMBOL (sound, 0);
438
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;
453
454 return sound;
6cdfb6e6
RS
455}
456
457/* Put our console back up, for ending a suspended session. */
458void
459take_console (void)
460{
461 reset_kbd ();
462 SetConsoleActiveScreenBuffer (cur_screen);
463}
464
465void
466reset_terminal_modes (void)
467{
468 unset_kbd ();
469 SetConsoleActiveScreenBuffer (prev_screen);
6cdfb6e6
RS
470}
471
472void
473set_terminal_modes (void)
474{
475 CONSOLE_CURSOR_INFO cci;
476
477 if (cur_screen == NULL)
478 {
479 reset_kbd ();
480 cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
481 0, NULL,
482 CONSOLE_TEXTMODE_BUFFER,
483 NULL);
484
485 if (cur_screen == INVALID_HANDLE_VALUE)
486 {
487 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
488 printf ("LastError = 0x%lx\n", GetLastError ());
489 fflush (stdout);
490 exit (0);
491 }
492
493 SetConsoleActiveScreenBuffer (cur_screen);
494
e312961b
GV
495 /* make cursor big and visible (100 on Win95 makes it disappear) */
496 cci.dwSize = 99;
6cdfb6e6
RS
497 cci.bVisible = TRUE;
498 (void) SetConsoleCursorInfo (cur_screen, &cci);
499 }
500}
501
502/* hmmm... perhaps these let us bracket screen changes so that we can flush
503 clumps rather than one-character-at-a-time...
504
505 we'll start with not moving the cursor while an update is in progress. */
506void
507update_begin (FRAME_PTR f)
508{
509}
510
511void
512update_end (FRAME_PTR f)
513{
514 SetConsoleCursorPosition (cur_screen, cursor_coords);
515}
516
517void
518set_terminal_window (int size)
519{
520}
521
522void
523unset_kbd (void)
524{
525 SetConsoleMode (keyboard_handle, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
526 ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT);
527}
528
529void
530reset_kbd (void)
531{
532 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
533 SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
534}
535
536typedef int (*term_hook) ();
537
538void
539initialize_win_nt_display (void)
540{
541 CONSOLE_SCREEN_BUFFER_INFO info;
542
543 cursor_to_hook = (term_hook) move_cursor;
544 raw_cursor_to_hook = (term_hook) move_cursor;
545 clear_to_end_hook = (term_hook) clear_to_end;
546 clear_frame_hook = (term_hook) clear_frame;
547 clear_end_of_line_hook = (term_hook) clear_end_of_line;
548 ins_del_lines_hook = (term_hook) ins_del_lines;
549 change_line_highlight_hook = (term_hook) change_line_highlight;
550 reassert_line_highlight_hook = (term_hook) reassert_line_highlight;
551 insert_glyphs_hook = (term_hook) insert_glyphs;
552 write_glyphs_hook = (term_hook) write_glyphs;
553 delete_glyphs_hook = (term_hook) delete_glyphs;
554 ring_bell_hook = (term_hook) ring_bell;
555 reset_terminal_modes_hook = (term_hook) reset_terminal_modes;
556 set_terminal_modes_hook = (term_hook) set_terminal_modes;
557 set_terminal_window_hook = (term_hook) set_terminal_window;
558 update_begin_hook = (term_hook) update_begin;
559 update_end_hook = (term_hook) update_end;
560
561 read_socket_hook = win32_read_socket;
562 mouse_position_hook = win32_mouse_position;
563
564 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
565
566 set_terminal_modes ();
567
568 GetConsoleScreenBufferInfo (cur_screen, &info);
569
570 meta_key = 1;
571 char_attr = info.wAttributes & 0xFF;
572 char_attr_normal = char_attr;
573 char_attr_reverse = ((char_attr & 0xf) << 4) + ((char_attr & 0xf0) >> 4);
574
575 FRAME_HEIGHT (selected_frame) = info.dwSize.Y; /* lines per page */
576 FRAME_WIDTH (selected_frame) = info.dwSize.X; /* characters per line */
577
578 move_cursor (0, 0);
579
580 clear_frame ();
581}
582
583DEFUN ("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;
588{
589 char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
590 char_attr_reverse = XFASTINT (background) + (XFASTINT (foreground) << 4);
591
592 Frecenter (Qnil);
593 return Qt;
594}
595
596DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
597 "Set cursor size.")
598 (size)
599 Lisp_Object size;
600{
601 CONSOLE_CURSOR_INFO cci;
602 cci.dwSize = XFASTINT (size);
603 cci.bVisible = TRUE;
604 (void) SetConsoleCursorInfo (cur_screen, &cci);
605
606 return Qt;
607}
608
609void
610pixel_to_glyph_coords (FRAME_PTR f, int pix_x, int pix_y, int *x, int *y,
611 void *bounds, int noclip)
612{
613 *x = pix_x;
614 *y = pix_y;
615}
616
617void
618glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y)
619{
620 *pix_x = x;
621 *pix_y = y;
622}
623
0534d577 624void
6cdfb6e6
RS
625syms_of_ntterm ()
626{
627 defsubr (&Sset_screen_color);
628 defsubr (&Sset_cursor_size);
0534d577 629 defsubr (&Sset_message_beep);
6cdfb6e6 630}