terminal: GetConsoleScreenBufferInfoEx doesn't return the actual palette

Windows Terminal version (or Windows build number)

1.9.1523.0

Other Software

No response

Steps to reproduce

  1. Compile the following code:
#include <iomanip>
#include <iostream>

#include <windows.h>


int main()
{
	CONSOLE_SCREEN_BUFFER_INFOEX Info{ sizeof(Info) };
	if (!GetConsoleScreenBufferInfoEx(GetStdHandle(STD_OUTPUT_HANDLE), &Info))
		return 1;

	for (const auto& i: Info.ColorTable)
	{
		std::cout << std::hex << std::setw(8) << std::setfill('0') << i << '\n';
	}

	std::cout.flush();
}

  1. Set WT palette to “Vintage” in settings
  2. Run the compiled code

Expected Behavior

The same colour codes as in the corresponding section of C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview_1.9.1523.0_x64__8wekyb3d8bbwe\defaults.json:

000000
800000
008000
808000
000080
800080
008080
C0C0C0
808080
FF0000
00FF00
FFFF00
0000FF
FF00FF
00FFFF
FFFFFF

Actual Behavior

It looks like the default Windows 10 palette is returned instead:

000c0c0c
00da3700
000ea113
00dd963a
001f0fc5
00981788
00009cc1
00cccccc
00767676
00ff783b
000cc616
00d6d661
005648e7
009e00b4
00a5f1f9
00f2f2f2

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Comments: 17 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I think one of the proposals was to trigger SIGWINCH whenever the color changes […]

That was my proposal / patch you came across 😃

Here’s the link for reference: https://gitlab.gnome.org/GNOME/vte/-/issues/2740

(For thread tending purposes, I moved the byte swapping discussion over to #16795)

My understanding is that conpty is designed to work in a similar fashion to the Linux pty system, so a Linux terminal could theoretically be ported to Windows without too much effort. I don’t know all the details, but I think there’s an input stream, an output stream, and a signal stream, and it’s the latter that is responsible for notifying conhost of window size changes, similar to the SIGWINCH signal on Linux

There isn’t an equivalent signal for palette changes (as far as I’m aware), so that would be something we’d have to invent. Whereas conhost querying the palette from the conpty client just relies on standard escape sequences that a lot of terminals should already support out of the box. That’s why I was considering a query as my initial approach to the problem.

But as you’re both proposing, having the conpty client notify conhost of palette changes does seem like a much better idea. And if some don’t support it, they’d be no worse off than they are now. I’m not very familiar with this part of the code, so there may be technical reasons why this isn’t feasible, but if the core devs don’t raise any objections, I’d be willing to give it a try some time.

@j4james @zadjii-msft Here are some brainstorming thoughts. Maybe some of them will be viable, or maybe some of them with spark further ideas.

conhost (which handles GCSBIE) doesn’t know what the terminal’s colors are. To find that out, it would need to send an escape sequence to the connected conpty client, and then block while it waits for a response, which isn’t great for performance.

What if conhost didn’t need to wait?

  • What if the conpty client could notify conhost when the colors are set? (Not a requirement for conpty clients, but an option for them.)
    • Maybe a notification could provide the specific colors, so GCSBIE doesn’t need to query the colors.
    • Maybe a notification could simply indicate that the colors changed, so the next GCSBIE knows to query the colors.
    • What if a named event were the notification mechanism? Then it’s optional and simple.
  • What if conhost could make async queries to update its knowledge?
    • A given GCSBIE call wouldn’t necessarily return perfectly up-to-date color state, but that can be considered as a race condition – it’s always possible a user or app could change the colors right after a GCSBIE call anyway.

This is problematic, because some applications call GCSBIE a lot. Imagine a number that you think is a ridiculous amount, and it’s likely more than that.

Yes, GCSBIE can get called a ton. What if the work weren’t done every time?

  • What if GCSBIE only queried colors from conpty at most once per N seconds?
  • What if GCSBIE cached the results of a previous query, and used the cached results until the next time it makes a successful query?
  • What if the query mechanism could be asynchronous such that GCSBIE initiated a query but continued without waiting for the result? The result could get updated asynchronously, and would become available soon for a subsequent GCSBIE.

And to further complicate the matter, there’s no guarantee that the connected conpty client even supports palette queries.

Do you mean that there is a single two-way channel of communication, i.e. all data communication must be through input and output streams, so the two sides can only communicate by passing escape codes to each other? And so if one side doesn’t support responding to a query sequence then the other side can hang?

  • What if there were a way to know in advance whether the other side supported a particular query sequence?
    • What if there were a handshake? What if conpty clients could optionally send conhost their capabilities when they first connect? Maybe as a payload of some kind in an escape code.
  • What if another communication channel could be used optionally? Maybe not as a strict requirement on all conpty clients, but as an option.

I did play around with querying the palette once at startup, but that still introduces the complexity of having to wait for a response which may never arrive. An easier version of that would be to have the client pass in the palette via the initial command line. But both of those solutions fall apart if a user updates their palette settings at run-time.

I agree that supporting palette changes at runtime should be considered a requirement for any solution. Making runtime palette changes instantly be noticed is not necessarily a requirement, though.

So while I would love to get this working somehow, I just don’t see how. But if anyone has any bright ideas, feel free to share them here.

I’m not suggesting it would be trivial to implement, nor that it should be perfect with no caveats. But this is currently a pretty significant regression from the perspective of console mode programs.

To find that out, it would need to send an escape sequence to the connected conpty client, and then block while it waits for a response

Why? I have a very basic idea of how all this is organised, but this sounds unnecessarily inverted. Why can’t conhost return its internal local array, exactly as it does currently, but update that array whenever the connected conpty client updates its palette? There should be some notification mechanism. After all, you somehow do know client’s window and buffer dimensions, and I don’t think they are queried every time in a blocking way.


Our usage of this API is mostly related to colours mixing, e.g. transparency and shadows. To properly mix index colours we have to know to which exactly RGB values they are mapped.