7 #include <openbox/theme.h>
9 #define PADDING 2 /* openbox does it :/ */
11 static void theme_pixmap_paint(RrAppearance *a, gint w, gint h)
13 Pixmap out = RrPaintPixmap(a, w, h);
14 if (out) XFreePixmap(RrDisplay(a->inst), out);
17 static guint32 rr_color_pixel(const RrColor *c)
19 return (guint32)((RrColorRed(c) << 24) + (RrColorGreen(c) << 16) +
20 + (RrColorBlue(c) << 8) + 0xff);
23 /* XXX: Make this more general */
24 static GdkPixbuf* preview_menu(RrTheme *theme)
27 RrAppearance *title_text;
30 RrAppearance *background;
33 RrAppearance *disabled;
34 RrAppearance *selected;
35 RrAppearance *bullet; /* for submenu */
40 /* width and height of the whole menu */
48 /* set up appearances */
49 title = theme->a_menu_title;
51 title_text = theme->a_menu_text_title;
52 title_text->surface.parent = title;
53 title_text->texture[0].data.text.string = "menu";
55 normal = theme->a_menu_text_normal;
56 normal->texture[0].data.text.string = "normal";
58 disabled = theme->a_menu_text_disabled;
59 disabled->texture[0].data.text.string = "disabled";
61 selected = theme->a_menu_text_selected;
62 selected->texture[0].data.text.string = "selected";
64 bullet = theme->a_menu_bullet_normal;
66 /* determine window size */
67 RrMinSize(normal, &width, &th);
68 width += th + PADDING; /* make space for the bullet */
71 width += 2*theme->mbwidth + 2*PADDING;
73 /* get minimum title size */
74 RrMinSize(title, &tw, &title_h);
76 /* size of background behind each text line */
77 bw = width - 2*theme->mbwidth;
78 //title_h += 2*PADDING;
79 title_h = theme->menu_title_height;
81 RrMinSize(normal, &unused, &th);
84 height = title_h + 3*bh + 3*theme->mbwidth;
86 //height += 3*th + 3*theme->mbwidth + 5*PADDING;
89 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
90 gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_border_color));
93 x = y = theme->mbwidth;
94 theme_pixmap_paint(title, bw, title_h);
97 title_text->surface.parentx = 0;
98 title_text->surface.parenty = 0;
100 theme_pixmap_paint(title_text, bw, title_h);
102 pixmap = gdk_pixmap_foreign_new(title_text->pixmap);
103 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
104 gdk_colormap_get_system(),
105 0, 0, x, y, bw, title_h);
107 /* menu appears after title */
108 y += theme->mbwidth + title_h;
110 /* fill in menu appearance, used as the parent to every menu item's bg */
111 menu = theme->a_menu;
112 th = height - 3*theme->mbwidth - title_h;
113 theme_pixmap_paint(menu, bw, th);
115 pixmap = gdk_pixmap_foreign_new(menu->pixmap);
116 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
117 gdk_colormap_get_system(),
120 /* fill in background appearance, used as the parent to text items */
121 background = theme->a_menu_normal;
122 background->surface.parent = menu;
123 background->surface.parentx = 0;
124 background->surface.parenty = 0;
126 /* draw background for normal entry */
127 theme_pixmap_paint(background, bw, bh);
128 pixmap = gdk_pixmap_foreign_new(background->pixmap);
129 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
130 gdk_colormap_get_system(),
133 /* draw normal entry */
134 normal->surface.parent = background;
135 normal->surface.parentx = PADDING;
136 normal->surface.parenty = PADDING;
139 RrMinSize(normal, &tw, &th);
140 theme_pixmap_paint(normal, tw, th);
141 pixmap = gdk_pixmap_foreign_new(normal->pixmap);
142 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
143 gdk_colormap_get_system(),
147 RrMinSize(normal, &tw, &th);
148 bullet->surface.parent = background;
149 bullet->surface.parentx = bw - th;
150 bullet->surface.parenty = PADDING;
151 theme_pixmap_paint(bullet, th, th);
152 pixmap = gdk_pixmap_foreign_new(bullet->pixmap);
153 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
154 gdk_colormap_get_system(),
155 0, 0, width - theme->mbwidth - th, y,
160 /* draw background for disabled entry */
161 background->surface.parenty = bh;
162 theme_pixmap_paint(background, bw, bh);
163 pixmap = gdk_pixmap_foreign_new(background->pixmap);
164 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
165 gdk_colormap_get_system(),
166 0, 0, x - PADDING, y - PADDING,
169 /* draw disabled entry */
170 RrMinSize(disabled, &tw, &th);
171 disabled->surface.parent = background;
172 disabled->surface.parentx = PADDING;
173 disabled->surface.parenty = PADDING;
174 theme_pixmap_paint(disabled, tw, th);
175 pixmap = gdk_pixmap_foreign_new(disabled->pixmap);
176 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
177 gdk_colormap_get_system(),
182 /* draw background for selected entry */
183 background = theme->a_menu_selected;
184 background->surface.parent = menu;
185 background->surface.parentx = 2*bh;
187 theme_pixmap_paint(background, bw, bh);
188 pixmap = gdk_pixmap_foreign_new(background->pixmap);
189 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
190 gdk_colormap_get_system(),
191 0, 0, x - PADDING, y - PADDING,
194 /* draw selected entry */
195 RrMinSize(selected, &tw, &th);
196 selected->surface.parent = background;
197 selected->surface.parentx = PADDING;
198 selected->surface.parenty = PADDING;
199 theme_pixmap_paint(selected, tw, th);
200 pixmap = gdk_pixmap_foreign_new(selected->pixmap);
201 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
202 gdk_colormap_get_system(),
208 static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,
209 gboolean focus, gint width, gint height)
212 RrAppearance *handle;
216 GdkPixbuf *pixbuf = NULL;
219 gint w, label_w, h, x, y;
223 title = focus ? theme->a_focused_title : theme->a_unfocused_title;
226 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
227 gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_border_color));
230 w = width - 2*theme->fbwidth;
231 h = theme->title_height;
232 theme_pixmap_paint(title, w, h);
234 x = y = theme->fbwidth;;
235 pixmap = gdk_pixmap_foreign_new(title->pixmap);
236 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
237 gdk_colormap_get_system(),
240 /* calculate label width */
241 label_w = width - (theme->paddingx + theme->fbwidth + 1) * 2;
243 for (layout = titlelayout; *layout; layout++) {
246 label_w -= theme->button_size + 2 + theme->paddingx + 1;
253 label_w -= theme->button_size + theme->paddingx + 1;
260 x = theme->paddingx + theme->fbwidth + 1;
261 y += theme->paddingy + 1;
262 for (layout = titlelayout; *layout; layout++) {
264 if (*layout == 'N') {
266 /* set default icon */
267 a->texture[0].type = RR_TEXTURE_RGBA;
268 a->texture[0].data.rgba.width = 48;
269 a->texture[0].data.rgba.height = 48;
270 a->texture[0].data.rgba.data = theme->def_win_icon;
272 a->surface.parent = title;
273 a->surface.parentx = x;
274 a->surface.parenty = theme->paddingy;
276 w = h = theme->button_size + 2;
278 theme_pixmap_paint(a, w, h);
279 pixmap = gdk_pixmap_foreign_new(a->pixmap);
280 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
281 gdk_colormap_get_system(),
282 0, 0, x, y - 1, w, h);
284 x += theme->button_size + 2 + theme->paddingx + 1;
285 } else if (*layout == 'L') { /* label */
286 a = focus ? theme->a_focused_label : theme->a_unfocused_label;
287 a->texture[0].data.text.string = focus ? "active" : "inactive";
289 a->surface.parent = title;
290 a->surface.parentx = x;
291 a->surface.parenty = theme->paddingy;
293 h = theme->label_height;
295 theme_pixmap_paint(a, w, h);
296 pixmap = gdk_pixmap_foreign_new(a->pixmap);
297 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
298 gdk_colormap_get_system(),
299 0, 0, x, y - 1, w, h);
301 x += w + theme->paddingx + 1;
307 theme->a_focused_unpressed_desk :
308 theme->a_unfocused_unpressed_desk;
312 theme->a_focused_unpressed_shade :
313 theme->a_unfocused_unpressed_shade;
317 theme->a_focused_unpressed_iconify :
318 theme->a_unfocused_unpressed_iconify;
322 theme->a_focused_unpressed_max :
323 theme->a_unfocused_unpressed_max;
327 theme->a_focused_unpressed_close :
328 theme->a_unfocused_unpressed_close;
334 a->surface.parent = title;
335 a->surface.parentx = x;
336 a->surface.parenty = theme->paddingy + 1;
338 w = theme->button_size;
339 h = theme->button_size;
341 theme_pixmap_paint(a, w, h);
342 pixmap = gdk_pixmap_foreign_new(a->pixmap);
343 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
344 gdk_colormap_get_system(),
347 x += theme->button_size + theme->paddingx + 1;
351 if (theme->handle_height) {
353 handle = focus ? theme->a_focused_handle : theme->a_unfocused_handle;
354 x = 2*theme->fbwidth + theme->grip_width;
355 y = height - theme->fbwidth - theme->handle_height;
356 w = width - 4*theme->fbwidth - 2*theme->grip_width;
357 h = theme->handle_height;
359 theme_pixmap_paint(handle, w, h);
360 pixmap = gdk_pixmap_foreign_new(handle->pixmap);
361 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
362 gdk_colormap_get_system(),
365 /* openbox handles this drawing stuff differently (it fills the bottom
366 * of the window with the handle), so it avoids this bug where
367 * parentrelative grips are not fully filled. i'm avoiding it slightly
370 theme_pixmap_paint(handle, width, h);
373 a = focus ? theme->a_focused_grip : theme->a_unfocused_grip;
374 a->surface.parent = handle;
377 /* same y and h as handle */
378 w = theme->grip_width;
380 theme_pixmap_paint(a, w, h);
381 pixmap = gdk_pixmap_foreign_new(a->pixmap);
382 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
383 gdk_colormap_get_system(),
387 x = width - theme->fbwidth - theme->grip_width;
388 pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
389 gdk_colormap_get_system(),
393 /* retarded way of adding client colour */
395 y = theme->title_height + 2*theme->fbwidth;
396 w = width - 2*theme->fbwidth;
397 h = height - theme->title_height - 3*theme->fbwidth -
398 (theme->handle_height ? (theme->fbwidth + theme->handle_height) : 0);
400 scratch = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, w, h);
401 gdk_pixbuf_fill(scratch, rr_color_pixel(focus ?
402 theme->cb_focused_color :
403 theme->cb_unfocused_color));
405 gdk_pixbuf_copy_area(scratch, 0, 0, w, h, pixbuf, x, y);
410 static gint theme_label_width(RrTheme *theme, gboolean active)
416 label = theme->a_focused_label;
417 label->texture[0].data.text.string = "active";
419 label = theme->a_unfocused_label;
420 label->texture[0].data.text.string = "inactive";
423 return RrMinWidth(label);
426 static gint theme_window_min_width(RrTheme *theme, const gchar *titlelayout)
428 gint numbuttons = strlen(titlelayout);
429 gint w = 2 * (theme->fbwidth + theme->paddingx + 1);
431 if (g_strrstr(titlelayout, "L")) {
433 w += MAX(theme_label_width(theme, TRUE),
434 theme_label_width(theme, FALSE)) + theme->paddingx + 1;
437 w += (theme->button_size + theme->paddingx + 1) * numbuttons;
442 GdkPixbuf *preview_theme(const gchar *name, const gchar *titlelayout,
443 RrFont *active_window_font,
444 RrFont *inactive_window_font,
445 RrFont *menu_title_font,
446 RrFont *menu_item_font,
459 RrTheme *theme = RrThemeNew(rrinst, name,
460 active_window_font, inactive_window_font,
461 menu_title_font, menu_item_font, osd_font);
463 menu = preview_menu(theme);
465 window_w = theme_window_min_width(theme, titlelayout);
467 menu_w = gdk_pixbuf_get_width(menu);
468 h = gdk_pixbuf_get_height(menu);
470 w = MAX(window_w, menu_w) + 20;
472 preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
473 w, h + 2*(theme->title_height +5) + 1);
474 gdk_pixbuf_fill(preview, 0); /* clear */
476 window = preview_window(theme, titlelayout, FALSE, window_w, h);
477 gdk_pixbuf_copy_area(window, 0, 0, window_w, h, preview, 20, 0);
479 window = preview_window(theme, titlelayout, TRUE, window_w, h);
480 gdk_pixbuf_copy_area(window, 0, 0, window_w, h,
481 preview, 10, theme->title_height + 5);
483 gdk_pixbuf_copy_area(menu, 0, 0, menu_w, h,
484 preview, 0, 2 * (theme->title_height + 5));