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