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