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