Fix some memleaks
[mikachu/openbox.git] / render / theme.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    theme.c for the Openbox window manager
4    Copyright (c) 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(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                           RrTheme *theme, const gchar *maskname,
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, const gchar *name,
50                     gboolean allow_fallback,
51                     RrFont *active_window_font, RrFont *inactive_window_font,
52                     RrFont *menu_title_font, RrFont *menu_item_font,
53                     RrFont *osd_font)
54 {
55     XrmDatabase db = NULL;
56     RrJustify winjust, mtitlejust;
57     gchar *str;
58     RrTheme *theme;
59     gchar *path;
60     gboolean userdef;
61
62     if (name) {
63         db = loaddb(name, &path);
64         if (db == NULL) {
65             g_message("Unable to load the theme '%s'", name);
66             if (allow_fallback)
67                 g_message("Falling back to the default theme '%s'",
68                           DEFAULT_THEME);
69             /* fallback to the default theme */
70             name = NULL;
71         }
72     }
73     if (name == NULL) {
74         if (allow_fallback) {
75             db = loaddb(DEFAULT_THEME, &path);
76             if (db == NULL) {
77                 g_message("Unable to load the theme '%s'", DEFAULT_THEME);
78                 return NULL;
79             }
80         } else
81             return NULL;
82     }
83
84     theme = g_new0(RrTheme, 1);
85
86     theme->inst = inst;
87     theme->name = g_strdup(name ? name : DEFAULT_THEME);
88
89     theme->a_disabled_focused_max = RrAppearanceNew(inst, 1);
90     theme->a_disabled_unfocused_max = RrAppearanceNew(inst, 1);
91     theme->a_hover_focused_max = RrAppearanceNew(inst, 1);
92     theme->a_hover_unfocused_max = RrAppearanceNew(inst, 1);
93     theme->a_toggled_focused_unpressed_max = RrAppearanceNew(inst, 1);
94     theme->a_toggled_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
95     theme->a_toggled_hover_focused_max = RrAppearanceNew(inst, 1);
96     theme->a_toggled_hover_unfocused_max = RrAppearanceNew(inst, 1);
97     theme->a_toggled_focused_pressed_max = RrAppearanceNew(inst, 1);
98     theme->a_toggled_unfocused_pressed_max = RrAppearanceNew(inst, 1);
99     theme->a_focused_unpressed_max = RrAppearanceNew(inst, 1);
100     theme->a_focused_pressed_max = RrAppearanceNew(inst, 1);
101     theme->a_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
102     theme->a_unfocused_pressed_max = RrAppearanceNew(inst, 1);
103     theme->a_focused_grip = RrAppearanceNew(inst, 0);
104     theme->a_unfocused_grip = RrAppearanceNew(inst, 0);
105     theme->a_focused_title = RrAppearanceNew(inst, 0);
106     theme->a_unfocused_title = RrAppearanceNew(inst, 0);
107     theme->a_focused_label = RrAppearanceNew(inst, 1);
108     theme->a_unfocused_label = RrAppearanceNew(inst, 1);
109     theme->a_icon = RrAppearanceNew(inst, 1);
110     theme->a_focused_handle = RrAppearanceNew(inst, 0);
111     theme->a_unfocused_handle = RrAppearanceNew(inst, 0);
112     theme->a_menu = RrAppearanceNew(inst, 0);
113     theme->a_menu_title = RrAppearanceNew(inst, 0);
114     theme->a_menu_text_title = RrAppearanceNew(inst, 1);
115     theme->a_menu_normal = RrAppearanceNew(inst, 0);
116     theme->a_menu_selected = RrAppearanceNew(inst, 0);
117     theme->a_menu_disabled = RrAppearanceNew(inst, 0);
118     theme->a_menu_text_normal = RrAppearanceNew(inst, 1);
119     theme->a_menu_text_selected = RrAppearanceNew(inst, 1);
120     theme->a_menu_text_disabled = RrAppearanceNew(inst, 1);
121     theme->a_menu_text_disabled_selected = RrAppearanceNew(inst, 1);
122     theme->a_menu_bullet_normal = RrAppearanceNew(inst, 1);
123     theme->a_menu_bullet_selected = RrAppearanceNew(inst, 1);
124     theme->a_clear = RrAppearanceNew(inst, 0);
125     theme->a_clear_tex = RrAppearanceNew(inst, 1);
126     theme->osd_hilite_bg = RrAppearanceNew(inst, 0);
127     theme->osd_hilite_label = RrAppearanceNew(inst, 1);
128     theme->osd_hilite_fg = RrAppearanceNew(inst, 0);
129     theme->osd_unhilite_fg = RrAppearanceNew(inst, 0);
130
131     /* load the font stuff */
132     if (active_window_font) {
133         theme->win_font_focused = active_window_font;
134         RrFontRef(active_window_font);
135     } else
136         theme->win_font_focused = RrFontOpenDefault(inst);
137
138     if (inactive_window_font) {
139         theme->win_font_unfocused = inactive_window_font;
140         RrFontRef(inactive_window_font);
141     } else
142         theme->win_font_unfocused = RrFontOpenDefault(inst);
143
144     winjust = RR_JUSTIFY_LEFT;
145     if (read_string(db, "window.label.text.justify", &str)) {
146         if (!g_ascii_strcasecmp(str, "right"))
147             winjust = RR_JUSTIFY_RIGHT;
148         else if (!g_ascii_strcasecmp(str, "center"))
149             winjust = RR_JUSTIFY_CENTER;
150     }
151
152     if (menu_title_font) {
153         theme->menu_title_font = menu_title_font;
154         RrFontRef(menu_title_font);
155     } else
156         theme->menu_title_font = RrFontOpenDefault(inst);
157
158     mtitlejust = RR_JUSTIFY_LEFT;
159     if (read_string(db, "menu.title.text.justify", &str)) {
160         if (!g_ascii_strcasecmp(str, "right"))
161             mtitlejust = RR_JUSTIFY_RIGHT;
162         else if (!g_ascii_strcasecmp(str, "center"))
163             mtitlejust = RR_JUSTIFY_CENTER;
164     }
165
166     if (menu_item_font) {
167         theme->menu_font = menu_item_font;
168         RrFontRef(menu_item_font);
169     } else
170         theme->menu_font = RrFontOpenDefault(inst);
171
172     if (osd_font) {
173         theme->osd_font = osd_font;
174         RrFontRef(osd_font);
175     } else
176         theme->osd_font = RrFontOpenDefault(inst);
177
178     /* load direct dimensions */
179     if (!read_int(db, "menu.overlap", &theme->menu_overlap) ||
180         theme->menu_overlap < -100 || theme->menu_overlap > 100)
181         theme->menu_overlap = 0;
182     if (!read_int(db, "window.handle.width", &theme->handle_height) ||
183         theme->handle_height < 0 || theme->handle_height > 100)
184         theme->handle_height = 6;
185     if (!read_int(db, "padding.width", &theme->paddingx) ||
186         theme->paddingx < 0 || theme->paddingx > 100)
187         theme->paddingx = 3;
188     if (!read_int(db, "padding.height", &theme->paddingy) ||
189         theme->paddingy < 0 || theme->paddingy > 100)
190         theme->paddingy = theme->paddingx;
191     if (!read_int(db, "border.width", &theme->fbwidth) ||
192         theme->fbwidth < 0 || theme->fbwidth > 100)
193         theme->fbwidth = 1;
194     /* menu border width inherits from the frame border width */
195     if (!read_int(db, "menu.border.width", &theme->mbwidth) ||
196         theme->mbwidth < 0 || theme->mbwidth > 100)
197         theme->mbwidth = theme->fbwidth;
198     /* osd border width inherits from the frame border width */
199     if (!read_int(db, "osd.border.width", &theme->obwidth) ||
200         theme->obwidth < 0 || theme->obwidth > 100)
201         theme->obwidth = theme->fbwidth;
202     if (!read_int(db, "window.client.padding.width", &theme->cbwidthx) ||
203         theme->cbwidthx < 0 || theme->cbwidthx > 100)
204         theme->cbwidthx = theme->paddingx;
205     if (!read_int(db, "window.client.padding.height", &theme->cbwidthy) ||
206         theme->cbwidthy < 0 || theme->cbwidthy > 100)
207         theme->cbwidthy = theme->cbwidthx;
208
209     /* load colors */
210     if (!read_color(db, inst,
211                     "window.active.border.color",
212                     &theme->frame_focused_border_color) &&
213         !read_color(db, inst,
214                     "border.color",
215                     &theme->frame_focused_border_color))
216         theme->frame_focused_border_color = RrColorNew(inst, 0, 0, 0);
217     /* title separator focused color inherits from focused boder color */
218     if (!read_color(db, inst,
219                     "window.active.title.separator.color",
220                     &theme->title_separator_focused_color))
221         theme->title_separator_focused_color =
222             RrColorNew(inst,
223                        theme->frame_focused_border_color->r,
224                        theme->frame_focused_border_color->g,
225                        theme->frame_focused_border_color->b);
226     /* unfocused border color inherits from frame focused border color */
227     if (!read_color(db, inst,
228                     "window.inactive.border.color",
229                     &theme->frame_unfocused_border_color))
230         theme->frame_unfocused_border_color =
231             RrColorNew(inst, theme->frame_focused_border_color->r,
232                        theme->frame_focused_border_color->g,
233                        theme->frame_focused_border_color->b);
234     /* title separator unfocused color inherits from unfocused boder color */
235     if (!read_color(db, inst,
236                     "window.inactive.title.separator.color",
237                     &theme->title_separator_unfocused_color))
238         theme->title_separator_unfocused_color =
239             RrColorNew(inst,
240                        theme->frame_unfocused_border_color->r,
241                        theme->frame_unfocused_border_color->g,
242                        theme->frame_unfocused_border_color->b);
243
244     /* menu border color inherits from frame focused border color */
245     if (!read_color(db, inst, "menu.border.color", &theme->menu_border_color))
246         theme->menu_border_color =
247             RrColorNew(inst,
248                        theme->frame_focused_border_color->r,
249                        theme->frame_focused_border_color->g,
250                        theme->frame_focused_border_color->b);
251     /* osd border color inherits from frame focused border color */
252     if (!read_color(db, inst, "osd.border.color", &theme->osd_border_color))
253         theme->osd_border_color =
254             RrColorNew(inst,
255                        theme->frame_focused_border_color->r,
256                        theme->frame_focused_border_color->g,
257                        theme->frame_focused_border_color->b);
258     if (!read_color(db, inst,
259                     "window.active.client.color",
260                     &theme->cb_focused_color))
261         theme->cb_focused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
262     if (!read_color(db, inst,
263                     "window.inactive.client.color",
264                     &theme->cb_unfocused_color))
265         theme->cb_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
266     if (!read_color(db, inst,
267                     "window.active.label.text.color",
268                     &theme->title_focused_color))
269         theme->title_focused_color = RrColorNew(inst, 0x0, 0x0, 0x0);
270     if (!read_color(db, inst, "osd.label.text.color", &theme->osd_color))
271         theme->osd_color = RrColorNew(inst,
272                                       theme->title_focused_color->r,
273                                       theme->title_focused_color->g,
274                                       theme->title_focused_color->b);
275     if (!read_color(db, inst,
276                     "window.inactive.label.text.color",
277                     &theme->title_unfocused_color))
278         theme->title_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
279     if (!read_color(db, inst,
280                     "window.active.button.unpressed.image.color",
281                     &theme->titlebut_focused_unpressed_color))
282         theme->titlebut_focused_unpressed_color = RrColorNew(inst, 0, 0, 0);
283     if (!read_color(db, inst,
284                     "window.inactive.button.unpressed.image.color",
285                     &theme->titlebut_unfocused_unpressed_color))
286         theme->titlebut_unfocused_unpressed_color =
287             RrColorNew(inst, 0xff, 0xff, 0xff);
288     if (!read_color(db, inst,
289                     "window.active.button.pressed.image.color",
290                     &theme->titlebut_focused_pressed_color))
291         theme->titlebut_focused_pressed_color =
292             RrColorNew(inst,
293                        theme->titlebut_focused_unpressed_color->r,
294                        theme->titlebut_focused_unpressed_color->g,
295                        theme->titlebut_focused_unpressed_color->b);
296     if (!read_color(db, inst,
297                     "window.inactive.button.pressed.image.color",
298                     &theme->titlebut_unfocused_pressed_color))
299         theme->titlebut_unfocused_pressed_color =
300             RrColorNew(inst,
301                        theme->titlebut_unfocused_unpressed_color->r,
302                        theme->titlebut_unfocused_unpressed_color->g,
303                        theme->titlebut_unfocused_unpressed_color->b);
304     if (!read_color(db, inst,
305                     "window.active.button.disabled.image.color",
306                     &theme->titlebut_disabled_focused_color))
307         theme->titlebut_disabled_focused_color =
308             RrColorNew(inst, 0xff, 0xff, 0xff);
309     if (!read_color(db, inst,
310                     "window.inactive.button.disabled.image.color",
311                     &theme->titlebut_disabled_unfocused_color))
312         theme->titlebut_disabled_unfocused_color = RrColorNew(inst, 0, 0, 0);
313     if (!read_color(db, inst,
314                     "window.active.button.hover.image.color",
315                     &theme->titlebut_hover_focused_color))
316         theme->titlebut_hover_focused_color =
317             RrColorNew(inst,
318                        theme->titlebut_focused_unpressed_color->r,
319                        theme->titlebut_focused_unpressed_color->g,
320                        theme->titlebut_focused_unpressed_color->b);
321     if (!read_color(db, inst,
322                     "window.inactive.button.hover.image.color",
323                     &theme->titlebut_hover_unfocused_color))
324         theme->titlebut_hover_unfocused_color =
325             RrColorNew(inst,
326                        theme->titlebut_unfocused_unpressed_color->r,
327                        theme->titlebut_unfocused_unpressed_color->g,
328                        theme->titlebut_unfocused_unpressed_color->b);
329     if (!read_color(db, inst,
330                     "window.active.button.toggled.unpressed.image.color",
331                     &theme->titlebut_toggled_focused_unpressed_color) &&
332         !read_color(db, inst,
333                     "window.active.button.toggled.image.color",
334                     &theme->titlebut_toggled_focused_unpressed_color))
335         theme->titlebut_toggled_focused_unpressed_color =
336             RrColorNew(inst,
337                        theme->titlebut_focused_pressed_color->r,
338                        theme->titlebut_focused_pressed_color->g,
339                        theme->titlebut_focused_pressed_color->b);
340     if (!read_color(db, inst,
341                     "window.inactive.button.toggled.unpressed.image.color",
342                     &theme->titlebut_toggled_unfocused_unpressed_color) &&
343         !read_color(db, inst,
344                     "window.inactive.button.toggled.image.color",
345                     &theme->titlebut_toggled_unfocused_unpressed_color))
346         theme->titlebut_toggled_unfocused_unpressed_color =
347             RrColorNew(inst,
348                        theme->titlebut_unfocused_pressed_color->r,
349                        theme->titlebut_unfocused_pressed_color->g,
350                        theme->titlebut_unfocused_pressed_color->b);
351     if (!read_color(db, inst,
352                     "window.active.button.toggled.hover.image.color",
353                     &theme->titlebut_toggled_hover_focused_color))
354         theme->titlebut_toggled_hover_focused_color =
355             RrColorNew(inst,
356                        theme->titlebut_toggled_focused_unpressed_color->r,
357                        theme->titlebut_toggled_focused_unpressed_color->g,
358                        theme->titlebut_toggled_focused_unpressed_color->b);
359     if (!read_color(db, inst,
360                     "window.inactive.button.toggled.hover.image.color",
361                     &theme->titlebut_toggled_hover_unfocused_color))
362         theme->titlebut_toggled_hover_unfocused_color =
363             RrColorNew(inst,
364                        theme->titlebut_toggled_unfocused_unpressed_color->r,
365                        theme->titlebut_toggled_unfocused_unpressed_color->g,
366                        theme->titlebut_toggled_unfocused_unpressed_color->b);
367     if (!read_color(db, inst,
368                     "window.active.button.toggled.pressed.image.color",
369                     &theme->titlebut_toggled_focused_pressed_color))
370         theme->titlebut_toggled_focused_pressed_color =
371             RrColorNew(inst,
372                        theme->titlebut_focused_pressed_color->r,
373                        theme->titlebut_focused_pressed_color->g,
374                        theme->titlebut_focused_pressed_color->b);
375     if (!read_color(db, inst,
376                     "window.inactive.button.toggled.pressed.image.color",
377                     &theme->titlebut_toggled_unfocused_pressed_color))
378         theme->titlebut_toggled_unfocused_pressed_color =
379             RrColorNew(inst,
380                        theme->titlebut_unfocused_pressed_color->r,
381                        theme->titlebut_unfocused_pressed_color->g,
382                        theme->titlebut_unfocused_pressed_color->b);
383     if (!read_color(db, inst,
384                     "menu.title.text.color", &theme->menu_title_color))
385         theme->menu_title_color = RrColorNew(inst, 0, 0, 0);
386     if (!read_color(db, inst,
387                     "menu.items.text.color", &theme->menu_color))
388         theme->menu_color = RrColorNew(inst, 0xff, 0xff, 0xff);
389     if (!read_color(db, inst,
390                     "menu.items.disabled.text.color",
391                     &theme->menu_disabled_color))
392         theme->menu_disabled_color = RrColorNew(inst, 0, 0, 0);
393     if (!read_color(db, inst,
394                     "menu.items.active.disabled.text.color",
395                     &theme->menu_disabled_selected_color))
396         theme->menu_disabled_selected_color =
397             RrColorNew(inst,
398                        theme->menu_disabled_color->r,
399                        theme->menu_disabled_color->g,
400                        theme->menu_disabled_color->b);
401     if (!read_color(db, inst,
402                     "menu.items.active.text.color",
403                     &theme->menu_selected_color))
404         theme->menu_selected_color = RrColorNew(inst, 0, 0, 0);
405
406     /* load the image masks */
407
408     /* maximize button masks */
409     userdef = TRUE;
410     if (!read_mask(inst, path, theme, "max.xbm", &theme->max_mask)) {
411             guchar data[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
412             theme->max_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
413             userdef = FALSE;
414     }
415     if (!read_mask(inst, path, theme, "max_toggled.xbm",
416                    &theme->max_toggled_mask))
417     {
418         if (userdef)
419             theme->max_toggled_mask = RrPixmapMaskCopy(theme->max_mask);
420         else {
421             guchar data[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f };
422             theme->max_toggled_mask = RrPixmapMaskNew(inst, 6, 6,(gchar*)data);
423         }
424     }
425     if (!read_mask(inst, path, theme, "max_pressed.xbm",
426                    &theme->max_pressed_mask))
427         theme->max_pressed_mask = RrPixmapMaskCopy(theme->max_mask);
428     if (!read_mask(inst,path,theme,"max_disabled.xbm",
429                    &theme->max_disabled_mask))
430         theme->max_disabled_mask = RrPixmapMaskCopy(theme->max_mask);
431     if (!read_mask(inst, path, theme, "max_hover.xbm", &theme->max_hover_mask))
432         theme->max_hover_mask = RrPixmapMaskCopy(theme->max_mask);
433     if (!read_mask(inst, path, theme, "max_toggled_pressed.xbm",
434                    &theme->max_toggled_pressed_mask))
435         theme->max_toggled_pressed_mask =
436             RrPixmapMaskCopy(theme->max_toggled_mask);
437     if (!read_mask(inst, path, theme, "max_toggled_hover.xbm",
438                    &theme->max_toggled_hover_mask))
439         theme->max_toggled_hover_mask =
440             RrPixmapMaskCopy(theme->max_toggled_mask);
441
442     /* iconify button masks */
443     if (!read_mask(inst, path, theme, "iconify.xbm", &theme->iconify_mask)) {
444         guchar data[] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f };
445         theme->iconify_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
446     }
447     if (!read_mask(inst, path, theme, "iconify_pressed.xbm",
448                    &theme->iconify_pressed_mask))
449         theme->iconify_pressed_mask = RrPixmapMaskCopy(theme->iconify_mask);
450     if (!read_mask(inst, path, theme, "iconify_disabled.xbm",
451                    &theme->iconify_disabled_mask))
452         theme->iconify_disabled_mask = RrPixmapMaskCopy(theme->iconify_mask);
453     if (!read_mask(inst, path, theme, "iconify_hover.xbm",
454                    &theme->iconify_hover_mask))
455         theme->iconify_hover_mask = RrPixmapMaskCopy(theme->iconify_mask);
456
457     /* all desktops button masks */
458     userdef = TRUE;
459     if (!read_mask(inst, path, theme, "desk.xbm", &theme->desk_mask)) {
460         guchar data[] = { 0x33, 0x33, 0x00, 0x00, 0x33, 0x33 };
461         theme->desk_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
462         userdef = FALSE;
463     }
464     if (!read_mask(inst, path, theme, "desk_toggled.xbm",
465                    &theme->desk_toggled_mask)) {
466         if (userdef)
467             theme->desk_toggled_mask = RrPixmapMaskCopy(theme->desk_mask);
468         else {
469             guchar data[] = { 0x00, 0x1e, 0x1a, 0x16, 0x1e, 0x00 };
470             theme->desk_toggled_mask =
471                 RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
472         }
473     }
474     if (!read_mask(inst, path, theme, "desk_pressed.xbm",
475                    &theme->desk_pressed_mask))
476         theme->desk_pressed_mask = RrPixmapMaskCopy(theme->desk_mask);
477     if (!read_mask(inst, path, theme, "desk_disabled.xbm",
478                    &theme->desk_disabled_mask))
479         theme->desk_disabled_mask = RrPixmapMaskCopy(theme->desk_mask);
480     if (!read_mask(inst, path, theme, "desk_hover.xbm",
481                    &theme->desk_hover_mask))
482         theme->desk_hover_mask = RrPixmapMaskCopy(theme->desk_mask);
483     if (!read_mask(inst, path, theme, "desk_toggled_pressed.xbm",
484                    &theme->desk_toggled_pressed_mask))
485         theme->desk_toggled_pressed_mask =
486             RrPixmapMaskCopy(theme->desk_toggled_mask);
487     if (!read_mask(inst, path, theme, "desk_toggled_hover.xbm",
488                    &theme->desk_toggled_hover_mask))
489         theme->desk_toggled_hover_mask =
490             RrPixmapMaskCopy(theme->desk_toggled_mask);
491
492     /* shade button masks */
493     if (!read_mask(inst, path, theme, "shade.xbm", &theme->shade_mask)) {
494         guchar data[] = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 };
495         theme->shade_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
496     }
497     if (!read_mask(inst, path, theme, "shade_toggled.xbm",
498                   &theme->shade_toggled_mask))
499         theme->shade_toggled_mask = RrPixmapMaskCopy(theme->shade_mask);
500     if (!read_mask(inst, path, theme, "shade_pressed.xbm",
501                    &theme->shade_pressed_mask))
502         theme->shade_pressed_mask = RrPixmapMaskCopy(theme->shade_mask);
503     if (!read_mask(inst, path, theme, "shade_disabled.xbm",
504                    &theme->shade_disabled_mask))
505         theme->shade_disabled_mask = RrPixmapMaskCopy(theme->shade_mask);
506     if (!read_mask(inst, path, theme, "shade_hover.xbm",
507                    &theme->shade_hover_mask))
508         theme->shade_hover_mask = RrPixmapMaskCopy(theme->shade_mask);
509     if (!read_mask(inst, path, theme, "shade_toggled_pressed.xbm",
510                    &theme->shade_toggled_pressed_mask))
511         theme->shade_toggled_pressed_mask =
512             RrPixmapMaskCopy(theme->shade_toggled_mask);
513     if (!read_mask(inst, path, theme, "shade_toggled_hover.xbm",
514                    &theme->shade_toggled_hover_mask))
515         theme->shade_toggled_hover_mask =
516             RrPixmapMaskCopy(theme->shade_toggled_mask);
517
518     /* close button masks */
519     if (!read_mask(inst, path, theme, "close.xbm", &theme->close_mask)) {
520         guchar data[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 };
521         theme->close_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
522     }
523     if (!read_mask(inst, path, theme, "close_pressed.xbm",
524                    &theme->close_pressed_mask))
525         theme->close_pressed_mask = RrPixmapMaskCopy(theme->close_mask);
526     if (!read_mask(inst, path, theme, "close_disabled.xbm",
527                    &theme->close_disabled_mask))
528         theme->close_disabled_mask = RrPixmapMaskCopy(theme->close_mask);
529     if (!read_mask(inst, path, theme, "close_hover.xbm",
530                    &theme->close_hover_mask))
531         theme->close_hover_mask = RrPixmapMaskCopy(theme->close_mask);
532
533     /* submenu bullet mask */
534     if (!read_mask(inst, path, theme, "bullet.xbm", &theme->menu_bullet_mask))
535     {
536         guchar data[] = { 0x01, 0x03, 0x07, 0x0f, 0x07, 0x03, 0x01 };
537         theme->menu_bullet_mask = RrPixmapMaskNew(inst, 4, 7, (gchar*)data);
538     }
539
540     /* setup the default window icon */
541     theme->def_win_icon = read_c_image(OB_DEFAULT_ICON_WIDTH,
542                                        OB_DEFAULT_ICON_HEIGHT,
543                                        OB_DEFAULT_ICON_pixel_data);
544
545     /* read the decoration textures */
546     if (!read_appearance(db, inst,
547                          "window.active.title.bg", theme->a_focused_title,
548                          FALSE))
549         set_default_appearance(theme->a_focused_title);
550     if (!read_appearance(db, inst,
551                          "window.inactive.title.bg", theme->a_unfocused_title,
552                          FALSE))
553         set_default_appearance(theme->a_unfocused_title);
554     if (!read_appearance(db, inst,
555                          "window.active.label.bg", theme->a_focused_label,
556                          TRUE))
557         set_default_appearance(theme->a_focused_label);
558     if (!read_appearance(db, inst,
559                          "window.inactive.label.bg", theme->a_unfocused_label,
560                          TRUE))
561         set_default_appearance(theme->a_unfocused_label);
562     if (!read_appearance(db, inst,
563                          "window.active.handle.bg", theme->a_focused_handle,
564                          FALSE))
565         set_default_appearance(theme->a_focused_handle);
566     if (!read_appearance(db, inst,
567                          "window.inactive.handle.bg",theme->a_unfocused_handle,
568                          FALSE))
569         set_default_appearance(theme->a_unfocused_handle);
570     if (!read_appearance(db, inst,
571                          "window.active.grip.bg", theme->a_focused_grip,
572                          TRUE))
573         set_default_appearance(theme->a_focused_grip);
574     if (!read_appearance(db, inst,
575                          "window.inactive.grip.bg", theme->a_unfocused_grip,
576                          TRUE))
577         set_default_appearance(theme->a_unfocused_grip);
578     if (!read_appearance(db, inst,
579                          "menu.items.bg", theme->a_menu,
580                          FALSE))
581         set_default_appearance(theme->a_menu);
582     if (!read_appearance(db, inst,
583                          "menu.title.bg", theme->a_menu_title,
584                          TRUE))
585         set_default_appearance(theme->a_menu_title);
586     if (!read_appearance(db, inst,
587                          "menu.items.active.bg", theme->a_menu_selected,
588                          TRUE))
589         set_default_appearance(theme->a_menu_selected);
590     theme->a_menu_disabled_selected =
591         RrAppearanceCopy(theme->a_menu_selected);
592
593     /* read appearances for non-decorations (on-screen-display) */
594     if (!read_appearance(db, inst, "osd.bg", theme->osd_hilite_bg, FALSE)) {
595         RrAppearanceFree(theme->osd_hilite_bg);
596         theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_title);
597     }
598     if (!read_appearance(db, inst, "osd.label.bg",
599                          theme->osd_hilite_label, TRUE)) {
600         RrAppearanceFree(theme->osd_hilite_label);
601         theme->osd_hilite_label = RrAppearanceCopy(theme->a_focused_label);
602     }
603     /* osd_hilite_fg can't be parentrel */
604     if (!read_appearance(db, inst, "osd.hilight.bg",
605                          theme->osd_hilite_fg, FALSE)) {
606         RrAppearanceFree(theme->osd_hilite_fg);
607         if (theme->a_focused_label->surface.grad != RR_SURFACE_PARENTREL)
608             theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_label);
609         else
610             theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_title);
611     }
612     /* osd_unhilite_fg can't be parentrel either */
613     if (!read_appearance(db, inst, "osd.unhilight.bg",
614                          theme->osd_unhilite_fg, FALSE)) {
615         RrAppearanceFree(theme->osd_unhilite_fg);
616         if (theme->a_unfocused_label->surface.grad != RR_SURFACE_PARENTREL)
617             theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_label);
618         else
619             theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_title);
620     }
621
622     /* read buttons textures */
623     if (!read_appearance(db, inst,
624                          "window.active.button.disabled.bg",
625                          theme->a_disabled_focused_max,
626                          TRUE))
627         set_default_appearance(theme->a_disabled_focused_max);
628     if (!read_appearance(db, inst,
629                          "window.inactive.button.disabled.bg",
630                          theme->a_disabled_unfocused_max,
631                          TRUE))
632         set_default_appearance(theme->a_disabled_unfocused_max);
633     if (!read_appearance(db, inst,
634                          "window.active.button.pressed.bg",
635                          theme->a_focused_pressed_max,
636                          TRUE))
637         set_default_appearance(theme->a_focused_pressed_max);
638     if (!read_appearance(db, inst,
639                          "window.inactive.button.pressed.bg",
640                          theme->a_unfocused_pressed_max,
641                          TRUE))
642         set_default_appearance(theme->a_unfocused_pressed_max);
643     if (!read_appearance(db, inst,
644                          "window.active.button.toggled.unpressed.bg",
645                          theme->a_toggled_focused_unpressed_max,
646                          TRUE) &&
647         !read_appearance(db, inst,
648                          "window.active.button.toggled.bg",
649                          theme->a_toggled_focused_unpressed_max,
650                          TRUE))
651     {
652         RrAppearanceFree(theme->a_toggled_focused_unpressed_max);
653         theme->a_toggled_focused_unpressed_max =
654             RrAppearanceCopy(theme->a_focused_pressed_max);
655     }
656     if (!read_appearance(db, inst,
657                          "window.inactive.button.toggled.unpressed.bg",
658                          theme->a_toggled_unfocused_unpressed_max,
659                          TRUE) &&
660         !read_appearance(db, inst,
661                          "window.inactive.button.toggled.bg",
662                          theme->a_toggled_unfocused_unpressed_max,
663                          TRUE))
664     {
665         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_max);
666         theme->a_toggled_unfocused_unpressed_max =
667             RrAppearanceCopy(theme->a_unfocused_pressed_max);
668     }
669     if (!read_appearance(db, inst,
670                          "window.active.button.toggled.hover.bg",
671                          theme->a_toggled_hover_focused_max,
672                          TRUE))
673     {
674         RrAppearanceFree(theme->a_toggled_hover_focused_max);
675         theme->a_toggled_hover_focused_max =
676             RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
677     }
678     if (!read_appearance(db, inst,
679                          "window.inactive.button.toggled.hover.bg",
680                          theme->a_toggled_hover_unfocused_max,
681                          TRUE))
682     {
683         RrAppearanceFree(theme->a_toggled_hover_unfocused_max);
684         theme->a_toggled_hover_unfocused_max =
685             RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
686     }
687     if (!read_appearance(db, inst,
688                          "window.active.button.toggled.pressed.bg",
689                          theme->a_toggled_focused_pressed_max,
690                          TRUE))
691     {
692         RrAppearanceFree(theme->a_toggled_focused_pressed_max);
693         theme->a_toggled_focused_pressed_max =
694             RrAppearanceCopy(theme->a_focused_pressed_max);
695     }
696     if (!read_appearance(db, inst,
697                          "window.inactive.button.toggled.pressed.bg",
698                          theme->a_toggled_unfocused_pressed_max,
699                          TRUE))
700     {
701         RrAppearanceFree(theme->a_toggled_unfocused_pressed_max);
702         theme->a_toggled_unfocused_pressed_max =
703             RrAppearanceCopy(theme->a_unfocused_pressed_max);
704     }
705     if (!read_appearance(db, inst,
706                          "window.active.button.unpressed.bg",
707                          theme->a_focused_unpressed_max,
708                          TRUE))
709         set_default_appearance(theme->a_focused_unpressed_max);
710     if (!read_appearance(db, inst,
711                          "window.inactive.button.unpressed.bg",
712                          theme->a_unfocused_unpressed_max,
713                          TRUE))
714         set_default_appearance(theme->a_unfocused_unpressed_max);
715     if (!read_appearance(db, inst,
716                          "window.active.button.hover.bg",
717                          theme->a_hover_focused_max,
718                          TRUE))
719     {
720         RrAppearanceFree(theme->a_hover_focused_max);
721         theme->a_hover_focused_max =
722             RrAppearanceCopy(theme->a_focused_unpressed_max);
723     }
724     if (!read_appearance(db, inst,
725                          "window.inactive.button.hover.bg",
726                          theme->a_hover_unfocused_max,
727                          TRUE))
728     {
729         RrAppearanceFree(theme->a_hover_unfocused_max);
730         theme->a_hover_unfocused_max =
731             RrAppearanceCopy(theme->a_unfocused_unpressed_max);
732     }
733
734     theme->a_disabled_focused_close =
735         RrAppearanceCopy(theme->a_disabled_focused_max);
736     theme->a_disabled_unfocused_close =
737         RrAppearanceCopy(theme->a_disabled_unfocused_max);
738     theme->a_hover_focused_close =
739         RrAppearanceCopy(theme->a_hover_focused_max);
740     theme->a_hover_unfocused_close =
741         RrAppearanceCopy(theme->a_hover_unfocused_max);
742     theme->a_unfocused_unpressed_close =
743         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
744     theme->a_unfocused_pressed_close =
745         RrAppearanceCopy(theme->a_unfocused_pressed_max);
746     theme->a_focused_unpressed_close =
747         RrAppearanceCopy(theme->a_focused_unpressed_max);
748     theme->a_focused_pressed_close =
749         RrAppearanceCopy(theme->a_focused_pressed_max);
750     theme->a_disabled_focused_desk =
751         RrAppearanceCopy(theme->a_disabled_focused_max);
752     theme->a_disabled_unfocused_desk =
753         RrAppearanceCopy(theme->a_disabled_unfocused_max);
754     theme->a_hover_focused_desk =
755         RrAppearanceCopy(theme->a_hover_focused_max);
756     theme->a_hover_unfocused_desk =
757         RrAppearanceCopy(theme->a_hover_unfocused_max);
758     theme->a_toggled_hover_focused_desk =
759         RrAppearanceCopy(theme->a_toggled_hover_focused_max);
760     theme->a_toggled_hover_unfocused_desk =
761         RrAppearanceCopy(theme->a_toggled_hover_unfocused_max);
762     theme->a_toggled_focused_unpressed_desk =
763         RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
764     theme->a_toggled_unfocused_unpressed_desk =
765         RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
766     theme->a_toggled_focused_pressed_desk =
767         RrAppearanceCopy(theme->a_toggled_focused_pressed_max);
768     theme->a_toggled_unfocused_pressed_desk =
769         RrAppearanceCopy(theme->a_toggled_unfocused_pressed_max);
770     theme->a_unfocused_unpressed_desk =
771         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
772     theme->a_unfocused_pressed_desk =
773         RrAppearanceCopy(theme->a_unfocused_pressed_max);
774     theme->a_focused_unpressed_desk =
775         RrAppearanceCopy(theme->a_focused_unpressed_max);
776     theme->a_focused_pressed_desk =
777         RrAppearanceCopy(theme->a_focused_pressed_max);
778     theme->a_disabled_focused_shade =
779         RrAppearanceCopy(theme->a_disabled_focused_max);
780     theme->a_disabled_unfocused_shade =
781         RrAppearanceCopy(theme->a_disabled_unfocused_max);
782     theme->a_hover_focused_shade =
783         RrAppearanceCopy(theme->a_hover_focused_max);
784     theme->a_hover_unfocused_shade =
785         RrAppearanceCopy(theme->a_hover_unfocused_max);
786     theme->a_toggled_hover_focused_shade =
787         RrAppearanceCopy(theme->a_toggled_hover_focused_max);
788     theme->a_toggled_hover_unfocused_shade =
789         RrAppearanceCopy(theme->a_toggled_hover_unfocused_max);
790     theme->a_toggled_focused_unpressed_shade =
791         RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
792     theme->a_toggled_unfocused_unpressed_shade =
793         RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
794     theme->a_toggled_focused_pressed_shade =
795         RrAppearanceCopy(theme->a_toggled_focused_pressed_max);
796     theme->a_toggled_unfocused_pressed_shade =
797         RrAppearanceCopy(theme->a_toggled_unfocused_pressed_max);
798     theme->a_unfocused_unpressed_shade =
799         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
800     theme->a_unfocused_pressed_shade =
801         RrAppearanceCopy(theme->a_unfocused_pressed_max);
802     theme->a_focused_unpressed_shade =
803         RrAppearanceCopy(theme->a_focused_unpressed_max);
804     theme->a_focused_pressed_shade =
805         RrAppearanceCopy(theme->a_focused_pressed_max);
806     theme->a_disabled_focused_iconify =
807         RrAppearanceCopy(theme->a_disabled_focused_max);
808     theme->a_disabled_unfocused_iconify =
809         RrAppearanceCopy(theme->a_disabled_focused_max);
810     theme->a_hover_focused_iconify =
811         RrAppearanceCopy(theme->a_hover_focused_max);
812     theme->a_hover_unfocused_iconify =
813         RrAppearanceCopy(theme->a_hover_unfocused_max);
814     theme->a_unfocused_unpressed_iconify =
815         RrAppearanceCopy(theme->a_unfocused_unpressed_max);
816     theme->a_unfocused_pressed_iconify =
817         RrAppearanceCopy(theme->a_unfocused_pressed_max);
818     theme->a_focused_unpressed_iconify =
819         RrAppearanceCopy(theme->a_focused_unpressed_max);
820     theme->a_focused_pressed_iconify =
821         RrAppearanceCopy(theme->a_focused_pressed_max);
822
823     theme->a_icon->surface.grad =
824         theme->a_clear->surface.grad =
825         theme->a_clear_tex->surface.grad =
826         theme->a_menu_text_title->surface.grad =
827         theme->a_menu_normal->surface.grad =
828         theme->a_menu_disabled->surface.grad =
829         theme->a_menu_text_normal->surface.grad =
830         theme->a_menu_text_selected->surface.grad =
831         theme->a_menu_text_disabled->surface.grad =
832         theme->a_menu_text_disabled_selected->surface.grad =
833         theme->a_menu_bullet_normal->surface.grad =
834         theme->a_menu_bullet_selected->surface.grad = RR_SURFACE_PARENTREL;
835
836     /* set up the textures */
837     theme->a_focused_label->texture[0].type = RR_TEXTURE_TEXT;
838     theme->a_focused_label->texture[0].data.text.justify = winjust;
839     theme->a_focused_label->texture[0].data.text.font=theme->win_font_focused;
840     theme->a_focused_label->texture[0].data.text.color =
841         theme->title_focused_color;
842
843     if (read_string(db, "window.active.label.text.font", &str)) {
844         char *p;
845         gint i = 0;
846         gint j;
847         if (strstr(str, "shadow=y")) {
848             if ((p = strstr(str, "shadowoffset=")))
849                 i = parse_inline_number(p + strlen("shadowoffset="));
850             else
851                 i = 1;
852             theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
853             theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
854         }
855         if ((p = strstr(str, "shadowtint=")))
856         {
857             i = parse_inline_number(p + strlen("shadowtint="));
858             j = (i > 0 ? 0 : 255);
859             i = ABS(i*255/100);
860
861             theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
862             theme->title_focused_shadow_alpha = i;
863         } else {
864             theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
865             theme->title_focused_shadow_alpha = 50;
866         }
867     }
868
869     theme->a_focused_label->texture[0].data.text.shadow_color =
870         theme->title_focused_shadow_color;
871     theme->a_focused_label->texture[0].data.text.shadow_alpha =
872         theme->title_focused_shadow_alpha;
873
874     theme->osd_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
875     theme->osd_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
876     theme->osd_hilite_label->texture[0].data.text.font = theme->osd_font;
877     theme->osd_hilite_label->texture[0].data.text.color = theme->osd_color;
878
879     if (read_string(db, "osd.label.text.font", &str)) {
880         char *p;
881         gint i = 0;
882         gint j;
883         if (strstr(str, "shadow=y")) {
884             if ((p = strstr(str, "shadowoffset=")))
885                 i = parse_inline_number(p + strlen("shadowoffset="));
886             else
887                 i = 1;
888             theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
889             theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
890             theme->osd_hilite_label->texture[0].data.text.shadow_offset_x = i;
891             theme->osd_hilite_label->texture[0].data.text.shadow_offset_y = i;
892         }
893         if ((p = strstr(str, "shadowtint=")))
894         {
895             i = parse_inline_number(p + strlen("shadowtint="));
896             j = (i > 0 ? 0 : 255);
897             i = ABS(i*255/100);
898
899             theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
900             theme->title_focused_shadow_alpha = i;
901             theme->osd_shadow_color = RrColorNew(inst, j, j, j);
902             theme->osd_shadow_alpha = i;
903         } else {
904             theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
905             theme->title_focused_shadow_alpha = 50;
906             theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
907             theme->osd_shadow_alpha = 50;
908         }
909     } else {
910         /* inherit the font settings from the focused label */
911         theme->osd_hilite_label->texture[0].data.text.shadow_offset_x =
912             theme->a_focused_label->texture[0].data.text.shadow_offset_x;
913         theme->osd_hilite_label->texture[0].data.text.shadow_offset_y =
914             theme->a_focused_label->texture[0].data.text.shadow_offset_y;
915         if (theme->title_focused_shadow_color)
916             theme->osd_shadow_color =
917                 RrColorNew(inst,
918                            theme->title_focused_shadow_color->r,
919                            theme->title_focused_shadow_color->g,
920                            theme->title_focused_shadow_color->b);
921         else
922             theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
923         theme->osd_shadow_alpha = theme->title_focused_shadow_alpha;
924     }
925
926     theme->osd_hilite_label->texture[0].data.text.shadow_color =
927         theme->osd_shadow_color;
928     theme->osd_hilite_label->texture[0].data.text.shadow_alpha =
929         theme->osd_shadow_alpha;
930
931     theme->a_unfocused_label->texture[0].type = RR_TEXTURE_TEXT;
932     theme->a_unfocused_label->texture[0].data.text.justify = winjust;
933     theme->a_unfocused_label->texture[0].data.text.font =
934         theme->win_font_unfocused;
935     theme->a_unfocused_label->texture[0].data.text.color =
936         theme->title_unfocused_color;
937
938     if (read_string(db, "window.inactive.label.text.font", &str)) {
939         char *p;
940         gint i = 0;
941         gint j;
942         if (strstr(str, "shadow=y")) {
943             if ((p = strstr(str, "shadowoffset=")))
944                 i = parse_inline_number(p + strlen("shadowoffset="));
945             else
946                 i = 1;
947             theme->a_unfocused_label->texture[0].data.text.shadow_offset_x = i;
948             theme->a_unfocused_label->texture[0].data.text.shadow_offset_y = i;
949         }
950         if ((p = strstr(str, "shadowtint=")))
951         {
952             i = parse_inline_number(p + strlen("shadowtint="));
953             j = (i > 0 ? 0 : 255);
954             i = ABS(i*255/100);
955
956             theme->title_unfocused_shadow_color = RrColorNew(inst, j, j, j);
957             theme->title_unfocused_shadow_alpha = i;
958         } else {
959             theme->title_unfocused_shadow_color = RrColorNew(inst, 0, 0, 0);
960             theme->title_unfocused_shadow_alpha = 50;
961         }
962     }
963
964     theme->a_unfocused_label->texture[0].data.text.shadow_color =
965         theme->title_unfocused_shadow_color;
966     theme->a_unfocused_label->texture[0].data.text.shadow_alpha =
967         theme->title_unfocused_shadow_alpha;
968
969     theme->a_menu_text_title->texture[0].type = RR_TEXTURE_TEXT;
970     theme->a_menu_text_title->texture[0].data.text.justify = mtitlejust;
971     theme->a_menu_text_title->texture[0].data.text.font =
972         theme->menu_title_font;
973     theme->a_menu_text_title->texture[0].data.text.color =
974         theme->menu_title_color;
975
976     if (read_string(db, "menu.title.text.font", &str)) {
977         char *p;
978         gint i = 0;
979         gint j;
980         if (strstr(str, "shadow=y")) {
981             if ((p = strstr(str, "shadowoffset=")))
982                 i = parse_inline_number(p + strlen("shadowoffset="));
983             else
984                 i = 1;
985             theme->a_menu_text_title->texture[0].data.text.shadow_offset_x = i;
986             theme->a_menu_text_title->texture[0].data.text.shadow_offset_y = i;
987         }
988         if ((p = strstr(str, "shadowtint=")))
989         {
990             i = parse_inline_number(p + strlen("shadowtint="));
991             j = (i > 0 ? 0 : 255);
992             i = ABS(i*255/100);
993
994             theme->menu_title_shadow_color = RrColorNew(inst, j, j, j);
995             theme->menu_title_shadow_alpha = i;
996         } else {
997             theme->menu_title_shadow_color = RrColorNew(inst, 0, 0, 0);
998             theme->menu_title_shadow_alpha = 50;
999         }
1000     }
1001
1002     theme->a_menu_text_title->texture[0].data.text.shadow_color =
1003         theme->menu_title_shadow_color;
1004     theme->a_menu_text_title->texture[0].data.text.shadow_alpha =
1005         theme->menu_title_shadow_alpha;
1006
1007     theme->a_menu_text_normal->texture[0].type =
1008         theme->a_menu_text_selected->texture[0].type =
1009         theme->a_menu_text_disabled->texture[0].type =
1010         theme->a_menu_text_disabled_selected->texture[0].type =
1011         RR_TEXTURE_TEXT;
1012     theme->a_menu_text_normal->texture[0].data.text.justify =
1013         theme->a_menu_text_selected->texture[0].data.text.justify =
1014         theme->a_menu_text_disabled->texture[0].data.text.justify =
1015         theme->a_menu_text_disabled_selected->texture[0].data.text.justify =
1016         RR_JUSTIFY_LEFT;
1017     theme->a_menu_text_normal->texture[0].data.text.font =
1018         theme->a_menu_text_selected->texture[0].data.text.font =
1019         theme->a_menu_text_disabled->texture[0].data.text.font =
1020         theme->a_menu_text_disabled_selected->texture[0].data.text.font =
1021         theme->menu_font;
1022     theme->a_menu_text_normal->texture[0].data.text.color = theme->menu_color;
1023     theme->a_menu_text_selected->texture[0].data.text.color =
1024         theme->menu_selected_color;
1025     theme->a_menu_text_disabled->texture[0].data.text.color =
1026         theme->menu_disabled_color;
1027     theme->a_menu_text_disabled_selected->texture[0].data.text.color =
1028         theme->menu_disabled_selected_color;
1029
1030     if (read_string(db, "menu.items.font", &str)) {
1031         char *p;
1032         gint i = 0;
1033         gint j;
1034         if (strstr(str, "shadow=y")) {
1035             if ((p = strstr(str, "shadowoffset=")))
1036                 i = parse_inline_number(p + strlen("shadowoffset="));
1037             else
1038                 i = 1;
1039             theme->a_menu_text_normal->
1040                 texture[0].data.text.shadow_offset_x = i;
1041             theme->a_menu_text_normal->
1042                 texture[0].data.text.shadow_offset_y = i;
1043             theme->a_menu_text_selected->
1044                 texture[0].data.text.shadow_offset_x = i;
1045             theme->a_menu_text_selected->
1046                 texture[0].data.text.shadow_offset_y = i;
1047             theme->a_menu_text_disabled->
1048                 texture[0].data.text.shadow_offset_x = i;
1049             theme->a_menu_text_disabled->
1050                 texture[0].data.text.shadow_offset_y = i;
1051             theme->a_menu_text_disabled_selected->
1052                 texture[0].data.text.shadow_offset_x = i;
1053             theme->a_menu_text_disabled_selected->
1054                 texture[0].data.text.shadow_offset_y = i;
1055         }
1056         if ((p = strstr(str, "shadowtint=")))
1057         {
1058             i = parse_inline_number(p + strlen("shadowtint="));
1059             j = (i > 0 ? 0 : 255);
1060             i = ABS(i*255/100);
1061
1062             theme->menu_text_normal_shadow_color = RrColorNew(inst, j, j, j);
1063             theme->menu_text_selected_shadow_color = RrColorNew(inst, j, j, j);
1064             theme->menu_text_disabled_shadow_color = RrColorNew(inst, j, j, j);
1065             theme->menu_text_normal_shadow_alpha = i;
1066             theme->menu_text_selected_shadow_alpha = i;
1067             theme->menu_text_disabled_shadow_alpha = i;
1068             theme->menu_text_disabled_selected_shadow_alpha = i;
1069         } else {
1070             theme->menu_text_normal_shadow_color = RrColorNew(inst, 0, 0, 0);
1071             theme->menu_text_selected_shadow_color = RrColorNew(inst, 0, 0, 0);
1072             theme->menu_text_disabled_shadow_color = RrColorNew(inst, 0, 0, 0);
1073             theme->menu_text_normal_shadow_alpha = 50;
1074             theme->menu_text_selected_shadow_alpha = 50;
1075             theme->menu_text_disabled_selected_shadow_alpha = 50;
1076         }
1077     }
1078
1079     theme->a_menu_text_normal->texture[0].data.text.shadow_color =
1080         theme->menu_text_normal_shadow_color;
1081     theme->a_menu_text_normal->texture[0].data.text.shadow_alpha =
1082         theme->menu_text_normal_shadow_alpha;
1083     theme->a_menu_text_selected->texture[0].data.text.shadow_color =
1084         theme->menu_text_selected_shadow_color;
1085     theme->a_menu_text_selected->texture[0].data.text.shadow_alpha =
1086         theme->menu_text_selected_shadow_alpha;
1087     theme->a_menu_text_disabled->texture[0].data.text.shadow_color =
1088         theme->menu_text_disabled_shadow_color;
1089     theme->a_menu_text_disabled->texture[0].data.text.shadow_alpha =
1090         theme->menu_text_disabled_shadow_alpha;
1091     theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_color =
1092         theme->menu_text_disabled_shadow_color;
1093     theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_alpha =
1094         theme->menu_text_disabled_shadow_alpha;
1095
1096     theme->a_disabled_focused_max->texture[0].type =
1097         theme->a_disabled_unfocused_max->texture[0].type =
1098         theme->a_hover_focused_max->texture[0].type =
1099         theme->a_hover_unfocused_max->texture[0].type =
1100         theme->a_toggled_hover_focused_max->texture[0].type =
1101         theme->a_toggled_hover_unfocused_max->texture[0].type =
1102         theme->a_toggled_focused_unpressed_max->texture[0].type =
1103         theme->a_toggled_unfocused_unpressed_max->texture[0].type =
1104         theme->a_toggled_focused_pressed_max->texture[0].type =
1105         theme->a_toggled_unfocused_pressed_max->texture[0].type =
1106         theme->a_focused_unpressed_max->texture[0].type =
1107         theme->a_focused_pressed_max->texture[0].type =
1108         theme->a_unfocused_unpressed_max->texture[0].type =
1109         theme->a_unfocused_pressed_max->texture[0].type =
1110         theme->a_disabled_focused_close->texture[0].type =
1111         theme->a_disabled_unfocused_close->texture[0].type =
1112         theme->a_hover_focused_close->texture[0].type =
1113         theme->a_hover_unfocused_close->texture[0].type =
1114         theme->a_focused_unpressed_close->texture[0].type =
1115         theme->a_focused_pressed_close->texture[0].type =
1116         theme->a_unfocused_unpressed_close->texture[0].type =
1117         theme->a_unfocused_pressed_close->texture[0].type =
1118         theme->a_disabled_focused_desk->texture[0].type =
1119         theme->a_disabled_unfocused_desk->texture[0].type =
1120         theme->a_hover_focused_desk->texture[0].type =
1121         theme->a_hover_unfocused_desk->texture[0].type =
1122         theme->a_toggled_hover_focused_desk->texture[0].type =
1123         theme->a_toggled_hover_unfocused_desk->texture[0].type =
1124         theme->a_toggled_focused_unpressed_desk->texture[0].type =
1125         theme->a_toggled_unfocused_unpressed_desk->texture[0].type =
1126         theme->a_toggled_focused_pressed_desk->texture[0].type =
1127         theme->a_toggled_unfocused_pressed_desk->texture[0].type =
1128         theme->a_focused_unpressed_desk->texture[0].type =
1129         theme->a_focused_pressed_desk->texture[0].type =
1130         theme->a_unfocused_unpressed_desk->texture[0].type =
1131         theme->a_unfocused_pressed_desk->texture[0].type =
1132         theme->a_disabled_focused_shade->texture[0].type =
1133         theme->a_disabled_unfocused_shade->texture[0].type =
1134         theme->a_hover_focused_shade->texture[0].type =
1135         theme->a_hover_unfocused_shade->texture[0].type =
1136         theme->a_toggled_hover_focused_shade->texture[0].type =
1137         theme->a_toggled_hover_unfocused_shade->texture[0].type =
1138         theme->a_toggled_focused_unpressed_shade->texture[0].type =
1139         theme->a_toggled_unfocused_unpressed_shade->texture[0].type =
1140         theme->a_toggled_focused_pressed_shade->texture[0].type =
1141         theme->a_toggled_unfocused_pressed_shade->texture[0].type =
1142         theme->a_focused_unpressed_shade->texture[0].type =
1143         theme->a_focused_pressed_shade->texture[0].type =
1144         theme->a_unfocused_unpressed_shade->texture[0].type =
1145         theme->a_unfocused_pressed_shade->texture[0].type =
1146         theme->a_disabled_focused_iconify->texture[0].type =
1147         theme->a_disabled_unfocused_iconify->texture[0].type =
1148         theme->a_hover_focused_iconify->texture[0].type =
1149         theme->a_hover_unfocused_iconify->texture[0].type =
1150         theme->a_focused_unpressed_iconify->texture[0].type =
1151         theme->a_focused_pressed_iconify->texture[0].type =
1152         theme->a_unfocused_unpressed_iconify->texture[0].type =
1153         theme->a_unfocused_pressed_iconify->texture[0].type =
1154         theme->a_menu_bullet_normal->texture[0].type =
1155         theme->a_menu_bullet_selected->texture[0].type = RR_TEXTURE_MASK;
1156
1157     theme->a_disabled_focused_max->texture[0].data.mask.mask =
1158         theme->a_disabled_unfocused_max->texture[0].data.mask.mask =
1159         theme->max_disabled_mask;
1160     theme->a_hover_focused_max->texture[0].data.mask.mask =
1161         theme->a_hover_unfocused_max->texture[0].data.mask.mask =
1162         theme->max_hover_mask;
1163     theme->a_focused_pressed_max->texture[0].data.mask.mask =
1164         theme->a_unfocused_pressed_max->texture[0].data.mask.mask =
1165         theme->max_pressed_mask;
1166     theme->a_focused_unpressed_max->texture[0].data.mask.mask =
1167         theme->a_unfocused_unpressed_max->texture[0].data.mask.mask =
1168         theme->max_mask;
1169     theme->a_toggled_hover_focused_max->texture[0].data.mask.mask =
1170         theme->a_toggled_hover_unfocused_max->texture[0].data.mask.mask =
1171         theme->max_toggled_hover_mask;
1172     theme->a_toggled_focused_unpressed_max->texture[0].data.mask.mask =
1173         theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.mask =
1174         theme->max_toggled_mask;
1175     theme->a_toggled_focused_pressed_max->texture[0].data.mask.mask =
1176         theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.mask =
1177         theme->max_toggled_pressed_mask;
1178     theme->a_disabled_focused_close->texture[0].data.mask.mask =
1179         theme->a_disabled_unfocused_close->texture[0].data.mask.mask =
1180         theme->close_disabled_mask;
1181     theme->a_hover_focused_close->texture[0].data.mask.mask =
1182         theme->a_hover_unfocused_close->texture[0].data.mask.mask =
1183         theme->close_hover_mask;
1184     theme->a_focused_pressed_close->texture[0].data.mask.mask =
1185         theme->a_unfocused_pressed_close->texture[0].data.mask.mask =
1186         theme->close_pressed_mask;
1187     theme->a_focused_unpressed_close->texture[0].data.mask.mask =
1188         theme->a_unfocused_unpressed_close->texture[0].data.mask.mask =
1189         theme->close_mask;
1190     theme->a_disabled_focused_desk->texture[0].data.mask.mask =
1191         theme->a_disabled_unfocused_desk->texture[0].data.mask.mask =
1192         theme->desk_disabled_mask;
1193     theme->a_hover_focused_desk->texture[0].data.mask.mask =
1194         theme->a_hover_unfocused_desk->texture[0].data.mask.mask =
1195         theme->desk_hover_mask;
1196     theme->a_focused_pressed_desk->texture[0].data.mask.mask =
1197         theme->a_unfocused_pressed_desk->texture[0].data.mask.mask =
1198         theme->desk_pressed_mask;
1199     theme->a_focused_unpressed_desk->texture[0].data.mask.mask =
1200         theme->a_unfocused_unpressed_desk->texture[0].data.mask.mask =
1201         theme->desk_mask;
1202     theme->a_toggled_hover_focused_desk->texture[0].data.mask.mask =
1203         theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.mask =
1204         theme->desk_toggled_hover_mask;
1205     theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.mask =
1206         theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.mask =
1207         theme->desk_toggled_mask;
1208     theme->a_toggled_focused_pressed_desk->texture[0].data.mask.mask =
1209         theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.mask =
1210         theme->desk_toggled_pressed_mask;
1211     theme->a_disabled_focused_shade->texture[0].data.mask.mask =
1212         theme->a_disabled_unfocused_shade->texture[0].data.mask.mask =
1213         theme->shade_disabled_mask;
1214     theme->a_hover_focused_shade->texture[0].data.mask.mask =
1215         theme->a_hover_unfocused_shade->texture[0].data.mask.mask =
1216         theme->shade_hover_mask;
1217     theme->a_focused_pressed_shade->texture[0].data.mask.mask =
1218         theme->a_unfocused_pressed_shade->texture[0].data.mask.mask =
1219         theme->shade_pressed_mask;
1220     theme->a_focused_unpressed_shade->texture[0].data.mask.mask =
1221         theme->a_unfocused_unpressed_shade->texture[0].data.mask.mask =
1222         theme->shade_mask;
1223     theme->a_toggled_hover_focused_shade->texture[0].data.mask.mask =
1224         theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.mask =
1225         theme->shade_toggled_hover_mask;
1226     theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.mask =
1227         theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.mask =
1228         theme->shade_toggled_mask;
1229     theme->a_toggled_focused_pressed_shade->texture[0].data.mask.mask =
1230         theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.mask =
1231         theme->shade_toggled_pressed_mask;
1232     theme->a_disabled_focused_iconify->texture[0].data.mask.mask =
1233         theme->a_disabled_unfocused_iconify->texture[0].data.mask.mask =
1234         theme->iconify_disabled_mask;
1235     theme->a_hover_focused_iconify->texture[0].data.mask.mask =
1236         theme->a_hover_unfocused_iconify->texture[0].data.mask.mask =
1237         theme->iconify_hover_mask;
1238     theme->a_focused_pressed_iconify->texture[0].data.mask.mask =
1239         theme->a_unfocused_pressed_iconify->texture[0].data.mask.mask =
1240         theme->iconify_pressed_mask;
1241     theme->a_focused_unpressed_iconify->texture[0].data.mask.mask =
1242         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.mask =
1243         theme->iconify_mask;
1244     theme->a_menu_bullet_normal->texture[0].data.mask.mask =
1245     theme->a_menu_bullet_selected->texture[0].data.mask.mask =
1246         theme->menu_bullet_mask;
1247     theme->a_disabled_focused_max->texture[0].data.mask.color =
1248         theme->a_disabled_focused_close->texture[0].data.mask.color =
1249         theme->a_disabled_focused_desk->texture[0].data.mask.color =
1250         theme->a_disabled_focused_shade->texture[0].data.mask.color =
1251         theme->a_disabled_focused_iconify->texture[0].data.mask.color =
1252         theme->titlebut_disabled_focused_color;
1253     theme->a_disabled_unfocused_max->texture[0].data.mask.color =
1254         theme->a_disabled_unfocused_close->texture[0].data.mask.color =
1255         theme->a_disabled_unfocused_desk->texture[0].data.mask.color =
1256         theme->a_disabled_unfocused_shade->texture[0].data.mask.color =
1257         theme->a_disabled_unfocused_iconify->texture[0].data.mask.color =
1258         theme->titlebut_disabled_unfocused_color;
1259     theme->a_hover_focused_max->texture[0].data.mask.color =
1260         theme->a_hover_focused_close->texture[0].data.mask.color =
1261         theme->a_hover_focused_desk->texture[0].data.mask.color =
1262         theme->a_hover_focused_shade->texture[0].data.mask.color =
1263         theme->a_hover_focused_iconify->texture[0].data.mask.color =
1264         theme->titlebut_hover_focused_color;
1265     theme->a_hover_unfocused_max->texture[0].data.mask.color =
1266         theme->a_hover_unfocused_close->texture[0].data.mask.color =
1267         theme->a_hover_unfocused_desk->texture[0].data.mask.color =
1268         theme->a_hover_unfocused_shade->texture[0].data.mask.color =
1269         theme->a_hover_unfocused_iconify->texture[0].data.mask.color =
1270         theme->titlebut_hover_unfocused_color;
1271     theme->a_toggled_hover_focused_max->texture[0].data.mask.color =
1272         theme->a_toggled_hover_focused_desk->texture[0].data.mask.color =
1273         theme->a_toggled_hover_focused_shade->texture[0].data.mask.color =
1274         theme->titlebut_toggled_hover_focused_color;
1275     theme->a_toggled_hover_unfocused_max->texture[0].data.mask.color =
1276         theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.color =
1277         theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.color =
1278         theme->titlebut_toggled_hover_unfocused_color;
1279     theme->a_toggled_focused_unpressed_max->texture[0].data.mask.color =
1280         theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.color =
1281         theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.color =
1282         theme->titlebut_toggled_focused_unpressed_color;
1283     theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.color =
1284         theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.color =
1285         theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.color=
1286         theme->titlebut_toggled_unfocused_unpressed_color;
1287     theme->a_toggled_focused_pressed_max->texture[0].data.mask.color =
1288         theme->a_toggled_focused_pressed_desk->texture[0].data.mask.color =
1289         theme->a_toggled_focused_pressed_shade->texture[0].data.mask.color =
1290         theme->titlebut_toggled_focused_pressed_color;
1291     theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.color =
1292         theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.color =
1293         theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.color =
1294         theme->titlebut_toggled_unfocused_pressed_color;
1295     theme->a_focused_unpressed_max->texture[0].data.mask.color =
1296         theme->a_focused_unpressed_close->texture[0].data.mask.color =
1297         theme->a_focused_unpressed_desk->texture[0].data.mask.color =
1298         theme->a_focused_unpressed_shade->texture[0].data.mask.color =
1299         theme->a_focused_unpressed_iconify->texture[0].data.mask.color =
1300         theme->titlebut_focused_unpressed_color;
1301     theme->a_focused_pressed_max->texture[0].data.mask.color =
1302         theme->a_focused_pressed_close->texture[0].data.mask.color =
1303         theme->a_focused_pressed_desk->texture[0].data.mask.color =
1304         theme->a_focused_pressed_shade->texture[0].data.mask.color =
1305         theme->a_focused_pressed_iconify->texture[0].data.mask.color =
1306         theme->titlebut_focused_pressed_color;
1307     theme->a_unfocused_unpressed_max->texture[0].data.mask.color =
1308         theme->a_unfocused_unpressed_close->texture[0].data.mask.color =
1309         theme->a_unfocused_unpressed_desk->texture[0].data.mask.color =
1310         theme->a_unfocused_unpressed_shade->texture[0].data.mask.color =
1311         theme->a_unfocused_unpressed_iconify->texture[0].data.mask.color =
1312         theme->titlebut_unfocused_unpressed_color;
1313     theme->a_unfocused_pressed_max->texture[0].data.mask.color =
1314         theme->a_unfocused_pressed_close->texture[0].data.mask.color =
1315         theme->a_unfocused_pressed_desk->texture[0].data.mask.color =
1316         theme->a_unfocused_pressed_shade->texture[0].data.mask.color =
1317         theme->a_unfocused_pressed_iconify->texture[0].data.mask.color =
1318         theme->titlebut_unfocused_pressed_color;
1319     theme->a_menu_bullet_normal->texture[0].data.mask.color =
1320         theme->menu_color;
1321     theme->a_menu_bullet_selected->texture[0].data.mask.color =
1322         theme->menu_selected_color;
1323
1324     g_free(path);
1325     XrmDestroyDatabase(db);
1326
1327     /* set the font heights */
1328     theme->win_font_height = RrFontHeight
1329         (theme->win_font_focused,
1330          theme->a_focused_label->texture[0].data.text.shadow_offset_y);
1331     theme->win_font_height =
1332         MAX(theme->win_font_height,
1333             RrFontHeight
1334             (theme->win_font_focused,
1335              theme->a_unfocused_label->texture[0].data.text.shadow_offset_y));
1336     theme->menu_title_font_height = RrFontHeight
1337         (theme->menu_title_font,
1338          theme->a_menu_text_title->texture[0].data.text.shadow_offset_y);
1339     theme->menu_font_height = RrFontHeight
1340         (theme->menu_font,
1341          theme->a_menu_text_normal->texture[0].data.text.shadow_offset_y);
1342
1343     /* calculate some last extents */
1344     {
1345         gint ft, fb, fl, fr, ut, ub, ul, ur;
1346
1347         RrMargins(theme->a_focused_label, &fl, &ft, &fr, &fb);
1348         RrMargins(theme->a_unfocused_label, &ul, &ut, &ur, &ub);
1349         theme->label_height = theme->win_font_height + MAX(ft + fb, ut + ub);
1350         theme->label_height += theme->label_height % 2;
1351
1352         /* this would be nice I think, since padding.width can now be 0,
1353            but it breaks frame.c horribly and I don't feel like fixing that
1354            right now, so if anyone complains, here is how to keep text from
1355            going over the title's bevel/border with a padding.width of 0 and a
1356            bevelless/borderless label
1357            RrMargins(theme->a_focused_title, &fl, &ft, &fr, &fb);
1358            RrMargins(theme->a_unfocused_title, &ul, &ut, &ur, &ub);
1359            theme->title_height = theme->label_height +
1360            MAX(MAX(theme->padding * 2, ft + fb),
1361            MAX(theme->padding * 2, ut + ub));
1362         */
1363         theme->title_height = theme->label_height + theme->paddingy * 2;
1364
1365         RrMargins(theme->a_menu_title, &ul, &ut, &ur, &ub);
1366         theme->menu_title_label_height = theme->menu_title_font_height+ut+ub;
1367         theme->menu_title_height = theme->menu_title_label_height +
1368             theme->paddingy * 2;
1369     }
1370     theme->button_size = theme->label_height - 2;
1371     theme->grip_width = 25;
1372
1373     return theme;
1374 }
1375
1376 void RrThemeFree(RrTheme *theme)
1377 {
1378     if (theme) {
1379         g_free(theme->name);
1380
1381         RrColorFree(theme->menu_border_color);
1382         RrColorFree(theme->osd_border_color);
1383         RrColorFree(theme->frame_focused_border_color);
1384         RrColorFree(theme->frame_unfocused_border_color);
1385         RrColorFree(theme->title_separator_focused_color);
1386         RrColorFree(theme->title_separator_unfocused_color);
1387         RrColorFree(theme->cb_unfocused_color);
1388         RrColorFree(theme->cb_focused_color);
1389         RrColorFree(theme->title_focused_color);
1390         RrColorFree(theme->title_unfocused_color);
1391         RrColorFree(theme->titlebut_disabled_focused_color);
1392         RrColorFree(theme->titlebut_disabled_unfocused_color);
1393         RrColorFree(theme->titlebut_hover_focused_color);
1394         RrColorFree(theme->titlebut_hover_unfocused_color);
1395         RrColorFree(theme->titlebut_toggled_hover_focused_color);
1396         RrColorFree(theme->titlebut_toggled_hover_unfocused_color);
1397         RrColorFree(theme->titlebut_toggled_focused_pressed_color);
1398         RrColorFree(theme->titlebut_toggled_unfocused_pressed_color);
1399         RrColorFree(theme->titlebut_toggled_focused_unpressed_color);
1400         RrColorFree(theme->titlebut_toggled_unfocused_unpressed_color);
1401         RrColorFree(theme->titlebut_focused_pressed_color);
1402         RrColorFree(theme->titlebut_unfocused_pressed_color);
1403         RrColorFree(theme->titlebut_focused_unpressed_color);
1404         RrColorFree(theme->titlebut_unfocused_unpressed_color);
1405         RrColorFree(theme->menu_title_color);
1406         RrColorFree(theme->menu_color);
1407         RrColorFree(theme->menu_selected_color);
1408         RrColorFree(theme->menu_disabled_color);
1409         RrColorFree(theme->menu_disabled_selected_color);
1410         RrColorFree(theme->title_focused_shadow_color);
1411         RrColorFree(theme->title_unfocused_shadow_color);
1412         RrColorFree(theme->osd_color);
1413         RrColorFree(theme->osd_shadow_color);
1414         RrColorFree(theme->menu_title_shadow_color);
1415         RrColorFree(theme->menu_text_normal_shadow_color);
1416         RrColorFree(theme->menu_text_selected_shadow_color);
1417         RrColorFree(theme->menu_text_disabled_shadow_color);
1418         RrColorFree(theme->menu_text_disabled_selected_shadow_color);
1419
1420         g_free(theme->def_win_icon);
1421
1422         RrPixmapMaskFree(theme->max_mask);
1423         RrPixmapMaskFree(theme->max_toggled_mask);
1424         RrPixmapMaskFree(theme->max_toggled_hover_mask);
1425         RrPixmapMaskFree(theme->max_toggled_pressed_mask);
1426         RrPixmapMaskFree(theme->max_disabled_mask);
1427         RrPixmapMaskFree(theme->max_hover_mask);
1428         RrPixmapMaskFree(theme->max_pressed_mask);
1429         RrPixmapMaskFree(theme->desk_mask);
1430         RrPixmapMaskFree(theme->desk_toggled_mask);
1431         RrPixmapMaskFree(theme->desk_toggled_hover_mask);
1432         RrPixmapMaskFree(theme->desk_toggled_pressed_mask);
1433         RrPixmapMaskFree(theme->desk_disabled_mask);
1434         RrPixmapMaskFree(theme->desk_hover_mask);
1435         RrPixmapMaskFree(theme->desk_pressed_mask);
1436         RrPixmapMaskFree(theme->shade_mask);
1437         RrPixmapMaskFree(theme->shade_toggled_mask);
1438         RrPixmapMaskFree(theme->shade_toggled_hover_mask);
1439         RrPixmapMaskFree(theme->shade_toggled_pressed_mask);
1440         RrPixmapMaskFree(theme->shade_disabled_mask);
1441         RrPixmapMaskFree(theme->shade_hover_mask);
1442         RrPixmapMaskFree(theme->shade_pressed_mask);
1443         RrPixmapMaskFree(theme->iconify_mask);
1444         RrPixmapMaskFree(theme->iconify_disabled_mask);
1445         RrPixmapMaskFree(theme->iconify_hover_mask);
1446         RrPixmapMaskFree(theme->iconify_pressed_mask);
1447         RrPixmapMaskFree(theme->close_mask);
1448         RrPixmapMaskFree(theme->close_disabled_mask);
1449         RrPixmapMaskFree(theme->close_hover_mask);
1450         RrPixmapMaskFree(theme->close_pressed_mask);
1451         RrPixmapMaskFree(theme->menu_bullet_mask);
1452
1453         RrFontClose(theme->win_font_focused);
1454         RrFontClose(theme->win_font_unfocused);
1455         RrFontClose(theme->menu_title_font);
1456         RrFontClose(theme->menu_font);
1457
1458         RrAppearanceFree(theme->a_disabled_focused_max);
1459         RrAppearanceFree(theme->a_disabled_unfocused_max);
1460         RrAppearanceFree(theme->a_hover_focused_max);
1461         RrAppearanceFree(theme->a_hover_unfocused_max);
1462         RrAppearanceFree(theme->a_toggled_hover_focused_max);
1463         RrAppearanceFree(theme->a_toggled_hover_unfocused_max);
1464         RrAppearanceFree(theme->a_toggled_focused_unpressed_max);
1465         RrAppearanceFree(theme->a_toggled_focused_pressed_max);
1466         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_max);
1467         RrAppearanceFree(theme->a_toggled_unfocused_pressed_max);
1468         RrAppearanceFree(theme->a_focused_unpressed_max);
1469         RrAppearanceFree(theme->a_focused_pressed_max);
1470         RrAppearanceFree(theme->a_unfocused_unpressed_max);
1471         RrAppearanceFree(theme->a_unfocused_pressed_max);
1472         RrAppearanceFree(theme->a_disabled_focused_close);
1473         RrAppearanceFree(theme->a_disabled_unfocused_close);
1474         RrAppearanceFree(theme->a_hover_focused_close);
1475         RrAppearanceFree(theme->a_hover_unfocused_close);
1476         RrAppearanceFree(theme->a_focused_unpressed_close);
1477         RrAppearanceFree(theme->a_focused_pressed_close);
1478         RrAppearanceFree(theme->a_unfocused_unpressed_close);
1479         RrAppearanceFree(theme->a_unfocused_pressed_close);
1480         RrAppearanceFree(theme->a_disabled_focused_desk);
1481         RrAppearanceFree(theme->a_disabled_unfocused_desk);
1482         RrAppearanceFree(theme->a_hover_focused_desk);
1483         RrAppearanceFree(theme->a_hover_unfocused_desk);
1484         RrAppearanceFree(theme->a_toggled_hover_focused_desk);
1485         RrAppearanceFree(theme->a_toggled_hover_unfocused_desk);
1486         RrAppearanceFree(theme->a_toggled_focused_unpressed_desk);
1487         RrAppearanceFree(theme->a_toggled_focused_pressed_desk);
1488         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_desk);
1489         RrAppearanceFree(theme->a_toggled_unfocused_pressed_desk);
1490         RrAppearanceFree(theme->a_focused_unpressed_desk);
1491         RrAppearanceFree(theme->a_focused_pressed_desk);
1492         RrAppearanceFree(theme->a_unfocused_unpressed_desk);
1493         RrAppearanceFree(theme->a_unfocused_pressed_desk);
1494         RrAppearanceFree(theme->a_disabled_focused_shade);
1495         RrAppearanceFree(theme->a_disabled_unfocused_shade);
1496         RrAppearanceFree(theme->a_hover_focused_shade);
1497         RrAppearanceFree(theme->a_hover_unfocused_shade);
1498         RrAppearanceFree(theme->a_toggled_hover_focused_shade);
1499         RrAppearanceFree(theme->a_toggled_hover_unfocused_shade);
1500         RrAppearanceFree(theme->a_toggled_focused_unpressed_shade);
1501         RrAppearanceFree(theme->a_toggled_focused_pressed_shade);
1502         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_shade);
1503         RrAppearanceFree(theme->a_toggled_unfocused_pressed_shade);
1504         RrAppearanceFree(theme->a_focused_unpressed_shade);
1505         RrAppearanceFree(theme->a_focused_pressed_shade);
1506         RrAppearanceFree(theme->a_unfocused_unpressed_shade);
1507         RrAppearanceFree(theme->a_unfocused_pressed_shade);
1508         RrAppearanceFree(theme->a_disabled_focused_iconify);
1509         RrAppearanceFree(theme->a_disabled_unfocused_iconify);
1510         RrAppearanceFree(theme->a_hover_focused_iconify);
1511         RrAppearanceFree(theme->a_hover_unfocused_iconify);
1512         RrAppearanceFree(theme->a_focused_unpressed_iconify);
1513         RrAppearanceFree(theme->a_focused_pressed_iconify);
1514         RrAppearanceFree(theme->a_unfocused_unpressed_iconify);
1515         RrAppearanceFree(theme->a_unfocused_pressed_iconify);
1516         RrAppearanceFree(theme->a_focused_grip);
1517         RrAppearanceFree(theme->a_unfocused_grip);
1518         RrAppearanceFree(theme->a_focused_title);
1519         RrAppearanceFree(theme->a_unfocused_title);
1520         RrAppearanceFree(theme->a_focused_label);
1521         RrAppearanceFree(theme->a_unfocused_label);
1522         RrAppearanceFree(theme->a_icon);
1523         RrAppearanceFree(theme->a_focused_handle);
1524         RrAppearanceFree(theme->a_unfocused_handle);
1525         RrAppearanceFree(theme->a_menu);
1526         RrAppearanceFree(theme->a_menu_title);
1527         RrAppearanceFree(theme->a_menu_text_title);
1528         RrAppearanceFree(theme->a_menu_normal);
1529         RrAppearanceFree(theme->a_menu_selected);
1530         RrAppearanceFree(theme->a_menu_disabled);
1531         RrAppearanceFree(theme->a_menu_disabled_selected);
1532         RrAppearanceFree(theme->a_menu_text_normal);
1533         RrAppearanceFree(theme->a_menu_text_selected);
1534         RrAppearanceFree(theme->a_menu_text_disabled);
1535         RrAppearanceFree(theme->a_menu_text_disabled_selected);
1536         RrAppearanceFree(theme->a_menu_bullet_normal);
1537         RrAppearanceFree(theme->a_menu_bullet_selected);
1538         RrAppearanceFree(theme->a_clear);
1539         RrAppearanceFree(theme->a_clear_tex);
1540         RrAppearanceFree(theme->osd_hilite_bg);
1541         RrAppearanceFree(theme->osd_hilite_fg);
1542         RrAppearanceFree(theme->osd_hilite_label);
1543         RrAppearanceFree(theme->osd_unhilite_fg);
1544
1545         g_free(theme);
1546     }
1547 }
1548
1549 static XrmDatabase loaddb(const gchar *name, gchar **path)
1550 {
1551     GSList *it;
1552     XrmDatabase db = NULL;
1553     gchar *s;
1554
1555     if (name[0] == '/') {
1556         s = g_build_filename(name, "openbox-3", "themerc", NULL);
1557         if ((db = XrmGetFileDatabase(s)))
1558             *path = g_path_get_dirname(s);
1559         g_free(s);
1560     } else {
1561         /* XXX backwards compatibility, remove me sometime later */
1562         s = g_build_filename(g_get_home_dir(), ".themes", name,
1563                              "openbox-3", "themerc", NULL);
1564         if ((db = XrmGetFileDatabase(s)))
1565             *path = g_path_get_dirname(s);
1566         g_free(s);
1567
1568         for (it = parse_xdg_data_dir_paths(); !db && it;
1569              it = g_slist_next(it))
1570         {
1571             s = g_build_filename(it->data, "themes", name,
1572                                  "openbox-3", "themerc", NULL);
1573             if ((db = XrmGetFileDatabase(s)))
1574                 *path = g_path_get_dirname(s);
1575             g_free(s);
1576         }
1577     }
1578
1579     if (db == NULL) {
1580         s = g_build_filename(name, "themerc", NULL);
1581         if ((db = XrmGetFileDatabase(s)))
1582             *path = g_path_get_dirname(s);
1583         g_free(s);
1584     }
1585
1586     return db;
1587 }
1588
1589 static gchar *create_class_name(const gchar *rname)
1590 {
1591     gchar *rclass = g_strdup(rname);
1592     gchar *p = rclass;
1593
1594     while (TRUE) {
1595         *p = toupper(*p);
1596         p = strchr(p+1, '.');
1597         if (p == NULL) break;
1598         ++p;
1599         if (*p == '\0') break;
1600     }
1601     return rclass;
1602 }
1603
1604 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
1605 {
1606     gboolean ret = FALSE;
1607     gchar *rclass = create_class_name(rname);
1608     gchar *rettype, *end;
1609     XrmValue retvalue;
1610
1611     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1612         retvalue.addr != NULL) {
1613         *value = (gint)strtol(retvalue.addr, &end, 10);
1614         if (end != retvalue.addr)
1615             ret = TRUE;
1616     }
1617
1618     g_free(rclass);
1619     return ret;
1620 }
1621
1622 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
1623 {
1624     gboolean ret = FALSE;
1625     gchar *rclass = create_class_name(rname);
1626     gchar *rettype;
1627     XrmValue retvalue;
1628
1629     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1630         retvalue.addr != NULL) {
1631         *value = retvalue.addr;
1632         ret = TRUE;
1633     }
1634
1635     g_free(rclass);
1636     return ret;
1637 }
1638
1639 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
1640                            const gchar *rname, RrColor **value)
1641 {
1642     gboolean ret = FALSE;
1643     gchar *rclass = create_class_name(rname);
1644     gchar *rettype;
1645     XrmValue retvalue;
1646
1647     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1648         retvalue.addr != NULL) {
1649         RrColor *c = RrColorParse(inst, retvalue.addr);
1650         if (c != NULL) {
1651             *value = c;
1652             ret = TRUE;
1653         }
1654     }
1655
1656     g_free(rclass);
1657     return ret;
1658 }
1659
1660 static gboolean read_mask(const RrInstance *inst, const gchar *path,
1661                           RrTheme *theme, const gchar *maskname,
1662                           RrPixmapMask **value)
1663 {
1664     gboolean ret = FALSE;
1665     gchar *s;
1666     gint hx, hy; /* ignored */
1667     guint w, h;
1668     guchar *b;
1669
1670     s = g_build_filename(path, maskname, NULL);
1671     if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
1672         ret = TRUE;
1673         *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
1674         XFree(b);
1675     }
1676     g_free(s);
1677
1678     return ret;
1679 }
1680
1681 static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
1682                              RrReliefType *relief, RrBevelType *bevel,
1683                              gboolean *interlaced, gboolean *border,
1684                              gboolean allow_trans)
1685 {
1686     gchar *t;
1687
1688     /* convert to all lowercase */
1689     for (t = tex; *t != '\0'; ++t)
1690         *t = g_ascii_tolower(*t);
1691
1692     if (allow_trans && strstr(tex, "parentrelative") != NULL) {
1693         *grad = RR_SURFACE_PARENTREL;
1694     } else {
1695         if (strstr(tex, "gradient") != NULL) {
1696             if (strstr(tex, "crossdiagonal") != NULL)
1697                 *grad = RR_SURFACE_CROSS_DIAGONAL;
1698             else if (strstr(tex, "pyramid") != NULL)
1699                 *grad = RR_SURFACE_PYRAMID;
1700             else if (strstr(tex, "mirrorhorizontal") != NULL)
1701                 *grad = RR_SURFACE_MIRROR_HORIZONTAL;
1702             else if (strstr(tex, "horizontal") != NULL)
1703                 *grad = RR_SURFACE_HORIZONTAL;
1704             else if (strstr(tex, "splitvertical") != NULL)
1705                 *grad = RR_SURFACE_SPLIT_VERTICAL;
1706             else if (strstr(tex, "vertical") != NULL)
1707                 *grad = RR_SURFACE_VERTICAL;
1708             else
1709                 *grad = RR_SURFACE_DIAGONAL;
1710         } else {
1711             *grad = RR_SURFACE_SOLID;
1712         }
1713     }
1714
1715     if (strstr(tex, "sunken") != NULL)
1716         *relief = RR_RELIEF_SUNKEN;
1717     else if (strstr(tex, "flat") != NULL)
1718         *relief = RR_RELIEF_FLAT;
1719     else if (strstr(tex, "raised") != NULL)
1720         *relief = RR_RELIEF_RAISED;
1721     else
1722         *relief = (*grad == RR_SURFACE_PARENTREL) ?
1723                   RR_RELIEF_FLAT : RR_RELIEF_RAISED;
1724
1725     *border = FALSE;
1726     if (*relief == RR_RELIEF_FLAT) {
1727         if (strstr(tex, "border") != NULL)
1728             *border = TRUE;
1729     } else {
1730         if (strstr(tex, "bevel2") != NULL)
1731             *bevel = RR_BEVEL_2;
1732         else
1733             *bevel = RR_BEVEL_1;
1734     }
1735
1736     if (strstr(tex, "interlaced") != NULL)
1737         *interlaced = TRUE;
1738     else
1739         *interlaced = FALSE;
1740 }
1741
1742
1743 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
1744                                 const gchar *rname, RrAppearance *value,
1745                                 gboolean allow_trans)
1746 {
1747     gboolean ret = FALSE;
1748     gchar *rclass = create_class_name(rname);
1749     gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
1750     gchar *csplitname, *ctosplitname;
1751     gchar *rettype;
1752     XrmValue retvalue;
1753     gint i;
1754
1755     cname = g_strconcat(rname, ".color", NULL);
1756     ctoname = g_strconcat(rname, ".colorTo", NULL);
1757     bcname = g_strconcat(rname, ".border.color", NULL);
1758     icname = g_strconcat(rname, ".interlace.color", NULL);
1759     hname = g_strconcat(rname, ".highlight", NULL);
1760     sname = g_strconcat(rname, ".shadow", NULL);
1761     csplitname = g_strconcat(rname, ".color.splitTo", NULL);
1762     ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
1763
1764     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1765         retvalue.addr != NULL) {
1766         parse_appearance(retvalue.addr,
1767                          &value->surface.grad,
1768                          &value->surface.relief,
1769                          &value->surface.bevel,
1770                          &value->surface.interlaced,
1771                          &value->surface.border,
1772                          allow_trans);
1773         if (!read_color(db, inst, cname, &value->surface.primary))
1774             value->surface.primary = RrColorNew(inst, 0, 0, 0);
1775         if (!read_color(db, inst, ctoname, &value->surface.secondary))
1776             value->surface.secondary = RrColorNew(inst, 0, 0, 0);
1777         if (value->surface.border)
1778             if (!read_color(db, inst, bcname,
1779                             &value->surface.border_color))
1780                 value->surface.border_color = RrColorNew(inst, 0, 0, 0);
1781         if (value->surface.interlaced)
1782             if (!read_color(db, inst, icname,
1783                             &value->surface.interlace_color))
1784                 value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
1785         if (read_int(db, hname, &i) && i >= 0)
1786             value->surface.bevel_light_adjust = i;
1787         if (read_int(db, sname, &i) && i >= 0 && i <= 256)
1788             value->surface.bevel_dark_adjust = i;
1789
1790         if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
1791             gint r, g, b;
1792
1793             if (!read_color(db, inst, csplitname,
1794                             &value->surface.split_primary))
1795             {
1796                 r = value->surface.primary->r;
1797                 r += r >> 2;
1798                 g = value->surface.primary->g;
1799                 g += g >> 2;
1800                 b = value->surface.primary->b;
1801                 b += b >> 2;
1802                 if (r > 0xFF) r = 0xFF;
1803                 if (g > 0xFF) g = 0xFF;
1804                 if (b > 0xFF) b = 0xFF;
1805                 value->surface.split_primary = RrColorNew(inst, r, g, b);
1806             }
1807
1808             if (!read_color(db, inst, ctosplitname,
1809                             &value->surface.split_secondary))
1810             {
1811                 r = value->surface.secondary->r;
1812                 r += r >> 4;
1813                 g = value->surface.secondary->g;
1814                 g += g >> 4;
1815                 b = value->surface.secondary->b;
1816                 b += b >> 4;
1817                 if (r > 0xFF) r = 0xFF;
1818                 if (g > 0xFF) g = 0xFF;
1819                 if (b > 0xFF) b = 0xFF;
1820                 value->surface.split_secondary = RrColorNew(inst, r, g, b);
1821             }
1822         }
1823
1824         ret = TRUE;
1825     }
1826
1827     g_free(ctosplitname);
1828     g_free(csplitname);
1829     g_free(sname);
1830     g_free(hname);
1831     g_free(icname);
1832     g_free(bcname);
1833     g_free(ctoname);
1834     g_free(cname);
1835     g_free(rclass);
1836     return ret;
1837 }
1838
1839 static int parse_inline_number(const char *p)
1840 {
1841     int neg = 1;
1842     int res = 0;
1843     if (*p == '-') {
1844         neg = -1;
1845         ++p;
1846     }
1847     for (; isdigit(*p); ++p)
1848         res = res * 10 + *p - '0';
1849     res *= neg;
1850     return res;
1851 }
1852
1853 static void set_default_appearance(RrAppearance *a)
1854 {
1855     a->surface.grad = RR_SURFACE_SOLID;
1856     a->surface.relief = RR_RELIEF_FLAT;
1857     a->surface.bevel = RR_BEVEL_1;
1858     a->surface.interlaced = FALSE;
1859     a->surface.border = FALSE;
1860     a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
1861     a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
1862 }
1863
1864 /* Reads the output from gimp's C-Source file format into valid RGBA data for
1865    an RrTextureRGBA. */
1866 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
1867 {
1868     RrPixel32 *im, *p;
1869     gint i;
1870
1871     p = im = g_memdup(data, width * height * sizeof(RrPixel32));
1872
1873     for (i = 0; i < width * height; ++i) {
1874         guchar a = ((*p >> 24) & 0xff);
1875         guchar b = ((*p >> 16) & 0xff);
1876         guchar g = ((*p >>  8) & 0xff);
1877         guchar r = ((*p >>  0) & 0xff);
1878
1879         *p = ((r << RrDefaultRedOffset) +
1880               (g << RrDefaultGreenOffset) +
1881               (b << RrDefaultBlueOffset) +
1882               (a << RrDefaultAlphaOffset));
1883         p++;
1884     }
1885
1886     return im;
1887 }