comparison pidgin/gtkblist.c @ 25780:6ebabe0841a0

propagate from branch 'im.pidgin.pidgin' (head 06e4830f3567955e026f3d594afcc65a07d57b26) to branch 'im.pidgin.pidgin.next.minor' (head 22a0659074cef317fb0f96d98d9628d193dd224d)
author Gary Kramlich <grim@reaperworld.com>
date Thu, 30 Oct 2008 03:03:55 +0000
parents aa8ddc4e12af 5da76be14fdd
children e679c14e83b3
comparison
equal deleted inserted replaced
24330:882a1c4c11b4 25780:6ebabe0841a0
36 #include "prefs.h" 36 #include "prefs.h"
37 #include "plugin.h" 37 #include "plugin.h"
38 #include "request.h" 38 #include "request.h"
39 #include "signals.h" 39 #include "signals.h"
40 #include "pidginstock.h" 40 #include "pidginstock.h"
41 #include "theme-loader.h"
42 #include "theme-manager.h"
41 #include "util.h" 43 #include "util.h"
42 44
43 #include "gtkaccount.h" 45 #include "gtkaccount.h"
44 #include "gtkblist.h" 46 #include "gtkblist.h"
45 #include "gtkcellrendererexpander.h" 47 #include "gtkcellrendererexpander.h"
56 #include "gtkprivacy.h" 58 #include "gtkprivacy.h"
57 #include "gtkroomlist.h" 59 #include "gtkroomlist.h"
58 #include "gtkstatusbox.h" 60 #include "gtkstatusbox.h"
59 #include "gtkscrollbook.h" 61 #include "gtkscrollbook.h"
60 #include "gtksmiley.h" 62 #include "gtksmiley.h"
63 #include "gtkblist-theme-loader.h"
64 #include "gtkblist-theme.h"
61 #include "gtkutils.h" 65 #include "gtkutils.h"
62 #include "pidgin/minidialog.h" 66 #include "pidgin/minidialog.h"
63 #include "pidgin/pidgintooltip.h" 67 #include "pidgin/pidgintooltip.h"
64 68
65 #include <gdk/gdkkeysyms.h> 69 #include <gdk/gdkkeysyms.h>
119 123
120 /** Pointer to the mini-dialog about having signed on elsewhere, if one 124 /** Pointer to the mini-dialog about having signed on elsewhere, if one
121 * is showing; @c NULL otherwise. 125 * is showing; @c NULL otherwise.
122 */ 126 */
123 PidginMiniDialog *signed_on_elsewhere; 127 PidginMiniDialog *signed_on_elsewhere;
128
129 PidginBlistTheme *current_theme;
130
124 } PidginBuddyListPrivate; 131 } PidginBuddyListPrivate;
125 132
126 #define PIDGIN_BUDDY_LIST_GET_PRIVATE(list) \ 133 #define PIDGIN_BUDDY_LIST_GET_PRIVATE(list) \
127 ((PidginBuddyListPrivate *)((list)->priv)) 134 ((PidginBuddyListPrivate *)((list)->priv))
128 135
1788 } 1795 }
1789 1796
1790 return handled; 1797 return handled;
1791 } 1798 }
1792 1799
1793 static gboolean gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer user_data) 1800 static gboolean
1801 gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer user_data)
1794 { 1802 {
1795 GtkTreePath *path; 1803 GtkTreePath *path;
1796 PurpleBlistNode *node; 1804 PurpleBlistNode *node;
1797 GValue val; 1805 GValue val;
1798 GtkTreeIter iter; 1806 GtkTreeIter iter;
3774 ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), icon, 3782 ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), icon,
3775 icon_size, "GtkTreeView"); 3783 icon_size, "GtkTreeView");
3776 return ret; 3784 return ret;
3777 } 3785 }
3778 3786
3779 gchar *pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected, gboolean aliased) 3787 gchar *
3780 { 3788 pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected, gboolean aliased)
3781 const char *name; 3789 {
3782 char *esc, *text = NULL; 3790 const char *name, *name_color, *name_font, *status_color, *status_font;
3791 char *text = NULL;
3783 PurplePlugin *prpl; 3792 PurplePlugin *prpl;
3784 PurplePluginProtocolInfo *prpl_info = NULL; 3793 PurplePluginProtocolInfo *prpl_info = NULL;
3785 PurpleContact *contact; 3794 PurpleContact *contact;
3786 PurplePresence *presence; 3795 PurplePresence *presence;
3787 struct _pidgin_blist_node *gtkcontactnode = NULL; 3796 struct _pidgin_blist_node *gtkcontactnode = NULL;
3788 char *idletime = NULL, *statustext = NULL; 3797 char *idletime = NULL, *statustext = NULL, *nametext = NULL;
3789 time_t t;
3790 PurpleConversation *conv = find_conversation_with_buddy(b); 3798 PurpleConversation *conv = find_conversation_with_buddy(b);
3791 gboolean hidden_conv = FALSE; 3799 gboolean hidden_conv = FALSE;
3800 gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
3801 FontColorPair *pair;
3802 PidginBlistTheme *theme;
3792 3803
3793 if (conv != NULL) { 3804 if (conv != NULL) {
3794 PidginBlistNode *ui = b->node.ui_data; 3805 PidginBlistNode *ui = b->node.ui_data;
3795 if (ui) { 3806 if (ui) {
3796 if (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE) 3807 if (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE)
3804 /* XXX Good luck cleaning up this crap */ 3815 /* XXX Good luck cleaning up this crap */
3805 contact = (PurpleContact*)((PurpleBlistNode*)b)->parent; 3816 contact = (PurpleContact*)((PurpleBlistNode*)b)->parent;
3806 if(contact) 3817 if(contact)
3807 gtkcontactnode = ((PurpleBlistNode*)contact)->ui_data; 3818 gtkcontactnode = ((PurpleBlistNode*)contact)->ui_data;
3808 3819
3809 if(gtkcontactnode && !gtkcontactnode->contact_expanded && contact->alias) 3820 /* Name */
3821 if (gtkcontactnode && !gtkcontactnode->contact_expanded && contact->alias)
3810 name = contact->alias; 3822 name = contact->alias;
3811 else 3823 else
3812 name = purple_buddy_get_alias(b); 3824 name = purple_buddy_get_alias(b);
3813 3825
3814 esc = g_markup_escape_text(name, strlen(name)); 3826 nametext = g_markup_escape_text(name, strlen(name));
3815 3827
3816 presence = purple_buddy_get_presence(b); 3828 presence = purple_buddy_get_presence(b);
3817 3829
3818 if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons") && aliased) 3830 /* Name is all that is needed */
3819 { 3831 if (aliased && biglist) {
3820 if (!selected && purple_presence_is_idle(presence)) 3832
3821 { 3833 /* Status Info */
3822 text = g_strdup_printf("<span color='%s'>%s</span>", 3834 prpl = purple_find_prpl(purple_account_get_protocol_id(b->account));
3823 dim_grey(), esc); 3835
3824 g_free(esc); 3836 if (prpl != NULL)
3825 if (hidden_conv) { 3837 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
3826 char *tmp = text; 3838
3827 text = g_strdup_printf("<b>%s</b>", text); 3839 if (prpl_info && prpl_info->status_text && b->account->gc) {
3840 char *tmp = prpl_info->status_text(b);
3841 const char *end;
3842
3843 if(tmp && !g_utf8_validate(tmp, -1, &end)) {
3844 char *new = g_strndup(tmp,
3845 g_utf8_pointer_to_offset(tmp, end));
3846 g_free(tmp);
3847 tmp = new;
3848 }
3849 /* add ... to messages that are too long, GTK 2.6+ does it automatically */
3850 #if !GTK_CHECK_VERSION(2,6,0)
3851 if(tmp) {
3852 char buf[32];
3853 char *c = tmp;
3854 int length = 0, vis=0;
3855 gboolean inside = FALSE;
3856 g_strdelimit(tmp, "\n", ' ');
3857 purple_str_strip_char(tmp, '\r');
3858
3859 while(*c && vis < 20) {
3860 if(*c == '&')
3861 inside = TRUE;
3862 else if(*c == ';')
3863 inside = FALSE;
3864 if(!inside)
3865 vis++;
3866 c = g_utf8_next_char(c); /* this is fun */
3867 }
3868
3869 length = c - tmp;
3870
3871 if(vis == 20)
3872 g_snprintf(buf, sizeof(buf), "%%.%ds...", length);
3873 else
3874 g_snprintf(buf, sizeof(buf), "%%s ");
3875
3876 statustext = g_strdup_printf(buf, tmp);purple_presence_is_idle(presence)
3877
3828 g_free(tmp); 3878 g_free(tmp);
3829 } 3879 }
3830 return text; 3880 #else
3831 } 3881 if(tmp) {
3832 else if (hidden_conv) 3882 g_strdelimit(tmp, "\n", ' ');
3833 { 3883 purple_str_strip_char(tmp, '\r');
3834 char *tmp = esc;
3835 esc = g_strdup_printf("<b>%s</b>", esc);
3836 g_free(tmp);
3837 }
3838 return esc;
3839 }
3840
3841 prpl = purple_find_prpl(purple_account_get_protocol_id(b->account));
3842
3843 if (prpl != NULL)
3844 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
3845
3846 if (prpl_info && prpl_info->status_text && b->account->gc) {
3847 char *tmp = prpl_info->status_text(b);
3848 const char *end;
3849
3850 if(tmp && !g_utf8_validate(tmp, -1, &end)) {
3851 char *new = g_strndup(tmp,
3852 g_utf8_pointer_to_offset(tmp, end));
3853 g_free(tmp);
3854 tmp = new;
3855 }
3856
3857 #if !GTK_CHECK_VERSION(2,6,0)
3858 if(tmp) {
3859 char buf[32];
3860 char *c = tmp;
3861 int length = 0, vis=0;
3862 gboolean inside = FALSE;
3863 g_strdelimit(tmp, "\n", ' ');
3864 purple_str_strip_char(tmp, '\r');
3865
3866 while(*c && vis < 20) {
3867 if(*c == '&')
3868 inside = TRUE;
3869 else if(*c == ';')
3870 inside = FALSE;
3871 if(!inside)
3872 vis++;
3873 c = g_utf8_next_char(c); /* this is fun */
3874 } 3884 }
3875 3885 statustext = tmp;
3876 length = c - tmp; 3886 #endif
3877 3887 }
3878 if(vis == 20) 3888
3879 g_snprintf(buf, sizeof(buf), "%%.%ds...", length); 3889 if(!purple_presence_is_online(presence) && !statustext)
3880 else 3890 statustext = g_strdup(_("Offline"));
3881 g_snprintf(buf, sizeof(buf), "%%s "); 3891
3882 3892 /* Idle Text */
3883 statustext = g_strdup_printf(buf, tmp); 3893 if (purple_presence_is_idle(presence) && purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time")) {
3884
3885 g_free(tmp);
3886 }
3887 #else
3888 if(tmp) {
3889 g_strdelimit(tmp, "\n", ' ');
3890 purple_str_strip_char(tmp, '\r');
3891 }
3892 statustext = tmp;
3893 #endif
3894 }
3895
3896 if(!purple_presence_is_online(presence) && !statustext)
3897 statustext = g_strdup(_("Offline"));
3898 else if (!statustext)
3899 text = g_strdup(esc);
3900
3901 if (purple_presence_is_idle(presence)) {
3902 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time")) {
3903 time_t idle_secs = purple_presence_get_idle_time(presence); 3894 time_t idle_secs = purple_presence_get_idle_time(presence);
3904 3895
3905 if (idle_secs > 0) { 3896 if (idle_secs > 0) {
3906 int iday, ihrs, imin; 3897 int iday, ihrs, imin;
3898 time_t t;
3907 3899
3908 time(&t); 3900 time(&t);
3909 iday = (t - idle_secs) / (24 * 60 * 60); 3901 iday = (t - idle_secs) / (24 * 60 * 60);
3910 ihrs = ((t - idle_secs) / 60 / 60) % 24; 3902 ihrs = ((t - idle_secs) / 60 / 60) % 24;
3911 imin = ((t - idle_secs) / 60) % 60; 3903 imin = ((t - idle_secs) / 60) % 60;
3912 3904
3913 if (iday) 3905 if (iday)
3914 idletime = g_strdup_printf(_("Idle %dd %dh %02dm"), iday, ihrs, imin); 3906 idletime = g_strdup_printf(_("Idle %dd %dh %02dm"), iday, ihrs, imin);
3915 else if (ihrs) 3907 else if (ihrs)
3916 idletime = g_strdup_printf(_("Idle %dh %02dm"), ihrs, imin); 3908 idletime = g_strdup_printf(_("Idle %dh %02dm"), ihrs, imin);
3917 else 3909 else
3918 idletime = g_strdup_printf(_("Idle %dm"), imin); 3910 idletime = g_strdup_printf(_("Idle %dm"), imin);
3919 } 3911
3920 else 3912 } else idletime = g_strdup(_("Idle"));
3921 idletime = g_strdup(_("Idle")); 3913 }
3922 3914 }
3923 if (!selected) { 3915
3924 g_free(text); 3916 /* choose the colors of the text */
3925 text = g_strdup_printf("<span color='%s'>%s</span>\n" 3917 theme = pidgin_blist_get_theme();
3926 "<span color='%s' size='smaller'>%s%s%s</span>", 3918
3927 dim_grey(), esc, dim_grey(), 3919 if (theme == NULL) {
3920 status_color = name_color = "dim grey";
3921 status_font = name_font = "";
3922
3923 } else if (purple_presence_is_idle(presence)) {
3924 pair = pidgin_blist_theme_get_idle_text_info(theme);
3925 status_color = name_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
3926 status_font = name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
3927
3928 } else if (!purple_presence_is_online(presence)) {
3929 pair = pidgin_blist_theme_get_offline_text_info(theme);
3930 name_color = (pair != NULL && pair->color != NULL) ? pair->color : "black";
3931 name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
3932
3933 pair = pidgin_blist_theme_get_status_text_info(theme);
3934 status_color = (pair != NULL && pair->color != NULL) ? g_strdup(pair->color) : "dim grey";
3935 status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
3936
3937 } else if (purple_presence_is_available(presence)) {
3938 pair = pidgin_blist_theme_get_online_text_info(theme);
3939 name_color = (pair != NULL && pair->color != NULL) ? g_strdup(pair->color) : "black";
3940 name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
3941
3942 pair = pidgin_blist_theme_get_status_text_info(theme);
3943 status_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
3944 status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
3945
3946 } else {
3947 pair = pidgin_blist_theme_get_away_text_info(theme);
3948 name_color = (pair != NULL && pair->color != NULL) ? pair->color : "black";
3949 name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
3950
3951 pair = pidgin_blist_theme_get_status_text_info(theme);
3952 status_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
3953 status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
3954 }
3955
3956 if (aliased && selected) {
3957 name_color = "black";
3958 status_color = "black";
3959 }
3960
3961 /* Put it all together */
3962 if (aliased && biglist && (statustext || idletime)) {
3963 /* using <span size='smaller'> breaks the status, so it must be seperated into <small><span>*/
3964 text = g_strdup_printf("<span font_desc='%s' foreground='%s'>%s</span>\n"
3965 "<small><span font_desc='%s' foreground='%s'>%s%s%s</span></small>",
3966 name_font, name_color, nametext, status_font, status_color,
3928 idletime != NULL ? idletime : "", 3967 idletime != NULL ? idletime : "",
3929 (idletime != NULL && statustext != NULL) ? " - " : "", 3968 (idletime != NULL && statustext != NULL) ? " - " : "",
3930 statustext != NULL ? statustext : ""); 3969 statustext != NULL ? statustext : "");
3931 } 3970
3932 } 3971 } else text = g_strdup_printf("<span font_desc='%s' color='%s'>%s</span>", name_font, name_color, nametext);
3933 else if (!selected && !statustext) {/* We handle selected text later */ 3972
3934 g_free(text); 3973 g_free(nametext);
3935 text = g_strdup_printf("<span color='%s'>%s</span>", dim_grey(), esc); 3974 if (statustext)
3936 } else if (!selected && !text) { 3975 g_free(statustext);
3937 g_free(text); 3976 if (idletime)
3938 text = g_strdup_printf("<span color='%s'>%s</span>\n" 3977 g_free(idletime);
3939 "<span color='%s' size='smaller'>%s</span>",
3940 dim_grey(), esc, dim_grey(),
3941 statustext != NULL ? statustext : "");
3942 }
3943 } else if (!PURPLE_BUDDY_IS_ONLINE(b)) {
3944 if (!selected && !statustext) {/* We handle selected text later */
3945 g_free(text);
3946 text = g_strdup_printf("<span color='%s'>%s</span>", dim_grey(), esc);
3947 } else if (!selected && !text)
3948 text = g_strdup_printf("<span color='%s'>%s</span>\n"
3949 "<span color='%s' size='smaller'>%s</span>",
3950 dim_grey(), esc, dim_grey(),
3951 statustext != NULL ? statustext : "");
3952
3953 }
3954 /* Not idle and not selected */
3955 else if (!selected && !text)
3956 {
3957 text = g_strdup_printf("%s\n"
3958 "<span color='%s' size='smaller'>%s</span>",
3959 esc, dim_grey(),
3960 statustext != NULL ? statustext : "");
3961 }
3962
3963 /* It is selected. */
3964 if ((selected && !text) || (selected && idletime)) {
3965 g_free(text);
3966 text = g_strdup_printf("%s\n"
3967 "<span size='smaller'>%s%s%s</span>",
3968 esc,
3969 idletime != NULL ? idletime : "",
3970 (idletime != NULL && statustext != NULL) ? " - " : "",
3971 statustext != NULL ? statustext : "");
3972 }
3973
3974 g_free(idletime);
3975 g_free(statustext);
3976 g_free(esc);
3977 3978
3978 if (hidden_conv) { 3979 if (hidden_conv) {
3979 char *tmp = text; 3980 char *tmp = text;
3980 text = g_strdup_printf("<b>%s</b>", tmp); 3981 text = g_strdup_printf("<b>%s</b>", tmp);
3981 g_free(tmp); 3982 g_free(tmp);
5217 gtk_widget_show_all(ret); 5218 gtk_widget_show_all(ret);
5218 return ret; 5219 return ret;
5219 } 5220 }
5220 #endif 5221 #endif
5221 5222
5223 /* builds the blist layout according to to the current theme */
5224 static void
5225 pidgin_blist_build_layout(PurpleBuddyList *list)
5226 {
5227 GtkTreeViewColumn *column;
5228 PidginBlistLayout *layout;
5229 PidginBlistTheme *theme;
5230 GtkCellRenderer *rend;
5231 gint i, status_icon = 0, text = 1, emblem = 2, protocol_icon = 3, buddy_icon = 4;
5232
5233
5234 column = gtkblist->text_column;
5235
5236 if ((theme = pidgin_blist_get_theme()) != NULL && (layout = pidgin_blist_theme_get_layout(theme)) != NULL) {
5237 status_icon = layout->status_icon ;
5238 text = layout->text;
5239 emblem = layout->emblem;
5240 protocol_icon = layout->protocol_icon;
5241 buddy_icon = layout->buddy_icon;
5242 }
5243
5244 gtk_tree_view_column_clear(column);
5245
5246 /* group */
5247 rend = pidgin_cell_renderer_expander_new();
5248 gtk_tree_view_column_pack_start(column, rend, FALSE);
5249 gtk_tree_view_column_set_attributes(column, rend,
5250 "visible", GROUP_EXPANDER_VISIBLE_COLUMN,
5251 "expander-visible", GROUP_EXPANDER_COLUMN,
5252 #if GTK_CHECK_VERSION(2,6,0)
5253 "sensitive", GROUP_EXPANDER_COLUMN,
5254 "cell-background-gdk", BGCOLOR_COLUMN,
5255 #endif
5256 NULL);
5257
5258 /* contact */
5259 rend = pidgin_cell_renderer_expander_new();
5260 gtk_tree_view_column_pack_start(column, rend, FALSE);
5261 gtk_tree_view_column_set_attributes(column, rend,
5262 "visible", CONTACT_EXPANDER_VISIBLE_COLUMN,
5263 "expander-visible", CONTACT_EXPANDER_COLUMN,
5264 #if GTK_CHECK_VERSION(2,6,0)
5265 "sensitive", CONTACT_EXPANDER_COLUMN,
5266 "cell-background-gdk", BGCOLOR_COLUMN,
5267 #endif
5268 NULL);
5269
5270 for (i = 0; i < 5; i++) {
5271
5272 if (status_icon == i) {
5273 /* status icons */
5274 rend = gtk_cell_renderer_pixbuf_new();
5275 gtk_tree_view_column_pack_start(column, rend, FALSE);
5276 gtk_tree_view_column_set_attributes(column, rend,
5277 "pixbuf", STATUS_ICON_COLUMN,
5278 "visible", STATUS_ICON_VISIBLE_COLUMN,
5279 #if GTK_CHECK_VERSION(2,6,0)
5280 "cell-background-gdk", BGCOLOR_COLUMN,
5281 #endif
5282 NULL);
5283 g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
5284
5285 } else if (text == i) {
5286 /* name */
5287 gtkblist->text_rend = rend = gtk_cell_renderer_text_new();
5288 gtk_tree_view_column_pack_start(column, rend, TRUE);
5289 gtk_tree_view_column_set_attributes(column, rend,
5290 #if GTK_CHECK_VERSION(2,6,0)
5291 "cell-background-gdk", BGCOLOR_COLUMN,
5292 #endif
5293 "markup", NAME_COLUMN,
5294 NULL);
5295 #if GTK_CHECK_VERSION(2,6,0)
5296 g_signal_connect(G_OBJECT(rend), "editing-started", G_CALLBACK(gtk_blist_renderer_editing_started_cb), NULL);
5297 g_signal_connect(G_OBJECT(rend), "editing-canceled", G_CALLBACK(gtk_blist_renderer_editing_cancelled_cb), list);
5298 #endif
5299 g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), list);
5300 g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL);
5301 #if GTK_CHECK_VERSION(2,6,0)
5302 g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
5303 #endif
5304
5305 /* idle */
5306 rend = gtk_cell_renderer_text_new();
5307 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
5308 gtk_tree_view_column_pack_start(column, rend, FALSE);
5309 gtk_tree_view_column_set_attributes(column, rend,
5310 "markup", IDLE_COLUMN,
5311 "visible", IDLE_VISIBLE_COLUMN,
5312 #if GTK_CHECK_VERSION(2,6,0)
5313 "cell-background-gdk", BGCOLOR_COLUMN,
5314 #endif
5315 NULL);
5316 } else if (emblem == i) {
5317 /* emblem */
5318 rend = gtk_cell_renderer_pixbuf_new();
5319 g_object_set(rend, "xalign", 1.0, "yalign", 0.5, "ypad", 0, "xpad", 3, NULL);
5320 gtk_tree_view_column_pack_start(column, rend, FALSE);
5321 gtk_tree_view_column_set_attributes(column, rend, "pixbuf", EMBLEM_COLUMN,
5322 #if GTK_CHECK_VERSION(2,6,0)
5323 "cell-background-gdk", BGCOLOR_COLUMN,
5324 #endif
5325 "visible", EMBLEM_VISIBLE_COLUMN, NULL);
5326
5327 } else if (protocol_icon == i) {
5328 /* protocol icon */
5329 rend = gtk_cell_renderer_pixbuf_new();
5330 gtk_tree_view_column_pack_start(column, rend, FALSE);
5331 gtk_tree_view_column_set_attributes(column, rend,
5332 "pixbuf", PROTOCOL_ICON_COLUMN,
5333 "visible", PROTOCOL_ICON_VISIBLE_COLUMN,
5334 #if GTK_CHECK_VERSION(2,6,0)
5335 "cell-background-gdk", BGCOLOR_COLUMN,
5336 #endif
5337 NULL);
5338 g_object_set(rend, "xalign", 0.0, "xpad", 3, "ypad", 0, NULL);
5339
5340 } else if (buddy_icon == i) {
5341 /* buddy icon */
5342 rend = gtk_cell_renderer_pixbuf_new();
5343 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
5344 gtk_tree_view_column_pack_start(column, rend, FALSE);
5345 gtk_tree_view_column_set_attributes(column, rend, "pixbuf", BUDDY_ICON_COLUMN,
5346 #if GTK_CHECK_VERSION(2,6,0)
5347 "cell-background-gdk", BGCOLOR_COLUMN,
5348 #endif
5349 "visible", BUDDY_ICON_VISIBLE_COLUMN,
5350 NULL);
5351 }
5352
5353 }/* end for loop */
5354
5355 }
5356
5222 static void pidgin_blist_show(PurpleBuddyList *list) 5357 static void pidgin_blist_show(PurpleBuddyList *list)
5223 { 5358 {
5224 PidginBuddyListPrivate *priv; 5359 PidginBuddyListPrivate *priv;
5225 void *handle; 5360 void *handle;
5226 GtkCellRenderer *rend;
5227 GtkTreeViewColumn *column; 5361 GtkTreeViewColumn *column;
5228 GtkWidget *menu; 5362 GtkWidget *menu;
5229 GtkWidget *ebox; 5363 GtkWidget *ebox;
5230 GtkWidget *sw; 5364 GtkWidget *sw;
5231 GtkWidget *sep; 5365 GtkWidget *sep;
5247 } 5381 }
5248 5382
5249 gtkblist = PIDGIN_BLIST(list); 5383 gtkblist = PIDGIN_BLIST(list);
5250 priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); 5384 priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
5251 5385
5386 priv->current_theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"), "blist"));
5387
5252 gtkblist->empty_avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32); 5388 gtkblist->empty_avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
5253 gdk_pixbuf_fill(gtkblist->empty_avatar, 0x00000000); 5389 gdk_pixbuf_fill(gtkblist->empty_avatar, 0x00000000);
5254 5390
5255 gtkblist->window = pidgin_create_window(_("Buddy List"), 0, "buddy_list", TRUE); 5391 gtkblist->window = pidgin_create_window(_("Buddy List"), 0, "buddy_list", TRUE);
5256 g_signal_connect(G_OBJECT(gtkblist->window), "focus-in-event", 5392 g_signal_connect(G_OBJECT(gtkblist->window), "focus-in-event",
5279 (GtkTranslateFunc)item_factory_translate_func, 5415 (GtkTranslateFunc)item_factory_translate_func,
5280 NULL, NULL); 5416 NULL, NULL);
5281 gtk_item_factory_create_items(gtkblist->ift, sizeof(blist_menu) / sizeof(*blist_menu), 5417 gtk_item_factory_create_items(gtkblist->ift, sizeof(blist_menu) / sizeof(*blist_menu),
5282 blist_menu, NULL); 5418 blist_menu, NULL);
5283 pidgin_load_accels(); 5419 pidgin_load_accels();
5284 g_signal_connect(G_OBJECT(accel_group), "accel-changed", 5420 g_signal_connect(G_OBJECT(accel_group), "accel-changed", G_CALLBACK(pidgin_save_accels_cb), NULL);
5285 G_CALLBACK(pidgin_save_accels_cb), NULL); 5421
5286 menu = gtk_item_factory_get_widget(gtkblist->ift, "<PurpleMain>"); 5422 menu = gtk_item_factory_get_widget(gtkblist->ift, "<PurpleMain>");
5287 gtkblist->menutray = pidgin_menu_tray_new(); 5423 gtkblist->menutray = pidgin_menu_tray_new();
5288 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtkblist->menutray); 5424 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtkblist->menutray);
5289 gtk_widget_show(gtkblist->menutray); 5425 gtk_widget_show(gtkblist->menutray);
5290 gtk_widget_show(menu); 5426 gtk_widget_show(menu);
5430 pidgin_blist_create_tooltip, 5566 pidgin_blist_create_tooltip,
5431 pidgin_blist_paint_tip); 5567 pidgin_blist_paint_tip);
5432 5568
5433 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE); 5569 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE);
5434 5570
5571 /* expander columns */
5435 column = gtk_tree_view_column_new(); 5572 column = gtk_tree_view_column_new();
5436 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); 5573 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
5437 gtk_tree_view_column_set_visible(column, FALSE); 5574 gtk_tree_view_column_set_visible(column, FALSE);
5438 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(gtkblist->treeview), column); 5575 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(gtkblist->treeview), column);
5439 5576
5440 gtkblist->text_column = column = gtk_tree_view_column_new (); 5577 /* everything else column */
5441 rend = pidgin_cell_renderer_expander_new(); 5578 gtkblist->text_column = gtk_tree_view_column_new ();
5442 gtk_tree_view_column_pack_start(column, rend, FALSE); 5579 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->text_column);
5443 gtk_tree_view_column_set_attributes(column, rend, 5580 pidgin_blist_build_layout(list);
5444 "visible", GROUP_EXPANDER_VISIBLE_COLUMN,
5445 "expander-visible", GROUP_EXPANDER_COLUMN,
5446 #if GTK_CHECK_VERSION(2,6,0)
5447 "sensitive", GROUP_EXPANDER_COLUMN,
5448 "cell-background-gdk", BGCOLOR_COLUMN,
5449 #endif
5450 NULL);
5451
5452 rend = pidgin_cell_renderer_expander_new();
5453 gtk_tree_view_column_pack_start(column, rend, FALSE);
5454 gtk_tree_view_column_set_attributes(column, rend,
5455 "expander-visible", CONTACT_EXPANDER_COLUMN,
5456 #if GTK_CHECK_VERSION(2,6,0)
5457 "sensitive", CONTACT_EXPANDER_COLUMN,
5458 "cell-background-gdk", BGCOLOR_COLUMN,
5459 #endif
5460 "visible", CONTACT_EXPANDER_VISIBLE_COLUMN,
5461 NULL);
5462
5463 rend = gtk_cell_renderer_pixbuf_new();
5464 gtk_tree_view_column_pack_start(column, rend, FALSE);
5465 gtk_tree_view_column_set_attributes(column, rend,
5466 "pixbuf", STATUS_ICON_COLUMN,
5467 "visible", STATUS_ICON_VISIBLE_COLUMN,
5468 #if GTK_CHECK_VERSION(2,6,0)
5469 "cell-background-gdk", BGCOLOR_COLUMN,
5470 #endif
5471 NULL);
5472 g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
5473
5474 gtkblist->text_rend = rend = gtk_cell_renderer_text_new();
5475 gtk_tree_view_column_pack_start (column, rend, TRUE);
5476 gtk_tree_view_column_set_attributes(column, rend,
5477 #if GTK_CHECK_VERSION(2,6,0)
5478 "cell-background-gdk", BGCOLOR_COLUMN,
5479 #endif
5480 "markup", NAME_COLUMN,
5481 NULL);
5482 #if GTK_CHECK_VERSION(2,6,0)
5483 g_signal_connect(G_OBJECT(rend), "editing-started", G_CALLBACK(gtk_blist_renderer_editing_started_cb), NULL);
5484 g_signal_connect(G_OBJECT(rend), "editing-canceled", G_CALLBACK(gtk_blist_renderer_editing_cancelled_cb), list);
5485 #endif
5486 g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), list);
5487 g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL);
5488 #if GTK_CHECK_VERSION(2,6,0)
5489 g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
5490 #endif
5491 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
5492
5493 rend = gtk_cell_renderer_text_new();
5494 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
5495 gtk_tree_view_column_pack_start(column, rend, FALSE);
5496 gtk_tree_view_column_set_attributes(column, rend,
5497 "markup", IDLE_COLUMN,
5498 "visible", IDLE_VISIBLE_COLUMN,
5499 #if GTK_CHECK_VERSION(2,6,0)
5500 "cell-background-gdk", BGCOLOR_COLUMN,
5501 #endif
5502 NULL);
5503
5504 rend = gtk_cell_renderer_pixbuf_new();
5505 g_object_set(rend, "xalign", 1.0, "yalign", 0.5, "ypad", 0, "xpad", 3, NULL);
5506 gtk_tree_view_column_pack_start(column, rend, FALSE);
5507 gtk_tree_view_column_set_attributes(column, rend, "pixbuf", EMBLEM_COLUMN,
5508 #if GTK_CHECK_VERSION(2,6,0)
5509 "cell-background-gdk", BGCOLOR_COLUMN,
5510 #endif
5511 "visible", EMBLEM_VISIBLE_COLUMN, NULL);
5512
5513 rend = gtk_cell_renderer_pixbuf_new();
5514 gtk_tree_view_column_pack_start(column, rend, FALSE);
5515 gtk_tree_view_column_set_attributes(column, rend,
5516 "pixbuf", PROTOCOL_ICON_COLUMN,
5517 "visible", PROTOCOL_ICON_VISIBLE_COLUMN,
5518 #if GTK_CHECK_VERSION(2,6,0)
5519 "cell-background-gdk", BGCOLOR_COLUMN,
5520 #endif
5521 NULL);
5522 g_object_set(rend, "xalign", 0.0, "xpad", 3, "ypad", 0, NULL);
5523
5524 rend = gtk_cell_renderer_pixbuf_new();
5525 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
5526 gtk_tree_view_column_pack_start(column, rend, FALSE);
5527 gtk_tree_view_column_set_attributes(column, rend, "pixbuf", BUDDY_ICON_COLUMN,
5528 #if GTK_CHECK_VERSION(2,6,0)
5529 "cell-background-gdk", BGCOLOR_COLUMN,
5530 #endif
5531 "visible", BUDDY_ICON_VISIBLE_COLUMN,
5532 NULL);
5533
5534 5581
5535 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL); 5582 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL);
5536 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-expanded", G_CALLBACK(gtk_blist_row_expanded_cb), NULL); 5583 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-expanded", G_CALLBACK(gtk_blist_row_expanded_cb), NULL);
5537 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-collapsed", G_CALLBACK(gtk_blist_row_collapsed_cb), NULL); 5584 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-collapsed", G_CALLBACK(gtk_blist_row_collapsed_cb), NULL);
5538 g_signal_connect(G_OBJECT(gtkblist->treeview), "button-press-event", G_CALLBACK(gtk_blist_button_press_cb), NULL); 5585 g_signal_connect(G_OBJECT(gtkblist->treeview), "button-press-event", G_CALLBACK(gtk_blist_button_press_cb), NULL);
5955 gchar *title; 6002 gchar *title;
5956 gboolean biglist; 6003 gboolean biglist;
5957 GtkTreeIter iter; 6004 GtkTreeIter iter;
5958 GtkTreePath *path; 6005 GtkTreePath *path;
5959 gboolean expanded; 6006 gboolean expanded;
5960 GdkColor bgcolor; 6007 GdkColor *bgcolor = NULL;
5961 GdkPixbuf *avatar = NULL; 6008 GdkPixbuf *avatar = NULL;
6009 PidginBlistTheme *theme = NULL;
5962 6010
5963 if(!insert_node(list, gnode, &iter)) 6011 if(!insert_node(list, gnode, &iter))
5964 return; 6012 return;
5965 6013
5966 bgcolor = gtkblist->treeview->style->bg[GTK_STATE_ACTIVE]; 6014 if ((theme = pidgin_blist_get_theme()) == NULL)
6015 bgcolor = NULL;
6016 else if (purple_blist_node_get_bool(gnode, "collapsed") || count <= 0)
6017 bgcolor = pidgin_blist_theme_get_collapsed_background_color(theme);
6018 else bgcolor = pidgin_blist_theme_get_expanded_background_color(theme);
5967 6019
5968 path = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter); 6020 path = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
5969 expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(gtkblist->treeview), path); 6021 expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(gtkblist->treeview), path);
5970 gtk_tree_path_free(path); 6022 gtk_tree_path_free(path);
5971 6023
5979 gtk_tree_store_set(gtkblist->treemodel, &iter, 6031 gtk_tree_store_set(gtkblist->treemodel, &iter,
5980 STATUS_ICON_VISIBLE_COLUMN, FALSE, 6032 STATUS_ICON_VISIBLE_COLUMN, FALSE,
5981 STATUS_ICON_COLUMN, NULL, 6033 STATUS_ICON_COLUMN, NULL,
5982 NAME_COLUMN, title, 6034 NAME_COLUMN, title,
5983 NODE_COLUMN, gnode, 6035 NODE_COLUMN, gnode,
5984 /* BGCOLOR_COLUMN, &bgcolor, */ 6036 BGCOLOR_COLUMN, bgcolor,
5985 GROUP_EXPANDER_COLUMN, TRUE, 6037 GROUP_EXPANDER_COLUMN, TRUE,
5986 GROUP_EXPANDER_VISIBLE_COLUMN, TRUE, 6038 GROUP_EXPANDER_VISIBLE_COLUMN, TRUE,
5987 CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE, 6039 CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE,
5988 BUDDY_ICON_COLUMN, avatar, 6040 BUDDY_ICON_COLUMN, avatar,
5989 BUDDY_ICON_VISIBLE_COLUMN, biglist, 6041 BUDDY_ICON_VISIBLE_COLUMN, biglist,
6002 gboolean selected; 6054 gboolean selected;
6003 char group_count[12] = ""; 6055 char group_count[12] = "";
6004 char *mark, *esc; 6056 char *mark, *esc;
6005 PurpleBlistNode *selected_node = NULL; 6057 PurpleBlistNode *selected_node = NULL;
6006 GtkTreeIter iter; 6058 GtkTreeIter iter;
6059 FontColorPair *pair;
6060 gchar *text_color, *text_font;
6061 PidginBlistTheme *theme;
6007 6062
6008 group = (PurpleGroup*)gnode; 6063 group = (PurpleGroup*)gnode;
6009 6064
6010 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)), NULL, &iter)) { 6065 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)), NULL, &iter)) {
6011 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, 6066 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter,
6017 g_snprintf(group_count, sizeof(group_count), " (%d/%d)", 6072 g_snprintf(group_count, sizeof(group_count), " (%d/%d)",
6018 purple_blist_get_group_online_count(group), 6073 purple_blist_get_group_online_count(group),
6019 purple_blist_get_group_size(group, FALSE)); 6074 purple_blist_get_group_size(group, FALSE));
6020 } 6075 }
6021 6076
6077 theme = pidgin_blist_get_theme();
6078 if (theme == NULL)
6079 pair = NULL;
6080 else if
6081 (expanded) pair = pidgin_blist_theme_get_expanded_text_info(theme);
6082 else pair = pidgin_blist_theme_get_collapsed_text_info(theme);
6083
6084
6085 text_color = (selected || pair == NULL || pair->color == NULL) ? "black" : pair->color;
6086 text_font = (pair == NULL || pair->font == NULL) ? "" : pair->font;
6087
6022 esc = g_markup_escape_text(group->name, -1); 6088 esc = g_markup_escape_text(group->name, -1);
6023 mark = g_strdup_printf("<span weight='bold'>%s</span>%s", esc ? esc : "", group_count); 6089 mark = g_strdup_printf("<span foreground='%s' font_desc='%s'><b>%s</b>%s</span>",
6090 text_color, text_font, esc ? esc : "", group_count);
6024 6091
6025 g_free(esc); 6092 g_free(esc);
6026 return mark; 6093 return mark;
6027 } 6094 }
6028 6095
6029 static void buddy_node(PurpleBuddy *buddy, GtkTreeIter *iter, PurpleBlistNode *node) 6096 static void buddy_node(PurpleBuddy *buddy, GtkTreeIter *iter, PurpleBlistNode *node)
6030 { 6097 {
6031 PurplePresence *presence; 6098 PurplePresence *presence = purple_buddy_get_presence(buddy);
6032 GdkPixbuf *status, *avatar, *emblem, *prpl_icon; 6099 GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
6100 GdkColor *color = NULL;
6033 char *mark; 6101 char *mark;
6034 char *idle = NULL; 6102 char *idle = NULL;
6035 gboolean expanded = ((struct _pidgin_blist_node *)(node->parent->ui_data))->contact_expanded; 6103 gboolean expanded = ((struct _pidgin_blist_node *)(node->parent->ui_data))->contact_expanded;
6036 gboolean selected = (gtkblist->selected_node == node); 6104 gboolean selected = (gtkblist->selected_node == node);
6037 gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"); 6105 gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
6038 presence = purple_buddy_get_presence(buddy); 6106 PidginBlistTheme *theme;
6039 6107
6040 if (editing_blist) 6108 if (editing_blist)
6041 return; 6109 return;
6042 6110
6043 status = pidgin_blist_get_status_icon((PurpleBlistNode*)buddy, 6111 status = pidgin_blist_get_status_icon((PurpleBlistNode*)buddy,
6057 } 6125 }
6058 6126
6059 emblem = pidgin_blist_get_emblem((PurpleBlistNode*) buddy); 6127 emblem = pidgin_blist_get_emblem((PurpleBlistNode*) buddy);
6060 mark = pidgin_blist_get_name_markup(buddy, selected, TRUE); 6128 mark = pidgin_blist_get_name_markup(buddy, selected, TRUE);
6061 6129
6130 theme = pidgin_blist_get_theme();
6131
6062 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time") && 6132 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time") &&
6063 purple_presence_is_idle(presence) && 6133 purple_presence_is_idle(presence) && !biglist)
6064 !purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"))
6065 { 6134 {
6066 time_t idle_secs = purple_presence_get_idle_time(presence); 6135 time_t idle_secs = purple_presence_get_idle_time(presence);
6067 6136
6068 if (idle_secs > 0) 6137 if (idle_secs > 0)
6069 { 6138 {
6139 FontColorPair *pair = NULL;
6140 const gchar *textcolor;
6070 time_t t; 6141 time_t t;
6071 int ihrs, imin; 6142 int ihrs, imin;
6072 time(&t); 6143 time(&t);
6144
6073 ihrs = (t - idle_secs) / 3600; 6145 ihrs = (t - idle_secs) / 3600;
6074 imin = ((t - idle_secs) / 60) % 60; 6146 imin = ((t - idle_secs) / 60) % 60;
6075 idle = g_strdup_printf("%d:%02d", ihrs, imin); 6147
6076 } 6148 if (!selected && theme != NULL && (pair = pidgin_blist_theme_get_idle_text_info(theme)) != NULL && pair->color != NULL)
6077 } 6149 textcolor = pair->color;
6078 6150 else textcolor = "black";
6079 if (purple_presence_is_idle(presence)) 6151
6080 { 6152 idle = g_strdup_printf("<span color='%s' font_desc='%s'>%d:%02d</span>", textcolor,
6081 if (idle && !selected) { 6153 (pair == NULL || pair->font == NULL) ? "" : pair->font, ihrs, imin);
6082 char *i2 = g_strdup_printf("<span color='%s'>%s</span>",
6083 dim_grey(), idle);
6084 g_free(idle);
6085 idle = i2;
6086 } 6154 }
6087 } 6155 }
6088 6156
6089 prpl_icon = pidgin_create_prpl_icon(buddy->account, PIDGIN_PRPL_ICON_SMALL); 6157 prpl_icon = pidgin_create_prpl_icon(buddy->account, PIDGIN_PRPL_ICON_SMALL);
6158
6159 if (theme != NULL)
6160 color = pidgin_blist_theme_get_contact_color(theme);
6090 6161
6091 gtk_tree_store_set(gtkblist->treemodel, iter, 6162 gtk_tree_store_set(gtkblist->treemodel, iter,
6092 STATUS_ICON_COLUMN, status, 6163 STATUS_ICON_COLUMN, status,
6093 STATUS_ICON_VISIBLE_COLUMN, TRUE, 6164 STATUS_ICON_VISIBLE_COLUMN, TRUE,
6094 NAME_COLUMN, mark, 6165 NAME_COLUMN, mark,
6098 BUDDY_ICON_VISIBLE_COLUMN, biglist, 6169 BUDDY_ICON_VISIBLE_COLUMN, biglist,
6099 EMBLEM_COLUMN, emblem, 6170 EMBLEM_COLUMN, emblem,
6100 EMBLEM_VISIBLE_COLUMN, (emblem != NULL), 6171 EMBLEM_VISIBLE_COLUMN, (emblem != NULL),
6101 PROTOCOL_ICON_COLUMN, prpl_icon, 6172 PROTOCOL_ICON_COLUMN, prpl_icon,
6102 PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"), 6173 PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"),
6103 BGCOLOR_COLUMN, NULL, 6174 BGCOLOR_COLUMN, color,
6104 CONTACT_EXPANDER_COLUMN, NULL, 6175 CONTACT_EXPANDER_COLUMN, NULL,
6105 CONTACT_EXPANDER_VISIBLE_COLUMN, expanded, 6176 CONTACT_EXPANDER_VISIBLE_COLUMN, expanded,
6106 GROUP_EXPANDER_VISIBLE_COLUMN, FALSE, 6177 GROUP_EXPANDER_VISIBLE_COLUMN, FALSE,
6107 -1); 6178 -1);
6108 6179
6156 6227
6157 gtknode = (struct _pidgin_blist_node *)cnode->ui_data; 6228 gtknode = (struct _pidgin_blist_node *)cnode->ui_data;
6158 6229
6159 if(gtknode->contact_expanded) { 6230 if(gtknode->contact_expanded) {
6160 GdkPixbuf *status; 6231 GdkPixbuf *status;
6161 char *mark; 6232 gchar *mark;
6233 GdkColor *color = NULL;
6234 PidginBlistTheme *theme = pidgin_blist_get_theme();
6235 gboolean selected = (gtkblist->selected_node == cnode);
6236
6237 mark = g_markup_escape_text(purple_contact_get_alias(contact), -1);
6238
6239 if (theme != NULL) {
6240 FontColorPair *pair = pidgin_blist_theme_get_contact_text_info(theme);
6241 color = pidgin_blist_theme_get_contact_color(theme);
6242
6243 if (pair != NULL) {
6244 gchar *temp = g_strdup_printf("<span foreground='%s' font_desc='%s'>%s</span>",
6245 (selected || pair->color == NULL) ? "black" : pair->color,
6246 (pair->font == NULL) ? "" : pair->font, mark);
6247
6248 g_free(mark);
6249 mark = temp;
6250 }
6251 }
6162 6252
6163 status = pidgin_blist_get_status_icon(cnode, 6253 status = pidgin_blist_get_status_icon(cnode,
6164 biglist? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL); 6254 biglist? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL);
6165 6255
6166 mark = g_markup_escape_text(purple_contact_get_alias(contact), -1);
6167 gtk_tree_store_set(gtkblist->treemodel, &iter, 6256 gtk_tree_store_set(gtkblist->treemodel, &iter,
6168 STATUS_ICON_COLUMN, status, 6257 STATUS_ICON_COLUMN, status,
6169 STATUS_ICON_VISIBLE_COLUMN, TRUE, 6258 STATUS_ICON_VISIBLE_COLUMN, TRUE,
6170 NAME_COLUMN, mark, 6259 NAME_COLUMN, mark,
6171 IDLE_COLUMN, NULL, 6260 IDLE_COLUMN, NULL,
6172 IDLE_VISIBLE_COLUMN, FALSE, 6261 IDLE_VISIBLE_COLUMN, FALSE,
6173 BGCOLOR_COLUMN, NULL, 6262 BGCOLOR_COLUMN, color,
6174 BUDDY_ICON_COLUMN, NULL, 6263 BUDDY_ICON_COLUMN, NULL,
6175 CONTACT_EXPANDER_COLUMN, TRUE, 6264 CONTACT_EXPANDER_COLUMN, TRUE,
6176 CONTACT_EXPANDER_VISIBLE_COLUMN, TRUE, 6265 CONTACT_EXPANDER_VISIBLE_COLUMN, TRUE,
6177 GROUP_EXPANDER_VISIBLE_COLUMN, FALSE, 6266 GROUP_EXPANDER_VISIBLE_COLUMN, FALSE,
6178 -1); 6267 -1);
6236 chat = (PurpleChat*)node; 6325 chat = (PurpleChat*)node;
6237 6326
6238 if(purple_account_is_connected(chat->account)) { 6327 if(purple_account_is_connected(chat->account)) {
6239 GtkTreeIter iter; 6328 GtkTreeIter iter;
6240 GdkPixbuf *status, *avatar, *emblem, *prpl_icon; 6329 GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
6241 char *mark; 6330 gchar *mark, *color, *font, *tmp;
6242 gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"); 6331 gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
6243 gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"); 6332 gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
6244 PidginBlistNode *ui; 6333 PidginBlistNode *ui;
6245 PurpleConversation *conv; 6334 PurpleConversation *conv;
6246 gboolean hidden; 6335 gboolean hidden;
6336 GdkColor *bgcolor = NULL;
6337 FontColorPair *pair;
6338 PidginBlistTheme *theme;
6339 gboolean selected = (gtkblist->selected_node == node);
6247 6340
6248 if (!insert_node(list, node, &iter)) 6341 if (!insert_node(list, node, &iter))
6249 return; 6342 return;
6250 6343
6251 ui = node->ui_data; 6344 ui = node->ui_data;
6261 if(showicons) 6354 if(showicons)
6262 avatar = pidgin_blist_get_buddy_icon(node, TRUE, FALSE); 6355 avatar = pidgin_blist_get_buddy_icon(node, TRUE, FALSE);
6263 else 6356 else
6264 avatar = NULL; 6357 avatar = NULL;
6265 6358
6266 mark = g_markup_escape_text(purple_chat_get_name(chat), -1); 6359 mark = g_markup_escape_text(purple_chat_get_name(chat), -1);
6267 if (hidden) { 6360
6268 char *bold = g_strdup_printf("<b>%s</b>", mark); 6361 theme = pidgin_blist_get_theme();
6269 g_free(mark); 6362
6270 mark = bold; 6363 if (theme == NULL)
6271 } 6364 pair = NULL;
6365 else if (hidden)
6366 pair = pidgin_blist_theme_get_unread_message_text_info(theme);
6367 else pair = pidgin_blist_theme_get_online_text_info(theme);
6368
6369 font = (pair == NULL || pair->font == NULL) ? "" : g_strdup(pair->font);
6370 color = (selected || pair == NULL || pair->color == NULL) ? "black" : g_strdup(pair->color);
6371
6372 tmp = g_strdup_printf("<span font_desc='%s' color='%s' weight='%s'>%s</span>",
6373 font, color, hidden ? "bold" : "normal", mark);
6374
6375 g_free(mark);
6376 mark = tmp;
6272 6377
6273 prpl_icon = pidgin_create_prpl_icon(chat->account, PIDGIN_PRPL_ICON_SMALL); 6378 prpl_icon = pidgin_create_prpl_icon(chat->account, PIDGIN_PRPL_ICON_SMALL);
6379
6380 if (theme != NULL)
6381 bgcolor = pidgin_blist_theme_get_contact_color(theme);
6274 6382
6275 gtk_tree_store_set(gtkblist->treemodel, &iter, 6383 gtk_tree_store_set(gtkblist->treemodel, &iter,
6276 STATUS_ICON_COLUMN, status, 6384 STATUS_ICON_COLUMN, status,
6277 STATUS_ICON_VISIBLE_COLUMN, TRUE, 6385 STATUS_ICON_VISIBLE_COLUMN, TRUE,
6278 BUDDY_ICON_COLUMN, avatar ? avatar : gtkblist->empty_avatar, 6386 BUDDY_ICON_COLUMN, avatar ? avatar : gtkblist->empty_avatar,
6280 EMBLEM_COLUMN, emblem, 6388 EMBLEM_COLUMN, emblem,
6281 EMBLEM_VISIBLE_COLUMN, emblem != NULL, 6389 EMBLEM_VISIBLE_COLUMN, emblem != NULL,
6282 PROTOCOL_ICON_COLUMN, prpl_icon, 6390 PROTOCOL_ICON_COLUMN, prpl_icon,
6283 PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"), 6391 PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"),
6284 NAME_COLUMN, mark, 6392 NAME_COLUMN, mark,
6393 BGCOLOR_COLUMN, bgcolor,
6285 GROUP_EXPANDER_VISIBLE_COLUMN, FALSE, 6394 GROUP_EXPANDER_VISIBLE_COLUMN, FALSE,
6286 -1); 6395 -1);
6287 6396
6288 g_free(mark); 6397 g_free(mark);
6289 if(emblem) 6398 if(emblem)
6292 g_object_unref(status); 6401 g_object_unref(status);
6293 if(avatar) 6402 if(avatar)
6294 g_object_unref(avatar); 6403 g_object_unref(avatar);
6295 if(prpl_icon) 6404 if(prpl_icon)
6296 g_object_unref(prpl_icon); 6405 g_object_unref(prpl_icon);
6406
6297 } else { 6407 } else {
6298 pidgin_blist_hide_node(list, node, TRUE); 6408 pidgin_blist_hide_node(list, node, TRUE);
6299 } 6409 }
6300 } 6410 }
6301 6411
7151 purple_timeout_remove(gtknode->recent_signonoff_timer); 7261 purple_timeout_remove(gtknode->recent_signonoff_timer);
7152 gtknode->recent_signonoff_timer = purple_timeout_add(10000, 7262 gtknode->recent_signonoff_timer = purple_timeout_add(10000,
7153 (GSourceFunc)buddy_signonoff_timeout_cb, buddy); 7263 (GSourceFunc)buddy_signonoff_timeout_cb, buddy);
7154 } 7264 }
7155 7265
7266 void
7267 pidgin_blist_set_theme(PidginBlistTheme *theme)
7268 {
7269 PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
7270 PurpleBuddyList *list = purple_get_blist();
7271
7272 if (theme != NULL)
7273 purple_prefs_set_string(PIDGIN_PREFS_ROOT "/blist/theme",
7274 purple_theme_get_name(PURPLE_THEME(theme)));
7275 else purple_prefs_set_string(PIDGIN_PREFS_ROOT "/blist/theme", "");
7276
7277 priv->current_theme = theme;
7278
7279 pidgin_blist_build_layout(list);
7280
7281 pidgin_blist_refresh(list);
7282 }
7283
7284
7285 PidginBlistTheme *
7286 pidgin_blist_get_theme()
7287 {
7288 PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
7289
7290 return priv->current_theme;
7291 }
7292
7156 void pidgin_blist_init(void) 7293 void pidgin_blist_init(void)
7157 { 7294 {
7158 void *gtk_blist_handle = pidgin_blist_get_handle(); 7295 void *gtk_blist_handle = pidgin_blist_get_handle();
7159 7296
7160 cached_emblems = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); 7297 cached_emblems = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
7176 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/x", 0); 7313 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/x", 0);
7177 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/y", 0); 7314 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/y", 0);
7178 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/width", 250); /* Golden ratio, baby */ 7315 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/width", 250); /* Golden ratio, baby */
7179 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/height", 405); /* Golden ratio, baby */ 7316 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/height", 405); /* Golden ratio, baby */
7180 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay", 500); 7317 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay", 500);
7318 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/blist/theme", "");
7319
7320 purple_theme_manager_register_type(g_object_new(PIDGIN_TYPE_BLIST_THEME_LOADER, "type", "blist", NULL));
7181 7321
7182 /* Register our signals */ 7322 /* Register our signals */
7183 purple_signal_register(gtk_blist_handle, "gtkblist-hiding", 7323 purple_signal_register(gtk_blist_handle, "gtkblist-hiding",
7184 purple_marshal_VOID__POINTER, NULL, 1, 7324 purple_marshal_VOID__POINTER, NULL, 1,
7185 purple_value_new(PURPLE_TYPE_SUBTYPE, 7325 purple_value_new(PURPLE_TYPE_SUBTYPE,