Mercurial > pidgin.yaz
changeset 26664:5d71de58452c
Make it possible to load non-status icons using a PidginStockIconTheme.
For now, just chat-room emblems can be set, but adding other icons should
be trivial.
WISHLIST (Crazy/Driveby Patch Writers step forward please!):
* Move the theme-editor plugin to a subdirectory under plugins/.
* Make the 'Save' buttons work, possibly ask for some details when saving
(e.g. Author's name etc.)
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Mon, 20 Apr 2009 03:20:15 +0000 |
parents | 7519de6ea00f |
children | df0915055560 |
files | pidgin/pidginstock.c pidgin/pidginstock.h pidgin/plugins/themeedit-icon.c pidgin/plugins/themeedit.c |
diffstat | 4 files changed, 219 insertions(+), 93 deletions(-) [+] |
line wrap: on
line diff
--- a/pidgin/pidginstock.c Sun Apr 19 19:45:53 2009 +0000 +++ b/pidgin/pidginstock.c Mon Apr 20 03:20:15 2009 +0000 @@ -320,7 +320,7 @@ } static gchar * -find_icon_file(PidginStatusIconTheme *theme, const gchar *size, SizedStockIcon sized_icon, gboolean rtl) +find_icon_file(PidginIconTheme *theme, const gchar *size, SizedStockIcon sized_icon, gboolean rtl) { const gchar *file, *dir; gchar *file_full = NULL; @@ -352,7 +352,7 @@ } static void -add_sized_icon(GtkIconSet *iconset, GtkIconSize sizeid, PidginStatusIconTheme *theme, +add_sized_icon(GtkIconSet *iconset, GtkIconSize sizeid, PidginIconTheme *theme, const char *size, SizedStockIcon sized_icon, gboolean translucent) { char *filename; @@ -447,9 +447,9 @@ translucent = gtk_icon_set_new(); #define ADD_SIZED_ICON(name, size) if (sized_status_icons[i].name) { \ - add_sized_icon(normal, name, theme, size, sized_status_icons[i], FALSE); \ + add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], FALSE); \ if (sized_status_icons[i].translucent_name) \ - add_sized_icon(translucent, name, theme, size, sized_status_icons[i], TRUE); \ + add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], TRUE); \ } ADD_SIZED_ICON(microscopic, "11"); ADD_SIZED_ICON(extra_small, "16"); @@ -474,49 +474,41 @@ } void -pidgin_stock_init(void) +pidgin_stock_load_stock_icon_theme(PidginStockIconTheme *theme) { GtkIconFactory *icon_factory; - size_t i; + gint i; GtkWidget *win; - PidginIconThemeLoader *loader; - const gchar *path = NULL; - - if (stock_initted) - return; - stock_initted = TRUE; + if (theme != NULL) { + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/stock/icon-theme", + purple_theme_get_name(PURPLE_THEME(theme))); + purple_prefs_set_path(PIDGIN_PREFS_ROOT "/stock/icon-theme-dir", + purple_theme_get_dir(PURPLE_THEME(theme))); + } + else { + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/stock/icon-theme", ""); + purple_prefs_set_path(PIDGIN_PREFS_ROOT "/stock/icon-theme-dir", ""); + } - /* Setup the status icon theme */ - loader = g_object_new(PIDGIN_TYPE_ICON_THEME_LOADER, "type", "status-icon", NULL); - purple_theme_manager_register_type(PURPLE_THEME_LOADER(loader)); - purple_prefs_add_string(PIDGIN_PREFS_ROOT "/status/icon-theme", ""); - purple_prefs_add_path(PIDGIN_PREFS_ROOT "/status/icon-theme-dir", ""); - - /* Setup the icon factory. */ icon_factory = gtk_icon_factory_new(); gtk_icon_factory_add_default(icon_factory); - /* Er, yeah, a hack, but it works. :) */ win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_realize(win); /* All non-sized icons */ - for (i = 0; i < G_N_ELEMENTS(stock_icons); i++) - { + for (i = 0; i < G_N_ELEMENTS(stock_icons); i++) { GtkIconSource *source; GtkIconSet *iconset; gchar *filename; - if (stock_icons[i].dir == NULL) - { + if (stock_icons[i].dir == NULL) { /* GTK+ Stock icon */ iconset = gtk_style_lookup_icon_set(gtk_widget_get_style(win), stock_icons[i].filename); - } - else - { + } else { filename = find_file(stock_icons[i].dir, stock_icons[i].filename); if (filename == NULL) @@ -540,21 +532,13 @@ gtk_icon_set_unref(iconset); } - /* register custom icon sizes */ - microscopic = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC, 11, 11); - extra_small = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL, 16, 16); - small = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_SMALL, 22, 22); - medium = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_MEDIUM, 32, 32); - large = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_LARGE, 48, 48); - huge = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_HUGE, 64, 64); - /* All non-status sized icons */ for (i = 0; i < G_N_ELEMENTS(sized_stock_icons); i++) { GtkIconSet *iconset = gtk_icon_set_new(); #define ADD_SIZED_ICON(name, size) if (sized_stock_icons[i].name) \ - add_sized_icon(iconset, name, NULL, size, sized_stock_icons[i], FALSE); + add_sized_icon(iconset, name, PIDGIN_ICON_THEME(theme), size, sized_stock_icons[i], FALSE); ADD_SIZED_ICON(microscopic, "11"); ADD_SIZED_ICON(extra_small, "16"); ADD_SIZED_ICON(small, "22"); @@ -569,6 +553,39 @@ gtk_widget_destroy(win); g_object_unref(G_OBJECT(icon_factory)); +} + +void +pidgin_stock_init(void) +{ + PidginIconThemeLoader *loader, *stockloader; + const gchar *path = NULL; + + if (stock_initted) + return; + + stock_initted = TRUE; + + /* Setup the status icon theme */ + loader = g_object_new(PIDGIN_TYPE_ICON_THEME_LOADER, "type", "status-icon", NULL); + purple_theme_manager_register_type(PURPLE_THEME_LOADER(loader)); + purple_prefs_add_string(PIDGIN_PREFS_ROOT "/status/icon-theme", ""); + purple_prefs_add_path(PIDGIN_PREFS_ROOT "/status/icon-theme-dir", ""); + + stockloader = g_object_new(PIDGIN_TYPE_ICON_THEME_LOADER, "type", "stock-icon", NULL); + purple_theme_manager_register_type(PURPLE_THEME_LOADER(stockloader)); + purple_prefs_add_string(PIDGIN_PREFS_ROOT "/stock/icon-theme", ""); + purple_prefs_add_path(PIDGIN_PREFS_ROOT "/stock/icon-theme-dir", ""); + + /* register custom icon sizes */ + microscopic = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC, 11, 11); + extra_small = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL, 16, 16); + small = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_SMALL, 22, 22); + medium = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_MEDIUM, 32, 32); + large = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_LARGE, 48, 48); + huge = gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_HUGE, 64, 64); + + pidgin_stock_load_stock_icon_theme(NULL); /* Pre-load Status icon theme - this avoids a bug with displaying the correct icon in the tray, theme is destroyed after*/ if (purple_prefs_get_string(PIDGIN_PREFS_ROOT "/icon/status/theme") && @@ -583,3 +600,31 @@ /* Register the stock items. */ gtk_stock_add_static(stock_items, G_N_ELEMENTS(stock_items)); } + +static void +pidgin_stock_icon_theme_class_init(PidginStockIconThemeClass *klass) +{ +} + +GType +pidgin_stock_icon_theme_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (PidginStockIconThemeClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)pidgin_stock_icon_theme_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PidginStockIconTheme), + 0, /* n_preallocs */ + NULL, + NULL, /* value table */ + }; + type = g_type_register_static(PIDGIN_TYPE_ICON_THEME, + "PidginStockIconTheme", &info, 0); + } + return type; +}
--- a/pidgin/pidginstock.h Sun Apr 19 19:45:53 2009 +0000 +++ b/pidgin/pidginstock.h Mon Apr 20 03:20:15 2009 +0000 @@ -185,15 +185,54 @@ #define PIDGIN_ICON_SIZE_TANGO_HUGE "pidgin-icon-size-tango-huge" /** + * extends PidginIconTheme (gtkicon-theme.h) + * A pidgin stock icon theme. + * This object represents a Pidgin stock icon theme. + * + * PidginStockIconTheme is a PidginIconTheme Object. + */ +typedef struct _PidginStockIconTheme PidginStockIconTheme; +typedef struct _PidginStockIconThemeClass PidginStockIconThemeClass; + +#define PIDGIN_TYPE_STOCK_ICON_THEME (pidgin_stock_icon_theme_get_type ()) +#define PIDGIN_STOCK_ICON_THEME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIDGIN_TYPE_STOCK_ICON_THEME, PidginStockIconTheme)) +#define PIDGIN_STOCK_ICON_THEME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIDGIN_TYPE_STOCK_ICON_THEME, PidginStockIconThemeClass)) +#define PIDGIN_IS_STOCK_ICON_THEME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIDGIN_TYPE_STOCK_ICON_THEME)) +#define PIDGIN_IS_STOCK_ICON_THEME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIDGIN_TYPE_STOCK_ICON_THEME)) +#define PIDGIN_STOCK_ICON_THEME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIDGIN_TYPE_STOCK_ICON_THEME, PidginStockIconThemeClass)) + +struct _PidginStockIconTheme +{ + PidginIconTheme parent; +}; + +struct _PidginStockIconThemeClass +{ + PidginIconThemeClass parent_class; +}; + +G_BEGIN_DECLS + +/** + * GObject foo. + * @internal. + */ +GType pidgin_stock_icon_theme_get_type(void); + +/** * Loades all of the icons from the status icon theme into Pidgin stock * * @param theme the theme to load, or null to load all the default icons */ void pidgin_stock_load_status_icon_theme(PidginStatusIconTheme *theme); + +void pidgin_stock_load_stock_icon_theme(PidginStockIconTheme *theme); + /** * Sets up the purple stock repository. */ void pidgin_stock_init(void); +G_END_DECLS #endif /* _PIDGIN_STOCK_H_ */
--- a/pidgin/plugins/themeedit-icon.c Sun Apr 19 19:45:53 2009 +0000 +++ b/pidgin/plugins/themeedit-icon.c Mon Apr 20 03:20:15 2009 +0000 @@ -43,7 +43,7 @@ PIDGIN_ICON_SIZE_TANGO_HUGE, /* We don't have huge status icons, it seems! */ }; -static const struct { +static const struct options { const char *stockid; const char *text; } statuses[] = { @@ -52,50 +52,69 @@ {PIDGIN_STOCK_STATUS_BUSY, N_("Busy")}, {PIDGIN_STOCK_STATUS_OFFLINE, N_("Offline")}, {NULL, NULL} +}, chatemblems[] = { + {PIDGIN_STOCK_STATUS_IGNORED, N_("Ignored")}, + {PIDGIN_STOCK_STATUS_FOUNDER, N_("Founder")}, + {PIDGIN_STOCK_STATUS_OPERATOR, N_("Operator")}, + {PIDGIN_STOCK_STATUS_HALFOP, N_("Half Operator")}, + {PIDGIN_STOCK_STATUS_VOICE, N_("Voice")}, + {NULL, NULL} +}; + +static const struct { + const char *heading; + const struct options *options; +} sections[] = { + {N_("Status Icons"), statuses}, + {N_("Chatroom Embems"), chatemblems}, + {NULL, NULL} }; static PidginStatusIconTheme * create_icon_theme(GtkWidget *window) { - int i, j; + int s, i, j; char *dirname = "/tmp"; /* FIXME */ PidginStatusIconTheme *theme = g_object_new(PIDGIN_TYPE_STATUS_ICON_THEME, "type", "status-icon", "author", getlogin(), "directory", dirname, NULL); - for (i = 0; statuses[i].stockid; i++) { - GtkWidget *image = g_object_get_data(G_OBJECT(window), statuses[i].stockid); - GdkPixbuf *pixbuf = g_object_get_data(G_OBJECT(image), "pixbuf"); - if (!pixbuf) - continue; - pidgin_icon_theme_set_icon(PIDGIN_ICON_THEME(theme), statuses[i].stockid, - statuses[i].stockid); - for (j = 0; stocksizes[j]; j++) { - int width, height; - GtkIconSize iconsize; - char size[8]; - char *name; - GdkPixbuf *scale; - GError *error = NULL; + for (s = 0; sections[s].heading; s++) { + GtkWidget *vbox = g_object_get_data(G_OBJECT(window), sections[s].heading); + for (i = 0; sections[s].options[i].stockid; i++) { + GtkWidget *image = g_object_get_data(G_OBJECT(vbox), sections[s].options[i].stockid); + GdkPixbuf *pixbuf = g_object_get_data(G_OBJECT(image), "pixbuf"); + if (!pixbuf) + continue; + pidgin_icon_theme_set_icon(PIDGIN_ICON_THEME(theme), sections[s].options[i].stockid, + sections[s].options[i].stockid); + for (j = 0; stocksizes[j]; j++) { + int width, height; + GtkIconSize iconsize; + char size[8]; + char *name; + GdkPixbuf *scale; + GError *error = NULL; - iconsize = gtk_icon_size_from_name(stocksizes[j]); - gtk_icon_size_lookup(iconsize, &width, &height); - g_snprintf(size, sizeof(size), "%d", width); + iconsize = gtk_icon_size_from_name(stocksizes[j]); + gtk_icon_size_lookup(iconsize, &width, &height); + g_snprintf(size, sizeof(size), "%d", width); - if (i == 0) { - name = g_build_filename(dirname, size, NULL); - purple_build_dir(name, S_IRUSR | S_IWUSR | S_IXUSR); + if (i == 0) { + name = g_build_filename(dirname, size, NULL); + purple_build_dir(name, S_IRUSR | S_IWUSR | S_IXUSR); + g_free(name); + } + + name = g_build_filename(dirname, size, sections[s].options[i].stockid, NULL); + scale = gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR); + gdk_pixbuf_save(scale, name, "png", &error, "compression", "9", NULL); g_free(name); + g_object_unref(G_OBJECT(scale)); + if (error) + g_error_free(error); } - - name = g_build_filename(dirname, size, statuses[i].stockid, NULL); - scale = gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR); - gdk_pixbuf_save(scale, name, "png", &error, "compression", "9", NULL); - g_free(name); - g_object_unref(G_OBJECT(scale)); - if (error) - g_error_free(error); } } return theme; @@ -104,8 +123,21 @@ static void use_icon_theme(GtkWidget *w, GtkWidget *window) { + /* I don't quite understand the icon-theme stuff. For example, I don't + * know why PidginIconTheme needs to be abstract, or how PidginStatusIconTheme + * would be different from other PidginIconTheme's (e.g. PidginStockIconTheme) + * etc., but anyway, this works for now. + * + * Here's an interesting note: A PidginStatusIconTheme can be used for both + * stock and status icons. Like I said, I don't quite know how they could be + * different. So I am going to just keep it as it is, for now anyway, until I + * have the time to dig through this, or someone explains this stuff to me + * clearly. + * -- Sad + */ PidginStatusIconTheme *theme = create_icon_theme(window); pidgin_stock_load_status_icon_theme(PIDGIN_STATUS_ICON_THEME(theme)); + pidgin_stock_load_stock_icon_theme((PidginStockIconTheme *)theme); pidgin_blist_refresh(purple_get_blist()); g_object_unref(theme); } @@ -123,8 +155,12 @@ GError *error = NULL; GdkPixbuf *scale; int i; - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, &error); + GdkPixbuf *pixbuf; + if (!filename) + return; + + pixbuf = gdk_pixbuf_new_from_file(filename, &error); if (error || !pixbuf) { purple_debug_error("theme-editor-icon", "Unable to load icon file '%s' (%s)\n", filename, error ? error->message : "Reason unknown"); @@ -171,41 +207,47 @@ GtkWidget *dialog; GtkWidget *box, *vbox; GtkSizeGroup *sizegroup; - int i, j; + int s, i, j; dialog = pidgin_create_dialog(_("Pidgin Icon Theme Editor"), 0, "theme-editor-icon", FALSE); box = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(dialog), FALSE, PIDGIN_HIG_BOX_SPACE); - vbox = pidgin_make_frame(box, _("Status Icons")); sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - for (i = 0; statuses[i].stockid; i++) { - const char *id = statuses[i].stockid; - const char *text = _(statuses[i].text); + for (s = 0; sections[s].heading; s++) { + const char *heading = sections[s].heading; + + vbox = pidgin_make_frame(box, heading); + g_object_set_data(G_OBJECT(dialog), heading, vbox); - GtkWidget *hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); - GtkWidget *label = gtk_label_new(text); - GtkWidget *image = gtk_image_new_from_stock(id, - gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL)); - GtkWidget *ebox = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(ebox), image); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + for (i = 0; sections[s].options[i].stockid; i++) { + const char *id = sections[s].options[i].stockid; + const char *text = _(sections[s].options[i].text); + + GtkWidget *hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); + GtkWidget *label = gtk_label_new(text); + GtkWidget *image = gtk_image_new_from_stock(id, + gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL)); + GtkWidget *ebox = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(ebox), image); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - g_signal_connect(G_OBJECT(ebox), "button-press-event", G_CALLBACK(change_stock_image), image); - g_object_set_data(G_OBJECT(image), "property-name", (gpointer)id); + g_signal_connect(G_OBJECT(ebox), "button-press-event", G_CALLBACK(change_stock_image), image); + g_object_set_data(G_OBJECT(image), "property-name", (gpointer)id); - gtk_size_group_add_widget(sizegroup, label); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), ebox, FALSE, FALSE, 0); + gtk_size_group_add_widget(sizegroup, label); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ebox, FALSE, FALSE, 0); - for (j = 0; stocksizes[j]; j++) { - GtkWidget *sh = gtk_image_new_from_stock(id, gtk_icon_size_from_name(stocksizes[j])); - gtk_box_pack_start(GTK_BOX(hbox), sh, FALSE, FALSE, 0); - g_object_set_data(G_OBJECT(image), stocksizes[j], sh); + for (j = 0; stocksizes[j]; j++) { + GtkWidget *sh = gtk_image_new_from_stock(id, gtk_icon_size_from_name(stocksizes[j])); + gtk_box_pack_start(GTK_BOX(hbox), sh, FALSE, FALSE, 0); + g_object_set_data(G_OBJECT(image), stocksizes[j], sh); + } + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + g_object_set_data(G_OBJECT(vbox), id, image); } - - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - g_object_set_data(G_OBJECT(dialog), id, image); } gtk_dialog_set_has_separator(GTK_DIALOG(dialog), TRUE);
--- a/pidgin/plugins/themeedit.c Sun Apr 19 19:45:53 2009 +0000 +++ b/pidgin/plugins/themeedit.c Mon Apr 20 03:20:15 2009 +0000 @@ -299,7 +299,7 @@ act = purple_plugin_action_new(_("Edit Buddylist Theme"), pidgin_blist_theme_edit); l = g_list_append(l, act); - act = purple_plugin_action_new(_("Edit Status Icon Theme"), pidgin_icon_theme_edit); + act = purple_plugin_action_new(_("Edit Icon Theme"), pidgin_icon_theme_edit); l = g_list_append(l, act); return l;