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