]> icculus.org git repositories - dana/openbox.git/blob - engines/concept/config.c
Rename ObFramePlugin to ObFrameEngine
[dana/openbox.git] / engines / concept / config.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3  frame_default_config.c for the Openbox window manager
4  Copyright (c) 2006        Mikael Magnusson
5  Copyright (c) 2003-2007   Dana Jansens
6
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16
17  See the COPYING file for a copy of the GNU General Public License.
18  */
19
20 #include <X11/Xlib.h>
21
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "render/render.h"
27 #include "render/color.h"
28 #include "render/font.h"
29 #include "render/mask.h"
30 #include "render/icon.h"
31 #include "obt/parse.h"
32
33 #include "config.h"
34 #include "plugin.h"
35
36 void load_pixmap(const gchar * theme_name, const gchar * base_name,
37         GdkPixbuf ** gp, Pixmap * p);
38 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
39 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
40 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
41         const gchar *rname, RrColor **value);
42 static gboolean read_mask(const RrInstance *inst, const gchar *path,
43         ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value);
44 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
45         const gchar *rname, RrAppearance *value, gboolean allow_trans);
46 static int parse_inline_number(const char *p);
47 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
48 static void set_default_appearance(RrAppearance *a);
49
50 gint load_theme_config(const RrInstance *inst, const gchar *name,
51         const gchar * path, XrmDatabase db, RrFont *active_window_font,
52         RrFont *inactive_window_font, RrFont *menu_title_font,
53         RrFont *menu_item_font, RrFont *osd_font)
54 {
55     gchar *str;
56
57     if (!read_int(db, "concept.border_width", &theme_config.border_width)) {
58         theme_config.border_width = 2;
59     }
60     if (!read_color(db, inst, "concept.focus_border_color",
61             &theme_config.focus_border_color)) {
62         theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
63     }
64
65     if (!read_color(db, inst, "concept.focus_corner_color",
66             &theme_config.focus_corner_color)) {
67         theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
68     }
69
70     if (!read_color(db, inst, "concept.unfocus_border_color",
71             &theme_config.unfocus_border_color)) {
72         theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
73     }
74
75     if (!read_color(db, inst, "concept.unfocus_corner_color",
76             &theme_config.unfocus_corner_color)) {
77         theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
78     }
79
80     theme_config.inst = inst;
81     theme_config.name = g_strdup(name ? name : DEFAULT_THEME);
82
83     gdk_pixbuf_xlib_init(plugin.ob_display, plugin.ob_screen);
84
85     load_pixmap(name, "focus-top.png", &theme_config.focus_top,
86             &theme_config.px_focus_top);
87     load_pixmap(name, "focus-left.png", &theme_config.focus_left,
88             &theme_config.px_focus_left);
89     load_pixmap(name, "focus-right.png", &theme_config.focus_right,
90             &theme_config.px_focus_right);
91     load_pixmap(name, "focus-bottom.png", &theme_config.focus_bottom,
92             &theme_config.px_focus_bottom);
93
94     load_pixmap(name, "unfocus-top.png", &theme_config.unfocus_top,
95             &theme_config.px_unfocus_top);
96     load_pixmap(name, "unfocus-left.png", &theme_config.unfocus_left,
97             &theme_config.px_unfocus_left);
98     load_pixmap(name, "unfocus-right.png", &theme_config.unfocus_right,
99             &theme_config.px_unfocus_right);
100     load_pixmap(name, "unfocus-bottom.png", &theme_config.unfocus_bottom,
101             &theme_config.px_unfocus_bottom);
102
103     load_pixmap(name, "focus-topleft.png", &theme_config.focus_topleft,
104             &theme_config.px_focus_topleft);
105     load_pixmap(name, "focus-bottomleft.png", &theme_config.focus_bottomleft,
106             &theme_config.px_focus_bottomleft);
107     load_pixmap(name, "focus-topright.png", &theme_config.focus_topright,
108             &theme_config.px_focus_topright);
109     load_pixmap(name, "focus-bottomright.png", &theme_config.focus_bottomright,
110             &theme_config.px_focus_bottomright);
111
112     load_pixmap(name, "unfocus-topleft.png", &theme_config.unfocus_topleft,
113             &theme_config.px_unfocus_topleft);
114     load_pixmap(name, "unfocus-bottomleft.png",
115             &theme_config.unfocus_bottomleft,
116             &theme_config.px_unfocus_bottomleft);
117     load_pixmap(name, "unfocus-topright.png", &theme_config.unfocus_topright,
118             &theme_config.px_unfocus_topright);
119     load_pixmap(name, "unfocus-bottomright.png",
120             &theme_config.unfocus_bottomright,
121             &theme_config.px_unfocus_bottomright);
122
123     return 1;
124 }
125
126 void load_pixmap(const gchar * theme_name, const gchar * base_name,
127         GdkPixbuf ** gp, Pixmap * p)
128 {
129     gchar * s = g_build_filename(g_get_home_dir(), ".themes", theme_name,
130             "openbox-3", base_name, NULL);
131     ob_debug("Load file %s.\n", s);
132     *gp = gdk_pixbuf_new_from_file(s, NULL);
133     //GdkPixbuff * mask = NULL;
134     gdk_pixbuf_xlib_render_pixmap_and_mask(*gp, p, NULL, 128);
135     g_free(s);
136 }
137
138 static gchar *create_class_name(const gchar *rname)
139 {
140     gchar *rclass = g_strdup(rname);
141     gchar *p = rclass;
142
143     while (TRUE) {
144         *p = toupper(*p);
145         p = strchr(p+1, '.');
146         if (p == NULL)
147             break;
148         ++p;
149         if (*p == '\0')
150             break;
151     }
152     return rclass;
153 }
154
155 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
156 {
157     gboolean ret = FALSE;
158     gchar *rclass = create_class_name(rname);
159     gchar *rettype, *end;
160     XrmValue retvalue;
161
162     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
163             != NULL) {
164         *value = (gint)strtol(retvalue.addr, &end, 10);
165         if (end != retvalue.addr)
166             ret = TRUE;
167     }
168
169     g_free(rclass);
170     return ret;
171 }
172
173 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
174 {
175     gboolean ret = FALSE;
176     gchar *rclass = create_class_name(rname);
177     gchar *rettype;
178     XrmValue retvalue;
179
180     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
181             != NULL) {
182         *value = retvalue.addr;
183         ret = TRUE;
184     }
185
186     g_free(rclass);
187     return ret;
188 }
189
190 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
191         const gchar *rname, RrColor **value)
192 {
193     gboolean ret = FALSE;
194     gchar *rclass = create_class_name(rname);
195     gchar *rettype;
196     XrmValue retvalue;
197
198     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
199             != NULL) {
200         RrColor *c = RrColorParse(inst, retvalue.addr);
201         if (c != NULL) {
202             *value = c;
203             ret = TRUE;
204         }
205     }
206
207     g_free(rclass);
208     return ret;
209 }
210
211 static gboolean read_mask(const RrInstance *inst, const gchar *path,
212         ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value)
213 {
214     gboolean ret = FALSE;
215     gchar *s;
216     gint hx, hy; /* ignored */
217     guint w, h;
218     guchar *b;
219
220     s = g_build_filename(path, maskname, NULL);
221     if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
222         ret = TRUE;
223         *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
224         XFree(b);
225     }
226     g_free(s);
227
228     return ret;
229 }
230
231 static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
232         RrReliefType *relief, RrBevelType *bevel, gboolean *interlaced,
233         gboolean *border, gboolean allow_trans)
234 {
235     gchar *t;
236
237     /* convert to all lowercase */
238     for (t = tex; *t != '\0'; ++t)
239         *t = g_ascii_tolower(*t);
240
241     if (allow_trans && strstr(tex, "parentrelative") != NULL) {
242         *grad = RR_SURFACE_PARENTREL;
243     }
244     else {
245         if (strstr(tex, "gradient") != NULL) {
246             if (strstr(tex, "crossdiagonal") != NULL)
247                 *grad = RR_SURFACE_CROSS_DIAGONAL;
248             else if (strstr(tex, "pyramid") != NULL)
249                 *grad = RR_SURFACE_PYRAMID;
250             else if (strstr(tex, "mirrorhorizontal") != NULL)
251                 *grad = RR_SURFACE_MIRROR_HORIZONTAL;
252             else if (strstr(tex, "horizontal") != NULL)
253                 *grad = RR_SURFACE_HORIZONTAL;
254             else if (strstr(tex, "splitvertical") != NULL)
255                 *grad = RR_SURFACE_SPLIT_VERTICAL;
256             else if (strstr(tex, "vertical") != NULL)
257                 *grad = RR_SURFACE_VERTICAL;
258             else
259                 *grad = RR_SURFACE_DIAGONAL;
260         }
261         else {
262             *grad = RR_SURFACE_SOLID;
263         }
264     }
265
266     if (strstr(tex, "sunken") != NULL)
267         *relief = RR_RELIEF_SUNKEN;
268     else if (strstr(tex, "flat") != NULL)
269         *relief = RR_RELIEF_FLAT;
270     else if (strstr(tex, "raised") != NULL)
271         *relief = RR_RELIEF_RAISED;
272     else
273         *relief = (*grad == RR_SURFACE_PARENTREL) ? RR_RELIEF_FLAT
274                 : RR_RELIEF_RAISED;
275
276     *border = FALSE;
277     if (*relief == RR_RELIEF_FLAT) {
278         if (strstr(tex, "border") != NULL)
279             *border = TRUE;
280     }
281     else {
282         if (strstr(tex, "bevel2") != NULL)
283             *bevel = RR_BEVEL_2;
284         else
285             *bevel = RR_BEVEL_1;
286     }
287
288     if (strstr(tex, "interlaced") != NULL)
289         *interlaced = TRUE;
290     else
291         *interlaced = FALSE;
292 }
293
294 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
295         const gchar *rname, RrAppearance *value, gboolean allow_trans)
296 {
297     gboolean ret = FALSE;
298     gchar *rclass = create_class_name(rname);
299     gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
300     gchar *csplitname, *ctosplitname;
301     gchar *rettype;
302     XrmValue retvalue;
303     gint i;
304
305     cname = g_strconcat(rname, ".color", NULL);
306     ctoname = g_strconcat(rname, ".colorTo", NULL);
307     bcname = g_strconcat(rname, ".border.color", NULL);
308     icname = g_strconcat(rname, ".interlace.color", NULL);
309     hname = g_strconcat(rname, ".highlight", NULL);
310     sname = g_strconcat(rname, ".shadow", NULL);
311     csplitname = g_strconcat(rname, ".color.splitTo", NULL);
312     ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
313
314     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
315             != NULL) {
316         parse_appearance(retvalue.addr, &value->surface.grad,
317                 &value->surface.relief, &value->surface.bevel,
318                 &value->surface.interlaced, &value->surface.border, allow_trans);
319         if (!read_color(db, inst, cname, &value->surface.primary))
320             value->surface.primary = RrColorNew(inst, 0, 0, 0);
321         if (!read_color(db, inst, ctoname, &value->surface.secondary))
322             value->surface.secondary = RrColorNew(inst, 0, 0, 0);
323         if (value->surface.border)
324             if (!read_color(db, inst, bcname, &value->surface.border_color))
325                 value->surface.border_color = RrColorNew(inst, 0, 0, 0);
326         if (value->surface.interlaced)
327             if (!read_color(db, inst, icname, &value->surface.interlace_color))
328                 value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
329         if (read_int(db, hname, &i) && i >= 0)
330             value->surface.bevel_light_adjust = i;
331         if (read_int(db, sname, &i) && i >= 0 && i <= 256)
332             value->surface.bevel_dark_adjust = i;
333
334         if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
335             gint r, g, b;
336
337             if (!read_color(db, inst, csplitname, &value->surface.split_primary)) {
338                 r = value->surface.primary->r;
339                 r += r >> 2;
340                 g = value->surface.primary->g;
341                 g += g >> 2;
342                 b = value->surface.primary->b;
343                 b += b >> 2;
344                 if (r > 0xFF)
345                     r = 0xFF;
346                 if (g > 0xFF)
347                     g = 0xFF;
348                 if (b > 0xFF)
349                     b = 0xFF;
350                 value->surface.split_primary = RrColorNew(inst, r, g, b);
351             }
352
353             if (!read_color(db, inst, ctosplitname,
354                     &value->surface.split_secondary)) {
355                 r = value->surface.secondary->r;
356                 r += r >> 4;
357                 g = value->surface.secondary->g;
358                 g += g >> 4;
359                 b = value->surface.secondary->b;
360                 b += b >> 4;
361                 if (r > 0xFF)
362                     r = 0xFF;
363                 if (g > 0xFF)
364                     g = 0xFF;
365                 if (b > 0xFF)
366                     b = 0xFF;
367                 value->surface.split_secondary = RrColorNew(inst, r, g, b);
368             }
369         }
370
371         ret = TRUE;
372     }
373
374     g_free(ctosplitname);
375     g_free(csplitname);
376     g_free(sname);
377     g_free(hname);
378     g_free(icname);
379     g_free(bcname);
380     g_free(ctoname);
381     g_free(cname);
382     g_free(rclass);
383     return ret;
384 }
385
386 static int parse_inline_number(const char *p)
387 {
388     int neg = 1;
389     int res = 0;
390     if (*p == '-') {
391         neg = -1;
392         ++p;
393     }
394     for (; isdigit(*p); ++p)
395         res = res * 10 + *p - '0';
396     res *= neg;
397     return res;
398 }
399
400 static void set_default_appearance(RrAppearance *a)
401 {
402     a->surface.grad = RR_SURFACE_SOLID;
403     a->surface.relief = RR_RELIEF_FLAT;
404     a->surface.bevel = RR_BEVEL_1;
405     a->surface.interlaced = FALSE;
406     a->surface.border = FALSE;
407     a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
408     a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
409 }
410
411 /* Reads the output from gimp's C-Source file format into valid RGBA data for
412  an RrTextureRGBA. */
413 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
414 {
415     RrPixel32 *im, *p;
416     gint i;
417
418     p = im = g_memdup(data, width * height * sizeof(RrPixel32));
419
420     for (i = 0; i < width * height; ++i) {
421         guchar a = ((*p >> 24) & 0xff);
422         guchar b = ((*p >> 16) & 0xff);
423         guchar g = ((*p >> 8) & 0xff);
424         guchar r = ((*p >> 0) & 0xff);
425
426         *p = ((r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset) + (b
427                 << RrDefaultBlueOffset) + (a << RrDefaultAlphaOffset));
428         p++;
429     }
430
431     return im;
432 }