1 /*
2     roxterm - VTE/GTK terminal emulator with tabs
3     Copyright (C) 2004-2015 Tony Houghton <h@realh.co.uk>
4 
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.
9 
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.
14 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 
21 #include "colourscheme.h"
22 #include "dlg.h"
23 #include "dynopts.h"
24 
25 #define COLOURSCHEME_GROUP "roxterm colour scheme"
26 
27 typedef struct {
28     GdkRGBA *foreground, *background, *cursor, *cursorfg, *bold, *dim;
29     GdkRGBA *palette;
30     int palette_size;
31 } ColourScheme;
32 
33 static DynamicOptions *colour_scheme_dynopts = NULL;
34 
delete_scheme(ColourScheme * scheme)35 static void delete_scheme(ColourScheme *scheme)
36 {
37     g_free(scheme->foreground);
38     g_free(scheme->background);
39     g_free(scheme->cursor);
40     g_free(scheme->bold);
41     g_free(scheme->dim);
42     g_free(scheme->palette);
43     g_free(scheme);
44 }
45 
colour_scheme_reset_cached_data(Options * opts)46 void colour_scheme_reset_cached_data(Options *opts)
47 {
48     ColourScheme *scheme = options_get_data(opts);
49 
50     if (scheme)
51         delete_scheme(scheme);
52     scheme = g_new0(ColourScheme, 1);
53     options_associate_data(opts, scheme);
54 }
55 
colour_scheme_lookup_and_ref(const char * scheme_name)56 Options *colour_scheme_lookup_and_ref(const char *scheme_name)
57 {
58     Options *opts;
59 
60     if (!colour_scheme_dynopts)
61         colour_scheme_dynopts = dynamic_options_get("Colours");
62     opts = dynamic_options_lookup_and_ref(colour_scheme_dynopts,
63             scheme_name, COLOURSCHEME_GROUP);
64     colour_scheme_reset_cached_data(opts);
65     return opts;
66 }
67 
colour_scheme_unref(Options * opts)68 gboolean colour_scheme_unref(Options * opts)
69 {
70     ColourScheme *scheme;
71 
72     g_return_val_if_fail(opts, FALSE);
73     scheme = options_get_data(opts);
74     g_return_val_if_fail(scheme, FALSE);
75 
76     if (dynamic_options_unref(colour_scheme_dynopts,
77                 options_get_leafname(opts)))
78     {
79         delete_scheme(scheme);
80         return TRUE;
81     }
82     return FALSE;
83 }
84 
colour_scheme_choose_default(int palette_entry)85 static const char *colour_scheme_choose_default(int palette_entry)
86 {
87     static const char *default_colours[16] = {
88         "#2c2c2c", "#c00000", "#00c000", "#c0c000",
89             "#5555ff", "#aa00aa", "#00aaaa", "#e8e8e8",
90         "#000000", "#ff0000", "#00ff00", "#ffff00",
91             "#2666ff", "#ff00ff", "#00ffff", "#ffffff"
92     };
93 
94     return default_colours[palette_entry];
95 }
96 
97 static gboolean
colour_scheme_parse(ColourScheme * scheme,GdkRGBA * colour,const char * colour_name)98 colour_scheme_parse(ColourScheme * scheme, GdkRGBA *colour,
99         const char *colour_name)
100 {
101     (void) scheme;
102     if (gdk_rgba_parse(colour, colour_name))
103     {
104         return TRUE;
105     }
106     return FALSE;
107 }
108 
colour_scheme_lookup_and_parse(Options * opts,ColourScheme * scheme,GdkRGBA * colour,const char * key,const char * default_colour,gboolean warn)109 static gboolean colour_scheme_lookup_and_parse(Options * opts,
110         ColourScheme * scheme, GdkRGBA * colour, const char *key,
111         const char *default_colour, gboolean warn)
112 {
113     char *name = options_lookup_string(opts, key);
114     gboolean result = TRUE;
115 
116     if (!name || !colour_scheme_parse(scheme, colour, name))
117     {
118         if (warn && name)
119         {
120             dlg_warning(NULL,
121                     _("Unable to parse colour '%s' for %s in scheme %s"),
122                     name, key, options_get_leafname(opts));
123         }
124         if (default_colour)
125             result = colour_scheme_parse(scheme, colour, default_colour);
126         else
127             result = FALSE;
128     }
129     if (name)
130         g_free(name);
131     return result;
132 }
133 
134 static void
colour_scheme_parse_palette_range(Options * opts,ColourScheme * scheme,int start,int end)135 colour_scheme_parse_palette_range(Options * opts, ColourScheme * scheme,
136     int start, int end)
137 {
138     int n;
139 
140     for (n = start; n < 16; ++n)
141     {
142         char key[8];
143         sprintf(key, "%d", n);
144 
145         colour_scheme_lookup_and_parse(opts, scheme, &scheme->palette[n], key,
146                     colour_scheme_choose_default(n), n < end);
147     }
148 }
149 
colour_scheme_parse_palette(Options * opts,ColourScheme * scheme)150 static void colour_scheme_parse_palette(Options * opts, ColourScheme * scheme)
151 {
152     if (!scheme->palette)
153         scheme->palette = g_new0(GdkRGBA, 16);
154     scheme->palette_size = options_lookup_int(opts, "palette_size");
155     switch (scheme->palette_size)
156     {
157         case 8:
158         case 16:
159             /* No problem */
160             break;
161         case 24:
162             /* No longer supported, use 16 */
163             scheme->palette_size = 16;
164             break;
165         case -1:
166             /* Not given, probably fine */
167             scheme->palette_size = 0;
168             break;
169         case 0:
170             break;
171         default:
172             dlg_warning(NULL,
173                 _("Invalid palette size %d in colour scheme %s"),
174                 scheme->palette_size, options_get_leafname(opts));
175             scheme->palette_size = 0;
176             break;
177     }
178     colour_scheme_parse_palette_range(opts, scheme, 0, scheme->palette_size);
179 }
180 
colour_scheme_get_palette(Options * opts)181 GdkRGBA *colour_scheme_get_palette(Options * opts)
182 {
183     ColourScheme *scheme;
184 
185     g_return_val_if_fail(opts, NULL);
186     scheme = options_get_data(opts);
187     g_return_val_if_fail(scheme, NULL);
188 
189     colour_scheme_parse_palette(opts, scheme);
190     return scheme->palette;
191 }
192 
colour_scheme_get_palette_size(Options * opts)193 int colour_scheme_get_palette_size(Options * opts)
194 {
195     ColourScheme *scheme;
196 
197     g_return_val_if_fail(opts, 0);
198     scheme = options_get_data(opts);
199     g_return_val_if_fail(scheme, 0);
200 
201     colour_scheme_parse_palette(opts, scheme);
202     return scheme->palette_size;
203 }
204 
colour_scheme_get_named_colour(Options * opts,const char * name,const char * dflt,size_t member_offset,gboolean allow_null)205 static GdkRGBA *colour_scheme_get_named_colour(Options *opts,
206         const char *name, const char *dflt,
207         size_t member_offset, gboolean allow_null)
208 {
209     ColourScheme *scheme;
210     GdkRGBA **member;
211 
212     g_return_val_if_fail(opts, NULL);
213     scheme = options_get_data(opts);
214     g_return_val_if_fail(scheme, NULL);
215 
216     member = (GdkRGBA **) (((char *) scheme) + member_offset);
217     if (!*member)
218     {
219         *member = g_new0(GdkRGBA, 1);
220         if (!colour_scheme_lookup_and_parse(opts, scheme, *member,
221                     name, allow_null ? NULL : dflt, TRUE))
222         {
223             g_free(*member);
224             *member = NULL;
225         }
226     }
227     return *member;
228 }
229 
colour_scheme_get_cursor_colour(Options * opts,gboolean allow_null)230 GdkRGBA *colour_scheme_get_cursor_colour(Options *opts,
231         gboolean allow_null)
232 {
233     return colour_scheme_get_named_colour(opts, "cursor", "#ccc",
234             offsetof(ColourScheme, cursor), allow_null);
235 }
236 
colour_scheme_get_cursorfg_colour(Options * opts,gboolean allow_null)237 GdkRGBA *colour_scheme_get_cursorfg_colour(Options * opts,
238         gboolean allow_null)
239 {
240     return colour_scheme_get_named_colour(opts, "cursorfg", "#000",
241             offsetof(ColourScheme, cursorfg), allow_null);
242 }
243 
colour_scheme_get_foreground_colour(Options * opts,gboolean allow_null)244 GdkRGBA *colour_scheme_get_foreground_colour(Options * opts,
245             gboolean allow_null)
246 {
247     return colour_scheme_get_named_colour(opts, "foreground", "#ccc",
248             offsetof(ColourScheme, foreground), allow_null);
249 }
250 
colour_scheme_get_background_colour(Options * opts,gboolean allow_null)251 GdkRGBA *colour_scheme_get_background_colour(Options * opts,
252         gboolean allow_null)
253 {
254     return colour_scheme_get_named_colour(opts, "background", "#000",
255             offsetof(ColourScheme, background), allow_null);
256 }
257 
colour_scheme_get_bold_colour(Options * opts,gboolean allow_null)258 GdkRGBA *colour_scheme_get_bold_colour(Options * opts,
259         gboolean allow_null)
260 {
261     return colour_scheme_get_named_colour(opts, "bold", "#fff",
262             offsetof(ColourScheme, bold), allow_null);
263 }
264 
colour_scheme_set_palette_size(Options * opts,int size)265 void colour_scheme_set_palette_size(Options * opts, int size)
266 {
267     ColourScheme *scheme;
268 
269     g_return_if_fail(opts);
270     scheme = options_get_data(opts);
271     g_return_if_fail(scheme);
272     scheme->palette_size = size;
273 }
274 
colour_scheme_set_colour(Options * opts,ColourScheme * scheme,GdkRGBA ** colour,const char * key,const char * colour_name)275 static void colour_scheme_set_colour(Options *opts, ColourScheme *scheme,
276         GdkRGBA **colour, const char *key, const char *colour_name)
277 {
278     if (!*colour)
279         *colour = g_new(GdkRGBA, 1);
280     if (!colour_name || colour_scheme_parse(scheme, *colour, colour_name))
281         options_set_string(opts, key, colour_name);
282     if (!colour_name)
283     {
284         g_free(*colour);
285         *colour = NULL;
286     }
287 }
288 
colour_scheme_set_palette_entry(Options * opts,int index,const char * colour_name)289 void colour_scheme_set_palette_entry(Options * opts, int index,
290         const char *colour_name)
291 {
292     ColourScheme *scheme;
293     char key[8];
294     GdkRGBA *colour;
295 
296     g_return_if_fail(opts);
297     g_return_if_fail(colour_name);
298     g_return_if_fail(index >= 0 && index < 16);
299     scheme = options_get_data(opts);
300     g_return_if_fail(scheme);
301     colour = &scheme->palette[index];
302     sprintf(key, "%d", index);
303     colour_scheme_set_colour(opts, scheme, &colour, key, colour_name);
304 }
305 
colour_scheme_set_named_colour(Options * opts,const char * field_name,const char * colour_name,size_t member_offset)306 static void colour_scheme_set_named_colour(Options *opts,
307         const char *field_name,
308         const char *colour_name, size_t member_offset)
309 {
310     ColourScheme *scheme;
311     GdkRGBA **member;
312 
313     g_return_if_fail(opts);
314     scheme = options_get_data(opts);
315     g_return_if_fail(scheme);
316     member = (GdkRGBA **) (((char *) scheme) + member_offset);
317     colour_scheme_set_colour(opts, scheme, member,
318             field_name, colour_name);
319 }
320 
colour_scheme_set_cursor_colour(Options * opts,const char * colour_name)321 void colour_scheme_set_cursor_colour(Options * opts, const char *colour_name)
322 {
323     colour_scheme_set_named_colour(opts, "cursor", colour_name,
324             offsetof(ColourScheme, cursor));
325 }
326 
colour_scheme_set_cursorfg_colour(Options * opts,const char * colour_name)327 void colour_scheme_set_cursorfg_colour(Options * opts, const char *colour_name)
328 {
329     colour_scheme_set_named_colour(opts, "cursorfg", colour_name,
330             offsetof(ColourScheme, cursorfg));
331 }
332 
colour_scheme_set_foreground_colour(Options * opts,const char * colour_name)333 void colour_scheme_set_foreground_colour(Options * opts,
334         const char *colour_name)
335 {
336     colour_scheme_set_named_colour(opts, "foreground", colour_name,
337             offsetof(ColourScheme, foreground));
338 }
339 
colour_scheme_set_background_colour(Options * opts,const char * colour_name)340 void colour_scheme_set_background_colour(Options * opts,
341         const char *colour_name)
342 {
343     colour_scheme_set_named_colour(opts, "background", colour_name,
344             offsetof(ColourScheme, background));
345 }
346 
colour_scheme_set_bold_colour(Options * opts,const char * colour_name)347 void colour_scheme_set_bold_colour(Options * opts,
348         const char *colour_name)
349 {
350     colour_scheme_set_named_colour(opts, "bold", colour_name,
351             offsetof(ColourScheme, bold));
352 }
353 
354 /* vi:set sw=4 ts=4 noet cindent cino= */
355