Search code examples
cterminalcolorsncursesxterm

How to not change the colors in other terminal programs?


I found an old game I wrote using ncurses. I noticed that after closing the game and running another ncurses based program, the colours had changed for that program as well. This is entirely expected behaviour that I wasn't aware of when I wrote the game several years ago.

Since ncurses doesn't know the initial palette, there is no way to reset the palette to its initial values after quitting the game. With this in mind, what is the best way to deal with colours in ncurses?

Here's what I've considered:

  1. Only override colours that are higher up in the palette. If you start changing colours from position 0, it's very likely that you will change colours that other programs are using. If you start at 100 (for instance), it's much less likely that your changes will interfere with another program. I suppose not changing the 16 colour ANSI palette is the key here.
  2. Manually inspect the default palette and choose default colours that fit the game. Besides being cumbersome and perhaps not letting you set the exact colour you want, there is no guarantee that the default palette will be the same on all systems. There might be a library to automatically get the corresponding xterm colour. It seems like https://github.com/vim-scripts/CSApprox is doing something like that. I would assume that most modern systems will run terminals with the same palette, so it might be fine, depending on what systems you are targeting. The default palette of xterm is available here: https://jonasjacek.github.io/colors/
  3. Use color_content to get the original colour. I tried it and it didn't work. ncurses can only get the colour content of colours that were set by init_color.
  4. Restore the palette to the default xterm palette. I suppose if the terminal supports 256 colours, there's a good chance that it is using the default xterm palette. However, the user might have changed it, so it might still interfere with the users configuration.
  5. Use API specific to xterm or other terminal emulator for getting colours. I don't know if any such API exists, but it would be a potential solution, with the major drawback that it will only support that specific terminal emulator.

I might implement both 1 and 2, and let the user choose the behaviour by passing a flag. I don't know of any terminal programs that use rich colours, so not sure how many programs out there actually face this problem, but there's bound to be at least a few. If you have any examples of how other programs deal with this, that would be very helpful.


Solution

  • From https://invisible-island.net/ncurses/ncurses.faq.html:

    If your terminal description does not contain the orig_pair or orig_colors capability, you will be unable to reset colors to the pre-curses state. This happens, for example, with aixterm.

    However, if your terminal does support resetting colors to a default state, ncurses will use this when exiting Curses mode. Terminal types that do this include the Linux console, rxvt and the XFree86 xterm.

    To find out if your terminal can reset the colors, run:

    infocmp -L | grep orig
    

    Mine can only reset pairs and not colors. I haven't found an API to check this from the program itself, but there's no real reason to check it unless you've implemented multiple ways of dealing with colors. I have, by the way, and I'm not happy with either.

    I tried overriding colors higher up in the palette and I still managed to change colors for other programs. I still think it's sensible to avoid the 16 first colors, but it seems like there are no colors that you can safely change.

    I also tried using the default colors from https://jonasjacek.github.io/colors/, but I couldn't get the effect I wanted. I could probably simplify the theme and still make it look nice, but I couldn't replicate the look I was going for.

    It seems like the best solution is to make a nice looking theme with the default colors, unless that isn't possible, in which case you will just have to accept that other programs might not look great as a result. It's not too difficult to open a new terminal anyway, and that will get your colors sorted again.