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