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