Ticket #305 (dont work rename/copy on some chars)
[midnight-commander.git] / src / color.c
blob99811d88255c420c98951782d21329c9d85df6ad
1 /* Color setup
2 Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2007 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19 /** \file color.c
20 * \brief Source: color setup
23 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include "global.h"
30 #include "tty.h"
31 #include "setup.h" /* For the externs */
32 #include "color.h"
34 /* Set to force black and white display at program startup */
35 int disable_colors = 0;
37 /* Set if we are actually using colors */
38 int use_colors = 0;
40 /* Color styles for normal and error dialogs */
41 int dialog_colors [4];
42 int alarm_colors [4];
44 #define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
46 #ifdef HAVE_SLANG
47 # define color_map_fg(n) color_map[n].fg
48 # define color_map_bg(n) color_map[n].bg
49 #else
50 # define color_map_fg(n) (color_map[n].fg & COLOR_WHITE)
51 # define color_map_bg(n) (color_map[n].bg & COLOR_WHITE)
52 #endif
54 struct colorpair {
55 const char *name; /* Name of the entry */
56 CTYPE fg; /* foreground color */
57 CTYPE bg; /* background color */
60 static struct colorpair color_map [] = {
61 { "normal=", 0, 0 }, /* normal */ /* 1 */
62 { "selected=", 0, 0 }, /* selected */
63 { "marked=", 0, 0 }, /* marked */
64 { "markselect=", 0, 0 }, /* marked/selected */
65 { "errors=", 0, 0 }, /* errors */
66 { "menu=", 0, 0 }, /* menu entry */
67 { "reverse=", 0, 0 }, /* reverse */
69 /* Dialog colors */
70 { "dnormal=", 0, 0 }, /* Dialog normal */ /* 8 */
71 { "dfocus=", 0, 0 }, /* Dialog focused */
72 { "dhotnormal=", 0, 0 }, /* Dialog normal/hot */
73 { "dhotfocus=", 0, 0 }, /* Dialog focused/hot */
75 { "viewunderline=", 0, 0 }, /* _\b? sequence in view, underline in editor */
76 { "menusel=", 0, 0 }, /* Menu selected color */ /* 13 */
77 { "menuhot=", 0, 0 }, /* Color for menu hotkeys */
78 { "menuhotsel=", 0, 0 }, /* Menu hotkeys/selected entry */
80 { "helpnormal=", 0, 0 }, /* Help normal */ /* 16 */
81 { "helpitalic=", 0, 0 }, /* Italic in help */
82 { "helpbold=", 0, 0 }, /* Bold in help */
83 { "helplink=", 0, 0 }, /* Not selected hyperlink */
84 { "helpslink=", 0, 0 }, /* Selected hyperlink */
86 { "gauge=", 0, 0 }, /* Color of the progress bar (percentage) *//* 21 */
87 { "input=", 0, 0 },
89 /* Per file types colors */
90 { "directory=", 0, 0 }, /* 23 */
91 { "executable=", 0, 0 },
92 { "link=", 0, 0 }, /* symbolic link (neither stale nor link to directory) */
93 { "stalelink=", 0, 0 }, /* stale symbolic link */
94 { "device=", 0, 0 },
95 { "special=", 0, 0 }, /* sockets, fifo */
96 { "core=", 0, 0 }, /* core files */ /* 29 */
98 { 0, 0, 0 }, /* not usable (DEFAULT_COLOR_INDEX) *//* 30 */
99 { 0, 0, 0 }, /* unused */
100 { 0, 0, 0 }, /* not usable (A_REVERSE) */
101 { 0, 0, 0 }, /* not usable (A_REVERSE_BOLD) */
103 /* editor colors start at 34 */
104 { "editnormal=", 0, 0 }, /* normal */ /* 34 */
105 { "editbold=", 0, 0 }, /* search->found */
106 { "editmarked=", 0, 0 }, /* marked/selected */
107 { "editwhitespace=", 0, 0 }, /* whitespace */
108 { "editlinestate=", 0, 0 }, /* line number bar*/
110 /* error dialog colors start at 39 */
111 { "errdhotnormal=", 0, 0 }, /* Error dialog normal/hot */ /* 39 */
112 { "errdhotfocus=", 0, 0 }, /* Error dialog focused/hot */
115 struct color_table_s {
116 const char *name;
117 int value;
121 static struct color_table_s const color_table [] = {
122 { "black", COLOR_BLACK },
123 { "gray", COLOR_BLACK | A_BOLD },
124 { "red", COLOR_RED },
125 { "brightred", COLOR_RED | A_BOLD },
126 { "green", COLOR_GREEN },
127 { "brightgreen", COLOR_GREEN | A_BOLD },
128 { "brown", COLOR_YELLOW },
129 { "yellow", COLOR_YELLOW | A_BOLD },
130 { "blue", COLOR_BLUE },
131 { "brightblue", COLOR_BLUE | A_BOLD },
132 { "magenta", COLOR_MAGENTA },
133 { "brightmagenta", COLOR_MAGENTA | A_BOLD },
134 { "cyan", COLOR_CYAN },
135 { "brightcyan", COLOR_CYAN | A_BOLD },
136 { "lightgray", COLOR_WHITE },
137 { "white", COLOR_WHITE | A_BOLD },
138 { "default", 0 } /* default color of the terminal */
141 #ifdef HAVE_SLANG
142 # define color_value(i) color_table [i].name
143 # define color_name(i) color_table [i].name
144 #else
145 # define color_value(i) color_table [i].value
146 # define color_name(i) color_table [i].name
147 #endif
149 static void get_color (const char *cpp, CTYPE *colp)
151 size_t i;
153 for (i = 0; i < ELEMENTS(color_table); i++){
154 if (strcmp (cpp, color_name (i)) == 0){
155 *colp = color_value (i);
156 return;
161 static void get_two_colors (char **cpp, struct colorpair *colorpairp)
163 char *p = *cpp;
164 int state;
166 state = 0;
168 for (; *p; p++){
169 if (*p == ':'){
170 *p = 0;
171 get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
172 *p = ':';
173 *cpp = p + 1;
174 return;
177 if (*p == ','){
178 state = 1;
179 *p = 0;
180 get_color (*cpp, &colorpairp->fg);
181 *p = ',';
182 *cpp = p + 1;
185 get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
188 static void configure_colors_string (const char *the_color_string)
190 char *color_string, *p;
191 size_t i;
192 int found;
194 if (!the_color_string)
195 return;
197 p = color_string = g_strdup (the_color_string);
198 while (color_string && *color_string){
199 while (*color_string == ' ' || *color_string == '\t')
200 color_string++;
202 found = 0;
203 for (i = 0; i < ELEMENTS(color_map); i++){
204 int klen;
206 if (!color_map [i].name)
207 continue;
208 klen = strlen (color_map [i].name);
210 if (strncmp (color_string, color_map [i].name, klen) == 0){
211 color_string += klen;
212 get_two_colors (&color_string, &color_map [i]);
213 found = 1;
216 if (!found){
217 while (*color_string && *color_string != ':')
218 color_string++;
219 if (*color_string)
220 color_string++;
223 g_free (p);
226 static void configure_colors (void)
228 gchar *default_colors = g_strconcat (
229 "normal=lightgray,blue:"
230 "selected=black,cyan:"
231 "marked=yellow,blue:"
232 "markselect=yellow,cyan:"
233 "errors=white,red:"
234 "menu=white,cyan:"
235 "reverse=black,lightgray:"
236 "dnormal=black,lightgray:"
237 "dfocus=black,cyan:"
238 "dhotnormal=blue,lightgray:"
239 "dhotfocus=blue,cyan:"
240 "viewunderline=brightred,blue:"
241 "menuhot=yellow,cyan:"
242 "menusel=white,black:"
243 "menuhotsel=yellow,black:"
244 "helpnormal=black,lightgray:"
245 "helpitalic=red,lightgray:"
246 "helpbold=blue,lightgray:"
247 "helplink=black,cyan:"
248 "helpslink=yellow,blue:"
249 "gauge=white,black:"
250 "input=black,cyan:"
251 "directory=white,blue:"
253 "executable=brightgreen,blue:"
254 "link=lightgray,blue:"
255 "stalelink=brightred,blue:"
256 "device=brightmagenta,blue:"
257 "core=red,blue:"
258 "special=black,blue:"
259 "editnormal=lightgray,blue:"
260 "editbold=yellow,blue:"
261 "editmarked=black,cyan:"
262 "editwhitespace=brightblue,blue:"
263 "editlinestate=white,cyan:"
264 "errdhotnormal=yellow,red:"
265 "errdhotfocus=yellow,lightgray", NULL);
267 extern char *command_line_colors;
269 configure_colors_string (default_colors);
270 configure_colors_string (setup_color_string);
271 configure_colors_string (term_color_string);
272 configure_colors_string (getenv ("MC_COLOR_TABLE"));
273 configure_colors_string (command_line_colors);
274 g_free(default_colors);
277 #ifndef HAVE_SLANG
278 #define MAX_PAIRS 64
279 int attr_pairs [MAX_PAIRS];
280 #endif
282 static void
283 load_dialog_colors (void)
285 dialog_colors [0] = COLOR_NORMAL;
286 dialog_colors [1] = COLOR_FOCUS;
287 dialog_colors [2] = COLOR_HOT_NORMAL;
288 dialog_colors [3] = COLOR_HOT_FOCUS;
290 alarm_colors [0] = ERROR_COLOR;
291 alarm_colors [1] = REVERSE_COLOR;
292 alarm_colors [2] = ERROR_HOT_NORMAL;
293 alarm_colors [3] = ERROR_HOT_FOCUS;
296 void init_colors (void)
298 size_t i;
300 int hascolors;
302 /* FIXME: if S-Lang is used, this function must be called regardless
303 of whether we are interested in its result */
304 hascolors = has_colors ();
306 if (!disable_colors && hascolors){
307 use_colors = 1;
310 if (use_colors){
311 start_color ();
312 #ifndef HAVE_SLANG
313 use_default_colors ();
314 #endif /* !HAVE_SLANG */
315 configure_colors ();
317 #ifndef HAVE_SLANG
318 if (ELEMENTS (color_map) > MAX_PAIRS){
319 /* This message should only be seen by the developers */
320 fprintf (stderr,
321 "Too many defined colors, resize MAX_PAIRS on color.c");
322 exit (1);
324 #endif /* !HAVE_SLANG */
326 if (use_colors) {
327 #ifdef HAVE_SLANG
329 * We are relying on undocumented feature of
330 * S-Lang to make COLOR_PAIR(DEFAULT_COLOR_INDEX)
331 * the default fg/bg of the terminal.
332 * Hopefully, future versions of S-Lang will
333 * document this feature.
335 SLtt_set_color (DEFAULT_COLOR_INDEX, NULL, "default", "default");
336 #else
337 /* Use default terminal colors */
338 mc_init_pair (DEFAULT_COLOR_INDEX, -1, -1);
339 #endif /* !HAVE_SLANG */
342 for (i = 0; i < ELEMENTS (color_map); i++){
343 if (!color_map [i].name)
344 continue;
346 mc_init_pair (i+1, color_map_fg(i), color_map_bg(i));
348 #ifndef HAVE_SLANG
350 * ncurses doesn't remember bold attribute in the color pairs,
351 * so we should keep track of it in a separate array.
353 attr_pairs [i+1] = color_map [i].fg & A_BOLD;
354 #endif /* !HAVE_SLANG */
357 load_dialog_colors ();
360 /* Functions necessary to implement syntax highlighting */
362 static int max_index = 0;
364 static int
365 alloc_color_pair (CTYPE foreground, CTYPE background)
367 mc_init_pair (++max_index, foreground, background);
368 return max_index;
371 static struct colors_avail {
372 struct colors_avail *next;
373 char *fg, *bg;
374 int index;
375 } c = { 0, 0, 0, 0 };
377 #ifdef HAVE_SLANG
378 void
379 mc_init_pair (int index, CTYPE foreground, CTYPE background)
381 if (!background)
382 background = "default";
384 if (!foreground)
385 foreground = "default";
387 SLtt_set_color (index, "", (char *) foreground, (char *) background);
388 if (index > max_index)
389 max_index = index;
393 try_alloc_color_pair (const char *fg, const char *bg)
395 struct colors_avail *p = &c;
397 c.index = EDITOR_NORMAL_COLOR_INDEX;
398 for (;;) {
399 if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
400 && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
401 return p->index;
402 if (!p->next)
403 break;
404 p = p->next;
406 p->next = g_new (struct colors_avail, 1);
407 p = p->next;
408 p->next = 0;
409 p->fg = fg ? g_strdup (fg) : 0;
410 p->bg = bg ? g_strdup (bg) : 0;
411 if (!fg)
412 /* Index in color_map array = COLOR_INDEX - 1 */
413 fg = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].fg;
414 if (!bg)
415 bg = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].bg;
416 p->index = alloc_color_pair (fg, bg);
417 return p->index;
420 #else /* !HAVE_SLANG */
421 void
422 mc_init_pair (int index, CTYPE foreground, CTYPE background)
424 init_pair (index, foreground, background == 0 ? -1 : background);
425 if (index > max_index)
426 max_index = index;
430 try_alloc_color_pair (const char *fg, const char *bg)
432 int fg_index, bg_index;
433 int bold_attr;
434 struct colors_avail *p = &c;
436 c.index = EDITOR_NORMAL_COLOR_INDEX;
437 for (;;) {
438 if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
439 && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
440 return p->index;
441 if (!p->next)
442 break;
443 p = p->next;
445 p->next = g_new (struct colors_avail, 1);
446 p = p->next;
447 p->next = 0;
448 p->fg = fg ? g_strdup (fg) : 0;
449 p->bg = bg ? g_strdup (bg) : 0;
450 if (!fg)
451 /* Index in color_map array = COLOR_INDEX - 1 */
452 fg_index = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].fg;
453 else
454 get_color (fg, &fg_index);
456 if (!bg)
457 bg_index = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].bg;
458 else
459 get_color (bg, &bg_index);
461 bold_attr = fg_index & A_BOLD;
462 fg_index = fg_index & COLOR_WHITE;
463 bg_index = bg_index & COLOR_WHITE;
465 p->index = alloc_color_pair (fg_index, bg_index);
466 attr_pairs [p->index] = bold_attr;
467 return p->index;
469 #endif /* !HAVE_SLANG */
471 void
472 done_colors (void)
474 struct colors_avail *p, *next;
476 for (p = c.next; p; p = next) {
477 next = p->next;
478 g_free (p->fg);
479 g_free (p->bg);
480 g_free (p);
482 c.next = NULL;