5 Copyright (C) 2009-2023
6 Free Software Foundation, Inc.
9 Slava Zanko <slavazanko@gmail.com>, 2009
10 Egmont Koblinger <egmont@gmail.com>, 2010
11 Andrew Borodin <aborodin@vmail.ru>, 2012
13 This file is part of the Midnight Commander.
15 The Midnight Commander is free software: you can redistribute it
16 and/or modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation, either version 3 of the License,
18 or (at your option) any later version.
20 The Midnight Commander is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #include "lib/tty/color.h"
36 /*** global variables ****************************************************************************/
38 int mc_skin_color__cache
[MC_SKIN_COLOR_CACHE_COUNT
];
40 /*** file scope macro definitions ****************************************************************/
42 /*** file scope type declarations ****************************************************************/
44 /*** forward declarations (file scope functions) *************************************************/
46 /*** file scope variables ************************************************************************/
48 /* --------------------------------------------------------------------------------------------- */
49 /*** file scope functions ************************************************************************/
50 /* --------------------------------------------------------------------------------------------- */
52 static tty_color_pair_t
*
53 mc_skin_color_get_from_hash (mc_skin_t
* mc_skin
, const gchar
* group
, const gchar
* key
)
55 gchar kname
[BUF_TINY
];
56 tty_color_pair_t
*mc_skin_color
;
58 if (group
== NULL
|| key
== NULL
)
62 mc_skin
= &mc_skin__default
;
64 g_snprintf (kname
, sizeof (kname
), "%s.%s", group
, key
);
65 mc_skin_color
= (tty_color_pair_t
*) g_hash_table_lookup (mc_skin
->colors
, (gpointer
) kname
);
70 /* --------------------------------------------------------------------------------------------- */
74 mc_skin_color_remove_from_hash (mc_skin_t
* mc_skin
, const gchar
* group
, const gchar
* key
)
76 gchar kname
[BUF_TINY
];
77 if (group
== NULL
|| key
== NULL
)
81 mc_skin
= &mc_skin__default
;
83 g_snprintf (kname
, sizeof (kname
), "%s.%s", group
, key
);
84 g_hash_table_remove (mc_skin
->colors
, (gpointer
) kname
);
88 /* --------------------------------------------------------------------------------------------- */
91 mc_skin_color_add_to_hash (mc_skin_t
* mc_skin
, const gchar
* group
, const gchar
* key
,
92 tty_color_pair_t
* mc_skin_color
)
96 kname
= g_strdup_printf ("%s.%s", group
, key
);
99 if (g_hash_table_lookup (mc_skin
->colors
, (gpointer
) kname
) != NULL
)
100 g_hash_table_remove (mc_skin
->colors
, (gpointer
) kname
);
102 g_hash_table_insert (mc_skin
->colors
, (gpointer
) kname
, (gpointer
) mc_skin_color
);
106 /* --------------------------------------------------------------------------------------------- */
108 static tty_color_pair_t
*
109 mc_skin_color_get_with_defaults (const gchar
* group
, const gchar
* name
)
111 tty_color_pair_t
*mc_skin_color
;
113 mc_skin_color
= mc_skin_color_get_from_hash (NULL
, group
, name
);
114 if (mc_skin_color
!= NULL
)
115 return mc_skin_color
;
117 mc_skin_color
= mc_skin_color_get_from_hash (NULL
, group
, "_default_");
118 if (mc_skin_color
!= NULL
)
119 return mc_skin_color
;
121 mc_skin_color
= mc_skin_color_get_from_hash (NULL
, "core", "_default_");
122 return mc_skin_color
;
125 /* --------------------------------------------------------------------------------------------- */
127 /* If an alias is found, alloc a new string for the resolved value and free the input parameter.
128 Otherwise it's a no-op returning the original string. */
130 mc_skin_color_look_up_alias (mc_skin_t
* mc_skin
, gchar
* str
)
135 orig
= g_strdup (str
);
136 str2
= g_strdup (str
);
143 values
= mc_config_get_string_list (mc_skin
->config
, "aliases", str
, &items_count
);
144 if (items_count
!= 1)
146 /* No such alias declaration found, that is, we've got the resolved value. */
154 str
= g_strdup (values
[0]);
157 /* str2 resolves at half speed than str. This is used for loop detection. */
160 values
= mc_config_get_string_list (mc_skin
->config
, "aliases", str2
, &items_count
);
161 g_assert (items_count
== 1);
163 str2
= g_strdup (values
[0]);
166 if (strcmp (str
, str2
) == 0)
170 "Loop detected while trying to resolve alias \"%s\" in skin \"%s\"\n",
171 orig
, mc_skin
->name
);
180 /* --------------------------------------------------------------------------------------------- */
182 static tty_color_pair_t
*
183 mc_skin_color_get_from_ini_file (mc_skin_t
* mc_skin
, const gchar
* group
, const gchar
* key
)
187 tty_color_pair_t
*mc_skin_color
, *tmp
;
189 values
= mc_config_get_string_list (mc_skin
->config
, group
, key
, &items_count
);
190 if (values
== NULL
|| values
[0] == NULL
)
196 mc_skin_color
= g_try_new0 (tty_color_pair_t
, 1);
197 if (mc_skin_color
== NULL
)
203 tmp
= mc_skin_color_get_with_defaults (group
, "_default_");
204 mc_skin_color
->fg
= (items_count
> 0 && values
[0][0]) ?
205 mc_skin_color_look_up_alias (mc_skin
, g_strstrip (g_strdup (values
[0]))) :
206 (tmp
!= NULL
) ? g_strdup (tmp
->fg
) : NULL
;
207 mc_skin_color
->bg
= (items_count
> 1 && values
[1][0]) ?
208 mc_skin_color_look_up_alias (mc_skin
, g_strstrip (g_strdup (values
[1]))) :
209 (tmp
!= NULL
) ? g_strdup (tmp
->bg
) : NULL
;
210 mc_skin_color
->attrs
= (items_count
> 2 && values
[2][0]) ?
211 mc_skin_color_look_up_alias (mc_skin
, g_strstrip (g_strdup (values
[2]))) :
212 (tmp
!= NULL
) ? g_strdup (tmp
->attrs
) : NULL
;
216 mc_skin_color
->pair_index
= tty_try_alloc_color_pair (mc_skin_color
, FALSE
);
218 return mc_skin_color
;
221 /* --------------------------------------------------------------------------------------------- */
224 mc_skin_color_set_default_for_terminal (mc_skin_t
* mc_skin
)
226 tty_color_pair_t
*mc_skin_color
;
228 mc_skin_color
= g_try_new0 (tty_color_pair_t
, 1);
229 if (mc_skin_color
!= NULL
)
231 mc_skin_color
->fg
= g_strdup ("default");
232 mc_skin_color
->bg
= g_strdup ("default");
233 mc_skin_color
->attrs
= NULL
;
234 mc_skin_color
->pair_index
= tty_try_alloc_color_pair (mc_skin_color
, FALSE
);
235 mc_skin_color_add_to_hash (mc_skin
, "skin", "terminal_default_color", mc_skin_color
);
239 /* --------------------------------------------------------------------------------------------- */
242 mc_skin_color_cache_init (void)
244 DEFAULT_COLOR
= mc_skin_color_get ("skin", "terminal_default_color");
245 NORMAL_COLOR
= mc_skin_color_get ("core", "_default_");
246 MARKED_COLOR
= mc_skin_color_get ("core", "marked");
247 SELECTED_COLOR
= mc_skin_color_get ("core", "selected");
248 MARKED_SELECTED_COLOR
= mc_skin_color_get ("core", "markselect");
249 DISABLED_COLOR
= mc_skin_color_get ("core", "disabled");
250 REVERSE_COLOR
= mc_skin_color_get ("core", "reverse");
251 HEADER_COLOR
= mc_skin_color_get ("core", "header");
252 COMMAND_MARK_COLOR
= mc_skin_color_get ("core", "commandlinemark");
253 SHADOW_COLOR
= mc_skin_color_get ("core", "shadow");
255 COLOR_NORMAL
= mc_skin_color_get ("dialog", "_default_");
256 COLOR_FOCUS
= mc_skin_color_get ("dialog", "dfocus");
257 COLOR_HOT_NORMAL
= mc_skin_color_get ("dialog", "dhotnormal");
258 COLOR_HOT_FOCUS
= mc_skin_color_get ("dialog", "dhotfocus");
259 COLOR_TITLE
= mc_skin_color_get ("dialog", "dtitle");
261 ERROR_COLOR
= mc_skin_color_get ("error", "_default_");
262 ERROR_FOCUS
= mc_skin_color_get ("error", "errdfocus");
263 ERROR_HOT_NORMAL
= mc_skin_color_get ("error", "errdhotnormal");
264 ERROR_HOT_FOCUS
= mc_skin_color_get ("error", "errdhotfocus");
265 ERROR_TITLE
= mc_skin_color_get ("error", "errdtitle");
267 MENU_ENTRY_COLOR
= mc_skin_color_get ("menu", "_default_");
268 MENU_SELECTED_COLOR
= mc_skin_color_get ("menu", "menusel");
269 MENU_HOT_COLOR
= mc_skin_color_get ("menu", "menuhot");
270 MENU_HOTSEL_COLOR
= mc_skin_color_get ("menu", "menuhotsel");
271 MENU_INACTIVE_COLOR
= mc_skin_color_get ("menu", "menuinactive");
273 PMENU_ENTRY_COLOR
= mc_skin_color_get ("popupmenu", "_default_");
274 PMENU_SELECTED_COLOR
= mc_skin_color_get ("popupmenu", "menusel");
275 PMENU_TITLE_COLOR
= mc_skin_color_get ("popupmenu", "menutitle");
277 BUTTONBAR_HOTKEY_COLOR
= mc_skin_color_get ("buttonbar", "hotkey");
278 BUTTONBAR_BUTTON_COLOR
= mc_skin_color_get ("buttonbar", "button");
280 STATUSBAR_COLOR
= mc_skin_color_get ("statusbar", "_default_");
282 GAUGE_COLOR
= mc_skin_color_get ("core", "gauge");
283 INPUT_COLOR
= mc_skin_color_get ("core", "input");
284 INPUT_HISTORY_COLOR
= mc_skin_color_get ("core", "inputhistory");
285 COMMAND_HISTORY_COLOR
= mc_skin_color_get ("core", "commandhistory");
286 INPUT_MARK_COLOR
= mc_skin_color_get ("core", "inputmark");
287 INPUT_UNCHANGED_COLOR
= mc_skin_color_get ("core", "inputunchanged");
289 HELP_NORMAL_COLOR
= mc_skin_color_get ("help", "_default_");
290 HELP_ITALIC_COLOR
= mc_skin_color_get ("help", "helpitalic");
291 HELP_BOLD_COLOR
= mc_skin_color_get ("help", "helpbold");
292 HELP_LINK_COLOR
= mc_skin_color_get ("help", "helplink");
293 HELP_SLINK_COLOR
= mc_skin_color_get ("help", "helpslink");
294 HELP_TITLE_COLOR
= mc_skin_color_get ("help", "helptitle");
296 VIEW_NORMAL_COLOR
= mc_skin_color_get ("viewer", "_default_");
297 VIEW_BOLD_COLOR
= mc_skin_color_get ("viewer", "viewbold");
298 VIEW_UNDERLINED_COLOR
= mc_skin_color_get ("viewer", "viewunderline");
299 VIEW_SELECTED_COLOR
= mc_skin_color_get ("viewer", "viewselected");
301 EDITOR_NORMAL_COLOR
= mc_skin_color_get ("editor", "_default_");
302 EDITOR_BOLD_COLOR
= mc_skin_color_get ("editor", "editbold");
303 EDITOR_MARKED_COLOR
= mc_skin_color_get ("editor", "editmarked");
304 EDITOR_WHITESPACE_COLOR
= mc_skin_color_get ("editor", "editwhitespace");
305 EDITOR_NONPRINTABLE_COLOR
= mc_skin_color_get ("editor", "editnonprintable");
306 EDITOR_RIGHT_MARGIN_COLOR
= mc_skin_color_get ("editor", "editrightmargin");
307 LINE_STATE_COLOR
= mc_skin_color_get ("editor", "editlinestate");
308 EDITOR_BACKGROUND
= mc_skin_color_get ("editor", "editbg");
309 EDITOR_FRAME
= mc_skin_color_get ("editor", "editframe");
310 EDITOR_FRAME_ACTIVE
= mc_skin_color_get ("editor", "editframeactive");
311 EDITOR_FRAME_DRAG
= mc_skin_color_get ("editor", "editframedrag");
313 BOOK_MARK_COLOR
= mc_skin_color_get ("editor", "bookmark");
314 BOOK_MARK_FOUND_COLOR
= mc_skin_color_get ("editor", "bookmarkfound");
316 DFF_ADD_COLOR
= mc_skin_color_get ("diffviewer", "added");
317 DFF_CHG_COLOR
= mc_skin_color_get ("diffviewer", "changedline");
318 DFF_CHH_COLOR
= mc_skin_color_get ("diffviewer", "changednew");
319 DFF_CHD_COLOR
= mc_skin_color_get ("diffviewer", "changed");
320 DFF_DEL_COLOR
= mc_skin_color_get ("diffviewer", "removed");
321 DFF_ERROR_COLOR
= mc_skin_color_get ("diffviewer", "error");
324 /* --------------------------------------------------------------------------------------------- */
327 mc_skin_color_check_inisection (const gchar
* group
)
329 return !((strcasecmp ("skin", group
) == 0) || (strcasecmp ("aliases", group
) == 0)
330 || (strcasecmp ("lines", group
) == 0) || (strncasecmp ("widget-", group
, 7) == 0));
333 /* --------------------------------------------------------------------------------------------- */
336 mc_skin_color_check_bw_mode (mc_skin_t
* mc_skin
)
338 gchar
**groups
, **orig_groups
;
340 if (tty_use_colors () && !mc_global
.tty
.disable_colors
)
343 orig_groups
= mc_config_get_groups (mc_skin
->config
, NULL
);
345 for (groups
= orig_groups
; *groups
!= NULL
; groups
++)
346 if (mc_skin_color_check_inisection (*groups
))
347 mc_config_del_group (mc_skin
->config
, *groups
);
349 g_strfreev (orig_groups
);
351 mc_skin_hardcoded_blackwhite_colors (mc_skin
);
354 /* --------------------------------------------------------------------------------------------- */
355 /*** public functions ****************************************************************************/
356 /* --------------------------------------------------------------------------------------------- */
359 mc_skin_color_parse_ini_file (mc_skin_t
* mc_skin
)
361 gboolean ret
= FALSE
;
363 gchar
**groups
, **orig_groups
;
364 tty_color_pair_t
*mc_skin_color
;
366 mc_skin_color_check_bw_mode (mc_skin
);
368 orig_groups
= mc_config_get_groups (mc_skin
->config
, &items_count
);
369 if (*orig_groups
== NULL
)
372 /* as first, need to set up default colors */
373 mc_skin_color_set_default_for_terminal (mc_skin
);
374 mc_skin_color
= mc_skin_color_get_from_ini_file (mc_skin
, "core", "_default_");
375 if (mc_skin_color
== NULL
)
378 tty_color_set_defaults (mc_skin_color
);
379 mc_skin_color_add_to_hash (mc_skin
, "core", "_default_", mc_skin_color
);
381 for (groups
= orig_groups
; *groups
!= NULL
; groups
++)
383 gchar
**keys
, **orig_keys
;
385 if (!mc_skin_color_check_inisection (*groups
))
388 orig_keys
= mc_config_get_keys (mc_skin
->config
, *groups
, NULL
);
390 for (keys
= orig_keys
; *keys
!= NULL
; keys
++)
392 mc_skin_color
= mc_skin_color_get_from_ini_file (mc_skin
, *groups
, *keys
);
393 if (mc_skin_color
!= NULL
)
394 mc_skin_color_add_to_hash (mc_skin
, *groups
, *keys
, mc_skin_color
);
396 g_strfreev (orig_keys
);
399 mc_skin_color_cache_init ();
404 g_strfreev (orig_groups
);
408 /* --------------------------------------------------------------------------------------------- */
411 mc_skin_color_get (const gchar
* group
, const gchar
* name
)
413 tty_color_pair_t
*mc_skin_color
;
415 mc_skin_color
= mc_skin_color_get_with_defaults (group
, name
);
417 return (mc_skin_color
!= NULL
) ? mc_skin_color
->pair_index
: 0;
420 /* --------------------------------------------------------------------------------------------- */