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