From 3803df4bae100d7e26133fb448d3a6fcc82c3d53 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 31 May 2007 04:11:29 +0000 Subject: [PATCH] add theme previews! yay syscrash! --- Makefile.am | 2 + src/handlers.c | 119 ++++++++++++-- src/main.c | 7 +- src/main.h | 5 +- src/preview.c | 436 +++++++++++++++++++++++++++++++++++++++++++++++++ src/preview.h | 16 ++ 6 files changed, 568 insertions(+), 17 deletions(-) create mode 100644 src/preview.c create mode 100644 src/preview.h diff --git a/Makefile.am b/Makefile.am index 4b71903..420aaec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,6 +42,8 @@ src_obconf_SOURCES = \ src/main.h \ src/handlers.c \ src/handlers.h \ + src/preview.c \ + src/preview.h \ src/theme.c \ src/theme.h \ src/tree.c \ diff --git a/src/handlers.c b/src/handlers.c index b8db244..8c6862d 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -35,6 +35,10 @@ static int num_desktops; static GList *desktop_names; static GtkListStore *theme_store; +static RrFont *active_window_font, *inactive_window_font, *menu_title_font, *menu_item_font, *osd_font; + +static gchar *titlelayout; + static void on_desktop_names_cell_edited(GtkCellRendererText *cell, const gchar *path_string, const gchar *new_text, @@ -42,6 +46,7 @@ static void on_desktop_names_cell_edited(GtkCellRendererText *cell, static void on_theme_names_selection_changed(GtkTreeSelection *sel, gpointer data); +static void handlers_update_theme_previews(); void setup_behavior_tab() @@ -384,6 +389,8 @@ static void reset_theme_names(GtkWidget *w) GList *it, *next; gint i; + RrFont *active, *inactive, *menu_t, *menu_i, *osd; + name = tree_get_string("theme/name", "TheBear"); for (it = themes; it; it = g_list_next(it)) @@ -427,7 +434,7 @@ static void reset_theme_names(GtkWidget *w) gtk_list_store_append(theme_store, &iter); gtk_list_store_set(theme_store, &iter, 0, it->data, - 1, TRUE, + 1, NULL, -1); if(!strcmp(name, it->data)) { @@ -454,18 +461,27 @@ void setup_theme_names(GtkWidget *w) mapping = TRUE; /* widget setup */ - theme_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN); + theme_store = gtk_list_store_new(2, G_TYPE_STRING, GDK_TYPE_PIXBUF); gtk_tree_view_set_model(GTK_TREE_VIEW(w), GTK_TREE_MODEL(theme_store)); g_object_unref (theme_store); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(w)), GTK_SELECTION_SINGLE); + /* text column for the names */ render = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes ("Name", render, "text", 0, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(w), column); + /* pixbuf column, for theme previews */ + render = gtk_cell_renderer_pixbuf_new(); + g_object_set(render, "xalign", 1.0); + column = gtk_tree_view_column_new_with_attributes + ("Preview", render, "pixbuf", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(w), column); + + /* setup the selection handler */ select = gtk_tree_view_get_selection(GTK_TREE_VIEW (w)); gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); @@ -475,6 +491,8 @@ void setup_theme_names(GtkWidget *w) reset_theme_names(w); + handlers_update_theme_previews(); + mapping = FALSE; } @@ -485,6 +503,7 @@ void setup_title_layout(GtkWidget *w) mapping = TRUE; layout = tree_get_string("theme/titleLayout", "NLIMC"); + titlelayout = g_strdup(layout); gtk_entry_set_text(GTK_ENTRY(w), layout); g_free(layout); @@ -513,14 +532,18 @@ void setup_window_border(GtkWidget *w) mapping = FALSE; } -static void setup_font(GtkWidget *w, const gchar *place) +static RrFont *setup_font(GtkWidget *w, const gchar *place) { + RrFont *font; gchar *fontstring, *node; gchar *name, **names; gchar *size; gchar *weight; gchar *slant; + RrFontWeight rr_weight = RR_FONTWEIGHT_NORMAL; + RrFontSlant rr_slant = RR_FONTSLANT_NORMAL; + mapping = TRUE; node = g_strdup_printf("theme/font:place=%s/name", place); @@ -555,6 +578,12 @@ static void setup_font(GtkWidget *w, const gchar *place) fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size); gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring); + + if (!g_ascii_strcasecmp(weight, "Bold")) rr_weight = RR_FONTWEIGHT_BOLD; + if (!g_ascii_strcasecmp(slant, "Italic")) rr_slant = RR_FONTSLANT_ITALIC; + if (!g_ascii_strcasecmp(slant, "Oblique")) rr_slant = RR_FONTSLANT_OBLIQUE; + + font = RrFontOpen(rrinst, name, atoi(size), rr_weight, rr_slant); g_free(fontstring); g_free(slant); g_free(weight); @@ -562,31 +591,33 @@ static void setup_font(GtkWidget *w, const gchar *place) g_free(name); mapping = FALSE; + + return font; } void setup_font_active(GtkWidget *w) { - setup_font(w, "ActiveWindow"); + active_window_font = setup_font(w, "ActiveWindow"); } void setup_font_inactive(GtkWidget *w) { - setup_font(w, "InactiveWindow"); + inactive_window_font = setup_font(w, "InactiveWindow"); } void setup_font_menu_header(GtkWidget *w) { - setup_font(w, "MenuHeader"); + menu_title_font = setup_font(w, "MenuHeader"); } void setup_font_menu_item(GtkWidget *w) { - setup_font(w, "MenuItem"); + menu_item_font = setup_font(w, "MenuItem"); } void setup_font_display(GtkWidget *w) { - setup_font(w, "OnScreenDisplay"); + osd_font = setup_font(w, "OnScreenDisplay"); } @@ -680,7 +711,7 @@ void on_window_border_toggled(GtkToggleButton *w, gpointer data) tree_set_bool("theme/keepBorder", b); } -static void on_font_set(GtkFontButton *w, const gchar *place) +static RrFont *on_font_set(GtkFontButton *w, const gchar *place) { gchar *c; gchar *font, *node; @@ -688,6 +719,9 @@ static void on_font_set(GtkFontButton *w, const gchar *place) const gchar *bold = NULL; const gchar *italic = NULL; + RrFontWeight weight = RR_FONTWEIGHT_NORMAL; + RrFontSlant slant = RR_FONTSLANT_NORMAL; + if (mapping) return; font = g_strdup(gtk_font_button_get_font_name(w)); @@ -721,32 +755,49 @@ static void on_font_set(GtkFontButton *w, const gchar *place) tree_set_string(node, italic); g_free(node); + if (!g_ascii_strcasecmp(bold, "Bold")) weight = RR_FONTWEIGHT_BOLD; + if (!g_ascii_strcasecmp(italic, "Italic")) slant = RR_FONTSLANT_ITALIC; + if (!g_ascii_strcasecmp(italic, "Oblique")) slant = RR_FONTSLANT_OBLIQUE; + + return RrFontOpen(rrinst, font, atoi(size), weight, slant); + g_free(font); + } void on_font_active_font_set(GtkFontButton *w, gpointer data) { - on_font_set(w, "ActiveWindow"); + RrFontClose(active_window_font); + active_window_font = on_font_set(w, "ActiveWindow"); + handlers_update_theme_previews(); } void on_font_inactive_font_set(GtkFontButton *w, gpointer data) { - on_font_set(w, "InactiveWindow"); + RrFontClose(inactive_window_font); + inactive_window_font = on_font_set(w, "InactiveWindow"); + handlers_update_theme_previews(); } void on_font_menu_header_font_set(GtkFontButton *w, gpointer data) { - on_font_set(w, "MenuHeader"); + RrFontClose(menu_title_font); + menu_title_font = on_font_set(w, "MenuHeader"); + handlers_update_theme_previews(); } void on_font_menu_item_font_set(GtkFontButton *w, gpointer data) { - on_font_set(w, "MenuItem"); + RrFontClose(menu_item_font); + menu_item_font = on_font_set(w, "MenuItem"); + handlers_update_theme_previews(); } void on_font_display_font_set(GtkFontButton *w, gpointer data) { - on_font_set(w, "OnScreenDisplay"); + RrFontClose(osd_font); + osd_font = on_font_set(w, "OnScreenDisplay"); + handlers_update_theme_previews(); } void on_focus_mouse_toggled(GtkToggleButton *w, gpointer data) @@ -1170,7 +1221,12 @@ void on_title_layout_changed(GtkEntry *w, gpointer data) gtk_entry_set_text(w, layout); tree_set_string("theme/titleLayout", layout); + + g_free(titlelayout); + titlelayout = g_strdup(layout); g_free(layout); + + } static void set_desktop_names() @@ -1356,3 +1412,38 @@ void handlers_install_theme(gchar *path) g_free(name); } } + + +static gboolean update_theme_preview_iterate(gpointer data) +{ + GtkListStore *ls = data; + static GtkTreeIter iter; + static gboolean restart = TRUE; + gchar *name; + + if (restart) { + if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls), &iter)) + return; + restart = FALSE; + } else { + if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(ls), &iter)) { + restart = TRUE; + return; + } + } + + gtk_tree_model_get(GTK_TREE_MODEL(ls), &iter, 0, &name, -1); + + gtk_list_store_set(GTK_LIST_STORE(ls), &iter, 1, + preview_theme(name, titlelayout, active_window_font, + inactive_window_font, menu_title_font, + menu_item_font, osd_font), + -1); +} + +static void handlers_update_theme_previews() +{ + g_idle_remove_by_data(theme_store); + g_idle_add_full(G_PRIORITY_LOW, update_theme_preview_iterate, + theme_store, NULL); +} diff --git a/src/main.c b/src/main.c index 7afa615..d0ca923 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,7 @@ GtkWidget *mainwin = NULL; GladeXML *glade; xmlDocPtr doc; xmlNodePtr root; +RrInstance *rrinst; static gchar *obc_theme_install = NULL; static gchar *obc_theme_archive = NULL; @@ -118,8 +119,6 @@ int main(int argc, char **argv) return; } - parse_paths_startup(); - p = g_build_filename(GLADEDIR, "obconf.glade", NULL); glade = glade_xml_new(p, NULL, NULL); g_free(p); @@ -130,6 +129,9 @@ int main(int argc, char **argv) return 1; } + parse_paths_startup(); + rrinst = RrInstanceNew(GDK_DISPLAY(), gdk_x11_get_default_screen()); + xmlIndentTreeOutput = 1; if (!parse_load_rc(NULL, &doc, &root)) { obconf_error("Failed to load an rc.xml. You have probably failed to " @@ -206,6 +208,7 @@ int main(int argc, char **argv) gtk_main(); + RrInstanceFree(rrinst); parse_paths_shutdown(); xmlFreeDoc(doc); diff --git a/src/main.h b/src/main.h index 7d1b119..b560e55 100644 --- a/src/main.h +++ b/src/main.h @@ -19,7 +19,9 @@ #ifndef obconf__main_h #define obconf__main_h -#include "openbox/parse.h" +#include +#include +#include #include #include @@ -27,6 +29,7 @@ extern GladeXML *glade; extern xmlDocPtr doc; extern xmlNodePtr root; +extern RrInstance *rrinst; extern GtkWidget *mainwin; void obconf_error(gchar *msg); diff --git a/src/preview.c b/src/preview.c new file mode 100644 index 0000000..8b2a47a --- /dev/null +++ b/src/preview.c @@ -0,0 +1,436 @@ +#include "theme.h" +#include "main.h" +#include "tree.h" + +#include + +#include + +#define PADDING 2 /* openbox does it :/ */ + +static void theme_pixmap_paint(RrAppearance *a, gint w, gint h) +{ + Pixmap out = RrPaintPixmap(a, w, h); + if (out) XFreePixmap(RrDisplay(a->inst), out); +} + +static guint32 rr_color_pixel(const RrColor *c) +{ + return (guint32)((RrColorRed(c) << 24) | (RrColorGreen(c) << 16) + | (RrColorBlue(c) << 8) | 255); +} + +/* 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; +} + +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, FALSE, 8, width, height); + gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_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 + 1; + 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.data = theme->def_win_icon; + + a->surface.parent = title; + a->surface.parentx = x; + 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 - 1, 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; + 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 - 1, w, h); + + x += w + theme->paddingx + 1; + } else { + /* buttons */ + switch (*layout) { + case 'D': + a = focus ? theme->a_focused_unpressed_desk : theme->a_unfocused_unpressed_desk; + break; + case 'S': + a = focus ? theme->a_focused_unpressed_shade : theme->a_unfocused_unpressed_shade; + break; + case 'I': + a = focus ? theme->a_focused_unpressed_iconify : theme->a_unfocused_unpressed_iconify; + break; + case 'M': + a = focus ? theme->a_focused_unpressed_max : theme->a_unfocused_unpressed_max; + break; + case 'C': + a = focus ? theme->a_focused_unpressed_close : theme->a_unfocused_unpressed_close; + break; + default: + continue; + } + + a->surface.parent = title; + a->surface.parentx = x; + 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); + pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, 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); + } + + /* 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, FALSE, 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); + + return pixbuf; +} + +static gint theme_label_width(RrTheme *theme, gboolean active) +{ + gint w, h; + RrAppearance *label; + + if (active) { + label = theme->a_focused_label; + label->texture[0].data.text.string = "active"; + } else { + label = theme->a_unfocused_label; + label->texture[0].data.text.string = "inactive"; + } + + return RrMinWidth(label); +} + +static gint theme_window_min_width(RrTheme *theme, const gchar *titlelayout) +{ + gint numbuttons = strlen(titlelayout); + gint w = 2 * (theme->fbwidth + theme->paddingx + 1); + + if (g_strrstr(titlelayout, "L")) { + numbuttons--; + w += MAX(theme_label_width(theme, TRUE), theme_label_width(theme, FALSE)) + theme->paddingx + 1; + } + + w += (theme->button_size + theme->paddingx + 1) * numbuttons; + + return w; +} + +GdkPixbuf *preview_theme(const gchar *name, const gchar *titlelayout, + RrFont *active_window_font, + RrFont *inactive_window_font, + RrFont *menu_title_font, + RrFont *menu_item_font, + RrFont *osd_font) +{ + + GdkPixbuf *preview; + GdkPixbuf *menu; + GdkPixbuf *window; + + gint window_w; + gint menu_w; + + gint w, h; + + RrTheme *theme = RrThemeNew(rrinst, name, + active_window_font, inactive_window_font, + menu_title_font, menu_item_font, osd_font); + + menu = preview_menu(theme); + + window_w = theme_window_min_width(theme, titlelayout); + + menu_w = gdk_pixbuf_get_width(menu); + h = gdk_pixbuf_get_height(menu); + + w = MAX(window_w, menu_w) + 20; + + preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h + 2*(theme->title_height +5) + 1); + gdk_pixbuf_fill(preview, 0); /* clear */ + + window = preview_window(theme, titlelayout, FALSE, window_w, h); + gdk_pixbuf_copy_area(window, 0, 0, window_w, h, preview, 20, 0); + + window = preview_window(theme, titlelayout, TRUE, window_w, h); + gdk_pixbuf_copy_area(window, 0, 0, window_w, h, preview, 10, theme->title_height + 5); + + gdk_pixbuf_copy_area(menu, 0, 0, menu_w, h, preview, 0, 2 * (theme->title_height + 5)); + + RrThemeFree(theme); + + return preview; +} diff --git a/src/preview.h b/src/preview.h new file mode 100644 index 0000000..defa183 --- /dev/null +++ b/src/preview.h @@ -0,0 +1,16 @@ +#ifndef obconf__preview_h +#define obconf__preview_h + +#include + +#include +#include + +GdkPixbuf *preview_theme(gchar *name, gchar *titlelayout, + RrFont *active_window_font, + RrFont *inactive_window_font, + RrFont *menu_title_font, + RrFont *menu_item_font, + RrFont *osd_font); + +#endif -- 2.34.1