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