]> icculus.org git repositories - dana/openbox.git/blob - engines/concept2/frame_concept2_config.c
Implement plugin engine to draw frame (Follow Master patch)
[dana/openbox.git] / engines / concept2 / frame_concept2_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 "frame_concept2_config.h"
21 #include "frame_concept2_plugin.h"
22
23 #include "render/render.h"
24 #include "render/color.h"
25 #include "render/font.h"
26 #include "render/mask.h"
27 #include "render/icon.h"
28 #include "parser/parse.h"
29
30 #include <X11/Xlib.h>
31
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 static XrmDatabase loaddb(const gchar *name, gchar **path);
37 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
38 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
39 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
40         const gchar *rname, RrColor **value);
41 static gboolean read_mask(const RrInstance *inst, const gchar *path,
42         ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value);
43 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
44         const gchar *rname, RrAppearance *value, gboolean allow_trans);
45 static int parse_inline_number(const char *p);
46 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
47 static void set_default_appearance(RrAppearance *a);
48
49 gint load_theme_config(const RrInstance *inst, const gchar *name,
50         const gchar * path, XrmDatabase db, RrFont *active_window_font,
51         RrFont *inactive_window_font, RrFont *menu_title_font,
52         RrFont *menu_item_font, RrFont *osd_font)
53 {
54     gchar *str;
55
56     if (!read_int(db, "concept.border_width", &theme_config.border_width)) {
57         theme_config.border_width = 2;
58     }
59     if (!read_int(db, "concept.left_width", &theme_config.left_width)) {
60         theme_config.left_width = 15;
61     }
62     if (!read_color(db, inst, "concept.focus_border_color",
63             &theme_config.focus_border_color)) {
64         theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
65     }
66
67     if (!read_color(db, inst, "concept.focus_corner_color",
68             &theme_config.focus_corner_color)) {
69         theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
70     }
71
72     if (!read_color(db, inst, "concept.unfocus_border_color",
73             &theme_config.unfocus_border_color)) {
74         theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
75     }
76
77     if (!read_color(db, inst, "concept.unfocus_corner_color",
78             &theme_config.unfocus_corner_color)) {
79         theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
80     }
81
82     theme_config.inst = inst;
83     theme_config.name = g_strdup(name ? name : DEFAULT_THEME);
84
85     return 1;
86 }
87
88 static XrmDatabase loaddb(const gchar *name, gchar **path)
89 {
90     GSList *it;
91     XrmDatabase db = NULL;
92     gchar *s;
93
94     if (name[0] == '/') {
95         s = g_build_filename(name, "openbox-3", "themerc", NULL);
96         if ((db = XrmGetFileDatabase(s)))
97             *path = g_path_get_dirname(s);
98         g_free(s);
99     }
100     else {
101         /* XXX backwards compatibility, remove me sometime later */
102         s = g_build_filename(g_get_home_dir(), ".themes", name, "openbox-3",
103                 "themerc", NULL);
104         if ((db = XrmGetFileDatabase(s)))
105             *path = g_path_get_dirname(s);
106         g_free(s);
107
108         for (it = parse_xdg_data_dir_paths(); !db && it; it = g_slist_next(it)) {
109             s = g_build_filename(it->data, "themes", name, "openbox-3",
110                     "themerc", NULL);
111             if ((db = XrmGetFileDatabase(s)))
112                 *path = g_path_get_dirname(s);
113             g_free(s);
114         }
115     }
116
117     if (db == NULL) {
118         s = g_build_filename(name, "themerc", NULL);
119         if ((db = XrmGetFileDatabase(s)))
120             *path = g_path_get_dirname(s);
121         g_free(s);
122     }
123
124     return db;
125 }
126
127 static gchar *create_class_name(const gchar *rname)
128 {
129     gchar *rclass = g_strdup(rname);
130     gchar *p = rclass;
131
132     while (TRUE) {
133         *p = toupper(*p);
134         p = strchr(p+1, '.');
135         if (p == NULL)
136             break;
137         ++p;
138         if (*p == '\0')
139             break;
140     }
141     return rclass;
142 }
143
144 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
145 {
146     gboolean ret = FALSE;
147     gchar *rclass = create_class_name(rname);
148     gchar *rettype, *end;
149     XrmValue retvalue;
150
151     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
152             != NULL) {
153         *value = (gint)strtol(retvalue.addr, &end, 10);
154         if (end != retvalue.addr)
155             ret = TRUE;
156     }
157
158     g_free(rclass);
159     return ret;
160 }
161
162 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
163 {
164     gboolean ret = FALSE;
165     gchar *rclass = create_class_name(rname);
166     gchar *rettype;
167     XrmValue retvalue;
168
169     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
170             != NULL) {
171         *value = retvalue.addr;
172         ret = TRUE;
173     }
174
175     g_free(rclass);
176     return ret;
177 }
178
179 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
180         const gchar *rname, RrColor **value)
181 {
182     gboolean ret = FALSE;
183     gchar *rclass = create_class_name(rname);
184     gchar *rettype;
185     XrmValue retvalue;
186
187     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
188             != NULL) {
189         RrColor *c = RrColorParse(inst, retvalue.addr);
190         if (c != NULL) {
191             *value = c;
192             ret = TRUE;
193         }
194     }
195
196     g_free(rclass);
197     return ret;
198 }
199
200 static gboolean read_mask(const RrInstance *inst, const gchar *path,
201         ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value)
202 {
203     gboolean ret = FALSE;
204     gchar *s;
205     gint hx, hy; /* ignored */
206     guint w, h;
207     guchar *b;
208
209     s = g_build_filename(path, maskname, NULL);
210     if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
211         ret = TRUE;
212         *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
213         XFree(b);
214     }
215     g_free(s);
216
217     return ret;
218 }
219
220 static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
221         RrReliefType *relief, RrBevelType *bevel, gboolean *interlaced,
222         gboolean *border, gboolean allow_trans)
223 {
224     gchar *t;
225
226     /* convert to all lowercase */
227     for (t = tex; *t != '\0'; ++t)
228         *t = g_ascii_tolower(*t);
229
230     if (allow_trans && strstr(tex, "parentrelative") != NULL) {
231         *grad = RR_SURFACE_PARENTREL;
232     }
233     else {
234         if (strstr(tex, "gradient") != NULL) {
235             if (strstr(tex, "crossdiagonal") != NULL)
236                 *grad = RR_SURFACE_CROSS_DIAGONAL;
237             else if (strstr(tex, "pyramid") != NULL)
238                 *grad = RR_SURFACE_PYRAMID;
239             else if (strstr(tex, "mirrorhorizontal") != NULL)
240                 *grad = RR_SURFACE_MIRROR_HORIZONTAL;
241             else if (strstr(tex, "horizontal") != NULL)
242                 *grad = RR_SURFACE_HORIZONTAL;
243             else if (strstr(tex, "splitvertical") != NULL)
244                 *grad = RR_SURFACE_SPLIT_VERTICAL;
245             else if (strstr(tex, "vertical") != NULL)
246                 *grad = RR_SURFACE_VERTICAL;
247             else
248                 *grad = RR_SURFACE_DIAGONAL;
249         }
250         else {
251             *grad = RR_SURFACE_SOLID;
252         }
253     }
254
255     if (strstr(tex, "sunken") != NULL)
256         *relief = RR_RELIEF_SUNKEN;
257     else if (strstr(tex, "flat") != NULL)
258         *relief = RR_RELIEF_FLAT;
259     else if (strstr(tex, "raised") != NULL)
260         *relief = RR_RELIEF_RAISED;
261     else
262         *relief = (*grad == RR_SURFACE_PARENTREL) ? RR_RELIEF_FLAT
263                 : RR_RELIEF_RAISED;
264
265     *border = FALSE;
266     if (*relief == RR_RELIEF_FLAT) {
267         if (strstr(tex, "border") != NULL)
268             *border = TRUE;
269     }
270     else {
271         if (strstr(tex, "bevel2") != NULL)
272             *bevel = RR_BEVEL_2;
273         else
274             *bevel = RR_BEVEL_1;
275     }
276
277     if (strstr(tex, "interlaced") != NULL)
278         *interlaced = TRUE;
279     else
280         *interlaced = FALSE;
281 }
282
283 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
284         const gchar *rname, RrAppearance *value, gboolean allow_trans)
285 {
286     gboolean ret = FALSE;
287     gchar *rclass = create_class_name(rname);
288     gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
289     gchar *csplitname, *ctosplitname;
290     gchar *rettype;
291     XrmValue retvalue;
292     gint i;
293
294     cname = g_strconcat(rname, ".color", NULL);
295     ctoname = g_strconcat(rname, ".colorTo", NULL);
296     bcname = g_strconcat(rname, ".border.color", NULL);
297     icname = g_strconcat(rname, ".interlace.color", NULL);
298     hname = g_strconcat(rname, ".highlight", NULL);
299     sname = g_strconcat(rname, ".shadow", NULL);
300     csplitname = g_strconcat(rname, ".color.splitTo", NULL);
301     ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
302
303     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
304             != NULL) {
305         parse_appearance(retvalue.addr, &value->surface.grad,
306                 &value->surface.relief, &value->surface.bevel,
307                 &value->surface.interlaced, &value->surface.border, allow_trans);
308         if (!read_color(db, inst, cname, &value->surface.primary))
309             value->surface.primary = RrColorNew(inst, 0, 0, 0);
310         if (!read_color(db, inst, ctoname, &value->surface.secondary))
311             value->surface.secondary = RrColorNew(inst, 0, 0, 0);
312         if (value->surface.border)
313             if (!read_color(db, inst, bcname, &value->surface.border_color))
314                 value->surface.border_color = RrColorNew(inst, 0, 0, 0);
315         if (value->surface.interlaced)
316             if (!read_color(db, inst, icname, &value->surface.interlace_color))
317                 value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
318         if (read_int(db, hname, &i) && i >= 0)
319             value->surface.bevel_light_adjust = i;
320         if (read_int(db, sname, &i) && i >= 0 && i <= 256)
321             value->surface.bevel_dark_adjust = i;
322
323         if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
324             gint r, g, b;
325
326             if (!read_color(db, inst, csplitname, &value->surface.split_primary)) {
327                 r = value->surface.primary->r;
328                 r += r >> 2;
329                 g = value->surface.primary->g;
330                 g += g >> 2;
331                 b = value->surface.primary->b;
332                 b += b >> 2;
333                 if (r > 0xFF)
334                     r = 0xFF;
335                 if (g > 0xFF)
336                     g = 0xFF;
337                 if (b > 0xFF)
338                     b = 0xFF;
339                 value->surface.split_primary = RrColorNew(inst, r, g, b);
340             }
341
342             if (!read_color(db, inst, ctosplitname,
343                     &value->surface.split_secondary)) {
344                 r = value->surface.secondary->r;
345                 r += r >> 4;
346                 g = value->surface.secondary->g;
347                 g += g >> 4;
348                 b = value->surface.secondary->b;
349                 b += b >> 4;
350                 if (r > 0xFF)
351                     r = 0xFF;
352                 if (g > 0xFF)
353                     g = 0xFF;
354                 if (b > 0xFF)
355                     b = 0xFF;
356                 value->surface.split_secondary = RrColorNew(inst, r, g, b);
357             }
358         }
359
360         ret = TRUE;
361     }
362
363     g_free(ctosplitname);
364     g_free(csplitname);
365     g_free(sname);
366     g_free(hname);
367     g_free(icname);
368     g_free(bcname);
369     g_free(ctoname);
370     g_free(cname);
371     g_free(rclass);
372     return ret;
373 }
374
375 static int parse_inline_number(const char *p)
376 {
377     int neg = 1;
378     int res = 0;
379     if (*p == '-') {
380         neg = -1;
381         ++p;
382     }
383     for (; isdigit(*p); ++p)
384         res = res * 10 + *p - '0';
385     res *= neg;
386     return res;
387 }
388
389 static void set_default_appearance(RrAppearance *a)
390 {
391     a->surface.grad = RR_SURFACE_SOLID;
392     a->surface.relief = RR_RELIEF_FLAT;
393     a->surface.bevel = RR_BEVEL_1;
394     a->surface.interlaced = FALSE;
395     a->surface.border = FALSE;
396     a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
397     a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
398 }
399
400 /* Reads the output from gimp's C-Source file format into valid RGBA data for
401  an RrTextureRGBA. */
402 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
403 {
404     RrPixel32 *im, *p;
405     gint i;
406
407     p = im = g_memdup(data, width * height * sizeof(RrPixel32));
408
409     for (i = 0; i < width * height; ++i) {
410         guchar a = ((*p >> 24) & 0xff);
411         guchar b = ((*p >> 16) & 0xff);
412         guchar g = ((*p >> 8) & 0xff);
413         guchar r = ((*p >> 0) & 0xff);
414
415         *p = ((r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset) + (b
416                 << RrDefaultBlueOffset) + (a << RrDefaultAlphaOffset));
417         p++;
418     }
419
420     return im;
421 }