1 /* Terminal hooks for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1992, 1999, 2001-2021 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
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or (at
9 your option) any later version.
10
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.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19 /*
20 Tim Fleehart (apollo@online.com) 1-17-92
21 Geoff Voelker (voelker@cs.washington.edu) 9-12-93
22 */
23
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <windows.h>
29
30 #include "lisp.h"
31 #include "coding.h"
32 #include "termchar.h" /* for FRAME_TTY */
33 #include "dispextern.h" /* for tty_defined_color */
34 #include "menu.h" /* for tty_menu_show */
35 #include "w32term.h"
36 #include "w32common.h" /* for os_subtype */
37 #include "w32inevt.h"
38
39 #ifdef WINDOWSNT
40 #include "w32.h" /* for syms_of_ntterm */
41 #endif
42
43 static void w32con_move_cursor (struct frame *f, int row, int col);
44 static void w32con_clear_to_end (struct frame *f);
45 static void w32con_clear_frame (struct frame *f);
46 static void w32con_clear_end_of_line (struct frame *f, int);
47 static void w32con_ins_del_lines (struct frame *f, int vpos, int n);
48 static void w32con_insert_glyphs (struct frame *f, struct glyph *start, int len);
49 static void w32con_write_glyphs (struct frame *f, struct glyph *string, int len);
50 static void w32con_delete_glyphs (struct frame *f, int n);
51 static void w32con_reset_terminal_modes (struct terminal *t);
52 static void w32con_set_terminal_modes (struct terminal *t);
53 static void w32con_update_begin (struct frame * f);
54 static void w32con_update_end (struct frame * f);
55 static WORD w32_face_attributes (struct frame *f, int face_id);
56
57 static COORD cursor_coords;
58 static HANDLE prev_screen, cur_screen;
59 static WORD char_attr_normal;
60 static DWORD prev_console_mode;
61
62 static CONSOLE_CURSOR_INFO console_cursor_info;
63 #ifndef USE_SEPARATE_SCREEN
64 static CONSOLE_CURSOR_INFO prev_console_cursor;
65 #endif
66
67 HANDLE keyboard_handle;
68 int w32_console_unicode_input;
69
70
71 /* Setting this as the ctrl handler prevents emacs from being killed when
72 someone hits ^C in a 'suspended' session (child shell).
73 Also ignore Ctrl-Break signals. */
74
75 BOOL ctrl_c_handler (unsigned long);
76
77 BOOL
ctrl_c_handler(unsigned long type)78 ctrl_c_handler (unsigned long type)
79 {
80 /* Only ignore "interrupt" events when running interactively. */
81 return (!noninteractive
82 && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
83 }
84
85
86 /* Move the cursor to (ROW, COL) on FRAME. */
87 static void
w32con_move_cursor(struct frame * f,int row,int col)88 w32con_move_cursor (struct frame *f, int row, int col)
89 {
90 cursor_coords.X = col;
91 cursor_coords.Y = row;
92
93 /* TODO: for multi-tty support, cur_screen should be replaced with a
94 reference to the terminal for this frame. */
95 SetConsoleCursorPosition (cur_screen, cursor_coords);
96 }
97
98 void
w32con_hide_cursor(void)99 w32con_hide_cursor (void)
100 {
101 GetConsoleCursorInfo (cur_screen, &console_cursor_info);
102 console_cursor_info.bVisible = FALSE;
103 SetConsoleCursorInfo (cur_screen, &console_cursor_info);
104 }
105
106 void
w32con_show_cursor(void)107 w32con_show_cursor (void)
108 {
109 GetConsoleCursorInfo (cur_screen, &console_cursor_info);
110 console_cursor_info.bVisible = TRUE;
111 SetConsoleCursorInfo (cur_screen, &console_cursor_info);
112 }
113
114 /* Clear from cursor to end of screen. */
115 static void
w32con_clear_to_end(struct frame * f)116 w32con_clear_to_end (struct frame *f)
117 {
118 w32con_clear_end_of_line (f, FRAME_COLS (f) - 1);
119 w32con_ins_del_lines (f, cursor_coords.Y, FRAME_TOTAL_LINES (f) - cursor_coords.Y - 1);
120 }
121
122 /* Clear the frame. */
123 static void
w32con_clear_frame(struct frame * f)124 w32con_clear_frame (struct frame *f)
125 {
126 COORD dest;
127 int n;
128 DWORD r;
129 CONSOLE_SCREEN_BUFFER_INFO info;
130
131 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
132
133 /* Remember that the screen buffer might be wider than the window. */
134 n = FRAME_TOTAL_LINES (f) * info.dwSize.X;
135 dest.X = dest.Y = 0;
136
137 FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
138 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
139
140 w32con_move_cursor (f, 0, 0);
141 }
142
143
144 static struct glyph glyph_base[80];
145 static struct glyph *glyphs = glyph_base;
146 static size_t glyphs_len = ARRAYELTS (glyph_base);
147 static BOOL ceol_initialized = FALSE;
148
149 /* Clear from Cursor to end (what's "standout marker"?). */
150 static void
w32con_clear_end_of_line(struct frame * f,int end)151 w32con_clear_end_of_line (struct frame *f, int end)
152 {
153 /* Time to reallocate our "empty row"? With today's large screens,
154 it is not unthinkable to see TTY frames well in excess of
155 80-character width. */
156 if (end - cursor_coords.X > glyphs_len)
157 {
158 if (glyphs == glyph_base)
159 glyphs = NULL;
160 glyphs = xrealloc (glyphs, FRAME_COLS (f) * sizeof (struct glyph));
161 glyphs_len = FRAME_COLS (f);
162 ceol_initialized = FALSE;
163 }
164 if (!ceol_initialized)
165 {
166 int i;
167 for (i = 0; i < glyphs_len; i++)
168 {
169 memcpy (&glyphs[i], &space_glyph, sizeof (struct glyph));
170 }
171 ceol_initialized = TRUE;
172 }
173 w32con_write_glyphs (f, glyphs, end - cursor_coords.X);
174 }
175
176 /* Insert n lines at vpos. if n is negative delete -n lines. */
177 static void
w32con_ins_del_lines(struct frame * f,int vpos,int n)178 w32con_ins_del_lines (struct frame *f, int vpos, int n)
179 {
180 int i, nb;
181 SMALL_RECT scroll;
182 SMALL_RECT clip;
183 COORD dest;
184 CHAR_INFO fill;
185
186 if (n < 0)
187 {
188 scroll.Top = vpos - n;
189 scroll.Bottom = FRAME_TOTAL_LINES (f);
190 dest.Y = vpos;
191 }
192 else
193 {
194 scroll.Top = vpos;
195 scroll.Bottom = FRAME_TOTAL_LINES (f) - n;
196 dest.Y = vpos + n;
197 }
198 clip.Top = clip.Left = scroll.Left = 0;
199 clip.Right = scroll.Right = FRAME_COLS (f);
200 clip.Bottom = FRAME_TOTAL_LINES (f);
201
202 dest.X = 0;
203
204 fill.Char.AsciiChar = 0x20;
205 fill.Attributes = char_attr_normal;
206
207 ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
208
209 /* Here we have to deal with a w32 console flake: If the scroll
210 region looks like abc and we scroll c to a and fill with d we get
211 cbd... if we scroll block c one line at a time to a, we get cdd...
212 Emacs expects cdd consistently... So we have to deal with that
213 here... (this also occurs scrolling the same way in the other
214 direction. */
215
216 if (n > 0)
217 {
218 if (scroll.Bottom < dest.Y)
219 {
220 for (i = scroll.Bottom; i < dest.Y; i++)
221 {
222 w32con_move_cursor (f, i, 0);
223 w32con_clear_end_of_line (f, FRAME_COLS (f));
224 }
225 }
226 }
227 else
228 {
229 nb = dest.Y + (scroll.Bottom - scroll.Top) + 1;
230
231 if (nb < scroll.Top)
232 {
233 for (i = nb; i < scroll.Top; i++)
234 {
235 w32con_move_cursor (f, i, 0);
236 w32con_clear_end_of_line (f, FRAME_COLS (f));
237 }
238 }
239 }
240
241 cursor_coords.X = 0;
242 cursor_coords.Y = vpos;
243 }
244
245 #undef LEFT
246 #undef RIGHT
247 #define LEFT 1
248 #define RIGHT 0
249
250 static void
scroll_line(struct frame * f,int dist,int direction)251 scroll_line (struct frame *f, int dist, int direction)
252 {
253 /* The idea here is to implement a horizontal scroll in one line to
254 implement delete and half of insert. */
255 SMALL_RECT scroll, clip;
256 COORD dest;
257 CHAR_INFO fill;
258
259 clip.Top = scroll.Top = clip.Bottom = scroll.Bottom = cursor_coords.Y;
260 clip.Left = 0;
261 clip.Right = FRAME_COLS (f);
262
263 if (direction == LEFT)
264 {
265 scroll.Left = cursor_coords.X + dist;
266 scroll.Right = FRAME_COLS (f) - 1;
267 }
268 else
269 {
270 scroll.Left = cursor_coords.X;
271 scroll.Right = FRAME_COLS (f) - dist - 1;
272 }
273
274 dest.X = cursor_coords.X;
275 dest.Y = cursor_coords.Y;
276
277 fill.Char.AsciiChar = 0x20;
278 fill.Attributes = char_attr_normal;
279
280 ScrollConsoleScreenBuffer (cur_screen, &scroll, &clip, dest, &fill);
281 }
282
283
284 /* If start is zero insert blanks instead of a string at start ?. */
285 static void
w32con_insert_glyphs(struct frame * f,register struct glyph * start,register int len)286 w32con_insert_glyphs (struct frame *f, register struct glyph *start,
287 register int len)
288 {
289 scroll_line (f, len, RIGHT);
290
291 /* Move len chars to the right starting at cursor_coords, fill with blanks */
292 if (start)
293 {
294 /* Print the first len characters of start, cursor_coords.X adjusted
295 by write_glyphs. */
296
297 w32con_write_glyphs (f, start, len);
298 }
299 else
300 {
301 w32con_clear_end_of_line (f, cursor_coords.X + len);
302 }
303 }
304
305 static void
w32con_write_glyphs(struct frame * f,register struct glyph * string,register int len)306 w32con_write_glyphs (struct frame *f, register struct glyph *string,
307 register int len)
308 {
309 DWORD r;
310 WORD char_attr;
311 LPCSTR conversion_buffer;
312 struct coding_system *coding;
313
314 if (len <= 0)
315 return;
316
317 /* If terminal_coding does any conversion, use it, otherwise use
318 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
319 because it always return 1 if the member src_multibyte is 1. */
320 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
321 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
322 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
323 the tail. */
324 coding->mode &= ~CODING_MODE_LAST_BLOCK;
325
326 while (len > 0)
327 {
328 /* Identify a run of glyphs with the same face. */
329 int face_id = string->face_id;
330 int n;
331
332 for (n = 1; n < len; ++n)
333 if (string[n].face_id != face_id)
334 break;
335
336 /* Turn appearance modes of the face of the run on. */
337 char_attr = w32_face_attributes (f, face_id);
338
339 if (n == len)
340 /* This is the last run. */
341 coding->mode |= CODING_MODE_LAST_BLOCK;
342 conversion_buffer = (LPCSTR) encode_terminal_code (string, n, coding);
343 if (coding->produced > 0)
344 {
345 /* Set the attribute for these characters. */
346 if (!FillConsoleOutputAttribute (cur_screen, char_attr,
347 coding->produced, cursor_coords,
348 &r))
349 {
350 printf ("Failed writing console attributes: %lu\n",
351 GetLastError ());
352 fflush (stdout);
353 }
354
355 /* Write the characters. */
356 if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
357 coding->produced, cursor_coords,
358 &r))
359 {
360 printf ("Failed writing console characters: %lu\n",
361 GetLastError ());
362 fflush (stdout);
363 }
364
365 cursor_coords.X += coding->produced;
366 w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X);
367 }
368 len -= n;
369 string += n;
370 }
371 }
372
373 /* Used for mouse highlight. */
374 static void
w32con_write_glyphs_with_face(struct frame * f,register int x,register int y,register struct glyph * string,register int len,register int face_id)375 w32con_write_glyphs_with_face (struct frame *f, register int x, register int y,
376 register struct glyph *string, register int len,
377 register int face_id)
378 {
379 LPCSTR conversion_buffer;
380 struct coding_system *coding;
381
382 if (len <= 0)
383 return;
384
385 /* If terminal_coding does any conversion, use it, otherwise use
386 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
387 because it always return 1 if the member src_multibyte is 1. */
388 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
389 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
390 /* We are going to write the entire block of glyphs in one go, as
391 they all have the same face. So this _is_ the last block. */
392 coding->mode |= CODING_MODE_LAST_BLOCK;
393
394 conversion_buffer = (LPCSTR) encode_terminal_code (string, len, coding);
395 if (coding->produced > 0)
396 {
397 DWORD filled, written;
398 /* Compute the character attributes corresponding to the face. */
399 DWORD char_attr = w32_face_attributes (f, face_id);
400 COORD start_coords;
401
402 start_coords.X = x;
403 start_coords.Y = y;
404 /* Set the attribute for these characters. */
405 if (!FillConsoleOutputAttribute (cur_screen, char_attr,
406 coding->produced, start_coords,
407 &filled))
408 DebPrint (("Failed writing console attributes: %d\n", GetLastError ()));
409 else
410 {
411 /* Write the characters. */
412 if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer,
413 filled, start_coords, &written))
414 DebPrint (("Failed writing console characters: %d\n",
415 GetLastError ()));
416 }
417 }
418 }
419
420 /* Implementation of draw_row_with_mouse_face for W32 console. */
421 void
tty_draw_row_with_mouse_face(struct window * w,struct glyph_row * row,int start_hpos,int end_hpos,enum draw_glyphs_face draw)422 tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
423 int start_hpos, int end_hpos,
424 enum draw_glyphs_face draw)
425 {
426 int nglyphs = end_hpos - start_hpos;
427 struct frame *f = XFRAME (WINDOW_FRAME (w));
428 struct tty_display_info *tty = FRAME_TTY (f);
429 int face_id = tty->mouse_highlight.mouse_face_face_id;
430 int pos_x, pos_y;
431
432 if (end_hpos >= row->used[TEXT_AREA])
433 nglyphs = row->used[TEXT_AREA] - start_hpos;
434
435 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
436 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
437
438 if (draw == DRAW_MOUSE_FACE)
439 w32con_write_glyphs_with_face (f, pos_x, pos_y,
440 row->glyphs[TEXT_AREA] + start_hpos,
441 nglyphs, face_id);
442 else if (draw == DRAW_NORMAL_TEXT)
443 {
444 COORD save_coords = cursor_coords;
445
446 w32con_move_cursor (f, pos_y, pos_x);
447 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
448 w32con_move_cursor (f, save_coords.Y, save_coords.X);
449 }
450 }
451
452 static void
w32con_delete_glyphs(struct frame * f,int n)453 w32con_delete_glyphs (struct frame *f, int n)
454 {
455 /* delete chars means scroll chars from cursor_coords.X + n to
456 cursor_coords.X, anything beyond the edge of the screen should
457 come out empty... */
458
459 scroll_line (f, n, LEFT);
460 }
461
462
463 static void
w32con_reset_terminal_modes(struct terminal * t)464 w32con_reset_terminal_modes (struct terminal *t)
465 {
466 COORD dest;
467 CONSOLE_SCREEN_BUFFER_INFO info;
468 int n;
469 DWORD r;
470
471 /* Clear the complete screen buffer. This is required because Emacs
472 sets the cursor position to the top of the buffer, but there might
473 be other output below the bottom of the Emacs frame if the screen buffer
474 is larger than the window size. */
475 GetConsoleScreenBufferInfo (cur_screen, &info);
476 dest.X = 0;
477 dest.Y = 0;
478 n = info.dwSize.X * info.dwSize.Y;
479
480 FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r);
481 FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r);
482 /* Now that the screen is clear, put the cursor at the top. */
483 SetConsoleCursorPosition (cur_screen, dest);
484
485 #ifdef USE_SEPARATE_SCREEN
486 SetConsoleActiveScreenBuffer (prev_screen);
487 #else
488 SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
489 #endif
490
491 SetConsoleMode (keyboard_handle, prev_console_mode);
492 }
493
494 static void
w32con_set_terminal_modes(struct terminal * t)495 w32con_set_terminal_modes (struct terminal *t)
496 {
497 CONSOLE_CURSOR_INFO cci;
498
499 /* make cursor big and visible (100 on Windows 95 makes it disappear) */
500 cci.dwSize = 99;
501 cci.bVisible = TRUE;
502 (void) SetConsoleCursorInfo (cur_screen, &cci);
503
504 SetConsoleActiveScreenBuffer (cur_screen);
505
506 /* If Quick Edit is enabled for the console, it will get in the way
507 of receiving mouse events, so we disable it. But leave the
508 Insert Mode as it was set by the user. */
509 DWORD new_console_mode
510 = ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_EXTENDED_FLAGS;
511 if ((prev_console_mode & ENABLE_INSERT_MODE) != 0)
512 new_console_mode |= ENABLE_INSERT_MODE;
513 SetConsoleMode (keyboard_handle, new_console_mode);
514
515 /* Initialize input mode: interrupt_input off, no flow control, allow
516 8 bit character input, standard quit char. */
517 Fset_input_mode (Qnil, Qnil, make_fixnum (2), Qnil);
518 }
519
520 /* hmmm... perhaps these let us bracket screen changes so that we can flush
521 clumps rather than one-character-at-a-time...
522
523 we'll start with not moving the cursor while an update is in progress. */
524 static void
w32con_update_begin(struct frame * f)525 w32con_update_begin (struct frame * f)
526 {
527 }
528
529 static void
w32con_update_end(struct frame * f)530 w32con_update_end (struct frame * f)
531 {
532 SetConsoleCursorPosition (cur_screen, cursor_coords);
533 }
534
535 /***********************************************************************
536 stubs from termcap.c
537 ***********************************************************************/
538
539 void sys_tputs (char *, int, int (*) (int));
540
541 void
sys_tputs(char * str,int nlines,int (* outfun)(int))542 sys_tputs (char *str, int nlines, int (*outfun) (int))
543 {
544 }
545
546 char *sys_tgetstr (char *, char **);
547
548 char *
sys_tgetstr(char * cap,char ** area)549 sys_tgetstr (char *cap, char **area)
550 {
551 return NULL;
552 }
553
554
555 /***********************************************************************
556 stubs from cm.c
557 ***********************************************************************/
558
559 struct tty_display_info *current_tty = NULL;
560 int cost = 0;
561
562 int evalcost (int);
563
564 int
evalcost(int c)565 evalcost (int c)
566 {
567 return c;
568 }
569
570 int cmputc (int);
571
572 int
cmputc(int c)573 cmputc (int c)
574 {
575 return c;
576 }
577
578 void cmcheckmagic (struct tty_display_info *);
579
580 void
cmcheckmagic(struct tty_display_info * tty)581 cmcheckmagic (struct tty_display_info *tty)
582 {
583 }
584
585 void cmcostinit (struct tty_display_info *);
586
587 void
cmcostinit(struct tty_display_info * tty)588 cmcostinit (struct tty_display_info *tty)
589 {
590 }
591
592 void cmgoto (struct tty_display_info *, int, int);
593
594 void
cmgoto(struct tty_display_info * tty,int row,int col)595 cmgoto (struct tty_display_info *tty, int row, int col)
596 {
597 }
598
599 void Wcm_clear (struct tty_display_info *);
600
601 void
Wcm_clear(struct tty_display_info * tty)602 Wcm_clear (struct tty_display_info *tty)
603 {
604 }
605
606
607 /* Report the current cursor position. The following two functions
608 are used in term.c's tty menu code, so they are not really
609 "stubs". */
610 int
cursorX(struct tty_display_info * tty)611 cursorX (struct tty_display_info *tty)
612 {
613 return cursor_coords.X;
614 }
615
616 int
cursorY(struct tty_display_info * tty)617 cursorY (struct tty_display_info *tty)
618 {
619 return cursor_coords.Y;
620 }
621
622 /***********************************************************************
623 Faces
624 ***********************************************************************/
625
626
627 /* Turn appearances of face FACE_ID on tty frame F on. */
628
629 static WORD
w32_face_attributes(struct frame * f,int face_id)630 w32_face_attributes (struct frame *f, int face_id)
631 {
632 WORD char_attr;
633 struct face *face = FACE_FROM_ID (f, face_id);
634
635 char_attr = char_attr_normal;
636
637 /* Reverse the default color if requested. If background and
638 foreground are specified, then they have been reversed already. */
639 if (face->tty_reverse_p)
640 char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4)
641 + ((char_attr & 0x00f0) >> 4);
642
643 /* Before the terminal is properly initialized, all colors map to 0.
644 Don't try to resolve them. */
645 if (NILP (Vtty_defined_color_alist))
646 return char_attr;
647
648 /* Colors should be in the range 0...15 unless they are one of
649 FACE_TTY_DEFAULT_COLOR, FACE_TTY_DEFAULT_FG_COLOR or
650 FACE_TTY_DEFAULT_BG_COLOR. Other out of range colors are
651 invalid, so it is better to use the default color if they ever
652 get through to here. */
653 if (face->foreground >= 0 && face->foreground < 16)
654 char_attr = (char_attr & 0xfff0) + face->foreground;
655
656 if (face->background >= 0 && face->background < 16)
657 char_attr = (char_attr & 0xff0f) + (face->background << 4);
658
659 return char_attr;
660 }
661
662 void
initialize_w32_display(struct terminal * term,int * width,int * height)663 initialize_w32_display (struct terminal *term, int *width, int *height)
664 {
665 CONSOLE_SCREEN_BUFFER_INFO info;
666
667 term->rif = 0; /* No window based redisplay on the console. */
668 term->cursor_to_hook = w32con_move_cursor;
669 term->raw_cursor_to_hook = w32con_move_cursor;
670 term->clear_to_end_hook = w32con_clear_to_end;
671 term->clear_frame_hook = w32con_clear_frame;
672 term->clear_end_of_line_hook = w32con_clear_end_of_line;
673 term->ins_del_lines_hook = w32con_ins_del_lines;
674 term->insert_glyphs_hook = w32con_insert_glyphs;
675 term->write_glyphs_hook = w32con_write_glyphs;
676 term->delete_glyphs_hook = w32con_delete_glyphs;
677 term->ring_bell_hook = w32_sys_ring_bell;
678 term->reset_terminal_modes_hook = w32con_reset_terminal_modes;
679 term->set_terminal_modes_hook = w32con_set_terminal_modes;
680 term->set_terminal_window_hook = NULL;
681 term->update_begin_hook = w32con_update_begin;
682 term->update_end_hook = w32con_update_end;
683
684 term->defined_color_hook = &tty_defined_color; /* xfaces.c */
685 term->read_socket_hook = w32_console_read_socket;
686 term->mouse_position_hook = w32_console_mouse_position;
687 term->menu_show_hook = tty_menu_show;
688
689 /* The following are not used on the console. */
690 term->frame_rehighlight_hook = 0;
691 term->frame_raise_lower_hook = 0;
692 term->set_vertical_scroll_bar_hook = 0;
693 term->set_horizontal_scroll_bar_hook = 0;
694 term->condemn_scroll_bars_hook = 0;
695 term->redeem_scroll_bar_hook = 0;
696 term->judge_scroll_bars_hook = 0;
697 term->frame_up_to_date_hook = 0;
698
699 /* Initialize the mouse-highlight data. */
700 reset_mouse_highlight (&term->display_info.tty->mouse_highlight);
701
702 /* Initialize interrupt_handle. */
703 init_crit ();
704
705 /* Remember original console settings. */
706 keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
707 GetConsoleMode (keyboard_handle, &prev_console_mode);
708
709 prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
710
711 #ifdef USE_SEPARATE_SCREEN
712 cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
713 0, NULL,
714 CONSOLE_TEXTMODE_BUFFER,
715 NULL);
716
717 if (cur_screen == INVALID_HANDLE_VALUE)
718 {
719 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
720 printf ("LastError = 0x%lx\n", GetLastError ());
721 fflush (stdout);
722 exit (0);
723 }
724 #else
725 cur_screen = prev_screen;
726 GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
727 #endif
728
729 /* Respect setting of LINES and COLUMNS environment variables. */
730 {
731 char * lines = getenv ("LINES");
732 char * columns = getenv ("COLUMNS");
733
734 if (lines != NULL && columns != NULL)
735 {
736 SMALL_RECT new_win_dims;
737 COORD new_size;
738
739 new_size.X = atoi (columns);
740 new_size.Y = atoi (lines);
741
742 GetConsoleScreenBufferInfo (cur_screen, &info);
743
744 /* Shrink the window first, so the buffer dimensions can be
745 reduced if necessary. */
746 new_win_dims.Top = 0;
747 new_win_dims.Left = 0;
748 new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1;
749 new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1;
750 SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
751
752 SetConsoleScreenBufferSize (cur_screen, new_size);
753
754 /* Set the window size to match the buffer dimension. */
755 new_win_dims.Top = 0;
756 new_win_dims.Left = 0;
757 new_win_dims.Bottom = new_size.Y - 1;
758 new_win_dims.Right = new_size.X - 1;
759 SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims);
760 }
761 }
762
763 GetConsoleScreenBufferInfo (cur_screen, &info);
764
765 char_attr_normal = info.wAttributes;
766
767 /* Determine if the info returned by GetConsoleScreenBufferInfo
768 is realistic. Old MS Telnet servers used to only fill out
769 the dwSize portion, even modern one fill the whole struct with
770 garbage when using non-MS telnet clients. */
771 if ((w32_use_full_screen_buffer
772 && (info.dwSize.Y < 20 || info.dwSize.Y > 100
773 || info.dwSize.X < 40 || info.dwSize.X > 200))
774 || (!w32_use_full_screen_buffer
775 && (info.srWindow.Bottom - info.srWindow.Top < 20
776 || info.srWindow.Bottom - info.srWindow.Top > 100
777 || info.srWindow.Right - info.srWindow.Left < 40
778 || info.srWindow.Right - info.srWindow.Left > 100)))
779 {
780 *height = 25;
781 *width = 80;
782 }
783
784 else if (w32_use_full_screen_buffer)
785 {
786 *height = info.dwSize.Y; /* lines per page */
787 *width = info.dwSize.X; /* characters per line */
788 }
789 else
790 {
791 /* Lines per page. Use buffer coords instead of buffer size. */
792 *height = 1 + info.srWindow.Bottom - info.srWindow.Top;
793 /* Characters per line. Use buffer coords instead of buffer size. */
794 *width = 1 + info.srWindow.Right - info.srWindow.Left;
795 }
796
797 /* Force reinitialization of the "empty row" buffer, in case they
798 dumped from a running session. */
799 if (glyphs != glyph_base)
800 {
801 glyphs = NULL;
802 glyphs_len = 0;
803 ceol_initialized = FALSE;
804 }
805
806 if (os_subtype == OS_NT)
807 w32_console_unicode_input = 1;
808 else
809 w32_console_unicode_input = 0;
810
811 /* Setup w32_display_info structure for this frame. */
812 w32_initialize_display_info (build_string ("Console"));
813
814 /* Set up the keyboard hook. */
815 setup_w32_kbdhook ();
816 }
817
818
819 DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
820 doc: /* Set screen foreground and background colors.
821
822 Arguments should be indices between 0 and 15, see w32console.el. */)
823 (Lisp_Object foreground, Lisp_Object background)
824 {
825 char_attr_normal = XFIXNAT (foreground) + (XFIXNAT (background) << 4);
826
827 Frecenter (Qnil, Qt);
828 return Qt;
829 }
830
831 DEFUN ("get-screen-color", Fget_screen_color, Sget_screen_color, 0, 0, 0,
832 doc: /* Get color indices of the current screen foreground and background.
833
834 The colors are returned as a list of 2 indices (FOREGROUND BACKGROUND).
835 See w32console.el and `tty-defined-color-alist' for mapping of indices
836 to colors. */)
837 (void)
838 {
839 return Fcons (make_fixnum (char_attr_normal & 0x000f),
840 Fcons (make_fixnum ((char_attr_normal >> 4) & 0x000f), Qnil));
841 }
842
843 DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
844 doc: /* Set cursor size. */)
845 (Lisp_Object size)
846 {
847 CONSOLE_CURSOR_INFO cci;
848 cci.dwSize = XFIXNAT (size);
849 cci.bVisible = TRUE;
850 (void) SetConsoleCursorInfo (cur_screen, &cci);
851
852 return Qt;
853 }
854
855 void
syms_of_ntterm(void)856 syms_of_ntterm (void)
857 {
858 DEFVAR_BOOL ("w32-use-full-screen-buffer",
859 w32_use_full_screen_buffer,
860 doc: /* Non-nil means make terminal frames use the full screen buffer dimensions.
861 This is desirable when running Emacs over telnet.
862 A value of nil means use the current console window dimensions; this
863 may be preferable when working directly at the console with a large
864 scroll-back buffer. */);
865 w32_use_full_screen_buffer = 0;
866
867 defsubr (&Sset_screen_color);
868 defsubr (&Sget_screen_color);
869 defsubr (&Sset_cursor_size);
870 }
871