handle parentrel app labels, by using the title's texture instead
[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     else if (theme->app_hilite_label->surface.grad == RR_SURFACE_PARENTREL) {
482         if (!read_appearance(db, inst,
483                              "window.active.title.bg",
484                              theme->app_hilite_label,
485                              FALSE))
486             set_default_appearance(theme->app_hilite_label);
487     }
488     if (!read_appearance(db, inst,
489                          "window.inactive.title.bg", theme->app_unhilite_bg,
490                          FALSE))
491         set_default_appearance(theme->app_unhilite_bg);
492     if (!read_appearance(db, inst,
493                          "window.inactive.label.bg", theme->app_unhilite_label,
494                          TRUE))
495         set_default_appearance(theme->app_unhilite_label);
496     else if (theme->app_unhilite_label->surface.grad == RR_SURFACE_PARENTREL) {
497         if (!read_appearance(db, inst,
498                              "window.inactive.title.bg",
499                              theme->app_unhilite_label,
500                              FALSE))
501             set_default_appearance(theme->app_unhilite_label);
502     }
503         
504
505     /* read buttons textures */
506     if (!read_appearance(db, inst,
507                          "window.active.button.disabled.bg",
508                          theme->a_disabled_focused_max,
509                          TRUE))
510         set_default_appearance(theme->a_disabled_focused_max);
511     if (!read_appearance(db, inst,
512                          "window.inactive.button.disabled.bg",
513                          theme->a_disabled_unfocused_max,
514                          TRUE))
515         set_default_appearance(theme->a_disabled_unfocused_max);
516     if (!read_appearance(db, inst,
517                          "window.active.button.pressed.bg",
518                          theme->a_focused_pressed_max,
519                          TRUE))
520         set_default_appearance(theme->a_focused_pressed_max);
521     if (!read_appearance(db, inst,
522                          "window.inactive.button.pressed.bg",
523                          theme->a_unfocused_pressed_max,
524                          TRUE))
525         set_default_appearance(theme->a_unfocused_pressed_max);
526     if (!read_appearance(db, inst,
527                          "window.active.button.toggled.bg",
528                          theme->a_toggled_focused_max,
529                          TRUE))
530     {
531         RrAppearanceFree(theme->a_toggled_focused_max);
532         theme->a_toggled_focused_max =
533             RrAppearanceCopy(theme->a_focused_pressed_max);
534     }
535     if (!read_appearance(db, inst,
536                          "window.inactive.button.toggled.bg",
537                          theme->a_toggled_unfocused_max,
538                          TRUE))
539     {
540         RrAppearanceFree(theme->a_toggled_unfocused_max);
541         theme->a_toggled_unfocused_max =
542             RrAppearanceCopy(theme->a_unfocused_pressed_max);
543     }
544     if (!read_appearance(db, inst,
545                          "window.active.button.unpressed.bg",
546                          theme->a_focused_unpressed_max,
547                          TRUE))
548         set_default_appearance(theme->a_focused_unpressed_max);
549     if (!read_appearance(db, inst,
550                          "window.inactive.button.unpressed.bg",
551                          theme->a_unfocused_unpressed_max,
552                          TRUE))
553         set_default_appearance(theme->a_unfocused_unpressed_max);
554     if (!read_appearance(db, inst,
555                          "window.active.button.hover.bg",
556                          theme->a_hover_focused_max,
557                          TRUE))
558     {
559         RrAppearanceFree(theme->a_hover_focused_max);
560         theme->a_hover_focused_max =
561             RrAppearanceCopy(theme->a_focused_unpressed_max);
562     }
563     if (!read_appearance(db, inst,
564                          "window.inactive.button.hover.bg",
565                          theme->a_hover_unfocused_max,
566                          TRUE))
567     {
568         RrAppearanceFree(theme->a_hover_unfocused_max);
569         theme->a_hover_unfocused_max =
570             RrAppearanceCopy(theme->a_unfocused_unpressed_max);
571     }
572
573     theme->a_disabled_focused_close =
574         RrAppearanceCopy(theme->a_disabled_focused_max);
575     theme->a_disabled_unfocused_close =
576         RrAppearanceCopy(theme->a_disabled_unfocused_max);
577     theme->a_hover_focused_close =
578         RrAppearanceCopy(theme->a_hover_focused_max);
579     theme->a_hover_unfocused_close =
580         RrAppearanceCopy(theme->a_hover_unfocused_max);
581     theme->a_unfocused_unpressed_close =
582         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
583     theme->a_unfocused_pressed_close =
584         RrAppearanceCopy(theme->a_unfocused_pressed_max);
585     theme->a_focused_unpressed_close =
586         RrAppearanceCopy(theme->a_focused_unpressed_max);
587     theme->a_focused_pressed_close =
588         RrAppearanceCopy(theme->a_focused_pressed_max);
589     theme->a_disabled_focused_desk =
590         RrAppearanceCopy(theme->a_disabled_focused_max);
591     theme->a_disabled_unfocused_desk =
592         RrAppearanceCopy(theme->a_disabled_unfocused_max);
593     theme->a_hover_focused_desk =
594         RrAppearanceCopy(theme->a_hover_focused_max);
595     theme->a_hover_unfocused_desk =
596         RrAppearanceCopy(theme->a_hover_unfocused_max); 
597     theme->a_toggled_focused_desk =
598         RrAppearanceCopy(theme->a_toggled_focused_max);
599    theme->a_toggled_unfocused_desk =
600         RrAppearanceCopy(theme->a_toggled_unfocused_max);
601     theme->a_unfocused_unpressed_desk =
602         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
603     theme->a_unfocused_pressed_desk =
604         RrAppearanceCopy(theme->a_unfocused_pressed_max);
605     theme->a_focused_unpressed_desk =
606         RrAppearanceCopy(theme->a_focused_unpressed_max);
607     theme->a_focused_pressed_desk =
608         RrAppearanceCopy(theme->a_focused_pressed_max);
609     theme->a_disabled_focused_shade =
610         RrAppearanceCopy(theme->a_disabled_focused_max);
611     theme->a_disabled_unfocused_shade =
612         RrAppearanceCopy(theme->a_disabled_unfocused_max);
613     theme->a_hover_focused_shade =
614         RrAppearanceCopy(theme->a_hover_focused_max);
615     theme->a_hover_unfocused_shade =
616         RrAppearanceCopy(theme->a_hover_unfocused_max);
617     theme->a_toggled_focused_shade =
618         RrAppearanceCopy(theme->a_toggled_focused_max);
619     theme->a_toggled_unfocused_shade =
620         RrAppearanceCopy(theme->a_toggled_unfocused_max);
621     theme->a_unfocused_unpressed_shade =
622         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
623     theme->a_unfocused_pressed_shade =
624         RrAppearanceCopy(theme->a_unfocused_pressed_max);
625     theme->a_focused_unpressed_shade =
626         RrAppearanceCopy(theme->a_focused_unpressed_max);
627     theme->a_focused_pressed_shade =
628         RrAppearanceCopy(theme->a_focused_pressed_max);
629     theme->a_disabled_focused_iconify =
630         RrAppearanceCopy(theme->a_disabled_focused_max);
631     theme->a_disabled_unfocused_iconify =
632         RrAppearanceCopy(theme->a_disabled_focused_max);
633     theme->a_hover_focused_iconify =
634         RrAppearanceCopy(theme->a_hover_focused_max);
635     theme->a_hover_unfocused_iconify =
636         RrAppearanceCopy(theme->a_hover_unfocused_max);
637     theme->a_unfocused_unpressed_iconify =
638         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
639     theme->a_unfocused_pressed_iconify =
640         RrAppearanceCopy(theme->a_unfocused_pressed_max);
641     theme->a_focused_unpressed_iconify =
642         RrAppearanceCopy(theme->a_focused_unpressed_max);
643     theme->a_focused_pressed_iconify =
644         RrAppearanceCopy(theme->a_focused_pressed_max);
645
646     theme->a_icon->surface.grad =
647         theme->a_clear->surface.grad =
648         theme->a_clear_tex->surface.grad =
649         theme->a_menu_normal->surface.grad =
650         theme->a_menu_disabled->surface.grad =
651         theme->a_menu_text_normal->surface.grad =
652         theme->a_menu_text_disabled->surface.grad =
653         theme->a_menu_text_selected->surface.grad =
654         theme->a_menu_bullet_normal->surface.grad =
655         theme->a_menu_bullet_selected->surface.grad = RR_SURFACE_PARENTREL;
656
657     /* set up the textures */
658     theme->a_focused_label->texture[0].type = 
659         theme->app_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
660     theme->a_focused_label->texture[0].data.text.justify = winjust;
661     theme->app_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
662     theme->a_focused_label->texture[0].data.text.font =
663         theme->app_hilite_label->texture[0].data.text.font =
664         theme->winfont_focused;
665     theme->a_focused_label->texture[0].data.text.color =
666         theme->app_hilite_label->texture[0].data.text.color =
667         theme->title_focused_color;
668
669     theme->a_unfocused_label->texture[0].type =
670         theme->app_unhilite_label->texture[0].type = RR_TEXTURE_TEXT;
671     theme->a_unfocused_label->texture[0].data.text.justify = winjust;
672     theme->app_unhilite_label->texture[0].data.text.justify =
673         RR_JUSTIFY_LEFT;
674     theme->a_unfocused_label->texture[0].data.text.font =
675         theme->app_unhilite_label->texture[0].data.text.font =
676         theme->winfont_unfocused;
677     theme->a_unfocused_label->texture[0].data.text.color =
678         theme->app_unhilite_label->texture[0].data.text.color =
679         theme->title_unfocused_color;
680
681     theme->a_menu_title->texture[0].type = RR_TEXTURE_TEXT;
682     theme->a_menu_title->texture[0].data.text.justify = mtitlejust;
683     theme->a_menu_title->texture[0].data.text.font = theme->mtitlefont;
684     theme->a_menu_title->texture[0].data.text.color = theme->menu_title_color;
685
686     theme->a_menu_text_normal->texture[0].type =
687         theme->a_menu_text_disabled->texture[0].type = 
688         theme->a_menu_text_selected->texture[0].type = RR_TEXTURE_TEXT;
689     theme->a_menu_text_normal->texture[0].data.text.justify = 
690         theme->a_menu_text_disabled->texture[0].data.text.justify = 
691         theme->a_menu_text_selected->texture[0].data.text.justify =
692         RR_JUSTIFY_LEFT;
693     theme->a_menu_text_normal->texture[0].data.text.font =
694         theme->a_menu_text_disabled->texture[0].data.text.font =
695         theme->a_menu_text_selected->texture[0].data.text.font = theme->mfont;
696     theme->a_menu_text_normal->texture[0].data.text.color = theme->menu_color;
697     theme->a_menu_text_disabled->texture[0].data.text.color =
698         theme->menu_disabled_color;
699     theme->a_menu_text_selected->texture[0].data.text.color =
700         theme->menu_selected_color;
701
702     theme->a_disabled_focused_max->texture[0].type = 
703         theme->a_disabled_unfocused_max->texture[0].type = 
704         theme->a_hover_focused_max->texture[0].type = 
705         theme->a_hover_unfocused_max->texture[0].type = 
706         theme->a_toggled_focused_max->texture[0].type = 
707         theme->a_toggled_unfocused_max->texture[0].type = 
708         theme->a_focused_unpressed_max->texture[0].type = 
709         theme->a_focused_pressed_max->texture[0].type = 
710         theme->a_unfocused_unpressed_max->texture[0].type = 
711         theme->a_unfocused_pressed_max->texture[0].type = 
712         theme->a_disabled_focused_close->texture[0].type = 
713         theme->a_disabled_unfocused_close->texture[0].type = 
714         theme->a_hover_focused_close->texture[0].type = 
715         theme->a_hover_unfocused_close->texture[0].type = 
716         theme->a_focused_unpressed_close->texture[0].type = 
717         theme->a_focused_pressed_close->texture[0].type = 
718         theme->a_unfocused_unpressed_close->texture[0].type = 
719         theme->a_unfocused_pressed_close->texture[0].type = 
720         theme->a_disabled_focused_desk->texture[0].type = 
721         theme->a_disabled_unfocused_desk->texture[0].type = 
722         theme->a_hover_focused_desk->texture[0].type = 
723         theme->a_hover_unfocused_desk->texture[0].type = 
724         theme->a_toggled_focused_desk->texture[0].type = 
725         theme->a_toggled_unfocused_desk->texture[0].type = 
726         theme->a_focused_unpressed_desk->texture[0].type = 
727         theme->a_focused_pressed_desk->texture[0].type = 
728         theme->a_unfocused_unpressed_desk->texture[0].type = 
729         theme->a_unfocused_pressed_desk->texture[0].type = 
730         theme->a_disabled_focused_shade->texture[0].type = 
731         theme->a_disabled_unfocused_shade->texture[0].type = 
732         theme->a_hover_focused_shade->texture[0].type = 
733         theme->a_hover_unfocused_shade->texture[0].type = 
734         theme->a_toggled_focused_shade->texture[0].type = 
735         theme->a_toggled_unfocused_shade->texture[0].type = 
736         theme->a_focused_unpressed_shade->texture[0].type = 
737         theme->a_focused_pressed_shade->texture[0].type = 
738         theme->a_unfocused_unpressed_shade->texture[0].type = 
739         theme->a_unfocused_pressed_shade->texture[0].type = 
740         theme->a_disabled_focused_iconify->texture[0].type = 
741         theme->a_disabled_unfocused_iconify->texture[0].type = 
742         theme->a_hover_focused_iconify->texture[0].type = 
743         theme->a_hover_unfocused_iconify->texture[0].type = 
744         theme->a_focused_unpressed_iconify->texture[0].type = 
745         theme->a_focused_pressed_iconify->texture[0].type = 
746         theme->a_unfocused_unpressed_iconify->texture[0].type = 
747         theme->a_unfocused_pressed_iconify->texture[0].type =
748         theme->a_menu_bullet_normal->texture[0].type =
749         theme->a_menu_bullet_selected->texture[0].type = RR_TEXTURE_MASK;
750     
751     theme->a_disabled_focused_max->texture[0].data.mask.mask = 
752         theme->a_disabled_unfocused_max->texture[0].data.mask.mask = 
753         theme->max_disabled_mask;
754     theme->a_hover_focused_max->texture[0].data.mask.mask = 
755         theme->a_hover_unfocused_max->texture[0].data.mask.mask = 
756         theme->max_hover_mask;
757     theme->a_focused_pressed_max->texture[0].data.mask.mask = 
758         theme->a_unfocused_pressed_max->texture[0].data.mask.mask =
759         theme->max_pressed_mask;
760     theme->a_focused_unpressed_max->texture[0].data.mask.mask = 
761         theme->a_unfocused_unpressed_max->texture[0].data.mask.mask = 
762         theme->max_mask;
763     theme->a_toggled_focused_max->texture[0].data.mask.mask = 
764         theme->a_toggled_unfocused_max->texture[0].data.mask.mask =
765         theme->max_toggled_mask;
766     theme->a_disabled_focused_close->texture[0].data.mask.mask = 
767         theme->a_disabled_unfocused_close->texture[0].data.mask.mask = 
768         theme->close_disabled_mask;
769     theme->a_hover_focused_close->texture[0].data.mask.mask = 
770         theme->a_hover_unfocused_close->texture[0].data.mask.mask = 
771         theme->close_hover_mask;
772     theme->a_focused_pressed_close->texture[0].data.mask.mask = 
773         theme->a_unfocused_pressed_close->texture[0].data.mask.mask =
774         theme->close_pressed_mask;
775     theme->a_focused_unpressed_close->texture[0].data.mask.mask = 
776         theme->a_unfocused_unpressed_close->texture[0].data.mask.mask =
777         theme->close_mask;
778     theme->a_disabled_focused_desk->texture[0].data.mask.mask = 
779         theme->a_disabled_unfocused_desk->texture[0].data.mask.mask = 
780         theme->desk_disabled_mask;
781     theme->a_hover_focused_desk->texture[0].data.mask.mask = 
782         theme->a_hover_unfocused_desk->texture[0].data.mask.mask = 
783         theme->desk_hover_mask;
784     theme->a_focused_pressed_desk->texture[0].data.mask.mask = 
785         theme->a_unfocused_pressed_desk->texture[0].data.mask.mask =
786         theme->desk_pressed_mask;
787     theme->a_focused_unpressed_desk->texture[0].data.mask.mask = 
788         theme->a_unfocused_unpressed_desk->texture[0].data.mask.mask = 
789         theme->desk_mask;
790     theme->a_toggled_focused_desk->texture[0].data.mask.mask = 
791         theme->a_toggled_unfocused_desk->texture[0].data.mask.mask =
792         theme->desk_toggled_mask;
793     theme->a_disabled_focused_shade->texture[0].data.mask.mask = 
794         theme->a_disabled_unfocused_shade->texture[0].data.mask.mask = 
795         theme->shade_disabled_mask;
796     theme->a_hover_focused_shade->texture[0].data.mask.mask = 
797         theme->a_hover_unfocused_shade->texture[0].data.mask.mask = 
798         theme->shade_hover_mask;
799     theme->a_focused_pressed_shade->texture[0].data.mask.mask = 
800         theme->a_unfocused_pressed_shade->texture[0].data.mask.mask =
801         theme->shade_pressed_mask;
802     theme->a_focused_unpressed_shade->texture[0].data.mask.mask = 
803         theme->a_unfocused_unpressed_shade->texture[0].data.mask.mask = 
804         theme->shade_mask;
805     theme->a_toggled_focused_shade->texture[0].data.mask.mask = 
806         theme->a_toggled_unfocused_shade->texture[0].data.mask.mask =
807         theme->shade_toggled_mask;
808     theme->a_disabled_focused_iconify->texture[0].data.mask.mask = 
809         theme->a_disabled_unfocused_iconify->texture[0].data.mask.mask = 
810         theme->iconify_disabled_mask;
811     theme->a_hover_focused_iconify->texture[0].data.mask.mask = 
812         theme->a_hover_unfocused_iconify->texture[0].data.mask.mask = 
813         theme->iconify_hover_mask;
814     theme->a_focused_pressed_iconify->texture[0].data.mask.mask = 
815         theme->a_unfocused_pressed_iconify->texture[0].data.mask.mask =
816         theme->iconify_pressed_mask;
817     theme->a_focused_unpressed_iconify->texture[0].data.mask.mask = 
818         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.mask = 
819         theme->iconify_mask;
820     theme->a_menu_bullet_normal->texture[0].data.mask.mask = 
821     theme->a_menu_bullet_selected->texture[0].data.mask.mask = 
822         theme->menu_bullet_mask;
823     theme->a_disabled_focused_max->texture[0].data.mask.color = 
824         theme->a_disabled_focused_close->texture[0].data.mask.color = 
825         theme->a_disabled_focused_desk->texture[0].data.mask.color = 
826         theme->a_disabled_focused_shade->texture[0].data.mask.color = 
827         theme->a_disabled_focused_iconify->texture[0].data.mask.color = 
828         theme->titlebut_disabled_focused_color;
829     theme->a_disabled_unfocused_max->texture[0].data.mask.color = 
830         theme->a_disabled_unfocused_close->texture[0].data.mask.color = 
831         theme->a_disabled_unfocused_desk->texture[0].data.mask.color = 
832         theme->a_disabled_unfocused_shade->texture[0].data.mask.color = 
833         theme->a_disabled_unfocused_iconify->texture[0].data.mask.color = 
834         theme->titlebut_disabled_unfocused_color;
835     theme->a_hover_focused_max->texture[0].data.mask.color = 
836         theme->a_hover_focused_close->texture[0].data.mask.color = 
837         theme->a_hover_focused_desk->texture[0].data.mask.color = 
838         theme->a_hover_focused_shade->texture[0].data.mask.color = 
839         theme->a_hover_focused_iconify->texture[0].data.mask.color = 
840         theme->titlebut_hover_focused_color;
841     theme->a_hover_unfocused_max->texture[0].data.mask.color = 
842         theme->a_hover_unfocused_close->texture[0].data.mask.color = 
843         theme->a_hover_unfocused_desk->texture[0].data.mask.color = 
844         theme->a_hover_unfocused_shade->texture[0].data.mask.color = 
845         theme->a_hover_unfocused_iconify->texture[0].data.mask.color = 
846         theme->titlebut_hover_unfocused_color;
847     theme->a_toggled_focused_max->texture[0].data.mask.color = 
848         theme->a_toggled_focused_desk->texture[0].data.mask.color = 
849         theme->a_toggled_focused_shade->texture[0].data.mask.color = 
850         theme->titlebut_toggled_focused_color;
851     theme->a_toggled_unfocused_max->texture[0].data.mask.color = 
852         theme->a_toggled_unfocused_desk->texture[0].data.mask.color = 
853         theme->a_toggled_unfocused_shade->texture[0].data.mask.color = 
854         theme->titlebut_toggled_unfocused_color;
855     theme->a_focused_unpressed_max->texture[0].data.mask.color = 
856         theme->a_focused_unpressed_close->texture[0].data.mask.color = 
857         theme->a_focused_unpressed_desk->texture[0].data.mask.color = 
858         theme->a_focused_unpressed_shade->texture[0].data.mask.color = 
859         theme->a_focused_unpressed_iconify->texture[0].data.mask.color = 
860         theme->titlebut_focused_unpressed_color;
861     theme->a_focused_pressed_max->texture[0].data.mask.color = 
862         theme->a_focused_pressed_close->texture[0].data.mask.color = 
863         theme->a_focused_pressed_desk->texture[0].data.mask.color = 
864         theme->a_focused_pressed_shade->texture[0].data.mask.color = 
865         theme->a_focused_pressed_iconify->texture[0].data.mask.color =
866         theme->titlebut_focused_pressed_color;
867     theme->a_unfocused_unpressed_max->texture[0].data.mask.color = 
868         theme->a_unfocused_unpressed_close->texture[0].data.mask.color = 
869         theme->a_unfocused_unpressed_desk->texture[0].data.mask.color = 
870         theme->a_unfocused_unpressed_shade->texture[0].data.mask.color = 
871         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.color = 
872         theme->titlebut_unfocused_unpressed_color;
873         theme->a_unfocused_pressed_max->texture[0].data.mask.color = 
874         theme->a_unfocused_pressed_close->texture[0].data.mask.color = 
875         theme->a_unfocused_pressed_desk->texture[0].data.mask.color = 
876         theme->a_unfocused_pressed_shade->texture[0].data.mask.color = 
877         theme->a_unfocused_pressed_iconify->texture[0].data.mask.color =
878         theme->titlebut_unfocused_pressed_color;
879     theme->a_menu_bullet_normal->texture[0].data.mask.color = 
880         theme->menu_color;
881     theme->a_menu_bullet_selected->texture[0].data.mask.color = 
882         theme->menu_selected_color;
883
884     XrmDestroyDatabase(db);
885
886     {
887         gint fl, ft, fr, fb;
888         gint ul, ut, ur, ub;
889
890         RrMargins(theme->a_focused_label, &fl, &ft, &fr, &fb);
891         RrMargins(theme->a_unfocused_label, &ul, &ut, &ur, &ub);
892         theme->label_height = theme->winfont_height
893             + MAX(ft + fb, ut + ub);
894
895         /* this would be nice I think, since padding.width can now be 0,
896            but it breaks frame.c horribly and I don't feel like fixing that
897            right now, so if anyone complains, here is how to keep text from
898            going over the title's bevel/border with a padding.width of 0 and a
899            bevelless/borderless label
900         RrMargins(theme->a_focused_title, &fl, &ft, &fr, &fb);
901         RrMargins(theme->a_unfocused_title, &ul, &ut, &ur, &ub);
902         theme->title_height = theme->label_height +
903             MAX(MAX(theme->padding * 2, ft + fb),
904                 MAX(theme->padding * 2, ut + ub));
905         */
906         theme->title_height = theme->label_height + theme->padding * 2;
907     }
908     theme->button_size = theme->label_height - 2;
909     theme->grip_width = theme->title_height * 1.5;
910
911     return theme;
912 }
913
914 void RrThemeFree(RrTheme *theme)
915 {
916     if (theme) {
917         g_free(theme->name);
918
919         RrColorFree(theme->b_color);
920         RrColorFree(theme->cb_unfocused_color);
921         RrColorFree(theme->cb_focused_color);
922         RrColorFree(theme->title_unfocused_color);
923         RrColorFree(theme->title_focused_color);
924         RrColorFree(theme->titlebut_disabled_focused_color);
925         RrColorFree(theme->titlebut_disabled_unfocused_color);
926         RrColorFree(theme->titlebut_hover_focused_color);
927         RrColorFree(theme->titlebut_hover_unfocused_color);
928         RrColorFree(theme->titlebut_toggled_focused_color);
929         RrColorFree(theme->titlebut_toggled_unfocused_color);
930         RrColorFree(theme->titlebut_unfocused_pressed_color);
931         RrColorFree(theme->titlebut_focused_pressed_color);
932         RrColorFree(theme->titlebut_unfocused_unpressed_color);
933         RrColorFree(theme->titlebut_focused_unpressed_color);
934         RrColorFree(theme->menu_color);
935         RrColorFree(theme->menu_title_color);
936         RrColorFree(theme->menu_disabled_color);
937         RrColorFree(theme->menu_selected_color);
938
939         g_free(theme->def_win_icon);
940
941         RrPixmapMaskFree(theme->max_mask);
942         RrPixmapMaskFree(theme->max_toggled_mask);
943         RrPixmapMaskFree(theme->max_disabled_mask);
944         RrPixmapMaskFree(theme->max_hover_mask);
945         RrPixmapMaskFree(theme->max_pressed_mask);
946         RrPixmapMaskFree(theme->desk_mask);
947         RrPixmapMaskFree(theme->desk_toggled_mask);
948         RrPixmapMaskFree(theme->desk_disabled_mask);
949         RrPixmapMaskFree(theme->desk_hover_mask);
950         RrPixmapMaskFree(theme->desk_pressed_mask);
951         RrPixmapMaskFree(theme->shade_mask);
952         RrPixmapMaskFree(theme->shade_toggled_mask);
953         RrPixmapMaskFree(theme->shade_disabled_mask);
954         RrPixmapMaskFree(theme->shade_hover_mask);
955         RrPixmapMaskFree(theme->shade_pressed_mask);
956         RrPixmapMaskFree(theme->iconify_mask);
957         RrPixmapMaskFree(theme->iconify_disabled_mask);
958         RrPixmapMaskFree(theme->iconify_hover_mask);
959         RrPixmapMaskFree(theme->iconify_pressed_mask);
960         RrPixmapMaskFree(theme->close_mask);
961         RrPixmapMaskFree(theme->close_disabled_mask);
962         RrPixmapMaskFree(theme->close_hover_mask);
963         RrPixmapMaskFree(theme->close_pressed_mask);
964         RrPixmapMaskFree(theme->menu_bullet_mask);
965
966         RrFontClose(theme->winfont_focused); 
967         RrFontClose(theme->winfont_unfocused);
968         RrFontClose(theme->mtitlefont);
969         RrFontClose(theme->mfont);
970
971         RrAppearanceFree(theme->a_disabled_focused_max);
972         RrAppearanceFree(theme->a_disabled_unfocused_max);
973         RrAppearanceFree(theme->a_hover_focused_max);
974         RrAppearanceFree(theme->a_hover_unfocused_max);
975         RrAppearanceFree(theme->a_toggled_focused_max);
976         RrAppearanceFree(theme->a_toggled_unfocused_max);
977         RrAppearanceFree(theme->a_focused_unpressed_max);
978         RrAppearanceFree(theme->a_focused_pressed_max);
979         RrAppearanceFree(theme->a_unfocused_unpressed_max);
980         RrAppearanceFree(theme->a_unfocused_pressed_max);
981         RrAppearanceFree(theme->a_disabled_focused_close);
982         RrAppearanceFree(theme->a_disabled_unfocused_close);
983         RrAppearanceFree(theme->a_hover_focused_close);
984         RrAppearanceFree(theme->a_hover_unfocused_close);
985         RrAppearanceFree(theme->a_focused_unpressed_close);
986         RrAppearanceFree(theme->a_focused_pressed_close);
987         RrAppearanceFree(theme->a_unfocused_unpressed_close);
988         RrAppearanceFree(theme->a_unfocused_pressed_close);
989         RrAppearanceFree(theme->a_disabled_focused_desk);
990         RrAppearanceFree(theme->a_disabled_unfocused_desk);
991         RrAppearanceFree(theme->a_hover_focused_desk);
992         RrAppearanceFree(theme->a_hover_unfocused_desk);
993         RrAppearanceFree(theme->a_toggled_focused_desk);
994         RrAppearanceFree(theme->a_toggled_unfocused_desk);
995         RrAppearanceFree(theme->a_focused_unpressed_desk);
996         RrAppearanceFree(theme->a_focused_pressed_desk);
997         RrAppearanceFree(theme->a_unfocused_unpressed_desk);
998         RrAppearanceFree(theme->a_unfocused_pressed_desk);
999         RrAppearanceFree(theme->a_disabled_focused_shade);
1000         RrAppearanceFree(theme->a_disabled_unfocused_shade);
1001         RrAppearanceFree(theme->a_hover_focused_shade);
1002         RrAppearanceFree(theme->a_hover_unfocused_shade);
1003         RrAppearanceFree(theme->a_toggled_focused_shade);
1004         RrAppearanceFree(theme->a_toggled_unfocused_shade);
1005         RrAppearanceFree(theme->a_focused_unpressed_shade);
1006         RrAppearanceFree(theme->a_focused_pressed_shade);
1007         RrAppearanceFree(theme->a_unfocused_unpressed_shade);
1008         RrAppearanceFree(theme->a_unfocused_pressed_shade);
1009         RrAppearanceFree(theme->a_disabled_focused_iconify);
1010         RrAppearanceFree(theme->a_disabled_unfocused_iconify);
1011         RrAppearanceFree(theme->a_hover_focused_iconify);
1012         RrAppearanceFree(theme->a_hover_unfocused_iconify);
1013         RrAppearanceFree(theme->a_focused_unpressed_iconify);
1014         RrAppearanceFree(theme->a_focused_pressed_iconify);
1015         RrAppearanceFree(theme->a_unfocused_unpressed_iconify);
1016         RrAppearanceFree(theme->a_unfocused_pressed_iconify);
1017         RrAppearanceFree(theme->a_focused_grip);
1018         RrAppearanceFree(theme->a_unfocused_grip);
1019         RrAppearanceFree(theme->a_focused_title);
1020         RrAppearanceFree(theme->a_unfocused_title);
1021         RrAppearanceFree(theme->a_focused_label);
1022         RrAppearanceFree(theme->a_unfocused_label);
1023         RrAppearanceFree(theme->a_icon);
1024         RrAppearanceFree(theme->a_focused_handle);
1025         RrAppearanceFree(theme->a_unfocused_handle);
1026         RrAppearanceFree(theme->a_menu);
1027         RrAppearanceFree(theme->a_menu_title);
1028         RrAppearanceFree(theme->a_menu_normal);
1029         RrAppearanceFree(theme->a_menu_disabled);
1030         RrAppearanceFree(theme->a_menu_selected);
1031         RrAppearanceFree(theme->a_menu_text_normal);
1032         RrAppearanceFree(theme->a_menu_text_disabled);
1033         RrAppearanceFree(theme->a_menu_text_selected);
1034         RrAppearanceFree(theme->a_menu_bullet_normal);
1035         RrAppearanceFree(theme->a_menu_bullet_selected);
1036         RrAppearanceFree(theme->a_clear);
1037         RrAppearanceFree(theme->a_clear_tex);
1038         RrAppearanceFree(theme->app_hilite_bg);
1039         RrAppearanceFree(theme->app_unhilite_bg);
1040         RrAppearanceFree(theme->app_hilite_label);
1041         RrAppearanceFree(theme->app_unhilite_label);
1042     }
1043 }
1044
1045 static XrmDatabase loaddb(RrTheme *theme, char *name)
1046 {
1047     XrmDatabase db;
1048
1049     char *s = g_build_filename(g_get_home_dir(), ".openbox", "themes",
1050                                name, "themerc", NULL);
1051     if ((db = XrmGetFileDatabase(s)))
1052         theme->path = g_path_get_dirname(s);
1053     g_free(s);
1054     if (db == NULL) {
1055         char *s = g_build_filename(THEMEDIR, name, "themerc", NULL);
1056         if ((db = XrmGetFileDatabase(s)))
1057             theme->path = g_path_get_dirname(s);
1058         g_free(s);
1059     }
1060     if (db == NULL) {
1061         char *s = g_build_filename(name, "themerc", NULL);
1062         if ((db = XrmGetFileDatabase(s)))
1063             theme->path = g_path_get_dirname(s);
1064         g_free(s);
1065     }
1066
1067     return db;
1068 }
1069
1070 static char *create_class_name(char *rname)
1071 {
1072     char *rclass = g_strdup(rname);
1073     char *p = rclass;
1074
1075     while (TRUE) {
1076         *p = toupper(*p);
1077         p = strchr(p+1, '.');
1078         if (p == NULL) break;
1079         ++p;
1080         if (*p == '\0') break;
1081     }
1082     return rclass;
1083 }
1084
1085 static gboolean read_int(XrmDatabase db, char *rname, int *value)
1086 {
1087     gboolean ret = FALSE;
1088     char *rclass = create_class_name(rname);
1089     char *rettype, *end;
1090     XrmValue retvalue;
1091   
1092     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1093         retvalue.addr != NULL) {
1094         *value = (int)strtol(retvalue.addr, &end, 10);
1095         if (end != retvalue.addr)
1096             ret = TRUE;
1097     }
1098
1099     g_free(rclass);
1100     return ret;
1101 }
1102
1103 static gboolean read_string(XrmDatabase db, char *rname, char **value)
1104 {
1105     gboolean ret = FALSE;
1106     char *rclass = create_class_name(rname);
1107     char *rettype;
1108     XrmValue retvalue;
1109   
1110     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1111         retvalue.addr != NULL) {
1112         *value = retvalue.addr;
1113         ret = TRUE;
1114     }
1115
1116     g_free(rclass);
1117     return ret;
1118 }
1119
1120 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
1121                            gchar *rname, RrColor **value)
1122 {
1123     gboolean ret = FALSE;
1124     char *rclass = create_class_name(rname);
1125     char *rettype;
1126     XrmValue retvalue;
1127   
1128     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1129         retvalue.addr != NULL) {
1130         RrColor *c = RrColorParse(inst, retvalue.addr);
1131         if (c != NULL) {
1132             *value = c;
1133             ret = TRUE;
1134         }
1135     }
1136
1137     g_free(rclass);
1138     return ret;
1139 }
1140
1141 static gboolean read_mask(const RrInstance *inst,
1142                           gchar *maskname, RrTheme *theme,
1143                           RrPixmapMask **value)
1144 {
1145     gboolean ret = FALSE;
1146     char *s;
1147     int hx, hy; /* ignored */
1148     unsigned int w, h;
1149     unsigned char *b;
1150
1151     s = g_build_filename(theme->path, maskname, NULL);
1152     if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
1153         ret = TRUE;
1154         *value = RrPixmapMaskNew(inst, w, h, (char*)b);
1155         XFree(b);
1156     }
1157     g_free(s);
1158
1159     return ret;
1160 }
1161
1162 static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
1163                              RrReliefType *relief, RrBevelType *bevel,
1164                              gboolean *interlaced, gboolean *border,
1165                              gboolean allow_trans)
1166 {
1167     char *t;
1168
1169     /* convert to all lowercase */
1170     for (t = tex; *t != '\0'; ++t)
1171         *t = g_ascii_tolower(*t);
1172
1173     if (allow_trans && strstr(tex, "parentrelative") != NULL) {
1174         *grad = RR_SURFACE_PARENTREL;
1175     } else {
1176         if (strstr(tex, "gradient") != NULL) {
1177             if (strstr(tex, "crossdiagonal") != NULL)
1178                 *grad = RR_SURFACE_CROSS_DIAGONAL;
1179             else if (strstr(tex, "pyramid") != NULL)
1180                 *grad = RR_SURFACE_PYRAMID;
1181             else if (strstr(tex, "horizontal") != NULL)
1182                 *grad = RR_SURFACE_HORIZONTAL;
1183             else if (strstr(tex, "vertical") != NULL)
1184                 *grad = RR_SURFACE_VERTICAL;
1185             else
1186                 *grad = RR_SURFACE_DIAGONAL;
1187         } else {
1188             *grad = RR_SURFACE_SOLID;
1189         }
1190
1191         if (strstr(tex, "sunken") != NULL)
1192             *relief = RR_RELIEF_SUNKEN;
1193         else if (strstr(tex, "flat") != NULL)
1194             *relief = RR_RELIEF_FLAT;
1195         else
1196             *relief = RR_RELIEF_RAISED;
1197         
1198         *border = FALSE;
1199         if (*relief == RR_RELIEF_FLAT) {
1200             if (strstr(tex, "border") != NULL)
1201                 *border = TRUE;
1202         } else {
1203             if (strstr(tex, "bevel2") != NULL)
1204                 *bevel = RR_BEVEL_2;
1205             else
1206                 *bevel = RR_BEVEL_1;
1207         }
1208
1209         if (strstr(tex, "interlaced") != NULL)
1210             *interlaced = TRUE;
1211         else
1212             *interlaced = FALSE;
1213     }
1214 }
1215
1216
1217 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
1218                                 gchar *rname, RrAppearance *value,
1219                                 gboolean allow_trans)
1220 {
1221     gboolean ret = FALSE;
1222     char *rclass = create_class_name(rname);
1223     char *cname, *ctoname, *bcname, *icname;
1224     char *rettype;
1225     XrmValue retvalue;
1226
1227     cname = g_strconcat(rname, ".color", NULL);
1228     ctoname = g_strconcat(rname, ".colorTo", NULL);
1229     bcname = g_strconcat(rname, ".border.color", NULL);
1230     icname = g_strconcat(rname, ".interlace.color", NULL);
1231
1232     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1233         retvalue.addr != NULL) {
1234         parse_appearance(retvalue.addr,
1235                          &value->surface.grad,
1236                          &value->surface.relief,
1237                          &value->surface.bevel,
1238                          &value->surface.interlaced,
1239                          &value->surface.border,
1240                          allow_trans);
1241         if (!read_color(db, inst, cname, &value->surface.primary))
1242             value->surface.primary = RrColorNew(inst, 0, 0, 0);
1243         if (!read_color(db, inst, ctoname, &value->surface.secondary))
1244             value->surface.secondary = RrColorNew(inst, 0, 0, 0);
1245         if (value->surface.border)
1246             if (!read_color(db, inst, bcname,
1247                             &value->surface.border_color))
1248                 value->surface.border_color = RrColorNew(inst, 0, 0, 0);
1249         if (value->surface.interlaced)
1250             if (!read_color(db, inst, icname,
1251                             &value->surface.interlace_color))
1252                 value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
1253         ret = TRUE;
1254     }
1255
1256     g_free(icname);
1257     g_free(bcname);
1258     g_free(ctoname);
1259     g_free(cname);
1260     g_free(rclass);
1261     return ret;
1262 }
1263
1264 static void set_default_appearance(RrAppearance *a)
1265 {
1266     a->surface.grad = RR_SURFACE_SOLID;
1267     a->surface.relief = RR_RELIEF_FLAT;
1268     a->surface.bevel = RR_BEVEL_1;
1269     a->surface.interlaced = FALSE;
1270     a->surface.border = FALSE;
1271     a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
1272     a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
1273 }
1274
1275 /* Reads the output from gimp's C-Source file format into valid RGBA data for
1276    an RrTextureRGBA. */
1277 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
1278 {
1279     RrPixel32 *im, *p;
1280     gint i;
1281
1282     p = im = g_memdup(OB_DEFAULT_ICON_pixel_data,
1283                       OB_DEFAULT_ICON_WIDTH * OB_DEFAULT_ICON_HEIGHT *
1284                       sizeof(RrPixel32));
1285
1286     for (i = 0; i < OB_DEFAULT_ICON_WIDTH*OB_DEFAULT_ICON_HEIGHT; ++i) {
1287         guchar a = ((*p >> 24) & 0xff);
1288         guchar b = ((*p >> 16) & 0xff);
1289         guchar g = ((*p >>  8) & 0xff);
1290         guchar r = ((*p >>  0) & 0xff);
1291
1292         *p = ((r << RrDefaultRedOffset) +
1293               (g << RrDefaultGreenOffset) +
1294               (b << RrDefaultBlueOffset) +
1295               (a << RrDefaultAlphaOffset));
1296         p++;
1297     }
1298
1299     return im;
1300 }