e927b82cf8b9b94600b966003bd7e15d4c840510
[dana/openbox.git] / obrender / theme.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    theme.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 "render.h"
21 #include "color.h"
22 #include "font.h"
23 #include "mask.h"
24 #include "theme.h"
25 #include "icon.h"
26 #include "obt/paths.h"
27
28 #include <X11/Xlib.h>
29 #include <X11/Xresource.h>
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 static XrmDatabase loaddb(const gchar *name, gchar **path);
35 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
36 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
37 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
38                            const gchar *rname, RrColor **value);
39 static gboolean read_mask(const RrInstance *inst, const gchar *path,
40                           RrTheme *theme, const gchar *maskname,
41                           RrPixmapMask **value);
42 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
43                                 const gchar *rname, RrAppearance *value,
44                                 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 static RrFont *get_font(RrFont *target, RrFont **default_font,
50                         const RrInstance *inst)
51 {
52     if (target) {
53         RrFontRef(target);
54         return target;
55     } else {
56         /* Only load the default font once */
57         if (*default_font) {
58             RrFontRef(*default_font);
59         } else {
60             *default_font = RrFontOpenDefault(inst);
61         }
62         return *default_font;
63     }
64 }
65
66 #define READ_INT(x_resstr, x_var, x_min, x_max, x_def) \
67     if (!read_int(db, x_resstr, & x_var) || \
68             x_var < x_min || x_var > x_max) \
69         x_var = x_def;
70
71 #define READ_COLOR(x_resstr, x_var, x_def) \
72     if (!read_color(db, inst, x_resstr, & x_var)) \
73         x_var = x_def;
74
75 #define READ_COLOR_(x_res1, x_res2, x_var, x_def) \
76     if (!read_color(db, inst, x_res1, & x_var) && \
77         !read_color(db, inst, x_res2, & x_var)) \
78         x_var = x_def;
79
80 #define READ_MASK_COPY(x_file, x_var, x_copysrc) \
81     if (!read_mask(inst, path, theme, x_file, & x_var)) \
82         x_var = RrPixmapMaskCopy(x_copysrc);
83
84 #define READ_APPEARANCE(x_resstr, x_var, x_parrel) \
85     if (!read_appearance(db, inst, x_resstr, x_var, x_parrel)) \
86         set_default_appearance(x_var);
87
88 #define READ_APPEARANCE_COPY(x_resstr, x_var, x_parrel, x_defval) \
89     if (!read_appearance(db, inst, x_resstr, x_var, x_parrel)) {\
90         RrAppearanceFree(x_var); \
91         x_var = RrAppearanceCopy(x_defval); }
92
93 #define READ_APPEARANCE_(x_res1, x_res2, x_var, x_parrel, x_defval) \
94     if (!read_appearance(db, inst, x_res1, x_var, x_parrel) && \
95         !read_appearance(db, inst, x_res2, x_var, x_parrel)) {\
96         RrAppearanceFree(x_var); \
97         x_var = RrAppearanceCopy(x_defval); }
98
99 RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name,
100                     gboolean allow_fallback,
101                     RrFont *active_window_font, RrFont *inactive_window_font,
102                     RrFont *menu_title_font, RrFont *menu_item_font,
103                     RrFont *active_osd_font, RrFont *inactive_osd_font)
104 {
105     XrmDatabase db = NULL;
106     RrJustify winjust, mtitlejust;
107     gchar *str;
108     RrTheme *theme;
109     RrFont *default_font = NULL;
110     gchar *path;
111     gboolean userdef;
112     gint menu_overlap = 0;
113     RrAppearance *a_disabled_focused_tmp;
114     RrAppearance *a_disabled_unfocused_tmp;
115     RrAppearance *a_hover_focused_tmp;
116     RrAppearance *a_hover_unfocused_tmp;
117     RrAppearance *a_focused_unpressed_tmp;
118     RrAppearance *a_focused_pressed_tmp;
119     RrAppearance *a_unfocused_unpressed_tmp;
120     RrAppearance *a_unfocused_pressed_tmp;
121     RrAppearance *a_toggled_hover_focused_tmp;
122     RrAppearance *a_toggled_hover_unfocused_tmp;
123     RrAppearance *a_toggled_focused_unpressed_tmp;
124     RrAppearance *a_toggled_focused_pressed_tmp;
125     RrAppearance *a_toggled_unfocused_unpressed_tmp;
126     RrAppearance *a_toggled_unfocused_pressed_tmp;
127
128     if (name) {
129         db = loaddb(name, &path);
130         if (db == NULL) {
131             g_message("Unable to load the theme '%s'", name);
132             if (allow_fallback)
133                 g_message("Falling back to the default theme '%s'",
134                           DEFAULT_THEME);
135             /* fallback to the default theme */
136             name = NULL;
137         }
138     }
139     if (name == NULL) {
140         if (allow_fallback) {
141             db = loaddb(DEFAULT_THEME, &path);
142             if (db == NULL) {
143                 g_message("Unable to load the theme '%s'", DEFAULT_THEME);
144                 return NULL;
145             }
146         } else
147             return NULL;
148     }
149
150     /* initialize temp reading textures */
151     a_disabled_focused_tmp = RrAppearanceNew(inst, 1);
152     a_disabled_unfocused_tmp = RrAppearanceNew(inst, 1);
153     a_hover_focused_tmp = RrAppearanceNew(inst, 1);
154     a_hover_unfocused_tmp = RrAppearanceNew(inst, 1);
155     a_toggled_focused_unpressed_tmp = RrAppearanceNew(inst, 1);
156     a_toggled_unfocused_unpressed_tmp = RrAppearanceNew(inst, 1);
157     a_toggled_hover_focused_tmp = RrAppearanceNew(inst, 1);
158     a_toggled_hover_unfocused_tmp = RrAppearanceNew(inst, 1);
159     a_toggled_focused_pressed_tmp = RrAppearanceNew(inst, 1);
160     a_toggled_unfocused_pressed_tmp = RrAppearanceNew(inst, 1);
161     a_focused_unpressed_tmp = RrAppearanceNew(inst, 1);
162     a_focused_pressed_tmp = RrAppearanceNew(inst, 1);
163     a_unfocused_unpressed_tmp = RrAppearanceNew(inst, 1);
164     a_unfocused_pressed_tmp = RrAppearanceNew(inst, 1);
165
166     /* initialize theme */
167     theme = g_slice_new0(RrTheme, 1);
168
169     theme->inst = inst;
170     theme->name = g_strdup(name ? name : DEFAULT_THEME);
171
172     theme->a_disabled_focused_max = RrAppearanceNew(inst, 1);
173     theme->a_disabled_unfocused_max = RrAppearanceNew(inst, 1);
174     theme->a_hover_focused_max = RrAppearanceNew(inst, 1);
175     theme->a_hover_unfocused_max = RrAppearanceNew(inst, 1);
176     theme->a_toggled_focused_unpressed_max = RrAppearanceNew(inst, 1);
177     theme->a_toggled_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
178     theme->a_toggled_hover_focused_max = RrAppearanceNew(inst, 1);
179     theme->a_toggled_hover_unfocused_max = RrAppearanceNew(inst, 1);
180     theme->a_toggled_focused_pressed_max = RrAppearanceNew(inst, 1);
181     theme->a_toggled_unfocused_pressed_max = RrAppearanceNew(inst, 1);
182     theme->a_focused_unpressed_max = RrAppearanceNew(inst, 1);
183     theme->a_focused_pressed_max = RrAppearanceNew(inst, 1);
184     theme->a_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
185     theme->a_unfocused_pressed_max = RrAppearanceNew(inst, 1);
186     theme->a_focused_grip = RrAppearanceNew(inst, 0);
187     theme->a_unfocused_grip = RrAppearanceNew(inst, 0);
188     theme->a_focused_title = RrAppearanceNew(inst, 0);
189     theme->a_unfocused_title = RrAppearanceNew(inst, 0);
190     theme->a_focused_label = RrAppearanceNew(inst, 1);
191     theme->a_unfocused_label = RrAppearanceNew(inst, 1);
192     theme->a_icon = RrAppearanceNew(inst, 1);
193     theme->a_focused_handle = RrAppearanceNew(inst, 0);
194     theme->a_unfocused_handle = RrAppearanceNew(inst, 0);
195     theme->a_menu = RrAppearanceNew(inst, 0);
196     theme->a_menu_title = RrAppearanceNew(inst, 0);
197     theme->a_menu_text_title = RrAppearanceNew(inst, 1);
198     theme->a_menu_normal = RrAppearanceNew(inst, 0);
199     theme->a_menu_selected = RrAppearanceNew(inst, 0);
200     theme->a_menu_disabled = RrAppearanceNew(inst, 0);
201     /* a_menu_disabled_selected is copied from a_menu_selected */
202     theme->a_menu_text_normal = RrAppearanceNew(inst, 1);
203     theme->a_menu_text_selected = RrAppearanceNew(inst, 1);
204     theme->a_menu_text_disabled = RrAppearanceNew(inst, 1);
205     theme->a_menu_text_disabled_selected = RrAppearanceNew(inst, 1);
206     theme->a_menu_bullet_normal = RrAppearanceNew(inst, 1);
207     theme->a_menu_bullet_selected = RrAppearanceNew(inst, 1);
208     theme->a_clear = RrAppearanceNew(inst, 0);
209     theme->a_clear_tex = RrAppearanceNew(inst, 1);
210     theme->osd_bg = RrAppearanceNew(inst, 0);
211     theme->osd_hilite_label = RrAppearanceNew(inst, 1);
212     theme->osd_hilite_bg = RrAppearanceNew(inst, 0);
213     theme->osd_unhilite_label = RrAppearanceNew(inst, 1);
214     theme->osd_unhilite_bg = RrAppearanceNew(inst, 0);
215
216     /* load the font stuff */
217     theme->win_font_focused = get_font(active_window_font,
218                                        &default_font, inst);
219     theme->win_font_unfocused = get_font(inactive_window_font,
220                                          &default_font, inst);
221
222     winjust = RR_JUSTIFY_LEFT;
223     if (read_string(db, "window.label.text.justify", &str)) {
224         if (!g_ascii_strcasecmp(str, "right"))
225             winjust = RR_JUSTIFY_RIGHT;
226         else if (!g_ascii_strcasecmp(str, "center"))
227             winjust = RR_JUSTIFY_CENTER;
228     }
229
230     theme->menu_title_font = get_font(menu_title_font, &default_font, inst);
231
232     mtitlejust = RR_JUSTIFY_LEFT;
233     if (read_string(db, "menu.title.text.justify", &str)) {
234         if (!g_ascii_strcasecmp(str, "right"))
235             mtitlejust = RR_JUSTIFY_RIGHT;
236         else if (!g_ascii_strcasecmp(str, "center"))
237             mtitlejust = RR_JUSTIFY_CENTER;
238     }
239
240     theme->menu_font = get_font(menu_item_font, &default_font, inst);
241
242     theme->osd_font_hilite = get_font(active_osd_font, &default_font, inst);
243     theme->osd_font_unhilite = get_font(inactive_osd_font, &default_font,inst);
244
245     /* load direct dimensions */
246     READ_INT("menu.overlap", menu_overlap, -100, 100, 0);
247     READ_INT("menu.overlap.x", theme->menu_overlap_x, -100, 100, menu_overlap);
248     READ_INT("menu.overlap.y", theme->menu_overlap_y, -100, 100, menu_overlap);
249     READ_INT("window.handle.width", theme->handle_height, 0, 100, 6);
250     READ_INT("padding.width", theme->paddingx, 0, 100, 3);
251     READ_INT("padding.height", theme->paddingy, 0, 100, theme->paddingx);
252     READ_INT("border.width", theme->fbwidth, 0, 100, 1);
253     READ_INT("menu.border.width", theme->mbwidth, 0, 100, theme->fbwidth);
254     READ_INT("osd.border.width", theme->obwidth, 0, 100, theme->fbwidth);
255     READ_INT("menu.separator.width", theme->menu_sep_width, 1, 100, 1);
256     READ_INT("menu.separator.padding.width", theme->menu_sep_paddingx, 0, 100, 6);
257     READ_INT("menu.separator.padding.height", theme->menu_sep_paddingy, 0, 100, 3);
258     READ_INT("window.client.padding.width", theme->cbwidthx, 0, 100,
259              theme->paddingx);
260     READ_INT("window.client.padding.height", theme->cbwidthy, 0, 100,
261              theme->cbwidthx);
262
263     /* load colors */
264     READ_COLOR_("window.active.border.color", "border.color",
265                 theme->frame_focused_border_color, RrColorNew(inst, 0, 0, 0));
266
267     /* title separator focused color inherits from focused border color */
268     READ_COLOR("window.active.title.separator.color",
269                theme->title_separator_focused_color,
270                RrColorCopy(theme->frame_focused_border_color));
271
272     /* unfocused border color inherits from frame focused border color */
273     READ_COLOR("window.inactive.border.color",
274                theme->frame_unfocused_border_color,
275                RrColorCopy(theme->frame_focused_border_color));
276
277     /* title separator unfocused color inherits from unfocused border color */
278     READ_COLOR("window.inactive.title.separator.color",
279                theme->title_separator_unfocused_color,
280                RrColorCopy(theme->frame_unfocused_border_color));
281
282     /* menu border color inherits from frame focused border color */
283     READ_COLOR("menu.border.color", theme->menu_border_color,
284                RrColorCopy(theme->frame_focused_border_color));
285
286     /* osd border color inherits from frame focused border color */
287     READ_COLOR("osd.border.color", theme->osd_border_color,
288                RrColorCopy(theme->frame_focused_border_color));
289
290     READ_COLOR("window.active.client.color", theme->cb_focused_color,
291                RrColorNew(inst, 0xff, 0xff, 0xff));
292
293     READ_COLOR("window.inactive.client.color", theme->cb_unfocused_color,
294                RrColorNew(inst, 0xff, 0xff, 0xff));
295
296     READ_COLOR("window.active.label.text.color", theme->title_focused_color,
297                RrColorNew(inst, 0x0, 0x0, 0x0));
298
299     READ_COLOR_("osd.active.label.text.color",
300                 "osd.label.text.color",
301                 theme->osd_color, RrColorCopy(theme->title_focused_color));
302
303     READ_COLOR("window.inactive.label.text.color", theme->title_unfocused_color,
304                RrColorCopy(theme->title_unfocused_color));
305
306     READ_COLOR("osd.inactive.label.text.color", theme->osd_text_inactive_color,
307                RrColorNew(inst, 0xff, 0xff, 0xff));
308
309     READ_COLOR("window.inactive.label.text.color",
310                theme->title_unfocused_color,
311                RrColorNew(inst, 0xff, 0xff, 0xff));
312
313     READ_COLOR("window.active.button.unpressed.image.color",
314                theme->titlebut_focused_unpressed_color,
315                RrColorNew(inst, 0, 0, 0));
316
317     READ_COLOR("window.inactive.button.unpressed.image.color",
318                theme->titlebut_unfocused_unpressed_color,
319                RrColorNew(inst, 0xff, 0xff, 0xff));
320
321     READ_COLOR("window.active.button.pressed.image.color",
322                theme->titlebut_focused_pressed_color,
323                RrColorCopy(theme->titlebut_focused_unpressed_color));
324
325     READ_COLOR("window.inactive.button.pressed.image.color",
326                theme->titlebut_unfocused_pressed_color,
327                RrColorCopy(theme->titlebut_unfocused_unpressed_color));
328
329     READ_COLOR("window.active.button.disabled.image.color",
330                theme->titlebut_disabled_focused_color,
331                RrColorNew(inst, 0xff, 0xff, 0xff));
332
333     READ_COLOR("window.inactive.button.disabled.image.color",
334                theme->titlebut_disabled_unfocused_color,
335                RrColorNew(inst, 0, 0, 0));
336
337     READ_COLOR("window.active.button.hover.image.color",
338                theme->titlebut_hover_focused_color,
339                RrColorCopy(theme->titlebut_focused_unpressed_color));
340
341     READ_COLOR("window.inactive.button.hover.image.color",
342                theme->titlebut_hover_unfocused_color,
343                RrColorCopy(theme->titlebut_unfocused_unpressed_color));
344
345     READ_COLOR_("window.active.button.toggled.unpressed.image.color",
346                 "window.active.button.toggled.image.color",
347                 theme->titlebut_toggled_focused_unpressed_color,
348                 RrColorCopy(theme->titlebut_focused_pressed_color));
349
350     READ_COLOR_("window.inactive.button.toggled.unpressed.image.color",
351                 "window.inactive.button.toggled.image.color",
352                 theme->titlebut_toggled_unfocused_unpressed_color,
353                 RrColorCopy(theme->titlebut_unfocused_pressed_color));
354
355     READ_COLOR("window.active.button.toggled.hover.image.color",
356                theme->titlebut_toggled_hover_focused_color,
357                RrColorCopy(theme->titlebut_toggled_focused_unpressed_color));
358
359     READ_COLOR("window.inactive.button.toggled.hover.image.color",
360                theme->titlebut_toggled_hover_unfocused_color,
361                RrColorCopy(theme->titlebut_toggled_unfocused_unpressed_color));
362
363     READ_COLOR("window.active.button.toggled.pressed.image.color",
364                theme->titlebut_toggled_focused_pressed_color,
365                RrColorCopy(theme->titlebut_focused_pressed_color));
366
367     READ_COLOR("window.inactive.button.toggled.pressed.image.color",
368                theme->titlebut_toggled_unfocused_pressed_color,
369                RrColorCopy(theme->titlebut_unfocused_pressed_color));
370
371     READ_COLOR("menu.title.text.color", theme->menu_title_color,
372                RrColorNew(inst, 0, 0, 0));
373
374     READ_COLOR("menu.items.text.color", theme->menu_color,
375                RrColorNew(inst, 0xff, 0xff, 0xff));
376
377     READ_COLOR("menu.items.disabled.text.color", theme->menu_disabled_color,
378                RrColorNew(inst, 0, 0, 0));
379
380     READ_COLOR("menu.items.active.disabled.text.color",
381                theme->menu_disabled_selected_color,
382                RrColorCopy(theme->menu_disabled_color));
383
384     READ_COLOR("menu.items.active.text.color", theme->menu_selected_color,
385                RrColorNew(inst, 0, 0, 0));
386
387     READ_COLOR("menu.separator.color", theme->menu_sep_color,
388                RrColorCopy(theme->menu_color));
389
390     /* load the image masks */
391
392     /* maximize button masks */
393     userdef = TRUE;
394     if (!read_mask(inst, path, theme, "max.xbm", &theme->max_mask)) {
395             guchar data[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
396             theme->max_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
397             userdef = FALSE;
398     }
399     if (!read_mask(inst, path, theme, "max_toggled.xbm",
400                    &theme->max_toggled_mask))
401     {
402         if (userdef)
403             theme->max_toggled_mask = RrPixmapMaskCopy(theme->max_mask);
404         else {
405             guchar data[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f };
406             theme->max_toggled_mask = RrPixmapMaskNew(inst, 6, 6,(gchar*)data);
407         }
408     }
409     READ_MASK_COPY("max_pressed.xbm", theme->max_pressed_mask,
410                    theme->max_mask);
411     READ_MASK_COPY("max_disabled.xbm", theme->max_disabled_mask,
412                    theme->max_mask);
413     READ_MASK_COPY("max_hover.xbm", theme->max_hover_mask, theme->max_mask);
414     READ_MASK_COPY("max_toggled_pressed.xbm", theme->max_toggled_pressed_mask,
415                    theme->max_toggled_mask);
416     READ_MASK_COPY("max_toggled_hover.xbm", theme->max_toggled_hover_mask,
417                    theme->max_toggled_mask);
418
419     /* iconify button masks */
420     if (!read_mask(inst, path, theme, "iconify.xbm", &theme->iconify_mask)) {
421         guchar data[] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f };
422         theme->iconify_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
423     }
424     READ_MASK_COPY("iconify_pressed.xbm", theme->iconify_pressed_mask,
425                    theme->iconify_mask);
426     READ_MASK_COPY("iconify_disabled.xbm", theme->iconify_disabled_mask,
427                    theme->iconify_mask);
428     READ_MASK_COPY("iconify_hover.xbm", theme->iconify_hover_mask,
429                    theme->iconify_mask);
430
431     /* all desktops button masks */
432     userdef = TRUE;
433     if (!read_mask(inst, path, theme, "desk.xbm", &theme->desk_mask)) {
434         guchar data[] = { 0x33, 0x33, 0x00, 0x00, 0x33, 0x33 };
435         theme->desk_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
436         userdef = FALSE;
437     }
438     if (!read_mask(inst, path, theme, "desk_toggled.xbm",
439                    &theme->desk_toggled_mask)) {
440         if (userdef)
441             theme->desk_toggled_mask = RrPixmapMaskCopy(theme->desk_mask);
442         else {
443             guchar data[] = { 0x00, 0x1e, 0x1a, 0x16, 0x1e, 0x00 };
444             theme->desk_toggled_mask =
445                 RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
446         }
447     }
448     READ_MASK_COPY("desk_pressed.xbm", theme->desk_pressed_mask,
449                    theme->desk_mask);
450     READ_MASK_COPY("desk_disabled.xbm", theme->desk_disabled_mask,
451                    theme->desk_mask);
452     READ_MASK_COPY("desk_hover.xbm", theme->desk_hover_mask, theme->desk_mask);
453     READ_MASK_COPY("desk_toggled_pressed.xbm",
454                    theme->desk_toggled_pressed_mask, theme->desk_toggled_mask);
455     READ_MASK_COPY("desk_toggled_hover.xbm", theme->desk_toggled_hover_mask,
456                    theme->desk_toggled_mask);
457
458     /* shade button masks */
459     if (!read_mask(inst, path, theme, "shade.xbm", &theme->shade_mask)) {
460         guchar data[] = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 };
461         theme->shade_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
462     }
463     READ_MASK_COPY("shade_toggled.xbm", theme->shade_toggled_mask,
464                    theme->shade_mask);
465     READ_MASK_COPY("shade_pressed.xbm", theme->shade_pressed_mask,
466                    theme->shade_mask);
467     READ_MASK_COPY("shade_disabled.xbm", theme->shade_disabled_mask,
468                    theme->shade_mask);
469     READ_MASK_COPY("shade_hover.xbm", theme->shade_hover_mask,
470                    theme->shade_mask);
471     READ_MASK_COPY("shade_toggled_pressed.xbm",
472                    theme->shade_toggled_pressed_mask,
473                    theme->shade_toggled_mask);
474     READ_MASK_COPY("shade_toggled_hover.xbm",
475                    theme->shade_toggled_hover_mask, theme->shade_toggled_mask);
476
477     /* close button masks */
478     if (!read_mask(inst, path, theme, "close.xbm", &theme->close_mask)) {
479         guchar data[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 };
480         theme->close_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
481     }
482     READ_MASK_COPY("close_pressed.xbm", theme->close_pressed_mask,
483                    theme->close_mask);
484     READ_MASK_COPY("close_disabled.xbm", theme->close_disabled_mask,
485                    theme->close_mask);
486     READ_MASK_COPY("close_hover.xbm", theme->close_hover_mask,
487                    theme->close_mask);
488
489     /* submenu bullet mask */
490     if (!read_mask(inst, path, theme, "bullet.xbm", &theme->menu_bullet_mask))
491     {
492         guchar data[] = { 0x01, 0x03, 0x07, 0x0f, 0x07, 0x03, 0x01 };
493         theme->menu_bullet_mask = RrPixmapMaskNew(inst, 4, 7, (gchar*)data);
494     }
495
496     /* up and down arrows */
497     {
498         guchar data[] = { 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00 };
499         theme->down_arrow_mask = RrPixmapMaskNew(inst, 9, 4, (gchar*)data);
500     }
501     {
502         guchar data[] = { 0x10, 0x00, 0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00 };
503         theme->up_arrow_mask = RrPixmapMaskNew(inst, 9, 4, (gchar*)data);
504     }
505
506     /* setup the default window icon */
507     theme->def_win_icon = read_c_image(OB_DEFAULT_ICON_WIDTH,
508                                        OB_DEFAULT_ICON_HEIGHT,
509                                        OB_DEFAULT_ICON_pixel_data);
510     theme->def_win_icon_w = OB_DEFAULT_ICON_WIDTH;
511     theme->def_win_icon_h = OB_DEFAULT_ICON_HEIGHT;
512
513     /* read the decoration textures */
514     READ_APPEARANCE("window.active.title.bg", theme->a_focused_title, FALSE);
515     READ_APPEARANCE("window.inactive.title.bg", theme->a_unfocused_title,
516                     FALSE);
517     READ_APPEARANCE("window.active.label.bg", theme->a_focused_label, TRUE);
518     READ_APPEARANCE("window.inactive.label.bg", theme->a_unfocused_label,
519                     TRUE);
520     READ_APPEARANCE("window.active.handle.bg", theme->a_focused_handle, FALSE);
521     READ_APPEARANCE("window.inactive.handle.bg",theme->a_unfocused_handle,
522                     FALSE);
523     READ_APPEARANCE("window.active.grip.bg", theme->a_focused_grip, TRUE);
524     READ_APPEARANCE("window.inactive.grip.bg", theme->a_unfocused_grip, TRUE);
525     READ_APPEARANCE("menu.items.bg", theme->a_menu, FALSE);
526     READ_APPEARANCE("menu.title.bg", theme->a_menu_title, TRUE);
527     READ_APPEARANCE("menu.items.active.bg", theme->a_menu_selected, TRUE);
528
529     theme->a_menu_disabled_selected =
530         RrAppearanceCopy(theme->a_menu_selected);
531
532     /* read appearances for non-decorations (on-screen-display) */
533     if (!read_appearance(db, inst, "osd.bg", theme->osd_bg, FALSE)) {
534         RrAppearanceFree(theme->osd_bg);
535         theme->osd_bg = RrAppearanceCopy(theme->a_focused_title);
536     }
537     if (!read_appearance(db, inst, "osd.active.label.bg",
538                          theme->osd_hilite_label, TRUE) &&
539         !read_appearance(db, inst, "osd.label.bg",
540                          theme->osd_hilite_label, TRUE)) {
541         RrAppearanceFree(theme->osd_hilite_label);
542         theme->osd_hilite_label = RrAppearanceCopy(theme->a_focused_label);
543     }
544     if (!read_appearance(db, inst, "osd.inactive.label.bg",
545                          theme->osd_unhilite_label, TRUE)) {
546         RrAppearanceFree(theme->osd_unhilite_label);
547         theme->osd_unhilite_label = RrAppearanceCopy(theme->a_unfocused_label);
548     }
549     /* osd_hilite_fg can't be parentrel */
550     if (!read_appearance(db, inst, "osd.hilight.bg",
551                          theme->osd_hilite_bg, FALSE)) {
552         RrAppearanceFree(theme->osd_hilite_bg);
553         if (theme->a_focused_label->surface.grad != RR_SURFACE_PARENTREL)
554             theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_label);
555         else
556             theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_title);
557     }
558     /* osd_unhilite_fg can't be parentrel either */
559     if (!read_appearance(db, inst, "osd.unhilight.bg",
560                          theme->osd_unhilite_bg, FALSE)) {
561         RrAppearanceFree(theme->osd_unhilite_bg);
562         if (theme->a_unfocused_label->surface.grad != RR_SURFACE_PARENTREL)
563             theme->osd_unhilite_bg=RrAppearanceCopy(theme->a_unfocused_label);
564         else
565             theme->osd_unhilite_bg=RrAppearanceCopy(theme->a_unfocused_title);
566     }
567
568     /* read buttons textures */
569     READ_APPEARANCE("window.active.button.disabled.bg",
570                     a_disabled_focused_tmp, TRUE);
571     READ_APPEARANCE("window.inactive.button.disabled.bg",
572                     a_disabled_unfocused_tmp, TRUE);
573     READ_APPEARANCE("window.active.button.pressed.bg",
574                     a_focused_pressed_tmp, TRUE);
575     READ_APPEARANCE("window.inactive.button.pressed.bg",
576                     a_unfocused_pressed_tmp, TRUE);
577
578     READ_APPEARANCE_("window.active.button.toggled.unpressed.bg",
579                      "window.active.button.toggled.bg",
580                      a_toggled_focused_unpressed_tmp, TRUE,
581                      a_focused_pressed_tmp);
582     READ_APPEARANCE_("window.inactive.button.toggled.unpressed.bg",
583                      "window.inactive.button.toggled.bg",
584                      a_toggled_unfocused_unpressed_tmp, TRUE,
585                      a_unfocused_pressed_tmp);
586
587     READ_APPEARANCE_COPY("window.active.button.toggled.hover.bg",
588                          a_toggled_hover_focused_tmp, TRUE,
589                          a_toggled_focused_unpressed_tmp);
590     READ_APPEARANCE_COPY("window.inactive.button.toggled.hover.bg",
591                          a_toggled_hover_unfocused_tmp, TRUE,
592                          a_toggled_unfocused_unpressed_tmp);
593
594     READ_APPEARANCE_COPY("window.active.button.toggled.pressed.bg",
595                          a_toggled_focused_pressed_tmp, TRUE,
596                          a_focused_pressed_tmp);
597     READ_APPEARANCE_COPY("window.inactive.button.toggled.pressed.bg",
598                          a_toggled_unfocused_pressed_tmp, TRUE,
599                          a_unfocused_pressed_tmp);
600
601     READ_APPEARANCE("window.active.button.unpressed.bg",
602                     a_focused_unpressed_tmp, TRUE);
603     READ_APPEARANCE("window.inactive.button.unpressed.bg",
604                     a_unfocused_unpressed_tmp, TRUE);
605
606     READ_APPEARANCE_COPY("window.active.button.hover.bg",
607                          a_hover_focused_tmp, TRUE,
608                          a_focused_unpressed_tmp);
609     READ_APPEARANCE_COPY("window.inactive.button.hover.bg",
610                          a_hover_unfocused_tmp, TRUE,
611                          a_unfocused_unpressed_tmp);
612
613     theme->a_disabled_focused_max =
614         RrAppearanceCopy(a_disabled_focused_tmp);
615     theme->a_disabled_unfocused_max =
616         RrAppearanceCopy(a_disabled_unfocused_tmp);
617     theme->a_hover_focused_max =
618         RrAppearanceCopy(a_hover_focused_tmp);
619     theme->a_hover_unfocused_max =
620         RrAppearanceCopy(a_hover_unfocused_tmp);
621     theme->a_unfocused_unpressed_max =
622         RrAppearanceCopy(a_unfocused_unpressed_tmp);
623     theme->a_unfocused_pressed_max =
624         RrAppearanceCopy(a_unfocused_pressed_tmp);
625     theme->a_focused_unpressed_max =
626         RrAppearanceCopy(a_focused_unpressed_tmp);
627     theme->a_focused_pressed_max =
628         RrAppearanceCopy(a_focused_pressed_tmp);
629     theme->a_disabled_focused_close =
630         RrAppearanceCopy(a_disabled_focused_tmp);
631     theme->a_disabled_unfocused_close =
632         RrAppearanceCopy(a_disabled_unfocused_tmp);
633     theme->a_hover_focused_close =
634         RrAppearanceCopy(a_hover_focused_tmp);
635     theme->a_hover_unfocused_close =
636         RrAppearanceCopy(a_hover_unfocused_tmp);
637     theme->a_unfocused_unpressed_close =
638         RrAppearanceCopy(a_unfocused_unpressed_tmp);
639     theme->a_unfocused_pressed_close =
640         RrAppearanceCopy(a_unfocused_pressed_tmp);
641     theme->a_focused_unpressed_close =
642         RrAppearanceCopy(a_focused_unpressed_tmp);
643     theme->a_focused_pressed_close =
644         RrAppearanceCopy(a_focused_pressed_tmp);
645     theme->a_disabled_focused_desk =
646         RrAppearanceCopy(a_disabled_focused_tmp);
647     theme->a_disabled_unfocused_desk =
648         RrAppearanceCopy(a_disabled_unfocused_tmp);
649     theme->a_hover_focused_desk =
650         RrAppearanceCopy(a_hover_focused_tmp);
651     theme->a_hover_unfocused_desk =
652         RrAppearanceCopy(a_hover_unfocused_tmp);
653     theme->a_toggled_hover_focused_desk =
654         RrAppearanceCopy(a_toggled_hover_focused_tmp);
655     theme->a_toggled_hover_unfocused_desk =
656         RrAppearanceCopy(a_toggled_hover_unfocused_tmp);
657     theme->a_toggled_focused_unpressed_desk =
658         RrAppearanceCopy(a_toggled_focused_unpressed_tmp);
659     theme->a_toggled_unfocused_unpressed_desk =
660         RrAppearanceCopy(a_toggled_unfocused_unpressed_tmp);
661     theme->a_toggled_focused_pressed_desk =
662         RrAppearanceCopy(a_toggled_focused_pressed_tmp);
663     theme->a_toggled_unfocused_pressed_desk =
664         RrAppearanceCopy(a_toggled_unfocused_pressed_tmp);
665     theme->a_unfocused_unpressed_desk =
666         RrAppearanceCopy(a_unfocused_unpressed_tmp);
667     theme->a_unfocused_pressed_desk =
668         RrAppearanceCopy(a_unfocused_pressed_tmp);
669     theme->a_focused_unpressed_desk =
670         RrAppearanceCopy(a_focused_unpressed_tmp);
671     theme->a_focused_pressed_desk =
672         RrAppearanceCopy(a_focused_pressed_tmp);
673     theme->a_disabled_focused_shade =
674         RrAppearanceCopy(a_disabled_focused_tmp);
675     theme->a_disabled_unfocused_shade =
676         RrAppearanceCopy(a_disabled_unfocused_tmp);
677     theme->a_hover_focused_shade =
678         RrAppearanceCopy(a_hover_focused_tmp);
679     theme->a_hover_unfocused_shade =
680         RrAppearanceCopy(a_hover_unfocused_tmp);
681     theme->a_toggled_hover_focused_shade =
682         RrAppearanceCopy(a_toggled_hover_focused_tmp);
683     theme->a_toggled_hover_unfocused_shade =
684         RrAppearanceCopy(a_toggled_hover_unfocused_tmp);
685     theme->a_toggled_focused_unpressed_shade =
686         RrAppearanceCopy(a_toggled_focused_unpressed_tmp);
687     theme->a_toggled_unfocused_unpressed_shade =
688         RrAppearanceCopy(a_toggled_unfocused_unpressed_tmp);
689     theme->a_toggled_focused_pressed_shade =
690         RrAppearanceCopy(a_toggled_focused_pressed_tmp);
691     theme->a_toggled_unfocused_pressed_shade =
692         RrAppearanceCopy(a_toggled_unfocused_pressed_tmp);
693     theme->a_unfocused_unpressed_shade =
694         RrAppearanceCopy(a_unfocused_unpressed_tmp);
695     theme->a_unfocused_pressed_shade =
696         RrAppearanceCopy(a_unfocused_pressed_tmp);
697     theme->a_focused_unpressed_shade =
698         RrAppearanceCopy(a_focused_unpressed_tmp);
699     theme->a_focused_pressed_shade =
700         RrAppearanceCopy(a_focused_pressed_tmp);
701     theme->a_disabled_focused_iconify =
702         RrAppearanceCopy(a_disabled_focused_tmp);
703     theme->a_disabled_unfocused_iconify =
704         RrAppearanceCopy(a_disabled_focused_tmp);
705     theme->a_hover_focused_iconify =
706         RrAppearanceCopy(a_hover_focused_tmp);
707     theme->a_hover_unfocused_iconify =
708         RrAppearanceCopy(a_hover_unfocused_tmp);
709     theme->a_unfocused_unpressed_iconify =
710         RrAppearanceCopy(a_unfocused_unpressed_tmp);
711     theme->a_unfocused_pressed_iconify =
712         RrAppearanceCopy(a_unfocused_pressed_tmp);
713     theme->a_focused_unpressed_iconify =
714         RrAppearanceCopy(a_focused_unpressed_tmp);
715     theme->a_focused_pressed_iconify =
716         RrAppearanceCopy(a_focused_pressed_tmp);
717
718     theme->a_icon->surface.grad =
719         theme->a_clear->surface.grad =
720         theme->a_clear_tex->surface.grad =
721         theme->a_menu_text_title->surface.grad =
722         theme->a_menu_normal->surface.grad =
723         theme->a_menu_disabled->surface.grad =
724         theme->a_menu_text_normal->surface.grad =
725         theme->a_menu_text_selected->surface.grad =
726         theme->a_menu_text_disabled->surface.grad =
727         theme->a_menu_text_disabled_selected->surface.grad =
728         theme->a_menu_bullet_normal->surface.grad =
729         theme->a_menu_bullet_selected->surface.grad = RR_SURFACE_PARENTREL;
730
731     /* set up the textures */
732     theme->a_focused_label->texture[0].type = RR_TEXTURE_TEXT;
733     theme->a_focused_label->texture[0].data.text.justify = winjust;
734     theme->a_focused_label->texture[0].data.text.font=theme->win_font_focused;
735     theme->a_focused_label->texture[0].data.text.color =
736         theme->title_focused_color;
737
738     if (read_string(db, "window.active.label.text.font", &str)) {
739         char *p;
740         gint i = 0;
741         gint j;
742         if (strstr(str, "shadow=y")) {
743             if ((p = strstr(str, "shadowoffset=")))
744                 i = parse_inline_number(p + strlen("shadowoffset="));
745             else
746                 i = 1;
747             theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
748             theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
749         }
750         if ((p = strstr(str, "shadowtint=")))
751         {
752             i = parse_inline_number(p + strlen("shadowtint="));
753             j = (i > 0 ? 0 : 255);
754             i = ABS(i*255/100);
755
756             theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
757             theme->title_focused_shadow_alpha = i;
758         } else {
759             theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
760             theme->title_focused_shadow_alpha = 50;
761         }
762     }
763
764     theme->a_focused_label->texture[0].data.text.shadow_color =
765         theme->title_focused_shadow_color;
766     theme->a_focused_label->texture[0].data.text.shadow_alpha =
767         theme->title_focused_shadow_alpha;
768
769     theme->osd_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
770     theme->osd_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
771     theme->osd_hilite_label->texture[0].data.text.font =
772         theme->osd_font_hilite;
773     theme->osd_hilite_label->texture[0].data.text.color =
774         theme->osd_text_active_color;
775
776     if (read_string(db, "osd.active.label.text.font", &str) ||
777         read_string(db, "osd.label.text.font", &str))
778     {
779         char *p;
780         gint i = 0;
781         gint j;
782         if (strstr(str, "shadow=y")) {
783             if ((p = strstr(str, "shadowoffset=")))
784                 i = parse_inline_number(p + strlen("shadowoffset="));
785             else
786                 i = 1;
787             theme->osd_hilite_label->texture[0].data.text.shadow_offset_x = i;
788             theme->osd_hilite_label->texture[0].data.text.shadow_offset_y = i;
789         }
790         if ((p = strstr(str, "shadowtint=")))
791         {
792             i = parse_inline_number(p + strlen("shadowtint="));
793             j = (i > 0 ? 0 : 255);
794             i = ABS(i*255/100);
795
796             theme->osd_text_active_shadow_color = RrColorNew(inst, j, j, j);
797             theme->osd_text_active_shadow_alpha = i;
798         } else {
799             theme->osd_text_active_shadow_color = RrColorNew(inst, 0, 0, 0);
800             theme->osd_text_active_shadow_alpha = 50;
801         }
802     } else {
803         /* inherit the font settings from the focused label */
804         theme->osd_hilite_label->texture[0].data.text.shadow_offset_x =
805             theme->a_focused_label->texture[0].data.text.shadow_offset_x;
806         theme->osd_hilite_label->texture[0].data.text.shadow_offset_y =
807             theme->a_focused_label->texture[0].data.text.shadow_offset_y;
808         if (theme->title_focused_shadow_color)
809             theme->osd_text_active_shadow_color =
810                 RrColorNew(inst,
811                            theme->title_focused_shadow_color->r,
812                            theme->title_focused_shadow_color->g,
813                            theme->title_focused_shadow_color->b);
814         else
815             theme->osd_text_active_shadow_color = RrColorNew(inst, 0, 0, 0);
816         theme->osd_text_active_shadow_alpha =
817             theme->title_focused_shadow_alpha;
818     }
819
820     theme->osd_hilite_label->texture[0].data.text.shadow_color =
821         theme->osd_text_active_shadow_color;
822     theme->osd_hilite_label->texture[0].data.text.shadow_alpha =
823         theme->osd_text_active_shadow_alpha;
824
825     theme->a_unfocused_label->texture[0].type = RR_TEXTURE_TEXT;
826     theme->a_unfocused_label->texture[0].data.text.justify = winjust;
827     theme->a_unfocused_label->texture[0].data.text.font =
828         theme->win_font_unfocused;
829     theme->a_unfocused_label->texture[0].data.text.color =
830         theme->title_unfocused_color;
831
832     if (read_string(db, "window.inactive.label.text.font", &str)) {
833         char *p;
834         gint i = 0;
835         gint j;
836         if (strstr(str, "shadow=y")) {
837             if ((p = strstr(str, "shadowoffset=")))
838                 i = parse_inline_number(p + strlen("shadowoffset="));
839             else
840                 i = 1;
841             theme->a_unfocused_label->texture[0].data.text.shadow_offset_x = i;
842             theme->a_unfocused_label->texture[0].data.text.shadow_offset_y = i;
843         }
844         if ((p = strstr(str, "shadowtint=")))
845         {
846             i = parse_inline_number(p + strlen("shadowtint="));
847             j = (i > 0 ? 0 : 255);
848             i = ABS(i*255/100);
849
850             theme->title_unfocused_shadow_color = RrColorNew(inst, j, j, j);
851             theme->title_unfocused_shadow_alpha = i;
852         } else {
853             theme->title_unfocused_shadow_color = RrColorNew(inst, 0, 0, 0);
854             theme->title_unfocused_shadow_alpha = 50;
855         }
856     }
857
858     theme->a_unfocused_label->texture[0].data.text.shadow_color =
859         theme->title_unfocused_shadow_color;
860     theme->a_unfocused_label->texture[0].data.text.shadow_alpha =
861         theme->title_unfocused_shadow_alpha;
862
863     theme->osd_unhilite_label->texture[0].type = RR_TEXTURE_TEXT;
864     theme->osd_unhilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
865     theme->osd_unhilite_label->texture[0].data.text.font =
866         theme->osd_font_unhilite;
867     theme->osd_unhilite_label->texture[0].data.text.color =
868         theme->osd_text_inactive_color;
869
870     if (read_string(db, "osd.inactive.label.text.font", &str))
871     {
872         char *p;
873         gint i = 0;
874         gint j;
875         if (strstr(str, "shadow=y")) {
876             if ((p = strstr(str, "shadowoffset=")))
877                 i = parse_inline_number(p + strlen("shadowoffset="));
878             else
879                 i = 1;
880             theme->osd_unhilite_label->texture[0].data.text.shadow_offset_x=i;
881             theme->osd_unhilite_label->texture[0].data.text.shadow_offset_y=i;
882         }
883         if ((p = strstr(str, "shadowtint=")))
884         {
885             i = parse_inline_number(p + strlen("shadowtint="));
886             j = (i > 0 ? 0 : 255);
887             i = ABS(i*255/100);
888
889             theme->osd_text_inactive_shadow_color = RrColorNew(inst, j, j, j);
890             theme->osd_text_inactive_shadow_alpha = i;
891         } else {
892             theme->osd_text_inactive_shadow_color = RrColorNew(inst, 0, 0, 0);
893             theme->osd_text_inactive_shadow_alpha = 50;
894         }
895     } else {
896         /* inherit the font settings from the unfocused label */
897         theme->osd_unhilite_label->texture[0].data.text.shadow_offset_x =
898             theme->a_unfocused_label->texture[0].data.text.shadow_offset_x;
899         theme->osd_unhilite_label->texture[0].data.text.shadow_offset_y =
900             theme->a_unfocused_label->texture[0].data.text.shadow_offset_y;
901         if (theme->title_unfocused_shadow_color)
902             theme->osd_text_inactive_shadow_color =
903                 RrColorNew(inst,
904                            theme->title_unfocused_shadow_color->r,
905                            theme->title_unfocused_shadow_color->g,
906                            theme->title_unfocused_shadow_color->b);
907         else
908             theme->osd_text_inactive_shadow_color = RrColorNew(inst, 0, 0, 0);
909         theme->osd_text_inactive_shadow_alpha =
910             theme->title_unfocused_shadow_alpha;
911     }
912
913     theme->osd_unhilite_label->texture[0].data.text.shadow_color =
914         theme->osd_text_inactive_shadow_color;
915     theme->osd_unhilite_label->texture[0].data.text.shadow_alpha =
916         theme->osd_text_inactive_shadow_alpha;
917
918     theme->a_menu_text_title->texture[0].type = RR_TEXTURE_TEXT;
919     theme->a_menu_text_title->texture[0].data.text.justify = mtitlejust;
920     theme->a_menu_text_title->texture[0].data.text.font =
921         theme->menu_title_font;
922     theme->a_menu_text_title->texture[0].data.text.color =
923         theme->menu_title_color;
924
925     if (read_string(db, "menu.title.text.font", &str)) {
926         char *p;
927         gint i = 0;
928         gint j;
929         if (strstr(str, "shadow=y")) {
930             if ((p = strstr(str, "shadowoffset=")))
931                 i = parse_inline_number(p + strlen("shadowoffset="));
932             else
933                 i = 1;
934             theme->a_menu_text_title->texture[0].data.text.shadow_offset_x = i;
935             theme->a_menu_text_title->texture[0].data.text.shadow_offset_y = i;
936         }
937         if ((p = strstr(str, "shadowtint=")))
938         {
939             i = parse_inline_number(p + strlen("shadowtint="));
940             j = (i > 0 ? 0 : 255);
941             i = ABS(i*255/100);
942
943             theme->menu_title_shadow_color = RrColorNew(inst, j, j, j);
944             theme->menu_title_shadow_alpha = i;
945         } else {
946             theme->menu_title_shadow_color = RrColorNew(inst, 0, 0, 0);
947             theme->menu_title_shadow_alpha = 50;
948         }
949     }
950
951     theme->a_menu_text_title->texture[0].data.text.shadow_color =
952         theme->menu_title_shadow_color;
953     theme->a_menu_text_title->texture[0].data.text.shadow_alpha =
954         theme->menu_title_shadow_alpha;
955
956     theme->a_menu_text_normal->texture[0].type =
957         theme->a_menu_text_selected->texture[0].type =
958         theme->a_menu_text_disabled->texture[0].type =
959         theme->a_menu_text_disabled_selected->texture[0].type =
960         RR_TEXTURE_TEXT;
961     theme->a_menu_text_normal->texture[0].data.text.justify =
962         theme->a_menu_text_selected->texture[0].data.text.justify =
963         theme->a_menu_text_disabled->texture[0].data.text.justify =
964         theme->a_menu_text_disabled_selected->texture[0].data.text.justify =
965         RR_JUSTIFY_LEFT;
966     theme->a_menu_text_normal->texture[0].data.text.font =
967         theme->a_menu_text_selected->texture[0].data.text.font =
968         theme->a_menu_text_disabled->texture[0].data.text.font =
969         theme->a_menu_text_disabled_selected->texture[0].data.text.font =
970         theme->menu_font;
971     theme->a_menu_text_normal->texture[0].data.text.color = theme->menu_color;
972     theme->a_menu_text_selected->texture[0].data.text.color =
973         theme->menu_selected_color;
974     theme->a_menu_text_disabled->texture[0].data.text.color =
975         theme->menu_disabled_color;
976     theme->a_menu_text_disabled_selected->texture[0].data.text.color =
977         theme->menu_disabled_selected_color;
978
979     if (read_string(db, "menu.items.font", &str)) {
980         char *p;
981         gint i = 0;
982         gint j;
983         if (strstr(str, "shadow=y")) {
984             if ((p = strstr(str, "shadowoffset=")))
985                 i = parse_inline_number(p + strlen("shadowoffset="));
986             else
987                 i = 1;
988             theme->a_menu_text_normal->
989                 texture[0].data.text.shadow_offset_x = i;
990             theme->a_menu_text_normal->
991                 texture[0].data.text.shadow_offset_y = i;
992             theme->a_menu_text_selected->
993                 texture[0].data.text.shadow_offset_x = i;
994             theme->a_menu_text_selected->
995                 texture[0].data.text.shadow_offset_y = i;
996             theme->a_menu_text_disabled->
997                 texture[0].data.text.shadow_offset_x = i;
998             theme->a_menu_text_disabled->
999                 texture[0].data.text.shadow_offset_y = i;
1000             theme->a_menu_text_disabled_selected->
1001                 texture[0].data.text.shadow_offset_x = i;
1002             theme->a_menu_text_disabled_selected->
1003                 texture[0].data.text.shadow_offset_y = i;
1004         }
1005         if ((p = strstr(str, "shadowtint=")))
1006         {
1007             i = parse_inline_number(p + strlen("shadowtint="));
1008             j = (i > 0 ? 0 : 255);
1009             i = ABS(i*255/100);
1010
1011             theme->menu_text_normal_shadow_color = RrColorNew(inst, j, j, j);
1012             theme->menu_text_selected_shadow_color = RrColorNew(inst, j, j, j);
1013             theme->menu_text_disabled_shadow_color = RrColorNew(inst, j, j, j);
1014             theme->menu_text_normal_shadow_alpha = i;
1015             theme->menu_text_selected_shadow_alpha = i;
1016             theme->menu_text_disabled_shadow_alpha = i;
1017             theme->menu_text_disabled_selected_shadow_alpha = i;
1018         } else {
1019             theme->menu_text_normal_shadow_color = RrColorNew(inst, 0, 0, 0);
1020             theme->menu_text_selected_shadow_color = RrColorNew(inst, 0, 0, 0);
1021             theme->menu_text_disabled_shadow_color = RrColorNew(inst, 0, 0, 0);
1022             theme->menu_text_normal_shadow_alpha = 50;
1023             theme->menu_text_selected_shadow_alpha = 50;
1024             theme->menu_text_disabled_selected_shadow_alpha = 50;
1025         }
1026     }
1027
1028     theme->a_menu_text_normal->texture[0].data.text.shadow_color =
1029         theme->menu_text_normal_shadow_color;
1030     theme->a_menu_text_normal->texture[0].data.text.shadow_alpha =
1031         theme->menu_text_normal_shadow_alpha;
1032     theme->a_menu_text_selected->texture[0].data.text.shadow_color =
1033         theme->menu_text_selected_shadow_color;
1034     theme->a_menu_text_selected->texture[0].data.text.shadow_alpha =
1035         theme->menu_text_selected_shadow_alpha;
1036     theme->a_menu_text_disabled->texture[0].data.text.shadow_color =
1037         theme->menu_text_disabled_shadow_color;
1038     theme->a_menu_text_disabled->texture[0].data.text.shadow_alpha =
1039         theme->menu_text_disabled_shadow_alpha;
1040     theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_color =
1041         theme->menu_text_disabled_shadow_color;
1042     theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_alpha =
1043         theme->menu_text_disabled_shadow_alpha;
1044
1045     theme->a_disabled_focused_max->texture[0].type =
1046         theme->a_disabled_unfocused_max->texture[0].type =
1047         theme->a_hover_focused_max->texture[0].type =
1048         theme->a_hover_unfocused_max->texture[0].type =
1049         theme->a_toggled_hover_focused_max->texture[0].type =
1050         theme->a_toggled_hover_unfocused_max->texture[0].type =
1051         theme->a_toggled_focused_unpressed_max->texture[0].type =
1052         theme->a_toggled_unfocused_unpressed_max->texture[0].type =
1053         theme->a_toggled_focused_pressed_max->texture[0].type =
1054         theme->a_toggled_unfocused_pressed_max->texture[0].type =
1055         theme->a_focused_unpressed_max->texture[0].type =
1056         theme->a_focused_pressed_max->texture[0].type =
1057         theme->a_unfocused_unpressed_max->texture[0].type =
1058         theme->a_unfocused_pressed_max->texture[0].type =
1059         theme->a_disabled_focused_close->texture[0].type =
1060         theme->a_disabled_unfocused_close->texture[0].type =
1061         theme->a_hover_focused_close->texture[0].type =
1062         theme->a_hover_unfocused_close->texture[0].type =
1063         theme->a_focused_unpressed_close->texture[0].type =
1064         theme->a_focused_pressed_close->texture[0].type =
1065         theme->a_unfocused_unpressed_close->texture[0].type =
1066         theme->a_unfocused_pressed_close->texture[0].type =
1067         theme->a_disabled_focused_desk->texture[0].type =
1068         theme->a_disabled_unfocused_desk->texture[0].type =
1069         theme->a_hover_focused_desk->texture[0].type =
1070         theme->a_hover_unfocused_desk->texture[0].type =
1071         theme->a_toggled_hover_focused_desk->texture[0].type =
1072         theme->a_toggled_hover_unfocused_desk->texture[0].type =
1073         theme->a_toggled_focused_unpressed_desk->texture[0].type =
1074         theme->a_toggled_unfocused_unpressed_desk->texture[0].type =
1075         theme->a_toggled_focused_pressed_desk->texture[0].type =
1076         theme->a_toggled_unfocused_pressed_desk->texture[0].type =
1077         theme->a_focused_unpressed_desk->texture[0].type =
1078         theme->a_focused_pressed_desk->texture[0].type =
1079         theme->a_unfocused_unpressed_desk->texture[0].type =
1080         theme->a_unfocused_pressed_desk->texture[0].type =
1081         theme->a_disabled_focused_shade->texture[0].type =
1082         theme->a_disabled_unfocused_shade->texture[0].type =
1083         theme->a_hover_focused_shade->texture[0].type =
1084         theme->a_hover_unfocused_shade->texture[0].type =
1085         theme->a_toggled_hover_focused_shade->texture[0].type =
1086         theme->a_toggled_hover_unfocused_shade->texture[0].type =
1087         theme->a_toggled_focused_unpressed_shade->texture[0].type =
1088         theme->a_toggled_unfocused_unpressed_shade->texture[0].type =
1089         theme->a_toggled_focused_pressed_shade->texture[0].type =
1090         theme->a_toggled_unfocused_pressed_shade->texture[0].type =
1091         theme->a_focused_unpressed_shade->texture[0].type =
1092         theme->a_focused_pressed_shade->texture[0].type =
1093         theme->a_unfocused_unpressed_shade->texture[0].type =
1094         theme->a_unfocused_pressed_shade->texture[0].type =
1095         theme->a_disabled_focused_iconify->texture[0].type =
1096         theme->a_disabled_unfocused_iconify->texture[0].type =
1097         theme->a_hover_focused_iconify->texture[0].type =
1098         theme->a_hover_unfocused_iconify->texture[0].type =
1099         theme->a_focused_unpressed_iconify->texture[0].type =
1100         theme->a_focused_pressed_iconify->texture[0].type =
1101         theme->a_unfocused_unpressed_iconify->texture[0].type =
1102         theme->a_unfocused_pressed_iconify->texture[0].type =
1103         theme->a_menu_bullet_normal->texture[0].type =
1104         theme->a_menu_bullet_selected->texture[0].type = RR_TEXTURE_MASK;
1105
1106     theme->a_disabled_focused_max->texture[0].data.mask.mask =
1107         theme->a_disabled_unfocused_max->texture[0].data.mask.mask =
1108         theme->max_disabled_mask;
1109     theme->a_hover_focused_max->texture[0].data.mask.mask =
1110         theme->a_hover_unfocused_max->texture[0].data.mask.mask =
1111         theme->max_hover_mask;
1112     theme->a_focused_pressed_max->texture[0].data.mask.mask =
1113         theme->a_unfocused_pressed_max->texture[0].data.mask.mask =
1114         theme->max_pressed_mask;
1115     theme->a_focused_unpressed_max->texture[0].data.mask.mask =
1116         theme->a_unfocused_unpressed_max->texture[0].data.mask.mask =
1117         theme->max_mask;
1118     theme->a_toggled_hover_focused_max->texture[0].data.mask.mask =
1119         theme->a_toggled_hover_unfocused_max->texture[0].data.mask.mask =
1120         theme->max_toggled_hover_mask;
1121     theme->a_toggled_focused_unpressed_max->texture[0].data.mask.mask =
1122         theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.mask =
1123         theme->max_toggled_mask;
1124     theme->a_toggled_focused_pressed_max->texture[0].data.mask.mask =
1125         theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.mask =
1126         theme->max_toggled_pressed_mask;
1127     theme->a_disabled_focused_close->texture[0].data.mask.mask =
1128         theme->a_disabled_unfocused_close->texture[0].data.mask.mask =
1129         theme->close_disabled_mask;
1130     theme->a_hover_focused_close->texture[0].data.mask.mask =
1131         theme->a_hover_unfocused_close->texture[0].data.mask.mask =
1132         theme->close_hover_mask;
1133     theme->a_focused_pressed_close->texture[0].data.mask.mask =
1134         theme->a_unfocused_pressed_close->texture[0].data.mask.mask =
1135         theme->close_pressed_mask;
1136     theme->a_focused_unpressed_close->texture[0].data.mask.mask =
1137         theme->a_unfocused_unpressed_close->texture[0].data.mask.mask =
1138         theme->close_mask;
1139     theme->a_disabled_focused_desk->texture[0].data.mask.mask =
1140         theme->a_disabled_unfocused_desk->texture[0].data.mask.mask =
1141         theme->desk_disabled_mask;
1142     theme->a_hover_focused_desk->texture[0].data.mask.mask =
1143         theme->a_hover_unfocused_desk->texture[0].data.mask.mask =
1144         theme->desk_hover_mask;
1145     theme->a_focused_pressed_desk->texture[0].data.mask.mask =
1146         theme->a_unfocused_pressed_desk->texture[0].data.mask.mask =
1147         theme->desk_pressed_mask;
1148     theme->a_focused_unpressed_desk->texture[0].data.mask.mask =
1149         theme->a_unfocused_unpressed_desk->texture[0].data.mask.mask =
1150         theme->desk_mask;
1151     theme->a_toggled_hover_focused_desk->texture[0].data.mask.mask =
1152         theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.mask =
1153         theme->desk_toggled_hover_mask;
1154     theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.mask =
1155         theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.mask =
1156         theme->desk_toggled_mask;
1157     theme->a_toggled_focused_pressed_desk->texture[0].data.mask.mask =
1158         theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.mask =
1159         theme->desk_toggled_pressed_mask;
1160     theme->a_disabled_focused_shade->texture[0].data.mask.mask =
1161         theme->a_disabled_unfocused_shade->texture[0].data.mask.mask =
1162         theme->shade_disabled_mask;
1163     theme->a_hover_focused_shade->texture[0].data.mask.mask =
1164         theme->a_hover_unfocused_shade->texture[0].data.mask.mask =
1165         theme->shade_hover_mask;
1166     theme->a_focused_pressed_shade->texture[0].data.mask.mask =
1167         theme->a_unfocused_pressed_shade->texture[0].data.mask.mask =
1168         theme->shade_pressed_mask;
1169     theme->a_focused_unpressed_shade->texture[0].data.mask.mask =
1170         theme->a_unfocused_unpressed_shade->texture[0].data.mask.mask =
1171         theme->shade_mask;
1172     theme->a_toggled_hover_focused_shade->texture[0].data.mask.mask =
1173         theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.mask =
1174         theme->shade_toggled_hover_mask;
1175     theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.mask =
1176         theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.mask =
1177         theme->shade_toggled_mask;
1178     theme->a_toggled_focused_pressed_shade->texture[0].data.mask.mask =
1179         theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.mask =
1180         theme->shade_toggled_pressed_mask;
1181     theme->a_disabled_focused_iconify->texture[0].data.mask.mask =
1182         theme->a_disabled_unfocused_iconify->texture[0].data.mask.mask =
1183         theme->iconify_disabled_mask;
1184     theme->a_hover_focused_iconify->texture[0].data.mask.mask =
1185         theme->a_hover_unfocused_iconify->texture[0].data.mask.mask =
1186         theme->iconify_hover_mask;
1187     theme->a_focused_pressed_iconify->texture[0].data.mask.mask =
1188         theme->a_unfocused_pressed_iconify->texture[0].data.mask.mask =
1189         theme->iconify_pressed_mask;
1190     theme->a_focused_unpressed_iconify->texture[0].data.mask.mask =
1191         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.mask =
1192         theme->iconify_mask;
1193     theme->a_menu_bullet_normal->texture[0].data.mask.mask =
1194     theme->a_menu_bullet_selected->texture[0].data.mask.mask =
1195         theme->menu_bullet_mask;
1196     theme->a_disabled_focused_max->texture[0].data.mask.color =
1197         theme->a_disabled_focused_close->texture[0].data.mask.color =
1198         theme->a_disabled_focused_desk->texture[0].data.mask.color =
1199         theme->a_disabled_focused_shade->texture[0].data.mask.color =
1200         theme->a_disabled_focused_iconify->texture[0].data.mask.color =
1201         theme->titlebut_disabled_focused_color;
1202     theme->a_disabled_unfocused_max->texture[0].data.mask.color =
1203         theme->a_disabled_unfocused_close->texture[0].data.mask.color =
1204         theme->a_disabled_unfocused_desk->texture[0].data.mask.color =
1205         theme->a_disabled_unfocused_shade->texture[0].data.mask.color =
1206         theme->a_disabled_unfocused_iconify->texture[0].data.mask.color =
1207         theme->titlebut_disabled_unfocused_color;
1208     theme->a_hover_focused_max->texture[0].data.mask.color =
1209         theme->a_hover_focused_close->texture[0].data.mask.color =
1210         theme->a_hover_focused_desk->texture[0].data.mask.color =
1211         theme->a_hover_focused_shade->texture[0].data.mask.color =
1212         theme->a_hover_focused_iconify->texture[0].data.mask.color =
1213         theme->titlebut_hover_focused_color;
1214     theme->a_hover_unfocused_max->texture[0].data.mask.color =
1215         theme->a_hover_unfocused_close->texture[0].data.mask.color =
1216         theme->a_hover_unfocused_desk->texture[0].data.mask.color =
1217         theme->a_hover_unfocused_shade->texture[0].data.mask.color =
1218         theme->a_hover_unfocused_iconify->texture[0].data.mask.color =
1219         theme->titlebut_hover_unfocused_color;
1220     theme->a_toggled_hover_focused_max->texture[0].data.mask.color =
1221         theme->a_toggled_hover_focused_desk->texture[0].data.mask.color =
1222         theme->a_toggled_hover_focused_shade->texture[0].data.mask.color =
1223         theme->titlebut_toggled_hover_focused_color;
1224     theme->a_toggled_hover_unfocused_max->texture[0].data.mask.color =
1225         theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.color =
1226         theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.color =
1227         theme->titlebut_toggled_hover_unfocused_color;
1228     theme->a_toggled_focused_unpressed_max->texture[0].data.mask.color =
1229         theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.color =
1230         theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.color =
1231         theme->titlebut_toggled_focused_unpressed_color;
1232     theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.color =
1233         theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.color =
1234         theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.color=
1235         theme->titlebut_toggled_unfocused_unpressed_color;
1236     theme->a_toggled_focused_pressed_max->texture[0].data.mask.color =
1237         theme->a_toggled_focused_pressed_desk->texture[0].data.mask.color =
1238         theme->a_toggled_focused_pressed_shade->texture[0].data.mask.color =
1239         theme->titlebut_toggled_focused_pressed_color;
1240     theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.color =
1241         theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.color =
1242         theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.color =
1243         theme->titlebut_toggled_unfocused_pressed_color;
1244     theme->a_focused_unpressed_max->texture[0].data.mask.color =
1245         theme->a_focused_unpressed_close->texture[0].data.mask.color =
1246         theme->a_focused_unpressed_desk->texture[0].data.mask.color =
1247         theme->a_focused_unpressed_shade->texture[0].data.mask.color =
1248         theme->a_focused_unpressed_iconify->texture[0].data.mask.color =
1249         theme->titlebut_focused_unpressed_color;
1250     theme->a_focused_pressed_max->texture[0].data.mask.color =
1251         theme->a_focused_pressed_close->texture[0].data.mask.color =
1252         theme->a_focused_pressed_desk->texture[0].data.mask.color =
1253         theme->a_focused_pressed_shade->texture[0].data.mask.color =
1254         theme->a_focused_pressed_iconify->texture[0].data.mask.color =
1255         theme->titlebut_focused_pressed_color;
1256     theme->a_unfocused_unpressed_max->texture[0].data.mask.color =
1257         theme->a_unfocused_unpressed_close->texture[0].data.mask.color =
1258         theme->a_unfocused_unpressed_desk->texture[0].data.mask.color =
1259         theme->a_unfocused_unpressed_shade->texture[0].data.mask.color =
1260         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.color =
1261         theme->titlebut_unfocused_unpressed_color;
1262     theme->a_unfocused_pressed_max->texture[0].data.mask.color =
1263         theme->a_unfocused_pressed_close->texture[0].data.mask.color =
1264         theme->a_unfocused_pressed_desk->texture[0].data.mask.color =
1265         theme->a_unfocused_pressed_shade->texture[0].data.mask.color =
1266         theme->a_unfocused_pressed_iconify->texture[0].data.mask.color =
1267         theme->titlebut_unfocused_pressed_color;
1268     theme->a_menu_bullet_normal->texture[0].data.mask.color =
1269         theme->menu_color;
1270     theme->a_menu_bullet_selected->texture[0].data.mask.color =
1271         theme->menu_selected_color;
1272
1273     g_free(path);
1274     XrmDestroyDatabase(db);
1275
1276     /* set the font heights */
1277     theme->win_font_height = RrFontHeight
1278         (theme->win_font_focused,
1279          theme->a_focused_label->texture[0].data.text.shadow_offset_y);
1280     theme->win_font_height =
1281         MAX(theme->win_font_height,
1282             RrFontHeight
1283             (theme->win_font_focused,
1284              theme->a_unfocused_label->texture[0].data.text.shadow_offset_y));
1285     theme->menu_title_font_height = RrFontHeight
1286         (theme->menu_title_font,
1287          theme->a_menu_text_title->texture[0].data.text.shadow_offset_y);
1288     theme->menu_font_height = RrFontHeight
1289         (theme->menu_font,
1290          theme->a_menu_text_normal->texture[0].data.text.shadow_offset_y);
1291
1292     /* calculate some last extents */
1293     {
1294         gint ft, fb, fl, fr, ut, ub, ul, ur;
1295
1296         RrMargins(theme->a_focused_label, &fl, &ft, &fr, &fb);
1297         RrMargins(theme->a_unfocused_label, &ul, &ut, &ur, &ub);
1298         theme->label_height = theme->win_font_height + MAX(ft + fb, ut + ub);
1299         theme->label_height += theme->label_height % 2;
1300
1301         /* this would be nice I think, since padding.width can now be 0,
1302            but it breaks frame.c horribly and I don't feel like fixing that
1303            right now, so if anyone complains, here is how to keep text from
1304            going over the title's bevel/border with a padding.width of 0 and a
1305            bevelless/borderless label
1306            RrMargins(theme->a_focused_title, &fl, &ft, &fr, &fb);
1307            RrMargins(theme->a_unfocused_title, &ul, &ut, &ur, &ub);
1308            theme->title_height = theme->label_height +
1309            MAX(MAX(theme->padding * 2, ft + fb),
1310            MAX(theme->padding * 2, ut + ub));
1311         */
1312         theme->title_height = theme->label_height + theme->paddingy * 2;
1313
1314         RrMargins(theme->a_menu_title, &ul, &ut, &ur, &ub);
1315         theme->menu_title_label_height = theme->menu_title_font_height+ut+ub;
1316         theme->menu_title_height = theme->menu_title_label_height +
1317             theme->paddingy * 2;
1318     }
1319     theme->button_size = theme->label_height - 2;
1320     theme->grip_width = 25;
1321
1322     RrAppearanceFree(a_disabled_focused_tmp);
1323     RrAppearanceFree(a_disabled_unfocused_tmp);
1324     RrAppearanceFree(a_hover_focused_tmp);
1325     RrAppearanceFree(a_hover_unfocused_tmp);
1326     RrAppearanceFree(a_focused_unpressed_tmp);
1327     RrAppearanceFree(a_focused_pressed_tmp);
1328     RrAppearanceFree(a_unfocused_unpressed_tmp);
1329     RrAppearanceFree(a_unfocused_pressed_tmp);
1330     RrAppearanceFree(a_toggled_hover_focused_tmp);
1331     RrAppearanceFree(a_toggled_hover_unfocused_tmp);
1332     RrAppearanceFree(a_toggled_focused_unpressed_tmp);
1333     RrAppearanceFree(a_toggled_focused_pressed_tmp);
1334     RrAppearanceFree(a_toggled_unfocused_unpressed_tmp);
1335     RrAppearanceFree(a_toggled_unfocused_pressed_tmp);
1336
1337     return theme;
1338 }
1339
1340 void RrThemeFree(RrTheme *theme)
1341 {
1342     if (theme) {
1343         g_free(theme->name);
1344
1345         RrColorFree(theme->menu_border_color);
1346         RrColorFree(theme->osd_border_color);
1347         RrColorFree(theme->frame_focused_border_color);
1348         RrColorFree(theme->frame_unfocused_border_color);
1349         RrColorFree(theme->title_separator_focused_color);
1350         RrColorFree(theme->title_separator_unfocused_color);
1351         RrColorFree(theme->cb_unfocused_color);
1352         RrColorFree(theme->cb_focused_color);
1353         RrColorFree(theme->title_focused_color);
1354         RrColorFree(theme->title_unfocused_color);
1355         RrColorFree(theme->titlebut_disabled_focused_color);
1356         RrColorFree(theme->titlebut_disabled_unfocused_color);
1357         RrColorFree(theme->titlebut_hover_focused_color);
1358         RrColorFree(theme->titlebut_hover_unfocused_color);
1359         RrColorFree(theme->titlebut_toggled_hover_focused_color);
1360         RrColorFree(theme->titlebut_toggled_hover_unfocused_color);
1361         RrColorFree(theme->titlebut_toggled_focused_pressed_color);
1362         RrColorFree(theme->titlebut_toggled_unfocused_pressed_color);
1363         RrColorFree(theme->titlebut_toggled_focused_unpressed_color);
1364         RrColorFree(theme->titlebut_toggled_unfocused_unpressed_color);
1365         RrColorFree(theme->titlebut_focused_pressed_color);
1366         RrColorFree(theme->titlebut_unfocused_pressed_color);
1367         RrColorFree(theme->titlebut_focused_unpressed_color);
1368         RrColorFree(theme->titlebut_unfocused_unpressed_color);
1369         RrColorFree(theme->menu_title_color);
1370         RrColorFree(theme->menu_sep_color);
1371         RrColorFree(theme->menu_color);
1372         RrColorFree(theme->menu_selected_color);
1373         RrColorFree(theme->menu_disabled_color);
1374         RrColorFree(theme->menu_disabled_selected_color);
1375         RrColorFree(theme->title_focused_shadow_color);
1376         RrColorFree(theme->title_unfocused_shadow_color);
1377         RrColorFree(theme->osd_text_active_color);
1378         RrColorFree(theme->osd_text_inactive_color);
1379         RrColorFree(theme->osd_text_active_shadow_color);
1380         RrColorFree(theme->osd_text_inactive_shadow_color);
1381         RrColorFree(theme->menu_title_shadow_color);
1382         RrColorFree(theme->menu_text_normal_shadow_color);
1383         RrColorFree(theme->menu_text_selected_shadow_color);
1384         RrColorFree(theme->menu_text_disabled_shadow_color);
1385         RrColorFree(theme->menu_text_disabled_selected_shadow_color);
1386
1387         g_free(theme->def_win_icon);
1388
1389         RrPixmapMaskFree(theme->max_mask);
1390         RrPixmapMaskFree(theme->max_toggled_mask);
1391         RrPixmapMaskFree(theme->max_toggled_hover_mask);
1392         RrPixmapMaskFree(theme->max_toggled_pressed_mask);
1393         RrPixmapMaskFree(theme->max_disabled_mask);
1394         RrPixmapMaskFree(theme->max_hover_mask);
1395         RrPixmapMaskFree(theme->max_pressed_mask);
1396         RrPixmapMaskFree(theme->desk_mask);
1397         RrPixmapMaskFree(theme->desk_toggled_mask);
1398         RrPixmapMaskFree(theme->desk_toggled_hover_mask);
1399         RrPixmapMaskFree(theme->desk_toggled_pressed_mask);
1400         RrPixmapMaskFree(theme->desk_disabled_mask);
1401         RrPixmapMaskFree(theme->desk_hover_mask);
1402         RrPixmapMaskFree(theme->desk_pressed_mask);
1403         RrPixmapMaskFree(theme->shade_mask);
1404         RrPixmapMaskFree(theme->shade_toggled_mask);
1405         RrPixmapMaskFree(theme->shade_toggled_hover_mask);
1406         RrPixmapMaskFree(theme->shade_toggled_pressed_mask);
1407         RrPixmapMaskFree(theme->shade_disabled_mask);
1408         RrPixmapMaskFree(theme->shade_hover_mask);
1409         RrPixmapMaskFree(theme->shade_pressed_mask);
1410         RrPixmapMaskFree(theme->iconify_mask);
1411         RrPixmapMaskFree(theme->iconify_disabled_mask);
1412         RrPixmapMaskFree(theme->iconify_hover_mask);
1413         RrPixmapMaskFree(theme->iconify_pressed_mask);
1414         RrPixmapMaskFree(theme->close_mask);
1415         RrPixmapMaskFree(theme->close_disabled_mask);
1416         RrPixmapMaskFree(theme->close_hover_mask);
1417         RrPixmapMaskFree(theme->close_pressed_mask);
1418         RrPixmapMaskFree(theme->menu_bullet_mask);
1419         RrPixmapMaskFree(theme->down_arrow_mask);
1420         RrPixmapMaskFree(theme->up_arrow_mask);
1421
1422         RrFontClose(theme->win_font_focused);
1423         RrFontClose(theme->win_font_unfocused);
1424         RrFontClose(theme->menu_title_font);
1425         RrFontClose(theme->menu_font);
1426         RrFontClose(theme->osd_font_hilite);
1427         RrFontClose(theme->osd_font_unhilite);
1428
1429         RrAppearanceFree(theme->a_disabled_focused_max);
1430         RrAppearanceFree(theme->a_disabled_unfocused_max);
1431         RrAppearanceFree(theme->a_hover_focused_max);
1432         RrAppearanceFree(theme->a_hover_unfocused_max);
1433         RrAppearanceFree(theme->a_toggled_hover_focused_max);
1434         RrAppearanceFree(theme->a_toggled_hover_unfocused_max);
1435         RrAppearanceFree(theme->a_toggled_focused_unpressed_max);
1436         RrAppearanceFree(theme->a_toggled_focused_pressed_max);
1437         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_max);
1438         RrAppearanceFree(theme->a_toggled_unfocused_pressed_max);
1439         RrAppearanceFree(theme->a_focused_unpressed_max);
1440         RrAppearanceFree(theme->a_focused_pressed_max);
1441         RrAppearanceFree(theme->a_unfocused_unpressed_max);
1442         RrAppearanceFree(theme->a_unfocused_pressed_max);
1443         RrAppearanceFree(theme->a_disabled_focused_close);
1444         RrAppearanceFree(theme->a_disabled_unfocused_close);
1445         RrAppearanceFree(theme->a_hover_focused_close);
1446         RrAppearanceFree(theme->a_hover_unfocused_close);
1447         RrAppearanceFree(theme->a_focused_unpressed_close);
1448         RrAppearanceFree(theme->a_focused_pressed_close);
1449         RrAppearanceFree(theme->a_unfocused_unpressed_close);
1450         RrAppearanceFree(theme->a_unfocused_pressed_close);
1451         RrAppearanceFree(theme->a_disabled_focused_desk);
1452         RrAppearanceFree(theme->a_disabled_unfocused_desk);
1453         RrAppearanceFree(theme->a_hover_focused_desk);
1454         RrAppearanceFree(theme->a_hover_unfocused_desk);
1455         RrAppearanceFree(theme->a_toggled_hover_focused_desk);
1456         RrAppearanceFree(theme->a_toggled_hover_unfocused_desk);
1457         RrAppearanceFree(theme->a_toggled_focused_unpressed_desk);
1458         RrAppearanceFree(theme->a_toggled_focused_pressed_desk);
1459         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_desk);
1460         RrAppearanceFree(theme->a_toggled_unfocused_pressed_desk);
1461         RrAppearanceFree(theme->a_focused_unpressed_desk);
1462         RrAppearanceFree(theme->a_focused_pressed_desk);
1463         RrAppearanceFree(theme->a_unfocused_unpressed_desk);
1464         RrAppearanceFree(theme->a_unfocused_pressed_desk);
1465         RrAppearanceFree(theme->a_disabled_focused_shade);
1466         RrAppearanceFree(theme->a_disabled_unfocused_shade);
1467         RrAppearanceFree(theme->a_hover_focused_shade);
1468         RrAppearanceFree(theme->a_hover_unfocused_shade);
1469         RrAppearanceFree(theme->a_toggled_hover_focused_shade);
1470         RrAppearanceFree(theme->a_toggled_hover_unfocused_shade);
1471         RrAppearanceFree(theme->a_toggled_focused_unpressed_shade);
1472         RrAppearanceFree(theme->a_toggled_focused_pressed_shade);
1473         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_shade);
1474         RrAppearanceFree(theme->a_toggled_unfocused_pressed_shade);
1475         RrAppearanceFree(theme->a_focused_unpressed_shade);
1476         RrAppearanceFree(theme->a_focused_pressed_shade);
1477         RrAppearanceFree(theme->a_unfocused_unpressed_shade);
1478         RrAppearanceFree(theme->a_unfocused_pressed_shade);
1479         RrAppearanceFree(theme->a_disabled_focused_iconify);
1480         RrAppearanceFree(theme->a_disabled_unfocused_iconify);
1481         RrAppearanceFree(theme->a_hover_focused_iconify);
1482         RrAppearanceFree(theme->a_hover_unfocused_iconify);
1483         RrAppearanceFree(theme->a_focused_unpressed_iconify);
1484         RrAppearanceFree(theme->a_focused_pressed_iconify);
1485         RrAppearanceFree(theme->a_unfocused_unpressed_iconify);
1486         RrAppearanceFree(theme->a_unfocused_pressed_iconify);
1487         RrAppearanceFree(theme->a_focused_grip);
1488         RrAppearanceFree(theme->a_unfocused_grip);
1489         RrAppearanceFree(theme->a_focused_title);
1490         RrAppearanceFree(theme->a_unfocused_title);
1491         RrAppearanceFree(theme->a_focused_label);
1492         RrAppearanceFree(theme->a_unfocused_label);
1493         RrAppearanceFree(theme->a_icon);
1494         RrAppearanceFree(theme->a_focused_handle);
1495         RrAppearanceFree(theme->a_unfocused_handle);
1496         RrAppearanceFree(theme->a_menu);
1497         RrAppearanceFree(theme->a_menu_title);
1498         RrAppearanceFree(theme->a_menu_text_title);
1499         RrAppearanceFree(theme->a_menu_normal);
1500         RrAppearanceFree(theme->a_menu_selected);
1501         RrAppearanceFree(theme->a_menu_disabled);
1502         RrAppearanceFree(theme->a_menu_disabled_selected);
1503         RrAppearanceFree(theme->a_menu_text_normal);
1504         RrAppearanceFree(theme->a_menu_text_selected);
1505         RrAppearanceFree(theme->a_menu_text_disabled);
1506         RrAppearanceFree(theme->a_menu_text_disabled_selected);
1507         RrAppearanceFree(theme->a_menu_bullet_normal);
1508         RrAppearanceFree(theme->a_menu_bullet_selected);
1509         RrAppearanceFree(theme->a_clear);
1510         RrAppearanceFree(theme->a_clear_tex);
1511         RrAppearanceFree(theme->osd_bg);
1512         RrAppearanceFree(theme->osd_hilite_bg);
1513         RrAppearanceFree(theme->osd_hilite_label);
1514         RrAppearanceFree(theme->osd_unhilite_bg);
1515         RrAppearanceFree(theme->osd_unhilite_label);
1516
1517         g_slice_free(RrTheme, theme);
1518     }
1519 }
1520
1521 static XrmDatabase loaddb(const gchar *name, gchar **path)
1522 {
1523     GSList *it;
1524     XrmDatabase db = NULL;
1525     gchar *s;
1526
1527     if (name[0] == '/') {
1528         s = g_build_filename(name, "openbox-3", "themerc", NULL);
1529         if ((db = XrmGetFileDatabase(s)))
1530             *path = g_path_get_dirname(s);
1531         g_free(s);
1532     } else {
1533         ObtPaths *p;
1534
1535         p = obt_paths_new();
1536
1537         /* XXX backwards compatibility, remove me sometime later */
1538         s = g_build_filename(g_get_home_dir(), ".themes", name,
1539                              "openbox-3", "themerc", NULL);
1540         if ((db = XrmGetFileDatabase(s)))
1541             *path = g_path_get_dirname(s);
1542         g_free(s);
1543
1544         for (it = obt_paths_data_dirs(p); !db && it; it = g_slist_next(it))
1545         {
1546             s = g_build_filename(it->data, "themes", name,
1547                                  "openbox-3", "themerc", NULL);
1548             if ((db = XrmGetFileDatabase(s)))
1549                 *path = g_path_get_dirname(s);
1550             g_free(s);
1551         }
1552
1553         obt_paths_unref(p);
1554     }
1555
1556     if (db == NULL) {
1557         s = g_build_filename(name, "themerc", NULL);
1558         if ((db = XrmGetFileDatabase(s)))
1559             *path = g_path_get_dirname(s);
1560         g_free(s);
1561     }
1562
1563     return db;
1564 }
1565
1566 static gchar *create_class_name(const gchar *rname)
1567 {
1568     gchar *rclass = g_strdup(rname);
1569     gchar *p = rclass;
1570
1571     while (TRUE) {
1572         *p = toupper(*p);
1573         p = strchr(p+1, '.');
1574         if (p == NULL) break;
1575         ++p;
1576         if (*p == '\0') break;
1577     }
1578     return rclass;
1579 }
1580
1581 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
1582 {
1583     gboolean ret = FALSE;
1584     gchar *rclass = create_class_name(rname);
1585     gchar *rettype, *end;
1586     XrmValue retvalue;
1587
1588     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1589         retvalue.addr != NULL) {
1590         *value = (gint)strtol(retvalue.addr, &end, 10);
1591         if (end != retvalue.addr)
1592             ret = TRUE;
1593     }
1594
1595     g_free(rclass);
1596     return ret;
1597 }
1598
1599 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
1600 {
1601     gboolean ret = FALSE;
1602     gchar *rclass = create_class_name(rname);
1603     gchar *rettype;
1604     XrmValue retvalue;
1605
1606     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1607         retvalue.addr != NULL) {
1608         *value = retvalue.addr;
1609         ret = TRUE;
1610     }
1611
1612     g_free(rclass);
1613     return ret;
1614 }
1615
1616 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
1617                            const gchar *rname, RrColor **value)
1618 {
1619     gboolean ret = FALSE;
1620     gchar *rclass = create_class_name(rname);
1621     gchar *rettype;
1622     XrmValue retvalue;
1623
1624     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1625         retvalue.addr != NULL) {
1626         RrColor *c = RrColorParse(inst, retvalue.addr);
1627         if (c != NULL) {
1628             *value = c;
1629             ret = TRUE;
1630         }
1631     }
1632
1633     g_free(rclass);
1634     return ret;
1635 }
1636
1637 static gboolean read_mask(const RrInstance *inst, const gchar *path,
1638                           RrTheme *theme, const gchar *maskname,
1639                           RrPixmapMask **value)
1640 {
1641     gboolean ret = FALSE;
1642     gchar *s;
1643     gint hx, hy; /* ignored */
1644     guint w, h;
1645     guchar *b;
1646
1647     s = g_build_filename(path, maskname, NULL);
1648     if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
1649         ret = TRUE;
1650         *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
1651         XFree(b);
1652     }
1653     g_free(s);
1654
1655     return ret;
1656 }
1657
1658 static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
1659                              RrReliefType *relief, RrBevelType *bevel,
1660                              gboolean *interlaced, gboolean *border,
1661                              gboolean allow_trans)
1662 {
1663     gchar *t;
1664
1665     /* convert to all lowercase */
1666     for (t = tex; *t != '\0'; ++t)
1667         *t = g_ascii_tolower(*t);
1668
1669     if (allow_trans && strstr(tex, "parentrelative") != NULL) {
1670         *grad = RR_SURFACE_PARENTREL;
1671     } else {
1672         if (strstr(tex, "gradient") != NULL) {
1673             if (strstr(tex, "crossdiagonal") != NULL)
1674                 *grad = RR_SURFACE_CROSS_DIAGONAL;
1675             else if (strstr(tex, "pyramid") != NULL)
1676                 *grad = RR_SURFACE_PYRAMID;
1677             else if (strstr(tex, "mirrorhorizontal") != NULL)
1678                 *grad = RR_SURFACE_MIRROR_HORIZONTAL;
1679             else if (strstr(tex, "horizontal") != NULL)
1680                 *grad = RR_SURFACE_HORIZONTAL;
1681             else if (strstr(tex, "splitvertical") != NULL)
1682                 *grad = RR_SURFACE_SPLIT_VERTICAL;
1683             else if (strstr(tex, "vertical") != NULL)
1684                 *grad = RR_SURFACE_VERTICAL;
1685             else
1686                 *grad = RR_SURFACE_DIAGONAL;
1687         } else {
1688             *grad = RR_SURFACE_SOLID;
1689         }
1690     }
1691
1692     if (strstr(tex, "sunken") != NULL)
1693         *relief = RR_RELIEF_SUNKEN;
1694     else if (strstr(tex, "flat") != NULL)
1695         *relief = RR_RELIEF_FLAT;
1696     else if (strstr(tex, "raised") != NULL)
1697         *relief = RR_RELIEF_RAISED;
1698     else
1699         *relief = (*grad == RR_SURFACE_PARENTREL) ?
1700                   RR_RELIEF_FLAT : RR_RELIEF_RAISED;
1701
1702     *border = FALSE;
1703     if (*relief == RR_RELIEF_FLAT) {
1704         if (strstr(tex, "border") != NULL)
1705             *border = TRUE;
1706     } else {
1707         if (strstr(tex, "bevel2") != NULL)
1708             *bevel = RR_BEVEL_2;
1709         else
1710             *bevel = RR_BEVEL_1;
1711     }
1712
1713     if (strstr(tex, "interlaced") != NULL)
1714         *interlaced = TRUE;
1715     else
1716         *interlaced = FALSE;
1717 }
1718
1719 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
1720                                 const gchar *rname, RrAppearance *value,
1721                                 gboolean allow_trans)
1722 {
1723     gboolean ret = FALSE;
1724     gchar *rclass = create_class_name(rname);
1725     gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
1726     gchar *csplitname, *ctosplitname;
1727     gchar *rettype;
1728     XrmValue retvalue;
1729     gint i;
1730
1731     cname = g_strconcat(rname, ".color", NULL);
1732     ctoname = g_strconcat(rname, ".colorTo", NULL);
1733     bcname = g_strconcat(rname, ".border.color", NULL);
1734     icname = g_strconcat(rname, ".interlace.color", NULL);
1735     hname = g_strconcat(rname, ".highlight", NULL);
1736     sname = g_strconcat(rname, ".shadow", NULL);
1737     csplitname = g_strconcat(rname, ".color.splitTo", NULL);
1738     ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
1739
1740     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1741         retvalue.addr != NULL) {
1742         parse_appearance(retvalue.addr,
1743                          &value->surface.grad,
1744                          &value->surface.relief,
1745                          &value->surface.bevel,
1746                          &value->surface.interlaced,
1747                          &value->surface.border,
1748                          allow_trans);
1749         if (!read_color(db, inst, cname, &value->surface.primary))
1750             value->surface.primary = RrColorNew(inst, 0, 0, 0);
1751         if (!read_color(db, inst, ctoname, &value->surface.secondary))
1752             value->surface.secondary = RrColorNew(inst, 0, 0, 0);
1753         if (value->surface.border)
1754             if (!read_color(db, inst, bcname,
1755                             &value->surface.border_color))
1756                 value->surface.border_color = RrColorNew(inst, 0, 0, 0);
1757         if (value->surface.interlaced)
1758             if (!read_color(db, inst, icname,
1759                             &value->surface.interlace_color))
1760                 value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
1761         if (read_int(db, hname, &i) && i >= 0)
1762             value->surface.bevel_light_adjust = i;
1763         if (read_int(db, sname, &i) && i >= 0 && i <= 256)
1764             value->surface.bevel_dark_adjust = i;
1765
1766         if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
1767             gint r, g, b;
1768
1769             if (!read_color(db, inst, csplitname,
1770                             &value->surface.split_primary))
1771             {
1772                 r = value->surface.primary->r;
1773                 r += r >> 2;
1774                 g = value->surface.primary->g;
1775                 g += g >> 2;
1776                 b = value->surface.primary->b;
1777                 b += b >> 2;
1778                 if (r > 0xFF) r = 0xFF;
1779                 if (g > 0xFF) g = 0xFF;
1780                 if (b > 0xFF) b = 0xFF;
1781                 value->surface.split_primary = RrColorNew(inst, r, g, b);
1782             }
1783
1784             if (!read_color(db, inst, ctosplitname,
1785                             &value->surface.split_secondary))
1786             {
1787                 r = value->surface.secondary->r;
1788                 r += r >> 4;
1789                 g = value->surface.secondary->g;
1790                 g += g >> 4;
1791                 b = value->surface.secondary->b;
1792                 b += b >> 4;
1793                 if (r > 0xFF) r = 0xFF;
1794                 if (g > 0xFF) g = 0xFF;
1795                 if (b > 0xFF) b = 0xFF;
1796                 value->surface.split_secondary = RrColorNew(inst, r, g, b);
1797             }
1798         }
1799
1800         ret = TRUE;
1801     }
1802
1803     g_free(ctosplitname);
1804     g_free(csplitname);
1805     g_free(sname);
1806     g_free(hname);
1807     g_free(icname);
1808     g_free(bcname);
1809     g_free(ctoname);
1810     g_free(cname);
1811     g_free(rclass);
1812     return ret;
1813 }
1814
1815 static int parse_inline_number(const char *p)
1816 {
1817     int neg = 1;
1818     int res = 0;
1819     if (*p == '-') {
1820         neg = -1;
1821         ++p;
1822     }
1823     for (; isdigit(*p); ++p)
1824         res = res * 10 + *p - '0';
1825     res *= neg;
1826     return res;
1827 }
1828
1829 static void set_default_appearance(RrAppearance *a)
1830 {
1831     a->surface.grad = RR_SURFACE_SOLID;
1832     a->surface.relief = RR_RELIEF_FLAT;
1833     a->surface.bevel = RR_BEVEL_1;
1834     a->surface.interlaced = FALSE;
1835     a->surface.border = FALSE;
1836     a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
1837     a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
1838 }
1839
1840 /* Reads the output from gimp's C-Source file format into valid RGBA data for
1841    an RrTextureRGBA. */
1842 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
1843 {
1844     RrPixel32 *im, *p;
1845     gint i;
1846
1847     p = im = g_memdup(data, width * height * sizeof(RrPixel32));
1848
1849     for (i = 0; i < width * height; ++i) {
1850         guchar a = ((*p >> 24) & 0xff);
1851         guchar b = ((*p >> 16) & 0xff);
1852         guchar g = ((*p >>  8) & 0xff);
1853         guchar r = ((*p >>  0) & 0xff);
1854
1855         *p = ((r << RrDefaultRedOffset) +
1856               (g << RrDefaultGreenOffset) +
1857               (b << RrDefaultBlueOffset) +
1858               (a << RrDefaultAlphaOffset));
1859         p++;
1860     }
1861
1862     return im;
1863 }