diff options
| author | ewantown | 2025-10-12 07:23:53 -0700 |
|---|---|---|
| committer | Eli Zaretskii | 2026-04-08 15:12:14 +0300 |
| commit | 2bca4ac0ed7f9911c5d1443615ec3e1ac3364a8d (patch) | |
| tree | 77583a72152db370e2430a2f110c5f063f933fb4 /src | |
| parent | 9b8361d9abddb32a343ba325421bad13be2837b8 (diff) | |
| download | emacs-2bca4ac0ed7f9911c5d1443615ec3e1ac3364a8d.tar.gz emacs-2bca4ac0ed7f9911c5d1443615ec3e1ac3364a8d.zip | |
Support 24-bit TrueColor on MS-Windows console
* src/w32console.c (DEFAULTP, SSPRINTF, w32con_write_vt_seq)
(w32con_get_cursor_coords): New functions and macros.
(w32con_write_glyphs): Hide cursor before writing to the console.
Add code for writing in virtual-terminal mode when
'w32_use_virtual_terminal' is non-zero.
(w32con_write_glyphs_with_face): Add code for writing in
virtual-terminal mode when 'w32_use_virtual_terminal' is non-zero.
(w32con_setup_virtual_terminal): New function.
(w32con_set_terminal_modes): Call it.
(turn_on_face, turn_off_face): New functions.
(initialize_w32_display): Save background and foreground, and the
current TTY.
(Fset_screen_color): Accept an additional optional argument VTP;
if non-nil, arrange for 24-bit display to use the specified
colors.
(Fget_screen_color): Accept an additional optional argument VTP;
if non-nil, return colors used by 24-bit display.
(Fw32_use_virtual_terminal, Fw32_use_virtual_terminal_p): New
functions.
* src/term.c (tty_setup_colors) [WINDOWSNT]: Set up
virtual-terminal sequences for colors.
(init_tty) [WINDOWSNT]: Set up terminfo capabilities for Windows
virtual-terminal.
* src/xdisp.c (redisplay_internal): Don't call set_tty_color_mode
for WINDOWSNT.
* lisp/term/w32console.el (w32-tty-set-base-colors)
(w32-tty-define-base-colors, w32-tty-define-8bit-colors)
(w32-tty-define-24bit-colors, w32-tty-get-pixel): New functions.
(terminal-init-w32console): Remove color setup.
(w32-tty-setup-colors): New function.
* lisp/term/tty-colors.el (tty-color-mode-alist): Add --color
modes for 256 and 24-bit color modes.
* lisp/startup.el (tty-handle-args): Fix --color handling.
* lisp/faces.el (tty-set-up-initial-frame-faces): Set up colors
for MS-Windows consoles.
* etc/NEWS:
* doc/emacs/msdos.texi (Windows Misc):
* doc/emacs/cmdargs.texi (Colors X): Document 24-bit color support
on MS-Windows.
(Bug#79298)
Diffstat (limited to 'src')
| -rw-r--r-- | src/term.c | 51 | ||||
| -rw-r--r-- | src/termchar.h | 2 | ||||
| -rw-r--r-- | src/w32console.c | 348 | ||||
| -rw-r--r-- | src/xdisp.c | 2 |
4 files changed, 339 insertions, 64 deletions
diff --git a/src/term.c b/src/term.c index b5cf418450f..766eeebe5e8 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -2207,7 +2207,7 @@ TERMINAL does not refer to a text terminal. */) | |||
| 2207 | return make_fixnum (t ? t->display_info.tty->TN_max_colors : 0); | 2207 | return make_fixnum (t ? t->display_info.tty->TN_max_colors : 0); |
| 2208 | } | 2208 | } |
| 2209 | 2209 | ||
| 2210 | #if !defined DOS_NT && !defined HAVE_ANDROID | 2210 | #if !defined MSDOS && !defined HAVE_ANDROID |
| 2211 | 2211 | ||
| 2212 | /* Declare here rather than in the function, as in the rest of Emacs, | 2212 | /* Declare here rather than in the function, as in the rest of Emacs, |
| 2213 | to work around an HPUX compiler bug (?). See | 2213 | to work around an HPUX compiler bug (?). See |
| @@ -2246,7 +2246,7 @@ tty_default_color_capabilities (struct tty_display_info *tty, bool save) | |||
| 2246 | MODE's value is generally the number of colors which we want to | 2246 | MODE's value is generally the number of colors which we want to |
| 2247 | support; zero means set up for the default capabilities, the ones | 2247 | support; zero means set up for the default capabilities, the ones |
| 2248 | we saw at init_tty time; -1 means turn off color support. */ | 2248 | we saw at init_tty time; -1 means turn off color support. */ |
| 2249 | static void | 2249 | void |
| 2250 | tty_setup_colors (struct tty_display_info *tty, int mode) | 2250 | tty_setup_colors (struct tty_display_info *tty, int mode) |
| 2251 | { | 2251 | { |
| 2252 | /* Canonicalize all negative values of MODE. */ | 2252 | /* Canonicalize all negative values of MODE. */ |
| @@ -2269,6 +2269,10 @@ tty_setup_colors (struct tty_display_info *tty, int mode) | |||
| 2269 | #ifdef TERMINFO | 2269 | #ifdef TERMINFO |
| 2270 | tty->TS_set_foreground = "\033[3%p1%dm"; | 2270 | tty->TS_set_foreground = "\033[3%p1%dm"; |
| 2271 | tty->TS_set_background = "\033[4%p1%dm"; | 2271 | tty->TS_set_background = "\033[4%p1%dm"; |
| 2272 | #elif WINDOWSNT | ||
| 2273 | tty->TS_orig_pair = "\x1b[39m\x1b[49m"; | ||
| 2274 | tty->TS_set_foreground = "\x1b[%lum"; | ||
| 2275 | tty->TS_set_background = "\x1b[%lum"; | ||
| 2272 | #else | 2276 | #else |
| 2273 | tty->TS_set_foreground = "\033[3%dm"; | 2277 | tty->TS_set_foreground = "\033[3%dm"; |
| 2274 | tty->TS_set_background = "\033[4%dm"; | 2278 | tty->TS_set_background = "\033[4%dm"; |
| @@ -2276,6 +2280,26 @@ tty_setup_colors (struct tty_display_info *tty, int mode) | |||
| 2276 | tty->TN_max_colors = 8; | 2280 | tty->TN_max_colors = 8; |
| 2277 | tty->TN_no_color_video = 0; | 2281 | tty->TN_no_color_video = 0; |
| 2278 | break; | 2282 | break; |
| 2283 | #ifdef WINDOWSNT | ||
| 2284 | case 16: | ||
| 2285 | tty->TN_max_colors = 16; | ||
| 2286 | tty->TS_set_foreground = "\x1b[%lum"; | ||
| 2287 | tty->TS_set_background = "\x1b[%lum"; | ||
| 2288 | tty->TN_no_color_video = 0; | ||
| 2289 | break; | ||
| 2290 | case 256: | ||
| 2291 | tty->TN_max_colors = 256; | ||
| 2292 | tty->TS_set_foreground = "\x1b[38;5;%lum"; | ||
| 2293 | tty->TS_set_background = "\x1b[48;5;%lum"; | ||
| 2294 | tty->TN_no_color_video = 0; | ||
| 2295 | break; | ||
| 2296 | case 16777216: | ||
| 2297 | tty->TN_max_colors = 16777216; | ||
| 2298 | tty->TS_set_foreground = "\x1b[38;2;%lu;%lu;%lum"; | ||
| 2299 | tty->TS_set_background = "\x1b[48;2;%lu;%lu;%lum"; | ||
| 2300 | tty->TN_no_color_video = 0; | ||
| 2301 | break; | ||
| 2302 | #endif | ||
| 2279 | } | 2303 | } |
| 2280 | } | 2304 | } |
| 2281 | 2305 | ||
| @@ -2312,7 +2336,7 @@ set_tty_color_mode (struct tty_display_info *tty, struct frame *f) | |||
| 2312 | } | 2336 | } |
| 2313 | } | 2337 | } |
| 2314 | 2338 | ||
| 2315 | #endif /* !DOS_NT && !HAVE_ANDROID */ | 2339 | #endif /* !MSDOS && !HAVE_ANDROID */ |
| 2316 | 2340 | ||
| 2317 | char * | 2341 | char * |
| 2318 | tty_type_name (Lisp_Object terminal) | 2342 | tty_type_name (Lisp_Object terminal) |
| @@ -4644,6 +4668,22 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ | |||
| 4644 | 4668 | ||
| 4645 | initialize_w32_display (terminal, &width, &height); | 4669 | initialize_w32_display (terminal, &width, &height); |
| 4646 | 4670 | ||
| 4671 | tty->TN_no_color_video = 0; | ||
| 4672 | tty->TN_max_colors = 16777216; | ||
| 4673 | tty->TS_orig_pair = "\x1b[39m\x1b[49m"; | ||
| 4674 | tty->TS_set_foreground = "\x1b[38;2;%lu;%lu;%lum"; | ||
| 4675 | tty->TS_set_background = "\x1b[48;2;%lu;%lu;%lum"; | ||
| 4676 | |||
| 4677 | /* Save default color capabilities */ | ||
| 4678 | tty_default_color_capabilities (tty, 1); | ||
| 4679 | |||
| 4680 | tty->TS_enter_bold_mode = "\x1b[1m"; | ||
| 4681 | tty->TS_enter_italic_mode = "\x1b[3m"; | ||
| 4682 | tty->TS_enter_strike_through_mode = "\x1b[9m"; | ||
| 4683 | tty->TS_enter_underline_mode = "\x1b[4m"; | ||
| 4684 | tty->TS_enter_reverse_mode = "\x1b[7m"; | ||
| 4685 | tty->TS_exit_attribute_mode = "\x1b[0m"; | ||
| 4686 | |||
| 4647 | FrameRows (tty) = height; | 4687 | FrameRows (tty) = height; |
| 4648 | FrameCols (tty) = width; | 4688 | FrameCols (tty) = width; |
| 4649 | tty->specified_window = height; | 4689 | tty->specified_window = height; |
| @@ -4689,7 +4729,6 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ | |||
| 4689 | don't think we're losing anything by turning it off. */ | 4729 | don't think we're losing anything by turning it off. */ |
| 4690 | tty->line_ins_del_ok = 0; | 4730 | tty->line_ins_del_ok = 0; |
| 4691 | 4731 | ||
| 4692 | tty->TN_max_colors = 16; /* Must be non-zero for tty-display-color-p. */ | ||
| 4693 | #endif /* DOS_NT */ | 4732 | #endif /* DOS_NT */ |
| 4694 | 4733 | ||
| 4695 | #ifdef HAVE_GPM | 4734 | #ifdef HAVE_GPM |
| @@ -5205,11 +5244,11 @@ non-nil to enable this optimization. */); | |||
| 5205 | defsubr (&Stty_display_pixel_width); | 5244 | defsubr (&Stty_display_pixel_width); |
| 5206 | defsubr (&Stty_display_pixel_height); | 5245 | defsubr (&Stty_display_pixel_height); |
| 5207 | 5246 | ||
| 5208 | #if !defined DOS_NT && !defined HAVE_ANDROID | 5247 | #if !defined MSDOS && !defined HAVE_ANDROID |
| 5209 | default_orig_pair = NULL; | 5248 | default_orig_pair = NULL; |
| 5210 | default_set_foreground = NULL; | 5249 | default_set_foreground = NULL; |
| 5211 | default_set_background = NULL; | 5250 | default_set_background = NULL; |
| 5212 | #endif /* !DOS_NT && !HAVE_ANDROID */ | 5251 | #endif /* !MSDOS && !HAVE_ANDROID */ |
| 5213 | 5252 | ||
| 5214 | #ifndef HAVE_ANDROID | 5253 | #ifndef HAVE_ANDROID |
| 5215 | encode_terminal_src = NULL; | 5254 | encode_terminal_src = NULL; |
diff --git a/src/termchar.h b/src/termchar.h index 9d7c3a2a555..9a9001d5cef 100644 --- a/src/termchar.h +++ b/src/termchar.h | |||
| @@ -249,4 +249,6 @@ struct input_event; | |||
| 249 | extern Lisp_Object tty_handle_tab_bar_click (struct frame *, int, int, bool, | 249 | extern Lisp_Object tty_handle_tab_bar_click (struct frame *, int, int, bool, |
| 250 | struct input_event *); | 250 | struct input_event *); |
| 251 | 251 | ||
| 252 | extern void tty_setup_colors (struct tty_display_info *tty, int mode); | ||
| 253 | |||
| 252 | #endif /* EMACS_TERMCHAR_H */ | 254 | #endif /* EMACS_TERMCHAR_H */ |
diff --git a/src/w32console.c b/src/w32console.c index be5e0b92072..b0a2f0c1c0e 100644 --- a/src/w32console.c +++ b/src/w32console.c | |||
| @@ -19,6 +19,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 19 | /* | 19 | /* |
| 20 | Tim Fleehart (apollo@online.com) 1-17-92 | 20 | Tim Fleehart (apollo@online.com) 1-17-92 |
| 21 | Geoff Voelker (voelker@cs.washington.edu) 9-12-93 | 21 | Geoff Voelker (voelker@cs.washington.edu) 9-12-93 |
| 22 | Ewan Townshend (ewan@etown.dev) 2025-08 | ||
| 23 | * c. ~ 2025: 24bit RGB support in Windows (10+) Terminal | ||
| 24 | * https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences | ||
| 22 | */ | 25 | */ |
| 23 | 26 | ||
| 24 | 27 | ||
| @@ -53,11 +56,17 @@ static void w32con_set_terminal_modes (struct terminal *t); | |||
| 53 | static void w32con_update_begin (struct frame * f); | 56 | static void w32con_update_begin (struct frame * f); |
| 54 | static void w32con_update_end (struct frame * f); | 57 | static void w32con_update_end (struct frame * f); |
| 55 | static WORD w32_face_attributes (struct frame *f, int face_id); | 58 | static WORD w32_face_attributes (struct frame *f, int face_id); |
| 59 | static int w32con_write_vt_seq (const char *); | ||
| 60 | static void turn_on_face (struct frame *, int face_id); | ||
| 61 | static void turn_off_face (struct frame *, int face_id); | ||
| 62 | static COORD w32con_get_cursor_coords (); | ||
| 56 | 63 | ||
| 57 | static COORD cursor_coords; | 64 | static COORD cursor_coords; |
| 58 | static HANDLE prev_screen, cur_screen; | 65 | static HANDLE prev_screen, cur_screen; |
| 59 | static WORD char_attr_normal; | 66 | static WORD char_attr_normal; |
| 60 | static DWORD prev_console_mode; | 67 | static DWORD prev_console_mode; |
| 68 | static int bg_normal; | ||
| 69 | static int fg_normal; | ||
| 61 | 70 | ||
| 62 | static CONSOLE_CURSOR_INFO console_cursor_info; | 71 | static CONSOLE_CURSOR_INFO console_cursor_info; |
| 63 | #ifndef USE_SEPARATE_SCREEN | 72 | #ifndef USE_SEPARATE_SCREEN |
| @@ -67,7 +76,10 @@ static CONSOLE_CURSOR_INFO prev_console_cursor; | |||
| 67 | extern HANDLE keyboard_handle; | 76 | extern HANDLE keyboard_handle; |
| 68 | HANDLE keyboard_handle; | 77 | HANDLE keyboard_handle; |
| 69 | int w32_console_unicode_input; | 78 | int w32_console_unicode_input; |
| 70 | 79 | extern int w32_use_virtual_terminal; | |
| 80 | int w32_use_virtual_terminal = 1; | ||
| 81 | extern struct tty_display_info *current_tty; | ||
| 82 | struct tty_display_info *current_tty = NULL; | ||
| 71 | 83 | ||
| 72 | /* Setting this as the ctrl handler prevents emacs from being killed when | 84 | /* Setting this as the ctrl handler prevents emacs from being killed when |
| 73 | someone hits ^C in a 'suspended' session (child shell). | 85 | someone hits ^C in a 'suspended' session (child shell). |
| @@ -83,6 +95,38 @@ ctrl_c_handler (unsigned long type) | |||
| 83 | && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)); | 95 | && (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)); |
| 84 | } | 96 | } |
| 85 | 97 | ||
| 98 | #define DEFAULTP(p) \ | ||
| 99 | (p == FACE_TTY_DEFAULT_COLOR \ | ||
| 100 | || p == FACE_TTY_DEFAULT_FG_COLOR \ | ||
| 101 | || p == FACE_TTY_DEFAULT_BG_COLOR) | ||
| 102 | |||
| 103 | #define SEQMAX 256 /* Arbitrary upper limit on VT sequence size */ | ||
| 104 | |||
| 105 | #define SSPRINTF(buf, i, sz, fmt, ...) \ | ||
| 106 | do { \ | ||
| 107 | eassert (*i < sz && sz <= SEQMAX); \ | ||
| 108 | if (fmt && *i < sz && sz <= SEQMAX) \ | ||
| 109 | *i += snprintf (buf + *i, sz - *i, fmt, __VA_ARGS__); \ | ||
| 110 | } while (0) | ||
| 111 | |||
| 112 | /* Writes virtual terminal sequence to screen */ | ||
| 113 | static int | ||
| 114 | w32con_write_vt_seq (const char *seq) | ||
| 115 | { | ||
| 116 | char buf[SEQMAX]; | ||
| 117 | DWORD n = 0, k = 0; | ||
| 118 | SSPRINTF (buf, &n, SEQMAX, seq, NULL); | ||
| 119 | if (n) WriteConsole (cur_screen, (LPCSTR) buf, n, &k, NULL); | ||
| 120 | return k; | ||
| 121 | } | ||
| 122 | |||
| 123 | static COORD | ||
| 124 | w32con_get_cursor_coords () | ||
| 125 | { | ||
| 126 | CONSOLE_SCREEN_BUFFER_INFO info; | ||
| 127 | GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info); | ||
| 128 | return info.dwCursorPosition; | ||
| 129 | } | ||
| 86 | 130 | ||
| 87 | /* Move the cursor to (ROW, COL) on FRAME. */ | 131 | /* Move the cursor to (ROW, COL) on FRAME. */ |
| 88 | static void | 132 | static void |
| @@ -309,10 +353,11 @@ w32con_write_glyphs (struct frame *f, register struct glyph *string, | |||
| 309 | register int len) | 353 | register int len) |
| 310 | { | 354 | { |
| 311 | DWORD r; | 355 | DWORD r; |
| 312 | WORD char_attr; | ||
| 313 | LPCSTR conversion_buffer; | 356 | LPCSTR conversion_buffer; |
| 314 | struct coding_system *coding; | 357 | struct coding_system *coding; |
| 315 | 358 | ||
| 359 | w32con_hide_cursor(); | ||
| 360 | |||
| 316 | if (len <= 0) | 361 | if (len <= 0) |
| 317 | return; | 362 | return; |
| 318 | 363 | ||
| @@ -342,8 +387,6 @@ w32con_write_glyphs (struct frame *f, register struct glyph *string, | |||
| 342 | 387 | ||
| 343 | /* w32con_clear_end_of_line sets frame of glyphs to NULL. */ | 388 | /* w32con_clear_end_of_line sets frame of glyphs to NULL. */ |
| 344 | struct frame *attr_frame = face_id_frame ? face_id_frame : f; | 389 | struct frame *attr_frame = face_id_frame ? face_id_frame : f; |
| 345 | /* Turn appearance modes of the face of the run on. */ | ||
| 346 | char_attr = w32_face_attributes (attr_frame, face_id); | ||
| 347 | 390 | ||
| 348 | if (n == len) | 391 | if (n == len) |
| 349 | /* This is the last run. */ | 392 | /* This is the last run. */ |
| @@ -351,31 +394,45 @@ w32con_write_glyphs (struct frame *f, register struct glyph *string, | |||
| 351 | conversion_buffer = (LPCSTR) encode_terminal_code (string, n, coding); | 394 | conversion_buffer = (LPCSTR) encode_terminal_code (string, n, coding); |
| 352 | if (coding->produced > 0) | 395 | if (coding->produced > 0) |
| 353 | { | 396 | { |
| 354 | /* Compute the string's width on display by accounting for | 397 | if (w32_use_virtual_terminal) |
| 355 | character's width. FIXME: this doesn't handle character | ||
| 356 | compositions. */ | ||
| 357 | ptrdiff_t ncols = strwidth (coding->source, coding->src_bytes); | ||
| 358 | /* Set the attribute for these characters. */ | ||
| 359 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, ncols, | ||
| 360 | cursor_coords, &r)) | ||
| 361 | { | 398 | { |
| 362 | printf ("Failed writing console attributes: %lu\n", | 399 | turn_on_face (f, face_id); |
| 363 | GetLastError ()); | 400 | WriteConsole (cur_screen, conversion_buffer, |
| 364 | fflush (stdout); | 401 | coding->produced, &r, NULL); |
| 402 | turn_off_face (f, face_id); | ||
| 403 | cursor_coords = w32con_get_cursor_coords (); | ||
| 365 | } | 404 | } |
| 366 | 405 | else | |
| 367 | /* Write the characters. */ | ||
| 368 | if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer, | ||
| 369 | coding->produced, cursor_coords, | ||
| 370 | &r)) | ||
| 371 | { | 406 | { |
| 372 | printf ("Failed writing console characters: %lu\n", | 407 | /* Account for character width. |
| 373 | GetLastError ()); | 408 | FIXME: this doesn't handle character compositions. */ |
| 374 | fflush (stdout); | 409 | ptrdiff_t ncols = strwidth (coding->source, coding->src_bytes); |
| 375 | } | 410 | |
| 411 | /* Turn appearance modes of the face of the run on. */ | ||
| 412 | WORD char_attr = w32_face_attributes (attr_frame, face_id); | ||
| 376 | 413 | ||
| 377 | cursor_coords.X += ncols; | 414 | /* Set the attribute for these characters. */ |
| 378 | w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X); | 415 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, ncols, |
| 416 | cursor_coords, &r)) | ||
| 417 | { | ||
| 418 | printf ("Failed writing console attributes: %lu\n", | ||
| 419 | GetLastError ()); | ||
| 420 | fflush (stdout); | ||
| 421 | } | ||
| 422 | |||
| 423 | /* Write the characters. */ | ||
| 424 | if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer, | ||
| 425 | coding->produced, cursor_coords, | ||
| 426 | &r)) | ||
| 427 | { | ||
| 428 | printf ("Failed writing console characters: %lu\n", | ||
| 429 | GetLastError ()); | ||
| 430 | fflush (stdout); | ||
| 431 | } | ||
| 432 | |||
| 433 | cursor_coords.X += ncols; | ||
| 434 | w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X); | ||
| 435 | } | ||
| 379 | } | 436 | } |
| 380 | len -= n; | 437 | len -= n; |
| 381 | string += n; | 438 | string += n; |
| @@ -391,6 +448,8 @@ w32con_write_glyphs_with_face (struct frame *f, register int x, register int y, | |||
| 391 | LPCSTR conversion_buffer; | 448 | LPCSTR conversion_buffer; |
| 392 | struct coding_system *coding; | 449 | struct coding_system *coding; |
| 393 | 450 | ||
| 451 | w32con_hide_cursor(); | ||
| 452 | |||
| 394 | if (len <= 0) | 453 | if (len <= 0) |
| 395 | return; | 454 | return; |
| 396 | 455 | ||
| @@ -407,28 +466,42 @@ w32con_write_glyphs_with_face (struct frame *f, register int x, register int y, | |||
| 407 | if (coding->produced > 0) | 466 | if (coding->produced > 0) |
| 408 | { | 467 | { |
| 409 | DWORD filled, written; | 468 | DWORD filled, written; |
| 410 | /* Compute the character attributes corresponding to the face. */ | 469 | if (w32_use_virtual_terminal) |
| 411 | DWORD char_attr = w32_face_attributes (f, face_id); | 470 | { |
| 412 | COORD start_coords; | 471 | COORD saved_coords = cursor_coords; |
| 413 | /* Compute the string's width on display by accounting for | 472 | w32con_move_cursor(f, y, x); |
| 414 | character's width. FIXME: this doesn't handle character | 473 | turn_on_face (f, face_id); |
| 415 | compositions. */ | 474 | WriteConsole (cur_screen, conversion_buffer, |
| 416 | ptrdiff_t ncols = strwidth (coding->source, coding->src_bytes); | 475 | coding->produced, &written, NULL); |
| 417 | 476 | turn_off_face (f, face_id); | |
| 418 | start_coords.X = x; | 477 | w32con_move_cursor(f, saved_coords.Y, saved_coords.X); |
| 419 | start_coords.Y = y; | 478 | } |
| 420 | /* Set the attribute for these characters. */ | ||
| 421 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, ncols, | ||
| 422 | start_coords, &filled)) | ||
| 423 | DebPrint (("Failed writing console attributes: %d\n", GetLastError ())); | ||
| 424 | else | 479 | else |
| 425 | { | 480 | { |
| 426 | /* Write the characters. */ | 481 | /* Compute the character attributes corresponding to the face. */ |
| 427 | if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer, | 482 | DWORD char_attr = w32_face_attributes (f, face_id); |
| 428 | coding->produced, start_coords, | 483 | COORD start_coords; |
| 429 | &written)) | 484 | |
| 430 | DebPrint (("Failed writing console characters: %d\n", | 485 | start_coords.X = x; |
| 431 | GetLastError ())); | 486 | start_coords.Y = y; |
| 487 | |||
| 488 | /* Account for character width. | ||
| 489 | FIXME: this doesn't handle character compositions. */ | ||
| 490 | ptrdiff_t ncols = strwidth (coding->source, coding->src_bytes); | ||
| 491 | |||
| 492 | /* Set the attribute for these characters. */ | ||
| 493 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, ncols, | ||
| 494 | start_coords, &filled)) | ||
| 495 | DebPrint (("Failed writing console attributes: %d\n", GetLastError ())); | ||
| 496 | else | ||
| 497 | { | ||
| 498 | /* Write the characters. */ | ||
| 499 | if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer, | ||
| 500 | coding->produced, start_coords, | ||
| 501 | &written)) | ||
| 502 | DebPrint (("Failed writing console characters: %d\n", | ||
| 503 | GetLastError ())); | ||
| 504 | } | ||
| 432 | } | 505 | } |
| 433 | } | 506 | } |
| 434 | } | 507 | } |
| @@ -529,6 +602,33 @@ w32con_delete_glyphs (struct frame *f, int n) | |||
| 529 | scroll_line (f, n, LEFT); | 602 | scroll_line (f, n, LEFT); |
| 530 | } | 603 | } |
| 531 | 604 | ||
| 605 | static void | ||
| 606 | w32con_setup_virtual_terminal (void) | ||
| 607 | { | ||
| 608 | /* Disable unless 24bit color is supported (v. > 10.0.15063). */ | ||
| 609 | w32_use_virtual_terminal = w32_use_virtual_terminal | ||
| 610 | && (w32_major_version > 10 | ||
| 611 | || (w32_major_version == 10 | ||
| 612 | && (w32_minor_version > 0 || w32_build_number > 15063))); | ||
| 613 | |||
| 614 | DWORD out_mode; | ||
| 615 | GetConsoleMode (cur_screen, &out_mode); | ||
| 616 | out_mode |= ENABLE_PROCESSED_OUTPUT; | ||
| 617 | out_mode |= DISABLE_NEWLINE_AUTO_RETURN; | ||
| 618 | |||
| 619 | if (w32_use_virtual_terminal) | ||
| 620 | out_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; | ||
| 621 | else | ||
| 622 | out_mode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING; | ||
| 623 | |||
| 624 | int out_mode_set = SetConsoleMode (cur_screen, out_mode); | ||
| 625 | w32_use_virtual_terminal = w32_use_virtual_terminal && out_mode_set; | ||
| 626 | |||
| 627 | int max_colors = w32_use_virtual_terminal ? 16777216 : 16; | ||
| 628 | tty_setup_colors (current_tty, max_colors); | ||
| 629 | |||
| 630 | safe_calln (Qtty_set_up_initial_frame_faces); | ||
| 631 | } | ||
| 532 | 632 | ||
| 533 | static void | 633 | static void |
| 534 | w32con_reset_terminal_modes (struct terminal *t) | 634 | w32con_reset_terminal_modes (struct terminal *t) |
| @@ -585,6 +685,7 @@ w32con_set_terminal_modes (struct terminal *t) | |||
| 585 | /* Initialize input mode: interrupt_input off, no flow control, allow | 685 | /* Initialize input mode: interrupt_input off, no flow control, allow |
| 586 | 8 bit character input, standard quit char. */ | 686 | 8 bit character input, standard quit char. */ |
| 587 | Fset_input_mode (Qnil, Qnil, make_fixnum (2), Qnil); | 687 | Fset_input_mode (Qnil, Qnil, make_fixnum (2), Qnil); |
| 688 | w32con_setup_virtual_terminal (); | ||
| 588 | } | 689 | } |
| 589 | 690 | ||
| 590 | /* hmmm... perhaps these let us bracket screen changes so that we can flush | 691 | /* hmmm... perhaps these let us bracket screen changes so that we can flush |
| @@ -631,8 +732,6 @@ sys_tgetstr (char *cap, char **area) | |||
| 631 | stubs from cm.c | 732 | stubs from cm.c |
| 632 | ***********************************************************************/ | 733 | ***********************************************************************/ |
| 633 | 734 | ||
| 634 | extern struct tty_display_info *current_tty; | ||
| 635 | struct tty_display_info *current_tty = NULL; | ||
| 636 | extern int cost; | 735 | extern int cost; |
| 637 | int cost = 0; | 736 | int cost = 0; |
| 638 | 737 | ||
| @@ -736,6 +835,87 @@ w32_face_attributes (struct frame *f, int face_id) | |||
| 736 | return char_attr; | 835 | return char_attr; |
| 737 | } | 836 | } |
| 738 | 837 | ||
| 838 | static void | ||
| 839 | turn_on_face (struct frame *f, int face_id) | ||
| 840 | { | ||
| 841 | struct face *face = FACE_FROM_ID (f, face_id); | ||
| 842 | struct tty_display_info *tty = FRAME_TTY (f); | ||
| 843 | unsigned long fg = face->foreground; | ||
| 844 | unsigned long bg = face->background; | ||
| 845 | |||
| 846 | /* construct combined VT sequence for face attributes */ | ||
| 847 | DWORD n = 0; | ||
| 848 | size_t sz = SEQMAX; | ||
| 849 | char seq[sz]; | ||
| 850 | sz--; | ||
| 851 | |||
| 852 | if (face->tty_bold_p) | ||
| 853 | SSPRINTF (seq, &n, sz, tty->TS_enter_bold_mode, NULL); | ||
| 854 | if (face->tty_italic_p) | ||
| 855 | SSPRINTF (seq, &n, sz, tty->TS_enter_italic_mode, NULL); | ||
| 856 | if (face->tty_strike_through_p) | ||
| 857 | SSPRINTF (seq, &n, sz, tty->TS_enter_strike_through_mode, NULL); | ||
| 858 | if (face->underline != 0) | ||
| 859 | SSPRINTF (seq, &n, sz, tty->TS_enter_underline_mode, NULL); | ||
| 860 | /* Note: when face->tty_reverse_p != 0 and fg and bg are specified, | ||
| 861 | their values are already swapped and reversing them here would swap | ||
| 862 | them back, but we need to handle the reversal when unspecified. */ | ||
| 863 | if (face->tty_reverse_p && DEFAULTP (fg) && DEFAULTP (bg)) | ||
| 864 | SSPRINTF (seq, &n, sz, tty->TS_enter_reverse_mode, NULL); | ||
| 865 | |||
| 866 | if (DEFAULTP (fg)) fg = fg_normal; | ||
| 867 | if (DEFAULTP (bg)) bg = bg_normal; | ||
| 868 | |||
| 869 | const char *set_fg = tty->TS_set_foreground; | ||
| 870 | const char *set_bg = tty->TS_set_background; | ||
| 871 | if (tty->TN_max_colors == 8 || tty->TN_max_colors == 16) | ||
| 872 | { | ||
| 873 | /* fg and bg are indices into 16 base colors (see link at top). */ | ||
| 874 | unsigned long fgi = 0, bgi = 0; | ||
| 875 | |||
| 876 | fgi = (fg >= 0 && fg < 8) | ||
| 877 | ? fg + 30 | ||
| 878 | : (fg >= 8 && fg < 16) | ||
| 879 | ? fg - 8 + 90 | ||
| 880 | : 0; | ||
| 881 | if (fgi) | ||
| 882 | SSPRINTF (seq, &n, sz, set_fg, fgi); | ||
| 883 | |||
| 884 | bgi = (bg >= 0 && bg < 8) | ||
| 885 | ? bg + 40 | ||
| 886 | : (bg >= 8 && bg < 16) | ||
| 887 | ? bg - 8 + 100 | ||
| 888 | : 0; | ||
| 889 | if (bgi) | ||
| 890 | SSPRINTF (seq, &n, sz, set_bg, bgi); | ||
| 891 | } | ||
| 892 | else if (tty->TN_max_colors == 256) | ||
| 893 | { | ||
| 894 | /* fg and bg are xterm indices. */ | ||
| 895 | if (fg >= 0 && fg < 256) | ||
| 896 | SSPRINTF (seq, &n, sz, set_fg, fg); | ||
| 897 | |||
| 898 | if (bg >= 0 && bg < 256) | ||
| 899 | SSPRINTF (seq, &n, sz, set_bg, bg); | ||
| 900 | } | ||
| 901 | else if (tty->TN_max_colors == 16777216) | ||
| 902 | { | ||
| 903 | /* fg and bg are pixel values -- decompose to rgb triples. */ | ||
| 904 | unsigned long rf = fg/65536, gf = (fg/256)&255, bf = fg&255; | ||
| 905 | unsigned long rb = bg/65536, gb = (bg/256)&255, bb = bg&255; | ||
| 906 | SSPRINTF (seq, &n, sz, set_fg, rf, gf, bf); | ||
| 907 | SSPRINTF (seq, &n, sz, set_bg, rb, gb, bb); | ||
| 908 | } | ||
| 909 | w32con_write_vt_seq ((const char *) seq); | ||
| 910 | } | ||
| 911 | |||
| 912 | static void | ||
| 913 | turn_off_face (struct frame *f, int face_id) | ||
| 914 | { | ||
| 915 | struct tty_display_info *tty = FRAME_TTY (f); | ||
| 916 | w32con_write_vt_seq (tty->TS_exit_attribute_mode); | ||
| 917 | } | ||
| 918 | |||
| 739 | /* The IME window is needed to receive the session notifications | 919 | /* The IME window is needed to receive the session notifications |
| 740 | required to reset the low level keyboard hook state. */ | 920 | required to reset the low level keyboard hook state. */ |
| 741 | 921 | ||
| @@ -868,6 +1048,8 @@ initialize_w32_display (struct terminal *term, int *width, int *height) | |||
| 868 | } | 1048 | } |
| 869 | 1049 | ||
| 870 | char_attr_normal = info.wAttributes; | 1050 | char_attr_normal = info.wAttributes; |
| 1051 | fg_normal = char_attr_normal & 0x000f; | ||
| 1052 | bg_normal = (char_attr_normal >> 4) & 0x000f; | ||
| 871 | 1053 | ||
| 872 | /* Determine if the info returned by GetConsoleScreenBufferInfo | 1054 | /* Determine if the info returned by GetConsoleScreenBufferInfo |
| 873 | is realistic. Old MS Telnet servers used to only fill out | 1055 | is realistic. Old MS Telnet servers used to only fill out |
| @@ -921,31 +1103,81 @@ initialize_w32_display (struct terminal *term, int *width, int *height) | |||
| 921 | 1103 | ||
| 922 | /* Set up the keyboard hook. */ | 1104 | /* Set up the keyboard hook. */ |
| 923 | setup_w32_kbdhook (hwnd); | 1105 | setup_w32_kbdhook (hwnd); |
| 1106 | |||
| 1107 | /* Set current_tty to the tty of this terminal */ | ||
| 1108 | current_tty = term->display_info.tty; | ||
| 924 | } | 1109 | } |
| 925 | 1110 | ||
| 926 | 1111 | ||
| 927 | DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0, | 1112 | DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 3, 0, |
| 928 | doc: /* Set screen foreground and background colors. | 1113 | doc: /* Set screen foreground and background colors. |
| 929 | 1114 | ||
| 930 | Arguments should be indices between 0 and 15, see w32console.el. */) | 1115 | Arguments should be indices for colors in the list returned by `tty-color-alist'. |
| 931 | (Lisp_Object foreground, Lisp_Object background) | 1116 | If VTP is non-nil, settings affect virtual terminal processing only. |
| 1117 | Otherwise, arguments should be between 0 and 15, and settings will | ||
| 1118 | be effective only when virtual terminal processing is disabled. | ||
| 1119 | |||
| 1120 | See w32console.el and the documentation for `w32-use-virtual-terminal'. */) | ||
| 1121 | (Lisp_Object foreground, Lisp_Object background, Lisp_Object vtp) | ||
| 932 | { | 1122 | { |
| 933 | char_attr_normal = XFIXNAT (foreground) + (XFIXNAT (background) << 4); | 1123 | int fg = XFIXNAT (foreground); |
| 1124 | int bg = XFIXNAT (background); | ||
| 1125 | |||
| 1126 | if (NILP (vtp)) | ||
| 1127 | { | ||
| 1128 | char_attr_normal = fg + (bg << 4); | ||
| 1129 | } | ||
| 1130 | else | ||
| 1131 | { | ||
| 1132 | fg_normal = fg; | ||
| 1133 | bg_normal = bg; | ||
| 1134 | } | ||
| 934 | 1135 | ||
| 935 | Frecenter (Qnil, Qt); | 1136 | Frecenter (Qnil, Qt); |
| 936 | return Qt; | 1137 | return Qt; |
| 937 | } | 1138 | } |
| 938 | 1139 | ||
| 939 | DEFUN ("get-screen-color", Fget_screen_color, Sget_screen_color, 0, 0, 0, | 1140 | DEFUN ("get-screen-color", Fget_screen_color, Sget_screen_color, 0, 1, 0, |
| 940 | doc: /* Get color indices of the current screen foreground and background. | 1141 | doc: /* Get color indices of the current screen foreground and background. |
| 941 | 1142 | ||
| 942 | The colors are returned as a list of 2 indices (FOREGROUND BACKGROUND). | 1143 | The colors are returned as a list of 2 indices (FOREGROUND BACKGROUND) for |
| 943 | See w32console.el and `tty-defined-color-alist' for mapping of indices | 1144 | colors in the list returned by `tty-color-alist`. |
| 944 | to colors. */) | 1145 | |
| 1146 | If VTP is non-nil, returns settings effective when virtual terminal | ||
| 1147 | processing is enabled. Otherwise, returns settings effective when | ||
| 1148 | virtual terminal processing is disabled. | ||
| 1149 | |||
| 1150 | See w32console.el and the documentation for `w32-use-virtual-terminal'. */) | ||
| 1151 | (Lisp_Object vtp) | ||
| 1152 | { | ||
| 1153 | int fg = NILP (vtp) ? char_attr_normal & 0x000f : fg_normal; | ||
| 1154 | int bg = NILP (vtp) ? (char_attr_normal >> 4) & 0x000f : bg_normal; | ||
| 1155 | |||
| 1156 | return Fcons (make_fixnum (fg), Fcons (make_fixnum (bg), Qnil)); | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | DEFUN ("w32-use-virtual-terminal", Fw32_use_virtual_terminal, Sw32_use_virtual_terminal, 1, 1, 0, | ||
| 1160 | doc: /* Enables (disables) virtual terminal sequence processing if argument is t (nil). */) | ||
| 1161 | (Lisp_Object arg) | ||
| 1162 | { | ||
| 1163 | if (EQ (arg, Qt)) | ||
| 1164 | w32_use_virtual_terminal = 1; | ||
| 1165 | else if (EQ (arg, Qnil)) | ||
| 1166 | w32_use_virtual_terminal = 0; | ||
| 1167 | else { | ||
| 1168 | error ("Invalid argument: expects t or nil."); | ||
| 1169 | return Qnil; | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | w32con_setup_virtual_terminal (); | ||
| 1173 | return Qt; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | DEFUN ("w32-use-virtual-terminal-p", Fw32_use_virtual_terminal_p, Sw32_use_virtual_terminal_p, 0, 0, 0, | ||
| 1177 | doc: /* Returns t (nil) if virtual terminal sequence processing is enabled (disabled). */) | ||
| 945 | (void) | 1178 | (void) |
| 946 | { | 1179 | { |
| 947 | return Fcons (make_fixnum (char_attr_normal & 0x000f), | 1180 | return w32_use_virtual_terminal ? Qt : Qnil; |
| 948 | Fcons (make_fixnum ((char_attr_normal >> 4) & 0x000f), Qnil)); | ||
| 949 | } | 1181 | } |
| 950 | 1182 | ||
| 951 | DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0, | 1183 | DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0, |
| @@ -974,5 +1206,7 @@ scroll-back buffer. */); | |||
| 974 | 1206 | ||
| 975 | defsubr (&Sset_screen_color); | 1207 | defsubr (&Sset_screen_color); |
| 976 | defsubr (&Sget_screen_color); | 1208 | defsubr (&Sget_screen_color); |
| 1209 | defsubr (&Sw32_use_virtual_terminal); | ||
| 1210 | defsubr (&Sw32_use_virtual_terminal_p); | ||
| 977 | defsubr (&Sset_cursor_size); | 1211 | defsubr (&Sset_cursor_size); |
| 978 | } | 1212 | } |
diff --git a/src/xdisp.c b/src/xdisp.c index 6f06206b43e..99474d7abdc 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -17387,7 +17387,7 @@ redisplay_internal (void) | |||
| 17387 | area, displaying a different frame means redisplay the | 17387 | area, displaying a different frame means redisplay the |
| 17388 | whole thing. */ | 17388 | whole thing. */ |
| 17389 | SET_FRAME_GARBAGED (sf); | 17389 | SET_FRAME_GARBAGED (sf); |
| 17390 | #if !defined DOS_NT && !defined HAVE_ANDROID | 17390 | #if !defined MSDOS && !defined HAVE_ANDROID |
| 17391 | set_tty_color_mode (FRAME_TTY (sf), sf); | 17391 | set_tty_color_mode (FRAME_TTY (sf), sf); |
| 17392 | #endif | 17392 | #endif |
| 17393 | } | 17393 | } |