]> icculus.org git repositories - dana/openbox.git/blob - render/theme.c
add toggled textuers for titlebar buttons
[dana/openbox.git] / render / theme.c
1 #include "render.h"
2 #include "color.h"
3 #include "font.h"
4 #include "mask.h"
5 #include "theme.h"
6
7 #include <X11/Xlib.h>
8 #include <X11/Xresource.h>
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 static XrmDatabase loaddb(RrTheme *theme, char *name);
14 static gboolean read_int(XrmDatabase db, char *rname, int *value);
15 static gboolean read_string(XrmDatabase db, char *rname, char **value);
16 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
17                            gchar *rname, RrColor **value);
18 static gboolean read_mask(const RrInstance *inst,
19                           gchar *maskname, RrTheme *theme,
20                           RrPixmapMask **value);
21 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
22                                 gchar *rname, RrAppearance *value,
23                                 gboolean allow_trans);
24 static void set_default_appearance(RrAppearance *a);
25
26 RrTheme* RrThemeNew(const RrInstance *inst, gchar *name)
27 {
28     XrmDatabase db = NULL;
29     RrJustify winjust, mtitlejust, mjust;
30     gchar *str;
31     gchar *font_str;
32     RrTheme *theme;
33
34     theme = g_new0(RrTheme, 1);
35
36     theme->inst = inst;
37
38     theme->a_disabled_focused_max = RrAppearanceNew(inst, 1);
39     theme->a_disabled_unfocused_max = RrAppearanceNew(inst, 1);
40     theme->a_hover_focused_max = RrAppearanceNew(inst, 1);
41     theme->a_hover_unfocused_max = RrAppearanceNew(inst, 1);
42     theme->a_toggled_focused_max = RrAppearanceNew(inst, 1);
43     theme->a_toggled_unfocused_max = RrAppearanceNew(inst, 1);
44     theme->a_focused_unpressed_max = RrAppearanceNew(inst, 1);
45     theme->a_focused_pressed_max = RrAppearanceNew(inst, 1);
46     theme->a_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
47     theme->a_unfocused_pressed_max = RrAppearanceNew(inst, 1);
48     theme->a_focused_grip = RrAppearanceNew(inst, 0);
49     theme->a_unfocused_grip = RrAppearanceNew(inst, 0);
50     theme->a_focused_title = RrAppearanceNew(inst, 0);
51     theme->a_unfocused_title = RrAppearanceNew(inst, 0);
52     theme->a_focused_label = RrAppearanceNew(inst, 1);
53     theme->a_unfocused_label = RrAppearanceNew(inst, 1);
54     theme->a_icon = RrAppearanceNew(inst, 1);
55     theme->a_focused_handle = RrAppearanceNew(inst, 0);
56     theme->a_unfocused_handle = RrAppearanceNew(inst, 0);
57     theme->a_menu = RrAppearanceNew(inst, 0);
58     theme->a_menu_title = RrAppearanceNew(inst, 1);
59     theme->a_menu_item = RrAppearanceNew(inst, 1);
60     theme->a_menu_disabled = RrAppearanceNew(inst, 1);
61     theme->a_menu_hilite = RrAppearanceNew(inst, 1);
62
63     theme->app_hilite_bg = RrAppearanceNew(inst, 0);
64     theme->app_unhilite_bg = RrAppearanceNew(inst, 0);
65     theme->app_hilite_label = RrAppearanceNew(inst, 1);
66     theme->app_unhilite_label = RrAppearanceNew(inst, 1);
67     theme->app_icon = RrAppearanceNew(inst, 1);
68
69     if (name) {
70         db = loaddb(theme, name);
71         if (db == NULL) {
72             g_warning("Failed to load the theme '%s'\n"
73                       "Falling back to the default: '%s'",
74                       name, DEFAULT_THEME);
75         } else
76             theme->name = g_path_get_basename(name);
77     }
78     if (db == NULL) {
79         db = loaddb(theme, DEFAULT_THEME);
80         if (db == NULL) {
81             g_warning("Failed to load the theme '%s'.", DEFAULT_THEME);
82             return NULL;
83         } else
84             theme->name = g_path_get_basename(DEFAULT_THEME);
85     }
86
87     /* load the font stuff */
88     if (!read_string(db, "window.title.xftfont", &font_str))
89         font_str = "arial,sans:bold:pixelsize=10:shadow=y:shadowtint=50";
90
91     if (!(theme->winfont = RrFontOpen(inst, font_str))) {
92         RrThemeFree(theme);
93         return NULL;
94     }
95     theme->winfont_height = RrFontHeight(theme->winfont);
96
97     winjust = RR_JUSTIFY_LEFT;
98     if (read_string(db, "window.justify", &str)) {
99         if (!g_ascii_strcasecmp(str, "right"))
100             winjust = RR_JUSTIFY_RIGHT;
101         else if (!g_ascii_strcasecmp(str, "center"))
102             winjust = RR_JUSTIFY_CENTER;
103     }
104
105     if (!read_string(db, "menu.title.xftfont", &font_str))
106         font_str = "arial,sans:bold:pixelsize=12:shadow=y";
107
108     if (!(theme->mtitlefont = RrFontOpen(inst, font_str))) {
109         RrThemeFree(theme);
110         return NULL;
111     }
112     theme->mtitlefont_height = RrFontHeight(theme->mtitlefont);
113
114     mtitlejust = RR_JUSTIFY_LEFT;
115     if (read_string(db, "menu.title.justify", &str)) {
116         if (!g_ascii_strcasecmp(str, "right"))
117             mtitlejust = RR_JUSTIFY_RIGHT;
118         else if (!g_ascii_strcasecmp(str, "center"))
119             mtitlejust = RR_JUSTIFY_CENTER;
120     }
121
122     if (!read_string(db, "menu.frame.xftfont", &font_str))
123         font_str = "arial,sans:bold:pixelsize=11:shadow=y";
124
125     if (!(theme->mfont = RrFontOpen(inst, font_str))) {
126         RrThemeFree(theme);
127         return NULL;
128     }
129     theme->mfont_height = RrFontHeight(theme->mfont);
130
131     mjust = RR_JUSTIFY_LEFT;
132     if (read_string(db, "menu.frame.justify", &str)) {
133         if (!g_ascii_strcasecmp(str, "right"))
134             mjust = RR_JUSTIFY_RIGHT;
135         else if (!g_ascii_strcasecmp(str, "center"))
136             mjust = RR_JUSTIFY_CENTER;
137     }
138
139     /* load direct dimensions */
140     if (!read_int(db, "menuOverlap", &theme->menu_overlap) ||
141         theme->menu_overlap < 0 || theme->menu_overlap > 20)
142         theme->handle_height = 0;
143     if (!read_int(db, "handleWidth", &theme->handle_height) ||
144         theme->handle_height < 0 || theme->handle_height > 100)
145         theme->handle_height = 6;
146     if (!read_int(db, "bevelWidth", &theme->bevel) ||
147         theme->bevel <= 0 || theme->bevel > 100) theme->bevel = 3;
148     if (!read_int(db, "borderWidth", &theme->bwidth) ||
149         theme->bwidth < 0 || theme->bwidth > 100) theme->bwidth = 1;
150     if (!read_int(db, "frameWidth", &theme->cbwidth) ||
151         theme->cbwidth < 0 || theme->cbwidth > 100)
152         theme->cbwidth = theme->bevel;
153
154     /* load colors */
155     if (!read_color(db, inst,
156                     "borderColor", &theme->b_color))
157         theme->b_color = RrColorNew(inst, 0, 0, 0);
158     if (!read_color(db, inst,
159                     "window.frame.focusColor", &theme->cb_focused_color))
160         theme->cb_focused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
161     if (!read_color(db, inst,
162                     "window.frame.unfocusColor",&theme->cb_unfocused_color))
163         theme->cb_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
164     if (!read_color(db, inst,
165                     "window.label.focus.textColor",
166                     &theme->title_focused_color))
167         theme->title_focused_color = RrColorNew(inst, 0x0, 0x0, 0x0);
168     if (!read_color(db, inst,
169                     "window.label.unfocus.textColor",
170                     &theme->title_unfocused_color))
171         theme->title_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
172     if (!read_color(db, inst,
173                     "window.button.focus.picColor",
174                     &theme->titlebut_focused_unpressed_color))
175         theme->titlebut_focused_unpressed_color = RrColorNew(inst, 0, 0, 0);
176     if (!read_color(db, inst,
177                     "window.button.unfocus.picColor",
178                     &theme->titlebut_unfocused_unpressed_color))
179         theme->titlebut_unfocused_unpressed_color =
180             RrColorNew(inst, 0xff, 0xff, 0xff);
181     if (!read_color(db, inst,
182                     "window.button.pressed.focus.picColor",
183                     &theme->titlebut_focused_pressed_color))
184         theme->titlebut_focused_pressed_color =
185             RrColorNew(inst,
186                        theme->titlebut_focused_unpressed_color->r,
187                        theme->titlebut_focused_unpressed_color->g,
188                        theme->titlebut_focused_unpressed_color->b);
189     if (!read_color(db, inst,
190                     "window.button.pressed.unfocus.picColor",
191                     &theme->titlebut_unfocused_pressed_color))
192         theme->titlebut_unfocused_pressed_color =
193             RrColorNew(inst,
194                        theme->titlebut_unfocused_unpressed_color->r,
195                        theme->titlebut_unfocused_unpressed_color->g,
196                        theme->titlebut_unfocused_unpressed_color->b);
197     if (!read_color(db, inst,
198                     "window.button.disabled.focus.picColor",
199                     &theme->titlebut_disabled_focused_color))
200         theme->titlebut_disabled_focused_color =
201             RrColorNew(inst, 0xff, 0xff, 0xff);
202     if (!read_color(db, inst,
203                     "window.button.disabled.unfocus.picColor",
204                     &theme->titlebut_disabled_unfocused_color))
205         theme->titlebut_disabled_unfocused_color = RrColorNew(inst, 0, 0, 0);
206     if (!read_color(db, inst,
207                     "window.button.hover.focus.picColor",
208                     &theme->titlebut_hover_focused_color))
209         theme->titlebut_hover_focused_color =
210             RrColorNew(inst,
211                        theme->titlebut_focused_unpressed_color->r,
212                        theme->titlebut_focused_unpressed_color->g,
213                        theme->titlebut_focused_unpressed_color->b);
214     if (!read_color(db, inst,
215                     "window.button.hover.unfocus.picColor",
216                     &theme->titlebut_hover_unfocused_color))
217         theme->titlebut_hover_unfocused_color =
218             RrColorNew(inst,
219                        theme->titlebut_unfocused_unpressed_color->r,
220                        theme->titlebut_unfocused_unpressed_color->g,
221                        theme->titlebut_unfocused_unpressed_color->b);
222     if (!read_color(db, inst,
223                     "window.button.toggled.focus.picColor",
224                     &theme->titlebut_toggled_focused_color))
225         theme->titlebut_toggled_focused_color =
226             RrColorNew(inst,
227                        theme->titlebut_focused_pressed_color->r,
228                        theme->titlebut_focused_pressed_color->g,
229                        theme->titlebut_focused_pressed_color->b);
230     if (!read_color(db, inst,
231                     "window.button.toggled.unfocus.picColor",
232                     &theme->titlebut_toggled_unfocused_color))
233         theme->titlebut_toggled_unfocused_color =
234             RrColorNew(inst,
235                        theme->titlebut_unfocused_pressed_color->r,
236                        theme->titlebut_unfocused_pressed_color->g,
237                        theme->titlebut_unfocused_pressed_color->b);
238     if (!read_color(db, inst,
239                     "menu.title.textColor", &theme->menu_title_color))
240         theme->menu_title_color = RrColorNew(inst, 0, 0, 0);
241     if (!read_color(db, inst,
242                     "menu.frame.textColor", &theme->menu_color))
243         theme->menu_color = RrColorNew(inst, 0xff, 0xff, 0xff);
244     if (!read_color(db, inst,
245                     "menu.frame.disableColor", &theme->menu_disabled_color))
246         theme->menu_disabled_color = RrColorNew(inst, 0, 0, 0);
247     if (!read_color(db, inst,
248                     "menu.hilite.textColor", &theme->menu_hilite_color))
249         theme->menu_hilite_color = RrColorNew(inst, 0, 0, 0);
250
251     if (read_mask(inst, "max.xbm", theme, &theme->max_mask)) {
252         if (!read_mask(inst, "max_toggled.xbm", theme,
253                        &theme->max_toggled_mask)) {
254             theme->max_toggled_mask = RrPixmapMaskCopy(theme->max_mask);
255         }
256         if (!read_mask(inst, "max_disabled.xbm", theme,
257                        &theme->max_disabled_mask)) {
258             theme->max_disabled_mask = RrPixmapMaskCopy(theme->max_mask);
259         } 
260         if (!read_mask(inst, "max_hover.xbm", theme, &theme->max_hover_mask)) {
261             theme->max_hover_mask = RrPixmapMaskCopy(theme->max_mask);
262         }
263    } else {
264         {
265             char data[] = { 0x7f, 0x7f, 0x7f, 0x41, 0x41, 0x41, 0x7f };
266             theme->max_mask = RrPixmapMaskNew(inst, 7, 7, data);
267         }
268         {
269             char data[] = { 0x7c, 0x44, 0x47, 0x47, 0x7f, 0x1f, 0x1f };
270             theme->max_toggled_mask = RrPixmapMaskNew(inst, 7, 7, data);
271         }
272         theme->max_disabled_mask = RrPixmapMaskCopy(theme->max_mask);
273         theme->max_hover_mask = RrPixmapMaskCopy(theme->max_mask);
274     }
275
276     if (read_mask(inst, "iconify.xbm", theme, &theme->iconify_mask)) {
277         if (!read_mask(inst, "iconify_disabled.xbm", theme,
278                        &theme->iconify_disabled_mask)) {
279             theme->iconify_disabled_mask =
280                 RrPixmapMaskCopy(theme->iconify_mask);
281         } 
282         if (!read_mask(inst, "iconify_hover.xbm", theme,
283                        &theme->iconify_hover_mask)) {
284             theme->iconify_hover_mask = RrPixmapMaskCopy(theme->iconify_mask);
285         }
286     } else {
287         {
288             char data[] = { 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f };
289             theme->iconify_mask = RrPixmapMaskNew(inst, 7, 7, data);
290         }
291         theme->iconify_disabled_mask = RrPixmapMaskCopy(theme->iconify_mask);
292         theme->iconify_hover_mask = RrPixmapMaskCopy(theme->iconify_mask);
293     }
294
295     if (read_mask(inst, "stick.xbm", theme, &theme->desk_mask)) {
296         if (!read_mask(inst, "stick_toggled.xbm", theme,
297                        &theme->desk_toggled_mask)) {
298             theme->desk_toggled_mask = RrPixmapMaskCopy(theme->desk_mask);
299         }
300     } else {
301         {
302             char data[] = { 0x63, 0x63, 0x00, 0x00, 0x00, 0x63, 0x63 };
303             theme->desk_mask = RrPixmapMaskNew(inst, 7, 7, data);
304         }
305         {
306             char data[] = { 0x00, 0x36, 0x36, 0x08, 0x36, 0x36, 0x00 };
307             theme->desk_toggled_mask = RrPixmapMaskNew(inst, 7, 7, data);
308         }
309     }
310
311     if (read_mask(inst, "shade.xbm", theme, &theme->shade_mask)) {
312         if (!read_mask(inst, "shade_toggled.xbm", theme,
313                        &theme->shade_toggled_mask)) {
314             theme->shade_toggled_mask = RrPixmapMaskCopy(theme->shade_mask);
315         }
316         if (!read_mask(inst, "shade_disabled.xbm", theme,
317                        &theme->shade_disabled_mask)) {
318             theme->shade_disabled_mask = RrPixmapMaskCopy(theme->shade_mask);
319         } 
320         if (!read_mask(inst, "shade_hover.xbm", theme, 
321                        &theme->shade_hover_mask)) {
322             theme->shade_hover_mask = RrPixmapMaskCopy(theme->shade_mask);
323         }
324     } else {
325         {
326             char data[] = { 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00 };
327             theme->shade_mask = RrPixmapMaskNew(inst, 7, 7, data);
328         }
329         {
330             char data[] = { 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x7f };
331             theme->shade_toggled_mask = RrPixmapMaskNew(inst, 7, 7, data);
332         }
333         theme->shade_disabled_mask = RrPixmapMaskCopy(theme->shade_mask);
334         theme->shade_hover_mask = RrPixmapMaskCopy(theme->shade_mask);
335     }
336
337     if (read_mask(inst, "close.xbm", theme, &theme->close_mask)) {
338         if (!read_mask(inst, "close_disabled.xbm", theme,
339                        &theme->close_disabled_mask)) {
340             theme->close_disabled_mask = RrPixmapMaskCopy(theme->close_mask);
341         } 
342         if (!read_mask(inst, "close_hover.xbm", theme,
343                        &theme->close_hover_mask)) {
344             theme->close_hover_mask = RrPixmapMaskCopy(theme->close_mask);
345         }
346     } else {
347         {
348             char data[] = { 0x63, 0x77, 0x3e, 0x1c, 0x3e, 0x77, 0x63 };
349             theme->close_mask = RrPixmapMaskNew(inst, 7, 7, data);
350         }
351         theme->close_disabled_mask = RrPixmapMaskCopy(theme->close_mask);
352         theme->close_hover_mask = RrPixmapMaskCopy(theme->close_mask);
353     }        
354
355     /* read the decoration textures */
356     if (!read_appearance(db, inst,
357                          "window.title.focus", theme->a_focused_title,
358                          FALSE))
359         set_default_appearance(theme->a_focused_title);
360     if (!read_appearance(db, inst,
361                          "window.title.unfocus", theme->a_unfocused_title,
362                          FALSE))
363         set_default_appearance(theme->a_unfocused_title);
364     if (!read_appearance(db, inst,
365                          "window.label.focus", theme->a_focused_label,
366                          TRUE))
367         set_default_appearance(theme->a_focused_label);
368     if (!read_appearance(db, inst,
369                          "window.label.unfocus", theme->a_unfocused_label,
370                          TRUE))
371         set_default_appearance(theme->a_unfocused_label);
372     if (!read_appearance(db, inst,
373                          "window.handle.focus", theme->a_focused_handle,
374                          FALSE))
375         set_default_appearance(theme->a_focused_handle);
376     if (!read_appearance(db, inst,
377                          "window.handle.unfocus",theme->a_unfocused_handle,
378                          FALSE))
379         set_default_appearance(theme->a_unfocused_handle);
380     if (!read_appearance(db, inst,
381                          "window.grip.focus", theme->a_focused_grip,
382                          TRUE))
383         set_default_appearance(theme->a_focused_grip);
384     if (!read_appearance(db, inst,
385                          "window.grip.unfocus", theme->a_unfocused_grip,
386                          TRUE))
387         set_default_appearance(theme->a_unfocused_grip);
388     if (!read_appearance(db, inst,
389                          "menu.frame", theme->a_menu,
390                          FALSE))
391         set_default_appearance(theme->a_menu);
392     if (!read_appearance(db, inst,
393                          "menu.title", theme->a_menu_title,
394                          FALSE))
395         set_default_appearance(theme->a_menu_title);
396     if (!read_appearance(db, inst,
397                          "menu.hilite", theme->a_menu_hilite,
398                          TRUE))
399         set_default_appearance(theme->a_menu_hilite);
400
401     /* read the appearances for rendering non-decorations */
402     if (!read_appearance(db, inst,
403                          "window.title.focus", theme->app_hilite_bg,
404                          FALSE))
405         set_default_appearance(theme->app_hilite_bg);
406     if (!read_appearance(db, inst,
407                          "window.label.focus", theme->app_hilite_label,
408                          TRUE))
409         set_default_appearance(theme->app_hilite_label);
410     if (!read_appearance(db, inst,
411                          "window.title.unfocus", theme->app_unhilite_bg,
412                          FALSE))
413         set_default_appearance(theme->app_unhilite_bg);
414     if (!read_appearance(db, inst,
415                          "window.label.unfocus", theme->app_unhilite_label,
416                          TRUE))
417         set_default_appearance(theme->app_unhilite_label);
418
419     /* read buttons textures */
420     if (!read_appearance(db, inst,
421                          "window.button.disabled.focus",
422                          theme->a_disabled_focused_max,
423                          TRUE))
424         set_default_appearance(theme->a_disabled_focused_max);
425     if (!read_appearance(db, inst,
426                          "window.button.disabled.unfocus",
427                          theme->a_disabled_unfocused_max,
428                          TRUE))
429         set_default_appearance(theme->a_disabled_unfocused_max);
430     if (!read_appearance(db, inst,
431                          "window.button.pressed.focus",
432                          theme->a_focused_pressed_max,
433                          TRUE))
434         set_default_appearance(theme->a_focused_pressed_max);
435     if (!read_appearance(db, inst,
436                          "window.button.pressed.unfocus",
437                          theme->a_unfocused_pressed_max,
438                          TRUE))
439         set_default_appearance(theme->a_unfocused_pressed_max);
440     if (!read_appearance(db, inst,
441                          "window.button.toggled.focus",
442                          theme->a_toggled_focused_max,
443                          TRUE))
444         theme->a_toggled_focused_max =
445             RrAppearanceCopy(theme->a_focused_pressed_max);
446     if (!read_appearance(db, inst,
447                          "window.button.toggled.unfocus",
448                          theme->a_toggled_unfocused_max,
449                          TRUE))
450         theme->a_toggled_unfocused_max =
451             RrAppearanceCopy(theme->a_unfocused_pressed_max);
452     if (!read_appearance(db, inst,
453                          "window.button.focus",
454                          theme->a_focused_unpressed_max,
455                          TRUE))
456         set_default_appearance(theme->a_focused_unpressed_max);
457     if (!read_appearance(db, inst,
458                          "window.button.unfocus",
459                          theme->a_unfocused_unpressed_max,
460                          TRUE))
461         set_default_appearance(theme->a_unfocused_unpressed_max);
462     if (!read_appearance(db, inst,
463                          "window.button.hover.focus",
464                          theme->a_hover_focused_max,
465                          TRUE))
466         theme->a_hover_focused_max =
467             RrAppearanceCopy(theme->a_focused_unpressed_max);
468     if (!read_appearance(db, inst,
469                          "window.button.hover.unfocus",
470                          theme->a_hover_unfocused_max,
471                          TRUE))
472         theme->a_hover_unfocused_max =
473             RrAppearanceCopy(theme->a_unfocused_unpressed_max);
474
475     theme->a_disabled_focused_close =
476         RrAppearanceCopy(theme->a_disabled_focused_max);
477     theme->a_disabled_unfocused_close =
478         RrAppearanceCopy(theme->a_disabled_unfocused_max);
479     theme->a_hover_focused_close =
480         RrAppearanceCopy(theme->a_hover_focused_max);
481     theme->a_hover_unfocused_close =
482         RrAppearanceCopy(theme->a_hover_unfocused_max);
483     theme->a_unfocused_unpressed_close =
484         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
485     theme->a_unfocused_pressed_close =
486         RrAppearanceCopy(theme->a_unfocused_pressed_max);
487     theme->a_focused_unpressed_close =
488         RrAppearanceCopy(theme->a_focused_unpressed_max);
489     theme->a_focused_pressed_close =
490         RrAppearanceCopy(theme->a_focused_pressed_max);
491     theme->a_disabled_focused_desk =
492         RrAppearanceCopy(theme->a_disabled_focused_max);
493     theme->a_disabled_unfocused_desk =
494         RrAppearanceCopy(theme->a_disabled_unfocused_max);
495     theme->a_hover_focused_desk =
496         RrAppearanceCopy(theme->a_hover_focused_max);
497     theme->a_hover_unfocused_desk =
498         RrAppearanceCopy(theme->a_hover_unfocused_max); 
499     theme->a_toggled_focused_desk =
500         RrAppearanceCopy(theme->a_toggled_focused_max);
501    theme->a_toggled_unfocused_desk =
502         RrAppearanceCopy(theme->a_toggled_unfocused_max);
503     theme->a_unfocused_unpressed_desk =
504         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
505     theme->a_unfocused_pressed_desk =
506         RrAppearanceCopy(theme->a_unfocused_pressed_max);
507     theme->a_focused_unpressed_desk =
508         RrAppearanceCopy(theme->a_focused_unpressed_max);
509     theme->a_focused_pressed_desk =
510         RrAppearanceCopy(theme->a_focused_pressed_max);
511     theme->a_disabled_focused_shade =
512         RrAppearanceCopy(theme->a_disabled_focused_max);
513     theme->a_disabled_unfocused_shade =
514         RrAppearanceCopy(theme->a_disabled_unfocused_max);
515     theme->a_hover_focused_shade =
516         RrAppearanceCopy(theme->a_hover_focused_max);
517     theme->a_hover_unfocused_shade =
518         RrAppearanceCopy(theme->a_hover_unfocused_max);
519     theme->a_toggled_focused_shade =
520         RrAppearanceCopy(theme->a_toggled_focused_max);
521     theme->a_toggled_unfocused_shade =
522         RrAppearanceCopy(theme->a_toggled_unfocused_max);
523     theme->a_unfocused_unpressed_shade =
524         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
525     theme->a_unfocused_pressed_shade =
526         RrAppearanceCopy(theme->a_unfocused_pressed_max);
527     theme->a_focused_unpressed_shade =
528         RrAppearanceCopy(theme->a_focused_unpressed_max);
529     theme->a_focused_pressed_shade =
530         RrAppearanceCopy(theme->a_focused_pressed_max);
531     theme->a_disabled_focused_iconify =
532         RrAppearanceCopy(theme->a_disabled_focused_max);
533     theme->a_disabled_unfocused_iconify =
534         RrAppearanceCopy(theme->a_disabled_focused_max);
535     theme->a_hover_focused_iconify =
536         RrAppearanceCopy(theme->a_hover_focused_max);
537     theme->a_hover_unfocused_iconify =
538         RrAppearanceCopy(theme->a_hover_unfocused_max);
539     theme->a_unfocused_unpressed_iconify =
540         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
541     theme->a_unfocused_pressed_iconify =
542         RrAppearanceCopy(theme->a_unfocused_pressed_max);
543     theme->a_focused_unpressed_iconify =
544         RrAppearanceCopy(theme->a_focused_unpressed_max);
545     theme->a_focused_pressed_iconify =
546         RrAppearanceCopy(theme->a_focused_pressed_max);
547
548     theme->a_icon->surface.grad = RR_SURFACE_PARENTREL;
549
550     /* set up the textures */
551     theme->a_focused_label->texture[0].type = 
552         theme->app_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
553     theme->a_focused_label->texture[0].data.text.justify = winjust;
554     theme->app_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
555     theme->a_focused_label->texture[0].data.text.font =
556         theme->app_hilite_label->texture[0].data.text.font = theme->winfont;
557     theme->a_focused_label->texture[0].data.text.color =
558         theme->app_hilite_label->texture[0].data.text.color =
559         theme->title_focused_color;
560
561     theme->a_unfocused_label->texture[0].type =
562         theme->app_unhilite_label->texture[0].type = RR_TEXTURE_TEXT;
563     theme->a_unfocused_label->texture[0].data.text.justify = winjust;
564     theme->app_unhilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
565     theme->a_unfocused_label->texture[0].data.text.font =
566         theme->app_unhilite_label->texture[0].data.text.font = theme->winfont;
567     theme->a_unfocused_label->texture[0].data.text.color =
568         theme->app_unhilite_label->texture[0].data.text.color =
569         theme->title_unfocused_color;
570
571     theme->a_menu_title->texture[0].type = RR_TEXTURE_TEXT;
572     theme->a_menu_title->texture[0].data.text.justify = mtitlejust;
573     theme->a_menu_title->texture[0].data.text.font = theme->mtitlefont;
574     theme->a_menu_title->texture[0].data.text.color = theme->menu_title_color;
575
576     theme->a_menu_item->surface.grad = 
577         theme->a_menu_disabled->surface.grad =
578         theme->app_icon->surface.grad = RR_SURFACE_PARENTREL;
579
580     theme->a_menu_item->texture[0].type =
581         theme->a_menu_disabled->texture[0].type = 
582         theme->a_menu_hilite->texture[0].type = RR_TEXTURE_TEXT;
583     theme->a_menu_item->texture[0].data.text.justify = 
584         theme->a_menu_disabled->texture[0].data.text.justify = 
585         theme->a_menu_hilite->texture[0].data.text.justify = mjust;
586     theme->a_menu_item->texture[0].data.text.font =
587         theme->a_menu_disabled->texture[0].data.text.font =
588         theme->a_menu_hilite->texture[0].data.text.font = theme->mfont;
589     theme->a_menu_item->texture[0].data.text.color = theme->menu_color;
590     theme->a_menu_disabled->texture[0].data.text.color =
591         theme->menu_disabled_color;
592     theme->a_menu_hilite->texture[0].data.text.color =
593         theme->menu_hilite_color;
594
595     theme->a_disabled_focused_max->texture[0].type = 
596         theme->a_disabled_unfocused_max->texture[0].type = 
597         theme->a_hover_focused_max->texture[0].type = 
598         theme->a_hover_unfocused_max->texture[0].type = 
599         theme->a_toggled_focused_max->texture[0].type = 
600         theme->a_toggled_unfocused_max->texture[0].type = 
601         theme->a_focused_unpressed_max->texture[0].type = 
602         theme->a_focused_pressed_max->texture[0].type = 
603         theme->a_unfocused_unpressed_max->texture[0].type = 
604         theme->a_unfocused_pressed_max->texture[0].type = 
605         theme->a_disabled_focused_close->texture[0].type = 
606         theme->a_disabled_unfocused_close->texture[0].type = 
607         theme->a_hover_focused_close->texture[0].type = 
608         theme->a_hover_unfocused_close->texture[0].type = 
609         theme->a_focused_unpressed_close->texture[0].type = 
610         theme->a_focused_pressed_close->texture[0].type = 
611         theme->a_unfocused_unpressed_close->texture[0].type = 
612         theme->a_unfocused_pressed_close->texture[0].type = 
613         theme->a_disabled_focused_desk->texture[0].type = 
614         theme->a_disabled_unfocused_desk->texture[0].type = 
615         theme->a_hover_focused_desk->texture[0].type = 
616         theme->a_hover_unfocused_desk->texture[0].type = 
617         theme->a_toggled_focused_desk->texture[0].type = 
618         theme->a_toggled_unfocused_desk->texture[0].type = 
619         theme->a_focused_unpressed_desk->texture[0].type = 
620         theme->a_focused_pressed_desk->texture[0].type = 
621         theme->a_unfocused_unpressed_desk->texture[0].type = 
622         theme->a_unfocused_pressed_desk->texture[0].type = 
623         theme->a_disabled_focused_shade->texture[0].type = 
624         theme->a_disabled_unfocused_shade->texture[0].type = 
625         theme->a_hover_focused_shade->texture[0].type = 
626         theme->a_hover_unfocused_shade->texture[0].type = 
627         theme->a_toggled_focused_shade->texture[0].type = 
628         theme->a_toggled_unfocused_shade->texture[0].type = 
629         theme->a_focused_unpressed_shade->texture[0].type = 
630         theme->a_focused_pressed_shade->texture[0].type = 
631         theme->a_unfocused_unpressed_shade->texture[0].type = 
632         theme->a_unfocused_pressed_shade->texture[0].type = 
633         theme->a_disabled_focused_iconify->texture[0].type = 
634         theme->a_disabled_unfocused_iconify->texture[0].type = 
635         theme->a_hover_focused_iconify->texture[0].type = 
636         theme->a_hover_unfocused_iconify->texture[0].type = 
637         theme->a_focused_unpressed_iconify->texture[0].type = 
638         theme->a_focused_pressed_iconify->texture[0].type = 
639         theme->a_unfocused_unpressed_iconify->texture[0].type = 
640         theme->a_unfocused_pressed_iconify->texture[0].type = RR_TEXTURE_MASK;
641     theme->a_disabled_focused_max->texture[0].data.mask.mask = 
642         theme->a_disabled_unfocused_max->texture[0].data.mask.mask = 
643         theme->max_disabled_mask;
644     theme->a_hover_focused_max->texture[0].data.mask.mask = 
645         theme->a_hover_unfocused_max->texture[0].data.mask.mask = 
646         theme->max_hover_mask;
647     theme->a_focused_unpressed_max->texture[0].data.mask.mask = 
648         theme->a_unfocused_unpressed_max->texture[0].data.mask.mask = 
649         theme->a_focused_pressed_max->texture[0].data.mask.mask = 
650         theme->a_unfocused_pressed_max->texture[0].data.mask.mask =
651         theme->max_mask;
652     theme->a_toggled_focused_max->texture[0].data.mask.mask = 
653         theme->a_toggled_unfocused_max->texture[0].data.mask.mask =
654         theme->max_toggled_mask;
655     theme->a_disabled_focused_close->texture[0].data.mask.mask = 
656         theme->a_disabled_unfocused_close->texture[0].data.mask.mask = 
657         theme->close_disabled_mask;
658     theme->a_hover_focused_close->texture[0].data.mask.mask = 
659         theme->a_hover_unfocused_close->texture[0].data.mask.mask = 
660         theme->close_hover_mask;
661     theme->a_focused_pressed_close->texture[0].data.mask.mask = 
662         theme->a_unfocused_pressed_close->texture[0].data.mask.mask =
663         theme->a_focused_unpressed_close->texture[0].data.mask.mask = 
664         theme->a_unfocused_unpressed_close->texture[0].data.mask.mask =
665         theme->close_mask;
666     theme->a_disabled_focused_desk->texture[0].data.mask.mask = 
667         theme->a_disabled_unfocused_desk->texture[0].data.mask.mask = 
668         theme->desk_disabled_mask;
669     theme->a_hover_focused_desk->texture[0].data.mask.mask = 
670         theme->a_hover_unfocused_desk->texture[0].data.mask.mask = 
671         theme->desk_hover_mask;
672     theme->a_focused_unpressed_desk->texture[0].data.mask.mask = 
673         theme->a_unfocused_unpressed_desk->texture[0].data.mask.mask = 
674         theme->a_focused_pressed_desk->texture[0].data.mask.mask = 
675         theme->a_unfocused_pressed_desk->texture[0].data.mask.mask =
676         theme->desk_mask;
677     theme->a_toggled_focused_desk->texture[0].data.mask.mask = 
678         theme->a_toggled_unfocused_desk->texture[0].data.mask.mask =
679         theme->desk_mask;
680     theme->a_disabled_focused_shade->texture[0].data.mask.mask = 
681         theme->a_disabled_unfocused_shade->texture[0].data.mask.mask = 
682         theme->shade_disabled_mask;
683     theme->a_hover_focused_shade->texture[0].data.mask.mask = 
684         theme->a_hover_unfocused_shade->texture[0].data.mask.mask = 
685         theme->shade_hover_mask;
686     theme->a_focused_unpressed_shade->texture[0].data.mask.mask = 
687         theme->a_unfocused_unpressed_shade->texture[0].data.mask.mask = 
688         theme->a_focused_pressed_shade->texture[0].data.mask.mask = 
689         theme->a_unfocused_pressed_shade->texture[0].data.mask.mask =
690         theme->shade_mask;
691     theme->a_toggled_focused_shade->texture[0].data.mask.mask = 
692         theme->a_toggled_unfocused_shade->texture[0].data.mask.mask =
693         theme->shade_mask;
694     theme->a_disabled_focused_iconify->texture[0].data.mask.mask = 
695         theme->a_disabled_unfocused_iconify->texture[0].data.mask.mask = 
696         theme->iconify_disabled_mask;
697     theme->a_hover_focused_iconify->texture[0].data.mask.mask = 
698         theme->a_hover_unfocused_iconify->texture[0].data.mask.mask = 
699         theme->iconify_hover_mask;
700     theme->a_focused_unpressed_iconify->texture[0].data.mask.mask = 
701         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.mask = 
702         theme->a_focused_pressed_iconify->texture[0].data.mask.mask = 
703         theme->a_unfocused_pressed_iconify->texture[0].data.mask.mask =
704         theme->iconify_mask;
705     theme->a_disabled_focused_max->texture[0].data.mask.color = 
706         theme->a_disabled_focused_close->texture[0].data.mask.color = 
707         theme->a_disabled_focused_desk->texture[0].data.mask.color = 
708         theme->a_disabled_focused_shade->texture[0].data.mask.color = 
709         theme->a_disabled_focused_iconify->texture[0].data.mask.color = 
710         theme->titlebut_disabled_focused_color;
711     theme->a_disabled_unfocused_max->texture[0].data.mask.color = 
712         theme->a_disabled_unfocused_close->texture[0].data.mask.color = 
713         theme->a_disabled_unfocused_desk->texture[0].data.mask.color = 
714         theme->a_disabled_unfocused_shade->texture[0].data.mask.color = 
715         theme->a_disabled_unfocused_iconify->texture[0].data.mask.color = 
716         theme->titlebut_disabled_unfocused_color;
717     theme->a_hover_focused_max->texture[0].data.mask.color = 
718         theme->a_hover_focused_close->texture[0].data.mask.color = 
719         theme->a_hover_focused_desk->texture[0].data.mask.color = 
720         theme->a_hover_focused_shade->texture[0].data.mask.color = 
721         theme->a_hover_focused_iconify->texture[0].data.mask.color = 
722         theme->titlebut_hover_focused_color;
723     theme->a_hover_unfocused_max->texture[0].data.mask.color = 
724         theme->a_hover_unfocused_close->texture[0].data.mask.color = 
725         theme->a_hover_unfocused_desk->texture[0].data.mask.color = 
726         theme->a_hover_unfocused_shade->texture[0].data.mask.color = 
727         theme->a_hover_unfocused_iconify->texture[0].data.mask.color = 
728         theme->titlebut_hover_unfocused_color;
729     theme->a_toggled_focused_max->texture[0].data.mask.color = 
730         theme->a_toggled_focused_desk->texture[0].data.mask.color = 
731         theme->a_toggled_focused_shade->texture[0].data.mask.color = 
732         theme->titlebut_toggled_focused_color;
733     theme->a_toggled_unfocused_max->texture[0].data.mask.color = 
734         theme->a_toggled_unfocused_desk->texture[0].data.mask.color = 
735         theme->a_toggled_unfocused_shade->texture[0].data.mask.color = 
736         theme->titlebut_toggled_unfocused_color;
737     theme->a_focused_unpressed_max->texture[0].data.mask.color = 
738         theme->a_focused_unpressed_close->texture[0].data.mask.color = 
739         theme->a_focused_unpressed_desk->texture[0].data.mask.color = 
740         theme->a_focused_unpressed_shade->texture[0].data.mask.color = 
741         theme->a_focused_unpressed_iconify->texture[0].data.mask.color = 
742         theme->titlebut_focused_unpressed_color;
743     theme->a_focused_pressed_max->texture[0].data.mask.color = 
744         theme->a_focused_pressed_close->texture[0].data.mask.color = 
745         theme->a_focused_pressed_desk->texture[0].data.mask.color = 
746         theme->a_focused_pressed_shade->texture[0].data.mask.color = 
747         theme->a_focused_pressed_iconify->texture[0].data.mask.color =
748         theme->titlebut_focused_pressed_color;
749     theme->a_unfocused_unpressed_max->texture[0].data.mask.color = 
750         theme->a_unfocused_unpressed_close->texture[0].data.mask.color = 
751         theme->a_unfocused_unpressed_desk->texture[0].data.mask.color = 
752         theme->a_unfocused_unpressed_shade->texture[0].data.mask.color = 
753         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.color = 
754         theme->titlebut_unfocused_unpressed_color;
755         theme->a_unfocused_pressed_max->texture[0].data.mask.color = 
756         theme->a_unfocused_pressed_close->texture[0].data.mask.color = 
757         theme->a_unfocused_pressed_desk->texture[0].data.mask.color = 
758         theme->a_unfocused_pressed_shade->texture[0].data.mask.color = 
759         theme->a_unfocused_pressed_iconify->texture[0].data.mask.color =
760         theme->titlebut_unfocused_pressed_color;
761
762     XrmDestroyDatabase(db);
763
764     theme->label_height = theme->winfont_height;
765     theme->title_height = theme->label_height + theme->bevel * 2;
766     theme->button_size = theme->label_height - 2;
767     theme->grip_width = theme->button_size * 2;
768
769     return theme;
770 }
771
772 void RrThemeFree(RrTheme *theme)
773 {
774     if (theme) {
775         g_free(theme->name);
776
777         RrColorFree(theme->b_color);
778         RrColorFree(theme->cb_unfocused_color);
779         RrColorFree(theme->cb_focused_color);
780         RrColorFree(theme->title_unfocused_color);
781         RrColorFree(theme->title_focused_color);
782         RrColorFree(theme->titlebut_disabled_focused_color);
783         RrColorFree(theme->titlebut_disabled_unfocused_color);
784         RrColorFree(theme->titlebut_hover_focused_color);
785         RrColorFree(theme->titlebut_hover_unfocused_color);
786         RrColorFree(theme->titlebut_toggled_focused_color);
787         RrColorFree(theme->titlebut_toggled_unfocused_color);
788         RrColorFree(theme->titlebut_unfocused_pressed_color);
789         RrColorFree(theme->titlebut_focused_pressed_color);
790         RrColorFree(theme->titlebut_unfocused_unpressed_color);
791         RrColorFree(theme->titlebut_focused_unpressed_color);
792         RrColorFree(theme->menu_color);
793         RrColorFree(theme->menu_title_color);
794         RrColorFree(theme->menu_disabled_color);
795         RrColorFree(theme->menu_hilite_color);
796
797         RrPixmapMaskFree(theme->max_mask);
798         RrPixmapMaskFree(theme->max_toggled_mask);
799         RrPixmapMaskFree(theme->max_disabled_mask);
800         RrPixmapMaskFree(theme->max_hover_mask);
801         RrPixmapMaskFree(theme->desk_mask);
802         RrPixmapMaskFree(theme->desk_toggled_mask);
803         RrPixmapMaskFree(theme->desk_disabled_mask);
804         RrPixmapMaskFree(theme->desk_hover_mask);
805         RrPixmapMaskFree(theme->shade_mask);
806         RrPixmapMaskFree(theme->shade_toggled_mask);
807         RrPixmapMaskFree(theme->shade_disabled_mask);
808         RrPixmapMaskFree(theme->shade_hover_mask);
809         RrPixmapMaskFree(theme->iconify_mask);
810         RrPixmapMaskFree(theme->iconify_disabled_mask);
811         RrPixmapMaskFree(theme->iconify_hover_mask);
812         RrPixmapMaskFree(theme->close_mask);
813         RrPixmapMaskFree(theme->close_disabled_mask);
814         RrPixmapMaskFree(theme->close_hover_mask);
815
816         RrFontClose(theme->winfont);
817         RrFontClose(theme->mtitlefont);
818         RrFontClose(theme->mfont);
819
820         RrAppearanceFree(theme->a_disabled_focused_max);
821         RrAppearanceFree(theme->a_disabled_unfocused_max);
822         RrAppearanceFree(theme->a_hover_focused_max);
823         RrAppearanceFree(theme->a_hover_unfocused_max);
824         RrAppearanceFree(theme->a_toggled_focused_max);
825         RrAppearanceFree(theme->a_toggled_unfocused_max);
826         RrAppearanceFree(theme->a_focused_unpressed_max);
827         RrAppearanceFree(theme->a_focused_pressed_max);
828         RrAppearanceFree(theme->a_unfocused_unpressed_max);
829         RrAppearanceFree(theme->a_unfocused_pressed_max);
830         RrAppearanceFree(theme->a_disabled_focused_close);
831         RrAppearanceFree(theme->a_disabled_unfocused_close);
832         RrAppearanceFree(theme->a_hover_focused_close);
833         RrAppearanceFree(theme->a_hover_unfocused_close);
834         RrAppearanceFree(theme->a_focused_unpressed_close);
835         RrAppearanceFree(theme->a_focused_pressed_close);
836         RrAppearanceFree(theme->a_unfocused_unpressed_close);
837         RrAppearanceFree(theme->a_unfocused_pressed_close);
838         RrAppearanceFree(theme->a_disabled_focused_desk);
839         RrAppearanceFree(theme->a_disabled_unfocused_desk);
840         RrAppearanceFree(theme->a_hover_focused_desk);
841         RrAppearanceFree(theme->a_hover_unfocused_desk);
842         RrAppearanceFree(theme->a_toggled_focused_desk);
843         RrAppearanceFree(theme->a_toggled_unfocused_desk);
844         RrAppearanceFree(theme->a_focused_unpressed_desk);
845         RrAppearanceFree(theme->a_focused_pressed_desk);
846         RrAppearanceFree(theme->a_unfocused_unpressed_desk);
847         RrAppearanceFree(theme->a_unfocused_pressed_desk);
848         RrAppearanceFree(theme->a_disabled_focused_shade);
849         RrAppearanceFree(theme->a_disabled_unfocused_shade);
850         RrAppearanceFree(theme->a_hover_focused_shade);
851         RrAppearanceFree(theme->a_hover_unfocused_shade);
852         RrAppearanceFree(theme->a_toggled_focused_shade);
853         RrAppearanceFree(theme->a_toggled_unfocused_shade);
854         RrAppearanceFree(theme->a_focused_unpressed_shade);
855         RrAppearanceFree(theme->a_focused_pressed_shade);
856         RrAppearanceFree(theme->a_unfocused_unpressed_shade);
857         RrAppearanceFree(theme->a_unfocused_pressed_shade);
858         RrAppearanceFree(theme->a_disabled_focused_iconify);
859         RrAppearanceFree(theme->a_disabled_unfocused_iconify);
860         RrAppearanceFree(theme->a_hover_focused_iconify);
861         RrAppearanceFree(theme->a_hover_unfocused_iconify);
862         RrAppearanceFree(theme->a_focused_unpressed_iconify);
863         RrAppearanceFree(theme->a_focused_pressed_iconify);
864         RrAppearanceFree(theme->a_unfocused_unpressed_iconify);
865         RrAppearanceFree(theme->a_unfocused_pressed_iconify);
866         RrAppearanceFree(theme->a_focused_grip);
867         RrAppearanceFree(theme->a_unfocused_grip);
868         RrAppearanceFree(theme->a_focused_title);
869         RrAppearanceFree(theme->a_unfocused_title);
870         RrAppearanceFree(theme->a_focused_label);
871         RrAppearanceFree(theme->a_unfocused_label);
872         RrAppearanceFree(theme->a_icon);
873         RrAppearanceFree(theme->a_focused_handle);
874         RrAppearanceFree(theme->a_unfocused_handle);
875         RrAppearanceFree(theme->a_menu);
876         RrAppearanceFree(theme->a_menu_title);
877         RrAppearanceFree(theme->a_menu_item);
878         RrAppearanceFree(theme->a_menu_disabled);
879         RrAppearanceFree(theme->a_menu_hilite);
880         RrAppearanceFree(theme->app_hilite_bg);
881         RrAppearanceFree(theme->app_unhilite_bg);
882         RrAppearanceFree(theme->app_hilite_label);
883         RrAppearanceFree(theme->app_unhilite_label);
884         RrAppearanceFree(theme->app_icon);
885     }
886 }
887
888 static XrmDatabase loaddb(RrTheme *theme, char *name)
889 {
890     XrmDatabase db;
891
892     char *s = g_build_filename(name, "themerc", NULL);
893     if ((db = XrmGetFileDatabase(s)))
894         theme->path = g_path_get_dirname(s);
895     g_free(s);
896     if (db == NULL) {
897         char *s = g_build_filename(g_get_home_dir(), ".openbox", "themes",
898                                    name, "themerc", NULL);
899         if ((db = XrmGetFileDatabase(s)))
900             theme->path = g_path_get_dirname(s);
901         g_free(s);
902     }
903     if (db == NULL) {
904         char *s = g_build_filename(THEMEDIR, name, "themerc", NULL);
905         if ((db = XrmGetFileDatabase(s)))
906             theme->path = g_path_get_dirname(s);
907         g_free(s);
908     }
909
910     return db;
911 }
912
913 static char *create_class_name(char *rname)
914 {
915     char *rclass = g_strdup(rname);
916     char *p = rclass;
917
918     while (TRUE) {
919         *p = toupper(*p);
920         p = strchr(p+1, '.');
921         if (p == NULL) break;
922         ++p;
923         if (*p == '\0') break;
924     }
925     return rclass;
926 }
927
928 static gboolean read_int(XrmDatabase db, char *rname, int *value)
929 {
930     gboolean ret = FALSE;
931     char *rclass = create_class_name(rname);
932     char *rettype, *end;
933     XrmValue retvalue;
934   
935     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
936         retvalue.addr != NULL) {
937         *value = (int)strtol(retvalue.addr, &end, 10);
938         if (end != retvalue.addr)
939             ret = TRUE;
940     }
941
942     g_free(rclass);
943     return ret;
944 }
945
946 static gboolean read_string(XrmDatabase db, char *rname, char **value)
947 {
948     gboolean ret = FALSE;
949     char *rclass = create_class_name(rname);
950     char *rettype;
951     XrmValue retvalue;
952   
953     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
954         retvalue.addr != NULL) {
955         *value = retvalue.addr;
956         ret = TRUE;
957     }
958
959     g_free(rclass);
960     return ret;
961 }
962
963 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
964                            gchar *rname, RrColor **value)
965 {
966     gboolean ret = FALSE;
967     char *rclass = create_class_name(rname);
968     char *rettype;
969     XrmValue retvalue;
970   
971     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
972         retvalue.addr != NULL) {
973         RrColor *c = RrColorParse(inst, retvalue.addr);
974         if (c != NULL) {
975             *value = c;
976             ret = TRUE;
977         }
978     }
979
980     g_free(rclass);
981     return ret;
982 }
983
984 static gboolean read_mask(const RrInstance *inst,
985                           gchar *maskname, RrTheme *theme,
986                           RrPixmapMask **value)
987 {
988     gboolean ret = FALSE;
989     char *s;
990     int hx, hy; /* ignored */
991     unsigned int w, h;
992     unsigned char *b;
993
994     s = g_build_filename(g_get_home_dir(), ".openbox", "themes",
995                          theme->name, maskname, NULL);
996     if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess)
997         ret = TRUE;
998     else {
999         g_free(s);
1000         s = g_build_filename(THEMEDIR, theme->name, maskname, NULL);
1001         if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) 
1002             ret = TRUE;
1003         else {
1004             g_free(s);
1005             s = g_build_filename(theme->path, maskname, NULL);
1006             if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) 
1007                 ret = TRUE;
1008         }
1009     }
1010
1011     if (ret) {
1012         *value = RrPixmapMaskNew(inst, w, h, (char*)b);
1013         XFree(b);
1014     }
1015       
1016     g_free(s);
1017
1018     return ret;
1019 }
1020
1021 static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
1022                              RrReliefType *relief, RrBevelType *bevel,
1023                              gboolean *interlaced, gboolean *border,
1024                              gboolean allow_trans)
1025 {
1026     char *t;
1027
1028     /* convert to all lowercase */
1029     for (t = tex; *t != '\0'; ++t)
1030         *t = g_ascii_tolower(*t);
1031
1032     if (allow_trans && strstr(tex, "parentrelative") != NULL) {
1033         *grad = RR_SURFACE_PARENTREL;
1034     } else {
1035         if (strstr(tex, "gradient") != NULL) {
1036             if (strstr(tex, "crossdiagonal") != NULL)
1037                 *grad = RR_SURFACE_CROSS_DIAGONAL;
1038             else if (strstr(tex, "pyramid") != NULL)
1039                 *grad = RR_SURFACE_PYRAMID;
1040             else if (strstr(tex, "horizontal") != NULL)
1041                 *grad = RR_SURFACE_HORIZONTAL;
1042             else if (strstr(tex, "vertical") != NULL)
1043                 *grad = RR_SURFACE_VERTICAL;
1044             else
1045                 *grad = RR_SURFACE_DIAGONAL;
1046         } else {
1047             *grad = RR_SURFACE_SOLID;
1048         }
1049
1050         if (strstr(tex, "sunken") != NULL)
1051             *relief = RR_RELIEF_SUNKEN;
1052         else if (strstr(tex, "flat") != NULL)
1053             *relief = RR_RELIEF_FLAT;
1054         else
1055             *relief = RR_RELIEF_RAISED;
1056         
1057         *border = FALSE;
1058         if (*relief == RR_RELIEF_FLAT) {
1059             if (strstr(tex, "border") != NULL)
1060                 *border = TRUE;
1061         } else {
1062             if (strstr(tex, "bevel2") != NULL)
1063                 *bevel = RR_BEVEL_2;
1064             else
1065                 *bevel = RR_BEVEL_1;
1066         }
1067
1068         if (strstr(tex, "interlaced") != NULL)
1069             *interlaced = TRUE;
1070         else
1071             *interlaced = FALSE;
1072     }
1073 }
1074
1075
1076 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
1077                                 gchar *rname, RrAppearance *value,
1078                                 gboolean allow_trans)
1079 {
1080     gboolean ret = FALSE;
1081     char *rclass = create_class_name(rname), *cname, *ctoname, *bcname;
1082     char *rettype;
1083     XrmValue retvalue;
1084
1085     cname = g_strconcat(rname, ".color", NULL);
1086     ctoname = g_strconcat(rname, ".colorTo", NULL);
1087     bcname = g_strconcat(rname, ".borderColor", NULL);
1088
1089     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1090         retvalue.addr != NULL) {
1091         parse_appearance(retvalue.addr,
1092                          &value->surface.grad,
1093                          &value->surface.relief,
1094                          &value->surface.bevel,
1095                          &value->surface.interlaced,
1096                          &value->surface.border,
1097                          allow_trans);
1098         if (!read_color(db, inst, cname, &value->surface.primary))
1099             value->surface.primary = RrColorNew(inst, 0, 0, 0);
1100         if (!read_color(db, inst, ctoname, &value->surface.secondary))
1101             value->surface.secondary = RrColorNew(inst, 0, 0, 0);
1102         if (value->surface.border)
1103             if (!read_color(db, inst, bcname,
1104                             &value->surface.border_color))
1105                 value->surface.border_color = RrColorNew(inst, 0, 0, 0);
1106         ret = TRUE;
1107     }
1108
1109     g_free(bcname);
1110     g_free(ctoname);
1111     g_free(cname);
1112     g_free(rclass);
1113     return ret;
1114 }
1115
1116 static void set_default_appearance(RrAppearance *a)
1117 {
1118     a->surface.grad = RR_SURFACE_SOLID;
1119     a->surface.relief = RR_RELIEF_FLAT;
1120     a->surface.bevel = RR_BEVEL_1;
1121     a->surface.interlaced = FALSE;
1122     a->surface.border = FALSE;
1123     a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
1124     a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
1125 }