Commit | Line | Data |
---|---|---|
e6b20d65 | 1 | /* Terminal hooks for GNU Emacs on the Microsoft W32 API. |
8c2ac482 | 2 | Copyright (C) 1992, 1999 Free Software Foundation, Inc. |
6cdfb6e6 | 3 | |
3b7ad313 EN |
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 2, or (at your option) | |
9 | 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; 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. | |
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 | 30 | #include <windows.h> |
338b1bb2 | 31 | #include <string.h> |
6cdfb6e6 RS |
32 | |
33 | #include "lisp.h" | |
2091aeb2 | 34 | #include "charset.h" |
8c2ac482 | 35 | #include "coding.h" |
6cdfb6e6 RS |
36 | #include "disptab.h" |
37 | #include "termhooks.h" | |
b93b26cb JR |
38 | #include "dispextern.h" |
39 | /* Disable features in frame.h that require a Window System. */ | |
65fb143c JR |
40 | #undef HAVE_WINDOW_SYSTEM |
41 | #include "frame.h" | |
489f9371 | 42 | #include "w32inevt.h" |
6cdfb6e6 | 43 | |
0534d577 | 44 | /* from window.c */ |
6cdfb6e6 RS |
45 | extern Lisp_Object Frecenter (); |
46 | ||
47 | /* from keyboard.c */ | |
48 | extern int detect_input_pending (); | |
49 | ||
50 | /* from sysdep.c */ | |
51 | extern int read_input_pending (); | |
52 | ||
8c2ac482 | 53 | extern struct frame * updating_frame; |
6cdfb6e6 RS |
54 | extern int meta_key; |
55 | ||
7cb010ed JR |
56 | static void w32con_move_cursor (int row, int col); |
57 | static void w32con_clear_to_end (void); | |
58 | static void w32con_clear_frame (void); | |
59 | static void w32con_clear_end_of_line (int); | |
60 | static void w32con_ins_del_lines (int vpos, int n); | |
61 | static void w32con_insert_glyphs (struct glyph *start, int len); | |
62 | static void w32con_write_glyphs (struct glyph *string, int len); | |
63 | static void w32con_delete_glyphs (int n); | |
fbd6baed | 64 | void w32_sys_ring_bell (void); |
7cb010ed JR |
65 | static void w32con_reset_terminal_modes (void); |
66 | static void w32con_set_terminal_modes (void); | |
67 | static void w32con_set_terminal_window (int size); | |
68 | static void w32con_update_begin (struct frame * f); | |
69 | static void w32con_update_end (struct frame * f); | |
338b1bb2 | 70 | static WORD w32_face_attributes (struct frame *f, int face_id); |
6cdfb6e6 | 71 | |
338b1bb2 JR |
72 | static COORD cursor_coords; |
73 | static HANDLE prev_screen, cur_screen; | |
74 | static WORD char_attr_normal; | |
75 | static DWORD prev_console_mode; | |
6cdfb6e6 | 76 | |
3e671d90 | 77 | #ifndef USE_SEPARATE_SCREEN |
338b1bb2 | 78 | static CONSOLE_CURSOR_INFO prev_console_cursor; |
3e671d90 GV |
79 | #endif |
80 | ||
191100f2 AI |
81 | /* Determine whether to make frame dimensions match the screen buffer, |
82 | or the current window size. The former is desirable when running | |
83 | over telnet, while the latter is more useful when working directly at | |
84 | the console with a large scroll-back buffer. */ | |
85 | int w32_use_full_screen_buffer; | |
338b1bb2 | 86 | HANDLE keyboard_handle; |
191100f2 | 87 | |
6cdfb6e6 RS |
88 | |
89 | /* Setting this as the ctrl handler prevents emacs from being killed when | |
40d578c9 RS |
90 | someone hits ^C in a 'suspended' session (child shell). |
91 | Also ignore Ctrl-Break signals. */ | |
92 | ||
6cdfb6e6 RS |
93 | BOOL |
94 | ctrl_c_handler (unsigned long type) | |
95 | { | |
3e671d90 GV |
96 | /* Only ignore "interrupt" events when running interactively. */ |
97 | return (!noninteractive | |
98 | && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)); | |
6cdfb6e6 RS |
99 | } |
100 | ||
101 | /* If we're updating a frame, use it as the current frame | |
102 | Otherwise, use the selected frame. */ | |
8c2ac482 | 103 | #define PICK_FRAME() (updating_frame ? updating_frame : SELECTED_FRAME ()) |
6cdfb6e6 RS |
104 | |
105 | /* Move the cursor to (row, col). */ | |
4fdbdbbd | 106 | static void |
7cb010ed | 107 | w32con_move_cursor (int row, int col) |
6cdfb6e6 RS |
108 | { |
109 | cursor_coords.X = col; | |
110 | cursor_coords.Y = row; | |
177c0ea7 | 111 | |
8c2ac482 | 112 | if (updating_frame == (struct frame *) NULL) |
6cdfb6e6 RS |
113 | { |
114 | SetConsoleCursorPosition (cur_screen, cursor_coords); | |
115 | } | |
116 | } | |
117 | ||
118 | /* Clear from cursor to end of screen. */ | |
4fdbdbbd | 119 | static void |
7cb010ed | 120 | w32con_clear_to_end (void) |
6cdfb6e6 | 121 | { |
8c2ac482 | 122 | struct frame * f = PICK_FRAME (); |
177c0ea7 | 123 | |
7cb010ed JR |
124 | w32con_clear_end_of_line (FRAME_COLS (f) - 1); |
125 | w32con_ins_del_lines (cursor_coords.Y, FRAME_LINES (f) - cursor_coords.Y - 1); | |
6cdfb6e6 RS |
126 | } |
127 | ||
128 | /* Clear the frame. */ | |
7cb010ed JR |
129 | static void |
130 | w32con_clear_frame (void) | |
6cdfb6e6 | 131 | { |
8c2ac482 | 132 | struct frame * f = PICK_FRAME (); |
b47278e1 | 133 | COORD dest; |
84f5bd81 AI |
134 | int n; |
135 | DWORD r; | |
a5404e3a AI |
136 | CONSOLE_SCREEN_BUFFER_INFO info; |
137 | ||
138 | GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info); | |
b47278e1 | 139 | |
a5404e3a | 140 | /* Remember that the screen buffer might be wider than the window. */ |
90022f5a | 141 | n = FRAME_LINES (f) * info.dwSize.X; |
b47278e1 GV |
142 | dest.X = dest.Y = 0; |
143 | ||
338b1bb2 | 144 | FillConsoleOutputAttribute (cur_screen, char_attr_normal, n, dest, &r); |
b47278e1 GV |
145 | FillConsoleOutputCharacter (cur_screen, ' ', n, dest, &r); |
146 | ||
7cb010ed | 147 | w32con_move_cursor (0, 0); |
6cdfb6e6 RS |
148 | } |
149 | ||
150 | ||
8c2ac482 | 151 | static struct glyph glyph_base[256]; |
6cdfb6e6 RS |
152 | static BOOL ceol_initialized = FALSE; |
153 | ||
154 | /* Clear from Cursor to end (what's "standout marker"?). */ | |
7cb010ed JR |
155 | static void |
156 | w32con_clear_end_of_line (int end) | |
6cdfb6e6 RS |
157 | { |
158 | if (!ceol_initialized) | |
159 | { | |
160 | int i; | |
161 | for (i = 0; i < 256; i++) | |
162 | { | |
8c2ac482 | 163 | memcpy (&glyph_base[i], &space_glyph, sizeof (struct glyph)); |
6cdfb6e6 RS |
164 | } |
165 | ceol_initialized = TRUE; | |
166 | } | |
7cb010ed | 167 | w32con_write_glyphs (glyph_base, end - cursor_coords.X); /* fencepost ? */ |
6cdfb6e6 RS |
168 | } |
169 | ||
170 | /* Insert n lines at vpos. if n is negative delete -n lines. */ | |
7cb010ed JR |
171 | static void |
172 | w32con_ins_del_lines (int vpos, int n) | |
6cdfb6e6 | 173 | { |
e850a615 | 174 | int i, nb; |
6cdfb6e6 RS |
175 | SMALL_RECT scroll; |
176 | COORD dest; | |
177 | CHAR_INFO fill; | |
8c2ac482 | 178 | struct frame * f = PICK_FRAME (); |
6cdfb6e6 RS |
179 | |
180 | if (n < 0) | |
181 | { | |
182 | scroll.Top = vpos - n; | |
90022f5a | 183 | scroll.Bottom = FRAME_LINES (f); |
6cdfb6e6 RS |
184 | dest.Y = vpos; |
185 | } | |
186 | else | |
187 | { | |
188 | scroll.Top = vpos; | |
90022f5a | 189 | scroll.Bottom = FRAME_LINES (f) - n; |
6cdfb6e6 RS |
190 | dest.Y = vpos + n; |
191 | } | |
192 | scroll.Left = 0; | |
90022f5a | 193 | scroll.Right = FRAME_COLS (f); |
177c0ea7 | 194 | |
6cdfb6e6 | 195 | dest.X = 0; |
177c0ea7 | 196 | |
6cdfb6e6 | 197 | fill.Char.AsciiChar = 0x20; |
338b1bb2 | 198 | fill.Attributes = char_attr_normal; |
177c0ea7 | 199 | |
6cdfb6e6 RS |
200 | ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill); |
201 | ||
fbd6baed | 202 | /* Here we have to deal with a w32 console flake: If the scroll |
6cdfb6e6 RS |
203 | region looks like abc and we scroll c to a and fill with d we get |
204 | cbd... if we scroll block c one line at a time to a, we get cdd... | |
205 | Emacs expects cdd consistently... So we have to deal with that | |
206 | here... (this also occurs scrolling the same way in the other | |
207 | direction. */ | |
208 | ||
209 | if (n > 0) | |
210 | { | |
211 | if (scroll.Bottom < dest.Y) | |
212 | { | |
213 | for (i = scroll.Bottom; i < dest.Y; i++) | |
214 | { | |
7cb010ed JR |
215 | w32con_move_cursor (i, 0); |
216 | w32con_clear_end_of_line (FRAME_COLS (f)); | |
6cdfb6e6 RS |
217 | } |
218 | } | |
219 | } | |
220 | else | |
221 | { | |
222 | nb = dest.Y + (scroll.Bottom - scroll.Top) + 1; | |
223 | ||
224 | if (nb < scroll.Top) | |
177c0ea7 | 225 | { |
6cdfb6e6 RS |
226 | for (i = nb; i < scroll.Top; i++) |
227 | { | |
7cb010ed JR |
228 | w32con_move_cursor (i, 0); |
229 | w32con_clear_end_of_line (FRAME_COLS (f)); | |
6cdfb6e6 RS |
230 | } |
231 | } | |
232 | } | |
177c0ea7 | 233 | |
6cdfb6e6 RS |
234 | cursor_coords.X = 0; |
235 | cursor_coords.Y = vpos; | |
6cdfb6e6 RS |
236 | } |
237 | ||
238 | #undef LEFT | |
239 | #undef RIGHT | |
240 | #define LEFT 1 | |
241 | #define RIGHT 0 | |
242 | ||
4fdbdbbd | 243 | static void |
6cdfb6e6 RS |
244 | scroll_line (int dist, int direction) |
245 | { | |
246 | /* The idea here is to implement a horizontal scroll in one line to | |
247 | implement delete and half of insert. */ | |
248 | SMALL_RECT scroll; | |
249 | COORD dest; | |
250 | CHAR_INFO fill; | |
8c2ac482 | 251 | struct frame * f = PICK_FRAME (); |
177c0ea7 | 252 | |
6cdfb6e6 RS |
253 | scroll.Top = cursor_coords.Y; |
254 | scroll.Bottom = cursor_coords.Y; | |
177c0ea7 | 255 | |
6cdfb6e6 RS |
256 | if (direction == LEFT) |
257 | { | |
258 | scroll.Left = cursor_coords.X + dist; | |
90022f5a | 259 | scroll.Right = FRAME_COLS (f) - 1; |
6cdfb6e6 RS |
260 | } |
261 | else | |
262 | { | |
263 | scroll.Left = cursor_coords.X; | |
90022f5a | 264 | scroll.Right = FRAME_COLS (f) - dist - 1; |
6cdfb6e6 | 265 | } |
177c0ea7 | 266 | |
6cdfb6e6 RS |
267 | dest.X = cursor_coords.X; |
268 | dest.Y = cursor_coords.Y; | |
177c0ea7 | 269 | |
6cdfb6e6 | 270 | fill.Char.AsciiChar = 0x20; |
338b1bb2 JR |
271 | fill.Attributes = char_attr_normal; |
272 | ||
6cdfb6e6 RS |
273 | ScrollConsoleScreenBuffer (cur_screen, &scroll, NULL, dest, &fill); |
274 | } | |
275 | ||
276 | ||
277 | /* If start is zero insert blanks instead of a string at start ?. */ | |
7cb010ed JR |
278 | static void |
279 | w32con_insert_glyphs (register struct glyph *start, register int len) | |
6cdfb6e6 RS |
280 | { |
281 | scroll_line (len, RIGHT); | |
282 | ||
283 | /* Move len chars to the right starting at cursor_coords, fill with blanks */ | |
284 | if (start) | |
285 | { | |
286 | /* Print the first len characters of start, cursor_coords.X adjusted | |
287 | by write_glyphs. */ | |
177c0ea7 | 288 | |
7cb010ed | 289 | w32con_write_glyphs (start, len); |
6cdfb6e6 RS |
290 | } |
291 | else | |
292 | { | |
7cb010ed | 293 | w32con_clear_end_of_line (cursor_coords.X + len); |
6cdfb6e6 RS |
294 | } |
295 | } | |
296 | ||
853895f6 | 297 | extern unsigned char *encode_terminal_code P_ ((struct glyph *, int, |
29e1d29d | 298 | struct coding_system *)); |
853895f6 | 299 | |
7cb010ed JR |
300 | static void |
301 | w32con_write_glyphs (register struct glyph *string, register int len) | |
6cdfb6e6 | 302 | { |
84f5bd81 AI |
303 | int produced, consumed; |
304 | DWORD r; | |
8c2ac482 | 305 | struct frame * f = PICK_FRAME (); |
338b1bb2 | 306 | WORD char_attr; |
853895f6 KH |
307 | unsigned char *conversion_buffer; |
308 | struct coding_system *coding; | |
338b1bb2 JR |
309 | |
310 | if (len <= 0) | |
311 | return; | |
b47278e1 | 312 | |
853895f6 KH |
313 | /* If terminal_coding does any conversion, use it, otherwise use |
314 | safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here | |
315 | because it always return 1 if the member src_multibyte is 1. */ | |
316 | coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK | |
317 | ? &terminal_coding : &safe_terminal_coding); | |
8c2ac482 JR |
318 | /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at |
319 | the tail. */ | |
320 | terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK; | |
6cdfb6e6 | 321 | |
8c2ac482 | 322 | while (len > 0) |
6cdfb6e6 | 323 | { |
8c2ac482 JR |
324 | /* Identify a run of glyphs with the same face. */ |
325 | int face_id = string->face_id; | |
326 | int n; | |
177c0ea7 | 327 | |
8c2ac482 JR |
328 | for (n = 1; n < len; ++n) |
329 | if (string[n].face_id != face_id) | |
330 | break; | |
331 | ||
332 | /* Turn appearance modes of the face of the run on. */ | |
338b1bb2 | 333 | char_attr = w32_face_attributes (f, face_id); |
8c2ac482 | 334 | |
853895f6 KH |
335 | if (n == len) |
336 | /* This is the last run. */ | |
337 | coding->mode |= CODING_MODE_LAST_BLOCK; | |
338 | conversion_buffer = encode_terminal_code (string, n, coding); | |
339 | if (coding->produced > 0) | |
340 | { | |
341 | /* Set the attribute for these characters. */ | |
342 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, | |
343 | coding->produced, cursor_coords, | |
344 | &r)) | |
8c2ac482 | 345 | { |
853895f6 KH |
346 | printf ("Failed writing console attributes: %d\n", |
347 | GetLastError ()); | |
348 | fflush (stdout); | |
349 | } | |
350 | ||
351 | /* Write the characters. */ | |
352 | if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer, | |
353 | coding->produced, cursor_coords, | |
354 | &r)) | |
355 | { | |
356 | printf ("Failed writing console characters: %d\n", | |
357 | GetLastError ()); | |
358 | fflush (stdout); | |
359 | } | |
360 | ||
361 | cursor_coords.X += coding->produced; | |
362 | w32con_move_cursor (cursor_coords.Y, cursor_coords.X); | |
363 | } | |
364 | len -= n; | |
365 | string += n; | |
6cdfb6e6 | 366 | } |
6cdfb6e6 RS |
367 | } |
368 | ||
8c2ac482 | 369 | |
7cb010ed JR |
370 | static void |
371 | w32con_delete_glyphs (int n) | |
6cdfb6e6 | 372 | { |
177c0ea7 JB |
373 | /* delete chars means scroll chars from cursor_coords.X + n to |
374 | cursor_coords.X, anything beyond the edge of the screen should | |
6cdfb6e6 RS |
375 | come out empty... */ |
376 | ||
377 | scroll_line (n, LEFT); | |
378 | } | |
379 | ||
0534d577 | 380 | static unsigned int sound_type = 0xFFFFFFFF; |
78859b80 | 381 | #define MB_EMACS_SILENT (0xFFFFFFFF - 1) |
0534d577 | 382 | |
6cdfb6e6 | 383 | void |
fbd6baed | 384 | w32_sys_ring_bell (void) |
6cdfb6e6 | 385 | { |
177c0ea7 | 386 | if (sound_type == 0xFFFFFFFF) |
78859b80 | 387 | { |
0534d577 | 388 | Beep (666, 100); |
78859b80 GV |
389 | } |
390 | else if (sound_type == MB_EMACS_SILENT) | |
391 | { | |
392 | /* Do nothing. */ | |
393 | } | |
0534d577 | 394 | else |
78859b80 | 395 | MessageBeep (sound_type); |
6cdfb6e6 RS |
396 | } |
397 | ||
0534d577 | 398 | DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0, |
33f09670 JR |
399 | doc: /* Set the sound generated when the bell is rung. |
400 | SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent | |
401 | to use the corresponding system sound for the bell. The 'silent sound | |
402 | prevents Emacs from making any sound at all. | |
403 | SOUND is nil to use the normal beep. */) | |
0534d577 KH |
404 | (sound) |
405 | Lisp_Object sound; | |
6cdfb6e6 | 406 | { |
b7826503 | 407 | CHECK_SYMBOL (sound); |
0534d577 | 408 | |
177c0ea7 | 409 | if (NILP (sound)) |
0534d577 KH |
410 | sound_type = 0xFFFFFFFF; |
411 | else if (EQ (sound, intern ("asterisk"))) | |
412 | sound_type = MB_ICONASTERISK; | |
177c0ea7 | 413 | else if (EQ (sound, intern ("exclamation"))) |
0534d577 | 414 | sound_type = MB_ICONEXCLAMATION; |
177c0ea7 | 415 | else if (EQ (sound, intern ("hand"))) |
0534d577 | 416 | sound_type = MB_ICONHAND; |
177c0ea7 | 417 | else if (EQ (sound, intern ("question"))) |
0534d577 | 418 | sound_type = MB_ICONQUESTION; |
177c0ea7 | 419 | else if (EQ (sound, intern ("ok"))) |
0534d577 | 420 | sound_type = MB_OK; |
78859b80 GV |
421 | else if (EQ (sound, intern ("silent"))) |
422 | sound_type = MB_EMACS_SILENT; | |
0534d577 KH |
423 | else |
424 | sound_type = 0xFFFFFFFF; | |
425 | ||
426 | return sound; | |
6cdfb6e6 | 427 | } |
177c0ea7 | 428 | |
7cb010ed JR |
429 | static void |
430 | w32con_reset_terminal_modes (void) | |
6cdfb6e6 | 431 | { |
3e671d90 | 432 | #ifdef USE_SEPARATE_SCREEN |
6cdfb6e6 | 433 | SetConsoleActiveScreenBuffer (prev_screen); |
3e671d90 GV |
434 | #else |
435 | SetConsoleCursorInfo (prev_screen, &prev_console_cursor); | |
436 | #endif | |
437 | SetConsoleMode (keyboard_handle, prev_console_mode); | |
6cdfb6e6 RS |
438 | } |
439 | ||
7cb010ed JR |
440 | static void |
441 | w32con_set_terminal_modes (void) | |
6cdfb6e6 RS |
442 | { |
443 | CONSOLE_CURSOR_INFO cci; | |
444 | ||
3e671d90 GV |
445 | /* make cursor big and visible (100 on Win95 makes it disappear) */ |
446 | cci.dwSize = 99; | |
447 | cci.bVisible = TRUE; | |
448 | (void) SetConsoleCursorInfo (cur_screen, &cci); | |
6cdfb6e6 | 449 | |
3e671d90 | 450 | SetConsoleActiveScreenBuffer (cur_screen); |
6cdfb6e6 | 451 | |
3e671d90 | 452 | SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT); |
6cdfb6e6 | 453 | |
3e671d90 GV |
454 | /* Initialize input mode: interrupt_input off, no flow control, allow |
455 | 8 bit character input, standard quit char. */ | |
456 | Fset_input_mode (Qnil, Qnil, make_number (2), Qnil); | |
6cdfb6e6 RS |
457 | } |
458 | ||
459 | /* hmmm... perhaps these let us bracket screen changes so that we can flush | |
460 | clumps rather than one-character-at-a-time... | |
177c0ea7 | 461 | |
6cdfb6e6 | 462 | we'll start with not moving the cursor while an update is in progress. */ |
7cb010ed JR |
463 | static void |
464 | w32con_update_begin (struct frame * f) | |
6cdfb6e6 RS |
465 | { |
466 | } | |
467 | ||
7cb010ed JR |
468 | static void |
469 | w32con_update_end (struct frame * f) | |
6cdfb6e6 RS |
470 | { |
471 | SetConsoleCursorPosition (cur_screen, cursor_coords); | |
472 | } | |
473 | ||
7cb010ed JR |
474 | static void |
475 | w32con_set_terminal_window (int size) | |
6cdfb6e6 RS |
476 | { |
477 | } | |
478 | ||
8c2ac482 JR |
479 | /*********************************************************************** |
480 | Faces | |
481 | ***********************************************************************/ | |
482 | ||
483 | ||
484 | /* Turn appearances of face FACE_ID on tty frame F on. */ | |
485 | ||
338b1bb2 JR |
486 | static WORD |
487 | w32_face_attributes (f, face_id) | |
8c2ac482 JR |
488 | struct frame *f; |
489 | int face_id; | |
490 | { | |
338b1bb2 | 491 | WORD char_attr; |
8c2ac482 JR |
492 | struct face *face = FACE_FROM_ID (f, face_id); |
493 | ||
494 | xassert (face != NULL); | |
495 | ||
496 | char_attr = char_attr_normal; | |
497 | ||
338b1bb2 JR |
498 | if (face->foreground != FACE_TTY_DEFAULT_FG_COLOR |
499 | && face->foreground != FACE_TTY_DEFAULT_COLOR) | |
500 | char_attr = (char_attr & 0xfff0) + (face->foreground % 16); | |
501 | ||
502 | if (face->background != FACE_TTY_DEFAULT_BG_COLOR | |
503 | && face->background != FACE_TTY_DEFAULT_COLOR) | |
177c0ea7 | 504 | char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4); |
338b1bb2 | 505 | |
8c2ac482 | 506 | |
b93b26cb JR |
507 | /* NTEMACS_TODO: Faces defined during startup get both foreground |
508 | and background of 0. Need a better way around this - for now detect | |
509 | the problem and invert one of the faces to make the text readable. */ | |
338b1bb2 JR |
510 | if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f)) |
511 | char_attr ^= 0x0007; | |
8c2ac482 | 512 | |
e850a615 | 513 | if (face->tty_reverse_p) |
338b1bb2 JR |
514 | char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4) |
515 | + ((char_attr & 0x00f0) >> 4); | |
8c2ac482 | 516 | |
338b1bb2 | 517 | return char_attr; |
8c2ac482 JR |
518 | } |
519 | ||
520 | ||
338b1bb2 | 521 | /* Emulation of some X window features from xfns.c and xfaces.c. */ |
8c2ac482 | 522 | |
338b1bb2 JR |
523 | extern char unspecified_fg[], unspecified_bg[]; |
524 | ||
525 | ||
526 | /* Given a color index, return its standard name. */ | |
527 | Lisp_Object | |
528 | vga_stdcolor_name (int idx) | |
8c2ac482 | 529 | { |
338b1bb2 JR |
530 | /* Standard VGA colors, in the order of their standard numbering |
531 | in the default VGA palette. */ | |
532 | static char *vga_colors[16] = { | |
533 | "black", "blue", "green", "cyan", "red", "magenta", "brown", | |
534 | "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan", | |
535 | "lightred", "lightmagenta", "yellow", "white" | |
536 | }; | |
537 | ||
538 | extern Lisp_Object Qunspecified; | |
539 | ||
540 | if (idx >= 0 && idx < sizeof (vga_colors) / sizeof (vga_colors[0])) | |
541 | return build_string (vga_colors[idx]); | |
542 | else | |
543 | return Qunspecified; /* meaning the default */ | |
8c2ac482 | 544 | } |
338b1bb2 | 545 | |
6cdfb6e6 RS |
546 | typedef int (*term_hook) (); |
547 | ||
548 | void | |
e6b20d65 | 549 | initialize_w32_display (void) |
6cdfb6e6 RS |
550 | { |
551 | CONSOLE_SCREEN_BUFFER_INFO info; | |
177c0ea7 | 552 | |
7cb010ed JR |
553 | cursor_to_hook = w32con_move_cursor; |
554 | raw_cursor_to_hook = w32con_move_cursor; | |
555 | clear_to_end_hook = w32con_clear_to_end; | |
556 | clear_frame_hook = w32con_clear_frame; | |
557 | clear_end_of_line_hook = w32con_clear_end_of_line; | |
558 | ins_del_lines_hook = w32con_ins_del_lines; | |
559 | insert_glyphs_hook = w32con_insert_glyphs; | |
560 | write_glyphs_hook = w32con_write_glyphs; | |
561 | delete_glyphs_hook = w32con_delete_glyphs; | |
f3d268f9 | 562 | ring_bell_hook = w32_sys_ring_bell; |
7cb010ed JR |
563 | reset_terminal_modes_hook = w32con_reset_terminal_modes; |
564 | set_terminal_modes_hook = w32con_set_terminal_modes; | |
565 | set_terminal_window_hook = w32con_set_terminal_window; | |
566 | update_begin_hook = w32con_update_begin; | |
567 | update_end_hook = w32con_update_end; | |
177c0ea7 | 568 | |
fbd6baed | 569 | read_socket_hook = w32_console_read_socket; |
f3d268f9 | 570 | mouse_position_hook = w32_console_mouse_position; |
3e671d90 | 571 | |
c1e06681 AI |
572 | /* Initialize interrupt_handle. */ |
573 | init_crit (); | |
574 | ||
3e671d90 GV |
575 | /* Remember original console settings. */ |
576 | keyboard_handle = GetStdHandle (STD_INPUT_HANDLE); | |
577 | GetConsoleMode (keyboard_handle, &prev_console_mode); | |
578 | ||
6cdfb6e6 | 579 | prev_screen = GetStdHandle (STD_OUTPUT_HANDLE); |
177c0ea7 | 580 | |
3e671d90 GV |
581 | #ifdef USE_SEPARATE_SCREEN |
582 | cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE, | |
583 | 0, NULL, | |
584 | CONSOLE_TEXTMODE_BUFFER, | |
585 | NULL); | |
586 | ||
587 | if (cur_screen == INVALID_HANDLE_VALUE) | |
588 | { | |
589 | printf ("CreateConsoleScreenBuffer failed in ResetTerm\n"); | |
590 | printf ("LastError = 0x%lx\n", GetLastError ()); | |
591 | fflush (stdout); | |
592 | exit (0); | |
593 | } | |
594 | #else | |
595 | cur_screen = prev_screen; | |
596 | GetConsoleCursorInfo (prev_screen, &prev_console_cursor); | |
597 | #endif | |
598 | ||
191100f2 AI |
599 | /* Respect setting of LINES and COLUMNS environment variables. */ |
600 | { | |
601 | char * lines = getenv("LINES"); | |
602 | char * columns = getenv("COLUMNS"); | |
603 | ||
604 | if (lines != NULL && columns != NULL) | |
605 | { | |
606 | SMALL_RECT new_win_dims; | |
607 | COORD new_size; | |
608 | ||
609 | new_size.X = atoi (columns); | |
610 | new_size.Y = atoi (lines); | |
611 | ||
612 | GetConsoleScreenBufferInfo (cur_screen, &info); | |
613 | ||
614 | /* Shrink the window first, so the buffer dimensions can be | |
615 | reduced if necessary. */ | |
616 | new_win_dims.Top = 0; | |
617 | new_win_dims.Left = 0; | |
618 | new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1; | |
619 | new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1; | |
620 | SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims); | |
621 | ||
622 | SetConsoleScreenBufferSize (cur_screen, new_size); | |
623 | ||
624 | /* Set the window size to match the buffer dimension. */ | |
625 | new_win_dims.Top = 0; | |
626 | new_win_dims.Left = 0; | |
627 | new_win_dims.Bottom = new_size.Y - 1; | |
628 | new_win_dims.Right = new_size.X - 1; | |
629 | SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims); | |
630 | } | |
631 | } | |
632 | ||
6cdfb6e6 | 633 | GetConsoleScreenBufferInfo (cur_screen, &info); |
177c0ea7 | 634 | |
6cdfb6e6 | 635 | meta_key = 1; |
338b1bb2 | 636 | char_attr_normal = info.wAttributes; |
938469f2 | 637 | |
191100f2 AI |
638 | if (w32_use_full_screen_buffer) |
639 | { | |
90022f5a KS |
640 | FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y; /* lines per page */ |
641 | SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X); /* characters per line */ | |
191100f2 AI |
642 | } |
643 | else | |
644 | { | |
645 | /* Lines per page. Use buffer coords instead of buffer size. */ | |
90022f5a | 646 | FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom - |
177c0ea7 | 647 | info.srWindow.Top; |
191100f2 | 648 | /* Characters per line. Use buffer coords instead of buffer size. */ |
90022f5a | 649 | SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right - |
191100f2 AI |
650 | info.srWindow.Left); |
651 | } | |
65fb143c JR |
652 | |
653 | /* Setup w32_display_info structure for this frame. */ | |
654 | ||
655 | w32_initialize_display_info (build_string ("Console")); | |
656 | ||
6cdfb6e6 RS |
657 | } |
658 | ||
659 | DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0, | |
33f09670 | 660 | doc: /* Set screen colors. */) |
6cdfb6e6 RS |
661 | (foreground, background) |
662 | Lisp_Object foreground; | |
663 | Lisp_Object background; | |
664 | { | |
665 | char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4); | |
6cdfb6e6 RS |
666 | |
667 | Frecenter (Qnil); | |
668 | return Qt; | |
669 | } | |
670 | ||
671 | DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0, | |
33f09670 | 672 | doc: /* Set cursor size. */) |
6cdfb6e6 RS |
673 | (size) |
674 | Lisp_Object size; | |
675 | { | |
676 | CONSOLE_CURSOR_INFO cci; | |
677 | cci.dwSize = XFASTINT (size); | |
678 | cci.bVisible = TRUE; | |
679 | (void) SetConsoleCursorInfo (cur_screen, &cci); | |
177c0ea7 | 680 | |
6cdfb6e6 RS |
681 | return Qt; |
682 | } | |
683 | ||
0534d577 | 684 | void |
6cdfb6e6 RS |
685 | syms_of_ntterm () |
686 | { | |
191100f2 AI |
687 | DEFVAR_BOOL ("w32-use-full-screen-buffer", |
688 | &w32_use_full_screen_buffer, | |
33f09670 JR |
689 | doc: /* Non-nil means make terminal frames use the full screen buffer dimensions. |
690 | This is desirable when running Emacs over telnet, and is the default. | |
691 | A value of nil means use the current console window dimensions; this | |
692 | may be preferrable when working directly at the console with a large | |
693 | scroll-back buffer. */); | |
191100f2 AI |
694 | w32_use_full_screen_buffer = 1; |
695 | ||
6cdfb6e6 RS |
696 | defsubr (&Sset_screen_color); |
697 | defsubr (&Sset_cursor_size); | |
0534d577 | 698 | defsubr (&Sset_message_beep); |
6cdfb6e6 | 699 | } |
ab5796a9 MB |
700 | |
701 | /* arch-tag: a390a07f-f661-42bc-aeb4-e6d8bf860337 | |
702 | (do not change this comment) */ |