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