Manual pages: mcmcdiffmceditmcview

root/lib/tty/color-ncurses.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. mc_tty_color_attr_destroy_cb
  2. mc_tty_color_save_attr
  3. color_get_attr
  4. tty_color_init_lib
  5. tty_color_deinit_lib
  6. tty_color_try_alloc_lib_pair
  7. tty_setcolor
  8. tty_lowlevel_setcolor
  9. tty_set_normal_attrs
  10. tty_use_256colors
  11. tty_use_truecolors

   1 /*
   2    Color setup for NCurses screen library
   3 
   4    Copyright (C) 1994-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Andrew Borodin <aborodin@vmail.ru>, 2009
   9    Slava Zanko <slavazanko@gmail.com>, 2010
  10    Egmont Koblinger <egmont@gmail.com>, 2010
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file color-ncurses.c
  29  *  \brief Source: NCUrses-specific color setup
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <string.h>
  37 #include <sys/types.h>  // size_t
  38 
  39 #include "lib/global.h"
  40 
  41 #include "tty.h"
  42 #include "tty-ncurses.h"
  43 #include "color.h"  // variables
  44 #include "color-internal.h"
  45 
  46 /*** global variables ****************************************************************************/
  47 
  48 /*** file scope macro definitions ****************************************************************/
  49 
  50 /*** file scope type declarations ****************************************************************/
  51 
  52 /*** forward declarations (file scope functions) *************************************************/
  53 
  54 /*** file scope variables ************************************************************************/
  55 
  56 static GHashTable *mc_tty_color_color_pair_attrs = NULL;
  57 static int overlay_colors = 0;
  58 
  59 /* --------------------------------------------------------------------------------------------- */
  60 /*** file scope functions ************************************************************************/
  61 /* --------------------------------------------------------------------------------------------- */
  62 
  63 static inline void
  64 mc_tty_color_attr_destroy_cb (gpointer data)
     /* [previous][next][first][last][top][bottom][index][help]  */
  65 {
  66     g_free (data);
  67 }
  68 
  69 /* --------------------------------------------------------------------------------------------- */
  70 
  71 static void
  72 mc_tty_color_save_attr (int color_pair, int color_attr)
     /* [previous][next][first][last][top][bottom][index][help]  */
  73 {
  74     int *attr, *key;
  75 
  76     attr = g_try_new0 (int, 1);
  77     if (attr == NULL)
  78         return;
  79 
  80     key = g_try_new (int, 1);
  81     if (key == NULL)
  82     {
  83         g_free (attr);
  84         return;
  85     }
  86 
  87     *key = color_pair;
  88     *attr = color_attr;
  89 
  90     g_hash_table_replace (mc_tty_color_color_pair_attrs, (gpointer) key, (gpointer) attr);
  91 }
  92 
  93 /* --------------------------------------------------------------------------------------------- */
  94 
  95 static int
  96 color_get_attr (int color_pair)
     /* [previous][next][first][last][top][bottom][index][help]  */
  97 {
  98     int *fnd = NULL;
  99 
 100     if (mc_tty_color_color_pair_attrs != NULL)
 101         fnd = (int *) g_hash_table_lookup (mc_tty_color_color_pair_attrs, (gpointer) &color_pair);
 102     return (fnd != NULL) ? *fnd : 0;
 103 }
 104 
 105 /* --------------------------------------------------------------------------------------------- */
 106 /*** public functions ****************************************************************************/
 107 /* --------------------------------------------------------------------------------------------- */
 108 
 109 void
 110 tty_color_init_lib (gboolean disable, gboolean force)
     /* [previous][next][first][last][top][bottom][index][help]  */
 111 {
 112     (void) force;
 113 
 114     if (has_colors () && !disable)
 115     {
 116         use_colors = TRUE;
 117         start_color ();
 118         use_default_colors ();
 119 
 120         // Extended color mode detection routines must first be called before loading any skin
 121         tty_use_256colors (NULL);
 122         tty_use_truecolors (NULL);
 123     }
 124 
 125     mc_tty_color_color_pair_attrs = g_hash_table_new_full (
 126         g_int_hash, g_int_equal, mc_tty_color_attr_destroy_cb, mc_tty_color_attr_destroy_cb);
 127 }
 128 
 129 /* --------------------------------------------------------------------------------------------- */
 130 
 131 void
 132 tty_color_deinit_lib (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 133 {
 134     g_hash_table_destroy (mc_tty_color_color_pair_attrs);
 135     mc_tty_color_color_pair_attrs = NULL;
 136 }
 137 
 138 /* --------------------------------------------------------------------------------------------- */
 139 
 140 void
 141 tty_color_try_alloc_lib_pair (tty_color_lib_pair_t *mc_color_pair)
     /* [previous][next][first][last][top][bottom][index][help]  */
 142 {
 143     int ifg, ibg, attr;
 144 
 145     ifg = mc_color_pair->fg;
 146     ibg = mc_color_pair->bg;
 147     attr = mc_color_pair->attr;
 148 
 149     // If we have 8 indexed colors only, change foreground bright colors into bold and
 150     // background bright colors to basic colors
 151     if (COLORS <= 8 || (tty_use_truecolors (NULL) && overlay_colors <= 8))
 152     {
 153         if (ifg >= 8 && ifg < 16)
 154         {
 155             ifg &= 0x07;
 156             attr |= A_BOLD;
 157         }
 158 
 159         if (ibg >= 8 && ibg < 16)
 160         {
 161             ibg &= 0x07;
 162         }
 163     }
 164 
 165     // Shady trick: if we don't have the exact color, because it is overlaid by backwards
 166     // compatibility indexed values, just borrow one degree of red. The user won't notice :)
 167     if ((ifg & FLAG_TRUECOLOR) != 0)
 168     {
 169         ifg &= ~FLAG_TRUECOLOR;
 170         if (ifg != 0 && ifg <= overlay_colors)
 171             ifg += (1 << 16);
 172     }
 173 
 174     if ((ibg & FLAG_TRUECOLOR) != 0)
 175     {
 176         ibg &= ~FLAG_TRUECOLOR;
 177         if (ibg != 0 && ibg <= overlay_colors)
 178             ibg += (1 << 16);
 179     }
 180 
 181 #if NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) \
 182     && defined(HAVE_NCURSES_WIDECHAR)
 183     init_extended_pair (mc_color_pair->pair_index, ifg, ibg);
 184 #else
 185     init_pair (mc_color_pair->pair_index, ifg, ibg);
 186 #endif
 187     mc_tty_color_save_attr (mc_color_pair->pair_index, attr);
 188 }
 189 
 190 /* --------------------------------------------------------------------------------------------- */
 191 
 192 void
 193 tty_setcolor (int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 194 {
 195     attrset (COLOR_PAIR (color) | color_get_attr (color));
 196 }
 197 
 198 /* --------------------------------------------------------------------------------------------- */
 199 
 200 void
 201 tty_lowlevel_setcolor (int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 202 {
 203     tty_setcolor (color);
 204 }
 205 
 206 /* --------------------------------------------------------------------------------------------- */
 207 
 208 void
 209 tty_set_normal_attrs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 210 {
 211     standend ();
 212 }
 213 
 214 /* --------------------------------------------------------------------------------------------- */
 215 
 216 gboolean
 217 tty_use_256colors (GError **error)
     /* [previous][next][first][last][top][bottom][index][help]  */
 218 {
 219     (void) error;
 220 
 221     overlay_colors = tty_tigetnum ("CO", NULL);
 222 
 223     if (COLORS == 256 || (COLORS > 256 && overlay_colors == 256))
 224         return TRUE;
 225 
 226     if (tty_use_truecolors (NULL))
 227     {
 228         need_convert_256color = TRUE;
 229         return TRUE;
 230     }
 231 
 232     g_set_error (error, MC_ERROR, -1,
 233                  _ ("\nIf your terminal supports 256 colors, you need to set your TERM\n"
 234                     "environment variable to match your terminal, perhaps using\n"
 235                     "a *-256color or *-direct256 variant. Use the 'toe -a'\n"
 236                     "command to list all available variants on your system.\n"));
 237     return FALSE;
 238 }
 239 
 240 /* --------------------------------------------------------------------------------------------- */
 241 
 242 gboolean
 243 tty_use_truecolors (GError **error)
     /* [previous][next][first][last][top][bottom][index][help]  */
 244 {
 245     // Low level true color is supported since ncurses 6.0 patch 20170401 preceding release
 246     // of ncurses 6.1. It needs ABI 6 or higher.
 247 #if !(NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS)                             \
 248       && defined(NCURSES_EXT_FUNCS) && defined(HAVE_NCURSES_WIDECHAR))
 249     g_set_error (error, MC_ERROR, -1,
 250                  _ ("For true color support, you need version 6.1 or later of the ncurses\n"
 251                     "library with wide character and ABI 6 or higher support.\n"
 252                     "Please upgrade your system.\n"));
 253     return FALSE;
 254 #else
 255     // We support only bool RGB cap configuration (8:8:8 bits), but the other variants are so rare
 256     // that we don't need to bother.
 257     if (!(tty_tigetflag ("RGB", NULL) && COLORS == COLORS_TRUECOLOR))
 258     {
 259         g_set_error (
 260             error, MC_ERROR, -1,
 261             _ ("\nIf your terminal supports true colors, you need to set your TERM\n"
 262                "environment variable to a *-direct256, *-direct16, or *-direct variant.\n"
 263                "Use the 'toe -a' command to list all available variants on your system.\n"));
 264         return FALSE;
 265     }
 266 
 267     overlay_colors = tty_tigetnum ("CO", NULL);
 268 
 269     return TRUE;
 270 #endif
 271 }
 272 
 273 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */