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. mc_tty_color_pair_init_special
  5. tty_color_init_lib
  6. tty_color_deinit_lib
  7. tty_color_try_alloc_lib_pair
  8. tty_setcolor
  9. tty_lowlevel_setcolor
  10. tty_set_normal_attrs
  11. tty_use_256colors
  12. 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 
 107 static void
 108 mc_tty_color_pair_init_special (tty_color_lib_pair_t *mc_color_pair, int fg1, int bg1, int fg2,
     /* [previous][next][first][last][top][bottom][index][help]  */
 109                                 int bg2, int attr)
 110 {
 111     if (has_colors () && !mc_tty_color_disable)
 112         init_pair (mc_color_pair->pair_index, fg1, bg1);
 113     else
 114         init_pair (mc_color_pair->pair_index, fg2, bg2);
 115     mc_tty_color_save_attr (mc_color_pair->pair_index, attr);
 116 }
 117 
 118 /* --------------------------------------------------------------------------------------------- */
 119 /*** public functions ****************************************************************************/
 120 /* --------------------------------------------------------------------------------------------- */
 121 
 122 void
 123 tty_color_init_lib (gboolean disable, gboolean force)
     /* [previous][next][first][last][top][bottom][index][help]  */
 124 {
 125     (void) force;
 126 
 127     if (has_colors () && !disable)
 128     {
 129         use_colors = TRUE;
 130         start_color ();
 131         use_default_colors ();
 132 
 133         // Extended color mode detection routines must first be called before loading any skin
 134         tty_use_256colors (NULL);
 135         tty_use_truecolors (NULL);
 136     }
 137 
 138     mc_tty_color_color_pair_attrs = g_hash_table_new_full (
 139         g_int_hash, g_int_equal, mc_tty_color_attr_destroy_cb, mc_tty_color_attr_destroy_cb);
 140 }
 141 
 142 /* --------------------------------------------------------------------------------------------- */
 143 
 144 void
 145 tty_color_deinit_lib (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 146 {
 147     g_hash_table_destroy (mc_tty_color_color_pair_attrs);
 148     mc_tty_color_color_pair_attrs = NULL;
 149 }
 150 
 151 /* --------------------------------------------------------------------------------------------- */
 152 
 153 void
 154 tty_color_try_alloc_lib_pair (tty_color_lib_pair_t *mc_color_pair)
     /* [previous][next][first][last][top][bottom][index][help]  */
 155 {
 156     if (mc_color_pair->fg <= (int) SPEC_A_REVERSE)
 157     {
 158         switch (mc_color_pair->fg)
 159         {
 160         case SPEC_A_REVERSE:
 161             mc_tty_color_pair_init_special (mc_color_pair, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK,
 162                                             COLOR_WHITE | A_BOLD, A_REVERSE);
 163             break;
 164         case SPEC_A_BOLD:
 165             mc_tty_color_pair_init_special (mc_color_pair, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE,
 166                                             COLOR_BLACK, A_BOLD);
 167             break;
 168         case SPEC_A_BOLD_REVERSE:
 169             mc_tty_color_pair_init_special (mc_color_pair, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
 170                                             COLOR_WHITE, A_BOLD | A_REVERSE);
 171             break;
 172         case SPEC_A_UNDERLINE:
 173             mc_tty_color_pair_init_special (mc_color_pair, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE,
 174                                             COLOR_BLACK, A_UNDERLINE);
 175             break;
 176         default:
 177             break;
 178         }
 179     }
 180     else
 181     {
 182         int ifg, ibg, attr;
 183 
 184         ifg = mc_color_pair->fg;
 185         ibg = mc_color_pair->bg;
 186         attr = mc_color_pair->attr;
 187 
 188         // If we have 8 indexed colors only, change foreground bright colors into bold and
 189         // background bright colors to basic colors
 190         if (COLORS <= 8 || (tty_use_truecolors (NULL) && overlay_colors <= 8))
 191         {
 192             if (ifg >= 8 && ifg < 16)
 193             {
 194                 ifg &= 0x07;
 195                 attr |= A_BOLD;
 196             }
 197 
 198             if (ibg >= 8 && ibg < 16)
 199             {
 200                 ibg &= 0x07;
 201             }
 202         }
 203 
 204         // Shady trick: if we don't have the exact color, because it is overlaid by backwards
 205         // compatibility indexed values, just borrow one degree of red. The user won't notice :)
 206         if ((ifg & FLAG_TRUECOLOR) != 0)
 207         {
 208             ifg &= ~FLAG_TRUECOLOR;
 209             if (ifg != 0 && ifg <= overlay_colors)
 210                 ifg += (1 << 16);
 211         }
 212 
 213         if ((ibg & FLAG_TRUECOLOR) != 0)
 214         {
 215             ibg &= ~FLAG_TRUECOLOR;
 216             if (ibg != 0 && ibg <= overlay_colors)
 217                 ibg += (1 << 16);
 218         }
 219 
 220 #if NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) \
 221     && defined(HAVE_NCURSES_WIDECHAR)
 222         init_extended_pair (mc_color_pair->pair_index, ifg, ibg);
 223 #else
 224         init_pair (mc_color_pair->pair_index, ifg, ibg);
 225 #endif
 226         mc_tty_color_save_attr (mc_color_pair->pair_index, attr);
 227     }
 228 }
 229 
 230 /* --------------------------------------------------------------------------------------------- */
 231 
 232 void
 233 tty_setcolor (int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 234 {
 235     attrset (COLOR_PAIR (color) | color_get_attr (color));
 236 }
 237 
 238 /* --------------------------------------------------------------------------------------------- */
 239 
 240 void
 241 tty_lowlevel_setcolor (int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 242 {
 243     tty_setcolor (color);
 244 }
 245 
 246 /* --------------------------------------------------------------------------------------------- */
 247 
 248 void
 249 tty_set_normal_attrs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 250 {
 251     standend ();
 252 }
 253 
 254 /* --------------------------------------------------------------------------------------------- */
 255 
 256 gboolean
 257 tty_use_256colors (GError **error)
     /* [previous][next][first][last][top][bottom][index][help]  */
 258 {
 259     (void) error;
 260 
 261     overlay_colors = tty_tigetnum ("CO", NULL);
 262 
 263     if (COLORS == 256 || (COLORS > 256 && overlay_colors == 256))
 264         return TRUE;
 265 
 266     if (tty_use_truecolors (NULL))
 267     {
 268         need_convert_256color = TRUE;
 269         return TRUE;
 270     }
 271 
 272     g_set_error (error, MC_ERROR, -1,
 273                  _ ("\nIf your terminal supports 256 colors, you need to set your TERM\n"
 274                     "environment variable to match your terminal, perhaps using\n"
 275                     "a *-256color or *-direct256 variant. Use the 'toe -a'\n"
 276                     "command to list all available variants on your system.\n"));
 277     return FALSE;
 278 }
 279 
 280 /* --------------------------------------------------------------------------------------------- */
 281 
 282 gboolean
 283 tty_use_truecolors (GError **error)
     /* [previous][next][first][last][top][bottom][index][help]  */
 284 {
 285     // Low level true color is supported since ncurses 6.0 patch 20170401 preceding release
 286     // of ncurses 6.1. It needs ABI 6 or higher.
 287 #if !(NCURSES_VERSION_PATCH >= 20170401 && defined(NCURSES_EXT_COLORS)                             \
 288       && defined(NCURSES_EXT_FUNCS) && defined(HAVE_NCURSES_WIDECHAR))
 289     g_set_error (error, MC_ERROR, -1,
 290                  _ ("For true color support, you need version 6.1 or later of the ncurses\n"
 291                     "library with wide character and ABI 6 or higher support.\n"
 292                     "Please upgrade your system.\n"));
 293     return FALSE;
 294 #else
 295     // We support only bool RGB cap configuration (8:8:8 bits), but the other variants are so rare
 296     // that we don't need to bother.
 297     if (!(tty_tigetflag ("RGB", NULL) && COLORS == COLORS_TRUECOLOR))
 298     {
 299         g_set_error (
 300             error, MC_ERROR, -1,
 301             _ ("\nIf your terminal supports true colors, you need to set your TERM\n"
 302                "environment variable to a *-direct256, *-direct16, or *-direct variant.\n"
 303                "Use the 'toe -a' command to list all available variants on your system.\n"));
 304         return FALSE;
 305     }
 306 
 307     overlay_colors = tty_tigetnum ("CO", NULL);
 308 
 309     return TRUE;
 310 #endif
 311 }
 312 
 313 /* --------------------------------------------------------------------------------------------- */

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