1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 theme.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
26 #include "obt/paths.h"
29 #include <X11/Xresource.h>
35 RrAppearance *focused_disabled;
36 RrAppearance *unfocused_disabled;
37 RrAppearance *focused_hover;
38 RrAppearance *unfocused_hover;
39 RrAppearance *focused_unpressed;
40 RrAppearance *focused_pressed;
41 RrAppearance *unfocused_unpressed;
42 RrAppearance *unfocused_pressed;
43 RrAppearance *focused_hover_toggled;
44 RrAppearance *unfocused_hover_toggled;
45 RrAppearance *focused_unpressed_toggled;
46 RrAppearance *focused_pressed_toggled;
47 RrAppearance *unfocused_unpressed_toggled;
48 RrAppearance *unfocused_pressed_toggled;
51 static XrmDatabase loaddb(const gchar *name, gchar **path);
52 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
53 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
54 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
55 const gchar *rname, RrColor **value);
56 static gboolean read_mask(const RrInstance *inst, const gchar *path,
57 const gchar *maskname, RrPixmapMask **value);
58 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
59 const gchar *rname, RrAppearance *value,
60 gboolean allow_trans);
61 static int parse_inline_number(const char *p);
62 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
63 static void set_default_appearance(RrAppearance *a);
64 static void read_button_styles(XrmDatabase db, const RrInstance *inst,
66 const RrTheme *theme, RrButton *btn,
68 struct fallbacks *fbs,
70 guchar *toggled_mask);
72 static RrFont *get_font(RrFont *target, RrFont **default_font,
73 const RrInstance *inst)
79 /* Only load the default font once */
81 RrFontRef(*default_font);
83 *default_font = RrFontOpenDefault(inst);
89 #define READ_INT(x_resstr, x_var, x_min, x_max, x_def) \
90 if (!read_int(db, x_resstr, & x_var) || \
91 x_var < x_min || x_var > x_max) \
94 #define READ_COLOR(x_resstr, x_var, x_def) \
95 if (!read_color(db, inst, x_resstr, & x_var)) \
98 #define READ_COLOR_(x_res1, x_res2, x_var, x_def) \
99 if (!read_color(db, inst, x_res1, & x_var) && \
100 !read_color(db, inst, x_res2, & x_var)) \
103 #define READ_MASK_COPY(x_file, x_var, x_copysrc) \
104 if (!read_mask(inst, path, x_file, & x_var)) \
105 x_var = RrPixmapMaskCopy(x_copysrc);
107 #define READ_APPEARANCE(x_resstr, x_var, x_parrel) \
108 if (!read_appearance(db, inst, x_resstr, x_var, x_parrel)) \
109 set_default_appearance(x_var);
111 #define READ_APPEARANCE_COPY(x_resstr, x_var, x_parrel, x_defval) \
112 if (!read_appearance(db, inst, x_resstr, x_var, x_parrel)) {\
113 RrAppearanceFree(x_var); \
114 x_var = RrAppearanceCopy(x_defval); }
116 #define READ_APPEARANCE_COPY_TEXTURES(x_resstr, x_var, x_parrel, x_defval, n_tex) \
117 if (!read_appearance(db, inst, x_resstr, x_var, x_parrel)) {\
118 RrAppearanceFree(x_var); \
119 x_var = RrAppearanceCopy(x_defval); \
120 RrAppearanceRemoveTextures(x_var); \
121 RrAppearanceAddTextures(x_var, 5); }
123 #define READ_APPEARANCE_(x_res1, x_res2, x_var, x_parrel, x_defval) \
124 if (!read_appearance(db, inst, x_res1, x_var, x_parrel) && \
125 !read_appearance(db, inst, x_res2, x_var, x_parrel)) {\
126 RrAppearanceFree(x_var); \
127 x_var = RrAppearanceCopy(x_defval); }
129 RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name,
130 gboolean allow_fallback,
131 RrFont *active_window_font, RrFont *inactive_window_font,
132 RrFont *menu_title_font, RrFont *menu_item_font,
133 RrFont *active_osd_font, RrFont *inactive_osd_font)
135 XrmDatabase db = NULL;
136 RrJustify winjust, mtitlejust;
139 RrFont *default_font = NULL;
141 gint menu_overlap = 0;
142 struct fallbacks fbs;
145 db = loaddb(name, &path);
147 g_message("Unable to load the theme '%s'", name);
149 g_message("Falling back to the default theme '%s'",
151 /* fallback to the default theme */
156 if (allow_fallback) {
157 db = loaddb(DEFAULT_THEME, &path);
159 g_message("Unable to load the theme '%s'", DEFAULT_THEME);
166 /* initialize temp reading textures */
167 fbs.focused_disabled = RrAppearanceNew(inst, 1);
168 fbs.unfocused_disabled = RrAppearanceNew(inst, 1);
169 fbs.focused_hover = RrAppearanceNew(inst, 1);
170 fbs.unfocused_hover = RrAppearanceNew(inst, 1);
171 fbs.focused_unpressed_toggled = RrAppearanceNew(inst, 1);
172 fbs.unfocused_unpressed_toggled = RrAppearanceNew(inst, 1);
173 fbs.focused_hover_toggled = RrAppearanceNew(inst, 1);
174 fbs.unfocused_hover_toggled = RrAppearanceNew(inst, 1);
175 fbs.focused_pressed_toggled = RrAppearanceNew(inst, 1);
176 fbs.unfocused_pressed_toggled = RrAppearanceNew(inst, 1);
177 fbs.focused_unpressed = RrAppearanceNew(inst, 1);
178 fbs.focused_pressed = RrAppearanceNew(inst, 1);
179 fbs.unfocused_unpressed = RrAppearanceNew(inst, 1);
180 fbs.unfocused_pressed = RrAppearanceNew(inst, 1);
182 /* initialize theme */
183 theme = g_slice_new0(RrTheme);
186 theme->name = g_strdup(name ? name : DEFAULT_THEME);
189 theme->btn_max = RrButtonNew(inst);
190 theme->btn_close = RrButtonNew(inst);
191 theme->btn_desk = RrButtonNew(inst);
192 theme->btn_shade = RrButtonNew(inst);
193 theme->btn_iconify = RrButtonNew(inst);
195 /* init appearances */
196 theme->a_focused_grip = RrAppearanceNew(inst, 0);
197 theme->a_unfocused_grip = RrAppearanceNew(inst, 0);
198 theme->a_focused_title = RrAppearanceNew(inst, 0);
199 theme->a_unfocused_title = RrAppearanceNew(inst, 0);
200 theme->a_focused_label = RrAppearanceNew(inst, 1);
201 theme->a_unfocused_label = RrAppearanceNew(inst, 1);
202 theme->a_icon = RrAppearanceNew(inst, 1);
203 theme->a_focused_handle = RrAppearanceNew(inst, 0);
204 theme->a_unfocused_handle = RrAppearanceNew(inst, 0);
205 theme->a_menu = RrAppearanceNew(inst, 0);
206 theme->a_menu_title = RrAppearanceNew(inst, 0);
207 theme->a_menu_text_title = RrAppearanceNew(inst, 1);
208 theme->a_menu_normal = RrAppearanceNew(inst, 0);
209 theme->a_menu_selected = RrAppearanceNew(inst, 0);
210 theme->a_menu_disabled = RrAppearanceNew(inst, 0);
211 /* a_menu_disabled_selected is copied from a_menu_selected */
212 theme->a_menu_text_normal = RrAppearanceNew(inst, 1);
213 theme->a_menu_text_selected = RrAppearanceNew(inst, 1);
214 theme->a_menu_text_disabled = RrAppearanceNew(inst, 1);
215 theme->a_menu_text_disabled_selected = RrAppearanceNew(inst, 1);
216 theme->a_menu_bullet_normal = RrAppearanceNew(inst, 1);
217 theme->a_menu_bullet_selected = RrAppearanceNew(inst, 1);
218 theme->a_clear = RrAppearanceNew(inst, 0);
219 theme->a_clear_tex = RrAppearanceNew(inst, 1);
220 theme->osd_bg = RrAppearanceNew(inst, 0);
221 theme->osd_hilite_label = RrAppearanceNew(inst, 1);
222 theme->osd_hilite_bg = RrAppearanceNew(inst, 0);
223 theme->osd_unhilite_label = RrAppearanceNew(inst, 1);
224 theme->osd_unhilite_bg = RrAppearanceNew(inst, 0);
225 theme->osd_unpressed_button = RrAppearanceNew(inst, 1);
226 theme->osd_pressed_button = RrAppearanceNew(inst, 5);
227 theme->osd_focused_button = RrAppearanceNew(inst, 5);
229 /* load the font stuff */
230 theme->win_font_focused = get_font(active_window_font,
231 &default_font, inst);
232 theme->win_font_unfocused = get_font(inactive_window_font,
233 &default_font, inst);
235 winjust = RR_JUSTIFY_LEFT;
236 if (read_string(db, "window.label.text.justify", &str)) {
237 if (!g_ascii_strcasecmp(str, "right"))
238 winjust = RR_JUSTIFY_RIGHT;
239 else if (!g_ascii_strcasecmp(str, "center"))
240 winjust = RR_JUSTIFY_CENTER;
243 theme->menu_title_font = get_font(menu_title_font, &default_font, inst);
245 mtitlejust = RR_JUSTIFY_LEFT;
246 if (read_string(db, "menu.title.text.justify", &str)) {
247 if (!g_ascii_strcasecmp(str, "right"))
248 mtitlejust = RR_JUSTIFY_RIGHT;
249 else if (!g_ascii_strcasecmp(str, "center"))
250 mtitlejust = RR_JUSTIFY_CENTER;
253 theme->menu_font = get_font(menu_item_font, &default_font, inst);
255 theme->osd_font_hilite = get_font(active_osd_font, &default_font, inst);
256 theme->osd_font_unhilite = get_font(inactive_osd_font, &default_font,inst);
258 /* load direct dimensions */
259 READ_INT("menu.overlap", menu_overlap, -100, 100, 0);
260 READ_INT("menu.overlap.x", theme->menu_overlap_x, -100, 100, menu_overlap);
261 READ_INT("menu.overlap.y", theme->menu_overlap_y, -100, 100, menu_overlap);
262 READ_INT("window.handle.width", theme->handle_height, 0, 100, 6);
263 READ_INT("padding.width", theme->paddingx, 0, 100, 3);
264 READ_INT("padding.height", theme->paddingy, 0, 100, theme->paddingx);
265 READ_INT("border.width", theme->fbwidth, 0, 100, 1);
266 READ_INT("menu.border.width", theme->mbwidth, 0, 100, theme->fbwidth);
267 READ_INT("osd.border.width", theme->obwidth, 0, 100, theme->fbwidth);
268 READ_INT("undecorated.border.width", theme->ubwidth, 0, 100, theme->fbwidth);
269 READ_INT("menu.separator.width", theme->menu_sep_width, 1, 100, 1);
270 READ_INT("menu.separator.padding.width", theme->menu_sep_paddingx, 0, 100, 6);
271 READ_INT("menu.separator.padding.height", theme->menu_sep_paddingy, 0, 100, 3);
272 READ_INT("window.client.padding.width", theme->cbwidthx, 0, 100, theme->paddingx);
273 READ_INT("window.client.padding.height", theme->cbwidthy, 0, 100, theme->cbwidthx);
276 READ_COLOR_("window.active.border.color",
278 theme->frame_focused_border_color,
279 RrColorNew(inst, 0, 0, 0));
280 READ_COLOR("window.undecorated.active.border.color",
281 theme->frame_undecorated_focused_border_color,
282 RrColorCopy(theme->frame_focused_border_color));
283 READ_COLOR("window.active.title.separator.color",
284 theme->title_separator_focused_color,
285 RrColorCopy(theme->frame_focused_border_color));
287 READ_COLOR("window.inactive.border.color",
288 theme->frame_unfocused_border_color,
289 RrColorCopy(theme->frame_focused_border_color));
291 READ_COLOR("window.undecorated.inactive.border.color",
292 theme->frame_undecorated_unfocused_border_color,
293 RrColorCopy(theme->frame_unfocused_border_color));
295 READ_COLOR("window.inactive.title.separator.color",
296 theme->title_separator_unfocused_color,
297 RrColorCopy(theme->frame_unfocused_border_color));
299 READ_COLOR("menu.border.color",
300 theme->menu_border_color,
301 RrColorCopy(theme->frame_focused_border_color));
303 READ_COLOR("osd.border.color",
304 theme->osd_border_color,
305 RrColorCopy(theme->frame_focused_border_color));
307 READ_COLOR("window.active.client.color",
308 theme->cb_focused_color,
309 RrColorNew(inst, 0xff, 0xff, 0xff));
311 READ_COLOR("window.inactive.client.color",
312 theme->cb_unfocused_color,
313 RrColorNew(inst, 0xff, 0xff, 0xff));
315 READ_COLOR("window.active.label.text.color",
316 theme->title_focused_color,
317 RrColorNew(inst, 0x0, 0x0, 0x0));
319 READ_COLOR("window.inactive.label.text.color",
320 theme->title_unfocused_color,
321 RrColorNew(inst, 0xff, 0xff, 0xff));
323 READ_COLOR_("osd.active.label.text.color",
324 "osd.label.text.color",
325 theme->osd_text_active_color,
326 RrColorCopy(theme->title_focused_color));
328 READ_COLOR_("osd.inactive.label.text.color",
329 "osd.label.text.color",
330 theme->osd_text_inactive_color,
331 RrColorCopy(theme->title_unfocused_color));
333 READ_COLOR("window.active.button.unpressed.image.color",
334 theme->titlebut_focused_unpressed_color,
335 RrColorNew(inst, 0, 0, 0));
337 READ_COLOR("window.inactive.button.unpressed.image.color",
338 theme->titlebut_unfocused_unpressed_color,
339 RrColorNew(inst, 0xff, 0xff, 0xff));
341 READ_COLOR("window.active.button.pressed.image.color",
342 theme->titlebut_focused_pressed_color,
343 RrColorCopy(theme->titlebut_focused_unpressed_color));
345 READ_COLOR("window.inactive.button.pressed.image.color",
346 theme->titlebut_unfocused_pressed_color,
347 RrColorCopy(theme->titlebut_unfocused_unpressed_color));
349 READ_COLOR("window.active.button.disabled.image.color",
350 theme->titlebut_focused_disabled_color,
351 RrColorNew(inst, 0xff, 0xff, 0xff));
353 READ_COLOR("window.inactive.button.disabled.image.color",
354 theme->titlebut_unfocused_disabled_color,
355 RrColorNew(inst, 0, 0, 0));
357 READ_COLOR("window.active.button.hover.image.color",
358 theme->titlebut_focused_hover_color,
359 RrColorCopy(theme->titlebut_focused_unpressed_color));
361 READ_COLOR("window.inactive.button.hover.image.color",
362 theme->titlebut_unfocused_hover_color,
363 RrColorCopy(theme->titlebut_unfocused_unpressed_color));
365 READ_COLOR_("window.active.button.toggled.unpressed.image.color",
366 "window.active.button.toggled.image.color",
367 theme->titlebut_focused_unpressed_toggled_color,
368 RrColorCopy(theme->titlebut_focused_pressed_color));
370 READ_COLOR_("window.inactive.button.toggled.unpressed.image.color",
371 "window.inactive.button.toggled.image.color",
372 theme->titlebut_unfocused_unpressed_toggled_color,
373 RrColorCopy(theme->titlebut_unfocused_pressed_color));
375 READ_COLOR("window.active.button.toggled.hover.image.color",
376 theme->titlebut_focused_hover_toggled_color,
377 RrColorCopy(theme->titlebut_focused_unpressed_toggled_color));
379 READ_COLOR("window.inactive.button.toggled.hover.image.color",
380 theme->titlebut_unfocused_hover_toggled_color,
381 RrColorCopy(theme->titlebut_unfocused_unpressed_toggled_color));
383 READ_COLOR("window.active.button.toggled.pressed.image.color",
384 theme->titlebut_focused_pressed_toggled_color,
385 RrColorCopy(theme->titlebut_focused_pressed_color));
387 READ_COLOR("window.inactive.button.toggled.pressed.image.color",
388 theme->titlebut_unfocused_pressed_toggled_color,
389 RrColorCopy(theme->titlebut_unfocused_pressed_color));
391 READ_COLOR("menu.title.text.color",
392 theme->menu_title_color,
393 RrColorNew(inst, 0, 0, 0));
395 READ_COLOR("menu.items.text.color",
397 RrColorNew(inst, 0xff, 0xff, 0xff));
399 READ_COLOR("menu.bullet.image.color",
400 theme->menu_bullet_color,
401 RrColorCopy(theme->menu_color));
403 READ_COLOR("menu.items.disabled.text.color",
404 theme->menu_disabled_color,
405 RrColorNew(inst, 0, 0, 0));
407 READ_COLOR("menu.items.active.disabled.text.color",
408 theme->menu_disabled_selected_color,
409 RrColorCopy(theme->menu_disabled_color));
411 READ_COLOR("menu.items.active.text.color",
412 theme->menu_selected_color,
413 RrColorNew(inst, 0, 0, 0));
415 READ_COLOR("menu.separator.color",
416 theme->menu_sep_color,
417 RrColorCopy(theme->menu_color));
419 READ_COLOR("menu.bullet.selected.image.color",
420 theme->menu_bullet_selected_color,
421 RrColorCopy(theme->menu_selected_color));
423 READ_COLOR("osd.button.unpressed.text.color",
424 theme->osd_unpressed_color,
425 RrColorCopy(theme->osd_text_active_color));
426 READ_COLOR("osd.button.pressed.text.color",
427 theme->osd_pressed_color,
428 RrColorCopy(theme->osd_text_active_color));
429 READ_COLOR("osd.button.focused.text.color",
430 theme->osd_focused_color,
431 RrColorCopy(theme->osd_text_active_color));
432 READ_COLOR("osd.button.pressed.box.color",
433 theme->osd_pressed_lineart,
434 RrColorCopy(theme->titlebut_focused_pressed_color));
435 READ_COLOR("osd.button.focused.box.color",
436 theme->osd_focused_lineart,
437 RrColorCopy(theme->titlebut_focused_hover_color));
439 /* load window buttons */
441 /* bases: unpressed, pressed, disabled */
442 READ_APPEARANCE("window.active.button.unpressed.bg", fbs.focused_unpressed, TRUE);
443 READ_APPEARANCE("window.inactive.button.unpressed.bg", fbs.unfocused_unpressed, TRUE);
444 READ_APPEARANCE("window.active.button.pressed.bg", fbs.focused_pressed, TRUE);
445 READ_APPEARANCE("window.inactive.button.pressed.bg", fbs.unfocused_pressed, TRUE);
446 READ_APPEARANCE("window.active.button.disabled.bg", fbs.focused_disabled, TRUE);
447 READ_APPEARANCE("window.inactive.button.disabled.bg", fbs.unfocused_disabled, TRUE);
450 READ_APPEARANCE_COPY("window.active.button.hover.bg",
451 fbs.focused_hover, TRUE,
452 fbs.focused_unpressed);
453 READ_APPEARANCE_COPY("window.inactive.button.hover.bg",
454 fbs.unfocused_hover, TRUE,
455 fbs.unfocused_unpressed);
457 /* toggled unpressed */
458 READ_APPEARANCE_("window.active.button.toggled.unpressed.bg",
459 "window.active.button.toggled.bg",
460 fbs.focused_unpressed_toggled, TRUE,
461 fbs.focused_pressed);
462 READ_APPEARANCE_("window.inactive.button.toggled.unpressed.bg",
463 "window.inactive.button.toggled.bg",
464 fbs.unfocused_unpressed_toggled, TRUE,
465 fbs.unfocused_pressed);
467 /* toggled pressed */
468 READ_APPEARANCE_COPY("window.active.button.toggled.pressed.bg",
469 fbs.focused_pressed_toggled, TRUE,
470 fbs.focused_pressed);
471 READ_APPEARANCE_COPY("window.inactive.button.toggled.pressed.bg",
472 fbs.unfocused_pressed_toggled, TRUE,
473 fbs.unfocused_pressed);
476 READ_APPEARANCE_COPY("window.active.button.toggled.hover.bg",
477 fbs.focused_hover_toggled, TRUE,
478 fbs.focused_unpressed_toggled);
479 READ_APPEARANCE_COPY("window.inactive.button.toggled.hover.bg",
480 fbs.unfocused_hover_toggled, TRUE,
481 fbs.unfocused_unpressed_toggled);
484 /* now do individual buttons, if specified */
488 guchar normal_mask[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
489 guchar toggled_mask[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f };
490 read_button_styles(db, inst, path, theme, theme->btn_max, "max",
491 &fbs, normal_mask, toggled_mask);
496 guchar normal_mask[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 };
497 read_button_styles(db, inst, path, theme, theme->btn_close, "close",
498 &fbs, normal_mask, NULL);
501 /* all desktops button */
503 guchar normal_mask[] = { 0x33, 0x33, 0x00, 0x00, 0x33, 0x33 };
504 guchar toggled_mask[] = { 0x00, 0x1e, 0x1a, 0x16, 0x1e, 0x00 };
505 read_button_styles(db, inst, path, theme, theme->btn_desk, "desk",
506 &fbs, normal_mask, toggled_mask);
511 guchar normal_mask[] = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 };
512 read_button_styles(db, inst, path, theme, theme->btn_shade, "shade",
513 &fbs, normal_mask, normal_mask);
518 guchar normal_mask[] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f };
519 read_button_styles(db, inst, path, theme, theme->btn_iconify, "iconify",
520 &fbs, normal_mask, NULL);
523 /* submenu bullet mask */
524 if (!read_mask(inst, path, "bullet.xbm", &theme->menu_bullet_mask))
526 guchar data[] = { 0x01, 0x03, 0x07, 0x0f, 0x07, 0x03, 0x01 };
527 theme->menu_bullet_mask = RrPixmapMaskNew(inst, 4, 7, (gchar*)data);
530 /* up and down arrows */
532 guchar data[] = { 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00 };
533 theme->down_arrow_mask = RrPixmapMaskNew(inst, 9, 4, (gchar*)data);
536 guchar data[] = { 0x10, 0x00, 0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00 };
537 theme->up_arrow_mask = RrPixmapMaskNew(inst, 9, 4, (gchar*)data);
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 theme->def_win_icon_w = OB_DEFAULT_ICON_WIDTH;
545 theme->def_win_icon_h = OB_DEFAULT_ICON_HEIGHT;
547 /* read the decoration textures */
548 READ_APPEARANCE("window.active.title.bg", theme->a_focused_title, FALSE);
549 READ_APPEARANCE("window.inactive.title.bg", theme->a_unfocused_title, FALSE);
550 READ_APPEARANCE("window.active.label.bg", theme->a_focused_label, TRUE);
551 READ_APPEARANCE("window.inactive.label.bg", theme->a_unfocused_label, TRUE);
552 READ_APPEARANCE("window.active.handle.bg", theme->a_focused_handle, FALSE);
553 READ_APPEARANCE("window.inactive.handle.bg",theme->a_unfocused_handle, FALSE);
554 READ_APPEARANCE("window.active.grip.bg", theme->a_focused_grip, TRUE);
555 READ_APPEARANCE("window.inactive.grip.bg", theme->a_unfocused_grip, TRUE);
556 READ_APPEARANCE("menu.items.bg", theme->a_menu, FALSE);
557 READ_APPEARANCE("menu.title.bg", theme->a_menu_title, TRUE);
558 READ_APPEARANCE("menu.items.active.bg", theme->a_menu_selected, TRUE);
560 theme->a_menu_disabled_selected =
561 RrAppearanceCopy(theme->a_menu_selected);
563 /* read appearances for non-decorations (on-screen-display) */
564 if (!read_appearance(db, inst, "osd.bg", theme->osd_bg, FALSE))
566 RrAppearanceFree(theme->osd_bg);
567 theme->osd_bg = RrAppearanceCopy(theme->a_focused_title);
569 if (!read_appearance(db, inst, "osd.active.label.bg",
570 theme->osd_hilite_label, TRUE) &&
571 !read_appearance(db, inst, "osd.label.bg",
572 theme->osd_hilite_label, TRUE))
574 RrAppearanceFree(theme->osd_hilite_label);
575 theme->osd_hilite_label = RrAppearanceCopy(theme->a_focused_label);
577 if (!read_appearance(db, inst, "osd.inactive.label.bg",
578 theme->osd_unhilite_label, TRUE))
580 RrAppearanceFree(theme->osd_unhilite_label);
581 theme->osd_unhilite_label = RrAppearanceCopy(theme->a_unfocused_label);
583 /* osd_hilite_fg can't be parentrel */
584 if (!read_appearance(db, inst, "osd.hilight.bg",
585 theme->osd_hilite_bg, FALSE))
587 RrAppearanceFree(theme->osd_hilite_bg);
588 if (theme->a_focused_label->surface.grad != RR_SURFACE_PARENTREL)
589 theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_label);
591 theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_title);
593 /* osd_unhilite_fg can't be parentrel either */
594 if (!read_appearance(db, inst, "osd.unhilight.bg",
595 theme->osd_unhilite_bg, FALSE))
597 RrAppearanceFree(theme->osd_unhilite_bg);
598 if (theme->a_unfocused_label->surface.grad != RR_SURFACE_PARENTREL)
599 theme->osd_unhilite_bg=RrAppearanceCopy(theme->a_unfocused_label);
601 theme->osd_unhilite_bg=RrAppearanceCopy(theme->a_unfocused_title);
605 READ_APPEARANCE_COPY("osd.button.unpressed.bg", theme->osd_unpressed_button, TRUE, fbs.focused_unpressed);
606 READ_APPEARANCE_COPY_TEXTURES("osd.button.pressed.bg", theme->osd_pressed_button, TRUE, fbs.focused_pressed, 5);
607 READ_APPEARANCE_COPY_TEXTURES("osd.button.focused.bg", theme->osd_focused_button, TRUE, fbs.focused_unpressed, 5);
609 theme->a_icon->surface.grad =
610 theme->a_clear->surface.grad =
611 theme->a_clear_tex->surface.grad =
612 theme->a_menu_text_title->surface.grad =
613 theme->a_menu_normal->surface.grad =
614 theme->a_menu_disabled->surface.grad =
615 theme->a_menu_text_normal->surface.grad =
616 theme->a_menu_text_selected->surface.grad =
617 theme->a_menu_text_disabled->surface.grad =
618 theme->a_menu_text_disabled_selected->surface.grad =
619 theme->a_menu_bullet_normal->surface.grad =
620 theme->a_menu_bullet_selected->surface.grad = RR_SURFACE_PARENTREL;
622 /* set up the textures */
623 theme->a_focused_label->texture[0].type = RR_TEXTURE_TEXT;
624 theme->a_focused_label->texture[0].data.text.justify = winjust;
625 theme->a_focused_label->texture[0].data.text.font=theme->win_font_focused;
626 theme->a_focused_label->texture[0].data.text.color =
627 theme->title_focused_color;
629 if (read_string(db, "window.active.label.text.font", &str)) {
633 if (strstr(str, "shadow=y")) {
634 if ((p = strstr(str, "shadowoffset=")))
635 i = parse_inline_number(p + strlen("shadowoffset="));
638 theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
639 theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
641 if ((p = strstr(str, "shadowtint="))) {
642 i = parse_inline_number(p + strlen("shadowtint="));
643 j = (i > 0 ? 0 : 255);
646 theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
647 theme->title_focused_shadow_alpha = i;
649 theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
650 theme->title_focused_shadow_alpha = 50;
654 theme->a_focused_label->texture[0].data.text.shadow_color = theme->title_focused_shadow_color;
655 theme->a_focused_label->texture[0].data.text.shadow_alpha = theme->title_focused_shadow_alpha;
657 theme->osd_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
658 theme->osd_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
659 theme->osd_hilite_label->texture[0].data.text.font = theme->osd_font_hilite;
660 theme->osd_hilite_label->texture[0].data.text.color = theme->osd_text_active_color;
662 if (read_string(db, "osd.active.label.text.font", &str) ||
663 read_string(db, "osd.label.text.font", &str))
668 if (strstr(str, "shadow=y")) {
669 if ((p = strstr(str, "shadowoffset=")))
670 i = parse_inline_number(p + strlen("shadowoffset="));
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;
676 if ((p = strstr(str, "shadowtint="))) {
677 i = parse_inline_number(p + strlen("shadowtint="));
678 j = (i > 0 ? 0 : 255);
681 theme->osd_text_active_shadow_color = RrColorNew(inst, j, j, j);
682 theme->osd_text_active_shadow_alpha = i;
684 theme->osd_text_active_shadow_color = RrColorNew(inst, 0, 0, 0);
685 theme->osd_text_active_shadow_alpha = 50;
688 /* inherit the font settings from the focused label */
689 theme->osd_hilite_label->texture[0].data.text.shadow_offset_x =
690 theme->a_focused_label->texture[0].data.text.shadow_offset_x;
691 theme->osd_hilite_label->texture[0].data.text.shadow_offset_y =
692 theme->a_focused_label->texture[0].data.text.shadow_offset_y;
693 if (theme->title_focused_shadow_color)
694 theme->osd_text_active_shadow_color =
695 RrColorCopy(theme->title_focused_shadow_color);
697 theme->osd_text_active_shadow_color = RrColorNew(inst, 0, 0, 0);
698 theme->osd_text_active_shadow_alpha =
699 theme->title_focused_shadow_alpha;
702 theme->osd_hilite_label->texture[0].data.text.shadow_color =
703 theme->osd_text_active_shadow_color;
704 theme->osd_hilite_label->texture[0].data.text.shadow_alpha =
705 theme->osd_text_active_shadow_alpha;
707 theme->osd_unpressed_button->texture[0].type =
708 theme->osd_pressed_button->texture[0].type =
709 theme->osd_focused_button->texture[0].type =
712 theme->osd_unpressed_button->texture[0].data.text.justify =
713 theme->osd_pressed_button->texture[0].data.text.justify =
714 theme->osd_focused_button->texture[0].data.text.justify =
717 theme->osd_unpressed_button->texture[0].data.text.font =
718 theme->osd_pressed_button->texture[0].data.text.font =
719 theme->osd_focused_button->texture[0].data.text.font =
720 theme->osd_font_hilite;
722 theme->osd_unpressed_button->texture[0].data.text.color =
723 theme->osd_unpressed_color;
724 theme->osd_pressed_button->texture[0].data.text.color =
725 theme->osd_pressed_color;
726 theme->osd_focused_button->texture[0].data.text.color =
727 theme->osd_focused_color;
729 theme->osd_pressed_button->texture[1].data.lineart.color =
730 theme->osd_pressed_button->texture[2].data.lineart.color =
731 theme->osd_pressed_button->texture[3].data.lineart.color =
732 theme->osd_pressed_button->texture[4].data.lineart.color =
733 theme->osd_pressed_lineart;
735 theme->osd_focused_button->texture[1].data.lineart.color =
736 theme->osd_focused_button->texture[2].data.lineart.color =
737 theme->osd_focused_button->texture[3].data.lineart.color =
738 theme->osd_focused_button->texture[4].data.lineart.color =
739 theme->osd_focused_lineart;
741 theme->a_unfocused_label->texture[0].type = RR_TEXTURE_TEXT;
742 theme->a_unfocused_label->texture[0].data.text.justify = winjust;
743 theme->a_unfocused_label->texture[0].data.text.font = theme->win_font_unfocused;
744 theme->a_unfocused_label->texture[0].data.text.color = theme->title_unfocused_color;
746 if (read_string(db, "window.inactive.label.text.font", &str)) {
750 if (strstr(str, "shadow=y")) {
751 if ((p = strstr(str, "shadowoffset=")))
752 i = parse_inline_number(p + strlen("shadowoffset="));
755 theme->a_unfocused_label->texture[0].data.text.shadow_offset_x = i;
756 theme->a_unfocused_label->texture[0].data.text.shadow_offset_y = i;
758 if ((p = strstr(str, "shadowtint="))) {
759 i = parse_inline_number(p + strlen("shadowtint="));
760 j = (i > 0 ? 0 : 255);
763 theme->title_unfocused_shadow_color = RrColorNew(inst, j, j, j);
764 theme->title_unfocused_shadow_alpha = i;
766 theme->title_unfocused_shadow_color = RrColorNew(inst, 0, 0, 0);
767 theme->title_unfocused_shadow_alpha = 50;
771 theme->a_unfocused_label->texture[0].data.text.shadow_color =
772 theme->title_unfocused_shadow_color;
773 theme->a_unfocused_label->texture[0].data.text.shadow_alpha =
774 theme->title_unfocused_shadow_alpha;
776 theme->osd_unhilite_label->texture[0].type = RR_TEXTURE_TEXT;
777 theme->osd_unhilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
778 theme->osd_unhilite_label->texture[0].data.text.font =
779 theme->osd_font_unhilite;
780 theme->osd_unhilite_label->texture[0].data.text.color =
781 theme->osd_text_inactive_color;
783 if (read_string(db, "osd.inactive.label.text.font", &str)) {
787 if (strstr(str, "shadow=y")) {
788 if ((p = strstr(str, "shadowoffset=")))
789 i = parse_inline_number(p + strlen("shadowoffset="));
792 theme->osd_unhilite_label->texture[0].data.text.shadow_offset_x=i;
793 theme->osd_unhilite_label->texture[0].data.text.shadow_offset_y=i;
795 if ((p = strstr(str, "shadowtint="))) {
796 i = parse_inline_number(p + strlen("shadowtint="));
797 j = (i > 0 ? 0 : 255);
800 theme->osd_text_inactive_shadow_color = RrColorNew(inst, j, j, j);
801 theme->osd_text_inactive_shadow_alpha = i;
803 theme->osd_text_inactive_shadow_color = RrColorNew(inst, 0, 0, 0);
804 theme->osd_text_inactive_shadow_alpha = 50;
807 /* inherit the font settings from the unfocused label */
808 theme->osd_unhilite_label->texture[0].data.text.shadow_offset_x =
809 theme->a_unfocused_label->texture[0].data.text.shadow_offset_x;
810 theme->osd_unhilite_label->texture[0].data.text.shadow_offset_y =
811 theme->a_unfocused_label->texture[0].data.text.shadow_offset_y;
812 if (theme->title_unfocused_shadow_color)
813 theme->osd_text_inactive_shadow_color =
814 RrColorCopy(theme->title_unfocused_shadow_color);
816 theme->osd_text_inactive_shadow_color = RrColorNew(inst, 0, 0, 0);
817 theme->osd_text_inactive_shadow_alpha =
818 theme->title_unfocused_shadow_alpha;
821 theme->osd_unhilite_label->texture[0].data.text.shadow_color =
822 theme->osd_text_inactive_shadow_color;
823 theme->osd_unhilite_label->texture[0].data.text.shadow_alpha =
824 theme->osd_text_inactive_shadow_alpha;
826 theme->a_menu_text_title->texture[0].type = RR_TEXTURE_TEXT;
827 theme->a_menu_text_title->texture[0].data.text.justify = mtitlejust;
828 theme->a_menu_text_title->texture[0].data.text.font = theme->menu_title_font;
829 theme->a_menu_text_title->texture[0].data.text.color = theme->menu_title_color;
831 if (read_string(db, "menu.title.text.font", &str)) {
835 if (strstr(str, "shadow=y")) {
836 if ((p = strstr(str, "shadowoffset=")))
837 i = parse_inline_number(p + strlen("shadowoffset="));
840 theme->a_menu_text_title->texture[0].data.text.shadow_offset_x = i;
841 theme->a_menu_text_title->texture[0].data.text.shadow_offset_y = i;
843 if ((p = strstr(str, "shadowtint="))) {
844 i = parse_inline_number(p + strlen("shadowtint="));
845 j = (i > 0 ? 0 : 255);
848 theme->menu_title_shadow_color = RrColorNew(inst, j, j, j);
850 theme->menu_title_shadow_color = RrColorNew(inst, 0, 0, 0);
854 theme->a_menu_text_title->texture[0].data.text.shadow_color =
855 theme->menu_title_shadow_color;
856 theme->a_menu_text_title->texture[0].data.text.shadow_alpha =
860 theme->a_menu_text_normal->texture[0].type =
861 theme->a_menu_text_selected->texture[0].type =
862 theme->a_menu_text_disabled->texture[0].type =
863 theme->a_menu_text_disabled_selected->texture[0].type =
865 theme->a_menu_text_normal->texture[0].data.text.justify =
866 theme->a_menu_text_selected->texture[0].data.text.justify =
867 theme->a_menu_text_disabled->texture[0].data.text.justify =
868 theme->a_menu_text_disabled_selected->texture[0].data.text.justify =
870 theme->a_menu_text_normal->texture[0].data.text.font =
871 theme->a_menu_text_selected->texture[0].data.text.font =
872 theme->a_menu_text_disabled->texture[0].data.text.font =
873 theme->a_menu_text_disabled_selected->texture[0].data.text.font =
875 theme->a_menu_text_normal->texture[0].data.text.color = theme->menu_color;
876 theme->a_menu_text_selected->texture[0].data.text.color =
877 theme->menu_selected_color;
878 theme->a_menu_text_disabled->texture[0].data.text.color =
879 theme->menu_disabled_color;
880 theme->a_menu_text_disabled_selected->texture[0].data.text.color =
881 theme->menu_disabled_selected_color;
883 if (read_string(db, "menu.items.font", &str)) {
887 if (strstr(str, "shadow=y")) {
888 if ((p = strstr(str, "shadowoffset=")))
889 i = parse_inline_number(p + strlen("shadowoffset="));
892 theme->a_menu_text_normal->
893 texture[0].data.text.shadow_offset_x = i;
894 theme->a_menu_text_normal->
895 texture[0].data.text.shadow_offset_y = i;
896 theme->a_menu_text_selected->
897 texture[0].data.text.shadow_offset_x = i;
898 theme->a_menu_text_selected->
899 texture[0].data.text.shadow_offset_y = i;
900 theme->a_menu_text_disabled->
901 texture[0].data.text.shadow_offset_x = i;
902 theme->a_menu_text_disabled->
903 texture[0].data.text.shadow_offset_y = i;
904 theme->a_menu_text_disabled_selected->
905 texture[0].data.text.shadow_offset_x = i;
906 theme->a_menu_text_disabled_selected->
907 texture[0].data.text.shadow_offset_y = i;
909 if ((p = strstr(str, "shadowtint="))) {
910 i = parse_inline_number(p + strlen("shadowtint="));
911 j = (i > 0 ? 0 : 255);
914 theme->menu_text_shadow_color = RrColorNew(inst, j, j, j);
916 theme->menu_text_shadow_color = RrColorNew(inst, 0, 0, 0);
920 theme->a_menu_text_normal->texture[0].data.text.shadow_color =
921 theme->a_menu_text_selected->texture[0].data.text.shadow_color =
922 theme->a_menu_text_disabled->texture[0].data.text.shadow_color =
923 theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_color =
924 theme->menu_text_shadow_color;
926 theme->a_menu_text_normal->texture[0].data.text.shadow_alpha =
927 theme->a_menu_text_selected->texture[0].data.text.shadow_alpha =
928 theme->a_menu_text_disabled->texture[0].data.text.shadow_alpha =
929 theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_alpha =
933 theme->a_menu_bullet_normal->texture[0].type =
934 theme->a_menu_bullet_selected->texture[0].type = RR_TEXTURE_MASK;
935 theme->a_menu_bullet_normal->texture[0].data.mask.mask =
936 theme->a_menu_bullet_selected->texture[0].data.mask.mask =
937 theme->menu_bullet_mask;
938 theme->a_menu_bullet_normal->texture[0].data.mask.color =
939 theme->menu_bullet_color;
940 theme->a_menu_bullet_selected->texture[0].data.mask.color =
941 theme->menu_bullet_selected_color;
944 XrmDestroyDatabase(db);
946 /* set the font heights */
947 theme->win_font_height = RrFontHeight(theme->win_font_focused,
948 theme->a_focused_label->texture[0].data.text.shadow_offset_y);
949 theme->win_font_height =
950 MAX(theme->win_font_height,
951 RrFontHeight(theme->win_font_focused,
952 theme->a_unfocused_label->texture[0].data.text.shadow_offset_y));
953 theme->menu_title_font_height = RrFontHeight(theme->menu_title_font,
954 theme->a_menu_text_title->texture[0].data.text.shadow_offset_y);
955 theme->menu_font_height = RrFontHeight(theme->menu_font,
956 theme->a_menu_text_normal->texture[0].data.text.shadow_offset_y);
958 /* calculate some last extents */
960 gint ft, fb, fl, fr, ut, ub, ul, ur;
962 RrMargins(theme->a_focused_label, &fl, &ft, &fr, &fb);
963 RrMargins(theme->a_unfocused_label, &ul, &ut, &ur, &ub);
964 theme->label_height = theme->win_font_height + MAX(ft + fb, ut + ub);
965 theme->label_height += theme->label_height % 2;
967 /* this would be nice I think, since padding.width can now be 0,
968 but it breaks frame.c horribly and I don't feel like fixing that
969 right now, so if anyone complains, here is how to keep text from
970 going over the title's bevel/border with a padding.width of 0 and a
971 bevelless/borderless label
972 RrMargins(theme->a_focused_title, &fl, &ft, &fr, &fb);
973 RrMargins(theme->a_unfocused_title, &ul, &ut, &ur, &ub);
974 theme->title_height = theme->label_height +
975 MAX(MAX(theme->padding * 2, ft + fb),
976 MAX(theme->padding * 2, ut + ub));
978 theme->title_height = theme->label_height + theme->paddingy * 2;
980 RrMargins(theme->a_menu_title, &ul, &ut, &ur, &ub);
981 theme->menu_title_label_height = theme->menu_title_font_height+ut+ub;
982 theme->menu_title_height = theme->menu_title_label_height +
985 theme->button_size = theme->label_height - 2;
986 theme->grip_width = 25;
988 RrAppearanceFree(fbs.focused_disabled);
989 RrAppearanceFree(fbs.unfocused_disabled);
990 RrAppearanceFree(fbs.focused_hover);
991 RrAppearanceFree(fbs.unfocused_hover);
992 RrAppearanceFree(fbs.focused_unpressed);
993 RrAppearanceFree(fbs.focused_pressed);
994 RrAppearanceFree(fbs.unfocused_unpressed);
995 RrAppearanceFree(fbs.unfocused_pressed);
996 RrAppearanceFree(fbs.focused_hover_toggled);
997 RrAppearanceFree(fbs.unfocused_hover_toggled);
998 RrAppearanceFree(fbs.focused_unpressed_toggled);
999 RrAppearanceFree(fbs.focused_pressed_toggled);
1000 RrAppearanceFree(fbs.unfocused_unpressed_toggled);
1001 RrAppearanceFree(fbs.unfocused_pressed_toggled);
1006 void RrThemeFree(RrTheme *theme)
1009 g_free(theme->name);
1011 RrButtonFree(theme->btn_max);
1012 RrButtonFree(theme->btn_close);
1013 RrButtonFree(theme->btn_desk);
1014 RrButtonFree(theme->btn_shade);
1015 RrButtonFree(theme->btn_iconify);
1017 RrColorFree(theme->menu_border_color);
1018 RrColorFree(theme->osd_border_color);
1019 RrColorFree(theme->frame_focused_border_color);
1020 RrColorFree(theme->frame_undecorated_focused_border_color);
1021 RrColorFree(theme->frame_unfocused_border_color);
1022 RrColorFree(theme->frame_undecorated_unfocused_border_color);
1023 RrColorFree(theme->title_separator_focused_color);
1024 RrColorFree(theme->title_separator_unfocused_color);
1025 RrColorFree(theme->cb_unfocused_color);
1026 RrColorFree(theme->cb_focused_color);
1027 RrColorFree(theme->title_focused_color);
1028 RrColorFree(theme->title_unfocused_color);
1029 RrColorFree(theme->titlebut_focused_disabled_color);
1030 RrColorFree(theme->titlebut_unfocused_disabled_color);
1031 RrColorFree(theme->titlebut_focused_hover_color);
1032 RrColorFree(theme->titlebut_unfocused_hover_color);
1033 RrColorFree(theme->titlebut_focused_hover_toggled_color);
1034 RrColorFree(theme->titlebut_unfocused_hover_toggled_color);
1035 RrColorFree(theme->titlebut_focused_pressed_toggled_color);
1036 RrColorFree(theme->titlebut_unfocused_pressed_toggled_color);
1037 RrColorFree(theme->titlebut_focused_unpressed_toggled_color);
1038 RrColorFree(theme->titlebut_unfocused_unpressed_toggled_color);
1039 RrColorFree(theme->titlebut_focused_pressed_color);
1040 RrColorFree(theme->titlebut_unfocused_pressed_color);
1041 RrColorFree(theme->titlebut_focused_unpressed_color);
1042 RrColorFree(theme->titlebut_unfocused_unpressed_color);
1043 RrColorFree(theme->menu_title_color);
1044 RrColorFree(theme->menu_sep_color);
1045 RrColorFree(theme->menu_color);
1046 RrColorFree(theme->menu_bullet_color);
1047 RrColorFree(theme->menu_bullet_selected_color);
1048 RrColorFree(theme->menu_selected_color);
1049 RrColorFree(theme->menu_disabled_color);
1050 RrColorFree(theme->menu_disabled_selected_color);
1051 RrColorFree(theme->title_focused_shadow_color);
1052 RrColorFree(theme->title_unfocused_shadow_color);
1053 RrColorFree(theme->osd_text_active_color);
1054 RrColorFree(theme->osd_text_inactive_color);
1055 RrColorFree(theme->osd_text_active_shadow_color);
1056 RrColorFree(theme->osd_text_inactive_shadow_color);
1057 RrColorFree(theme->osd_pressed_color);
1058 RrColorFree(theme->osd_unpressed_color);
1059 RrColorFree(theme->osd_focused_color);
1060 RrColorFree(theme->osd_pressed_lineart);
1061 RrColorFree(theme->osd_focused_lineart);
1062 RrColorFree(theme->menu_title_shadow_color);
1063 RrColorFree(theme->menu_text_shadow_color);
1065 g_free(theme->def_win_icon);
1067 RrPixmapMaskFree(theme->menu_bullet_mask);
1068 RrPixmapMaskFree(theme->down_arrow_mask);
1069 RrPixmapMaskFree(theme->up_arrow_mask);
1071 RrFontClose(theme->win_font_focused);
1072 RrFontClose(theme->win_font_unfocused);
1073 RrFontClose(theme->menu_title_font);
1074 RrFontClose(theme->menu_font);
1075 RrFontClose(theme->osd_font_hilite);
1076 RrFontClose(theme->osd_font_unhilite);
1078 RrAppearanceFree(theme->a_focused_grip);
1079 RrAppearanceFree(theme->a_unfocused_grip);
1080 RrAppearanceFree(theme->a_focused_title);
1081 RrAppearanceFree(theme->a_unfocused_title);
1082 RrAppearanceFree(theme->a_focused_label);
1083 RrAppearanceFree(theme->a_unfocused_label);
1084 RrAppearanceFree(theme->a_icon);
1085 RrAppearanceFree(theme->a_focused_handle);
1086 RrAppearanceFree(theme->a_unfocused_handle);
1087 RrAppearanceFree(theme->a_menu);
1088 RrAppearanceFree(theme->a_menu_title);
1089 RrAppearanceFree(theme->a_menu_text_title);
1090 RrAppearanceFree(theme->a_menu_normal);
1091 RrAppearanceFree(theme->a_menu_selected);
1092 RrAppearanceFree(theme->a_menu_disabled);
1093 RrAppearanceFree(theme->a_menu_disabled_selected);
1094 RrAppearanceFree(theme->a_menu_text_normal);
1095 RrAppearanceFree(theme->a_menu_text_selected);
1096 RrAppearanceFree(theme->a_menu_text_disabled);
1097 RrAppearanceFree(theme->a_menu_text_disabled_selected);
1098 RrAppearanceFree(theme->a_menu_bullet_normal);
1099 RrAppearanceFree(theme->a_menu_bullet_selected);
1100 RrAppearanceFree(theme->a_clear);
1101 RrAppearanceFree(theme->a_clear_tex);
1102 RrAppearanceFree(theme->osd_bg);
1103 RrAppearanceFree(theme->osd_hilite_bg);
1104 RrAppearanceFree(theme->osd_hilite_label);
1105 RrAppearanceFree(theme->osd_unhilite_bg);
1106 RrAppearanceFree(theme->osd_unhilite_label);
1107 RrAppearanceFree(theme->osd_pressed_button);
1108 RrAppearanceFree(theme->osd_unpressed_button);
1109 RrAppearanceFree(theme->osd_focused_button);
1111 g_slice_free(RrTheme, theme);
1115 static XrmDatabase loaddb(const gchar *name, gchar **path)
1118 XrmDatabase db = NULL;
1121 if (name[0] == '/') {
1122 s = g_build_filename(name, "openbox-3", "themerc", NULL);
1123 if ((db = XrmGetFileDatabase(s)))
1124 *path = g_path_get_dirname(s);
1129 p = obt_paths_new();
1131 /* XXX backwards compatibility, remove me sometime later */
1132 s = g_build_filename(g_get_home_dir(), ".themes", name,
1133 "openbox-3", "themerc", NULL);
1134 if ((db = XrmGetFileDatabase(s)))
1135 *path = g_path_get_dirname(s);
1138 for (it = obt_paths_data_dirs(p); !db && it; it = g_slist_next(it))
1140 s = g_build_filename(it->data, "themes", name,
1141 "openbox-3", "themerc", NULL);
1142 if ((db = XrmGetFileDatabase(s)))
1143 *path = g_path_get_dirname(s);
1151 s = g_build_filename(name, "themerc", NULL);
1152 if ((db = XrmGetFileDatabase(s)))
1153 *path = g_path_get_dirname(s);
1160 static gchar *create_class_name(const gchar *rname)
1162 gchar *rclass = g_strdup(rname);
1167 p = strchr(p+1, '.');
1168 if (p == NULL) break;
1170 if (*p == '\0') break;
1175 static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
1177 gboolean ret = FALSE;
1178 gchar *rclass = create_class_name(rname);
1179 gchar *rettype, *end;
1182 if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1183 retvalue.addr != NULL) {
1184 *value = (gint)strtol(retvalue.addr, &end, 10);
1185 if (end != retvalue.addr)
1193 static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
1195 gboolean ret = FALSE;
1196 gchar *rclass = create_class_name(rname);
1200 if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1201 retvalue.addr != NULL) {
1202 g_strstrip(retvalue.addr);
1203 *value = retvalue.addr;
1211 static gboolean read_color(XrmDatabase db, const RrInstance *inst,
1212 const gchar *rname, RrColor **value)
1214 gboolean ret = FALSE;
1215 gchar *rclass = create_class_name(rname);
1219 if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1220 retvalue.addr != NULL) {
1223 /* retvalue.addr is inside the xrdb database so we can't destroy it
1224 but we can edit it in place, as g_strstrip does. */
1225 g_strstrip(retvalue.addr);
1226 c = RrColorParse(inst, retvalue.addr);
1237 static gboolean read_mask(const RrInstance *inst, const gchar *path,
1238 const gchar *maskname, RrPixmapMask **value)
1240 gboolean ret = FALSE;
1242 gint hx, hy; /* ignored */
1246 s = g_build_filename(path, maskname, NULL);
1247 if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
1249 *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
1257 static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
1258 RrReliefType *relief, RrBevelType *bevel,
1259 gboolean *interlaced, gboolean *border,
1260 gboolean allow_trans)
1264 /* convert to all lowercase */
1265 for (t = tex; *t != '\0'; ++t)
1266 *t = g_ascii_tolower(*t);
1268 if (allow_trans && strstr(tex, "parentrelative") != NULL) {
1269 *grad = RR_SURFACE_PARENTREL;
1271 if (strstr(tex, "gradient") != NULL) {
1272 if (strstr(tex, "crossdiagonal") != NULL)
1273 *grad = RR_SURFACE_CROSS_DIAGONAL;
1274 else if (strstr(tex, "pyramid") != NULL)
1275 *grad = RR_SURFACE_PYRAMID;
1276 else if (strstr(tex, "mirrorhorizontal") != NULL)
1277 *grad = RR_SURFACE_MIRROR_HORIZONTAL;
1278 else if (strstr(tex, "horizontal") != NULL)
1279 *grad = RR_SURFACE_HORIZONTAL;
1280 else if (strstr(tex, "splitvertical") != NULL)
1281 *grad = RR_SURFACE_SPLIT_VERTICAL;
1282 else if (strstr(tex, "vertical") != NULL)
1283 *grad = RR_SURFACE_VERTICAL;
1285 *grad = RR_SURFACE_DIAGONAL;
1287 *grad = RR_SURFACE_SOLID;
1291 if (strstr(tex, "sunken") != NULL)
1292 *relief = RR_RELIEF_SUNKEN;
1293 else if (strstr(tex, "flat") != NULL)
1294 *relief = RR_RELIEF_FLAT;
1295 else if (strstr(tex, "raised") != NULL)
1296 *relief = RR_RELIEF_RAISED;
1298 *relief = (*grad == RR_SURFACE_PARENTREL) ?
1299 RR_RELIEF_FLAT : RR_RELIEF_RAISED;
1302 if (*relief == RR_RELIEF_FLAT) {
1303 if (strstr(tex, "border") != NULL)
1306 if (strstr(tex, "bevel2") != NULL)
1307 *bevel = RR_BEVEL_2;
1309 *bevel = RR_BEVEL_1;
1312 if (strstr(tex, "interlaced") != NULL)
1315 *interlaced = FALSE;
1318 static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
1319 const gchar *rname, RrAppearance *value,
1320 gboolean allow_trans)
1322 gboolean ret = FALSE;
1323 gchar *rclass = create_class_name(rname);
1324 gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
1325 gchar *csplitname, *ctosplitname;
1330 cname = g_strconcat(rname, ".color", NULL);
1331 ctoname = g_strconcat(rname, ".colorTo", NULL);
1332 bcname = g_strconcat(rname, ".border.color", NULL);
1333 icname = g_strconcat(rname, ".interlace.color", NULL);
1334 hname = g_strconcat(rname, ".highlight", NULL);
1335 sname = g_strconcat(rname, ".shadow", NULL);
1336 csplitname = g_strconcat(rname, ".color.splitTo", NULL);
1337 ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
1339 if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
1340 retvalue.addr != NULL) {
1341 parse_appearance(retvalue.addr,
1342 &value->surface.grad,
1343 &value->surface.relief,
1344 &value->surface.bevel,
1345 &value->surface.interlaced,
1346 &value->surface.border,
1348 if (!read_color(db, inst, cname, &value->surface.primary))
1349 value->surface.primary = RrColorNew(inst, 0, 0, 0);
1350 if (!read_color(db, inst, ctoname, &value->surface.secondary))
1351 value->surface.secondary = RrColorNew(inst, 0, 0, 0);
1352 if (value->surface.border)
1353 if (!read_color(db, inst, bcname,
1354 &value->surface.border_color))
1355 value->surface.border_color = RrColorNew(inst, 0, 0, 0);
1356 if (value->surface.interlaced)
1357 if (!read_color(db, inst, icname,
1358 &value->surface.interlace_color))
1359 value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
1360 if (read_int(db, hname, &i) && i >= 0)
1361 value->surface.bevel_light_adjust = i;
1362 if (read_int(db, sname, &i) && i >= 0 && i <= 256)
1363 value->surface.bevel_dark_adjust = i;
1365 if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
1368 if (!read_color(db, inst, csplitname,
1369 &value->surface.split_primary))
1371 r = value->surface.primary->r;
1373 g = value->surface.primary->g;
1375 b = value->surface.primary->b;
1377 if (r > 0xFF) r = 0xFF;
1378 if (g > 0xFF) g = 0xFF;
1379 if (b > 0xFF) b = 0xFF;
1380 value->surface.split_primary = RrColorNew(inst, r, g, b);
1383 if (!read_color(db, inst, ctosplitname,
1384 &value->surface.split_secondary))
1386 r = value->surface.secondary->r;
1388 g = value->surface.secondary->g;
1390 b = value->surface.secondary->b;
1392 if (r > 0xFF) r = 0xFF;
1393 if (g > 0xFF) g = 0xFF;
1394 if (b > 0xFF) b = 0xFF;
1395 value->surface.split_secondary = RrColorNew(inst, r, g, b);
1402 g_free(ctosplitname);
1414 static int parse_inline_number(const char *p)
1422 for (; isdigit(*p); ++p)
1423 res = res * 10 + *p - '0';
1428 static void set_default_appearance(RrAppearance *a)
1430 a->surface.grad = RR_SURFACE_SOLID;
1431 a->surface.relief = RR_RELIEF_FLAT;
1432 a->surface.bevel = RR_BEVEL_1;
1433 a->surface.interlaced = FALSE;
1434 a->surface.border = FALSE;
1435 a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
1436 a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
1439 /* Reads the output from gimp's C-Source file format into valid RGBA data for
1440 an RrTextureRGBA. */
1441 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
1446 p = im = g_memdup(data, width * height * sizeof(RrPixel32));
1448 for (i = 0; i < width * height; ++i) {
1449 guchar a = ((*p >> 24) & 0xff);
1450 guchar b = ((*p >> 16) & 0xff);
1451 guchar g = ((*p >> 8) & 0xff);
1452 guchar r = ((*p >> 0) & 0xff);
1454 *p = ((r << RrDefaultRedOffset) +
1455 (g << RrDefaultGreenOffset) +
1456 (b << RrDefaultBlueOffset) +
1457 (a << RrDefaultAlphaOffset));
1464 static void read_button_styles(XrmDatabase db, const RrInstance *inst,
1466 const RrTheme *theme, RrButton *btn,
1467 const gchar *btnname,
1468 struct fallbacks *fbs,
1469 guchar *normal_mask,
1470 guchar *toggled_mask)
1472 gchar name[128], name2[128];
1473 gboolean userdef = TRUE;
1475 g_snprintf(name, 128, "%s.xbm", btnname);
1476 if (!read_mask(inst, path, name, &btn->unpressed_mask) && normal_mask)
1478 btn->unpressed_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)normal_mask);
1481 g_snprintf(name, 128, "%s_toggled.xbm", btnname);
1482 if (toggled_mask && !read_mask(inst, path, name, &btn->unpressed_toggled_mask))
1485 btn->unpressed_toggled_mask = RrPixmapMaskCopy(btn->unpressed_mask);
1487 btn->unpressed_toggled_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)toggled_mask);
1489 #define READ_BUTTON_MASK_COPY(type, fallback) \
1490 g_snprintf(name, 128, "%s_" #type ".xbm", btnname); \
1491 READ_MASK_COPY(name, btn->type##_mask, fallback);
1493 READ_BUTTON_MASK_COPY(pressed, btn->unpressed_mask);
1494 READ_BUTTON_MASK_COPY(disabled, btn->unpressed_mask);
1495 READ_BUTTON_MASK_COPY(hover, btn->unpressed_mask);
1497 READ_BUTTON_MASK_COPY(pressed_toggled, btn->unpressed_toggled_mask);
1498 READ_BUTTON_MASK_COPY(hover_toggled, btn->unpressed_toggled_mask);
1501 #define READ_BUTTON_APPEARANCE(typedots, type, fallback) \
1502 g_snprintf(name, 128, "window.active.button.%s." typedots ".image.color", btnname); \
1503 READ_COLOR(name, btn->focused_##type##_color, RrColorCopy(theme->titlebut_focused_##type##_color)); \
1504 g_snprintf(name, 128, "window.inactive.button.%s." typedots ".image.color", btnname); \
1505 READ_COLOR(name, btn->unfocused_##type##_color, RrColorCopy(theme->titlebut_unfocused_##type##_color)); \
1507 g_snprintf(name, 128, "window.active.button.%s." typedots ".bg", btnname); \
1508 g_snprintf(name2, 128, "window.active.button.%s.toggled.bg", btnname); \
1509 READ_APPEARANCE_(name, name2, btn->a_focused_##type, TRUE, fbs->focused_##type); \
1510 g_snprintf(name, 128, "window.inactive.button.%s." typedots ".bg", btnname); \
1511 g_snprintf(name2, 128, "window.inactive.button.%s.toggled.bg", btnname); \
1512 READ_APPEARANCE_(name, name2, btn->a_unfocused_##type, TRUE, fbs->unfocused_##type); \
1514 g_snprintf(name, 128, "window.active.button.%s." typedots ".bg", btnname); \
1515 READ_APPEARANCE_COPY(name, btn->a_focused_##type, TRUE, fbs->focused_##type); \
1516 g_snprintf(name, 128, "window.inactive.button.%s." typedots ".bg", btnname); \
1517 READ_APPEARANCE_COPY(name, btn->a_unfocused_##type, TRUE, fbs->unfocused_##type); \
1519 btn->a_unfocused_##type->texture[0].typ##e = \
1520 btn->a_focused_##type->texture[0].typ##e = \
1522 btn->a_unfocused_##type->texture[0].data.mask.mask = \
1523 btn->a_focused_##type->texture[0].data.mask.mask = \
1525 btn->a_unfocused_##type->texture[0].data.mask.color = \
1526 btn->unfocused_##type##_color; \
1527 btn->a_focused_##type->texture[0].data.mask.color = \
1528 btn->focused_##type##_color;
1530 READ_BUTTON_APPEARANCE("unpressed", unpressed, 0);
1531 READ_BUTTON_APPEARANCE("pressed", pressed, 0);
1532 READ_BUTTON_APPEARANCE("disabled", disabled, 0);
1533 READ_BUTTON_APPEARANCE("hover", hover, 0);
1535 READ_BUTTON_APPEARANCE("unpressed.toggled", unpressed_toggled, 1);
1536 READ_BUTTON_APPEARANCE("pressed.toggled", pressed_toggled, 0);
1537 READ_BUTTON_APPEARANCE("hover.toggled", hover_toggled, 0);