static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout, gboolean focus, gint width, gint height) { RrAppearance *title; RrAppearance *handle; RrAppearance *a; GdkPixmap *pixmap; GdkPixbuf *pixbuf = NULL; GdkPixbuf *scratch; gint w, label_w, h, x, y; const gchar *layout; title = focus ? theme->a_focused_title : theme->a_unfocused_title; /* set border */ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); gdk_pixbuf_fill(pixbuf, rr_color_pixel(focus ? theme->frame_focused_border_color : theme->frame_unfocused_border_color)); /* title */ w = width - 2*theme->fbwidth; h = theme->title_height; theme_pixmap_paint(title, w, h); x = y = theme->fbwidth; pixmap = gdk_pixmap_foreign_new(title->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, w, h); /* calculate label width */ label_w = width - (theme->paddingx + theme->fbwidth + 1) * 2; for (layout = titlelayout; *layout; layout++) { switch (*layout) { case 'N': label_w -= theme->button_size + 2 + theme->paddingx + 1; break; case 'D': case 'S': case 'I': case 'M': case 'C': label_w -= theme->button_size + theme->paddingx + 1; break; default: break; } } x = theme->paddingx + theme->fbwidth + 1; y += theme->paddingy; for (layout = titlelayout; *layout; layout++) { /* icon */ if (*layout == 'N') { a = theme->a_icon; /* set default icon */ a->texture[0].type = RR_TEXTURE_RGBA; a->texture[0].data.rgba.width = 48; a->texture[0].data.rgba.height = 48; a->texture[0].data.rgba.alpha = 0xff; a->texture[0].data.rgba.data = theme->def_win_icon; a->surface.parent = title; a->surface.parentx = x - theme->fbwidth; a->surface.parenty = theme->paddingy; w = h = theme->button_size + 2; theme_pixmap_paint(a, w, h); pixmap = gdk_pixmap_foreign_new(a->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, w, h); x += theme->button_size + 2 + theme->paddingx + 1; } else if (*layout == 'L') { /* label */ a = focus ? theme->a_focused_label : theme->a_unfocused_label; a->texture[0].data.text.string = focus ? "Active" : "Inactive"; a->surface.parent = title; a->surface.parentx = x - theme->fbwidth; a->surface.parenty = theme->paddingy; w = label_w; h = theme->label_height; theme_pixmap_paint(a, w, h); pixmap = gdk_pixmap_foreign_new(a->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, w, h); x += w + theme->paddingx + 1; } else { /* buttons */ switch (*layout) { case 'D': a = focus ? theme->btn_desk->a_focused_unpressed : theme->btn_desk->a_unfocused_unpressed; break; case 'S': a = focus ? theme->btn_shade->a_focused_unpressed : theme->btn_shade->a_unfocused_unpressed; break; case 'I': a = focus ? theme->btn_iconify->a_focused_unpressed : theme->btn_iconify->a_unfocused_unpressed; break; case 'M': a = focus ? theme->btn_max->a_focused_unpressed : theme->btn_max->a_unfocused_unpressed; break; case 'C': a = focus ? theme->btn_close->a_focused_unpressed : theme->btn_close->a_unfocused_unpressed; break; default: continue; } a->surface.parent = title; a->surface.parentx = x - theme->fbwidth; a->surface.parenty = theme->paddingy + 1; w = theme->button_size; h = theme->button_size; theme_pixmap_paint(a, w, h); pixmap = gdk_pixmap_foreign_new(a->pixmap); /* use y + 1 because these buttons should be centered wrt the label */ pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y + 1, w, h); x += theme->button_size + theme->paddingx + 1; } } if (theme->handle_height) { /* handle */ handle = focus ? theme->a_focused_handle : theme->a_unfocused_handle; x = 2*theme->fbwidth + theme->grip_width; y = height - theme->fbwidth - theme->handle_height; w = width - 4*theme->fbwidth - 2*theme->grip_width; h = theme->handle_height; theme_pixmap_paint(handle, w, h); pixmap = gdk_pixmap_foreign_new(handle->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, w, h); /* openbox handles this drawing stuff differently (it fills the bottom * of the window with the handle), so it avoids this bug where * parentrelative grips are not fully filled. i'm avoiding it slightly * differently. */ theme_pixmap_paint(handle, width, h); /* grips */ a = focus ? theme->a_focused_grip : theme->a_unfocused_grip; a->surface.parent = handle; x = theme->fbwidth; /* same y and h as handle */ w = theme->grip_width; theme_pixmap_paint(a, w, h); pixmap = gdk_pixmap_foreign_new(a->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, w, h); /* right grip */ x = width - theme->fbwidth - theme->grip_width; pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, w, h); } /* title separator colour */ x = theme->fbwidth; y = theme->fbwidth + theme->title_height; w = width - 2*theme->fbwidth; h = theme->fbwidth; scratch = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h); gdk_pixbuf_fill(scratch, rr_color_pixel(focus ? theme->title_separator_focused_color : theme->title_separator_unfocused_color)); gdk_pixbuf_copy_area(scratch, 0, 0, w, h, pixbuf, x, y); /* retarded way of adding client colour */ x = theme->fbwidth; y = theme->title_height + 2*theme->fbwidth; w = width - 2*theme->fbwidth; h = height - theme->title_height - 3*theme->fbwidth - (theme->handle_height ? (theme->fbwidth + theme->handle_height) : 0); scratch = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h); gdk_pixbuf_fill(scratch, rr_color_pixel(focus ? theme->cb_focused_color : theme->cb_unfocused_color)); gdk_pixbuf_copy_area(scratch, 0, 0, w, h, pixbuf, x, y); /* clear (no alpha!) the area where the client resides */ gdk_pixbuf_fill(scratch, 0xffffffff); gdk_pixbuf_copy_area(scratch, 0, 0, w - 2*theme->cbwidthx, h - 2*theme->cbwidthy, pixbuf, x + theme->cbwidthx, y + theme->cbwidthy); return pixbuf; }
/* XXX: Make this more general */ static GdkPixbuf* preview_menu(RrTheme *theme) { RrAppearance *title; RrAppearance *title_text; RrAppearance *menu; RrAppearance *background; RrAppearance *normal; RrAppearance *disabled; RrAppearance *selected; RrAppearance *bullet; /* for submenu */ GdkPixmap *pixmap; GdkPixbuf *pixbuf; /* width and height of the whole menu */ gint width, height; gint x, y; gint title_h; gint tw, th; gint bw, bh; gint unused; /* set up appearances */ title = theme->a_menu_title; title_text = theme->a_menu_text_title; title_text->surface.parent = title; title_text->texture[0].data.text.string = "Menu"; normal = theme->a_menu_text_normal; normal->texture[0].data.text.string = "Normal"; disabled = theme->a_menu_text_disabled; disabled->texture[0].data.text.string = "Disabled"; selected = theme->a_menu_text_selected; selected->texture[0].data.text.string = "Selected"; bullet = theme->a_menu_bullet_normal; /* determine window size */ RrMinSize(normal, &width, &th); width += th + PADDING; /* make space for the bullet */ //height = th; width += 2*theme->mbwidth + 2*PADDING; /* get minimum title size */ RrMinSize(title, &tw, &title_h); /* size of background behind each text line */ bw = width - 2*theme->mbwidth; //title_h += 2*PADDING; title_h = theme->menu_title_height; RrMinSize(normal, &unused, &th); bh = th + 2*PADDING; height = title_h + 3*bh + 3*theme->mbwidth; //height += 3*th + 3*theme->mbwidth + 5*PADDING; /* set border */ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_border_color)); /* draw title */ x = y = theme->mbwidth; theme_pixmap_paint(title, bw, title_h); /* draw title text */ title_text->surface.parentx = 0; title_text->surface.parenty = 0; theme_pixmap_paint(title_text, bw, title_h); pixmap = gdk_pixmap_foreign_new(title_text->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, bw, title_h); /* menu appears after title */ y += theme->mbwidth + title_h; /* fill in menu appearance, used as the parent to every menu item's bg */ menu = theme->a_menu; th = height - 3*theme->mbwidth - title_h; theme_pixmap_paint(menu, bw, th); pixmap = gdk_pixmap_foreign_new(menu->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, bw, th); /* fill in background appearance, used as the parent to text items */ background = theme->a_menu_normal; background->surface.parent = menu; background->surface.parentx = 0; background->surface.parenty = 0; /* draw background for normal entry */ theme_pixmap_paint(background, bw, bh); pixmap = gdk_pixmap_foreign_new(background->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, bw, bh); /* draw normal entry */ normal->surface.parent = background; normal->surface.parentx = PADDING; normal->surface.parenty = PADDING; x += PADDING; y += PADDING; RrMinSize(normal, &tw, &th); theme_pixmap_paint(normal, tw, th); pixmap = gdk_pixmap_foreign_new(normal->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, tw, th); /* draw bullet */ RrMinSize(normal, &tw, &th); bullet->surface.parent = background; bullet->surface.parentx = bw - th; bullet->surface.parenty = PADDING; theme_pixmap_paint(bullet, th, th); pixmap = gdk_pixmap_foreign_new(bullet->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, width - theme->mbwidth - th, y, th, th); y += th + 2*PADDING; /* draw background for disabled entry */ background->surface.parenty = bh; theme_pixmap_paint(background, bw, bh); pixmap = gdk_pixmap_foreign_new(background->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x - PADDING, y - PADDING, bw, bh); /* draw disabled entry */ RrMinSize(disabled, &tw, &th); disabled->surface.parent = background; disabled->surface.parentx = PADDING; disabled->surface.parenty = PADDING; theme_pixmap_paint(disabled, tw, th); pixmap = gdk_pixmap_foreign_new(disabled->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, tw, th); y += th + 2*PADDING; /* draw background for selected entry */ background = theme->a_menu_selected; background->surface.parent = menu; background->surface.parentx = 2*bh; theme_pixmap_paint(background, bw, bh); pixmap = gdk_pixmap_foreign_new(background->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x - PADDING, y - PADDING, bw, bh); /* draw selected entry */ RrMinSize(selected, &tw, &th); selected->surface.parent = background; selected->surface.parentx = PADDING; selected->surface.parenty = PADDING; theme_pixmap_paint(selected, tw, th); pixmap = gdk_pixmap_foreign_new(selected->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, tw, th); return pixbuf; }
/* XXX: Make this more general */ static GdkPixbuf* preview_menu(RrTheme *theme) { RrAppearance *title; RrAppearance *title_text; RrAppearance *menu; RrAppearance *background; RrAppearance *normal; RrAppearance *disabled; RrAppearance *selected; RrAppearance *bullet; /* for submenu */ cairo_surface_t *surface; GdkScreen *screen; Display *xdisplay; Visual *xvisual; GdkPixbuf *pixbuf, *tmp_pixbuf; /* width and height of the whole menu */ gint width, height; gint x, y; gint title_h; gint tw, th; gint bw, bh; gint unused; screen = gdk_screen_get_default(); xdisplay = gdk_x11_get_default_xdisplay(); xvisual = gdk_x11_visual_get_xvisual(gdk_screen_get_system_visual(screen)); /* set up appearances */ title = theme->a_menu_title; title_text = theme->a_menu_text_title; title_text->surface.parent = title; title_text->texture[0].data.text.string = "Menu"; normal = theme->a_menu_text_normal; normal->texture[0].data.text.string = "Normal"; disabled = theme->a_menu_text_disabled; disabled->texture[0].data.text.string = "Disabled"; selected = theme->a_menu_text_selected; selected->texture[0].data.text.string = "Selected"; bullet = theme->a_menu_bullet_normal; /* determine window size */ RrMinSize(normal, &width, &th); width += th + PADDING; /* make space for the bullet */ width += 2*theme->mbwidth + 2*PADDING; /* get minimum title size */ RrMinSize(title, &tw, &title_h); /* size of background behind each text line */ bw = width - 2*theme->mbwidth; //title_h += 2*PADDING; title_h = theme->menu_title_height; RrMinSize(normal, &unused, &th); bh = th + 2*PADDING; height = title_h + 3*bh + 3*theme->mbwidth; /* set border */ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_border_color)); tmp_pixbuf = gdk_pixbuf_copy(pixbuf); /* menu appears after inside the border */ x = y = theme->mbwidth; /* fill in menu appearance, used as the parent to every menu item's bg */ menu = theme->a_menu; th = height - 2 * theme->mbwidth; theme_pixmap_paint(menu, bw, th); /* draw title, it appears at the top of the menu background */ title->surface.parent = theme->a_menu; title->surface.parentx = 0; title->surface.parenty = 0; theme_pixmap_paint(title, bw, title_h); /* draw title text */ title_text->surface.parentx = 0; title_text->surface.parenty = 0; theme_pixmap_paint(title_text, bw, title_h); surface = cairo_xlib_surface_create(xdisplay, title_text->pixmap, xvisual, bw, title_h); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, title_h); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, title_h, pixbuf, x, y); y += title_h + theme->mbwidth; /* fill in background appearance, used as the parent to text items */ background = theme->a_menu_normal; background->surface.parent = menu; background->surface.parentx = x - theme->mbwidth; background->surface.parenty = y - theme->mbwidth; /* draw background for normal entry */ theme_pixmap_paint(background, bw, bh); surface = cairo_xlib_surface_create(xdisplay, background->pixmap, xvisual, bw, bh); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, bh); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, bh, pixbuf, x, y); /* draw normal entry */ normal->surface.parent = background; normal->surface.parentx = PADDING; normal->surface.parenty = PADDING; RrMinSize(normal, &tw, &th); theme_pixmap_paint(normal, tw, th); surface = cairo_xlib_surface_create(xdisplay, normal->pixmap, xvisual, tw, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, tw, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, tw, th, pixbuf, x + PADDING, y + PADDING); /* draw bullet */ RrMinSize(normal, &tw, &th); bullet->surface.parent = background; bullet->surface.parentx = bw - th; bullet->surface.parenty = PADDING; theme_pixmap_paint(bullet, th, th); surface = cairo_xlib_surface_create(xdisplay, bullet->pixmap, xvisual, th, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, th, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, th, th, pixbuf, width - theme->mbwidth - th, y + PADDING); y += th + 2*PADDING; /* draw background for disabled entry */ background->surface.parent = menu; background->surface.parentx = x - theme->mbwidth; background->surface.parenty = y - theme->mbwidth; theme_pixmap_paint(background, bw, bh); surface = cairo_xlib_surface_create(xdisplay, background->pixmap, xvisual, bw, bh); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, bh); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, bh, pixbuf, x, y); /* draw disabled entry */ RrMinSize(disabled, &tw, &th); disabled->surface.parent = background; disabled->surface.parentx = PADDING; disabled->surface.parenty = PADDING; theme_pixmap_paint(disabled, tw, th); surface = cairo_xlib_surface_create(xdisplay, disabled->pixmap, xvisual, tw, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, tw, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, tw, th, pixbuf, x + PADDING, y + PADDING); y += th + 2*PADDING; /* draw background for selected entry */ background = theme->a_menu_selected; background->surface.parent = menu; background->surface.parentx = x - theme->mbwidth; background->surface.parenty = y - theme->mbwidth; theme_pixmap_paint(background, bw, bh); surface = cairo_xlib_surface_create(xdisplay, background->pixmap, xvisual, bw, bh); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, bh); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, bh, pixbuf, x, y); /* draw selected entry */ RrMinSize(selected, &tw, &th); selected->surface.parent = background; selected->surface.parentx = PADDING; selected->surface.parenty = PADDING; theme_pixmap_paint(selected, tw, th); surface = cairo_xlib_surface_create(xdisplay, selected->pixmap, xvisual, tw, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, tw, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, tw, th, pixbuf, x + PADDING, y + PADDING); g_object_unref(tmp_pixbuf); return pixbuf; }