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