done some cleanup...
[midnight-commander.git] / src / color.c
blob8701ff54838ac65a3bb7deb10455dae0ca4f8487
1 /* Color setup
2 Copyright (C) 1994 Miguel de Icaza.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 #include <config.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "global.h"
22 #include "tty.h"
23 #include "setup.h" /* For the externs */
24 #include "color.h"
26 /* "$Id$" */
28 /* Set to force black and white display at program startup */
29 int disable_colors = 0;
31 /* Set if we are actually using colors */
32 int use_colors = 0;
34 /* Color styles for normal and error dialogs */
35 int dialog_colors [4];
36 int alarm_colors [4];
38 #define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
40 #ifdef HAVE_SLANG
41 # define color_map_fg(n) color_map[n].fg
42 # define color_map_bg(n) color_map[n].bg
43 #else
44 # define color_map_fg(n) (color_map[n].fg & COLOR_WHITE)
45 # define color_map_bg(n) (color_map[n].bg & COLOR_WHITE)
46 #endif
48 struct colorpair {
49 char *name; /* Name of the entry */
50 CTYPE fg; /* foreground color */
51 CTYPE bg; /* background color */
54 struct colorpair color_map [] = {
55 { "normal=", 0, 0 }, /* normal */ /* 1 */
56 { "selected=", 0, 0 }, /* selected */
57 { "marked=", 0, 0 }, /* marked */
58 { "markselect=", 0, 0 }, /* marked/selected */
59 { "errors=", 0, 0 }, /* errors */
60 { "menu=", 0, 0 }, /* menu entry */
61 { "reverse=", 0, 0 }, /* reverse */
63 /* Dialog colors */
64 { "dnormal=", 0, 0 }, /* Dialog normal */ /* 8 */
65 { "dfocus=", 0, 0 }, /* Dialog focused */
66 { "dhotnormal=", 0, 0 }, /* Dialog normal/hot */
67 { "dhotfocus=", 0, 0 }, /* Dialog focused/hot */
69 { "viewunderline=", 0, 0 }, /* _\b? sequence in view, underline in editor */
70 { "menusel=", 0, 0 }, /* Menu selected color */ /* 13 */
71 { "menuhot=", 0, 0 }, /* Color for menu hotkeys */
72 { "menuhotsel=", 0, 0 }, /* Menu hotkeys/selected entry */
74 { "helpnormal=", 0, 0 }, /* Help normal */ /* 16 */
75 { "helpitalic=", 0, 0 }, /* Italic in help */
76 { "helpbold=", 0, 0 }, /* Bold in help */
77 { "helplink=", 0, 0 }, /* Not selected hyperlink */
78 { "helpslink=", 0, 0 }, /* Selected hyperlink */
80 { "gauge=", 0, 0 }, /* Color of the progress bar (percentage) *//* 21 */
81 { "input=", 0, 0 },
83 /* Per file types colors */
84 { "directory=", 0, 0 }, /* 23 */
85 { "executable=", 0, 0 },
86 { "link=", 0, 0 }, /* symbolic link (neither stalled nor link to directory) */
87 { "stalledlink=",0, 0 }, /* stalled symbolic link */
88 { "device=", 0, 0 },
89 { "special=", 0, 0 }, /* sockets, fifo */
90 { "core=", 0, 0 }, /* core files */ /* 29 */
92 { 0, 0, 0 }, /* not usable (DEFAULT_COLOR_INDEX) *//* 30 */
93 { 0, 0, 0 }, /* unused */
94 { 0, 0, 0 }, /* not usable (A_REVERSE) */
95 { 0, 0, 0 }, /* not usable (A_REVERSE_BOLD) */
97 /* editor colors start at 34 */
98 { "editnormal=", 0, 0 }, /* normal */ /* 34 */
99 { "editbold=", 0, 0 }, /* search->found */
100 { "editmarked=", 0, 0 }, /* marked/selected */
103 struct color_table_s {
104 char *name;
105 int value;
109 static struct color_table_s const color_table [] = {
110 { "black", COLOR_BLACK },
111 { "gray", COLOR_BLACK | A_BOLD },
112 { "red", COLOR_RED },
113 { "brightred", COLOR_RED | A_BOLD },
114 { "green", COLOR_GREEN },
115 { "brightgreen", COLOR_GREEN | A_BOLD },
116 { "brown", COLOR_YELLOW },
117 { "yellow", COLOR_YELLOW | A_BOLD },
118 { "blue", COLOR_BLUE },
119 { "brightblue", COLOR_BLUE | A_BOLD },
120 { "magenta", COLOR_MAGENTA },
121 { "brightmagenta", COLOR_MAGENTA | A_BOLD },
122 { "cyan", COLOR_CYAN },
123 { "brightcyan", COLOR_CYAN | A_BOLD },
124 { "lightgray", COLOR_WHITE },
125 { "white", COLOR_WHITE | A_BOLD },
126 { "default", 0 } /* hack for transparent background */
129 #ifdef HAVE_SLANG
130 # define color_value(i) color_table [i].name
131 # define color_name(i) color_table [i].name
132 #else
133 # define color_value(i) color_table [i].value
134 # define color_name(i) color_table [i].name
135 #endif
137 static void get_color (char *cpp, CTYPE *colp)
139 int i;
141 for (i = 0; i < ELEMENTS(color_table); i++){
142 if (strcmp (cpp, color_name (i)) == 0){
143 *colp = color_value (i);
144 return;
149 static void get_two_colors (char **cpp, struct colorpair *colorpairp)
151 char *p = *cpp;
152 int state;
154 state = 0;
156 for (; *p; p++){
157 if (*p == ':'){
158 *p = 0;
159 get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
160 *p = ':';
161 *cpp = p + 1;
162 return;
165 if (*p == ','){
166 state = 1;
167 *p = 0;
168 get_color (*cpp, &colorpairp->fg);
169 *p = ',';
170 *cpp = p + 1;
173 get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
176 static void configure_colors_string (char *the_color_string)
178 char *color_string, *p;
179 int i, found;
181 if (!the_color_string)
182 return;
184 p = color_string = g_strdup (the_color_string);
185 while (color_string && *color_string){
186 while (*color_string == ' ' || *color_string == '\t')
187 color_string++;
189 found = 0;
190 for (i = 0; i < ELEMENTS(color_map); i++){
191 int klen;
193 if (!color_map [i].name)
194 continue;
195 klen = strlen (color_map [i].name);
197 if (strncmp (color_string, color_map [i].name, klen) == 0){
198 color_string += klen;
199 get_two_colors (&color_string, &color_map [i]);
200 found = 1;
203 if (!found){
204 while (*color_string && *color_string != ':')
205 color_string++;
206 if (*color_string)
207 color_string++;
210 g_free (p);
213 static void configure_colors (void)
215 extern char *command_line_colors;
216 extern char *default_edition_colors;
218 configure_colors_string (default_edition_colors);
219 configure_colors_string (setup_color_string);
220 configure_colors_string (term_color_string);
221 configure_colors_string (getenv ("MC_COLOR_TABLE"));
222 configure_colors_string (command_line_colors);
225 #ifndef HAVE_SLANG
226 #define MAX_PAIRS 64
227 int attr_pairs [MAX_PAIRS];
228 #endif
230 static void
231 load_dialog_colors (void)
233 dialog_colors [0] = COLOR_NORMAL;
234 dialog_colors [1] = COLOR_FOCUS;
235 dialog_colors [2] = COLOR_HOT_NORMAL;
236 dialog_colors [3] = COLOR_HOT_FOCUS;
238 alarm_colors [0] = ERROR_COLOR;
239 alarm_colors [1] = REVERSE_COLOR;
240 alarm_colors [2] = ERROR_COLOR;
241 alarm_colors [3] = COLOR_HOT_NORMAL;
244 void init_colors (void)
246 int i;
248 int hascolors;
250 /* FIXME: if S-Lang is used, this function must be called regardless
251 of whether we are interested in its result */
252 hascolors = has_colors ();
254 if (!disable_colors && hascolors){
255 use_colors = 1;
258 if (use_colors){
259 start_color ();
260 configure_colors ();
262 #ifndef HAVE_SLANG
263 if (ELEMENTS (color_map) > MAX_PAIRS){
264 /* This message should only be seen by the developers */
265 fprintf (stderr,
266 "Too many defined colors, resize MAX_PAIRS on color.c");
267 exit (1);
269 #endif /* !HAVE_SLANG */
271 if (use_colors) {
272 #ifdef HAVE_SLANG
274 * We are relying on undocumented feature of
275 * S-Lang to make COLOR_PAIR(DEFAULT_COLOR_INDEX)
276 * the default fg/bg of the terminal.
277 * Hopefully, future versions of S-Lang will
278 * document this feature.
280 SLtt_set_color (DEFAULT_COLOR_INDEX, NULL, "default", "default");
281 #else
282 /* Always white on black */
283 mc_init_pair(DEFAULT_COLOR_INDEX, COLOR_WHITE, COLOR_BLACK);
284 #endif /* !HAVE_SLANG */
287 for (i = 0; i < ELEMENTS (color_map); i++){
288 if (!color_map [i].name)
289 continue;
291 mc_init_pair (i+1, color_map_fg(i), color_map_bg(i));
293 #ifndef HAVE_SLANG
295 * ncurses doesn't remember bold attribute in the color pairs,
296 * so we should keep track of it in a separate array.
298 attr_pairs [i+1] = color_map [i].fg & A_BOLD;
299 #endif /* !HAVE_SLANG */
302 load_dialog_colors ();
305 /* Functions necessary to implement syntax highlighting */
307 static int max_index = 0;
309 static int
310 alloc_color_pair (CTYPE foreground, CTYPE background)
312 mc_init_pair (++max_index, foreground, background);
313 return max_index;
316 static struct colors_avail {
317 struct colors_avail *next;
318 char *fg, *bg;
319 int index;
320 } c = { 0, 0, 0, 0 };
322 #ifdef HAVE_SLANG
323 void
324 mc_init_pair (int index, CTYPE foreground, CTYPE background)
326 /* hack for transparent background for Eterm, rxvt or else */
327 if (background && !strcmp (background, "default"))
328 background = NULL;
329 /* if foreground is default, I guess we should use normal fore-color. */
331 SLtt_set_color (index, "", foreground, background);
332 if (index > max_index)
333 max_index = index;
337 try_alloc_color_pair (char *fg, char *bg)
339 struct colors_avail *p = &c;
341 c.index = EDITOR_NORMAL_COLOR_INDEX;
342 for (;;) {
343 if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
344 && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
345 return p->index;
346 if (!p->next)
347 break;
348 p = p->next;
350 p->next = g_new (struct colors_avail, 1);
351 p = p->next;
352 p->next = 0;
353 p->fg = fg ? g_strdup (fg) : 0;
354 p->bg = bg ? g_strdup (bg) : 0;
355 if (!fg)
356 /* Index in color_map array = COLOR_INDEX - 1 */
357 fg = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].fg;
358 if (!bg)
359 bg = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].bg;
360 p->index = alloc_color_pair (fg, bg);
361 return p->index;
364 #else /* !HAVE_SLANG */
365 void
366 mc_init_pair (int index, CTYPE foreground, CTYPE background)
368 init_pair (index, foreground, background);
369 if (index > max_index)
370 max_index = index;
374 try_alloc_color_pair (char *fg, char *bg)
376 int fg_index, bg_index;
377 int bold_attr;
378 struct colors_avail *p = &c;
380 c.index = EDITOR_NORMAL_COLOR_INDEX;
381 for (;;) {
382 if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
383 && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
384 return p->index;
385 if (!p->next)
386 break;
387 p = p->next;
389 p->next = g_new (struct colors_avail, 1);
390 p = p->next;
391 p->next = 0;
392 p->fg = fg ? g_strdup (fg) : 0;
393 p->bg = bg ? g_strdup (bg) : 0;
394 if (!fg)
395 /* Index in color_map array = COLOR_INDEX - 1 */
396 fg_index = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].fg;
397 else
398 get_color (fg, &fg_index);
400 if (!bg)
401 bg_index = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].bg;
402 else
403 get_color (bg, &bg_index);
405 bold_attr = fg_index & A_BOLD;
406 fg_index = fg_index & COLOR_WHITE;
407 bg_index = bg_index & COLOR_WHITE;
409 p->index = alloc_color_pair (fg_index, bg_index);
410 attr_pairs [p->index] = bold_attr;
411 return p->index;
413 #endif /* !HAVE_SLANG */
415 void
416 dealloc_color_pairs (void)
418 struct colors_avail *p, *next;
420 for (p = c.next; p; p = next) {
421 next = p->next;
422 if (p->fg)
423 g_free (p->fg);
424 if (p->bg)
425 g_free (p->bg);
426 g_free (p);
428 c.next = NULL;