1 /*
2  * Hides the blist on signon (or when it's created)
3  * Copyright (C) 2004-2008 Gary Kramlich
4  * Copyright (C) 2007-2008 Sadrul Habib Chowdhury
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02111-1301, USA.
20  */
21 
22 /* If you can't figure out what this line is for, DON'T TOUCH IT. */
23 #include "../common/pp_internal.h"
24 
25 #include <gdk/gdk.h>
26 #include <gtk/gtk.h>
27 
28 #include <gtkplugin.h>
29 #include <gtkblist.h>
30 #include <pluginpref.h>
31 #include <prefs.h>
32 
33 #include <string.h>
34 
35 #define PREF_MY "/plugins/gtk/amc_grim"
36 #define PREF_ROOT "/plugins/gtk/amc_grim/blistops"
37 #define PREF_LIST "/plugins/gtk/amc_grim/blistops/hidelist"
38 #define PREF_MENU "/plugins/gtk/amc_grim/blistops/hidemenu"
39 #define PREF_STRETCH "/plugins/gtk/amc_grim/blistops/stretch"
40 #define PREF_EMAIL "/plugins/gtk/amc_grim/blistops/email"
41 
42 static GtkWidget *w_blist = NULL;
43 static GtkWidget *w_menubar = NULL;
44 
45 static void
abracadabra(GtkWidget * w,gboolean v)46 abracadabra(GtkWidget *w, gboolean v)
47 {
48 	if(v)
49 		gtk_widget_hide(w);
50 	else
51 		gtk_widget_show(w);
52 }
53 
54 static gboolean
motion_notify_cb(GtkTreeView * view,GdkEventMotion * event,GtkRequisition * req)55 motion_notify_cb(GtkTreeView *view, GdkEventMotion *event, GtkRequisition *req)
56 {
57 	if (event->y < req->height) {
58 		gtk_widget_show(w_menubar);
59 	} else {
60 		gtk_widget_hide(w_menubar);
61 	}
62 
63 	return FALSE;
64 }
65 
66 static void
pref_cb(const char * name,PurplePrefType type,gconstpointer val,gpointer data)67 pref_cb(const char *name, PurplePrefType type,
68 		gconstpointer val, gpointer data)
69 {
70 	static GtkRequisition req;
71 	gboolean value = GPOINTER_TO_INT(val);
72 
73 	if(!g_ascii_strcasecmp(name, PREF_LIST))
74 		abracadabra(w_blist, value);
75 	else if(!g_ascii_strcasecmp(name, PREF_MENU)) {
76 		PidginBuddyList *gtkblist = pidgin_blist_get_default_gtk_blist();
77 		if (!value)
78 			g_signal_handlers_disconnect_matched(G_OBJECT(gtkblist->treeview), G_SIGNAL_MATCH_FUNC,
79 						0, 0, NULL, G_CALLBACK(motion_notify_cb), NULL);
80 		else {
81 			gtk_widget_show(w_menubar);
82 			gtk_widget_size_request(w_menubar, &req);
83 			g_signal_connect(gtkblist->treeview, "motion-notify-event", G_CALLBACK(motion_notify_cb), &req);
84 		}
85 		abracadabra(w_menubar, value);
86 	}
87 }
88 
89 static void
reset_row_heights(const char * name,PurplePrefType type,gconstpointer val,gpointer data)90 reset_row_heights(const char *name, PurplePrefType type,
91 		gconstpointer val, gpointer data)
92 {
93 	PidginBuddyList *gtkblist = pidgin_blist_get_default_gtk_blist();
94 	GtkTreeViewColumn *col = gtk_tree_view_get_column(GTK_TREE_VIEW(gtkblist->treeview), 1);
95 	GList *iter = gtk_tree_view_column_get_cell_renderers(col);
96 
97 	for (; iter; iter = g_list_delete_link(iter, iter)) {
98 		GtkCellRenderer *rend = iter->data;
99 		if (GTK_IS_CELL_RENDERER_PIXBUF(rend)) {
100 			g_object_set(rend, "height", val ? 32 : 16, NULL);
101 			break;
102 		}
103 	}
104 	if (iter)
105 		g_list_free(iter);
106 }
107 
108 static void
redraw_blist(const char * name,PurplePrefType type,gconstpointer val,gpointer data)109 redraw_blist(const char *name, PurplePrefType type,
110 		gconstpointer val, gpointer data)
111 {
112 	pidgin_blist_refresh(data);
113 }
114 
115 static void
row_changed_cb(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,PidginBuddyList * gtkblist)116 row_changed_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, PidginBuddyList *gtkblist)
117 {
118 	PurpleBlistNode *node;
119 	gboolean stretch, email;
120 	static gboolean inuse = FALSE, vis;
121 	const char *name;
122 	GdkPixbuf *pix = NULL;
123 	char *html;
124 
125 	if (inuse)
126 		return;
127 
128 	stretch = purple_prefs_get_bool(PREF_STRETCH);
129 	email = purple_prefs_get_bool(PREF_EMAIL);
130 	if (!stretch && !email)
131 		return;
132 
133 	inuse = TRUE;
134 
135 	gtk_tree_model_get(model, iter, NODE_COLUMN, &node,
136 			BUDDY_ICON_COLUMN, &pix, NAME_COLUMN, &html,
137 			BUDDY_ICON_VISIBLE_COLUMN, &vis, -1);
138 	if (PURPLE_BLIST_NODE_IS_CONTACT(node))
139 		node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
140 	if (!PURPLE_BLIST_NODE_IS_BUDDY(node))
141 		goto end;
142 
143 	if (email) {
144 		char *alias = g_markup_escape_text(purple_buddy_get_alias((PurpleBuddy*)node), -1);
145 		name = purple_buddy_get_name((PurpleBuddy*)node);
146 		if (g_utf8_collate(alias, name)) {
147 			char *new;
148 			char *find = g_strstr_len(html, -1, alias);
149 			if (find) {
150 				*find = '\0';
151 				new = g_strdup_printf("%s%s%s", html, name, find + strlen(alias));
152 				gtk_tree_store_set(GTK_TREE_STORE(model), iter, NAME_COLUMN, new, -1);
153 				g_free(new);
154 			}
155 		}
156 		g_free(alias);
157 	}
158 	if (stretch && vis && (!pix || pix == gtkblist->empty_avatar)) {
159 		/* Hiding the empty avatar makes the rows shorter than rows with buddy icons.
160 		 * We need to find a way to make sure that doesn't happen.
161 		 */
162 		gtk_tree_store_set(GTK_TREE_STORE(model), iter, BUDDY_ICON_VISIBLE_COLUMN, FALSE, -1);
163 	}
164 
165 end:
166 	if (pix)
167 		g_object_unref(pix);
168 	g_free(html);
169 	inuse = FALSE;
170 }
171 
172 static void
gtkblist_created_cb(PurpleBuddyList * blist)173 gtkblist_created_cb(PurpleBuddyList *blist)
174 {
175 	PidginBuddyList *gtkblist = PIDGIN_BLIST(blist);
176 
177 	w_blist = gtkblist->window;
178 #if PURPLE_VERSION_CHECK(3,0,0)
179 	w_menubar = gtk_ui_manager_get_widget(gtkblist->ui, "/BList");
180 #else
181 	w_menubar = gtk_item_factory_get_widget(gtkblist->ift, "<PurpleMain>");
182 #endif
183 
184 	g_signal_connect(gtkblist->treemodel, "row_changed", G_CALLBACK(row_changed_cb), gtkblist);
185 
186 	purple_prefs_trigger_callback(PREF_LIST);
187 	purple_prefs_trigger_callback(PREF_MENU);
188 
189 	purple_prefs_trigger_callback(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
190 }
191 
192 static gboolean
plugin_load(PurplePlugin * plugin)193 plugin_load(PurplePlugin *plugin)
194 {
195 	purple_signal_connect(pidgin_blist_get_handle(), "gtkblist-created", plugin,
196 						PURPLE_CALLBACK(gtkblist_created_cb), NULL);
197 
198 	if (pidgin_blist_get_default_gtk_blist())
199 		gtkblist_created_cb(purple_get_blist());
200 	purple_prefs_connect_callback(plugin, PREF_LIST, pref_cb, NULL);
201 	purple_prefs_connect_callback(plugin, PREF_MENU, pref_cb, NULL);
202 
203 	purple_prefs_connect_callback(plugin, PREF_STRETCH, redraw_blist, purple_get_blist());
204 	purple_prefs_connect_callback(plugin, PREF_EMAIL, redraw_blist, purple_get_blist());
205 
206 	purple_prefs_connect_callback(plugin, PIDGIN_PREFS_ROOT "/blist/show_buddy_icons",
207 				reset_row_heights, NULL);
208 
209 	return TRUE;
210 }
211 
212 static gboolean
plugin_unload(PurplePlugin * plugin)213 plugin_unload(PurplePlugin *plugin)
214 {
215 	if(w_blist) {
216 		gtk_widget_show(w_blist);
217 
218 		if(w_menubar)
219 			gtk_widget_show(w_menubar);
220 	}
221 
222 	return TRUE;
223 }
224 
225 static PurplePluginPrefFrame *
get_plugin_pref_frame(PurplePlugin * plugin)226 get_plugin_pref_frame(PurplePlugin *plugin)
227 {
228 	PurplePluginPrefFrame *frame;
229 	PurplePluginPref *ppref;
230 
231 	frame = purple_plugin_pref_frame_new();
232 
233 	ppref = purple_plugin_pref_new_with_name_and_label(PREF_LIST,
234 									_("Hide the buddy list when it is created"));
235 	purple_plugin_pref_frame_add(frame, ppref);
236 
237 	ppref = purple_plugin_pref_new_with_name_and_label(PREF_MENU,
238 									_("Hide the menu in the buddy list window"));
239 	purple_plugin_pref_frame_add(frame, ppref);
240 
241 	ppref = purple_plugin_pref_new_with_name_and_label(PREF_STRETCH,
242 									_("Stretch the buddyname if the buddy has no buddyicon."));
243 	purple_plugin_pref_frame_add(frame, ppref);
244 
245 	ppref = purple_plugin_pref_new_with_name_and_label(PREF_EMAIL,
246 									_("Show email addresses for all the buddies."));
247 	purple_plugin_pref_frame_add(frame, ppref);
248 
249 	return frame;
250 }
251 
252 static PurplePluginUiInfo prefs_info = {
253 	get_plugin_pref_frame,
254 	0,
255 	NULL,
256 	NULL,
257 	NULL,
258 	NULL,
259 	NULL
260 };
261 
262 static PurplePluginInfo info =
263 {
264 	PURPLE_PLUGIN_MAGIC,
265 	PURPLE_MAJOR_VERSION,
266 	PURPLE_MINOR_VERSION,
267 	PURPLE_PLUGIN_STANDARD,
268 	PIDGIN_PLUGIN_TYPE,
269 	0,
270 	NULL,
271 	PURPLE_PRIORITY_DEFAULT,
272 
273 	"gtk-plugin_pack-blistops",
274 	NULL,
275 	PP_VERSION,
276 	NULL,
277 	NULL,
278 	"Gary Kramlich <grim@reaperworld.com>",
279 	PP_WEBSITE,
280 
281 	plugin_load,
282 	plugin_unload,
283 	NULL,
284 
285 	NULL,
286 	NULL,
287 	&prefs_info,
288 	NULL,
289 	NULL,
290 	NULL,
291 	NULL,
292 	NULL
293 };
294 
295 static void
init_plugin(PurplePlugin * plugin)296 init_plugin(PurplePlugin *plugin)
297 {
298 #ifdef ENABLE_NLS
299 	bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
300 	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
301 #endif /* ENABLE_NLS */
302 
303 	info.name = _("Buddy List Options");
304 	info.summary = _("Gives extended options to the buddy list");
305 	info.description = _("Gives extended options to the buddy list");
306 
307 	purple_prefs_add_none(PREF_MY);
308 	purple_prefs_add_none(PREF_ROOT);
309 	purple_prefs_add_bool(PREF_LIST, FALSE);
310 	purple_prefs_add_bool(PREF_MENU, FALSE);
311 	purple_prefs_add_bool(PREF_STRETCH, TRUE);
312 	purple_prefs_add_bool(PREF_EMAIL, FALSE);
313 }
314 
315 PURPLE_INIT_PLUGIN(blistops, init_plugin, info)
316