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 /*** public functions ****************************************************************************/
105 /* --------------------------------------------------------------------------------------------- */
106
107 void
108 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)
*/
109 {
110 /* FIXME: if S-Lang is used, has_colors() must be called regardless
111 of whether we are interested in its result */
112 if (has_colors (disable, force) && !disable)
113 {
114 use_colors = TRUE;
115
116 // Extended color mode detection routines must first be called before loading any skin
117 tty_use_256colors (NULL);
118 tty_use_truecolors (NULL);
119 }
120 }
121
122 /* --------------------------------------------------------------------------------------------- */
123
124 void
125 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)
*/
126 {
127 }
128
129 /* --------------------------------------------------------------------------------------------- */
130
131 void
132 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)
*/
133 {
134 /*
135 * According to the S-Lang Library C Programmer's Guide (v2.3.0)
136 * (https://www.jedsoft.org/slang/doc/pdf/cslang.pdf), ยง7.4.4:
137 *
138 * "[for SLtt_set_color] When the SLtt_Use_Ansi_Colors variable is zero, all objects with
139 * numbers greater than one will be displayed in inverse video." Footnote: "This behavior can be
140 * modifed by using the SLtt_set_mono function call."
141 */
142 if (SLtt_Use_Ansi_Colors)
143 {
144 const char *fg, *bg;
145
146 fg = tty_color_get_name_by_index (mc_color_pair->fg);
147 bg = tty_color_get_name_by_index (mc_color_pair->bg);
148 SLtt_set_color (mc_color_pair->pair_index, (char *) "", (char *) fg, (char *) bg);
149 SLtt_add_color_attribute (mc_color_pair->pair_index, mc_color_pair->attr);
150 }
151 else
152 SLtt_set_mono (mc_color_pair->pair_index, NULL, mc_color_pair->attr);
153 }
154
155 /* --------------------------------------------------------------------------------------------- */
156
157 void
158 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)
*/
159 {
160 SLsmg_set_color (color);
161 }
162
163 /* --------------------------------------------------------------------------------------------- */
164 /**
165 * Set colorpair by index, don't interpret S-Lang "emulated attributes"
166 */
167
168 void
169 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)
*/
170 {
171 SLsmg_set_color (color & 0x7F);
172 }
173
174 /* --------------------------------------------------------------------------------------------- */
175
176 void
177 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)
*/
178 {
179 SLsmg_normal_video ();
180 }
181
182 /* --------------------------------------------------------------------------------------------- */
183
184 gboolean
185 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)
*/
186 {
187 int colors, overlay_colors;
188
189 colors = tty_tigetnum ("colors", "Co");
190 overlay_colors = tty_tigetnum ("CO", NULL);
191
192 if (SLtt_Use_Ansi_Colors && (colors == 256 || (colors > 256 && overlay_colors == 256)))
193 return TRUE;
194
195 if (tty_use_truecolors (NULL))
196 {
197 need_convert_256color = TRUE;
198 return TRUE;
199 }
200
201 g_set_error (error, MC_ERROR, -1,
202 _ ("\nIf your terminal supports 256 colors, you need to set your TERM\n"
203 "environment variable to match your terminal, perhaps using\n"
204 "a *-256color or *-direct256 variant. Use the 'toe -a'\n"
205 "command to list all available variants on your system.\n"));
206
207 return FALSE;
208 }
209
210 /* --------------------------------------------------------------------------------------------- */
211
212 gboolean
213 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)
*/
214 {
215 char *colorterm;
216
217 /* True color is supported since slang-2.3.1 on 64-bit machines,
218 and expected to be supported from slang-3 on 32-bit machines:
219 https://lists.jedsoft.org/lists/slang-users/2016/0000014.html
220 Check for sizeof (long) being 8, exactly as slang does. */
221 if (SLang_Version < 20301 || (sizeof (long) != 8 && SLang_Version < 30000))
222 {
223 g_set_error (error, MC_ERROR, -1, _ ("True color not supported in this slang version."));
224 return FALSE;
225 }
226
227 /* Duplicate slang's check so that we can pop up an error message
228 rather than silently use wrong colors. */
229 colorterm = getenv ("COLORTERM");
230 if (!((tty_tigetflag ("RGB", NULL) && tty_tigetnum ("colors", "Co") == COLORS_TRUECOLOR)
231 || (colorterm != NULL
232 && (strcmp (colorterm, "truecolor") == 0 || strcmp (colorterm, "24bit") == 0))))
233 {
234 g_set_error (error, MC_ERROR, -1,
235 _ ("\nIf your terminal supports true colors, you need to set your TERM\n"
236 "environment variable to a *-direct256, *-direct16, or *-direct variant.\n"
237 "Use the 'toe -a' command to list all available variants on your system.\n"
238 "Alternatively, you can set COLORTERM=truecolor.\n"));
239 return FALSE;
240 }
241
242 return TRUE;
243 }
244
245 /* --------------------------------------------------------------------------------------------- */