Skip to content

Commit 901dfc2

Browse files
author
Jakub Horký
committed
lib/tty: Add true color support with ncurses and improve S-Lang color detection
Enable true color support in ncurses. TERM must be set to a relevant terminfo entry, i.e. *-direct, *-direct16, or *-direct256. When set to *-direct256, both 256-color and true color mode can be used at the same time. Also fix true color detection in S-Lang. S-Lang checks for RGB terminfo capability to enable true color, so we should check for it as well. This means the COLORTERM variable doesn't need to be set when using direct terminfo variants. This also applies to simultaneous 256-color and true color mode. We need to access the RGB extended capability. This is supported in both S-Lang and ncurses, so unify the terminfo access routines to enable it. Now they should be called with both terminfo and termcap capability name. Update FAQ. Resolves: #4137 Resolves: #4821 Signed-off-by: Jakub Horký <[email protected]>
1 parent e317851 commit 901dfc2

File tree

15 files changed

+197
-144
lines changed

15 files changed

+197
-144
lines changed

doc/FAQ

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -403,47 +403,51 @@ Frequently Asked Questions
403403
If you get colors, be happy.
404404

405405
If your terminal stays black and white, your terminal doesn't support
406-
color. You might want to upgrade to a terminal which compatible with
406+
color. You might want to upgrade to a terminal which is compatible with
407407
the ANSI color sequences.
408408

409409
If your terminal goes completely black, see the next question.
410410

411411
More detailed answer:
412412

413-
Check that your terminal supports color. color_xterm, rxvt and Linux
414-
console do support, most other terminals don't. You can test color
415-
support with following simple C program:
413+
Check that your terminal supports color. Most terminals do. You can
414+
test color support with the following command:
416415

417-
#include <stdio.h>
416+
printf "\033[32m Hello color world! \033[m\n"
418417

419-
int main (void){
420-
printf ("\033[32m Hello world! \033[m\n");
421-
return 0;
422-
}
418+
You can test 256 color support with the following command:
423419

424-
Compile and run it. If you see "Hello world!" text in green your
425-
terminal supports color, otherwise not (however, for color_xterm see
426-
also the next question).
420+
printf "\033[38;5;120m Hello 256-color world! \033[m\n"
427421

428-
Check whether you are using Ncurses or the S-Lang library (type
429-
"mc -V" to find out).
422+
You can test true color support with the following command:
430423

431-
With S-Lang library you can force color support by setting the
432-
environment variable COLORTERM to any value.
424+
printf "\033[38;2;0;200;0m Hello true color world! \033[m\n"
433425

434-
If you use ncurses library, check that your terminfo database
435-
supports color. If not, you should install one of the enhanced
436-
terminfo databases included in GNU Midnight Commander source
437-
distribution.
426+
If you see the text in green, your terminal supports the respective
427+
color mode.
438428

439-
You might want to set the TERM environment variable so that you are
440-
using the correct terminfo database or termcap entry.
429+
Check that you are using the proper TERM variable for your terminal.
430+
If not, set it accordingly. You can use the 'toe -a' command to list
431+
all available terminfo entries.
441432

442-
If you use color_xterm (or rxvt) the correct value might be
443-
xterm-color, xtermc or simply xterm.
433+
If your terminal supports 256 colors, the correct entry name may be
434+
appended with -256color. If your terminal supports true color, it
435+
should be appended with -direct, -direct16, or -direct256. The best
436+
backwards compatibility option is -direct256 variant, which provides
437+
both 256-color and true color support simultaneously. The -direct16
438+
variant supports bright versions of the basic colors along with true
439+
color support, in contrast to the -direct variant, which supports
440+
only basic 8 colors together with true color when used in a skin.
444441

445-
If you use Linux console the correct value for TERM is linux or
446-
console.
442+
If there is no 256-color or true-color terminfo variant for your
443+
terminal, even though your terminal supports it, send an e-mail to
444+
ncurses/terminfo maintainers ([email protected]) and ask them to
445+
add one.
446+
447+
With the S-Lang library (you can check by 'mc -V'), you can force
448+
color support by setting the environment variable COLORTERM to any
449+
value, and specifically force true color support by setting it to
450+
'truecolor'.
447451

448452
4.5 My color_xterm goes completely (or partially) black!
449453

lib/skin/common.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,10 @@ mc_skin_init (const gchar *skin_override, GError **mcerror)
164164
if (is_good_init && mc_skin__default.have_256_colors && !tty_use_256colors (&error))
165165
{
166166
mc_propagate_error (mcerror, 0,
167-
_ ("Unable to use '%s' skin with 256 colors support\non non-256 colors "
168-
"terminal.\nDefault skin has been loaded"),
169-
mc_skin__default.name);
167+
_ ("Unable to use '%s' skin with 256 colors support:\n%s\nDefault "
168+
"skin has been loaded"),
169+
mc_skin__default.name, error->message);
170+
g_error_free (error);
170171
mc_skin_try_to_load_default ();
171172
mc_skin_colors_old_configure (&mc_skin__default);
172173
(void) mc_skin_ini_file_parse (&mc_skin__default);

lib/tty/color-internal.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ parse_256_or_true_color_name (const char *color_name)
155155
i = (h[0] << 20) | (h[0] << 16) | (h[1] << 12) | (h[1] << 8) | (h[2] << 4) | h[2];
156156
else
157157
i = (h[0] << 20) | (h[1] << 16) | (h[2] << 12) | (h[3] << 8) | (h[4] << 4) | h[5];
158-
return (1 << 24) | i;
158+
return FLAG_TRUECOLOR | i;
159159
}
160160
}
161161

@@ -178,7 +178,7 @@ tty_color_get_name_by_index (int idx)
178178
return color_table[i].name;
179179

180180
// Create and return the strings in "colorNNN" or "#rrggbb" format.
181-
if ((idx >= 16 && idx < 256) || (idx & (1 << 24)) != 0)
181+
if ((idx >= 16 && idx < 256) || (idx & FLAG_TRUECOLOR) != 0)
182182
{
183183
char name[9];
184184

lib/tty/color-internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
/*** typedefs(not structures) and defined constants **********************************************/
2020

21+
#define FLAG_TRUECOLOR (1 << 24)
22+
#define COLORS_TRUECOLOR (1 << 24)
23+
2124
/*** enums ***************************************************************************************/
2225

2326
typedef enum

lib/tty/color-ncurses.c

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include "lib/global.h"
4040

41+
#include "tty.h"
4142
#include "tty-ncurses.h"
4243
#include "color.h" // variables
4344
#include "color-internal.h"
@@ -53,6 +54,7 @@
5354
/*** file scope variables ************************************************************************/
5455

5556
static GHashTable *mc_tty_color_color_pair_attrs = NULL;
57+
static int overlay_colors = 0;
5658

5759
/* --------------------------------------------------------------------------------------------- */
5860
/*** file scope functions ************************************************************************/
@@ -179,8 +181,9 @@ tty_color_try_alloc_lib_pair (tty_color_lib_pair_t *mc_color_pair)
179181
ibg = mc_color_pair->bg;
180182
attr = mc_color_pair->attr;
181183

182-
// In legacy color mode, change bright colors into bold
183-
if (!tty_use_256colors (NULL) && !tty_use_truecolors (NULL))
184+
// If we have 8 indexed colors only, change foreground bright colors into bold and
185+
// background bright colors to basic colors
186+
if (COLORS <= 8 || (tty_use_truecolors (NULL) && overlay_colors <= 8))
184187
{
185188
if (ifg >= 8 && ifg < 16)
186189
{
@@ -191,11 +194,31 @@ tty_color_try_alloc_lib_pair (tty_color_lib_pair_t *mc_color_pair)
191194
if (ibg >= 8 && ibg < 16)
192195
{
193196
ibg &= 0x07;
194-
// attr | = A_BOLD | A_REVERSE ;
195197
}
196198
}
197199

200+
// Shady trick: if we don't have the exact color, because it is overlaid by backwards
201+
// compatibility indexed values, just borrow one degree of red. The user won't notice :)
202+
if ((ifg & FLAG_TRUECOLOR) != 0)
203+
{
204+
ifg &= ~FLAG_TRUECOLOR;
205+
if (ifg != 0 && ifg <= overlay_colors)
206+
ifg += (1 << 16);
207+
}
208+
209+
if ((ibg & FLAG_TRUECOLOR) != 0)
210+
{
211+
ibg &= ~FLAG_TRUECOLOR;
212+
if (ibg != 0 && ibg <= overlay_colors)
213+
ibg += (1 << 16);
214+
}
215+
216+
#if NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) \
217+
&& defined(HAVE_NCURSES_WIDECHAR)
218+
init_extended_pair (mc_color_pair->pair_index, ifg, ibg);
219+
#else
198220
init_pair (mc_color_pair->pair_index, ifg, ibg);
221+
#endif
199222
mc_tty_color_save_attr (mc_color_pair->pair_index, attr);
200223
}
201224
}
@@ -231,17 +254,52 @@ tty_use_256colors (GError **error)
231254
{
232255
(void) error;
233256

234-
return (COLORS == 256);
257+
overlay_colors = tty_tigetnum ("CO", NULL);
258+
259+
if (COLORS != 256 && !(COLORS > 256 && overlay_colors == 256))
260+
{
261+
g_set_error (error, MC_ERROR, -1,
262+
_ ("\nIf your terminal supports 256 colors, you need to set your TERM\n"
263+
"environment variable to match your terminal, perhaps using\n"
264+
"a *-256color or *-direct256 variant. Use the 'toe -a'\n"
265+
"command to list all available variants on your system.\n"));
266+
return FALSE;
267+
}
268+
269+
return TRUE;
235270
}
236271

237272
/* --------------------------------------------------------------------------------------------- */
238273

239274
gboolean
240275
tty_use_truecolors (GError **error)
241276
{
242-
// Not yet supported in ncurses
243-
g_set_error (error, MC_ERROR, -1, _ ("True color not supported with ncurses."));
277+
// Low level true color is supported since ncurses 6.0 patch 20170401 preceding release
278+
// of ncurses 6.1. It needs ABI 6 or higher.
279+
#if !(NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS) \
280+
&& defined(NCURSES_EXT_FUNCS) && defined(HAVE_NCURSES_WIDECHAR))
281+
g_set_error (error, MC_ERROR, -1,
282+
_ ("For true color support, you need version 6.1 or later of the ncurses\n"
283+
"library with wide character and ABI 6 or higher support.\n"
284+
"Please upgrade your system.\n"));
244285
return FALSE;
286+
#else
287+
// We support only bool RGB cap configuration (8:8:8 bits), but the other variants are so rare
288+
// that we don't need to bother.
289+
if (!(tty_tigetflag ("RGB", NULL) && COLORS == COLORS_TRUECOLOR))
290+
{
291+
g_set_error (
292+
error, MC_ERROR, -1,
293+
_ ("\nIf your terminal supports true colors, you need to set your TERM\n"
294+
"environment variable to a *-direct256, *-direct16, or *-direct variant.\n"
295+
"Use the 'toe -a' command to list all available variants on your system.\n"));
296+
return FALSE;
297+
}
298+
299+
overlay_colors = tty_tigetnum ("CO", NULL);
300+
301+
return TRUE;
302+
#endif
245303
}
246304

247305
/* --------------------------------------------------------------------------------------------- */

lib/tty/color-slang.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "lib/global.h"
3939
#include "lib/util.h" // whitespace()
4040

41+
#include "tty.h"
4142
#include "tty-slang.h"
4243
#include "color.h" // variables
4344
#include "color-internal.h"
@@ -61,7 +62,10 @@ has_colors (gboolean disable, gboolean force)
6162
{
6263
mc_tty_color_disable = disable;
6364

64-
if (force || (getenv ("COLORTERM") != NULL))
65+
// S-Lang enables color if the setaf/setab/setf/setb terminfo capabilities are set or
66+
// the COLORTERM environment variable is set
67+
68+
if (force)
6569
SLtt_Use_Ansi_Colors = 1;
6670

6771
if (!mc_tty_color_disable)
@@ -215,12 +219,19 @@ gboolean
215219
tty_use_256colors (GError **error)
216220
{
217221
gboolean ret;
222+
int colors, overlay_colors;
223+
224+
colors = tty_tigetnum ("colors", "Co");
225+
overlay_colors = tty_tigetnum ("CO", NULL);
218226

219-
ret = (SLtt_Use_Ansi_Colors && SLtt_tgetnum ((char *) "Co") == 256);
227+
ret = (SLtt_Use_Ansi_Colors && (colors == 256 || (colors > 256 && overlay_colors == 256)));
220228

221229
if (!ret)
222230
g_set_error (error, MC_ERROR, -1,
223-
_ ("Your terminal doesn't even seem to support 256 colors."));
231+
_ ("\nIf your terminal supports 256 colors, you need to set your TERM\n"
232+
"environment variable to match your terminal, perhaps using\n"
233+
"a *-256color or *-direct256 variant. Use the 'toe -a'\n"
234+
"command to list all available variants on your system.\n"));
224235

225236
return ret;
226237
}
@@ -245,11 +256,15 @@ tty_use_truecolors (GError **error)
245256
/* Duplicate slang's check so that we can pop up an error message
246257
rather than silently use wrong colors. */
247258
colorterm = getenv ("COLORTERM");
248-
if (colorterm == NULL
249-
|| (strcmp (colorterm, "truecolor") != 0 && strcmp (colorterm, "24bit") != 0))
259+
if (!((tty_tigetflag ("RGB", NULL) && tty_tigetnum ("colors", "Co") == COLORS_TRUECOLOR)
260+
|| (colorterm != NULL
261+
&& (strcmp (colorterm, "truecolor") == 0 || strcmp (colorterm, "24bit") == 0))))
250262
{
251263
g_set_error (error, MC_ERROR, -1,
252-
_ ("Set COLORTERM=truecolor if your terminal really supports true colors."));
264+
_ ("\nIf your terminal supports true colors, you need to set your TERM\n"
265+
"environment variable to a *-direct256, *-direct16, or *-direct variant.\n"
266+
"Use the 'toe -a' command to list all available variants on your system.\n"
267+
"Alternatively, you can set COLORTERM=truecolor.\n"));
253268
return FALSE;
254269
}
255270

lib/tty/tty-ncurses.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -739,12 +739,26 @@ tty_printf (const char *fmt, ...)
739739

740740
/* --------------------------------------------------------------------------------------------- */
741741

742-
char *
743-
tty_tgetstr (const char *cap)
742+
int
743+
tty_tigetflag (const char *terminfo_cap, MC_UNUSED const char *termcap_cap)
744744
{
745-
char *unused = NULL;
745+
return tigetflag ((NCURSES_CONST char *) terminfo_cap);
746+
}
746747

747-
return tgetstr ((NCURSES_CONST char *) cap, &unused);
748+
/* --------------------------------------------------------------------------------------------- */
749+
750+
int
751+
tty_tigetnum (const char *terminfo_cap, MC_UNUSED const char *termcap_cap)
752+
{
753+
return tigetnum ((NCURSES_CONST char *) terminfo_cap);
754+
}
755+
756+
/* --------------------------------------------------------------------------------------------- */
757+
758+
char *
759+
tty_tigetstr (const char *terminfo_cap, MC_UNUSED const char *termcap_cap)
760+
{
761+
return tigetstr ((NCURSES_CONST char *) terminfo_cap);
748762
}
749763

750764
/* --------------------------------------------------------------------------------------------- */

lib/tty/tty-slang.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,10 +756,34 @@ tty_printf (const char *fmt, ...)
756756

757757
/* --------------------------------------------------------------------------------------------- */
758758

759+
/* Although S-Lang uses the terminfo database by default (through its own parser), it expects
760+
* termcap codes to access standard capabilities. Nevertheless, it can also access extended
761+
* terminfo capabilities (including those that have no termcap equivalent, i.e., whose names
762+
* are longer than two characters).
763+
*/
764+
765+
/* --------------------------------------------------------------------------------------------- */
766+
767+
int
768+
tty_tigetflag (const char *terminfo_cap, const char *termcap_cap)
769+
{
770+
return SLtt_tgetflag ((SLFUTURE_CONST char *) (termcap_cap ? termcap_cap : terminfo_cap));
771+
}
772+
773+
/* --------------------------------------------------------------------------------------------- */
774+
775+
int
776+
tty_tigetnum (const char *terminfo_cap, const char *termcap_cap)
777+
{
778+
return SLtt_tgetnum ((SLFUTURE_CONST char *) (termcap_cap ? termcap_cap : terminfo_cap));
779+
}
780+
781+
/* --------------------------------------------------------------------------------------------- */
782+
759783
char *
760-
tty_tgetstr (const char *cap)
784+
tty_tigetstr (const char *terminfo_cap, const char *termcap_cap)
761785
{
762-
return SLtt_tgetstr ((SLFUTURE_CONST char *) cap);
786+
return SLtt_tgetstr ((SLFUTURE_CONST char *) (termcap_cap ? termcap_cap : terminfo_cap));
763787
}
764788

765789
/* --------------------------------------------------------------------------------------------- */

lib/tty/tty.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -371,16 +371,9 @@ tty_init_xterm_support (gboolean is_xterm)
371371
// Check mouse and ca capabilities
372372
/* terminfo/termcap structures have been already initialized,
373373
in slang_init() or/and init_curses() */
374-
// Check terminfo at first, then check termcap
375-
xmouse_seq = tty_tgetstr ("kmous");
376-
if (xmouse_seq == NULL)
377-
xmouse_seq = tty_tgetstr ("Km");
378-
smcup = tty_tgetstr ("smcup");
379-
if (smcup == NULL)
380-
smcup = tty_tgetstr ("ti");
381-
rmcup = tty_tgetstr ("rmcup");
382-
if (rmcup == NULL)
383-
rmcup = tty_tgetstr ("te");
374+
xmouse_seq = tty_tigetstr ("kmous", "Km");
375+
smcup = tty_tigetstr ("smcup", "ti");
376+
rmcup = tty_tigetstr ("rmcup", "te");
384377

385378
if (strcmp (termvalue, "cygwin") == 0)
386379
{

lib/tty/tty.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ typedef enum
6363

6464
extern int mc_tty_frm[];
6565

66-
extern char *tty_tgetstr (const char *name);
66+
extern int tty_tigetflag (const char *terminfo_cap, const char *termcap_cap);
67+
extern int tty_tigetnum (const char *terminfo_cap, const char *termcap_cap);
68+
extern char *tty_tigetstr (const char *terminfo_cap, const char *termcap_cap);
6769

6870
/*** declarations of public functions ************************************************************/
6971

0 commit comments

Comments
 (0)