Remove debugging macros.
[bpt/emacs.git] / src / w32console.c
CommitLineData
e6b20d65 1/* Terminal hooks for GNU Emacs on the Microsoft W32 API.
6cdfb6e6
RS
2 Copyright (C) 1992 Free Software Foundation, Inc.
3
3b7ad313
EN
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
6cdfb6e6
RS
20
21 Tim Fleehart (apollo@online.com) 1-17-92
22 Geoff Voelker (voelker@cs.washington.edu) 9-12-93
23*/
24
25
6816efce
GV
26#include <config.h>
27
6cdfb6e6
RS
28#include <stdlib.h>
29#include <stdio.h>
6cdfb6e6
RS
30#include <windows.h>
31
32#include "lisp.h"
2091aeb2 33#include "charset.h"
6cdfb6e6
RS
34#include "frame.h"
35#include "disptab.h"
36#include "termhooks.h"
489f9371 37#include "w32inevt.h"
6cdfb6e6 38
0534d577 39/* from window.c */
6cdfb6e6
RS
40extern Lisp_Object Frecenter ();
41
42/* from keyboard.c */
43extern int detect_input_pending ();
44
45/* from sysdep.c */
46extern int read_input_pending ();
47
48extern FRAME_PTR updating_frame;
49extern int meta_key;
50
51static void move_cursor (int row, int col);
52static void clear_to_end (void);
53static void clear_frame (void);
54static void clear_end_of_line (int);
55static void ins_del_lines (int vpos, int n);
56static void change_line_highlight (int, int, int);
57static void reassert_line_highlight (int, int);
58static void insert_glyphs (GLYPH *start, int len);
59static void write_glyphs (GLYPH *string, int len);
60static void delete_glyphs (int n);
fbd6baed 61void w32_sys_ring_bell (void);
6cdfb6e6
RS
62static void reset_terminal_modes (void);
63static void set_terminal_modes (void);
64static void set_terminal_window (int size);
65static void update_begin (FRAME_PTR f);
66static void update_end (FRAME_PTR f);
67static void reset_kbd (void);
68static void unset_kbd (void);
69static int hl_mode (int new_highlight);
70
71void
72DebPrint ()
73{
74}
75
76/* Init hook called in init_keyboard. */
77void (*keyboard_init_hook)(void) = reset_kbd;
78
79COORD cursor_coords;
80HANDLE prev_screen, cur_screen;
81UCHAR char_attr, char_attr_normal, char_attr_reverse;
82HANDLE keyboard_handle;
b6823b27 83DWORD prev_console_mode;
6cdfb6e6
RS
84
85
86/* Setting this as the ctrl handler prevents emacs from being killed when
40d578c9
RS
87 someone hits ^C in a 'suspended' session (child shell).
88 Also ignore Ctrl-Break signals. */
89
6cdfb6e6
RS
90BOOL
91ctrl_c_handler (unsigned long type)
92{
40d578c9 93 return (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT);
6cdfb6e6
RS
94}
95
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)
99
100/* Move the cursor to (row, col). */
101void
102move_cursor (int row, int col)
103{
104 cursor_coords.X = col;
105 cursor_coords.Y = row;
106
0534d577 107 if (updating_frame == (FRAME_PTR) NULL)
6cdfb6e6
RS
108 {
109 SetConsoleCursorPosition (cur_screen, cursor_coords);
110 }
111}
112
113/* Clear from cursor to end of screen. */
114void
115clear_to_end (void)
116{
117 FRAME_PTR f = PICK_FRAME ();
118
119 clear_end_of_line (FRAME_WIDTH (f) - 1);
120 ins_del_lines (cursor_coords.Y, FRAME_HEIGHT (f) - cursor_coords.Y - 1);
121}
122
123/* Clear the frame. */
124void
125clear_frame (void)
126{
6cdfb6e6 127 FRAME_PTR f = PICK_FRAME ();
b47278e1
GV
128 COORD dest;
129 int n, r;
130
6cdfb6e6
RS
131 hl_mode (0);
132
b47278e1
GV
133 n = FRAME_HEIGHT (f) * FRAME_WIDTH (f);
134 dest.X = dest.Y = 0;
135
136 FillConsoleOutputAttribute (cur_screen, char_attr, n, dest, &r);
137 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
138
6cdfb6e6
RS
139 move_cursor (0, 0);
140}
141
142
143static GLYPH glyph_base[256];
144static BOOL ceol_initialized = FALSE;
145
146/* Clear from Cursor to end (what's "standout marker"?). */
147void
148clear_end_of_line (int end)
149{
150 if (!ceol_initialized)
151 {
152 int i;
153 for (i = 0; i < 256; i++)
154 {
155 glyph_base[i] = SPACEGLYPH; /* empty space */
156 }
157 ceol_initialized = TRUE;
158 }
159 write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */
160}
161
162/* Insert n lines at vpos. if n is negative delete -n lines. */
163void
164ins_del_lines (int vpos, int n)
165{
166 int i, nb, save_highlight;
167 SMALL_RECT scroll;
168 COORD dest;
169 CHAR_INFO fill;
170 FRAME_PTR f = PICK_FRAME ();
171
172 if (n < 0)
173 {
174 scroll.Top = vpos - n;
175 scroll.Bottom = FRAME_HEIGHT (f);
176 dest.Y = vpos;
177 }
178 else
179 {
180 scroll.Top = vpos;
181 scroll.Bottom = FRAME_HEIGHT (f) - n;
182 dest.Y = vpos + n;
183 }
184 scroll.Left = 0;
185 scroll.Right = FRAME_WIDTH (f);
186
187 dest.X = 0;
188
189 save_highlight = hl_mode (0);
190
191 fill.Char.AsciiChar = 0x20;
192 fill.Attributes = char_attr;
193
194 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
195
fbd6baed 196 /* Here we have to deal with a w32 console flake: If the scroll
6cdfb6e6
RS
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. */
202
203 if (n > 0)
204 {
205 if (scroll.Bottom < dest.Y)
206 {
207 for (i = scroll.Bottom; i < dest.Y; i++)
208 {
209 move_cursor (i, 0);
210 clear_end_of_line (FRAME_WIDTH (f));
211 }
212 }
213 }
214 else
215 {
216 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
217
218 if (nb < scroll.Top)
219 {
220 for (i = nb; i < scroll.Top; i++)
221 {
222 move_cursor (i, 0);
223 clear_end_of_line (FRAME_WIDTH (f));
224 }
225 }
226 }
227
228 cursor_coords.X = 0;
229 cursor_coords.Y = vpos;
230
231 hl_mode (save_highlight);
232}
233
234/* Changes attribute to use when drawing characters to control. */
235static int
236hl_mode (int new_highlight)
237{
238 static int highlight = 0;
239 int old_highlight;
240
241 old_highlight = highlight;
242 highlight = (new_highlight != 0);
243 if (highlight)
244 {
245 char_attr = char_attr_reverse;
246 }
247 else
248 {
249 char_attr = char_attr_normal;
250 }
251 return old_highlight;
252}
253
254/* Call this when about to modify line at position VPOS and change whether it
255 is highlighted. */
256void
257change_line_highlight (int new_highlight, int vpos, int first_unused_hpos)
258{
259 hl_mode (new_highlight);
260 move_cursor (vpos, 0);
261 clear_end_of_line (first_unused_hpos);
262}
263
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. */
266void
267reassert_line_highlight (int highlight, int vpos)
268{
269 hl_mode (highlight);
270 vpos; /* pedantic compiler silencer */
271}
272
273#undef LEFT
274#undef RIGHT
275#define LEFT 1
276#define RIGHT 0
277
278void
279scroll_line (int dist, int direction)
280{
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 ();
287
288 scroll.Top = cursor_coords.Y;
289 scroll.Bottom = cursor_coords.Y;
290
291 if (direction == LEFT)
292 {
293 scroll.Left = cursor_coords.X + dist;
294 scroll.Right = FRAME_WIDTH (f) - 1;
295 }
296 else
297 {
298 scroll.Left = cursor_coords.X;
299 scroll.Right = FRAME_WIDTH (f) - dist - 1;
300 }
301
302 dest.X = cursor_coords.X;
303 dest.Y = cursor_coords.Y;
304
305 fill.Char.AsciiChar = 0x20;
306 fill.Attributes = char_attr;
307
308 ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill);
309}
310
311
312/* If start is zero insert blanks instead of a string at start ?. */
313void
314insert_glyphs (register GLYPH *start, register int len)
315{
316 scroll_line (len, RIGHT);
317
318 /* Move len chars to the right starting at cursor_coords, fill with blanks */
319 if (start)
320 {
321 /* Print the first len characters of start, cursor_coords.X adjusted
322 by write_glyphs. */
323
324 write_glyphs (start, len);
325 }
326 else
327 {
328 clear_end_of_line (cursor_coords.X + len);
329 }
330}
331
332void
333write_glyphs (register GLYPH *string, register int len)
334{
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;
343
b47278e1
GV
344 if (len <= 0)
345 return;
346
6cdfb6e6
RS
347 attrs = alloca (len * sizeof (*attrs));
348 chars = alloca (len * sizeof (*chars));
349 if (attrs == NULL || chars == NULL)
350 {
351 printf ("alloca failed in write_glyphs\n");
352 return;
353 }
354
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)
359 {
360 glyph = *string++;
361
362 if (glyph > glyph_len)
363 {
364 *ptr++ = glyph & 0xFF;
365 continue;
366 }
367 GLYPH_FOLLOW_ALIASES (glyph_table, glyph_len, glyph);
6e72ba86 368#ifndef HAVE_NTGUI
6cdfb6e6
RS
369 if (GLYPH_FACE (fixfix, glyph) != 0)
370 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix, glyph));
6e72ba86 371#endif /* !HAVE_NTGUI */
6cdfb6e6
RS
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 420void
fbd6baed 421w32_sys_ring_bell (void)
6cdfb6e6 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
e6b20d65 495 /* make cursor big and visible (100 on Windows 95 makes it disappear) */
e312961b 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{
b6823b27 525 SetConsoleMode (keyboard_handle, prev_console_mode);
6cdfb6e6
RS
526}
527
528void
529reset_kbd (void)
530{
531 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
b6823b27 532 GetConsoleMode (keyboard_handle, &prev_console_mode);
6cdfb6e6 533 SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
b6823b27
RS
534
535 /* Try to use interrupt input; if we can't, then start polling. */
536 Fset_input_mode (Qt, Qnil, Qt, Qnil);
6cdfb6e6
RS
537}
538
539typedef int (*term_hook) ();
540
541void
e6b20d65 542initialize_w32_display (void)
6cdfb6e6
RS
543{
544 CONSOLE_SCREEN_BUFFER_INFO info;
545
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;
fbd6baed 557 ring_bell_hook = (term_hook) w32_sys_ring_bell;
6cdfb6e6
RS
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;
563
fbd6baed
GV
564 read_socket_hook = w32_console_read_socket;
565 mouse_position_hook = w32_mouse_position;
6cdfb6e6
RS
566
567 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
568
569 set_terminal_modes ();
570
571 GetConsoleScreenBufferInfo (cur_screen, &info);
572
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);
577
578 FRAME_HEIGHT (selected_frame) = info.dwSize.Y; /* lines per page */
f6bb2a16 579 SET_FRAME_WIDTH (selected_frame, info.dwSize.X); /* characters per line */
6cdfb6e6
RS
580
581 move_cursor (0, 0);
582
583 clear_frame ();
584}
585
586DEFUN ("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;
591{
592 char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4);
593 char_attr_reverse = XFASTINT (background) + (XFASTINT (foreground) << 4);
594
595 Frecenter (Qnil);
596 return Qt;
597}
598
599DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
600 "Set cursor size.")
601 (size)
602 Lisp_Object size;
603{
604 CONSOLE_CURSOR_INFO cci;
605 cci.dwSize = XFASTINT (size);
606 cci.bVisible = TRUE;
607 (void) SetConsoleCursorInfo (cur_screen, &cci);
608
609 return Qt;
610}
611
6e72ba86 612#ifndef HAVE_NTGUI
6cdfb6e6
RS
613void
614pixel_to_glyph_coords (FRAME_PTR f, int pix_x, int pix_y, int *x, int *y,
615 void *bounds, int noclip)
616{
617 *x = pix_x;
618 *y = pix_y;
619}
620
621void
622glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y)
623{
624 *pix_x = x;
625 *pix_y = y;
626}
6e72ba86 627#endif /* !HAVE_NTGUI */
6cdfb6e6 628
0534d577 629void
6cdfb6e6
RS
630syms_of_ntterm ()
631{
632 defsubr (&Sset_screen_color);
633 defsubr (&Sset_cursor_size);
0534d577 634 defsubr (&Sset_message_beep);
6cdfb6e6 635}