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