]> icculus.org git repositories - mikachu/openbox.git/blob - engines/openbox/theme.c
make the shadow offset 1
[mikachu/openbox.git] / engines / openbox / theme.c
1 #include "openbox.h"
2 #include "../../kernel/themerc.h"
3
4 #include <glib.h>
5 #include <X11/Xlib.h>
6 #include <X11/Xresource.h>
7 #ifdef HAVE_STDLIB_H
8 #  include <stdlib.h>
9 #endif
10 #ifdef HAVE_CTYPE_H
11 #  include <ctype.h>
12 #endif
13 #ifdef HAVE_STRING_H
14 #  include <string.h>
15 #endif
16
17 static XrmDatabase loaddb(char *theme)
18 {
19     XrmDatabase db;
20
21     db = XrmGetFileDatabase(theme);
22     if (db == NULL) {
23         char *s = g_build_filename(g_get_home_dir(), ".openbox", "themes",
24                                    "openbox", theme, NULL);
25         db = XrmGetFileDatabase(s);
26         g_free(s);
27     }
28     if (db == NULL) {
29         char *s = g_build_filename(THEMEDIR, theme, NULL);
30         db = XrmGetFileDatabase(s);
31         g_free(s);
32     }
33     return db;
34 }
35
36 static char *create_class_name(char *rname)
37 {
38     char *rclass = g_strdup(rname);
39     char *p = rclass;
40
41     while (TRUE) {
42         *p = toupper(*p);
43         p = strchr(p+1, '.');
44         if (p == NULL) break;
45         ++p;
46         if (*p == '\0') break;
47     }
48     return rclass;
49 }
50
51 gboolean read_bool(XrmDatabase db, char *rname, gboolean *value)
52 {
53     gboolean ret = FALSE;
54     char *rclass = create_class_name(rname);
55     char *rettype;
56     XrmValue retvalue;
57   
58     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
59         retvalue.addr != NULL) {
60         if (!g_ascii_strcasecmp(retvalue.addr, "true"))
61             *value = TRUE;
62         else
63             *value = FALSE;
64         ret = TRUE;
65     }
66
67     g_free(rclass);
68     return ret;
69 }
70
71 gboolean read_int(XrmDatabase db, char *rname, int *value)
72 {
73     gboolean ret = FALSE;
74     char *rclass = create_class_name(rname);
75     char *rettype, *end;
76     XrmValue retvalue;
77   
78     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
79         retvalue.addr != NULL) {
80         *value = (int)strtol(retvalue.addr, &end, 10);
81         if (end != retvalue.addr)
82             ret = TRUE;
83     }
84
85     g_free(rclass);
86     return ret;
87 }
88
89 gboolean read_string(XrmDatabase db, char *rname, char **value)
90 {
91     gboolean ret = FALSE;
92     char *rclass = create_class_name(rname);
93     char *rettype;
94     XrmValue retvalue;
95   
96     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
97         retvalue.addr != NULL) {
98         *value = g_strdup(retvalue.addr);
99         ret = TRUE;
100     }
101
102     g_free(rclass);
103     return ret;
104 }
105
106 gboolean read_color(XrmDatabase db, char *rname, color_rgb **value)
107 {
108     gboolean ret = FALSE;
109     char *rclass = create_class_name(rname);
110     char *rettype;
111     XrmValue retvalue;
112   
113     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
114         retvalue.addr != NULL) {
115         color_rgb *c = color_parse(retvalue.addr);
116         if (c != NULL) {
117             *value = c;
118             ret = TRUE;
119         }
120     }
121
122     g_free(rclass);
123     return ret;
124 }
125
126 gboolean read_mask(XrmDatabase db, char *rname, pixmap_mask **value)
127 {
128     gboolean ret = FALSE;
129     char *rclass = create_class_name(rname);
130     char *rettype;
131     XrmValue retvalue;
132   
133     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
134         retvalue.addr != NULL) {
135     }
136
137     g_free(rclass);
138     return ret;
139 }
140
141 static void parse_appearance(char *tex, SurfaceColorType *grad,
142                           ReliefType *relief, BevelType *bevel,
143                           gboolean *interlaced, gboolean *border)
144 {
145     char *t;
146
147     /* convert to all lowercase */
148     for (t = tex; *t != '\0'; ++t)
149         *t = g_ascii_tolower(*t);
150
151     if (strstr(tex, "parentrelative") != NULL) {
152         *grad = Background_ParentRelative;
153     } else {
154         if (strstr(tex, "gradient") != NULL) {
155             if (strstr(tex, "crossdiagonal") != NULL)
156                 *grad = Background_CrossDiagonal;
157             else if (strstr(tex, "rectangle") != NULL)
158                 *grad = Background_Rectangle;
159             else if (strstr(tex, "pyramid") != NULL)
160                 *grad = Background_Pyramid;
161             else if (strstr(tex, "pipecross") != NULL)
162                 *grad = Background_PipeCross;
163             else if (strstr(tex, "elliptic") != NULL)
164                 *grad = Background_Elliptic;
165             else if (strstr(tex, "horizontal") != NULL)
166                 *grad = Background_Horizontal;
167             else if (strstr(tex, "vertical") != NULL)
168                 *grad = Background_Vertical;
169             else
170                 *grad = Background_Diagonal;
171         } else {
172             *grad = Background_Solid;
173         }
174
175         if (strstr(tex, "sunken") != NULL)
176             *relief = Sunken;
177         else if (strstr(tex, "flat") != NULL)
178             *relief = Flat;
179         else
180             *relief = Raised;
181         
182         *border = FALSE;
183         if (*relief == Flat) {
184             if (strstr(tex, "border") != NULL)
185                 *border = TRUE;
186         } else {
187             if (strstr(tex, "bevel2") != NULL)
188                 *bevel = Bevel2;
189             else
190                 *bevel = Bevel1;
191         }
192
193         if (strstr(tex, "interlaced") != NULL)
194             *interlaced = TRUE;
195         else
196             *interlaced = FALSE;
197     }
198 }
199
200
201 gboolean read_appearance(XrmDatabase db, char *rname, Appearance *value)
202 {
203     gboolean ret = FALSE;
204     char *rclass = create_class_name(rname), *cname, *ctoname, *bcname;
205     char *rettype;
206     XrmValue retvalue;
207
208     cname = g_strconcat(rname, ".color", NULL);
209     ctoname = g_strconcat(rname, ".colorTo", NULL);
210     bcname = g_strconcat(rname, ".borderColor", NULL);
211
212     if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
213         retvalue.addr != NULL) {
214         parse_appearance(retvalue.addr,
215                          &value->surface.data.planar.grad,
216                          &value->surface.data.planar.relief,
217                          &value->surface.data.planar.bevel,
218                          &value->surface.data.planar.interlaced,
219                          &value->surface.data.planar.border);
220         if (!read_color(db, cname, &value->surface.data.planar.primary))
221             value->surface.data.planar.primary = color_new(0, 0, 0);
222         if (!read_color(db, ctoname, &value->surface.data.planar.secondary))
223             value->surface.data.planar.secondary = color_new(0, 0, 0);
224         if (value->surface.data.planar.border)
225             if (!read_color(db, bcname,
226                             &value->surface.data.planar.border_color))
227                 value->surface.data.planar.border_color = color_new(0, 0, 0);
228         ret = TRUE;
229     }
230
231     g_free(bcname);
232     g_free(ctoname);
233     g_free(cname);
234     g_free(rclass);
235     return ret;
236 }
237
238 void set_default_appearance(Appearance *a)
239 {
240     a->surface.data.planar.grad = Background_Solid;
241     a->surface.data.planar.relief = Flat;
242     a->surface.data.planar.bevel = Bevel1;
243     a->surface.data.planar.interlaced = FALSE;
244     a->surface.data.planar.border = FALSE;
245     a->surface.data.planar.primary = color_new(0, 0, 0);
246     a->surface.data.planar.secondary = color_new(0, 0, 0);
247 }
248
249 gboolean load()
250 {
251     XrmDatabase db = NULL;
252     Justify winjust;
253     char *winjuststr;
254
255     if (themerc_theme != NULL) {
256         db = loaddb(themerc_theme);
257         if (db == NULL) {
258             g_warning("Failed to load the theme '%s'", themerc_theme);
259             g_message("Falling back to the default: '%s'", DEFAULT_THEME);
260         }
261     }
262     if (db == NULL) {
263         db = loaddb(DEFAULT_THEME);
264         if (db == NULL) {
265             g_warning("Failed to load the theme '%s'.", DEFAULT_THEME);
266             return FALSE;
267         }
268     }
269
270     /* load the font, not from the theme file tho, its in themerc_font */
271     s_winfont_shadow = 1; /* XXX read from themrc */
272     s_winfont_shadow_offset = 1; /* XXX read from themerc */
273     s_winfont = font_open(themerc_font);
274     s_winfont_height = font_height(s_winfont, s_winfont_shadow,
275                                    s_winfont_shadow_offset);
276
277     winjust = Justify_Left;
278     if (read_string(db, "window.justify", &winjuststr)) {
279         if (!g_ascii_strcasecmp(winjuststr, "right"))
280             winjust = Justify_Right;
281         else if (!g_ascii_strcasecmp(winjuststr, "center"))
282             winjust = Justify_Center;
283         g_free(winjuststr);
284     }
285
286     if (!read_int(db, "handleWidth", &s_handle_height) ||
287         s_handle_height < 0 || s_handle_height > 100) s_handle_height = 6;
288     if (!read_int(db, "bevelWidth", &s_bevel) ||
289         s_bevel <= 0 || s_bevel > 100) s_bevel = 3;
290     if (!read_int(db, "borderWidth", &s_bwidth) ||
291         s_bwidth < 0 || s_bwidth > 100) s_bwidth = 1;
292     if (!read_int(db, "frameWidth", &s_cbwidth) ||
293         s_cbwidth < 0 || s_cbwidth > 100) s_cbwidth = s_bevel;
294
295     if (!read_color(db, "borderColor", &s_b_color))
296         s_b_color = color_new(0, 0, 0);
297     if (!read_color(db, "window.frame.focusColor", &s_cb_focused_color))
298         s_cb_focused_color = color_new(0xff, 0xff, 0xff);
299     if (!read_color(db, "window.frame.unfocusColor", &s_cb_unfocused_color))
300         s_cb_unfocused_color = color_new(0xff, 0xff, 0xff);
301     if (!read_color(db, "window.label.focus.textColor",
302                     &s_title_focused_color))
303         s_title_focused_color = color_new(0xff, 0xff, 0xff);
304     if (!read_color(db, "window.label.unfocus.textColor",
305                     &s_title_unfocused_color))
306         s_title_unfocused_color = color_new(0xff, 0xff, 0xff);
307     if (!read_color(db, "window.button.focus.picColor",
308                     &s_titlebut_focused_color))
309         s_titlebut_focused_color = color_new(0, 0, 0);
310     if (!read_color(db, "window.button.unfocus.picColor",
311                     &s_titlebut_unfocused_color))
312         s_titlebut_unfocused_color = color_new(0xff, 0xff, 0xff);
313
314     if (!read_mask(db, "window.button.max.mask", &s_max_mask)) {
315         char data[] = { 0x7c, 0x44, 0x47, 0x47, 0x7f, 0x1f, 0x1f  };
316         s_max_mask = pixmap_mask_new(7, 7, data);
317     }
318     if (!read_mask(db, "window.button.icon.mask", &s_icon_mask)) {
319         char data[] = { 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e };
320         s_icon_mask = pixmap_mask_new(7, 7, data);
321     }
322     if (!read_mask(db, "window.button.stick.mask", &s_desk_mask)) {
323         char data[] = { 0x00, 0x36, 0x36, 0x00, 0x36, 0x36, 0x00 };
324         s_desk_mask = pixmap_mask_new(7, 7, data);
325     }
326     if (!read_mask(db, "window.button.close.mask", &s_close_mask)) {
327         char data[] = { 0x22, 0x77, 0x3e, 0x1c, 0x3e, 0x77, 0x22 };
328         s_close_mask = pixmap_mask_new(7, 7, data);
329     }        
330
331     if (!read_appearance(db, "window.title.focus", a_focused_title))
332         set_default_appearance(a_focused_title);
333     if (!read_appearance(db, "window.title.unfocus", a_unfocused_title))
334         set_default_appearance(a_unfocused_title);
335     if (!read_appearance(db, "window.label.focus", a_focused_label))
336         set_default_appearance(a_focused_label);
337     if (!read_appearance(db, "window.label.unfocus", a_unfocused_label))
338         set_default_appearance(a_unfocused_label);
339     if (!read_appearance(db, "window.handle.focus", a_focused_handle))
340         set_default_appearance(a_focused_handle);
341     if (!read_appearance(db, "window.handle.unfocus", a_unfocused_handle))
342         set_default_appearance(a_unfocused_handle);
343     if (!read_appearance(db, "window.grip.focus", a_focused_grip))
344         set_default_appearance(a_focused_grip);
345     if (!read_appearance(db, "window.grip.unfocus", a_unfocused_grip))
346         set_default_appearance(a_unfocused_grip);
347
348     if (!read_appearance(db, "window.button.pressed.focus",
349                          a_focused_pressed_max))
350         if (!read_appearance(db, "window.button.pressed",
351                              a_focused_pressed_max))
352             set_default_appearance(a_focused_pressed_max);
353     if (!read_appearance(db, "window.button.pressed.unfocus",
354                          a_unfocused_pressed_max))
355         if (!read_appearance(db, "window.button.pressed",
356                              a_unfocused_pressed_max))
357             set_default_appearance(a_unfocused_pressed_max);
358     if (!read_appearance(db, "window.button.focus",
359                          a_focused_unpressed_max))
360             set_default_appearance(a_focused_unpressed_max);
361     if (!read_appearance(db, "window.button.unfocus",
362                          a_unfocused_unpressed_max))
363             set_default_appearance(a_unfocused_unpressed_max);
364
365     a_unfocused_unpressed_close = appearance_copy(a_unfocused_unpressed_max);
366     a_unfocused_pressed_close = appearance_copy(a_unfocused_pressed_max);
367     a_focused_unpressed_close = appearance_copy(a_focused_unpressed_max);
368     a_focused_pressed_close = appearance_copy(a_focused_pressed_max);
369     a_unfocused_unpressed_desk = appearance_copy(a_unfocused_unpressed_max);
370     a_unfocused_pressed_desk = appearance_copy(a_unfocused_pressed_max);
371     a_focused_unpressed_desk = appearance_copy(a_focused_unpressed_max);
372     a_focused_pressed_desk = appearance_copy(a_focused_pressed_max);
373     a_unfocused_unpressed_iconify = appearance_copy(a_unfocused_unpressed_max);
374     a_unfocused_pressed_iconify = appearance_copy(a_unfocused_pressed_max);
375     a_focused_unpressed_iconify = appearance_copy(a_focused_unpressed_max);
376     a_focused_pressed_iconify = appearance_copy(a_focused_pressed_max);
377
378     a_icon->surface.data.planar.grad = Background_ParentRelative;
379
380     /* set up the textures */
381     a_focused_label->texture[0].type = Text;
382     a_focused_label->texture[0].data.text.justify = winjust;
383     a_focused_label->texture[0].data.text.font = s_winfont;
384     a_focused_label->texture[0].data.text.shadow = s_winfont_shadow;
385     a_focused_label->texture[0].data.text.offset = s_winfont_shadow_offset;
386     a_focused_label->texture[0].data.text.color = s_title_focused_color;
387
388     a_unfocused_label->texture[0].type = Text;
389     a_unfocused_label->texture[0].data.text.justify = winjust;
390     a_unfocused_label->texture[0].data.text.font = s_winfont;
391     a_unfocused_label->texture[0].data.text.shadow = s_winfont_shadow;
392     a_unfocused_label->texture[0].data.text.offset = s_winfont_shadow_offset;
393     a_unfocused_label->texture[0].data.text.color = s_title_unfocused_color;
394
395     a_focused_unpressed_max->texture[0].type = 
396         a_focused_pressed_max->texture[0].type = 
397         a_unfocused_unpressed_max->texture[0].type = 
398         a_unfocused_pressed_max->texture[0].type = 
399         a_focused_unpressed_close->texture[0].type = 
400         a_focused_pressed_close->texture[0].type = 
401         a_unfocused_unpressed_close->texture[0].type = 
402         a_unfocused_pressed_close->texture[0].type = 
403         a_focused_unpressed_desk->texture[0].type = 
404         a_focused_pressed_desk->texture[0].type = 
405         a_unfocused_unpressed_desk->texture[0].type = 
406         a_unfocused_pressed_desk->texture[0].type = 
407         a_focused_unpressed_iconify->texture[0].type = 
408         a_focused_pressed_iconify->texture[0].type = 
409         a_unfocused_unpressed_iconify->texture[0].type = 
410         a_unfocused_pressed_iconify->texture[0].type = Bitmask;
411     a_focused_unpressed_max->texture[0].data.mask.mask = 
412         a_focused_pressed_max->texture[0].data.mask.mask = 
413         a_unfocused_unpressed_max->texture[0].data.mask.mask = 
414         a_unfocused_pressed_max->texture[0].data.mask.mask = s_max_mask;
415     a_focused_unpressed_close->texture[0].data.mask.mask = 
416         a_focused_pressed_close->texture[0].data.mask.mask = 
417         a_unfocused_unpressed_close->texture[0].data.mask.mask = 
418         a_unfocused_pressed_close->texture[0].data.mask.mask = s_close_mask;
419     a_focused_unpressed_desk->texture[0].data.mask.mask = 
420         a_focused_pressed_desk->texture[0].data.mask.mask = 
421         a_unfocused_unpressed_desk->texture[0].data.mask.mask = 
422         a_unfocused_pressed_desk->texture[0].data.mask.mask = s_desk_mask;
423     a_focused_unpressed_iconify->texture[0].data.mask.mask = 
424         a_focused_pressed_iconify->texture[0].data.mask.mask = 
425         a_unfocused_unpressed_iconify->texture[0].data.mask.mask = 
426         a_unfocused_pressed_iconify->texture[0].data.mask.mask = s_icon_mask;
427     a_focused_unpressed_max->texture[0].data.mask.color = 
428         a_focused_pressed_max->texture[0].data.mask.color = 
429         a_focused_unpressed_close->texture[0].data.mask.color = 
430         a_focused_pressed_close->texture[0].data.mask.color = 
431         a_focused_unpressed_desk->texture[0].data.mask.color = 
432         a_focused_pressed_desk->texture[0].data.mask.color = 
433         a_focused_unpressed_iconify->texture[0].data.mask.color = 
434         a_focused_pressed_iconify->texture[0].data.mask.color =
435         s_titlebut_focused_color;
436     a_unfocused_unpressed_max->texture[0].data.mask.color = 
437         a_unfocused_pressed_max->texture[0].data.mask.color = 
438         a_unfocused_unpressed_close->texture[0].data.mask.color = 
439         a_unfocused_pressed_close->texture[0].data.mask.color = 
440         a_unfocused_unpressed_desk->texture[0].data.mask.color = 
441         a_unfocused_pressed_desk->texture[0].data.mask.color = 
442         a_unfocused_unpressed_iconify->texture[0].data.mask.color = 
443         a_unfocused_pressed_iconify->texture[0].data.mask.color =
444         s_titlebut_unfocused_color;
445
446     XrmDestroyDatabase(db);
447     return TRUE;
448 }
449
450