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