1 /*
2 Color setup for S_Lang 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 Egmont Koblinger <egmont@gmail.com>, 2010
10
11 This file is part of the Midnight Commander.
12
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
17
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <https://www.gnu.org/licenses/>.
25 */
26
27 /** \file color-slang.c
28 * \brief Source: S-Lang-specific color setup
29 */
30
31 #include <config.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h> // size_t
37
38 #include "lib/global.h"
39 #include "lib/util.h" // whitespace()
40
41 #include "tty.h"
42 #include "tty-slang.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 /* --------------------------------------------------------------------------------------------- */
57 /*** file scope functions ************************************************************************/
58 /* --------------------------------------------------------------------------------------------- */
59
60 static int
61 has_colors (gboolean disable, gboolean force)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
62 {
63 mc_tty_color_disable = disable;
64
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)
69 SLtt_Use_Ansi_Colors = 1;
70
71 if (!mc_tty_color_disable)
72 {
73 const char *terminal = getenv ("TERM");
74 const size_t len = strlen (terminal);
75 char *cts = mc_global.tty.color_terminal_string;
76
77 // check mc_global.tty.color_terminal_string
78 while (*cts != '\0')
79 {
80 char *s;
81 size_t i = 0;
82
83 while (whitespace (*cts))
84 cts++;
85 s = cts;
86
87 while (*cts != '\0' && *cts != ',')
88 {
89 cts++;
90 i++;
91 }
92
93 if ((i != 0) && (i == len) && (strncmp (s, terminal, i) == 0))
94 SLtt_Use_Ansi_Colors = 1;
95
96 if (*cts == ',')
97 cts++;
98 }
99 }
100 return SLtt_Use_Ansi_Colors;
101 }
102
103 /* --------------------------------------------------------------------------------------------- */
104
105 static void
106 mc_tty_color_pair_init_special (tty_color_lib_pair_t *mc_color_pair, const char *fg1,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
107 const char *bg1, const char *fg2, const char *bg2,
108 SLtt_Char_Type mask)
109 {
110 if (SLtt_Use_Ansi_Colors != 0)
111 {
112 if (!mc_tty_color_disable)
113 {
114 SLtt_set_color (mc_color_pair->pair_index, (char *) "", (char *) fg1, (char *) bg1);
115 }
116 else
117 {
118 SLtt_set_color (mc_color_pair->pair_index, (char *) "", (char *) fg2, (char *) bg2);
119 }
120 }
121 else
122 {
123 SLtt_set_mono (mc_color_pair->pair_index, NULL, mask);
124 }
125 }
126
127 /* --------------------------------------------------------------------------------------------- */
128 /*** public functions ****************************************************************************/
129 /* --------------------------------------------------------------------------------------------- */
130
131 void
132 tty_color_init_lib (gboolean disable, gboolean force)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
133 {
134 /* FIXME: if S-Lang is used, has_colors() must be called regardless
135 of whether we are interested in its result */
136 if (has_colors (disable, force) && !disable)
137 {
138 use_colors = TRUE;
139
140 // Extended color mode detection routines must first be called before loading any skin
141 tty_use_256colors (NULL);
142 tty_use_truecolors (NULL);
143 }
144 }
145
146 /* --------------------------------------------------------------------------------------------- */
147
148 void
149 tty_color_deinit_lib (void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
150 {
151 }
152
153 /* --------------------------------------------------------------------------------------------- */
154
155 void
156 tty_color_try_alloc_lib_pair (tty_color_lib_pair_t *mc_color_pair)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
157 {
158 if (mc_color_pair->fg <= (int) SPEC_A_REVERSE)
159 {
160 switch (mc_color_pair->fg)
161 {
162 case SPEC_A_REVERSE:
163 mc_tty_color_pair_init_special (mc_color_pair, "black", "white", "black", "lightgray",
164 SLTT_REV_MASK);
165 break;
166 case SPEC_A_BOLD:
167 mc_tty_color_pair_init_special (mc_color_pair, "white", "black", "white", "black",
168 SLTT_BOLD_MASK);
169 break;
170 case SPEC_A_BOLD_REVERSE:
171 mc_tty_color_pair_init_special (mc_color_pair, "white", "white", "white", "white",
172 SLTT_BOLD_MASK | SLTT_REV_MASK);
173 break;
174 case SPEC_A_UNDERLINE:
175 mc_tty_color_pair_init_special (mc_color_pair, "white", "black", "white", "black",
176 SLTT_ULINE_MASK);
177 break;
178 default:
179 break;
180 }
181 }
182 else
183 {
184 const char *fg, *bg;
185
186 fg = tty_color_get_name_by_index (mc_color_pair->fg);
187 bg = tty_color_get_name_by_index (mc_color_pair->bg);
188 SLtt_set_color (mc_color_pair->pair_index, (char *) "", (char *) fg, (char *) bg);
189 SLtt_add_color_attribute (mc_color_pair->pair_index, mc_color_pair->attr);
190 }
191 }
192
193 /* --------------------------------------------------------------------------------------------- */
194
195 void
196 tty_setcolor (int color)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
197 {
198 SLsmg_set_color (color);
199 }
200
201 /* --------------------------------------------------------------------------------------------- */
202 /**
203 * Set colorpair by index, don't interpret S-Lang "emulated attributes"
204 */
205
206 void
207 tty_lowlevel_setcolor (int color)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
208 {
209 SLsmg_set_color (color & 0x7F);
210 }
211
212 /* --------------------------------------------------------------------------------------------- */
213
214 void
215 tty_set_normal_attrs (void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
216 {
217 SLsmg_normal_video ();
218 }
219
220 /* --------------------------------------------------------------------------------------------- */
221
222 gboolean
223 tty_use_256colors (GError **error)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
224 {
225 int colors, overlay_colors;
226
227 colors = tty_tigetnum ("colors", "Co");
228 overlay_colors = tty_tigetnum ("CO", NULL);
229
230 if (SLtt_Use_Ansi_Colors && (colors == 256 || (colors > 256 && overlay_colors == 256)))
231 return TRUE;
232
233 if (tty_use_truecolors (NULL))
234 {
235 need_convert_256color = TRUE;
236 return TRUE;
237 }
238
239 g_set_error (error, MC_ERROR, -1,
240 _ ("\nIf your terminal supports 256 colors, you need to set your TERM\n"
241 "environment variable to match your terminal, perhaps using\n"
242 "a *-256color or *-direct256 variant. Use the 'toe -a'\n"
243 "command to list all available variants on your system.\n"));
244
245 return FALSE;
246 }
247
248 /* --------------------------------------------------------------------------------------------- */
249
250 gboolean
251 tty_use_truecolors (GError **error)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
252 {
253 char *colorterm;
254
255 /* True color is supported since slang-2.3.1 on 64-bit machines,
256 and expected to be supported from slang-3 on 32-bit machines:
257 https://lists.jedsoft.org/lists/slang-users/2016/0000014.html
258 Check for sizeof (long) being 8, exactly as slang does. */
259 if (SLang_Version < 20301 || (sizeof (long) != 8 && SLang_Version < 30000))
260 {
261 g_set_error (error, MC_ERROR, -1, _ ("True color not supported in this slang version."));
262 return FALSE;
263 }
264
265 /* Duplicate slang's check so that we can pop up an error message
266 rather than silently use wrong colors. */
267 colorterm = getenv ("COLORTERM");
268 if (!((tty_tigetflag ("RGB", NULL) && tty_tigetnum ("colors", "Co") == COLORS_TRUECOLOR)
269 || (colorterm != NULL
270 && (strcmp (colorterm, "truecolor") == 0 || strcmp (colorterm, "24bit") == 0))))
271 {
272 g_set_error (error, MC_ERROR, -1,
273 _ ("\nIf your terminal supports true colors, you need to set your TERM\n"
274 "environment variable to a *-direct256, *-direct16, or *-direct variant.\n"
275 "Use the 'toe -a' command to list all available variants on your system.\n"
276 "Alternatively, you can set COLORTERM=truecolor.\n"));
277 return FALSE;
278 }
279
280 return TRUE;
281 }
282
283 /* --------------------------------------------------------------------------------------------- */