15817
|
1 /**
|
|
2 * @file gntblist.c GNT BuddyList API
|
|
3 * @ingroup gntui
|
|
4 *
|
15822
|
5 * purple
|
15817
|
6 *
|
15822
|
7 * Purple is the legal property of its developers, whose names are too numerous
|
15817
|
8 * to list here. Please refer to the COPYRIGHT file distributed with this
|
|
9 * source distribution.
|
|
10 *
|
|
11 * This program is free software; you can redistribute it and/or modify
|
|
12 * it under the terms of the GNU General Public License as published by
|
|
13 * the Free Software Foundation; either version 2 of the License, or
|
|
14 * (at your option) any later version.
|
|
15 *
|
|
16 * This program is distributed in the hope that it will be useful,
|
|
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19 * GNU General Public License for more details.
|
|
20 *
|
|
21 * You should have received a copy of the GNU General Public License
|
|
22 * along with this program; if not, write to the Free Software
|
|
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
24 */
|
|
25 #include <account.h>
|
|
26 #include <blist.h>
|
|
27 #include <notify.h>
|
|
28 #include <request.h>
|
|
29 #include <savedstatuses.h>
|
|
30 #include <server.h>
|
|
31 #include <signal.h>
|
|
32 #include <status.h>
|
|
33 #include <util.h>
|
|
34 #include "debug.h"
|
|
35
|
15822
|
36 #include "finch.h"
|
15817
|
37 #include "gntbox.h"
|
|
38 #include "gntcombobox.h"
|
|
39 #include "gntentry.h"
|
|
40 #include "gntft.h"
|
|
41 #include "gntlabel.h"
|
|
42 #include "gntline.h"
|
|
43 #include "gntmenu.h"
|
|
44 #include "gntmenuitem.h"
|
|
45 #include "gntmenuitemcheck.h"
|
|
46 #include "gntpounce.h"
|
|
47 #include "gnttree.h"
|
|
48 #include "gntutils.h"
|
|
49 #include "gntwindow.h"
|
|
50
|
|
51 #include "gntblist.h"
|
|
52 #include "gntconv.h"
|
|
53 #include "gntstatus.h"
|
|
54 #include <string.h>
|
|
55
|
15822
|
56 #define PREF_ROOT "/purple/gnt/blist"
|
15817
|
57 #define TYPING_TIMEOUT 4000
|
|
58
|
|
59 typedef struct
|
|
60 {
|
|
61 GntWidget *window;
|
|
62 GntWidget *tree;
|
|
63
|
|
64 GntWidget *tooltip;
|
15822
|
65 PurpleBlistNode *tnode; /* Who is the tooltip being displayed for? */
|
15817
|
66 GList *tagged; /* A list of tagged blistnodes */
|
|
67
|
|
68 GntWidget *context;
|
15822
|
69 PurpleBlistNode *cnode;
|
15817
|
70
|
|
71 /* XXX: I am KISSing */
|
|
72 GntWidget *status; /* Dropdown with the statuses */
|
|
73 GntWidget *statustext; /* Status message */
|
|
74 int typing;
|
|
75
|
|
76 GntWidget *menu;
|
|
77 /* These are the menuitems that get regenerated */
|
|
78 GntMenuItem *accounts;
|
|
79 GntMenuItem *plugins;
|
|
80 } FinchBlist;
|
|
81
|
|
82 typedef enum
|
|
83 {
|
|
84 STATUS_PRIMITIVE = 0,
|
|
85 STATUS_SAVED_POPULAR,
|
|
86 STATUS_SAVED_ALL,
|
|
87 STATUS_SAVED_NEW
|
|
88 } StatusType;
|
|
89
|
|
90 typedef struct
|
|
91 {
|
|
92 StatusType type;
|
|
93 union
|
|
94 {
|
15822
|
95 PurpleStatusPrimitive prim;
|
|
96 PurpleSavedStatus *saved;
|
15817
|
97 } u;
|
|
98 } StatusBoxItem;
|
|
99
|
|
100 FinchBlist *ggblist;
|
|
101
|
15822
|
102 static void add_buddy(PurpleBuddy *buddy, FinchBlist *ggblist);
|
|
103 static void add_contact(PurpleContact *contact, FinchBlist *ggblist);
|
|
104 static void add_group(PurpleGroup *group, FinchBlist *ggblist);
|
|
105 static void add_chat(PurpleChat *chat, FinchBlist *ggblist);
|
|
106 static void add_node(PurpleBlistNode *node, FinchBlist *ggblist);
|
15817
|
107 static void draw_tooltip(FinchBlist *ggblist);
|
|
108 static gboolean remove_typing_cb(gpointer null);
|
|
109 static void remove_peripherals(FinchBlist *ggblist);
|
15822
|
110 static const char * get_display_name(PurpleBlistNode *node);
|
|
111 static void savedstatus_changed(PurpleSavedStatus *now, PurpleSavedStatus *old);
|
|
112 static void blist_show(PurpleBuddyList *list);
|
|
113 static void update_buddy_display(PurpleBuddy *buddy, FinchBlist *ggblist);
|
15817
|
114 static void account_signed_on_cb(void);
|
|
115
|
|
116 /* Sort functions */
|
15822
|
117 static int blist_node_compare_text(PurpleBlistNode *n1, PurpleBlistNode *n2);
|
|
118 static int blist_node_compare_status(PurpleBlistNode *n1, PurpleBlistNode *n2);
|
|
119 static int blist_node_compare_log(PurpleBlistNode *n1, PurpleBlistNode *n2);
|
15817
|
120
|
|
121 static gboolean
|
15822
|
122 is_contact_online(PurpleContact *contact)
|
15817
|
123 {
|
15822
|
124 PurpleBlistNode *node;
|
|
125 for (node = ((PurpleBlistNode*)contact)->child; node; node = node->next) {
|
|
126 if (PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node))
|
15817
|
127 return TRUE;
|
|
128 }
|
|
129 return FALSE;
|
|
130 }
|
|
131
|
|
132 static gboolean
|
15822
|
133 is_group_online(PurpleGroup *group)
|
15817
|
134 {
|
15822
|
135 PurpleBlistNode *node;
|
|
136 for (node = ((PurpleBlistNode*)group)->child; node; node = node->next) {
|
|
137 if (PURPLE_BLIST_NODE_IS_CHAT(node))
|
15817
|
138 return TRUE;
|
15822
|
139 else if (is_contact_online((PurpleContact*)node))
|
15817
|
140 return TRUE;
|
|
141 }
|
|
142 return FALSE;
|
|
143 }
|
|
144
|
|
145 static void
|
15822
|
146 new_node(PurpleBlistNode *node)
|
15817
|
147 {
|
|
148 }
|
|
149
|
15822
|
150 static void add_node(PurpleBlistNode *node, FinchBlist *ggblist)
|
15817
|
151 {
|
15822
|
152 if (PURPLE_BLIST_NODE_IS_BUDDY(node))
|
|
153 add_buddy((PurpleBuddy*)node, ggblist);
|
|
154 else if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
155 add_contact((PurpleContact*)node, ggblist);
|
|
156 else if (PURPLE_BLIST_NODE_IS_GROUP(node))
|
|
157 add_group((PurpleGroup*)node, ggblist);
|
|
158 else if (PURPLE_BLIST_NODE_IS_CHAT(node))
|
|
159 add_chat((PurpleChat *)node, ggblist);
|
15817
|
160 draw_tooltip(ggblist);
|
|
161 }
|
|
162
|
|
163 static void
|
|
164 remove_tooltip(FinchBlist *ggblist)
|
|
165 {
|
|
166 gnt_widget_destroy(ggblist->tooltip);
|
|
167 ggblist->tooltip = NULL;
|
|
168 ggblist->tnode = NULL;
|
|
169 }
|
|
170
|
|
171 static void
|
15822
|
172 node_remove(PurpleBuddyList *list, PurpleBlistNode *node)
|
15817
|
173 {
|
|
174 FinchBlist *ggblist = list->ui_data;
|
|
175
|
|
176 if (ggblist == NULL || node->ui_data == NULL)
|
|
177 return;
|
|
178
|
|
179 gnt_tree_remove(GNT_TREE(ggblist->tree), node);
|
|
180 node->ui_data = NULL;
|
|
181 if (ggblist->tagged)
|
|
182 ggblist->tagged = g_list_remove(ggblist->tagged, node);
|
|
183
|
15822
|
184 if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
|
185 PurpleContact *contact = (PurpleContact*)node->parent;
|
|
186 if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) ||
|
15817
|
187 contact->currentsize < 1)
|
15822
|
188 node_remove(list, (PurpleBlistNode*)contact);
|
|
189 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
|
190 PurpleGroup *group = (PurpleGroup*)node->parent;
|
|
191 if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) ||
|
15817
|
192 group->currentsize < 1)
|
|
193 node_remove(list, node->parent);
|
|
194 for (node = node->child; node; node = node->next)
|
|
195 node->ui_data = NULL;
|
|
196 }
|
|
197
|
|
198 draw_tooltip(ggblist);
|
|
199 }
|
|
200
|
|
201 static void
|
15822
|
202 node_update(PurpleBuddyList *list, PurpleBlistNode *node)
|
15817
|
203 {
|
|
204 /* It really looks like this should never happen ... but it does.
|
|
205 This will at least emit a warning to the log when it
|
|
206 happens, so maybe someone will figure it out. */
|
|
207 g_return_if_fail(node != NULL);
|
|
208
|
|
209 if (list->ui_data == NULL)
|
|
210 return; /* XXX: this is probably the place to auto-join chats */
|
|
211
|
|
212 if (node->ui_data != NULL) {
|
|
213 gnt_tree_change_text(GNT_TREE(ggblist->tree), node,
|
|
214 0, get_display_name(node));
|
|
215 gnt_tree_sort_row(GNT_TREE(ggblist->tree), node);
|
|
216 }
|
|
217
|
15822
|
218 if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
|
219 PurpleBuddy *buddy = (PurpleBuddy*)node;
|
|
220 if (purple_account_is_connected(buddy->account) &&
|
|
221 (PURPLE_BUDDY_IS_ONLINE(buddy) || purple_prefs_get_bool(PREF_ROOT "/showoffline")))
|
|
222 add_node((PurpleBlistNode*)buddy, list->ui_data);
|
15817
|
223 else
|
15822
|
224 node_remove(purple_get_blist(), node);
|
15817
|
225
|
|
226 node_update(list, node->parent);
|
15822
|
227 } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
|
|
228 add_chat((PurpleChat *)node, list->ui_data);
|
|
229 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
|
230 PurpleContact *contact = (PurpleContact*)node;
|
|
231 if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) ||
|
15817
|
232 contact->currentsize < 1)
|
15822
|
233 node_remove(purple_get_blist(), node);
|
15817
|
234 else
|
|
235 add_node(node, list->ui_data);
|
15822
|
236 } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
|
|
237 PurpleGroup *group = (PurpleGroup*)node;
|
|
238 if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) ||
|
15817
|
239 group->currentsize < 1)
|
|
240 node_remove(list, node);
|
|
241 }
|
|
242 }
|
|
243
|
|
244 static void
|
15822
|
245 new_list(PurpleBuddyList *list)
|
15817
|
246 {
|
|
247 if (ggblist)
|
|
248 return;
|
|
249
|
|
250 ggblist = g_new0(FinchBlist, 1);
|
|
251 list->ui_data = ggblist;
|
|
252 }
|
|
253
|
|
254 static void
|
15822
|
255 add_buddy_cb(void *data, PurpleRequestFields *allfields)
|
15817
|
256 {
|
15822
|
257 const char *username = purple_request_fields_get_string(allfields, "screenname");
|
|
258 const char *alias = purple_request_fields_get_string(allfields, "alias");
|
|
259 const char *group = purple_request_fields_get_string(allfields, "group");
|
|
260 PurpleAccount *account = purple_request_fields_get_account(allfields, "account");
|
15817
|
261 const char *error = NULL;
|
15822
|
262 PurpleGroup *grp;
|
|
263 PurpleBuddy *buddy;
|
15817
|
264
|
|
265 if (!username)
|
|
266 error = _("You must provide a screename for the buddy.");
|
|
267 else if (!group)
|
|
268 error = _("You must provide a group.");
|
|
269 else if (!account)
|
|
270 error = _("You must select an account.");
|
|
271
|
|
272 if (error)
|
|
273 {
|
15822
|
274 purple_notify_error(NULL, _("Error"), _("Error adding buddy"), error);
|
15817
|
275 return;
|
|
276 }
|
|
277
|
15822
|
278 grp = purple_find_group(group);
|
15817
|
279 if (!grp)
|
|
280 {
|
15822
|
281 grp = purple_group_new(group);
|
|
282 purple_blist_add_group(grp, NULL);
|
15817
|
283 }
|
|
284
|
15822
|
285 buddy = purple_buddy_new(account, username, alias);
|
|
286 purple_blist_add_buddy(buddy, NULL, grp, NULL);
|
|
287 purple_account_add_buddy(account, buddy);
|
15817
|
288 }
|
|
289
|
|
290 static void
|
15822
|
291 finch_request_add_buddy(PurpleAccount *account, const char *username, const char *grp, const char *alias)
|
15817
|
292 {
|
15822
|
293 PurpleRequestFields *fields = purple_request_fields_new();
|
|
294 PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL);
|
|
295 PurpleRequestField *field;
|
15817
|
296
|
15822
|
297 purple_request_fields_add_group(fields, group);
|
15817
|
298
|
15822
|
299 field = purple_request_field_string_new("screenname", _("Screen Name"), username, FALSE);
|
|
300 purple_request_field_group_add_field(group, field);
|
15817
|
301
|
15822
|
302 field = purple_request_field_string_new("alias", _("Alias"), alias, FALSE);
|
|
303 purple_request_field_group_add_field(group, field);
|
15817
|
304
|
15822
|
305 field = purple_request_field_string_new("group", _("Group"), grp, FALSE);
|
|
306 purple_request_field_group_add_field(group, field);
|
15817
|
307
|
15822
|
308 field = purple_request_field_account_new("account", _("Account"), NULL);
|
|
309 purple_request_field_account_set_show_all(field, FALSE);
|
15817
|
310 if (account)
|
15822
|
311 purple_request_field_account_set_value(field, account);
|
|
312 purple_request_field_group_add_field(group, field);
|
15817
|
313
|
15822
|
314 purple_request_fields(NULL, _("Add Buddy"), NULL, _("Please enter buddy information."),
|
15817
|
315 fields, _("Add"), G_CALLBACK(add_buddy_cb), _("Cancel"), NULL, NULL);
|
|
316 }
|
|
317
|
|
318 static void
|
15822
|
319 add_chat_cb(void *data, PurpleRequestFields *allfields)
|
15817
|
320 {
|
15822
|
321 PurpleAccount *account;
|
15817
|
322 const char *alias, *name, *group;
|
15822
|
323 PurpleChat *chat;
|
|
324 PurpleGroup *grp;
|
15817
|
325 GHashTable *hash = NULL;
|
15822
|
326 PurpleConnection *gc;
|
15817
|
327
|
15822
|
328 account = purple_request_fields_get_account(allfields, "account");
|
|
329 name = purple_request_fields_get_string(allfields, "name");
|
|
330 alias = purple_request_fields_get_string(allfields, "alias");
|
|
331 group = purple_request_fields_get_string(allfields, "group");
|
15817
|
332
|
15822
|
333 if (!purple_account_is_connected(account) || !name || !*name)
|
15817
|
334 return;
|
|
335
|
|
336 if (!group || !*group)
|
|
337 group = _("Chats");
|
|
338
|
15822
|
339 gc = purple_account_get_connection(account);
|
15817
|
340
|
15822
|
341 if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
|
|
342 hash = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, name);
|
15817
|
343
|
15822
|
344 chat = purple_chat_new(account, name, hash);
|
15817
|
345
|
|
346 if (chat != NULL) {
|
15822
|
347 if ((grp = purple_find_group(group)) == NULL) {
|
|
348 grp = purple_group_new(group);
|
|
349 purple_blist_add_group(grp, NULL);
|
15817
|
350 }
|
15822
|
351 purple_blist_add_chat(chat, grp, NULL);
|
|
352 purple_blist_alias_chat(chat, alias);
|
15817
|
353 }
|
|
354 }
|
|
355
|
|
356 static void
|
15822
|
357 finch_request_add_chat(PurpleAccount *account, PurpleGroup *grp, const char *alias, const char *name)
|
15817
|
358 {
|
15822
|
359 PurpleRequestFields *fields = purple_request_fields_new();
|
|
360 PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL);
|
|
361 PurpleRequestField *field;
|
15817
|
362
|
15822
|
363 purple_request_fields_add_group(fields, group);
|
15817
|
364
|
15822
|
365 field = purple_request_field_account_new("account", _("Account"), NULL);
|
|
366 purple_request_field_account_set_show_all(field, FALSE);
|
15817
|
367 if (account)
|
15822
|
368 purple_request_field_account_set_value(field, account);
|
|
369 purple_request_field_group_add_field(group, field);
|
15817
|
370
|
15822
|
371 field = purple_request_field_string_new("name", _("Name"), name, FALSE);
|
|
372 purple_request_field_group_add_field(group, field);
|
15817
|
373
|
15822
|
374 field = purple_request_field_string_new("alias", _("Alias"), alias, FALSE);
|
|
375 purple_request_field_group_add_field(group, field);
|
15817
|
376
|
15822
|
377 field = purple_request_field_string_new("group", _("Group"), grp ? grp->name : NULL, FALSE);
|
|
378 purple_request_field_group_add_field(group, field);
|
15817
|
379
|
15822
|
380 purple_request_fields(NULL, _("Add Chat"), NULL,
|
15817
|
381 _("You can edit more information from the context menu later."),
|
|
382 fields, _("Add"), G_CALLBACK(add_chat_cb), _("Cancel"), NULL, NULL);
|
|
383 }
|
|
384
|
|
385 static void
|
|
386 add_group_cb(gpointer null, const char *group)
|
|
387 {
|
15822
|
388 PurpleGroup *grp;
|
15817
|
389
|
|
390 if (!group || !*group)
|
|
391 {
|
15822
|
392 purple_notify_error(NULL, _("Error"), _("Error adding group"),
|
15817
|
393 _("You must give a name for the group to add."));
|
|
394 return;
|
|
395 }
|
|
396
|
15822
|
397 grp = purple_find_group(group);
|
15817
|
398 if (!grp)
|
|
399 {
|
15822
|
400 grp = purple_group_new(group);
|
|
401 purple_blist_add_group(grp, NULL);
|
15817
|
402 }
|
|
403 else
|
|
404 {
|
15822
|
405 purple_notify_error(NULL, _("Error"), _("Error adding group"),
|
15817
|
406 _("A group with the name already exists."));
|
|
407 }
|
|
408 }
|
|
409
|
|
410 static void
|
|
411 finch_request_add_group()
|
|
412 {
|
15822
|
413 purple_request_input(NULL, _("Add Group"), NULL, _("Enter the name of the group"),
|
15817
|
414 NULL, FALSE, FALSE, NULL,
|
|
415 _("Add"), G_CALLBACK(add_group_cb), _("Cancel"), NULL, NULL);
|
|
416 }
|
|
417
|
15822
|
418 static PurpleBlistUiOps blist_ui_ops =
|
15817
|
419 {
|
|
420 new_list,
|
|
421 new_node,
|
|
422 blist_show,
|
|
423 node_update,
|
|
424 node_remove,
|
|
425 NULL,
|
|
426 NULL,
|
|
427 .request_add_buddy = finch_request_add_buddy,
|
|
428 .request_add_chat = finch_request_add_chat,
|
|
429 .request_add_group = finch_request_add_group
|
|
430 };
|
|
431
|
|
432 static gpointer
|
|
433 finch_blist_get_handle()
|
|
434 {
|
|
435 static int handle;
|
|
436
|
|
437 return &handle;
|
|
438 }
|
|
439
|
|
440 static void
|
15822
|
441 add_group(PurpleGroup *group, FinchBlist *ggblist)
|
15817
|
442 {
|
15822
|
443 PurpleBlistNode *node = (PurpleBlistNode *)group;
|
15817
|
444 if (node->ui_data)
|
|
445 return;
|
|
446 node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), group,
|
|
447 gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), NULL, NULL);
|
|
448 }
|
|
449
|
|
450 static const char *
|
15822
|
451 get_display_name(PurpleBlistNode *node)
|
15817
|
452 {
|
|
453 static char text[2096];
|
|
454 char status[8] = " ";
|
|
455 const char *name = NULL;
|
|
456
|
15822
|
457 if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
458 node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node); /* XXX: this can return NULL?! */
|
15817
|
459
|
|
460 if (node == NULL)
|
|
461 return NULL;
|
|
462
|
15822
|
463 if (PURPLE_BLIST_NODE_IS_BUDDY(node))
|
15817
|
464 {
|
15822
|
465 PurpleBuddy *buddy = (PurpleBuddy *)node;
|
|
466 PurpleStatusPrimitive prim;
|
|
467 PurplePresence *presence;
|
|
468 PurpleStatus *now;
|
15817
|
469 gboolean ascii = gnt_ascii_only();
|
|
470
|
15822
|
471 presence = purple_buddy_get_presence(buddy);
|
|
472 now = purple_presence_get_active_status(presence);
|
15817
|
473
|
15822
|
474 prim = purple_status_type_get_primitive(purple_status_get_type(now));
|
15817
|
475
|
|
476 switch(prim)
|
|
477 {
|
15822
|
478 case PURPLE_STATUS_OFFLINE:
|
15817
|
479 strncpy(status, ascii ? "x" : "⊗", sizeof(status) - 1);
|
|
480 break;
|
15822
|
481 case PURPLE_STATUS_AVAILABLE:
|
15817
|
482 strncpy(status, ascii ? "o" : "â—¯", sizeof(status) - 1);
|
|
483 break;
|
|
484 default:
|
|
485 strncpy(status, ascii ? "." : "⊖", sizeof(status) - 1);
|
|
486 break;
|
|
487 }
|
15822
|
488 name = purple_buddy_get_alias(buddy);
|
15817
|
489 }
|
15822
|
490 else if (PURPLE_BLIST_NODE_IS_CHAT(node))
|
15817
|
491 {
|
15822
|
492 PurpleChat *chat = (PurpleChat*)node;
|
|
493 name = purple_chat_get_name(chat);
|
15817
|
494
|
|
495 strncpy(status, "~", sizeof(status) - 1);
|
|
496 }
|
15822
|
497 else if (PURPLE_BLIST_NODE_IS_GROUP(node))
|
|
498 return ((PurpleGroup*)node)->name;
|
15817
|
499
|
|
500 snprintf(text, sizeof(text) - 1, "%s %s", status, name);
|
|
501
|
|
502 return text;
|
|
503 }
|
|
504
|
|
505 static void
|
15822
|
506 add_chat(PurpleChat *chat, FinchBlist *ggblist)
|
15817
|
507 {
|
15822
|
508 PurpleGroup *group;
|
|
509 PurpleBlistNode *node = (PurpleBlistNode *)chat;
|
15817
|
510 if (node->ui_data)
|
|
511 return;
|
15822
|
512 if (!purple_account_is_connected(chat->account))
|
15817
|
513 return;
|
|
514
|
15822
|
515 group = purple_chat_get_group(chat);
|
|
516 add_node((PurpleBlistNode*)group, ggblist);
|
15817
|
517
|
|
518 node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), chat,
|
|
519 gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)),
|
|
520 group, NULL);
|
|
521 }
|
|
522
|
|
523 static void
|
15822
|
524 add_contact(PurpleContact *contact, FinchBlist *ggblist)
|
15817
|
525 {
|
15822
|
526 PurpleGroup *group;
|
|
527 PurpleBlistNode *node = (PurpleBlistNode*)contact;
|
15817
|
528 const char *name;
|
|
529
|
|
530 if (node->ui_data)
|
|
531 return;
|
|
532
|
|
533 name = get_display_name(node);
|
|
534 if (name == NULL)
|
|
535 return;
|
|
536
|
15822
|
537 group = (PurpleGroup*)node->parent;
|
|
538 add_node((PurpleBlistNode*)group, ggblist);
|
15817
|
539
|
|
540 node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), contact,
|
|
541 gnt_tree_create_row(GNT_TREE(ggblist->tree), name),
|
|
542 group, NULL);
|
|
543
|
|
544 gnt_tree_set_expanded(GNT_TREE(ggblist->tree), contact, FALSE);
|
|
545 }
|
|
546
|
|
547 static void
|
15822
|
548 add_buddy(PurpleBuddy *buddy, FinchBlist *ggblist)
|
15817
|
549 {
|
15822
|
550 PurpleContact *contact;
|
|
551 PurpleBlistNode *node = (PurpleBlistNode *)buddy;
|
15817
|
552 if (node->ui_data)
|
|
553 return;
|
|
554
|
15822
|
555 contact = (PurpleContact*)node->parent;
|
15817
|
556 if (!contact) /* When a new buddy is added and show-offline is set */
|
|
557 return;
|
15822
|
558 add_node((PurpleBlistNode*)contact, ggblist);
|
15817
|
559
|
|
560 node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), buddy,
|
|
561 gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)),
|
|
562 contact, NULL);
|
15822
|
563 if (purple_presence_is_idle(purple_buddy_get_presence(buddy))) {
|
15817
|
564 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, GNT_TEXT_FLAG_DIM);
|
|
565 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, GNT_TEXT_FLAG_DIM);
|
|
566 } else {
|
|
567 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, 0);
|
|
568 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, 0);
|
|
569 }
|
|
570 }
|
|
571
|
|
572 #if 0
|
|
573 static void
|
15822
|
574 buddy_signed_on(PurpleBuddy *buddy, FinchBlist *ggblist)
|
15817
|
575 {
|
15822
|
576 add_node((PurpleBlistNode*)buddy, ggblist);
|
15817
|
577 }
|
|
578
|
|
579 static void
|
15822
|
580 buddy_signed_off(PurpleBuddy *buddy, FinchBlist *ggblist)
|
15817
|
581 {
|
15822
|
582 node_remove(purple_get_blist(), (PurpleBlistNode*)buddy);
|
15817
|
583 }
|
|
584 #endif
|
|
585
|
15822
|
586 PurpleBlistUiOps *finch_blist_get_ui_ops()
|
15817
|
587 {
|
|
588 return &blist_ui_ops;
|
|
589 }
|
|
590
|
|
591 static void
|
|
592 selection_activate(GntWidget *widget, FinchBlist *ggblist)
|
|
593 {
|
|
594 GntTree *tree = GNT_TREE(ggblist->tree);
|
15822
|
595 PurpleBlistNode *node = gnt_tree_get_selection_data(tree);
|
15817
|
596
|
|
597 if (!node)
|
|
598 return;
|
|
599
|
15822
|
600 if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
601 node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
|
15817
|
602
|
15822
|
603 if (PURPLE_BLIST_NODE_IS_BUDDY(node))
|
15817
|
604 {
|
15822
|
605 PurpleBuddy *buddy = (PurpleBuddy *)node;
|
|
606 PurpleConversation *conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
|
|
607 purple_buddy_get_account(buddy),
|
|
608 purple_buddy_get_name(buddy));
|
15817
|
609 finch_conversation_set_active(conv);
|
|
610 }
|
15822
|
611 else if (PURPLE_BLIST_NODE_IS_CHAT(node))
|
15817
|
612 {
|
15822
|
613 PurpleChat *chat = (PurpleChat*)node;
|
15817
|
614 serv_join_chat(chat->account->gc, chat->components);
|
|
615 }
|
|
616 }
|
|
617
|
|
618 static void
|
|
619 context_menu_callback(GntMenuItem *item, gpointer data)
|
|
620 {
|
15822
|
621 PurpleMenuAction *action = data;
|
|
622 PurpleBlistNode *node = ggblist->cnode;
|
15817
|
623 if (action) {
|
15822
|
624 void (*callback)(PurpleBlistNode *, gpointer);
|
|
625 callback = (void (*)(PurpleBlistNode *, gpointer))action->callback;
|
15817
|
626 if (callback)
|
|
627 callback(action->data, node);
|
|
628 else
|
|
629 return;
|
|
630 }
|
|
631 }
|
|
632
|
|
633 static void
|
15822
|
634 gnt_append_menu_action(GntMenu *menu, PurpleMenuAction *action, gpointer parent)
|
15817
|
635 {
|
|
636 GList *list;
|
|
637 GntMenuItem *item;
|
|
638
|
|
639 if (action == NULL)
|
|
640 return;
|
|
641
|
|
642 item = gnt_menuitem_new(action->label);
|
|
643 if (action->callback)
|
|
644 gnt_menuitem_set_callback(GNT_MENUITEM(item), context_menu_callback, action);
|
|
645 gnt_menu_add_item(menu, GNT_MENUITEM(item));
|
|
646
|
|
647 if (action->children) {
|
|
648 GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP);
|
|
649 gnt_menuitem_set_submenu(item, GNT_MENU(sub));
|
|
650 for (list = action->children; list; list = list->next)
|
|
651 gnt_append_menu_action(GNT_MENU(sub), list->data, action);
|
|
652 }
|
|
653 }
|
|
654
|
|
655 static void
|
15822
|
656 append_proto_menu(GntMenu *menu, PurpleConnection *gc, PurpleBlistNode *node)
|
15817
|
657 {
|
|
658 GList *list;
|
15822
|
659 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
|
15817
|
660
|
|
661 if(!prpl_info || !prpl_info->blist_node_menu)
|
|
662 return;
|
|
663
|
|
664 for(list = prpl_info->blist_node_menu(node); list;
|
|
665 list = g_list_delete_link(list, list))
|
|
666 {
|
15822
|
667 PurpleMenuAction *act = (PurpleMenuAction *) list->data;
|
15817
|
668 act->data = node;
|
|
669 gnt_append_menu_action(menu, act, NULL);
|
|
670 }
|
|
671 }
|
|
672
|
|
673 static void
|
15822
|
674 add_custom_action(GntMenu *menu, const char *label, PurpleCallback callback,
|
15817
|
675 gpointer data)
|
|
676 {
|
15822
|
677 PurpleMenuAction *action = purple_menu_action_new(label, callback, data, NULL);
|
15817
|
678 gnt_append_menu_action(menu, action, NULL);
|
|
679 g_signal_connect_swapped(G_OBJECT(menu), "destroy",
|
15822
|
680 G_CALLBACK(purple_menu_action_free), action);
|
15817
|
681 }
|
|
682
|
|
683 static void
|
15822
|
684 chat_components_edit_ok(PurpleChat *chat, PurpleRequestFields *allfields)
|
15817
|
685 {
|
|
686 GList *groups, *fields;
|
|
687
|
15822
|
688 for (groups = purple_request_fields_get_groups(allfields); groups; groups = groups->next) {
|
|
689 fields = purple_request_field_group_get_fields(groups->data);
|
15817
|
690 for (; fields; fields = fields->next) {
|
15822
|
691 PurpleRequestField *field = fields->data;
|
15817
|
692 const char *id;
|
|
693 char *val;
|
|
694
|
15822
|
695 id = purple_request_field_get_id(field);
|
|
696 if (purple_request_field_get_type(field) == PURPLE_REQUEST_FIELD_INTEGER)
|
|
697 val = g_strdup_printf("%d", purple_request_field_int_get_value(field));
|
15817
|
698 else
|
15822
|
699 val = g_strdup(purple_request_field_string_get_value(field));
|
15817
|
700
|
|
701 g_hash_table_replace(chat->components, g_strdup(id), val); /* val should not be free'd */
|
|
702 }
|
|
703 }
|
|
704 }
|
|
705
|
|
706 static void
|
15822
|
707 chat_components_edit(PurpleChat *chat, PurpleBlistNode *selected)
|
15817
|
708 {
|
15822
|
709 PurpleRequestFields *fields = purple_request_fields_new();
|
|
710 PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL);
|
|
711 PurpleRequestField *field;
|
15817
|
712 GList *parts, *iter;
|
|
713 struct proto_chat_entry *pce;
|
|
714
|
15822
|
715 purple_request_fields_add_group(fields, group);
|
15817
|
716
|
15822
|
717 parts = PURPLE_PLUGIN_PROTOCOL_INFO(chat->account->gc->prpl)->chat_info(chat->account->gc);
|
15817
|
718
|
|
719 for (iter = parts; iter; iter = iter->next) {
|
|
720 pce = iter->data;
|
|
721 if (pce->is_int) {
|
|
722 int val;
|
|
723 const char *str = g_hash_table_lookup(chat->components, pce->identifier);
|
|
724 if (!str || sscanf(str, "%d", &val) != 1)
|
|
725 val = pce->min;
|
15822
|
726 field = purple_request_field_int_new(pce->identifier, pce->label, val);
|
15817
|
727 } else {
|
15822
|
728 field = purple_request_field_string_new(pce->identifier, pce->label,
|
15817
|
729 g_hash_table_lookup(chat->components, pce->identifier), FALSE);
|
|
730 }
|
|
731
|
15822
|
732 purple_request_field_group_add_field(group, field);
|
15817
|
733 g_free(pce);
|
|
734 }
|
|
735
|
|
736 g_list_free(parts);
|
|
737
|
15822
|
738 purple_request_fields(NULL, _("Edit Chat"), NULL, _("Please Update the necessary fields."),
|
15817
|
739 fields, _("Edit"), G_CALLBACK(chat_components_edit_ok), _("Cancel"), NULL, chat);
|
|
740 }
|
|
741
|
|
742 static void
|
|
743 autojoin_toggled(GntMenuItem *item, gpointer data)
|
|
744 {
|
15822
|
745 PurpleMenuAction *action = data;
|
|
746 purple_blist_node_set_bool(action->data, "gnt-autojoin",
|
15817
|
747 gnt_menuitem_check_get_checked(GNT_MENUITEM_CHECK(item)));
|
|
748 }
|
|
749
|
|
750 static void
|
15822
|
751 create_chat_menu(GntMenu *menu, PurpleChat *chat)
|
15817
|
752 {
|
15822
|
753 PurpleMenuAction *action = purple_menu_action_new(_("Auto-join"), NULL, chat, NULL);
|
15817
|
754 GntMenuItem *check = gnt_menuitem_check_new(action->label);
|
|
755 gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(check),
|
15822
|
756 purple_blist_node_get_bool((PurpleBlistNode*)chat, "gnt-autojoin"));
|
15817
|
757 gnt_menu_add_item(menu, check);
|
|
758 gnt_menuitem_set_callback(check, autojoin_toggled, action);
|
|
759 g_signal_connect_swapped(G_OBJECT(menu), "destroy",
|
15822
|
760 G_CALLBACK(purple_menu_action_free), action);
|
15817
|
761
|
15822
|
762 add_custom_action(menu, _("Edit Settings"), (PurpleCallback)chat_components_edit, chat);
|
15817
|
763 }
|
|
764
|
|
765 static void
|
15822
|
766 finch_add_buddy(PurpleGroup *grp, PurpleBlistNode *selected)
|
15817
|
767 {
|
15822
|
768 purple_blist_request_add_buddy(NULL, NULL, grp ? grp->name : NULL, NULL);
|
15817
|
769 }
|
|
770
|
|
771 static void
|
15822
|
772 finch_add_group(PurpleGroup *grp, PurpleBlistNode *selected)
|
15817
|
773 {
|
15822
|
774 purple_blist_request_add_group();
|
15817
|
775 }
|
|
776
|
|
777 static void
|
15822
|
778 finch_add_chat(PurpleGroup *grp, PurpleBlistNode *selected)
|
15817
|
779 {
|
15822
|
780 purple_blist_request_add_chat(NULL, grp, NULL, NULL);
|
15817
|
781 }
|
|
782
|
|
783 static void
|
15822
|
784 create_group_menu(GntMenu *menu, PurpleGroup *group)
|
15817
|
785 {
|
|
786 add_custom_action(menu, _("Add Buddy"),
|
15822
|
787 PURPLE_CALLBACK(finch_add_buddy), group);
|
15817
|
788 add_custom_action(menu, _("Add Chat"),
|
15822
|
789 PURPLE_CALLBACK(finch_add_chat), group);
|
15817
|
790 add_custom_action(menu, _("Add Group"),
|
15822
|
791 PURPLE_CALLBACK(finch_add_group), group);
|
15817
|
792 }
|
|
793
|
|
794 static void
|
15822
|
795 finch_blist_get_buddy_info_cb(PurpleBuddy *buddy, PurpleBlistNode *selected)
|
15817
|
796 {
|
15822
|
797 serv_get_info(buddy->account->gc, purple_buddy_get_name(buddy));
|
15817
|
798 }
|
|
799
|
|
800 static void
|
15822
|
801 finch_blist_menu_send_file_cb(PurpleBuddy *buddy, PurpleBlistNode *selected)
|
15817
|
802 {
|
|
803 serv_send_file(buddy->account->gc, buddy->name, NULL);
|
|
804 }
|
|
805
|
|
806 static void
|
15822
|
807 finch_blist_pounce_node_cb(PurpleBlistNode *node, PurpleBlistNode *selected)
|
15817
|
808 {
|
15822
|
809 PurpleBuddy *b;
|
|
810 if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
811 b = purple_contact_get_priority_buddy((PurpleContact *)node);
|
15817
|
812 else
|
15822
|
813 b = (PurpleBuddy *)node;
|
15817
|
814 finch_pounce_editor_show(b->account, b->name, NULL);
|
|
815 }
|
|
816
|
|
817
|
|
818 static void
|
15822
|
819 create_buddy_menu(GntMenu *menu, PurpleBuddy *buddy)
|
15817
|
820 {
|
15822
|
821 PurplePluginProtocolInfo *prpl_info;
|
15817
|
822
|
15822
|
823 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl);
|
15817
|
824 if (prpl_info && prpl_info->get_info)
|
|
825 {
|
|
826 add_custom_action(menu, _("Get Info"),
|
15822
|
827 PURPLE_CALLBACK(finch_blist_get_buddy_info_cb), buddy);
|
15817
|
828 }
|
|
829
|
|
830 add_custom_action(menu, _("Add Buddy Pounce"),
|
15822
|
831 PURPLE_CALLBACK(finch_blist_pounce_node_cb), buddy);
|
15817
|
832
|
|
833 if (prpl_info && prpl_info->send_file)
|
|
834 {
|
|
835 if (!prpl_info->can_receive_file ||
|
|
836 prpl_info->can_receive_file(buddy->account->gc, buddy->name))
|
|
837 add_custom_action(menu, _("Send File"),
|
15822
|
838 PURPLE_CALLBACK(finch_blist_menu_send_file_cb), buddy);
|
15817
|
839 }
|
|
840 #if 0
|
|
841 add_custom_action(tree, _("View Log"),
|
15822
|
842 PURPLE_CALLBACK(finch_blist_view_log_cb)), buddy);
|
15817
|
843 #endif
|
|
844
|
|
845 /* Protocol actions */
|
|
846 append_proto_menu(menu,
|
15822
|
847 purple_account_get_connection(purple_buddy_get_account(buddy)),
|
|
848 (PurpleBlistNode*)buddy);
|
15817
|
849 }
|
|
850
|
|
851 static void
|
15822
|
852 append_extended_menu(GntMenu *menu, PurpleBlistNode *node)
|
15817
|
853 {
|
|
854 GList *iter;
|
|
855
|
15822
|
856 for (iter = purple_blist_node_get_extended_menu(node);
|
15817
|
857 iter; iter = g_list_delete_link(iter, iter))
|
|
858 {
|
|
859 gnt_append_menu_action(menu, iter->data, NULL);
|
|
860 }
|
|
861 }
|
|
862
|
15822
|
863 /* Xerox'd from gtkdialogs.c:purple_gtkdialogs_remove_contact_cb */
|
15817
|
864 static void
|
15822
|
865 remove_contact(PurpleContact *contact)
|
15817
|
866 {
|
15822
|
867 PurpleBlistNode *bnode, *cnode;
|
|
868 PurpleGroup *group;
|
15817
|
869
|
15822
|
870 cnode = (PurpleBlistNode *)contact;
|
|
871 group = (PurpleGroup*)cnode->parent;
|
15817
|
872 for (bnode = cnode->child; bnode; bnode = bnode->next) {
|
15822
|
873 PurpleBuddy *buddy = (PurpleBuddy*)bnode;
|
|
874 if (purple_account_is_connected(buddy->account))
|
|
875 purple_account_remove_buddy(buddy->account, buddy, group);
|
15817
|
876 }
|
15822
|
877 purple_blist_remove_contact(contact);
|
15817
|
878 }
|
|
879
|
|
880 static void
|
15822
|
881 rename_blist_node(PurpleBlistNode *node, const char *newname)
|
15817
|
882 {
|
|
883 const char *name = newname;
|
|
884 if (name && !*name)
|
|
885 name = NULL;
|
|
886
|
15822
|
887 if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
|
888 PurpleContact *contact = (PurpleContact*)node;
|
|
889 PurpleBuddy *buddy = purple_contact_get_priority_buddy(contact);
|
|
890 purple_blist_alias_contact(contact, name);
|
|
891 purple_blist_alias_buddy(buddy, name);
|
15817
|
892 serv_alias_buddy(buddy);
|
15822
|
893 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
|
894 purple_blist_alias_buddy((PurpleBuddy*)node, name);
|
|
895 serv_alias_buddy((PurpleBuddy*)node);
|
|
896 } else if (PURPLE_BLIST_NODE_IS_CHAT(node))
|
|
897 purple_blist_alias_chat((PurpleChat*)node, name);
|
|
898 else if (PURPLE_BLIST_NODE_IS_GROUP(node) && (name != NULL))
|
|
899 purple_blist_rename_group((PurpleGroup*)node, name);
|
15817
|
900 else
|
|
901 g_return_if_reached();
|
|
902 }
|
|
903
|
|
904 static void
|
15822
|
905 finch_blist_rename_node_cb(PurpleBlistNode *node, PurpleBlistNode *selected)
|
15817
|
906 {
|
|
907 const char *name = NULL;
|
|
908 char *prompt;
|
|
909
|
15822
|
910 if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
911 name = purple_contact_get_alias((PurpleContact*)node);
|
|
912 else if (PURPLE_BLIST_NODE_IS_BUDDY(node))
|
|
913 name = purple_buddy_get_contact_alias((PurpleBuddy*)node);
|
|
914 else if (PURPLE_BLIST_NODE_IS_CHAT(node))
|
|
915 name = purple_chat_get_name((PurpleChat*)node);
|
|
916 else if (PURPLE_BLIST_NODE_IS_GROUP(node))
|
|
917 name = ((PurpleGroup*)node)->name;
|
15817
|
918 else
|
|
919 g_return_if_reached();
|
|
920
|
|
921 prompt = g_strdup_printf(_("Please enter the new name for %s"), name);
|
|
922
|
15822
|
923 purple_request_input(node, _("Rename"), prompt, _("Enter empty string to reset the name."),
|
15817
|
924 name, FALSE, FALSE, NULL, _("Rename"), G_CALLBACK(rename_blist_node),
|
|
925 _("Cancel"), NULL, node);
|
|
926
|
|
927 g_free(prompt);
|
|
928 }
|
|
929
|
15822
|
930 /* Xeroxed from gtkdialogs.c:purple_gtkdialogs_remove_group_cb*/
|
15817
|
931 static void
|
15822
|
932 remove_group(PurpleGroup *group)
|
15817
|
933 {
|
15822
|
934 PurpleBlistNode *cnode, *bnode;
|
15817
|
935
|
15822
|
936 cnode = ((PurpleBlistNode*)group)->child;
|
15817
|
937
|
|
938 while (cnode) {
|
15822
|
939 if (PURPLE_BLIST_NODE_IS_CONTACT(cnode)) {
|
15817
|
940 bnode = cnode->child;
|
|
941 cnode = cnode->next;
|
|
942 while (bnode) {
|
15822
|
943 PurpleBuddy *buddy;
|
|
944 if (PURPLE_BLIST_NODE_IS_BUDDY(bnode)) {
|
|
945 buddy = (PurpleBuddy*)bnode;
|
15817
|
946 bnode = bnode->next;
|
15822
|
947 if (purple_account_is_connected(buddy->account)) {
|
|
948 purple_account_remove_buddy(buddy->account, buddy, group);
|
|
949 purple_blist_remove_buddy(buddy);
|
15817
|
950 }
|
|
951 } else {
|
|
952 bnode = bnode->next;
|
|
953 }
|
|
954 }
|
15822
|
955 } else if (PURPLE_BLIST_NODE_IS_CHAT(cnode)) {
|
|
956 PurpleChat *chat = (PurpleChat *)cnode;
|
15817
|
957 cnode = cnode->next;
|
15822
|
958 if (purple_account_is_connected(chat->account))
|
|
959 purple_blist_remove_chat(chat);
|
15817
|
960 } else {
|
|
961 cnode = cnode->next;
|
|
962 }
|
|
963 }
|
|
964
|
15822
|
965 purple_blist_remove_group(group);
|
15817
|
966 }
|
|
967
|
|
968 static void
|
15822
|
969 finch_blist_remove_node(PurpleBlistNode *node)
|
15817
|
970 {
|
15822
|
971 if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
|
972 remove_contact((PurpleContact*)node);
|
|
973 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
|
974 PurpleBuddy *buddy = (PurpleBuddy*)node;
|
|
975 PurpleGroup *group = purple_buddy_get_group(buddy);
|
|
976 purple_account_remove_buddy(purple_buddy_get_account(buddy), buddy, group);
|
|
977 purple_blist_remove_buddy(buddy);
|
|
978 } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
|
|
979 purple_blist_remove_chat((PurpleChat*)node);
|
|
980 } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
|
|
981 remove_group((PurpleGroup*)node);
|
15817
|
982 }
|
|
983 }
|
|
984
|
|
985 static void
|
15822
|
986 finch_blist_remove_node_cb(PurpleBlistNode *node, PurpleBlistNode *selected)
|
15817
|
987 {
|
|
988 char *primary;
|
|
989 const char *name, *sec = NULL;
|
|
990
|
|
991 /* XXX: could be a contact */
|
15822
|
992 if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
|
993 PurpleContact *c = (PurpleContact*)node;
|
|
994 name = purple_contact_get_alias(c);
|
15817
|
995 if (c->totalsize > 1)
|
|
996 sec = _("Removing this contact will also remove all the buddies in the contact");
|
15822
|
997 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node))
|
|
998 name = purple_buddy_get_name((PurpleBuddy*)node);
|
|
999 else if (PURPLE_BLIST_NODE_IS_CHAT(node))
|
|
1000 name = purple_chat_get_name((PurpleChat*)node);
|
|
1001 else if (PURPLE_BLIST_NODE_IS_GROUP(node))
|
15817
|
1002 {
|
15822
|
1003 name = ((PurpleGroup*)node)->name;
|
15817
|
1004 sec = _("Removing this group will also remove all the buddies in the group");
|
|
1005 }
|
|
1006 else
|
|
1007 return;
|
|
1008
|
|
1009 primary = g_strdup_printf(_("Are you sure you want to remove %s?"), name);
|
|
1010
|
|
1011 /* XXX: anything to do with the returned ui-handle? */
|
15822
|
1012 purple_request_action(node, _("Confirm Remove"),
|
15817
|
1013 primary, sec,
|
|
1014 1, node, 2,
|
|
1015 _("Remove"), finch_blist_remove_node,
|
|
1016 _("Cancel"), NULL);
|
|
1017 g_free(primary);
|
|
1018 }
|
|
1019
|
|
1020 static void
|
15822
|
1021 finch_blist_toggle_tag_buddy(PurpleBlistNode *node)
|
15817
|
1022 {
|
|
1023 GList *iter;
|
|
1024 if (node == NULL)
|
|
1025 return;
|
15822
|
1026 if (PURPLE_BLIST_NODE_IS_CHAT(node) || PURPLE_BLIST_NODE_IS_GROUP(node))
|
15817
|
1027 return;
|
|
1028 if (ggblist->tagged && (iter = g_list_find(ggblist->tagged, node)) != NULL) {
|
|
1029 ggblist->tagged = g_list_delete_link(ggblist->tagged, iter);
|
|
1030 } else {
|
|
1031 ggblist->tagged = g_list_prepend(ggblist->tagged, node);
|
|
1032 }
|
15822
|
1033 if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
1034 node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
|
|
1035 update_buddy_display((PurpleBuddy*)node, ggblist);
|
15817
|
1036 }
|
|
1037
|
|
1038 static void
|
15822
|
1039 finch_blist_place_tagged(PurpleBlistNode *target)
|
15817
|
1040 {
|
15822
|
1041 PurpleGroup *tg = NULL;
|
|
1042 PurpleContact *tc = NULL;
|
15817
|
1043
|
|
1044 if (target == NULL)
|
|
1045 return;
|
|
1046
|
|
1047 /* This target resolution probably needs more clarification; for
|
|
1048 * example, if I tag a buddy in a contact, then place on
|
|
1049 * another buddy in the same contact, I probably intend to
|
|
1050 * place the tagged buddy immediately after (before?) the
|
|
1051 * target buddy -- this will simply move the tagged buddy
|
|
1052 * within the same contact without reference to position. */
|
15822
|
1053 if (PURPLE_BLIST_NODE_IS_GROUP(target))
|
|
1054 tg = (PurpleGroup*)target;
|
|
1055 else if (PURPLE_BLIST_NODE_IS_CONTACT(target))
|
|
1056 tc = (PurpleContact*)target;
|
15817
|
1057 else /* Buddy or Chat */
|
15822
|
1058 tc = (PurpleContact*)target->parent;
|
15817
|
1059
|
|
1060 if (ggblist->tagged) {
|
|
1061 GList *list = ggblist->tagged;
|
|
1062 ggblist->tagged = NULL;
|
|
1063
|
|
1064 while (list) {
|
15822
|
1065 PurpleBlistNode *node = list->data;
|
15817
|
1066 list = g_list_delete_link(list, list);
|
|
1067 if (tg) {
|
15822
|
1068 if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
1069 purple_blist_add_contact((PurpleContact*)node, tg, NULL);
|
15817
|
1070 else
|
15822
|
1071 purple_blist_add_buddy((PurpleBuddy*)node, NULL, tg, NULL);
|
15817
|
1072 } else {
|
15822
|
1073 if (PURPLE_BLIST_NODE_IS_BUDDY(node))
|
|
1074 purple_blist_add_buddy((PurpleBuddy*)node, tc,
|
|
1075 purple_buddy_get_group(purple_contact_get_priority_buddy(tc)), NULL);
|
|
1076 else if (PURPLE_BLIST_NODE_IS_CONTACT(node))
|
|
1077 purple_blist_merge_contact((PurpleContact*)node, target);
|
15817
|
1078 }
|
|
1079 }
|
|
1080 }
|
|
1081 }
|
|
1082
|
|
1083 static void
|
|
1084 context_menu_destroyed(GntWidget *widget, FinchBlist *ggblist)
|
|
1085 {
|
|
1086 ggblist->context = NULL;
|
|
1087 }
|
|
1088
|
|
1089 static void
|
|
1090 draw_context_menu(FinchBlist *ggblist)
|
|
1091 {
|
15822
|
1092 PurpleBlistNode *node = NULL;
|
15817
|
1093 GntWidget *context = NULL;
|
|
1094 GntTree *tree = NULL;
|
|
1095 int x, y, top, width;
|
|
1096 char *title = NULL;
|
|
1097
|
|
1098 tree = GNT_TREE(ggblist->tree);
|
|
1099
|
|
1100 node = gnt_tree_get_selection_data(tree);
|
|
1101
|
|
1102 if (ggblist->tooltip)
|
|
1103 remove_tooltip(ggblist);
|
|
1104
|
|
1105 ggblist->cnode = node;
|
|
1106
|
|
1107 ggblist->context = context = gnt_menu_new(GNT_MENU_POPUP);
|
|
1108 g_signal_connect(G_OBJECT(context), "destroy", G_CALLBACK(context_menu_destroyed), ggblist);
|
|
1109
|
|
1110 if (!node) {
|
|
1111 create_group_menu(GNT_MENU(context), NULL);
|
|
1112 title = g_strdup(_("Buddy List"));
|
15822
|
1113 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
15817
|
1114 create_buddy_menu(GNT_MENU(context),
|
15822
|
1115 purple_contact_get_priority_buddy((PurpleContact*)node));
|
|
1116 title = g_strdup(purple_contact_get_alias((PurpleContact*)node));
|
|
1117 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
|
1118 PurpleBuddy *buddy = (PurpleBuddy *)node;
|
15817
|
1119 create_buddy_menu(GNT_MENU(context), buddy);
|
15822
|
1120 title = g_strdup(purple_buddy_get_name(buddy));
|
|
1121 } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
|
|
1122 PurpleChat *chat = (PurpleChat*)node;
|
15817
|
1123 create_chat_menu(GNT_MENU(context), chat);
|
15822
|
1124 title = g_strdup(purple_chat_get_name(chat));
|
|
1125 } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
|
|
1126 PurpleGroup *group = (PurpleGroup *)node;
|
15817
|
1127 create_group_menu(GNT_MENU(context), group);
|
|
1128 title = g_strdup(group->name);
|
|
1129 }
|
|
1130
|
|
1131 append_extended_menu(GNT_MENU(context), node);
|
|
1132
|
|
1133 /* These are common for everything */
|
|
1134 if (node) {
|
|
1135 add_custom_action(GNT_MENU(context), _("Rename"),
|
15822
|
1136 PURPLE_CALLBACK(finch_blist_rename_node_cb), node);
|
15817
|
1137 add_custom_action(GNT_MENU(context), _("Remove"),
|
15822
|
1138 PURPLE_CALLBACK(finch_blist_remove_node_cb), node);
|
15817
|
1139
|
15822
|
1140 if (ggblist->tagged && (PURPLE_BLIST_NODE_IS_CONTACT(node)
|
|
1141 || PURPLE_BLIST_NODE_IS_GROUP(node))) {
|
15817
|
1142 add_custom_action(GNT_MENU(context), _("Place tagged"),
|
15822
|
1143 PURPLE_CALLBACK(finch_blist_place_tagged), node);
|
15817
|
1144 }
|
|
1145
|
15822
|
1146 if (PURPLE_BLIST_NODE_IS_BUDDY(node) || PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
15817
|
1147 add_custom_action(GNT_MENU(context), _("Toggle Tag"),
|
15822
|
1148 PURPLE_CALLBACK(finch_blist_toggle_tag_buddy), node);
|
15817
|
1149 }
|
|
1150 }
|
|
1151
|
|
1152 /* Set the position for the popup */
|
|
1153 gnt_widget_get_position(GNT_WIDGET(tree), &x, &y);
|
|
1154 gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL);
|
|
1155 top = gnt_tree_get_selection_visible_line(tree);
|
|
1156
|
|
1157 x += width;
|
|
1158 y += top - 1;
|
|
1159
|
|
1160 gnt_widget_set_position(context, x, y);
|
|
1161 gnt_screen_menu_show(GNT_MENU(context));
|
|
1162 g_free(title);
|
|
1163 }
|
|
1164
|
|
1165 static void
|
15822
|
1166 tooltip_for_buddy(PurpleBuddy *buddy, GString *str)
|
15817
|
1167 {
|
15822
|
1168 PurplePlugin *prpl;
|
|
1169 PurplePluginProtocolInfo *prpl_info;
|
|
1170 PurpleAccount *account;
|
|
1171 PurpleNotifyUserInfo *user_info;
|
|
1172 const char *alias = purple_buddy_get_alias(buddy);
|
15817
|
1173 char *tmp, *strip;
|
|
1174
|
15822
|
1175 user_info = purple_notify_user_info_new();
|
15817
|
1176
|
15822
|
1177 account = purple_buddy_get_account(buddy);
|
15817
|
1178
|
15822
|
1179 if (g_utf8_collate(purple_buddy_get_name(buddy), alias))
|
|
1180 purple_notify_user_info_add_pair(user_info, _("Nickname"), alias);
|
15817
|
1181
|
|
1182 tmp = g_strdup_printf("%s (%s)",
|
15822
|
1183 purple_account_get_username(account),
|
|
1184 purple_account_get_protocol_name(account));
|
|
1185 purple_notify_user_info_add_pair(user_info, _("Account"), tmp);
|
15817
|
1186 g_free(tmp);
|
|
1187
|
15822
|
1188 prpl = purple_find_prpl(purple_account_get_protocol_id(account));
|
|
1189 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
|
15817
|
1190 if (prpl_info && prpl_info->tooltip_text) {
|
|
1191 prpl_info->tooltip_text(buddy, user_info, TRUE);
|
|
1192 }
|
|
1193
|
15822
|
1194 if (purple_prefs_get_bool("/purple/gnt/blist/idletime")) {
|
|
1195 PurplePresence *pre = purple_buddy_get_presence(buddy);
|
|
1196 if (purple_presence_is_idle(pre)) {
|
|
1197 time_t idle = purple_presence_get_idle_time(pre);
|
15817
|
1198 if (idle > 0) {
|
15822
|
1199 char *st = purple_str_seconds_to_string(time(NULL) - idle);
|
|
1200 purple_notify_user_info_add_pair(user_info, _("Idle"), st);
|
15817
|
1201 g_free(st);
|
|
1202 }
|
|
1203 }
|
|
1204 }
|
|
1205
|
15822
|
1206 tmp = purple_notify_user_info_get_text_with_newline(user_info, "<BR>");
|
|
1207 purple_notify_user_info_destroy(user_info);
|
15817
|
1208
|
15822
|
1209 strip = purple_markup_strip_html(tmp);
|
15817
|
1210 g_string_append(str, strip);
|
|
1211 g_free(strip);
|
|
1212 g_free(tmp);
|
|
1213 }
|
|
1214
|
|
1215 static GString*
|
|
1216 make_sure_text_fits(GString *string)
|
|
1217 {
|
|
1218 int maxw = getmaxx(stdscr) - 3;
|
|
1219 char *str = gnt_util_onscreen_fit_string(string->str, maxw);
|
|
1220 string = g_string_assign(string, str);
|
|
1221 g_free(str);
|
|
1222 return string;
|
|
1223 }
|
|
1224
|
|
1225 static gboolean
|
|
1226 draw_tooltip_real(FinchBlist *ggblist)
|
|
1227 {
|
15822
|
1228 PurpleBlistNode *node;
|
15817
|
1229 int x, y, top, width, w, h;
|
|
1230 GString *str;
|
|
1231 GntTree *tree;
|
|
1232 GntWidget *widget, *box, *tv;
|
|
1233 char *title = NULL;
|
|
1234 int lastseen = 0;
|
|
1235
|
|
1236 widget = ggblist->tree;
|
|
1237 tree = GNT_TREE(widget);
|
|
1238
|
|
1239 if (!gnt_widget_has_focus(ggblist->tree) ||
|
|
1240 (ggblist->context && !GNT_WIDGET_IS_FLAG_SET(ggblist->context, GNT_WIDGET_INVISIBLE)))
|
|
1241 return FALSE;
|
|
1242
|
|
1243 if (ggblist->tooltip)
|
|
1244 {
|
|
1245 /* XXX: Once we can properly redraw on expose events, this can be removed at the end
|
|
1246 * to avoid the blinking*/
|
|
1247 remove_tooltip(ggblist);
|
|
1248 }
|
|
1249
|
|
1250 node = gnt_tree_get_selection_data(tree);
|
|
1251 if (!node)
|
|
1252 return FALSE;
|
|
1253
|
|
1254 str = g_string_new("");
|
|
1255
|
15822
|
1256 if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
|
|
1257 PurpleBuddy *pr = purple_contact_get_priority_buddy((PurpleContact*)node);
|
|
1258 gboolean offline = !PURPLE_BUDDY_IS_ONLINE(pr);
|
|
1259 gboolean showoffline = purple_prefs_get_bool(PREF_ROOT "/showoffline");
|
|
1260 const char *name = purple_buddy_get_name(pr);
|
15817
|
1261
|
|
1262 title = g_strdup(name);
|
|
1263 tooltip_for_buddy(pr, str);
|
|
1264 for (node = node->child; node; node = node->next) {
|
15822
|
1265 PurpleBuddy *buddy = (PurpleBuddy*)node;
|
15817
|
1266 if (offline) {
|
15822
|
1267 int value = purple_blist_node_get_int(node, "last_seen");
|
15817
|
1268 if (value > lastseen)
|
|
1269 lastseen = value;
|
|
1270 }
|
15822
|
1271 if (node == (PurpleBlistNode*)pr)
|
15817
|
1272 continue;
|
15822
|
1273 if (!purple_account_is_connected(buddy->account))
|
15817
|
1274 continue;
|
15822
|
1275 if (!showoffline && !PURPLE_BUDDY_IS_ONLINE(buddy))
|
15817
|
1276 continue;
|
|
1277 str = g_string_append(str, "\n----------\n");
|
|
1278 tooltip_for_buddy(buddy, str);
|
|
1279 }
|
15822
|
1280 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
|
1281 PurpleBuddy *buddy = (PurpleBuddy *)node;
|
15817
|
1282 tooltip_for_buddy(buddy, str);
|
15822
|
1283 title = g_strdup(purple_buddy_get_name(buddy));
|
|
1284 if (!PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node))
|
|
1285 lastseen = purple_blist_node_get_int(node, "last_seen");
|
|
1286 } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
|
|
1287 PurpleGroup *group = (PurpleGroup *)node;
|
15817
|
1288
|
|
1289 g_string_append_printf(str, _("Online: %d\nTotal: %d"),
|
15822
|
1290 purple_blist_get_group_online_count(group),
|
|
1291 purple_blist_get_group_size(group, FALSE));
|
15817
|
1292
|
|
1293 title = g_strdup(group->name);
|
15822
|
1294 } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
|
|
1295 PurpleChat *chat = (PurpleChat *)node;
|
|
1296 PurpleAccount *account = chat->account;
|
15817
|
1297
|
|
1298 g_string_append_printf(str, _("Account: %s (%s)"),
|
15822
|
1299 purple_account_get_username(account),
|
|
1300 purple_account_get_protocol_name(account));
|
15817
|
1301
|
15822
|
1302 title = g_strdup(purple_chat_get_name(chat));
|
15817
|
1303 } else {
|
|
1304 g_string_free(str, TRUE);
|
|
1305 return FALSE;
|
|
1306 }
|
|
1307
|
|
1308 if (lastseen > 0) {
|
15822
|
1309 char *tmp = purple_str_seconds_to_string(time(NULL) - lastseen);
|
15817
|
1310 g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp);
|
|
1311 g_free(tmp);
|
|
1312 }
|
|
1313
|
|
1314 gnt_widget_get_position(widget, &x, &y);
|
|
1315 gnt_widget_get_size(widget, &width, NULL);
|
|
1316 top = gnt_tree_get_selection_visible_line(tree);
|
|
1317
|
|
1318 x += width;
|
|
1319 y += top - 1;
|
|
1320
|
|
1321 box = gnt_box_new(FALSE, FALSE);
|
|
1322 gnt_box_set_toplevel(GNT_BOX(box), TRUE);
|
|
1323 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_NO_SHADOW);
|
|
1324 gnt_box_set_title(GNT_BOX(box), title);
|
|
1325
|
|
1326 str = make_sure_text_fits(str);
|
|
1327 gnt_util_get_text_bound(str->str, &w, &h);
|
|
1328 h = MAX(2, h);
|
|
1329 tv = gnt_text_view_new();
|
|
1330 gnt_widget_set_size(tv, w + 1, h);
|
|
1331 gnt_box_add_widget(GNT_BOX(box), tv);
|
|
1332
|
|
1333 gnt_widget_set_position(box, x, y);
|
|
1334 GNT_WIDGET_UNSET_FLAGS(box, GNT_WIDGET_CAN_TAKE_FOCUS);
|
|
1335 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT);
|
|
1336 gnt_widget_draw(box);
|
|
1337
|
|
1338 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), str->str, GNT_TEXT_FLAG_NORMAL);
|
|
1339 gnt_text_view_scroll(GNT_TEXT_VIEW(tv), 0);
|
|
1340
|
|
1341 g_free(title);
|
|
1342 g_string_free(str, TRUE);
|
|
1343 ggblist->tooltip = box;
|
|
1344 ggblist->tnode = node;
|
|
1345
|
|
1346 gnt_widget_set_name(ggblist->tooltip, "tooltip");
|
|
1347 return FALSE;
|
|
1348 }
|
|
1349
|
|
1350 static void
|
|
1351 draw_tooltip(FinchBlist *ggblist)
|
|
1352 {
|
|
1353 /* When an account has signed off, it removes one buddy at a time.
|
|
1354 * Drawing the tooltip after removing each buddy is expensive. On
|
|
1355 * top of that, if the selected buddy belongs to the disconnected
|
|
1356 * account, then retreiving the tooltip for that causes crash. So
|
|
1357 * let's make sure we wait for all the buddies to be removed first.*/
|
|
1358 int id = g_timeout_add(0, (GSourceFunc)draw_tooltip_real, ggblist);
|
|
1359 g_object_set_data_full(G_OBJECT(ggblist->window), "draw_tooltip_calback",
|
|
1360 GINT_TO_POINTER(id), (GDestroyNotify)g_source_remove);
|
|
1361 }
|
|
1362
|
|
1363 static void
|
|
1364 selection_changed(GntWidget *widget, gpointer old, gpointer current, FinchBlist *ggblist)
|
|
1365 {
|
|
1366 draw_tooltip(ggblist);
|
|
1367 }
|
|
1368
|
|
1369 static gboolean
|
|
1370 context_menu(GntWidget *widget, FinchBlist *ggblist)
|
|
1371 {
|
|
1372 draw_context_menu(ggblist);
|
|
1373 return TRUE;
|
|
1374 }
|
|
1375
|
|
1376 static gboolean
|
|
1377 key_pressed(GntWidget *widget, const char *text, FinchBlist *ggblist)
|
|
1378 {
|
|
1379 if (text[0] == 27 && text[1] == 0) {
|
|
1380 /* Escape was pressed */
|
|
1381 remove_peripherals(ggblist);
|
|
1382 } else if (strcmp(text, GNT_KEY_CTRL_O) == 0) {
|
15822
|
1383 purple_prefs_set_bool(PREF_ROOT "/showoffline",
|
|
1384 !purple_prefs_get_bool(PREF_ROOT "/showoffline"));
|
15817
|
1385 } else if (GNT_TREE(ggblist->tree)->search == NULL) {
|
|
1386 if (strcmp(text, "t") == 0) {
|
|
1387 finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
|
|
1388 gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down");
|
|
1389 } else if (strcmp(text, "a") == 0) {
|
|
1390 finch_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
|
|
1391 } else
|
|
1392 return FALSE;
|
|
1393 } else
|
|
1394 return FALSE;
|
|
1395
|
|
1396 return TRUE;
|
|
1397 }
|
|
1398
|
|
1399 static void
|
15822
|
1400 update_buddy_display(PurpleBuddy *buddy, FinchBlist *ggblist)
|
15817
|
1401 {
|
15822
|
1402 PurpleContact *contact;
|
15817
|
1403 GntTextFormatFlags bflag = 0, cflag = 0;
|
|
1404
|
15822
|
1405 contact = purple_buddy_get_contact(buddy);
|
15817
|
1406
|
15822
|
1407 gnt_tree_change_text(GNT_TREE(ggblist->tree), buddy, 0, get_display_name((PurpleBlistNode*)buddy));
|
|
1408 gnt_tree_change_text(GNT_TREE(ggblist->tree), contact, 0, get_display_name((PurpleBlistNode*)contact));
|
15817
|
1409
|
|
1410 if (ggblist->tagged && g_list_find(ggblist->tagged, buddy))
|
|
1411 bflag |= GNT_TEXT_FLAG_BOLD;
|
|
1412 if (ggblist->tagged && g_list_find(ggblist->tagged, contact))
|
|
1413 cflag |= GNT_TEXT_FLAG_BOLD;
|
|
1414
|
15822
|
1415 if (ggblist->tnode == (PurpleBlistNode*)buddy)
|
15817
|
1416 draw_tooltip(ggblist);
|
|
1417
|
15822
|
1418 if (purple_presence_is_idle(purple_buddy_get_presence(buddy))) {
|
15817
|
1419 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, bflag | GNT_TEXT_FLAG_DIM);
|
|
1420 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, cflag | GNT_TEXT_FLAG_DIM);
|
|
1421 } else {
|
|
1422 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, bflag);
|
|
1423 gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, cflag);
|
|
1424 }
|
|
1425 }
|
|
1426
|
|
1427 static void
|
15822
|
1428 buddy_status_changed(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *now, FinchBlist *ggblist)
|
15817
|
1429 {
|
|
1430 update_buddy_display(buddy, ggblist);
|
|
1431 }
|
|
1432
|
|
1433 static void
|
15822
|
1434 buddy_idle_changed(PurpleBuddy *buddy, int old, int new, FinchBlist *ggblist)
|
15817
|
1435 {
|
|
1436 update_buddy_display(buddy, ggblist);
|
|
1437 }
|
|
1438
|
|
1439 static void
|
|
1440 remove_peripherals(FinchBlist *ggblist)
|
|
1441 {
|
|
1442 if (ggblist->tooltip)
|
|
1443 remove_tooltip(ggblist);
|
|
1444 else if (ggblist->context)
|
|
1445 gnt_widget_destroy(ggblist->context);
|
|
1446 }
|
|
1447
|
|
1448 static void
|
|
1449 size_changed_cb(GntWidget *w, int wi, int h)
|
|
1450 {
|
|
1451 int width, height;
|
|
1452 gnt_widget_get_size(w, &width, &height);
|
15822
|
1453 purple_prefs_set_int(PREF_ROOT "/size/width", width);
|
|
1454 purple_prefs_set_int(PREF_ROOT "/size/height", height);
|
15817
|
1455 }
|
|
1456
|
|
1457 static void
|
|
1458 save_position_cb(GntWidget *w, int x, int y)
|
|
1459 {
|
15822
|
1460 purple_prefs_set_int(PREF_ROOT "/position/x", x);
|
|
1461 purple_prefs_set_int(PREF_ROOT "/position/y", y);
|
15817
|
1462 }
|
|
1463
|
|
1464 static void
|
|
1465 reset_blist_window(GntWidget *window, gpointer null)
|
|
1466 {
|
15822
|
1467 PurpleBlistNode *node;
|
|
1468 purple_signals_disconnect_by_handle(finch_blist_get_handle());
|
|
1469 purple_get_blist()->ui_data = NULL;
|
15817
|
1470
|
15822
|
1471 node = purple_blist_get_root();
|
15817
|
1472 while (node) {
|
|
1473 node->ui_data = NULL;
|
15822
|
1474 node = purple_blist_node_next(node, TRUE);
|
15817
|
1475 }
|
|
1476
|
|
1477 if (ggblist->typing)
|
|
1478 g_source_remove(ggblist->typing);
|
|
1479 remove_peripherals(ggblist);
|
|
1480 if (ggblist->tagged)
|
|
1481 g_list_free(ggblist->tagged);
|
|
1482 g_free(ggblist);
|
|
1483 ggblist = NULL;
|
|
1484 }
|
|
1485
|
|
1486 static void
|
|
1487 populate_buddylist()
|
|
1488 {
|
15822
|
1489 PurpleBlistNode *node;
|
|
1490 PurpleBuddyList *list;
|
15817
|
1491
|
15822
|
1492 if (strcmp(purple_prefs_get_string(PREF_ROOT "/sort_type"), "text") == 0) {
|
15817
|
1493 gnt_tree_set_compare_func(GNT_TREE(ggblist->tree),
|
|
1494 (GCompareFunc)blist_node_compare_text);
|
15822
|
1495 } else if (strcmp(purple_prefs_get_string(PREF_ROOT "/sort_type"), "status") == 0) {
|
15817
|
1496 gnt_tree_set_compare_func(GNT_TREE(ggblist->tree),
|
|
1497 (GCompareFunc)blist_node_compare_status);
|
15822
|
1498 } else if (strcmp(purple_prefs_get_string(PREF_ROOT "/sort_type"), "log") == 0) {
|
15817
|
1499 gnt_tree_set_compare_func(GNT_TREE(ggblist->tree),
|
|
1500 (GCompareFunc)blist_node_compare_log);
|
|
1501 }
|
|
1502
|
15822
|
1503 list = purple_get_blist();
|
|
1504 node = purple_blist_get_root();
|
15817
|
1505 while (node)
|
|
1506 {
|
|
1507 node_update(list, node);
|
15822
|
1508 node = purple_blist_node_next(node, FALSE);
|
15817
|
1509 }
|
|
1510 }
|
|
1511
|
|
1512 static void
|
|
1513 destroy_status_list(GList *list)
|
|
1514 {
|
|
1515 g_list_foreach(list, (GFunc)g_free, NULL);
|
|
1516 g_list_free(list);
|
|
1517 }
|
|
1518
|
|
1519 static void
|
|
1520 populate_status_dropdown()
|
|
1521 {
|
|
1522 int i;
|
|
1523 GList *iter;
|
|
1524 GList *items = NULL;
|
|
1525 StatusBoxItem *item = NULL;
|
|
1526
|
|
1527 /* First the primitives */
|
15822
|
1528 PurpleStatusPrimitive prims[] = {PURPLE_STATUS_AVAILABLE, PURPLE_STATUS_AWAY,
|
|
1529 PURPLE_STATUS_INVISIBLE, PURPLE_STATUS_OFFLINE, PURPLE_STATUS_UNSET};
|
15817
|
1530
|
|
1531 gnt_combo_box_remove_all(GNT_COMBO_BOX(ggblist->status));
|
|
1532
|
15822
|
1533 for (i = 0; prims[i] != PURPLE_STATUS_UNSET; i++)
|
15817
|
1534 {
|
|
1535 item = g_new0(StatusBoxItem, 1);
|
|
1536 item->type = STATUS_PRIMITIVE;
|
|
1537 item->u.prim = prims[i];
|
|
1538 items = g_list_prepend(items, item);
|
|
1539 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
|
15822
|
1540 purple_primitive_get_name_from_type(prims[i]));
|
15817
|
1541 }
|
|
1542
|
|
1543 /* Now the popular statuses */
|
15822
|
1544 for (iter = purple_savedstatuses_get_popular(6); iter; iter = iter->next)
|
15817
|
1545 {
|
|
1546 item = g_new0(StatusBoxItem, 1);
|
|
1547 item->type = STATUS_SAVED_POPULAR;
|
|
1548 item->u.saved = iter->data;
|
|
1549 items = g_list_prepend(items, item);
|
|
1550 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
|
15822
|
1551 purple_savedstatus_get_title(iter->data));
|
15817
|
1552 }
|
|
1553
|
|
1554 /* New savedstatus */
|
|
1555 item = g_new0(StatusBoxItem, 1);
|
|
1556 item->type = STATUS_SAVED_NEW;
|
|
1557 items = g_list_prepend(items, item);
|
|
1558 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
|
|
1559 _("New..."));
|
|
1560
|
|
1561 /* More savedstatuses */
|
|
1562 item = g_new0(StatusBoxItem, 1);
|
|
1563 item->type = STATUS_SAVED_ALL;
|
|
1564 items = g_list_prepend(items, item);
|
|
1565 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
|
|
1566 _("Saved..."));
|
|
1567
|
|
1568 /* The keys for the combobox are created here, and never used
|
|
1569 * anywhere else. So make sure the keys are freed when the widget
|
|
1570 * is destroyed. */
|
|
1571 g_object_set_data_full(G_OBJECT(ggblist->status), "list of statuses",
|
|
1572 items, (GDestroyNotify)destroy_status_list);
|
|
1573 }
|
|
1574
|
|
1575 static void
|
15822
|
1576 redraw_blist(const char *name, PurplePrefType type, gconstpointer val, gpointer data)
|
15817
|
1577 {
|
15822
|
1578 PurpleBlistNode *node, *sel;
|
15817
|
1579 if (ggblist == NULL || ggblist->window == NULL)
|
|
1580 return;
|
|
1581
|
|
1582 sel = gnt_tree_get_selection_data(GNT_TREE(ggblist->tree));
|
|
1583 gnt_tree_remove_all(GNT_TREE(ggblist->tree));
|
15822
|
1584 node = purple_blist_get_root();
|
|
1585 for (; node; node = purple_blist_node_next(node, TRUE))
|
15817
|
1586 node->ui_data = NULL;
|
|
1587 populate_buddylist();
|
|
1588 gnt_tree_set_selected(GNT_TREE(ggblist->tree), sel);
|
|
1589 draw_tooltip(ggblist);
|
|
1590 }
|
|
1591
|
|
1592 void finch_blist_init()
|
|
1593 {
|
15822
|
1594 purple_prefs_add_none(PREF_ROOT);
|
|
1595 purple_prefs_add_none(PREF_ROOT "/size");
|
|
1596 purple_prefs_add_int(PREF_ROOT "/size/width", 20);
|
|
1597 purple_prefs_add_int(PREF_ROOT "/size/height", 17);
|
|
1598 purple_prefs_add_none(PREF_ROOT "/position");
|
|
1599 purple_prefs_add_int(PREF_ROOT "/position/x", 0);
|
|
1600 purple_prefs_add_int(PREF_ROOT "/position/y", 0);
|
|
1601 purple_prefs_add_bool(PREF_ROOT "/idletime", TRUE);
|
|
1602 purple_prefs_add_bool(PREF_ROOT "/showoffline", FALSE);
|
|
1603 purple_prefs_add_string(PREF_ROOT "/sort_type", "text");
|
15817
|
1604
|
15822
|
1605 purple_prefs_connect_callback(finch_blist_get_handle(),
|
15817
|
1606 PREF_ROOT "/showoffline", redraw_blist, NULL);
|
15822
|
1607 purple_prefs_connect_callback(finch_blist_get_handle(),
|
15817
|
1608 PREF_ROOT "/sort_type", redraw_blist, NULL);
|
|
1609
|
15822
|
1610 purple_signal_connect(purple_connections_get_handle(), "signed-on", purple_blist_get_handle(),
|
15817
|
1611 G_CALLBACK(account_signed_on_cb), NULL);
|
|
1612 return;
|
|
1613 }
|
|
1614
|
|
1615 static gboolean
|
|
1616 remove_typing_cb(gpointer null)
|
|
1617 {
|
15822
|
1618 PurpleSavedStatus *current;
|
15817
|
1619 const char *message, *newmessage;
|
15822
|
1620 PurpleStatusPrimitive prim, newprim;
|
15817
|
1621 StatusBoxItem *item;
|
|
1622
|
15822
|
1623 current = purple_savedstatus_get_current();
|
|
1624 message = purple_savedstatus_get_message(current);
|
|
1625 prim = purple_savedstatus_get_type(current);
|
15817
|
1626
|
|
1627 newmessage = gnt_entry_get_text(GNT_ENTRY(ggblist->statustext));
|
|
1628 item = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(ggblist->status));
|
|
1629 g_return_val_if_fail(item->type == STATUS_PRIMITIVE, FALSE);
|
|
1630 newprim = item->u.prim;
|
|
1631
|
|
1632 if (newprim != prim || ((message && !newmessage) ||
|
|
1633 (!message && newmessage) ||
|
|
1634 (message && newmessage && g_utf8_collate(message, newmessage) != 0)))
|
|
1635 {
|
15822
|
1636 PurpleSavedStatus *status = purple_savedstatus_find_transient_by_type_and_message(newprim, newmessage);
|
15817
|
1637 /* Holy Crap! That's a LAWNG function name */
|
|
1638 if (status == NULL)
|
|
1639 {
|
15822
|
1640 status = purple_savedstatus_new(NULL, newprim);
|
|
1641 purple_savedstatus_set_message(status, newmessage);
|
15817
|
1642 }
|
|
1643
|
15822
|
1644 purple_savedstatus_activate(status);
|
15817
|
1645 }
|
|
1646
|
|
1647 gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree);
|
|
1648 if (ggblist->typing)
|
|
1649 g_source_remove(ggblist->typing);
|
|
1650 ggblist->typing = 0;
|
|
1651 return FALSE;
|
|
1652 }
|
|
1653
|
|
1654 static void
|
|
1655 status_selection_changed(GntComboBox *box, StatusBoxItem *old, StatusBoxItem *now, gpointer null)
|
|
1656 {
|
|
1657 gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), NULL);
|
|
1658 if (now->type == STATUS_SAVED_POPULAR)
|
|
1659 {
|
|
1660 /* Set the status immediately */
|
15822
|
1661 purple_savedstatus_activate(now->u.saved);
|
15817
|
1662 }
|
|
1663 else if (now->type == STATUS_PRIMITIVE)
|
|
1664 {
|
|
1665 /* Move the focus to the entry box */
|
|
1666 /* XXX: Make sure the selected status can have a message */
|
|
1667 gnt_box_move_focus(GNT_BOX(ggblist->window), 1);
|
|
1668 ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL);
|
|
1669 }
|
|
1670 else if (now->type == STATUS_SAVED_ALL)
|
|
1671 {
|
|
1672 /* Restore the selection to reflect current status. */
|
15822
|
1673 savedstatus_changed(purple_savedstatus_get_current(), NULL);
|
15817
|
1674 gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree);
|
|
1675 finch_savedstatus_show_all();
|
|
1676 }
|
|
1677 else if (now->type == STATUS_SAVED_NEW)
|
|
1678 {
|
15822
|
1679 savedstatus_changed(purple_savedstatus_get_current(), NULL);
|
15817
|
1680 gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree);
|
|
1681 finch_savedstatus_edit(NULL);
|
|
1682 }
|
|
1683 else
|
|
1684 g_return_if_reached();
|
|
1685 }
|
|
1686
|
|
1687 static gboolean
|
|
1688 status_text_changed(GntEntry *entry, const char *text, gpointer null)
|
|
1689 {
|
|
1690 if ((text[0] == 27 || (text[0] == '\t' && text[1] == '\0')) && ggblist->typing == 0)
|
|
1691 return FALSE;
|
|
1692
|
|
1693 if (ggblist->typing)
|
|
1694 g_source_remove(ggblist->typing);
|
|
1695 ggblist->typing = 0;
|
|
1696
|
|
1697 if (text[0] == '\r' && text[1] == 0)
|
|
1698 {
|
|
1699 /* Set the status only after you press 'Enter' */
|
|
1700 remove_typing_cb(NULL);
|
|
1701 return TRUE;
|
|
1702 }
|
|
1703
|
|
1704 ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL);
|
|
1705 return FALSE;
|
|
1706 }
|
|
1707
|
|
1708 static void
|
15822
|
1709 savedstatus_changed(PurpleSavedStatus *now, PurpleSavedStatus *old)
|
15817
|
1710 {
|
|
1711 GList *list;
|
15822
|
1712 PurpleStatusPrimitive prim;
|
15817
|
1713 const char *message;
|
|
1714 gboolean found = FALSE, saved = TRUE;
|
|
1715
|
|
1716 if (!ggblist)
|
|
1717 return;
|
|
1718
|
|
1719 /* Block the signals we don't want to emit */
|
|
1720 g_signal_handlers_block_matched(ggblist->status, G_SIGNAL_MATCH_FUNC,
|
|
1721 0, 0, NULL, status_selection_changed, NULL);
|
|
1722 g_signal_handlers_block_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC,
|
|
1723 0, 0, NULL, status_text_changed, NULL);
|
|
1724
|
15822
|
1725 prim = purple_savedstatus_get_type(now);
|
|
1726 message = purple_savedstatus_get_message(now);
|
15817
|
1727
|
|
1728 /* Rebuild the status dropdown */
|
|
1729 populate_status_dropdown();
|
|
1730
|
|
1731 while (!found) {
|
|
1732 list = g_object_get_data(G_OBJECT(ggblist->status), "list of statuses");
|
|
1733 for (; list; list = list->next)
|
|
1734 {
|
|
1735 StatusBoxItem *item = list->data;
|
|
1736 if ((saved && item->type != STATUS_PRIMITIVE && item->u.saved == now) ||
|
|
1737 (!saved && item->type == STATUS_PRIMITIVE && item->u.prim == prim))
|
|
1738 {
|
15822
|
1739 char *mess = purple_unescape_html(message);
|
15817
|
1740 gnt_combo_box_set_selected(GNT_COMBO_BOX(ggblist->status), item);
|
|
1741 gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), mess);
|
|
1742 gnt_widget_draw(ggblist->status);
|
|
1743 g_free(mess);
|
|
1744 found = TRUE;
|
|
1745 break;
|
|
1746 }
|
|
1747 }
|
|
1748 if (!saved)
|
|
1749 break;
|
|
1750 saved = FALSE;
|
|
1751 }
|
|
1752
|
|
1753 g_signal_handlers_unblock_matched(ggblist->status, G_SIGNAL_MATCH_FUNC,
|
|
1754 0, 0, NULL, status_selection_changed, NULL);
|
|
1755 g_signal_handlers_unblock_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC,
|
|
1756 0, 0, NULL, status_text_changed, NULL);
|
|
1757 }
|
|
1758
|
|
1759 static int
|
15822
|
1760 blist_node_compare_text(PurpleBlistNode *n1, PurpleBlistNode *n2)
|
15817
|
1761 {
|
|
1762 const char *s1, *s2;
|
|
1763 char *us1, *us2;
|
|
1764 int ret;
|
|
1765
|
|
1766 g_return_val_if_fail(n1->type == n2->type, -1);
|
|
1767
|
|
1768 switch (n1->type)
|
|
1769 {
|
15822
|
1770 case PURPLE_BLIST_GROUP_NODE:
|
|
1771 s1 = ((PurpleGroup*)n1)->name;
|
|
1772 s2 = ((PurpleGroup*)n2)->name;
|
15817
|
1773 break;
|
15822
|
1774 case PURPLE_BLIST_CHAT_NODE:
|
|
1775 s1 = purple_chat_get_name((PurpleChat*)n1);
|
|
1776 s2 = purple_chat_get_name((PurpleChat*)n2);
|
15817
|
1777 break;
|
15822
|
1778 case PURPLE_BLIST_BUDDY_NODE:
|
|
1779 return purple_presence_compare(purple_buddy_get_presence((PurpleBuddy*)n1),
|
|
1780 purple_buddy_get_presence((PurpleBuddy*)n2));
|
15817
|
1781 break;
|
15822
|
1782 case PURPLE_BLIST_CONTACT_NODE:
|
|
1783 s1 = purple_contact_get_alias((PurpleContact*)n1);
|
|
1784 s2 = purple_contact_get_alias((PurpleContact*)n2);
|
15817
|
1785 break;
|
|
1786 default:
|
|
1787 return -1;
|
|
1788 }
|
|
1789
|
|
1790 us1 = g_utf8_strup(s1, -1);
|
|
1791 us2 = g_utf8_strup(s2, -1);
|
|
1792 ret = g_utf8_collate(us1, us2);
|
|
1793 g_free(us1);
|
|
1794 g_free(us2);
|
|
1795
|
|
1796 return ret;
|
|
1797 }
|
|
1798
|
|
1799 static int
|
15822
|
1800 blist_node_compare_status(PurpleBlistNode *n1, PurpleBlistNode *n2)
|
15817
|
1801 {
|
|
1802 int ret;
|
|
1803
|
|
1804 g_return_val_if_fail(n1->type == n2->type, -1);
|
|
1805
|
|
1806 switch (n1->type) {
|
15822
|
1807 case PURPLE_BLIST_CONTACT_NODE:
|
|
1808 n1 = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)n1);
|
|
1809 n2 = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)n2);
|
15817
|
1810 /* now compare the presence of the priority buddies */
|
15822
|
1811 case PURPLE_BLIST_BUDDY_NODE:
|
|
1812 ret = purple_presence_compare(purple_buddy_get_presence((PurpleBuddy*)n1),
|
|
1813 purple_buddy_get_presence((PurpleBuddy*)n2));
|
15817
|
1814 if (ret != 0)
|
|
1815 return ret;
|
|
1816 break;
|
|
1817 default:
|
|
1818 break;
|
|
1819 }
|
|
1820
|
|
1821 /* Sort alphabetically if presence is not comparable */
|
|
1822 ret = blist_node_compare_text(n1, n2);
|
|
1823
|
|
1824 return ret;
|
|
1825 }
|
|
1826
|
|
1827 static int
|
15822
|
1828 get_contact_log_size(PurpleBlistNode *c)
|
15817
|
1829 {
|
|
1830 int log = 0;
|
15822
|
1831 PurpleBlistNode *node;
|
15817
|
1832
|
|
1833 for (node = c->child; node; node = node->next) {
|
15822
|
1834 PurpleBuddy *b = (PurpleBuddy*)node;
|
|
1835 log += purple_log_get_total_size(PURPLE_LOG_IM, b->name, b->account);
|
15817
|
1836 }
|
|
1837
|
|
1838 return log;
|
|
1839 }
|
|
1840
|
|
1841 static int
|
15822
|
1842 blist_node_compare_log(PurpleBlistNode *n1, PurpleBlistNode *n2)
|
15817
|
1843 {
|
|
1844 int ret;
|
15822
|
1845 PurpleBuddy *b1, *b2;
|
15817
|
1846
|
|
1847 g_return_val_if_fail(n1->type == n2->type, -1);
|
|
1848
|
|
1849 switch (n1->type) {
|
15822
|
1850 case PURPLE_BLIST_BUDDY_NODE:
|
|
1851 b1 = (PurpleBuddy*)n1;
|
|
1852 b2 = (PurpleBuddy*)n2;
|
|
1853 ret = purple_log_get_total_size(PURPLE_LOG_IM, b2->name, b2->account) -
|
|
1854 purple_log_get_total_size(PURPLE_LOG_IM, b1->name, b1->account);
|
15817
|
1855 if (ret != 0)
|
|
1856 return ret;
|
|
1857 break;
|
15822
|
1858 case PURPLE_BLIST_CONTACT_NODE:
|
15817
|
1859 ret = get_contact_log_size(n2) - get_contact_log_size(n1);
|
|
1860 if (ret != 0)
|
|
1861 return ret;
|
|
1862 break;
|
|
1863 default:
|
|
1864 break;
|
|
1865 }
|
|
1866 ret = blist_node_compare_text(n1, n2);
|
|
1867 return ret;
|
|
1868 }
|
|
1869
|
|
1870 static gboolean
|
|
1871 blist_clicked(GntTree *tree, GntMouseEvent event, int x, int y, gpointer ggblist)
|
|
1872 {
|
|
1873 if (event == GNT_RIGHT_MOUSE_DOWN) {
|
|
1874 draw_context_menu(ggblist);
|
|
1875 }
|
|
1876 return FALSE;
|
|
1877 }
|
|
1878
|
|
1879 static void
|
|
1880 plugin_action(GntMenuItem *item, gpointer data)
|
|
1881 {
|
15822
|
1882 PurplePluginAction *action = data;
|
15817
|
1883 if (action && action->callback)
|
|
1884 action->callback(action);
|
|
1885 }
|
|
1886
|
|
1887 static void
|
15822
|
1888 build_plugin_actions(GntMenuItem *item, PurplePlugin *plugin, gpointer context)
|
15817
|
1889 {
|
|
1890 GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP);
|
|
1891 GList *actions;
|
|
1892 GntMenuItem *menuitem;
|
|
1893
|
|
1894 gnt_menuitem_set_submenu(item, GNT_MENU(sub));
|
15822
|
1895 for (actions = PURPLE_PLUGIN_ACTIONS(plugin, context); actions;
|
15817
|
1896 actions = g_list_delete_link(actions, actions)) {
|
|
1897 if (actions->data) {
|
15822
|
1898 PurplePluginAction *action = actions->data;
|
15817
|
1899 action->plugin = plugin;
|
|
1900 action->context = context;
|
|
1901 menuitem = gnt_menuitem_new(action->label);
|
|
1902 gnt_menu_add_item(GNT_MENU(sub), menuitem);
|
|
1903
|
|
1904 gnt_menuitem_set_callback(menuitem, plugin_action, action);
|
|
1905 g_object_set_data_full(G_OBJECT(menuitem), "plugin_action",
|
15822
|
1906 action, (GDestroyNotify)purple_plugin_action_free);
|
15817
|
1907 }
|
|
1908 }
|
|
1909 }
|
|
1910
|
|
1911 static void
|
|
1912 reconstruct_plugins_menu()
|
|
1913 {
|
|
1914 GntWidget *sub;
|
|
1915 GntMenuItem *plg;
|
|
1916 GList *iter;
|
|
1917
|
|
1918 if (!ggblist)
|
|
1919 return;
|
|
1920
|
|
1921 if (ggblist->plugins == NULL)
|
|
1922 ggblist->plugins = gnt_menuitem_new(_("Plugins"));
|
|
1923
|
|
1924 plg = ggblist->plugins;
|
|
1925 sub = gnt_menu_new(GNT_MENU_POPUP);
|
|
1926 gnt_menuitem_set_submenu(plg, GNT_MENU(sub));
|
|
1927
|
15822
|
1928 for (iter = purple_plugins_get_loaded(); iter; iter = iter->next) {
|
|
1929 PurplePlugin *plugin = iter->data;
|
15817
|
1930 GntMenuItem *item;
|
15822
|
1931 if (PURPLE_IS_PROTOCOL_PLUGIN(plugin))
|
15817
|
1932 continue;
|
|
1933
|
15822
|
1934 if (!PURPLE_PLUGIN_HAS_ACTIONS(plugin))
|
15817
|
1935 continue;
|
|
1936
|
|
1937 item = gnt_menuitem_new(_(plugin->info->name));
|
|
1938 gnt_menu_add_item(GNT_MENU(sub), item);
|
|
1939 build_plugin_actions(item, plugin, NULL);
|
|
1940 }
|
|
1941 }
|
|
1942
|
|
1943 static void
|
|
1944 reconstruct_accounts_menu()
|
|
1945 {
|
|
1946 GntWidget *sub;
|
|
1947 GntMenuItem *acc, *item;
|
|
1948 GList *iter;
|
|
1949
|
|
1950 if (!ggblist)
|
|
1951 return;
|
|
1952
|
|
1953 if (ggblist->accounts == NULL)
|
|
1954 ggblist->accounts = gnt_menuitem_new(_("Accounts"));
|
|
1955
|
|
1956 acc = ggblist->accounts;
|
|
1957 sub = gnt_menu_new(GNT_MENU_POPUP);
|
|
1958 gnt_menuitem_set_submenu(acc, GNT_MENU(sub));
|
|
1959
|
15822
|
1960 for (iter = purple_accounts_get_all_active(); iter;
|
15817
|
1961 iter = g_list_delete_link(iter, iter)) {
|
15822
|
1962 PurpleAccount *account = iter->data;
|
|
1963 PurpleConnection *gc = purple_account_get_connection(account);
|
|
1964 PurplePlugin *prpl;
|
15817
|
1965
|
15822
|
1966 if (!gc || !PURPLE_CONNECTION_IS_CONNECTED(gc))
|
15817
|
1967 continue;
|
|
1968 prpl = gc->prpl;
|
|
1969
|
15822
|
1970 if (PURPLE_PLUGIN_HAS_ACTIONS(prpl)) {
|
|
1971 item = gnt_menuitem_new(purple_account_get_username(account));
|
15817
|
1972 gnt_menu_add_item(GNT_MENU(sub), item);
|
|
1973 build_plugin_actions(item, prpl, gc);
|
|
1974 }
|
|
1975 }
|
|
1976 }
|
|
1977
|
|
1978 static void
|
|
1979 account_signed_on_cb()
|
|
1980 {
|
15822
|
1981 PurpleBlistNode *node;
|
15817
|
1982
|
15822
|
1983 for (node = purple_blist_get_root(); node;
|
|
1984 node = purple_blist_node_next(node, FALSE)) {
|
|
1985 if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
|
|
1986 PurpleChat *chat = (PurpleChat*)node;
|
|
1987 if (purple_blist_node_get_bool(node, "gnt-autojoin"))
|
|
1988 serv_join_chat(purple_account_get_connection(chat->account), chat->components);
|
15817
|
1989 }
|
|
1990 }
|
|
1991 }
|
|
1992
|
|
1993 static void show_offline_cb(GntMenuItem *item, gpointer n)
|
|
1994 {
|
15822
|
1995 purple_prefs_set_bool(PREF_ROOT "/showoffline",
|
|
1996 !purple_prefs_get_bool(PREF_ROOT "/showoffline"));
|
15817
|
1997 }
|
|
1998
|
|
1999 static void sort_blist_change_cb(GntMenuItem *item, gpointer n)
|
|
2000 {
|
15822
|
2001 purple_prefs_set_string(PREF_ROOT "/sort_type", n);
|
15817
|
2002 }
|
|
2003
|
|
2004 /* XXX: send_im_select* -- Xerox */
|
|
2005 static void
|
15822
|
2006 send_im_select_cb(gpointer data, PurpleRequestFields *fields)
|
15817
|
2007 {
|
15822
|
2008 PurpleAccount *account;
|
15817
|
2009 const char *username;
|
|
2010
|
15822
|
2011 account = purple_request_fields_get_account(fields, "account");
|
|
2012 username = purple_request_fields_get_string(fields, "screenname");
|
15817
|
2013
|
15822
|
2014 purple_conversation_new(PURPLE_CONV_TYPE_IM, account, username);
|
15817
|
2015 }
|
|
2016
|
|
2017 static void
|
|
2018 send_im_select(GntMenuItem *item, gpointer n)
|
|
2019 {
|
15822
|
2020 PurpleRequestFields *fields;
|
|
2021 PurpleRequestFieldGroup *group;
|
|
2022 PurpleRequestField *field;
|
15817
|
2023
|
15822
|
2024 fields = purple_request_fields_new();
|
15817
|
2025
|
15822
|
2026 group = purple_request_field_group_new(NULL);
|
|
2027 purple_request_fields_add_group(fields, group);
|
15817
|
2028
|
15822
|
2029 field = purple_request_field_string_new("screenname", _("_Name"), NULL, FALSE);
|
|
2030 purple_request_field_set_type_hint(field, "screenname");
|
|
2031 purple_request_field_set_required(field, TRUE);
|
|
2032 purple_request_field_group_add_field(group, field);
|
15817
|
2033
|
15822
|
2034 field = purple_request_field_account_new("account", _("_Account"), NULL);
|
|
2035 purple_request_field_set_type_hint(field, "account");
|
|
2036 purple_request_field_set_visible(field,
|
|
2037 (purple_connections_get_all() != NULL &&
|
|
2038 purple_connections_get_all()->next != NULL));
|
|
2039 purple_request_field_set_required(field, TRUE);
|
|
2040 purple_request_field_group_add_field(group, field);
|
15817
|
2041
|
15822
|
2042 purple_request_fields(purple_get_blist(), _("New Instant Message"),
|
15817
|
2043 NULL,
|
|
2044 _("Please enter the screen name or alias of the person "
|
|
2045 "you would like to IM."),
|
|
2046 fields,
|
|
2047 _("OK"), G_CALLBACK(send_im_select_cb),
|
|
2048 _("Cancel"), NULL,
|
|
2049 NULL);
|
|
2050 }
|
|
2051
|
|
2052 static void
|
|
2053 create_menu()
|
|
2054 {
|
|
2055 GntWidget *menu, *sub;
|
|
2056 GntMenuItem *item;
|
|
2057 GntWindow *window;
|
|
2058
|
|
2059 if (!ggblist)
|
|
2060 return;
|
|
2061
|
|
2062 window = GNT_WINDOW(ggblist->window);
|
|
2063 ggblist->menu = menu = gnt_menu_new(GNT_MENU_TOPLEVEL);
|
|
2064 gnt_window_set_menu(window, GNT_MENU(menu));
|
|
2065
|
|
2066 item = gnt_menuitem_new(_("Options"));
|
|
2067 gnt_menu_add_item(GNT_MENU(menu), item);
|
|
2068
|
|
2069 sub = gnt_menu_new(GNT_MENU_POPUP);
|
|
2070 gnt_menuitem_set_submenu(item, GNT_MENU(sub));
|
|
2071
|
|
2072 item = gnt_menuitem_new(_("Send IM..."));
|
|
2073 gnt_menu_add_item(GNT_MENU(sub), item);
|
|
2074 gnt_menuitem_set_callback(GNT_MENUITEM(item), send_im_select, NULL);
|
|
2075
|
|
2076 item = gnt_menuitem_check_new(_("Toggle offline buddies"));
|
|
2077 gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(item),
|
15822
|
2078 purple_prefs_get_bool(PREF_ROOT "/showoffline"));
|
15817
|
2079 gnt_menu_add_item(GNT_MENU(sub), item);
|
|
2080 gnt_menuitem_set_callback(GNT_MENUITEM(item), show_offline_cb, NULL);
|
|
2081
|
|
2082 item = gnt_menuitem_new(_("Sort by status"));
|
|
2083 gnt_menu_add_item(GNT_MENU(sub), item);
|
|
2084 gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "status");
|
|
2085
|
|
2086 item = gnt_menuitem_new(_("Sort alphabetically"));
|
|
2087 gnt_menu_add_item(GNT_MENU(sub), item);
|
|
2088 gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "text");
|
|
2089
|
|
2090 item = gnt_menuitem_new(_("Sort by log size"));
|
|
2091 gnt_menu_add_item(GNT_MENU(sub), item);
|
|
2092 gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "log");
|
|
2093
|
|
2094 reconstruct_accounts_menu();
|
|
2095 gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts);
|
|
2096
|
|
2097 reconstruct_plugins_menu();
|
|
2098 gnt_menu_add_item(GNT_MENU(menu), ggblist->plugins);
|
|
2099 }
|
|
2100
|
|
2101 void finch_blist_show()
|
|
2102 {
|
15822
|
2103 blist_show(purple_get_blist());
|
15817
|
2104 }
|
|
2105
|
|
2106 static void
|
15822
|
2107 blist_show(PurpleBuddyList *list)
|
15817
|
2108 {
|
|
2109 if (ggblist == NULL)
|
|
2110 new_list(list);
|
|
2111 else if (ggblist->window)
|
|
2112 return;
|
|
2113
|
|
2114 ggblist->window = gnt_vwindow_new(FALSE);
|
|
2115 gnt_widget_set_name(ggblist->window, "buddylist");
|
|
2116 gnt_box_set_toplevel(GNT_BOX(ggblist->window), TRUE);
|
|
2117 gnt_box_set_title(GNT_BOX(ggblist->window), _("Buddy List"));
|
|
2118 gnt_box_set_pad(GNT_BOX(ggblist->window), 0);
|
|
2119
|
|
2120 ggblist->tree = gnt_tree_new();
|
|
2121
|
|
2122 GNT_WIDGET_SET_FLAGS(ggblist->tree, GNT_WIDGET_NO_BORDER);
|
15822
|
2123 gnt_widget_set_size(ggblist->tree, purple_prefs_get_int(PREF_ROOT "/size/width"),
|
|
2124 purple_prefs_get_int(PREF_ROOT "/size/height"));
|
|
2125 gnt_widget_set_position(ggblist->window, purple_prefs_get_int(PREF_ROOT "/position/x"),
|
|
2126 purple_prefs_get_int(PREF_ROOT "/position/y"));
|
15817
|
2127
|
|
2128 gnt_tree_set_col_width(GNT_TREE(ggblist->tree), 0,
|
15822
|
2129 purple_prefs_get_int(PREF_ROOT "/size/width") - 1);
|
15817
|
2130
|
|
2131 gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->tree);
|
|
2132
|
|
2133 ggblist->status = gnt_combo_box_new();
|
|
2134 gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->status);
|
|
2135 ggblist->statustext = gnt_entry_new(NULL);
|
|
2136 gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->statustext);
|
|
2137
|
|
2138 gnt_widget_show(ggblist->window);
|
|
2139
|
15822
|
2140 purple_signal_connect(purple_connections_get_handle(), "signed-on", finch_blist_get_handle(),
|
|
2141 PURPLE_CALLBACK(reconstruct_accounts_menu), NULL);
|
|
2142 purple_signal_connect(purple_connections_get_handle(), "signed-off", finch_blist_get_handle(),
|
|
2143 PURPLE_CALLBACK(reconstruct_accounts_menu), NULL);
|
|
2144 purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", finch_blist_get_handle(),
|
|
2145 PURPLE_CALLBACK(buddy_status_changed), ggblist);
|
|
2146 purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", finch_blist_get_handle(),
|
|
2147 PURPLE_CALLBACK(buddy_idle_changed), ggblist);
|
15817
|
2148
|
15822
|
2149 purple_signal_connect(purple_plugins_get_handle(), "plugin-load", finch_blist_get_handle(),
|
|
2150 PURPLE_CALLBACK(reconstruct_plugins_menu), NULL);
|
|
2151 purple_signal_connect(purple_plugins_get_handle(), "plugin-unload", finch_blist_get_handle(),
|
|
2152 PURPLE_CALLBACK(reconstruct_plugins_menu), NULL);
|
15817
|
2153
|
|
2154 #if 0
|
15822
|
2155 purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_blist_get_handle(),
|
|
2156 PURPLE_CALLBACK(buddy_signed_on), ggblist);
|
|
2157 purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_blist_get_handle(),
|
|
2158 PURPLE_CALLBACK(buddy_signed_off), ggblist);
|
15817
|
2159
|
|
2160 /* These I plan to use to indicate unread-messages etc. */
|
15822
|
2161 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", finch_blist_get_handle(),
|
|
2162 PURPLE_CALLBACK(received_im_msg), list);
|
|
2163 purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg", finch_blist_get_handle(),
|
|
2164 PURPLE_CALLBACK(sent_im_msg), NULL);
|
15817
|
2165
|
15822
|
2166 purple_signal_connect(purple_conversations_get_handle(), "received-chat-msg", finch_blist_get_handle(),
|
|
2167 PURPLE_CALLBACK(received_chat_msg), list);
|
15817
|
2168 #endif
|
|
2169
|
|
2170 g_signal_connect(G_OBJECT(ggblist->tree), "selection_changed", G_CALLBACK(selection_changed), ggblist);
|
|
2171 g_signal_connect(G_OBJECT(ggblist->tree), "key_pressed", G_CALLBACK(key_pressed), ggblist);
|
|
2172 g_signal_connect(G_OBJECT(ggblist->tree), "context-menu", G_CALLBACK(context_menu), ggblist);
|
|
2173 g_signal_connect_after(G_OBJECT(ggblist->tree), "clicked", G_CALLBACK(blist_clicked), ggblist);
|
|
2174 g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist);
|
|
2175 g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip),
|
|
2176 ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
|
|
2177 g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_peripherals),
|
|
2178 ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
|
|
2179 g_signal_connect(G_OBJECT(ggblist->tree), "size_changed", G_CALLBACK(size_changed_cb), NULL);
|
|
2180 g_signal_connect(G_OBJECT(ggblist->window), "position_set", G_CALLBACK(save_position_cb), NULL);
|
|
2181 g_signal_connect(G_OBJECT(ggblist->window), "destroy", G_CALLBACK(reset_blist_window), NULL);
|
|
2182
|
|
2183 /* Status signals */
|
15822
|
2184 purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed", finch_blist_get_handle(),
|
|
2185 PURPLE_CALLBACK(savedstatus_changed), NULL);
|
15817
|
2186 g_signal_connect(G_OBJECT(ggblist->status), "selection_changed",
|
|
2187 G_CALLBACK(status_selection_changed), NULL);
|
|
2188 g_signal_connect(G_OBJECT(ggblist->statustext), "key_pressed",
|
|
2189 G_CALLBACK(status_text_changed), NULL);
|
|
2190
|
|
2191 create_menu();
|
|
2192
|
|
2193 populate_buddylist();
|
|
2194
|
15822
|
2195 savedstatus_changed(purple_savedstatus_get_current(), NULL);
|
15817
|
2196 }
|
|
2197
|
|
2198 void finch_blist_uninit()
|
|
2199 {
|
|
2200 if (ggblist == NULL)
|
|
2201 return;
|
|
2202
|
|
2203 gnt_widget_destroy(ggblist->window);
|
|
2204 g_free(ggblist);
|
|
2205 ggblist = NULL;
|
|
2206 }
|
|
2207
|
|
2208 gboolean finch_blist_get_position(int *x, int *y)
|
|
2209 {
|
|
2210 if (!ggblist || !ggblist->window)
|
|
2211 return FALSE;
|
|
2212 gnt_widget_get_position(ggblist->window, x, y);
|
|
2213 return TRUE;
|
|
2214 }
|
|
2215
|
|
2216 void finch_blist_set_position(int x, int y)
|
|
2217 {
|
|
2218 gnt_widget_set_position(ggblist->window, x, y);
|
|
2219 }
|
|
2220
|
|
2221 gboolean finch_blist_get_size(int *width, int *height)
|
|
2222 {
|
|
2223 if (!ggblist || !ggblist->window)
|
|
2224 return FALSE;
|
|
2225 gnt_widget_get_size(ggblist->window, width, height);
|
|
2226 return TRUE;
|
|
2227 }
|
|
2228
|
|
2229 void finch_blist_set_size(int width, int height)
|
|
2230 {
|
|
2231 gnt_widget_set_size(ggblist->window, width, height);
|
|
2232 }
|
|
2233
|