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" | |
83be827a | 34 | #include "character.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 | ||
fc0b0cff JR |
297 | extern unsigned char *terminal_encode_buffer; |
298 | ||
853895f6 | 299 | extern unsigned char *encode_terminal_code P_ ((struct glyph *, int, |
29e1d29d | 300 | struct coding_system *)); |
853895f6 | 301 | |
7cb010ed JR |
302 | static void |
303 | w32con_write_glyphs (register struct glyph *string, register int len) | |
6cdfb6e6 | 304 | { |
84f5bd81 AI |
305 | int produced, consumed; |
306 | DWORD r; | |
8c2ac482 | 307 | struct frame * f = PICK_FRAME (); |
338b1bb2 JR |
308 | WORD char_attr; |
309 | ||
310 | if (len <= 0) | |
311 | return; | |
b47278e1 | 312 | |
8c2ac482 JR |
313 | /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at |
314 | the tail. */ | |
315 | terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK; | |
6cdfb6e6 | 316 | |
8c2ac482 | 317 | while (len > 0) |
6cdfb6e6 | 318 | { |
8c2ac482 JR |
319 | /* Identify a run of glyphs with the same face. */ |
320 | int face_id = string->face_id; | |
321 | int n; | |
177c0ea7 | 322 | |
8c2ac482 JR |
323 | for (n = 1; n < len; ++n) |
324 | if (string[n].face_id != face_id) | |
325 | break; | |
326 | ||
327 | /* Turn appearance modes of the face of the run on. */ | |
338b1bb2 | 328 | char_attr = w32_face_attributes (f, face_id); |
8c2ac482 JR |
329 | |
330 | while (n > 0) | |
331 | { | |
fc0b0cff JR |
332 | produced = encode_terminal_code (string, |
333 | n, | |
8c2ac482 JR |
334 | &consumed); |
335 | if (produced > 0) | |
336 | { | |
337 | /* Set the attribute for these characters. */ | |
338 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, | |
177c0ea7 | 339 | produced, cursor_coords, &r)) |
8c2ac482 JR |
340 | { |
341 | printf ("Failed writing console attributes: %d\n", | |
342 | GetLastError ()); | |
343 | fflush (stdout); | |
344 | } | |
345 | ||
346 | /* Write the characters. */ | |
fc0b0cff | 347 | if (!WriteConsoleOutputCharacter (cur_screen, terminal_encode_buffer, |
84f5bd81 | 348 | produced, cursor_coords, &r)) |
8c2ac482 JR |
349 | { |
350 | printf ("Failed writing console characters: %d\n", | |
351 | GetLastError ()); | |
352 | fflush (stdout); | |
353 | } | |
354 | ||
355 | cursor_coords.X += produced; | |
7cb010ed | 356 | w32con_move_cursor (cursor_coords.Y, cursor_coords.X); |
177c0ea7 | 357 | } |
8c2ac482 JR |
358 | len -= consumed; |
359 | n -= consumed; | |
360 | string += consumed; | |
361 | } | |
6cdfb6e6 RS |
362 | } |
363 | ||
8c2ac482 JR |
364 | /* We may have to output some codes to terminate the writing. */ |
365 | if (CODING_REQUIRE_FLUSHING (&terminal_coding)) | |
6cdfb6e6 | 366 | { |
fc0b0cff JR |
367 | Lisp_Object blank_string = build_string (""); |
368 | int conversion_buffer_size = 1024; | |
369 | ||
8c2ac482 | 370 | terminal_coding.mode |= CODING_MODE_LAST_BLOCK; |
fc0b0cff JR |
371 | terminal_coding.destination = (unsigned char *) xmalloc (conversion_buffer_size); |
372 | encode_coding_object (&terminal_coding, blank_string, 0, 0, | |
373 | 0, conversion_buffer_size, Qnil); | |
8c2ac482 JR |
374 | if (terminal_coding.produced > 0) |
375 | { | |
338b1bb2 | 376 | if (!FillConsoleOutputAttribute (cur_screen, char_attr_normal, |
8c2ac482 | 377 | terminal_coding.produced, |
177c0ea7 | 378 | cursor_coords, &r)) |
8c2ac482 JR |
379 | { |
380 | printf ("Failed writing console attributes: %d\n", | |
381 | GetLastError ()); | |
382 | fflush (stdout); | |
383 | } | |
384 | ||
385 | /* Write the characters. */ | |
fc0b0cff | 386 | if (!WriteConsoleOutputCharacter (cur_screen, terminal_coding.destination, |
84f5bd81 | 387 | produced, cursor_coords, &r)) |
8c2ac482 JR |
388 | { |
389 | printf ("Failed writing console characters: %d\n", | |
390 | GetLastError ()); | |
391 | fflush (stdout); | |
392 | } | |
393 | } | |
fc0b0cff | 394 | xfree (terminal_coding.destination); |
6cdfb6e6 | 395 | } |
6cdfb6e6 RS |
396 | } |
397 | ||
8c2ac482 | 398 | |
7cb010ed JR |
399 | static void |
400 | w32con_delete_glyphs (int n) | |
6cdfb6e6 | 401 | { |
177c0ea7 JB |
402 | /* delete chars means scroll chars from cursor_coords.X + n to |
403 | cursor_coords.X, anything beyond the edge of the screen should | |
6cdfb6e6 RS |
404 | come out empty... */ |
405 | ||
406 | scroll_line (n, LEFT); | |
407 | } | |
408 | ||
0534d577 | 409 | static unsigned int sound_type = 0xFFFFFFFF; |
78859b80 | 410 | #define MB_EMACS_SILENT (0xFFFFFFFF - 1) |
0534d577 | 411 | |
6cdfb6e6 | 412 | void |
fbd6baed | 413 | w32_sys_ring_bell (void) |
6cdfb6e6 | 414 | { |
177c0ea7 | 415 | if (sound_type == 0xFFFFFFFF) |
78859b80 | 416 | { |
0534d577 | 417 | Beep (666, 100); |
78859b80 GV |
418 | } |
419 | else if (sound_type == MB_EMACS_SILENT) | |
420 | { | |
421 | /* Do nothing. */ | |
422 | } | |
0534d577 | 423 | else |
78859b80 | 424 | MessageBeep (sound_type); |
6cdfb6e6 RS |
425 | } |
426 | ||
0534d577 | 427 | DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0, |
33f09670 JR |
428 | doc: /* Set the sound generated when the bell is rung. |
429 | SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent | |
430 | to use the corresponding system sound for the bell. The 'silent sound | |
431 | prevents Emacs from making any sound at all. | |
432 | SOUND is nil to use the normal beep. */) | |
0534d577 KH |
433 | (sound) |
434 | Lisp_Object sound; | |
6cdfb6e6 | 435 | { |
b7826503 | 436 | CHECK_SYMBOL (sound); |
0534d577 | 437 | |
177c0ea7 | 438 | if (NILP (sound)) |
0534d577 KH |
439 | sound_type = 0xFFFFFFFF; |
440 | else if (EQ (sound, intern ("asterisk"))) | |
441 | sound_type = MB_ICONASTERISK; | |
177c0ea7 | 442 | else if (EQ (sound, intern ("exclamation"))) |
0534d577 | 443 | sound_type = MB_ICONEXCLAMATION; |
177c0ea7 | 444 | else if (EQ (sound, intern ("hand"))) |
0534d577 | 445 | sound_type = MB_ICONHAND; |
177c0ea7 | 446 | else if (EQ (sound, intern ("question"))) |
0534d577 | 447 | sound_type = MB_ICONQUESTION; |
177c0ea7 | 448 | else if (EQ (sound, intern ("ok"))) |
0534d577 | 449 | sound_type = MB_OK; |
78859b80 GV |
450 | else if (EQ (sound, intern ("silent"))) |
451 | sound_type = MB_EMACS_SILENT; | |
0534d577 KH |
452 | else |
453 | sound_type = 0xFFFFFFFF; | |
454 | ||
455 | return sound; | |
6cdfb6e6 | 456 | } |
177c0ea7 | 457 | |
7cb010ed JR |
458 | static void |
459 | w32con_reset_terminal_modes (void) | |
6cdfb6e6 | 460 | { |
3e671d90 | 461 | #ifdef USE_SEPARATE_SCREEN |
6cdfb6e6 | 462 | SetConsoleActiveScreenBuffer (prev_screen); |
3e671d90 GV |
463 | #else |
464 | SetConsoleCursorInfo (prev_screen, &prev_console_cursor); | |
465 | #endif | |
466 | SetConsoleMode (keyboard_handle, prev_console_mode); | |
6cdfb6e6 RS |
467 | } |
468 | ||
7cb010ed JR |
469 | static void |
470 | w32con_set_terminal_modes (void) | |
6cdfb6e6 RS |
471 | { |
472 | CONSOLE_CURSOR_INFO cci; | |
473 | ||
3e671d90 GV |
474 | /* make cursor big and visible (100 on Win95 makes it disappear) */ |
475 | cci.dwSize = 99; | |
476 | cci.bVisible = TRUE; | |
477 | (void) SetConsoleCursorInfo (cur_screen, &cci); | |
6cdfb6e6 | 478 | |
3e671d90 | 479 | SetConsoleActiveScreenBuffer (cur_screen); |
6cdfb6e6 | 480 | |
3e671d90 | 481 | SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT); |
6cdfb6e6 | 482 | |
3e671d90 GV |
483 | /* Initialize input mode: interrupt_input off, no flow control, allow |
484 | 8 bit character input, standard quit char. */ | |
485 | Fset_input_mode (Qnil, Qnil, make_number (2), Qnil); | |
6cdfb6e6 RS |
486 | } |
487 | ||
488 | /* hmmm... perhaps these let us bracket screen changes so that we can flush | |
489 | clumps rather than one-character-at-a-time... | |
177c0ea7 | 490 | |
6cdfb6e6 | 491 | we'll start with not moving the cursor while an update is in progress. */ |
7cb010ed JR |
492 | static void |
493 | w32con_update_begin (struct frame * f) | |
6cdfb6e6 RS |
494 | { |
495 | } | |
496 | ||
7cb010ed JR |
497 | static void |
498 | w32con_update_end (struct frame * f) | |
6cdfb6e6 RS |
499 | { |
500 | SetConsoleCursorPosition (cur_screen, cursor_coords); | |
501 | } | |
502 | ||
7cb010ed JR |
503 | static void |
504 | w32con_set_terminal_window (int size) | |
6cdfb6e6 RS |
505 | { |
506 | } | |
507 | ||
8c2ac482 JR |
508 | /*********************************************************************** |
509 | Faces | |
510 | ***********************************************************************/ | |
511 | ||
512 | ||
513 | /* Turn appearances of face FACE_ID on tty frame F on. */ | |
514 | ||
338b1bb2 JR |
515 | static WORD |
516 | w32_face_attributes (f, face_id) | |
8c2ac482 JR |
517 | struct frame *f; |
518 | int face_id; | |
519 | { | |
338b1bb2 | 520 | WORD char_attr; |
8c2ac482 JR |
521 | struct face *face = FACE_FROM_ID (f, face_id); |
522 | ||
523 | xassert (face != NULL); | |
524 | ||
525 | char_attr = char_attr_normal; | |
526 | ||
338b1bb2 JR |
527 | if (face->foreground != FACE_TTY_DEFAULT_FG_COLOR |
528 | && face->foreground != FACE_TTY_DEFAULT_COLOR) | |
529 | char_attr = (char_attr & 0xfff0) + (face->foreground % 16); | |
530 | ||
531 | if (face->background != FACE_TTY_DEFAULT_BG_COLOR | |
532 | && face->background != FACE_TTY_DEFAULT_COLOR) | |
177c0ea7 | 533 | char_attr = (char_attr & 0xff0f) + ((face->background % 16) << 4); |
338b1bb2 | 534 | |
8c2ac482 | 535 | |
b93b26cb JR |
536 | /* NTEMACS_TODO: Faces defined during startup get both foreground |
537 | and background of 0. Need a better way around this - for now detect | |
538 | the problem and invert one of the faces to make the text readable. */ | |
338b1bb2 JR |
539 | if (((char_attr & 0x00f0) >> 4) == (char_attr & 0x000f)) |
540 | char_attr ^= 0x0007; | |
8c2ac482 | 541 | |
e850a615 | 542 | if (face->tty_reverse_p) |
338b1bb2 JR |
543 | char_attr = (char_attr & 0xff00) + ((char_attr & 0x000f) << 4) |
544 | + ((char_attr & 0x00f0) >> 4); | |
8c2ac482 | 545 | |
338b1bb2 | 546 | return char_attr; |
8c2ac482 JR |
547 | } |
548 | ||
549 | ||
338b1bb2 | 550 | /* Emulation of some X window features from xfns.c and xfaces.c. */ |
8c2ac482 | 551 | |
338b1bb2 JR |
552 | extern char unspecified_fg[], unspecified_bg[]; |
553 | ||
554 | ||
555 | /* Given a color index, return its standard name. */ | |
556 | Lisp_Object | |
557 | vga_stdcolor_name (int idx) | |
8c2ac482 | 558 | { |
338b1bb2 JR |
559 | /* Standard VGA colors, in the order of their standard numbering |
560 | in the default VGA palette. */ | |
561 | static char *vga_colors[16] = { | |
562 | "black", "blue", "green", "cyan", "red", "magenta", "brown", | |
563 | "lightgray", "darkgray", "lightblue", "lightgreen", "lightcyan", | |
564 | "lightred", "lightmagenta", "yellow", "white" | |
565 | }; | |
566 | ||
567 | extern Lisp_Object Qunspecified; | |
568 | ||
569 | if (idx >= 0 && idx < sizeof (vga_colors) / sizeof (vga_colors[0])) | |
570 | return build_string (vga_colors[idx]); | |
571 | else | |
572 | return Qunspecified; /* meaning the default */ | |
8c2ac482 | 573 | } |
338b1bb2 | 574 | |
6cdfb6e6 RS |
575 | typedef int (*term_hook) (); |
576 | ||
577 | void | |
e6b20d65 | 578 | initialize_w32_display (void) |
6cdfb6e6 RS |
579 | { |
580 | CONSOLE_SCREEN_BUFFER_INFO info; | |
177c0ea7 | 581 | |
7cb010ed JR |
582 | cursor_to_hook = w32con_move_cursor; |
583 | raw_cursor_to_hook = w32con_move_cursor; | |
584 | clear_to_end_hook = w32con_clear_to_end; | |
585 | clear_frame_hook = w32con_clear_frame; | |
586 | clear_end_of_line_hook = w32con_clear_end_of_line; | |
587 | ins_del_lines_hook = w32con_ins_del_lines; | |
588 | insert_glyphs_hook = w32con_insert_glyphs; | |
589 | write_glyphs_hook = w32con_write_glyphs; | |
590 | delete_glyphs_hook = w32con_delete_glyphs; | |
f3d268f9 | 591 | ring_bell_hook = w32_sys_ring_bell; |
7cb010ed JR |
592 | reset_terminal_modes_hook = w32con_reset_terminal_modes; |
593 | set_terminal_modes_hook = w32con_set_terminal_modes; | |
594 | set_terminal_window_hook = w32con_set_terminal_window; | |
595 | update_begin_hook = w32con_update_begin; | |
596 | update_end_hook = w32con_update_end; | |
177c0ea7 | 597 | |
fbd6baed | 598 | read_socket_hook = w32_console_read_socket; |
f3d268f9 | 599 | mouse_position_hook = w32_console_mouse_position; |
3e671d90 | 600 | |
c1e06681 AI |
601 | /* Initialize interrupt_handle. */ |
602 | init_crit (); | |
603 | ||
3e671d90 GV |
604 | /* Remember original console settings. */ |
605 | keyboard_handle = GetStdHandle (STD_INPUT_HANDLE); | |
606 | GetConsoleMode (keyboard_handle, &prev_console_mode); | |
607 | ||
6cdfb6e6 | 608 | prev_screen = GetStdHandle (STD_OUTPUT_HANDLE); |
177c0ea7 | 609 | |
3e671d90 GV |
610 | #ifdef USE_SEPARATE_SCREEN |
611 | cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE, | |
612 | 0, NULL, | |
613 | CONSOLE_TEXTMODE_BUFFER, | |
614 | NULL); | |
615 | ||
616 | if (cur_screen == INVALID_HANDLE_VALUE) | |
617 | { | |
618 | printf ("CreateConsoleScreenBuffer failed in ResetTerm\n"); | |
619 | printf ("LastError = 0x%lx\n", GetLastError ()); | |
620 | fflush (stdout); | |
621 | exit (0); | |
622 | } | |
623 | #else | |
624 | cur_screen = prev_screen; | |
625 | GetConsoleCursorInfo (prev_screen, &prev_console_cursor); | |
626 | #endif | |
627 | ||
191100f2 AI |
628 | /* Respect setting of LINES and COLUMNS environment variables. */ |
629 | { | |
630 | char * lines = getenv("LINES"); | |
631 | char * columns = getenv("COLUMNS"); | |
632 | ||
633 | if (lines != NULL && columns != NULL) | |
634 | { | |
635 | SMALL_RECT new_win_dims; | |
636 | COORD new_size; | |
637 | ||
638 | new_size.X = atoi (columns); | |
639 | new_size.Y = atoi (lines); | |
640 | ||
641 | GetConsoleScreenBufferInfo (cur_screen, &info); | |
642 | ||
643 | /* Shrink the window first, so the buffer dimensions can be | |
644 | reduced if necessary. */ | |
645 | new_win_dims.Top = 0; | |
646 | new_win_dims.Left = 0; | |
647 | new_win_dims.Bottom = min (new_size.Y, info.dwSize.Y) - 1; | |
648 | new_win_dims.Right = min (new_size.X, info.dwSize.X) - 1; | |
649 | SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims); | |
650 | ||
651 | SetConsoleScreenBufferSize (cur_screen, new_size); | |
652 | ||
653 | /* Set the window size to match the buffer dimension. */ | |
654 | new_win_dims.Top = 0; | |
655 | new_win_dims.Left = 0; | |
656 | new_win_dims.Bottom = new_size.Y - 1; | |
657 | new_win_dims.Right = new_size.X - 1; | |
658 | SetConsoleWindowInfo (cur_screen, TRUE, &new_win_dims); | |
659 | } | |
660 | } | |
661 | ||
6cdfb6e6 | 662 | GetConsoleScreenBufferInfo (cur_screen, &info); |
177c0ea7 | 663 | |
6cdfb6e6 | 664 | meta_key = 1; |
338b1bb2 | 665 | char_attr_normal = info.wAttributes; |
938469f2 | 666 | |
191100f2 AI |
667 | if (w32_use_full_screen_buffer) |
668 | { | |
90022f5a KS |
669 | FRAME_LINES (SELECTED_FRAME ()) = info.dwSize.Y; /* lines per page */ |
670 | SET_FRAME_COLS (SELECTED_FRAME (), info.dwSize.X); /* characters per line */ | |
191100f2 AI |
671 | } |
672 | else | |
673 | { | |
674 | /* Lines per page. Use buffer coords instead of buffer size. */ | |
90022f5a | 675 | FRAME_LINES (SELECTED_FRAME ()) = 1 + info.srWindow.Bottom - |
177c0ea7 | 676 | info.srWindow.Top; |
191100f2 | 677 | /* Characters per line. Use buffer coords instead of buffer size. */ |
90022f5a | 678 | SET_FRAME_COLS (SELECTED_FRAME (), 1 + info.srWindow.Right - |
191100f2 AI |
679 | info.srWindow.Left); |
680 | } | |
65fb143c JR |
681 | |
682 | /* Setup w32_display_info structure for this frame. */ | |
683 | ||
684 | w32_initialize_display_info (build_string ("Console")); | |
685 | ||
6cdfb6e6 RS |
686 | } |
687 | ||
688 | DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0, | |
33f09670 | 689 | doc: /* Set screen colors. */) |
6cdfb6e6 RS |
690 | (foreground, background) |
691 | Lisp_Object foreground; | |
692 | Lisp_Object background; | |
693 | { | |
694 | char_attr_normal = XFASTINT (foreground) + (XFASTINT (background) << 4); | |
6cdfb6e6 RS |
695 | |
696 | Frecenter (Qnil); | |
697 | return Qt; | |
698 | } | |
699 | ||
700 | DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0, | |
33f09670 | 701 | doc: /* Set cursor size. */) |
6cdfb6e6 RS |
702 | (size) |
703 | Lisp_Object size; | |
704 | { | |
705 | CONSOLE_CURSOR_INFO cci; | |
706 | cci.dwSize = XFASTINT (size); | |
707 | cci.bVisible = TRUE; | |
708 | (void) SetConsoleCursorInfo (cur_screen, &cci); | |
177c0ea7 | 709 | |
6cdfb6e6 RS |
710 | return Qt; |
711 | } | |
712 | ||
0534d577 | 713 | void |
6cdfb6e6 RS |
714 | syms_of_ntterm () |
715 | { | |
191100f2 AI |
716 | DEFVAR_BOOL ("w32-use-full-screen-buffer", |
717 | &w32_use_full_screen_buffer, | |
33f09670 JR |
718 | doc: /* Non-nil means make terminal frames use the full screen buffer dimensions. |
719 | This is desirable when running Emacs over telnet, and is the default. | |
720 | A value of nil means use the current console window dimensions; this | |
721 | may be preferrable when working directly at the console with a large | |
722 | scroll-back buffer. */); | |
191100f2 AI |
723 | w32_use_full_screen_buffer = 1; |
724 | ||
6cdfb6e6 RS |
725 | defsubr (&Sset_screen_color); |
726 | defsubr (&Sset_cursor_size); | |
0534d577 | 727 | defsubr (&Sset_message_beep); |
6cdfb6e6 | 728 | } |
6b61353c KH |
729 | |
730 | /* arch-tag: a390a07f-f661-42bc-aeb4-e6d8bf860337 | |
731 | (do not change this comment) */ |