2 * @file gntblist.c GNT BuddyList API
8 * Finch is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
35 #include <savedstatuses.h>
43 #include "gntcolors.h"
44 #include "gntcombobox.h"
51 #include "gntmenuitem.h"
52 #include "gntmenuitemcheck.h"
53 #include "gntpounce.h"
57 #include "gntwindow.h"
61 #include "gntstatus.h"
64 #define PREF_ROOT "/finch/blist"
65 #define TYPING_TIMEOUT_S 4
67 #define SHOW_EMPTY_GROUP_TIMEOUT 60
75 PurpleBlistNode
*tnode
; /* Who is the tooltip being displayed for? */
76 GList
*tagged
; /* A list of tagged blistnodes */
79 PurpleBlistNode
*cnode
;
81 /* XXX: I am KISSing */
82 GntWidget
*status
; /* Dropdown with the statuses */
83 GntWidget
*statustext
; /* Status message */
87 /* These are the menuitems that get regenerated */
88 GntMenuItem
*accounts
;
90 GntMenuItem
*grouping
;
92 /* When a new group is manually added, it is empty, but we still want to show it
93 * for a while (SHOW_EMPTY_GROUP_TIMEOUT seconds) even if 'show empty groups' is
97 guint new_group_timeout
;
99 FinchBlistManager
*manager
;
104 gpointer row
; /* the row in the GntTree */
105 guint signed_timer
; /* used when 'recently' signed on/off */
110 STATUS_PRIMITIVE
= 0,
111 STATUS_SAVED_POPULAR
,
121 PurpleStatusPrimitive prim
;
122 PurpleSavedStatus
*saved
;
126 static FinchBlist
*ggblist
;
128 static void add_buddy(PurpleBuddy
*buddy
, FinchBlist
*ggblist
);
129 static void add_contact(PurpleContact
*contact
, FinchBlist
*ggblist
);
130 static void add_group(PurpleGroup
*group
, FinchBlist
*ggblist
);
131 static void add_chat(PurpleChat
*chat
, FinchBlist
*ggblist
);
132 static void add_node(PurpleBlistNode
*node
, FinchBlist
*ggblist
);
133 static void node_update(PurpleBuddyList
*list
, PurpleBlistNode
*node
);
135 static gboolean
is_contact_online(PurpleContact
*contact
);
136 static gboolean
is_group_online(PurpleGroup
*group
);
138 static void draw_tooltip(FinchBlist
*ggblist
);
139 static void tooltip_for_buddy(PurpleBuddy
*buddy
, GString
*str
, gboolean full
);
140 static gboolean
remove_typing_cb(gpointer null
);
141 static void remove_peripherals(FinchBlist
*ggblist
);
142 static const char * get_display_name(PurpleBlistNode
*node
);
143 static void savedstatus_changed(PurpleSavedStatus
*now
, PurpleSavedStatus
*old
);
144 static void blist_show(PurpleBuddyList
*list
);
145 static void update_node_display(PurpleBlistNode
*buddy
, FinchBlist
*ggblist
);
146 static void update_buddy_display(PurpleBuddy
*buddy
, FinchBlist
*ggblist
);
147 static gboolean
account_autojoin_cb(PurpleConnection
*pc
, gpointer null
);
148 static void finch_request_add_buddy(PurpleAccount
*account
, const char *username
, const char *grp
, const char *alias
);
149 static void menu_group_set_cb(GntMenuItem
*item
, gpointer null
);
152 static int blist_node_compare_position(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
);
153 static int blist_node_compare_text(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
);
154 static int blist_node_compare_status(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
);
155 static int blist_node_compare_log(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
);
157 static int color_available
;
158 static int color_away
;
159 static int color_offline
;
160 static int color_idle
;
163 * Buddy List Manager functions.
166 static gboolean
default_can_add_node(PurpleBlistNode
*node
)
168 gboolean offline
= purple_prefs_get_bool(PREF_ROOT
"/showoffline");
170 if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
171 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
172 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
173 if (!purple_buddy_get_contact(buddy
))
174 return FALSE
; /* When a new buddy is added and show-offline is set */
175 if (PURPLE_BUDDY_IS_ONLINE(buddy
))
176 return TRUE
; /* The buddy is online */
177 if (!purple_account_is_connected(purple_buddy_get_account(buddy
)))
178 return FALSE
; /* The account is disconnected. Do not show */
180 return TRUE
; /* We want to see offline buddies too */
181 if (fnode
&& fnode
->signed_timer
)
182 return TRUE
; /* Show if the buddy just signed off */
183 if (purple_blist_node_get_bool(node
, "show_offline"))
185 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
187 for (nd
= purple_blist_node_get_first_child(node
);
188 nd
; nd
= purple_blist_node_get_sibling_next(nd
)) {
189 if (default_can_add_node(nd
))
192 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
193 PurpleChat
*chat
= (PurpleChat
*)node
;
194 if (purple_account_is_connected(purple_chat_get_account(chat
)))
195 return TRUE
; /* Show whenever the account is online */
196 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
198 gboolean empty
= purple_prefs_get_bool(PREF_ROOT
"/emptygroups");
200 return TRUE
; /* If we want to see empty groups, we can show any group */
202 for (nd
= purple_blist_node_get_first_child(node
);
203 nd
; nd
= purple_blist_node_get_sibling_next(nd
)) {
204 if (default_can_add_node(nd
))
208 if (ggblist
&& ggblist
->new_group
&& g_list_find(ggblist
->new_group
, node
))
215 static gpointer
default_find_parent(PurpleBlistNode
*node
)
218 switch (purple_blist_node_get_type(node
)) {
219 case PURPLE_BLIST_BUDDY_NODE
:
220 case PURPLE_BLIST_CONTACT_NODE
:
221 case PURPLE_BLIST_CHAT_NODE
:
222 ret
= purple_blist_node_get_parent(node
);
228 add_node(ret
, ggblist
);
232 static gboolean
default_create_tooltip(gpointer selected_row
, GString
**body
, char **tool_title
)
235 PurpleBlistNode
*node
= selected_row
;
240 purple_blist_node_get_type(node
) == PURPLE_BLIST_OTHER_NODE
)
243 str
= g_string_new("");
245 if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
246 PurpleBuddy
*pr
= purple_contact_get_priority_buddy((PurpleContact
*)node
);
247 gboolean offline
= !PURPLE_BUDDY_IS_ONLINE(pr
);
248 gboolean showoffline
= purple_prefs_get_bool(PREF_ROOT
"/showoffline");
249 const char *name
= purple_buddy_get_name(pr
);
251 title
= g_strdup(name
);
252 tooltip_for_buddy(pr
, str
, TRUE
);
253 for (node
= purple_blist_node_get_first_child(node
); node
; node
= purple_blist_node_get_sibling_next(node
)) {
254 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
256 int value
= purple_blist_node_get_int(node
, "last_seen");
257 if (value
> lastseen
)
260 if (node
== (PurpleBlistNode
*)pr
)
262 if (!purple_account_is_connected(purple_buddy_get_account(buddy
)))
264 if (!showoffline
&& !PURPLE_BUDDY_IS_ONLINE(buddy
))
266 str
= g_string_append(str
, "\n----------\n");
267 tooltip_for_buddy(buddy
, str
, FALSE
);
269 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
270 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
271 tooltip_for_buddy(buddy
, str
, TRUE
);
272 title
= g_strdup(purple_buddy_get_name(buddy
));
273 if (!PURPLE_BUDDY_IS_ONLINE((PurpleBuddy
*)node
))
274 lastseen
= purple_blist_node_get_int(node
, "last_seen");
275 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
276 PurpleGroup
*group
= (PurpleGroup
*)node
;
278 g_string_append_printf(str
, _("Online: %d\nTotal: %d"),
279 purple_blist_get_group_online_count(group
),
280 purple_blist_get_group_size(group
, FALSE
));
282 title
= g_strdup(purple_group_get_name(group
));
283 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
284 PurpleChat
*chat
= (PurpleChat
*)node
;
285 PurpleAccount
*account
= purple_chat_get_account(chat
);
287 g_string_append_printf(str
, _("Account: %s (%s)"),
288 purple_account_get_username(account
),
289 purple_account_get_protocol_name(account
));
291 title
= g_strdup(purple_chat_get_name(chat
));
293 g_string_free(str
, TRUE
);
298 char *tmp
= purple_str_seconds_to_string(time(NULL
) - lastseen
);
299 g_string_append_printf(str
, _("\nLast Seen: %s ago"), tmp
);
311 g_string_free(str
, TRUE
);
316 static FinchBlistManager default_manager
=
322 default_can_add_node
,
324 default_create_tooltip
,
325 {NULL
, NULL
, NULL
, NULL
}
327 static GList
*managers
;
329 static FinchBlistNode
*
330 create_finch_blist_node(PurpleBlistNode
*node
, gpointer row
)
332 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
334 fnode
= g_new0(FinchBlistNode
, 1);
335 fnode
->signed_timer
= 0;
336 FINCH_SET_DATA(node
, fnode
);
343 reset_blist_node_ui_data(PurpleBlistNode
*node
)
345 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
348 if (fnode
->signed_timer
)
349 purple_timeout_remove(fnode
->signed_timer
);
351 FINCH_SET_DATA(node
, NULL
);
355 get_display_color(PurpleBlistNode
*node
)
360 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
361 node
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)));
362 if (!PURPLE_BLIST_NODE_IS_BUDDY(node
))
365 buddy
= (PurpleBuddy
*)node
;
366 if (purple_presence_is_idle(purple_buddy_get_presence(buddy
))) {
368 } else if (purple_presence_is_available(purple_buddy_get_presence(buddy
))) {
369 color
= color_available
;
370 } else if (purple_presence_is_online(purple_buddy_get_presence(buddy
)) &&
371 !purple_presence_is_available(purple_buddy_get_presence(buddy
))) {
373 } else if (!purple_presence_is_online(purple_buddy_get_presence(buddy
))) {
374 color
= color_offline
;
380 static GntTextFormatFlags
381 get_blist_node_flag(PurpleBlistNode
*node
)
383 GntTextFormatFlags flag
= 0;
384 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
386 if (ggblist
->tagged
&& g_list_find(ggblist
->tagged
, node
))
387 flag
|= GNT_TEXT_FLAG_BOLD
;
389 if (fnode
&& fnode
->signed_timer
)
390 flag
|= GNT_TEXT_FLAG_BLINK
;
391 else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
392 node
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)));
393 fnode
= FINCH_GET_DATA(node
);
394 if (fnode
&& fnode
->signed_timer
)
395 flag
|= GNT_TEXT_FLAG_BLINK
;
396 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
397 /* If the node is collapsed, then check to see if any of the priority buddies of
398 * any of the contacts within this group recently signed on/off, and set the blink
399 * flag appropriately. */
400 /* XXX: Refs #5444 */
401 /* XXX: there's no way I can ask if the node is expanded or not? *sigh*
402 * API addition would be necessary */
404 if (!gnt_tree_get_expanded(GNT_TREE(ggblist
->tree
), node
)) {
405 for (node
= purple_blist_node_get_first_child(node
); node
;
406 node
= purple_blist_node_get_sibling_next(node
)) {
407 PurpleBlistNode
*pnode
;
408 pnode
= purple_contact_get_priority_buddy((PurpleContact
*)node
);
409 fnode
= FINCH_GET_DATA(node
);
410 if (fnode
&& fnode
->signed_timer
) {
411 flag
|= GNT_TEXT_FLAG_BLINK
;
423 blist_update_row_flags(PurpleBlistNode
*node
)
425 gnt_tree_set_row_flags(GNT_TREE(ggblist
->tree
), node
, get_blist_node_flag(node
));
426 gnt_tree_set_row_color(GNT_TREE(ggblist
->tree
), node
, get_display_color(node
));
431 is_contact_online(PurpleContact
*contact
)
433 PurpleBlistNode
*node
;
434 for (node
= purple_blist_node_get_first_child(((PurpleBlistNode
*)contact
)); node
;
435 node
= purple_blist_node_get_sibling_next(node
)) {
436 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
437 if (PURPLE_BUDDY_IS_ONLINE((PurpleBuddy
*)node
) ||
438 (fnode
&& fnode
->signed_timer
))
445 is_group_online(PurpleGroup
*group
)
447 PurpleBlistNode
*node
;
448 for (node
= purple_blist_node_get_first_child(((PurpleBlistNode
*)group
)); node
;
449 node
= purple_blist_node_get_sibling_next(node
)) {
450 if (PURPLE_BLIST_NODE_IS_CHAT(node
) &&
451 purple_account_is_connected(((PurpleChat
*)node
)->account
))
453 else if (is_contact_online((PurpleContact
*)node
))
461 new_node(PurpleBlistNode
*node
)
466 add_node(PurpleBlistNode
*node
, FinchBlist
*ggblist
)
468 if (FINCH_GET_DATA(node
))
471 if (!ggblist
->manager
->can_add_node(node
))
474 if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
475 add_buddy((PurpleBuddy
*)node
, ggblist
);
476 else if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
477 add_contact((PurpleContact
*)node
, ggblist
);
478 else if (PURPLE_BLIST_NODE_IS_GROUP(node
))
479 add_group((PurpleGroup
*)node
, ggblist
);
480 else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
481 add_chat((PurpleChat
*)node
, ggblist
);
483 draw_tooltip(ggblist
);
486 void finch_blist_manager_add_node(PurpleBlistNode
*node
)
488 add_node(node
, ggblist
);
492 remove_tooltip(FinchBlist
*ggblist
)
494 gnt_widget_destroy(ggblist
->tooltip
);
495 ggblist
->tooltip
= NULL
;
496 ggblist
->tnode
= NULL
;
500 node_remove(PurpleBuddyList
*list
, PurpleBlistNode
*node
)
502 FinchBlist
*ggblist
= FINCH_GET_DATA(list
);
503 PurpleBlistNode
*parent
;
505 if (ggblist
== NULL
|| FINCH_GET_DATA(node
) == NULL
)
508 if (PURPLE_BLIST_NODE_IS_GROUP(node
) && ggblist
->new_group
) {
509 ggblist
->new_group
= g_list_remove(ggblist
->new_group
, node
);
512 gnt_tree_remove(GNT_TREE(ggblist
->tree
), node
);
513 reset_blist_node_ui_data(node
);
515 ggblist
->tagged
= g_list_remove(ggblist
->tagged
, node
);
517 parent
= purple_blist_node_get_parent(node
);
518 for (node
= purple_blist_node_get_first_child(node
); node
;
519 node
= purple_blist_node_get_sibling_next(node
))
520 node_remove(list
, node
);
523 if (!ggblist
->manager
->can_add_node(parent
))
524 node_remove(list
, parent
);
526 node_update(list
, parent
);
529 draw_tooltip(ggblist
);
533 node_update(PurpleBuddyList
*list
, PurpleBlistNode
*node
)
535 /* It really looks like this should never happen ... but it does.
536 This will at least emit a warning to the log when it
537 happens, so maybe someone will figure it out. */
538 g_return_if_fail(node
!= NULL
);
540 if (FINCH_GET_DATA(list
)== NULL
)
541 return; /* XXX: this is probably the place to auto-join chats */
543 if (ggblist
->window
== NULL
)
546 if (FINCH_GET_DATA(node
)!= NULL
) {
547 gnt_tree_change_text(GNT_TREE(ggblist
->tree
), node
,
548 0, get_display_name(node
));
549 gnt_tree_sort_row(GNT_TREE(ggblist
->tree
), node
);
550 blist_update_row_flags(node
);
551 if (gnt_tree_get_parent_key(GNT_TREE(ggblist
->tree
), node
) !=
552 ggblist
->manager
->find_parent(node
))
553 node_remove(list
, node
);
556 if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
557 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
558 add_node((PurpleBlistNode
*)buddy
, FINCH_GET_DATA(list
));
559 node_update(list
, purple_blist_node_get_parent(node
));
560 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
561 add_node(node
, FINCH_GET_DATA(list
));
562 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
563 if (FINCH_GET_DATA(node
)== NULL
) {
564 /* The core seems to expect the UI to add the buddies. */
565 for (node
= purple_blist_node_get_first_child(node
); node
; node
= purple_blist_node_get_sibling_next(node
))
566 add_node(node
, FINCH_GET_DATA(list
));
568 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
569 if (!ggblist
->manager
->can_add_node(node
))
570 node_remove(list
, node
);
572 add_node(node
, FINCH_GET_DATA(list
));
574 if (ggblist
->tnode
== node
) {
575 draw_tooltip(ggblist
);
580 new_list(PurpleBuddyList
*list
)
585 ggblist
= g_new0(FinchBlist
, 1);
586 FINCH_SET_DATA(list
, ggblist
);
587 ggblist
->manager
= finch_blist_manager_find(purple_prefs_get_string(PREF_ROOT
"/grouping"));
588 if (!ggblist
->manager
)
589 ggblist
->manager
= &default_manager
;
592 static void destroy_list(PurpleBuddyList
*list
)
597 gnt_widget_destroy(ggblist
->window
);
603 remove_new_empty_group(gpointer data
)
605 PurpleBuddyList
*list
;
610 list
= purple_get_blist();
611 g_return_val_if_fail(list
, FALSE
);
613 ggblist
->new_group_timeout
= 0;
614 while (ggblist
->new_group
) {
615 PurpleBlistNode
*group
= ggblist
->new_group
->data
;
616 ggblist
->new_group
= g_list_delete_link(ggblist
->new_group
, ggblist
->new_group
);
617 node_update(list
, group
);
624 add_buddy_cb(void *data
, PurpleRequestFields
*allfields
)
626 const char *username
= purple_request_fields_get_string(allfields
, "screenname");
627 const char *alias
= purple_request_fields_get_string(allfields
, "alias");
628 const char *group
= purple_request_fields_get_string(allfields
, "group");
629 const char *invite
= purple_request_fields_get_string(allfields
, "invite");
630 PurpleAccount
*account
= purple_request_fields_get_account(allfields
, "account");
631 const char *error
= NULL
;
636 error
= _("You must provide a username for the buddy.");
638 error
= _("You must provide a group.");
640 error
= _("You must select an account.");
641 else if (!purple_account_is_connected(account
))
642 error
= _("The selected account is not online.");
646 finch_request_add_buddy(account
, username
, group
, alias
);
647 purple_notify_error(NULL
, _("Error"), _("Error adding buddy"), error
);
651 grp
= purple_find_group(group
);
654 grp
= purple_group_new(group
);
655 purple_blist_add_group(grp
, NULL
);
658 /* XXX: Ask to merge if there's already a buddy with the same alias in the same group (#4553) */
660 if ((buddy
= purple_find_buddy_in_group(account
, username
, grp
)) == NULL
)
662 buddy
= purple_buddy_new(account
, username
, alias
);
663 purple_blist_add_buddy(buddy
, NULL
, grp
, NULL
);
666 purple_account_add_buddy_with_invite(account
, buddy
, invite
);
670 finch_request_add_buddy(PurpleAccount
*account
, const char *username
, const char *grp
, const char *alias
)
672 PurpleRequestFields
*fields
= purple_request_fields_new();
673 PurpleRequestFieldGroup
*group
= purple_request_field_group_new(NULL
);
674 PurpleRequestField
*field
;
676 purple_request_fields_add_group(fields
, group
);
678 field
= purple_request_field_string_new("screenname", _("Username"), username
, FALSE
);
679 purple_request_field_group_add_field(group
, field
);
681 field
= purple_request_field_string_new("alias", _("Alias (optional)"), alias
, FALSE
);
682 purple_request_field_group_add_field(group
, field
);
684 field
= purple_request_field_string_new("invite", _("Invite message (optional)"), NULL
, FALSE
);
685 purple_request_field_group_add_field(group
, field
);
687 field
= purple_request_field_string_new("group", _("Add in group"), grp
, FALSE
);
688 purple_request_field_group_add_field(group
, field
);
689 purple_request_field_set_type_hint(field
, "group");
691 field
= purple_request_field_account_new("account", _("Account"), NULL
);
692 purple_request_field_account_set_show_all(field
, FALSE
);
694 purple_request_field_account_set_value(field
, account
);
695 purple_request_field_group_add_field(group
, field
);
697 purple_request_fields(NULL
, _("Add Buddy"), NULL
, _("Please enter buddy information."),
699 _("Add"), G_CALLBACK(add_buddy_cb
),
706 join_chat(PurpleChat
*chat
)
708 PurpleAccount
*account
= purple_chat_get_account(chat
);
710 PurpleConversation
*conv
;
713 /* This hack here is to work around the fact that there's no good way of
714 * getting the actual name of a chat. I don't understand why we return
715 * the alias for a chat when all we want is the name. */
718 name
= purple_chat_get_name(chat
);
719 conv
= purple_find_conversation_with_account(
720 PURPLE_CONV_TYPE_CHAT
, name
, account
);
721 chat
->alias
= (char *)alias
;
723 if (!conv
|| purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv
))) {
724 serv_join_chat(purple_account_get_connection(account
),
725 purple_chat_get_components(chat
));
727 purple_conversation_present(conv
);
732 add_chat_cb(void *data
, PurpleRequestFields
*allfields
)
734 PurpleAccount
*account
;
735 const char *alias
, *name
, *group
;
738 GHashTable
*hash
= NULL
;
739 PurpleConnection
*gc
;
741 PurplePluginProtocolInfo
*info
;
743 account
= purple_request_fields_get_account(allfields
, "account");
744 name
= purple_request_fields_get_string(allfields
, "name");
745 alias
= purple_request_fields_get_string(allfields
, "alias");
746 group
= purple_request_fields_get_string(allfields
, "group");
747 autojoin
= purple_request_fields_get_bool(allfields
, "autojoin");
749 if (!purple_account_is_connected(account
) || !name
|| !*name
)
752 if (!group
|| !*group
)
755 gc
= purple_account_get_connection(account
);
756 info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
757 if (info
->chat_info_defaults
!= NULL
)
758 hash
= info
->chat_info_defaults(gc
, name
);
760 chat
= purple_chat_new(account
, name
, hash
);
763 if ((grp
= purple_find_group(group
)) == NULL
) {
764 grp
= purple_group_new(group
);
765 purple_blist_add_group(grp
, NULL
);
767 purple_blist_add_chat(chat
, grp
, NULL
);
768 purple_blist_alias_chat(chat
, alias
);
769 purple_blist_node_set_bool((PurpleBlistNode
*)chat
, "gnt-autojoin", autojoin
);
777 finch_request_add_chat(PurpleAccount
*account
, PurpleGroup
*grp
, const char *alias
, const char *name
)
779 PurpleRequestFields
*fields
= purple_request_fields_new();
780 PurpleRequestFieldGroup
*group
= purple_request_field_group_new(NULL
);
781 PurpleRequestField
*field
;
783 purple_request_fields_add_group(fields
, group
);
785 field
= purple_request_field_account_new("account", _("Account"), NULL
);
786 purple_request_field_account_set_show_all(field
, FALSE
);
788 purple_request_field_account_set_value(field
, account
);
789 purple_request_field_group_add_field(group
, field
);
791 field
= purple_request_field_string_new("name", _("Name"), name
, FALSE
);
792 purple_request_field_group_add_field(group
, field
);
794 field
= purple_request_field_string_new("alias", _("Alias"), alias
, FALSE
);
795 purple_request_field_group_add_field(group
, field
);
797 field
= purple_request_field_string_new("group", _("Group"), grp
? purple_group_get_name(grp
) : NULL
, FALSE
);
798 purple_request_field_group_add_field(group
, field
);
799 purple_request_field_set_type_hint(field
, "group");
801 field
= purple_request_field_bool_new("autojoin", _("Auto-join"), FALSE
);
802 purple_request_field_group_add_field(group
, field
);
804 purple_request_fields(NULL
, _("Add Chat"), NULL
,
805 _("You can edit more information from the context menu later."),
806 fields
, _("Add"), G_CALLBACK(add_chat_cb
), _("Cancel"), NULL
,
812 add_group_cb(gpointer null
, const char *group
)
816 if (!group
|| !*group
) {
817 purple_notify_error(NULL
, _("Error"), _("Error adding group"),
818 _("You must give a name for the group to add."));
822 grp
= purple_find_group(group
);
824 grp
= purple_group_new(group
);
825 purple_blist_add_group(grp
, NULL
);
831 /* Treat the group as a new group even if it had existed before. This should
832 * make things easier to add buddies to empty groups (new or old) without having
833 * to turn on 'show empty groups' setting */
834 ggblist
->new_group
= g_list_prepend(ggblist
->new_group
, grp
);
835 if (ggblist
->new_group_timeout
)
836 purple_timeout_remove(ggblist
->new_group_timeout
);
837 ggblist
->new_group_timeout
= purple_timeout_add_seconds(SHOW_EMPTY_GROUP_TIMEOUT
,
838 remove_new_empty_group
, NULL
);
840 /* Select the group */
842 FinchBlistNode
*fnode
= FINCH_GET_DATA((PurpleBlistNode
*)grp
);
844 add_node((PurpleBlistNode
*)grp
, ggblist
);
845 gnt_tree_set_selected(GNT_TREE(ggblist
->tree
), grp
);
850 finch_request_add_group(void)
852 purple_request_input(NULL
, _("Add Group"), NULL
, _("Enter the name of the group"),
853 NULL
, FALSE
, FALSE
, NULL
,
854 _("Add"), G_CALLBACK(add_group_cb
), _("Cancel"), NULL
,
859 static PurpleBlistUiOps blist_ui_ops
=
868 finch_request_add_buddy
,
869 finch_request_add_chat
,
870 finch_request_add_group
,
878 finch_blist_get_handle(void)
886 add_group(PurpleGroup
*group
, FinchBlist
*ggblist
)
889 PurpleBlistNode
*node
= (PurpleBlistNode
*)group
;
890 if (FINCH_GET_DATA(node
))
892 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)group
);
893 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), group
,
894 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), get_display_name(node
)),
896 gnt_tree_set_expanded(GNT_TREE(ggblist
->tree
), node
,
897 !purple_blist_node_get_bool(node
, "collapsed"));
901 get_display_name(PurpleBlistNode
*node
)
903 static char text
[2096];
904 char status
[8] = " ";
905 const char *name
= NULL
;
907 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
908 node
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
))); /* XXX: this can return NULL?! */
913 if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
915 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
916 PurpleStatusPrimitive prim
;
917 PurplePresence
*presence
;
919 gboolean ascii
= gnt_ascii_only();
921 presence
= purple_buddy_get_presence(buddy
);
922 if (purple_presence_is_status_primitive_active(presence
, PURPLE_STATUS_MOBILE
))
923 strncpy(status
, ascii
? ":" : "☎", sizeof(status
) - 1);
925 now
= purple_presence_get_active_status(presence
);
927 prim
= purple_status_type_get_primitive(purple_status_get_type(now
));
930 case PURPLE_STATUS_OFFLINE
:
931 strncpy(status
, ascii
? "x" : "⊗", sizeof(status
) - 1);
933 case PURPLE_STATUS_AVAILABLE
:
934 strncpy(status
, ascii
? "o" : "â—¯", sizeof(status
) - 1);
937 strncpy(status
, ascii
? "." : "⊖", sizeof(status
) - 1);
941 name
= purple_buddy_get_alias(buddy
);
943 else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
945 PurpleChat
*chat
= (PurpleChat
*)node
;
946 name
= purple_chat_get_name(chat
);
948 strncpy(status
, "~", sizeof(status
) - 1);
950 else if (PURPLE_BLIST_NODE_IS_GROUP(node
))
951 return purple_group_get_name((PurpleGroup
*)node
);
953 g_snprintf(text
, sizeof(text
) - 1, "%s %s", status
, name
);
959 add_chat(PurpleChat
*chat
, FinchBlist
*ggblist
)
962 PurpleBlistNode
*node
= (PurpleBlistNode
*)chat
;
963 if (FINCH_GET_DATA(node
))
965 if (!purple_account_is_connected(purple_chat_get_account(chat
)))
968 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)chat
);
970 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), chat
,
971 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), get_display_name(node
)),
976 add_contact(PurpleContact
*contact
, FinchBlist
*ggblist
)
979 PurpleBlistNode
*node
= (PurpleBlistNode
*)contact
;
982 if (FINCH_GET_DATA(node
))
985 name
= get_display_name(node
);
989 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)contact
);
991 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), contact
,
992 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), name
),
995 gnt_tree_set_expanded(GNT_TREE(ggblist
->tree
), contact
, FALSE
);
999 add_buddy(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
1002 PurpleBlistNode
*node
= (PurpleBlistNode
*)buddy
;
1003 PurpleContact
*contact
;
1005 if (FINCH_GET_DATA(node
))
1008 contact
= purple_buddy_get_contact(buddy
);
1009 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)buddy
);
1011 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), buddy
,
1012 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), get_display_name(node
)),
1015 blist_update_row_flags((PurpleBlistNode
*)buddy
);
1016 if (buddy
== purple_contact_get_priority_buddy(contact
))
1017 blist_update_row_flags((PurpleBlistNode
*)contact
);
1022 buddy_signed_on(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
1024 add_node((PurpleBlistNode
*)buddy
, ggblist
);
1028 buddy_signed_off(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
1030 node_remove(purple_get_blist(), (PurpleBlistNode
*)buddy
);
1034 PurpleBlistUiOps
*finch_blist_get_ui_ops()
1036 return &blist_ui_ops
;
1040 selection_activate(GntWidget
*widget
, FinchBlist
*ggblist
)
1042 GntTree
*tree
= GNT_TREE(ggblist
->tree
);
1043 PurpleBlistNode
*node
= gnt_tree_get_selection_data(tree
);
1048 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1049 node
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)));
1051 if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
1053 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
1054 PurpleConversation
*conv
;
1055 conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM
,
1056 purple_buddy_get_name(buddy
),
1057 purple_buddy_get_account(buddy
));
1059 conv
= purple_conversation_new(PURPLE_CONV_TYPE_IM
,
1060 purple_buddy_get_account(buddy
),
1061 purple_buddy_get_name(buddy
));
1063 FinchConv
*ggconv
= FINCH_GET_DATA(conv
);
1064 gnt_window_present(ggconv
->window
);
1066 finch_conversation_set_active(conv
);
1068 else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
1070 join_chat((PurpleChat
*)node
);
1075 context_menu_callback(GntMenuItem
*item
, gpointer data
)
1077 PurpleMenuAction
*action
= data
;
1078 PurpleBlistNode
*node
= ggblist
->cnode
;
1080 void (*callback
)(PurpleBlistNode
*, gpointer
);
1081 callback
= (void (*)(PurpleBlistNode
*, gpointer
))action
->callback
;
1083 callback(node
, action
->data
);
1090 gnt_append_menu_action(GntMenu
*menu
, PurpleMenuAction
*action
, gpointer parent
)
1098 item
= gnt_menuitem_new(action
->label
);
1099 if (action
->callback
)
1100 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), context_menu_callback
, action
);
1101 gnt_menu_add_item(menu
, GNT_MENU_ITEM(item
));
1103 if (action
->children
) {
1104 GntWidget
*sub
= gnt_menu_new(GNT_MENU_POPUP
);
1105 gnt_menuitem_set_submenu(item
, GNT_MENU(sub
));
1106 for (list
= action
->children
; list
; list
= list
->next
)
1107 gnt_append_menu_action(GNT_MENU(sub
), list
->data
, action
);
1112 append_proto_menu(GntMenu
*menu
, PurpleConnection
*gc
, PurpleBlistNode
*node
)
1115 PurplePluginProtocolInfo
*prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1117 if(!prpl_info
|| !prpl_info
->blist_node_menu
)
1120 for(list
= prpl_info
->blist_node_menu(node
); list
;
1121 list
= g_list_delete_link(list
, list
))
1123 PurpleMenuAction
*act
= (PurpleMenuAction
*) list
->data
;
1127 gnt_append_menu_action(menu
, act
, NULL
);
1128 g_signal_connect_swapped(G_OBJECT(menu
), "destroy",
1129 G_CALLBACK(purple_menu_action_free
), act
);
1134 add_custom_action(GntMenu
*menu
, const char *label
, PurpleCallback callback
,
1137 PurpleMenuAction
*action
= purple_menu_action_new(label
, callback
, data
, NULL
);
1138 gnt_append_menu_action(menu
, action
, NULL
);
1139 g_signal_connect_swapped(G_OBJECT(menu
), "destroy",
1140 G_CALLBACK(purple_menu_action_free
), action
);
1144 chat_components_edit_ok(PurpleChat
*chat
, PurpleRequestFields
*allfields
)
1146 GList
*groups
, *fields
;
1148 for (groups
= purple_request_fields_get_groups(allfields
); groups
; groups
= groups
->next
) {
1149 fields
= purple_request_field_group_get_fields(groups
->data
);
1150 for (; fields
; fields
= fields
->next
) {
1151 PurpleRequestField
*field
= fields
->data
;
1155 id
= purple_request_field_get_id(field
);
1156 if (purple_request_field_get_type(field
) == PURPLE_REQUEST_FIELD_INTEGER
)
1157 val
= g_strdup_printf("%d", purple_request_field_int_get_value(field
));
1159 val
= g_strdup(purple_request_field_string_get_value(field
));
1162 g_hash_table_remove(purple_chat_get_components(chat
), id
);
1164 g_hash_table_replace(purple_chat_get_components(chat
), g_strdup(id
), val
); /* val should not be free'd */
1171 chat_components_edit(PurpleBlistNode
*selected
, PurpleChat
*chat
)
1173 PurpleRequestFields
*fields
= purple_request_fields_new();
1174 PurpleRequestFieldGroup
*group
= purple_request_field_group_new(NULL
);
1175 PurpleRequestField
*field
;
1176 GList
*parts
, *iter
;
1177 struct proto_chat_entry
*pce
;
1178 PurpleConnection
*gc
;
1180 purple_request_fields_add_group(fields
, group
);
1182 gc
= purple_account_get_connection(purple_chat_get_account(chat
));
1183 parts
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
))->chat_info(gc
);
1185 for (iter
= parts
; iter
; iter
= iter
->next
) {
1189 const char *str
= g_hash_table_lookup(purple_chat_get_components(chat
), pce
->identifier
);
1190 if (!str
|| sscanf(str
, "%d", &val
) != 1)
1192 field
= purple_request_field_int_new(pce
->identifier
, pce
->label
, val
);
1194 field
= purple_request_field_string_new(pce
->identifier
, pce
->label
,
1195 g_hash_table_lookup(purple_chat_get_components(chat
), pce
->identifier
), FALSE
);
1197 purple_request_field_string_set_masked(field
, TRUE
);
1201 purple_request_field_set_required(field
, TRUE
);
1203 purple_request_field_group_add_field(group
, field
);
1209 purple_request_fields(NULL
, _("Edit Chat"), NULL
, _("Please Update the necessary fields."),
1210 fields
, _("Edit"), G_CALLBACK(chat_components_edit_ok
), _("Cancel"), NULL
,
1216 autojoin_toggled(GntMenuItem
*item
, gpointer data
)
1218 PurpleMenuAction
*action
= data
;
1219 purple_blist_node_set_bool(action
->data
, "gnt-autojoin",
1220 gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item
)));
1224 create_chat_menu(GntMenu
*menu
, PurpleChat
*chat
)
1226 PurpleMenuAction
*action
= purple_menu_action_new(_("Auto-join"), NULL
, chat
, NULL
);
1227 GntMenuItem
*check
= gnt_menuitem_check_new(action
->label
);
1228 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(check
),
1229 purple_blist_node_get_bool((PurpleBlistNode
*)chat
, "gnt-autojoin"));
1230 gnt_menu_add_item(menu
, check
);
1231 gnt_menuitem_set_callback(check
, autojoin_toggled
, action
);
1232 g_signal_connect_swapped(G_OBJECT(menu
), "destroy",
1233 G_CALLBACK(purple_menu_action_free
), action
);
1235 add_custom_action(menu
, _("Edit Settings"), (PurpleCallback
)chat_components_edit
, chat
);
1239 finch_add_buddy(PurpleBlistNode
*selected
, PurpleGroup
*grp
)
1241 purple_blist_request_add_buddy(NULL
, NULL
, grp
? purple_group_get_name(grp
) : NULL
, NULL
);
1245 finch_add_group(PurpleBlistNode
*selected
, PurpleGroup
*grp
)
1247 purple_blist_request_add_group();
1251 finch_add_chat(PurpleBlistNode
*selected
, PurpleGroup
*grp
)
1253 purple_blist_request_add_chat(NULL
, grp
, NULL
, NULL
);
1257 create_group_menu(GntMenu
*menu
, PurpleGroup
*group
)
1259 add_custom_action(menu
, _("Add Buddy"),
1260 PURPLE_CALLBACK(finch_add_buddy
), group
);
1261 add_custom_action(menu
, _("Add Chat"),
1262 PURPLE_CALLBACK(finch_add_chat
), group
);
1263 add_custom_action(menu
, _("Add Group"),
1264 PURPLE_CALLBACK(finch_add_group
), group
);
1267 gpointer
finch_retrieve_user_info(PurpleConnection
*conn
, const char *name
)
1269 PurpleNotifyUserInfo
*info
= purple_notify_user_info_new();
1271 purple_notify_user_info_add_pair(info
, _("Information"), _("Retrieving..."));
1272 uihandle
= purple_notify_userinfo(conn
, name
, info
, NULL
, NULL
);
1273 purple_notify_user_info_destroy(info
);
1275 serv_get_info(conn
, name
);
1280 finch_blist_get_buddy_info_cb(PurpleBlistNode
*selected
, PurpleBuddy
*buddy
)
1282 finch_retrieve_user_info(purple_account_get_connection(purple_buddy_get_account(buddy
)), purple_buddy_get_name(buddy
));
1286 finch_blist_menu_send_file_cb(PurpleBlistNode
*selected
, PurpleBuddy
*buddy
)
1288 serv_send_file(purple_account_get_connection(purple_buddy_get_account(buddy
)), purple_buddy_get_name(buddy
), NULL
);
1292 finch_blist_pounce_node_cb(PurpleBlistNode
*selected
, PurpleBlistNode
*node
)
1295 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1296 b
= purple_contact_get_priority_buddy((PurpleContact
*)node
);
1298 b
= (PurpleBuddy
*)node
;
1299 finch_pounce_editor_show(purple_buddy_get_account(b
), purple_buddy_get_name(b
), NULL
);
1303 toggle_block_buddy(GntMenuItem
*item
, gpointer buddy
)
1305 gboolean block
= gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item
));
1306 PurpleAccount
*account
= purple_buddy_get_account(buddy
);
1307 const char *name
= purple_buddy_get_name(buddy
);
1309 block
? purple_privacy_deny(account
, name
, FALSE
, FALSE
) :
1310 purple_privacy_allow(account
, name
, FALSE
, FALSE
);
1314 toggle_show_offline(GntMenuItem
*item
, gpointer buddy
)
1316 purple_blist_node_set_bool(buddy
, "show_offline",
1317 !purple_blist_node_get_bool(buddy
, "show_offline"));
1318 if (!ggblist
->manager
->can_add_node(buddy
))
1319 node_remove(purple_get_blist(), buddy
);
1321 node_update(purple_get_blist(), buddy
);
1325 create_buddy_menu(GntMenu
*menu
, PurpleBuddy
*buddy
)
1327 PurpleAccount
*account
;
1330 PurplePluginProtocolInfo
*prpl_info
;
1331 PurpleConnection
*gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
1333 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1334 if (prpl_info
&& prpl_info
->get_info
)
1336 add_custom_action(menu
, _("Get Info"),
1337 PURPLE_CALLBACK(finch_blist_get_buddy_info_cb
), buddy
);
1340 add_custom_action(menu
, _("Add Buddy Pounce"),
1341 PURPLE_CALLBACK(finch_blist_pounce_node_cb
), buddy
);
1343 if (prpl_info
&& prpl_info
->send_file
)
1345 if (!prpl_info
->can_receive_file
||
1346 prpl_info
->can_receive_file(gc
, purple_buddy_get_name(buddy
)))
1347 add_custom_action(menu
, _("Send File"),
1348 PURPLE_CALLBACK(finch_blist_menu_send_file_cb
), buddy
);
1351 account
= purple_buddy_get_account(buddy
);
1352 permitted
= purple_privacy_check(account
, purple_buddy_get_name(buddy
));
1354 item
= gnt_menuitem_check_new(_("Blocked"));
1355 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
), !permitted
);
1356 gnt_menuitem_set_callback(item
, toggle_block_buddy
, buddy
);
1357 gnt_menu_add_item(menu
, item
);
1359 item
= gnt_menuitem_check_new(_("Show when offline"));
1360 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
), purple_blist_node_get_bool((PurpleBlistNode
*)buddy
, "show_offline"));
1361 gnt_menuitem_set_callback(item
, toggle_show_offline
, buddy
);
1362 gnt_menu_add_item(menu
, item
);
1364 /* Protocol actions */
1365 append_proto_menu(menu
,
1366 purple_account_get_connection(purple_buddy_get_account(buddy
)),
1367 (PurpleBlistNode
*)buddy
);
1371 append_extended_menu(GntMenu
*menu
, PurpleBlistNode
*node
)
1375 for (iter
= purple_blist_node_get_extended_menu(node
);
1376 iter
; iter
= g_list_delete_link(iter
, iter
))
1378 gnt_append_menu_action(menu
, iter
->data
, NULL
);
1379 g_signal_connect_swapped(G_OBJECT(menu
), "destroy",
1380 G_CALLBACK(purple_menu_action_free
), iter
->data
);
1384 /* Xerox'd from gtkdialogs.c:purple_gtkdialogs_remove_contact_cb */
1386 remove_contact(PurpleContact
*contact
)
1388 PurpleBlistNode
*bnode
, *cnode
;
1391 cnode
= (PurpleBlistNode
*)contact
;
1392 group
= (PurpleGroup
*)purple_blist_node_get_parent(cnode
);
1393 for (bnode
= purple_blist_node_get_first_child(cnode
); bnode
; bnode
= purple_blist_node_get_sibling_next(bnode
)) {
1394 PurpleBuddy
*buddy
= (PurpleBuddy
*)bnode
;
1395 PurpleAccount
*account
= purple_buddy_get_account(buddy
);
1396 if (purple_account_is_connected(account
))
1397 purple_account_remove_buddy(account
, buddy
, group
);
1399 purple_blist_remove_contact(contact
);
1403 rename_blist_node(PurpleBlistNode
*node
, const char *newname
)
1405 const char *name
= newname
;
1409 if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1410 PurpleContact
*contact
= (PurpleContact
*)node
;
1411 PurpleBuddy
*buddy
= purple_contact_get_priority_buddy(contact
);
1412 purple_blist_alias_contact(contact
, name
);
1413 purple_blist_alias_buddy(buddy
, name
);
1414 serv_alias_buddy(buddy
);
1415 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1416 purple_blist_alias_buddy((PurpleBuddy
*)node
, name
);
1417 serv_alias_buddy((PurpleBuddy
*)node
);
1418 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
1419 purple_blist_alias_chat((PurpleChat
*)node
, name
);
1420 else if (PURPLE_BLIST_NODE_IS_GROUP(node
) && (name
!= NULL
))
1421 purple_blist_rename_group((PurpleGroup
*)node
, name
);
1423 g_return_if_reached();
1427 finch_blist_rename_node_cb(PurpleBlistNode
*selected
, PurpleBlistNode
*node
)
1429 const char *name
= NULL
;
1433 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1434 name
= purple_contact_get_alias((PurpleContact
*)node
);
1435 else if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
1436 name
= purple_buddy_get_contact_alias((PurpleBuddy
*)node
);
1437 else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
1438 name
= purple_chat_get_name((PurpleChat
*)node
);
1439 else if (PURPLE_BLIST_NODE_IS_GROUP(node
))
1440 name
= purple_group_get_name((PurpleGroup
*)node
);
1442 g_return_if_reached();
1444 prompt
= g_strdup_printf(_("Please enter the new name for %s"), name
);
1446 text
= PURPLE_BLIST_NODE_IS_GROUP(node
) ? _("Rename") : _("Set Alias");
1447 purple_request_input(node
, text
, prompt
, _("Enter empty string to reset the name."),
1448 name
, FALSE
, FALSE
, NULL
, text
, G_CALLBACK(rename_blist_node
),
1457 static void showlog_cb(PurpleBlistNode
*sel
, PurpleBlistNode
*node
)
1460 PurpleAccount
*account
;
1463 if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1464 PurpleBuddy
*b
= (PurpleBuddy
*) node
;
1465 type
= PURPLE_LOG_IM
;
1466 name
= g_strdup(purple_buddy_get_name(b
));
1467 account
= purple_buddy_get_account(b
);
1468 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1469 PurpleChat
*c
= (PurpleChat
*) node
;
1470 PurplePluginProtocolInfo
*prpl_info
= NULL
;
1471 type
= PURPLE_LOG_CHAT
;
1472 account
= purple_chat_get_account(c
);
1473 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account
)));
1474 if (prpl_info
&& prpl_info
->get_chat_name
) {
1475 name
= prpl_info
->get_chat_name(purple_chat_get_components(c
));
1477 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1478 finch_log_show_contact((PurpleContact
*)node
);
1481 /* This callback should not have been registered for a node
1482 * that doesn't match the type of one of the blocks above. */
1483 g_return_if_reached();
1486 if (name
&& account
) {
1487 finch_log_show(type
, name
, account
);
1493 /* Xeroxed from gtkdialogs.c:purple_gtkdialogs_remove_group_cb*/
1495 remove_group(PurpleGroup
*group
)
1497 PurpleBlistNode
*cnode
, *bnode
;
1499 cnode
= purple_blist_node_get_first_child(((PurpleBlistNode
*)group
));
1502 if (PURPLE_BLIST_NODE_IS_CONTACT(cnode
)) {
1503 bnode
= purple_blist_node_get_first_child(cnode
);
1504 cnode
= purple_blist_node_get_sibling_next(cnode
);
1507 if (PURPLE_BLIST_NODE_IS_BUDDY(bnode
)) {
1508 PurpleAccount
*account
;
1509 buddy
= (PurpleBuddy
*)bnode
;
1510 bnode
= purple_blist_node_get_sibling_next(bnode
);
1511 account
= purple_buddy_get_account(buddy
);
1512 if (purple_account_is_connected(account
)) {
1513 purple_account_remove_buddy(account
, buddy
, group
);
1514 purple_blist_remove_buddy(buddy
);
1517 bnode
= purple_blist_node_get_sibling_next(bnode
);
1520 } else if (PURPLE_BLIST_NODE_IS_CHAT(cnode
)) {
1521 PurpleChat
*chat
= (PurpleChat
*)cnode
;
1522 cnode
= purple_blist_node_get_sibling_next(cnode
);
1523 if (purple_account_is_connected(purple_chat_get_account(chat
)))
1524 purple_blist_remove_chat(chat
);
1526 cnode
= purple_blist_node_get_sibling_next(cnode
);
1530 purple_blist_remove_group(group
);
1534 finch_blist_remove_node(PurpleBlistNode
*node
)
1536 if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1537 remove_contact((PurpleContact
*)node
);
1538 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1539 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
1540 PurpleGroup
*group
= purple_buddy_get_group(buddy
);
1541 purple_account_remove_buddy(purple_buddy_get_account(buddy
), buddy
, group
);
1542 purple_blist_remove_buddy(buddy
);
1543 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1544 purple_blist_remove_chat((PurpleChat
*)node
);
1545 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1546 remove_group((PurpleGroup
*)node
);
1551 finch_blist_remove_node_cb(PurpleBlistNode
*selected
, PurpleBlistNode
*node
)
1553 PurpleAccount
*account
= NULL
;
1555 const char *name
, *sec
= NULL
;
1557 if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1558 PurpleContact
*c
= (PurpleContact
*)node
;
1559 name
= purple_contact_get_alias(c
);
1560 if (c
->totalsize
> 1)
1561 sec
= _("Removing this contact will also remove all the buddies in the contact");
1562 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1563 name
= purple_buddy_get_name((PurpleBuddy
*)node
);
1564 account
= purple_buddy_get_account((PurpleBuddy
*)node
);
1565 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1566 name
= purple_chat_get_name((PurpleChat
*)node
);
1567 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1568 name
= purple_group_get_name((PurpleGroup
*)node
);
1569 sec
= _("Removing this group will also remove all the buddies in the group");
1574 primary
= g_strdup_printf(_("Are you sure you want to remove %s?"), name
);
1576 /* XXX: anything to do with the returned ui-handle? */
1577 purple_request_action(node
, _("Confirm Remove"),
1580 account
, name
, NULL
,
1582 _("Remove"), finch_blist_remove_node
,
1588 finch_blist_toggle_tag_buddy(PurpleBlistNode
*node
)
1593 if (ggblist
->tagged
&& (iter
= g_list_find(ggblist
->tagged
, node
)) != NULL
) {
1594 ggblist
->tagged
= g_list_delete_link(ggblist
->tagged
, iter
);
1596 ggblist
->tagged
= g_list_prepend(ggblist
->tagged
, node
);
1598 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1599 update_buddy_display(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)), ggblist
);
1600 else if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
1601 update_buddy_display((PurpleBuddy
*)node
, ggblist
);
1603 update_node_display(node
, ggblist
);
1607 finch_blist_place_tagged(PurpleBlistNode
*target
)
1609 PurpleGroup
*tg
= NULL
;
1610 PurpleContact
*tc
= NULL
;
1612 if (target
== NULL
||
1613 purple_blist_node_get_type(target
) == PURPLE_BLIST_OTHER_NODE
)
1616 if (PURPLE_BLIST_NODE_IS_GROUP(target
))
1617 tg
= (PurpleGroup
*)target
;
1618 else if (PURPLE_BLIST_NODE_IS_BUDDY(target
)) {
1619 tc
= (PurpleContact
*)purple_blist_node_get_parent(target
);
1620 tg
= (PurpleGroup
*)purple_blist_node_get_parent((PurpleBlistNode
*)tc
);
1622 if (PURPLE_BLIST_NODE_IS_CONTACT(target
))
1623 tc
= (PurpleContact
*)target
;
1624 tg
= (PurpleGroup
*)purple_blist_node_get_parent(target
);
1627 if (ggblist
->tagged
) {
1628 GList
*list
= ggblist
->tagged
;
1629 ggblist
->tagged
= NULL
;
1631 PurpleBlistNode
*node
= list
->data
;
1632 list
= g_list_delete_link(list
, list
);
1634 if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1635 update_node_display(node
, ggblist
);
1636 /* Add the group after the current group */
1637 purple_blist_add_group((PurpleGroup
*)node
, (PurpleBlistNode
*)tg
);
1638 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1639 update_buddy_display(purple_contact_get_priority_buddy((PurpleContact
*)node
), ggblist
);
1640 if (PURPLE_BLIST_NODE(tg
) == target
) {
1641 /* The target is a group, just add the contact to the group. */
1642 purple_blist_add_contact((PurpleContact
*)node
, tg
, NULL
);
1644 /* The target is either a buddy, or a contact. Merge with that contact. */
1645 purple_blist_merge_contact((PurpleContact
*)node
, (PurpleBlistNode
*)tc
);
1647 /* The target is a chat. Add the contact to the group after this chat. */
1648 purple_blist_add_contact((PurpleContact
*)node
, NULL
, target
);
1650 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1651 update_buddy_display((PurpleBuddy
*)node
, ggblist
);
1652 if (PURPLE_BLIST_NODE(tg
) == target
) {
1653 /* The target is a group. Add this buddy in a new contact under this group. */
1654 purple_blist_add_buddy((PurpleBuddy
*)node
, NULL
, tg
, NULL
);
1655 } else if (PURPLE_BLIST_NODE_IS_CONTACT(target
)) {
1656 /* Add to the contact. */
1657 purple_blist_add_buddy((PurpleBuddy
*)node
, tc
, NULL
, NULL
);
1658 } else if (PURPLE_BLIST_NODE_IS_BUDDY(target
)) {
1659 /* Add to the contact after the selected buddy. */
1660 purple_blist_add_buddy((PurpleBuddy
*)node
, NULL
, NULL
, target
);
1661 } else if (PURPLE_BLIST_NODE_IS_CHAT(target
)) {
1662 /* Add to the selected chat's group. */
1663 purple_blist_add_buddy((PurpleBuddy
*)node
, NULL
, tg
, NULL
);
1665 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1666 update_node_display(node
, ggblist
);
1667 if (PURPLE_BLIST_NODE(tg
) == target
)
1668 purple_blist_add_chat((PurpleChat
*)node
, tg
, NULL
);
1670 purple_blist_add_chat((PurpleChat
*)node
, NULL
, target
);
1677 context_menu_destroyed(GntWidget
*widget
, FinchBlist
*ggblist
)
1679 ggblist
->context
= NULL
;
1683 draw_context_menu(FinchBlist
*ggblist
)
1685 PurpleBlistNode
*node
= NULL
;
1686 GntWidget
*context
= NULL
;
1687 GntTree
*tree
= NULL
;
1688 int x
, y
, top
, width
;
1691 if (ggblist
->context
)
1694 tree
= GNT_TREE(ggblist
->tree
);
1696 node
= gnt_tree_get_selection_data(tree
);
1697 if (node
&& purple_blist_node_get_type(node
) == PURPLE_BLIST_OTHER_NODE
)
1700 if (ggblist
->tooltip
)
1701 remove_tooltip(ggblist
);
1703 ggblist
->cnode
= node
;
1705 ggblist
->context
= context
= gnt_menu_new(GNT_MENU_POPUP
);
1706 g_signal_connect(G_OBJECT(context
), "destroy", G_CALLBACK(context_menu_destroyed
), ggblist
);
1707 g_signal_connect(G_OBJECT(context
), "hide", G_CALLBACK(gnt_widget_destroy
), NULL
);
1710 create_group_menu(GNT_MENU(context
), NULL
);
1711 title
= g_strdup(_("Buddy List"));
1712 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1713 ggblist
->cnode
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)));
1714 create_buddy_menu(GNT_MENU(context
), (PurpleBuddy
*)ggblist
->cnode
);
1715 title
= g_strdup(purple_contact_get_alias((PurpleContact
*)node
));
1716 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1717 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
1718 create_buddy_menu(GNT_MENU(context
), buddy
);
1719 title
= g_strdup(purple_buddy_get_name(buddy
));
1720 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1721 PurpleChat
*chat
= (PurpleChat
*)node
;
1722 create_chat_menu(GNT_MENU(context
), chat
);
1723 title
= g_strdup(purple_chat_get_name(chat
));
1724 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1725 PurpleGroup
*group
= (PurpleGroup
*)node
;
1726 create_group_menu(GNT_MENU(context
), group
);
1727 title
= g_strdup(purple_group_get_name(group
));
1730 append_extended_menu(GNT_MENU(context
), node
);
1732 /* These are common for everything */
1734 add_custom_action(GNT_MENU(context
),
1735 PURPLE_BLIST_NODE_IS_GROUP(node
) ? _("Rename") : _("Alias"),
1736 PURPLE_CALLBACK(finch_blist_rename_node_cb
), node
);
1737 add_custom_action(GNT_MENU(context
), _("Remove"),
1738 PURPLE_CALLBACK(finch_blist_remove_node_cb
), node
);
1740 if (ggblist
->tagged
&& (PURPLE_BLIST_NODE_IS_CONTACT(node
)
1741 || PURPLE_BLIST_NODE_IS_GROUP(node
))) {
1742 add_custom_action(GNT_MENU(context
), _("Place tagged"),
1743 PURPLE_CALLBACK(finch_blist_place_tagged
), node
);
1746 if (PURPLE_BLIST_NODE_IS_BUDDY(node
) || PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1747 add_custom_action(GNT_MENU(context
), _("Toggle Tag"),
1748 PURPLE_CALLBACK(finch_blist_toggle_tag_buddy
), node
);
1750 if (!PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1751 add_custom_action(GNT_MENU(context
), _("View Log"),
1752 PURPLE_CALLBACK(showlog_cb
), node
);
1756 /* Set the position for the popup */
1757 gnt_widget_get_position(GNT_WIDGET(tree
), &x
, &y
);
1758 gnt_widget_get_size(GNT_WIDGET(tree
), &width
, NULL
);
1759 top
= gnt_tree_get_selection_visible_line(tree
);
1764 gnt_widget_set_position(context
, x
, y
);
1765 gnt_screen_menu_show(GNT_MENU(context
));
1770 tooltip_for_buddy(PurpleBuddy
*buddy
, GString
*str
, gboolean full
)
1773 PurplePluginProtocolInfo
*prpl_info
;
1774 PurpleAccount
*account
;
1775 PurpleNotifyUserInfo
*user_info
;
1776 PurplePresence
*presence
;
1777 const char *alias
= purple_buddy_get_alias(buddy
);
1780 user_info
= purple_notify_user_info_new();
1782 account
= purple_buddy_get_account(buddy
);
1783 presence
= purple_buddy_get_presence(buddy
);
1785 if (!full
|| g_utf8_collate(purple_buddy_get_name(buddy
), alias
)) {
1786 char *esc
= g_markup_escape_text(alias
, -1);
1787 purple_notify_user_info_add_pair(user_info
, _("Nickname"), esc
);
1791 tmp
= g_strdup_printf("%s (%s)",
1792 purple_account_get_username(account
),
1793 purple_account_get_protocol_name(account
));
1794 purple_notify_user_info_add_pair(user_info
, _("Account"), tmp
);
1797 prpl
= purple_find_prpl(purple_account_get_protocol_id(account
));
1798 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(prpl
);
1799 if (prpl_info
&& prpl_info
->tooltip_text
) {
1800 prpl_info
->tooltip_text(buddy
, user_info
, full
);
1803 if (purple_prefs_get_bool("/finch/blist/idletime")) {
1804 PurplePresence
*pre
= purple_buddy_get_presence(buddy
);
1805 if (purple_presence_is_idle(pre
)) {
1806 time_t idle
= purple_presence_get_idle_time(pre
);
1808 char *st
= purple_str_seconds_to_string(time(NULL
) - idle
);
1809 purple_notify_user_info_add_pair(user_info
, _("Idle"), st
);
1815 tmp
= purple_notify_user_info_get_text_with_newline(user_info
, "<BR>");
1816 purple_notify_user_info_destroy(user_info
);
1818 strip
= purple_markup_strip_html(tmp
);
1819 g_string_append(str
, strip
);
1821 if (purple_presence_is_status_primitive_active(presence
, PURPLE_STATUS_MOBILE
)) {
1822 g_string_append(str
, "\n");
1823 g_string_append(str
, _("On Mobile"));
1831 make_sure_text_fits(GString
*string
)
1833 int maxw
= getmaxx(stdscr
) - 3;
1834 char *str
= gnt_util_onscreen_fit_string(string
->str
, maxw
);
1835 string
= g_string_assign(string
, str
);
1841 draw_tooltip_real(FinchBlist
*ggblist
)
1843 PurpleBlistNode
*node
;
1844 int x
, y
, top
, width
, w
, h
;
1845 GString
*str
= NULL
;
1847 GntWidget
*widget
, *box
, *tv
;
1850 widget
= ggblist
->tree
;
1851 tree
= GNT_TREE(widget
);
1853 if (!gnt_widget_has_focus(ggblist
->tree
) ||
1854 (ggblist
->context
&& !GNT_WIDGET_IS_FLAG_SET(ggblist
->context
, GNT_WIDGET_INVISIBLE
)))
1857 if (ggblist
->tooltip
)
1859 /* XXX: Once we can properly redraw on expose events, this can be removed at the end
1860 * to avoid the blinking*/
1861 remove_tooltip(ggblist
);
1864 node
= gnt_tree_get_selection_data(tree
);
1868 if (!ggblist
->manager
->create_tooltip(node
, &str
, &title
))
1871 gnt_widget_get_position(widget
, &x
, &y
);
1872 gnt_widget_get_size(widget
, &width
, NULL
);
1873 top
= gnt_tree_get_selection_visible_line(tree
);
1878 box
= gnt_box_new(FALSE
, FALSE
);
1879 gnt_box_set_toplevel(GNT_BOX(box
), TRUE
);
1880 GNT_WIDGET_SET_FLAGS(box
, GNT_WIDGET_NO_SHADOW
);
1881 gnt_box_set_title(GNT_BOX(box
), title
);
1883 str
= make_sure_text_fits(str
);
1884 gnt_util_get_text_bound(str
->str
, &w
, &h
);
1886 tv
= gnt_text_view_new();
1887 gnt_widget_set_size(tv
, w
+ 1, h
);
1888 gnt_text_view_set_flag(GNT_TEXT_VIEW(tv
), GNT_TEXT_VIEW_NO_SCROLL
);
1889 gnt_box_add_widget(GNT_BOX(box
), tv
);
1891 if (x
+ w
>= getmaxx(stdscr
))
1893 gnt_widget_set_position(box
, x
, y
);
1894 GNT_WIDGET_UNSET_FLAGS(box
, GNT_WIDGET_CAN_TAKE_FOCUS
);
1895 GNT_WIDGET_SET_FLAGS(box
, GNT_WIDGET_TRANSIENT
);
1896 gnt_widget_draw(box
);
1898 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv
), str
->str
, GNT_TEXT_FLAG_NORMAL
);
1899 gnt_text_view_scroll(GNT_TEXT_VIEW(tv
), 0);
1902 g_string_free(str
, TRUE
);
1903 ggblist
->tooltip
= box
;
1904 ggblist
->tnode
= node
;
1906 gnt_widget_set_name(ggblist
->tooltip
, "tooltip");
1911 draw_tooltip(FinchBlist
*ggblist
)
1913 /* When an account has signed off, it removes one buddy at a time.
1914 * Drawing the tooltip after removing each buddy is expensive. On
1915 * top of that, if the selected buddy belongs to the disconnected
1916 * account, then retreiving the tooltip for that causes crash. So
1917 * let's make sure we wait for all the buddies to be removed first.*/
1918 int id
= g_timeout_add(0, (GSourceFunc
)draw_tooltip_real
, ggblist
);
1919 g_object_set_data_full(G_OBJECT(ggblist
->window
), "draw_tooltip_calback",
1920 GINT_TO_POINTER(id
), (GDestroyNotify
)g_source_remove
);
1924 selection_changed(GntWidget
*widget
, gpointer old
, gpointer current
, FinchBlist
*ggblist
)
1926 remove_peripherals(ggblist
);
1927 draw_tooltip(ggblist
);
1931 context_menu(GntWidget
*widget
, FinchBlist
*ggblist
)
1933 draw_context_menu(ggblist
);
1938 key_pressed(GntWidget
*widget
, const char *text
, FinchBlist
*ggblist
)
1940 if (text
[0] == 27 && text
[1] == 0) {
1941 /* Escape was pressed */
1942 if (gnt_tree_is_searching(GNT_TREE(ggblist
->tree
)))
1943 gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist
->tree
), "end-search", NULL
);
1944 remove_peripherals(ggblist
);
1945 } else if (purple_strequal(text
, GNT_KEY_INS
)) {
1946 PurpleBlistNode
*node
= gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
));
1947 purple_blist_request_add_buddy(NULL
, NULL
,
1948 node
&& PURPLE_BLIST_NODE_IS_GROUP(node
) ? purple_group_get_name(PURPLE_GROUP(node
)) : NULL
,
1950 } else if (!gnt_tree_is_searching(GNT_TREE(ggblist
->tree
))) {
1951 if (purple_strequal(text
, "t")) {
1952 finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
)));
1953 gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist
->tree
), "move-down", NULL
);
1954 } else if (purple_strequal(text
, "a")) {
1955 finch_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
)));
1965 update_node_display(PurpleBlistNode
*node
, FinchBlist
*ggblist
)
1967 GntTextFormatFlags flag
= get_blist_node_flag(node
);
1968 gnt_tree_set_row_flags(GNT_TREE(ggblist
->tree
), node
, flag
);
1972 update_buddy_display(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
1974 PurpleContact
*contact
;
1976 contact
= purple_buddy_get_contact(buddy
);
1978 gnt_tree_change_text(GNT_TREE(ggblist
->tree
), buddy
, 0, get_display_name((PurpleBlistNode
*)buddy
));
1979 gnt_tree_change_text(GNT_TREE(ggblist
->tree
), contact
, 0, get_display_name((PurpleBlistNode
*)contact
));
1981 blist_update_row_flags((PurpleBlistNode
*)buddy
);
1982 if (buddy
== purple_contact_get_priority_buddy(contact
))
1983 blist_update_row_flags((PurpleBlistNode
*)contact
);
1985 if (ggblist
->tnode
== (PurpleBlistNode
*)buddy
)
1986 draw_tooltip(ggblist
);
1990 buddy_status_changed(PurpleBuddy
*buddy
, PurpleStatus
*old
, PurpleStatus
*now
, FinchBlist
*ggblist
)
1992 update_buddy_display(buddy
, ggblist
);
1996 buddy_idle_changed(PurpleBuddy
*buddy
, int old
, int new, FinchBlist
*ggblist
)
1998 update_buddy_display(buddy
, ggblist
);
2002 remove_peripherals(FinchBlist
*ggblist
)
2004 if (ggblist
->tooltip
)
2005 remove_tooltip(ggblist
);
2006 else if (ggblist
->context
)
2007 gnt_widget_destroy(ggblist
->context
);
2011 size_changed_cb(GntWidget
*w
, int wi
, int h
)
2014 gnt_widget_get_size(w
, &width
, &height
);
2015 purple_prefs_set_int(PREF_ROOT
"/size/width", width
);
2016 purple_prefs_set_int(PREF_ROOT
"/size/height", height
);
2020 save_position_cb(GntWidget
*w
, int x
, int y
)
2022 purple_prefs_set_int(PREF_ROOT
"/position/x", x
);
2023 purple_prefs_set_int(PREF_ROOT
"/position/y", y
);
2027 reset_blist_window(GntWidget
*window
, gpointer null
)
2029 PurpleBlistNode
*node
;
2030 purple_signals_disconnect_by_handle(finch_blist_get_handle());
2031 FINCH_SET_DATA(purple_get_blist(), NULL
);
2033 node
= purple_blist_get_root();
2035 reset_blist_node_ui_data(node
);
2036 node
= purple_blist_node_next(node
, TRUE
);
2039 if (ggblist
->typing
)
2040 purple_timeout_remove(ggblist
->typing
);
2041 remove_peripherals(ggblist
);
2042 if (ggblist
->tagged
)
2043 g_list_free(ggblist
->tagged
);
2045 if (ggblist
->new_group_timeout
)
2046 purple_timeout_remove(ggblist
->new_group_timeout
);
2047 if (ggblist
->new_group
)
2048 g_list_free(ggblist
->new_group
);
2055 populate_buddylist(void)
2057 PurpleBlistNode
*node
;
2058 PurpleBuddyList
*list
;
2060 if (ggblist
->manager
->init
)
2061 ggblist
->manager
->init();
2063 if (purple_strequal(purple_prefs_get_string(PREF_ROOT
"/sort_type"), "text")) {
2064 gnt_tree_set_compare_func(GNT_TREE(ggblist
->tree
),
2065 (GCompareFunc
)blist_node_compare_text
);
2066 } else if (purple_strequal(purple_prefs_get_string(PREF_ROOT
"/sort_type"), "status")) {
2067 gnt_tree_set_compare_func(GNT_TREE(ggblist
->tree
),
2068 (GCompareFunc
)blist_node_compare_status
);
2069 } else if (purple_strequal(purple_prefs_get_string(PREF_ROOT
"/sort_type"), "log")) {
2070 gnt_tree_set_compare_func(GNT_TREE(ggblist
->tree
),
2071 (GCompareFunc
)blist_node_compare_log
);
2074 list
= purple_get_blist();
2075 node
= purple_blist_get_root();
2078 node_update(list
, node
);
2079 node
= purple_blist_node_next(node
, FALSE
);
2084 destroy_status_list(GList
*list
)
2086 g_list_foreach(list
, (GFunc
)g_free
, NULL
);
2091 populate_status_dropdown(void)
2095 GList
*items
= NULL
;
2096 StatusBoxItem
*item
= NULL
;
2098 /* First the primitives */
2099 PurpleStatusPrimitive prims
[] = {PURPLE_STATUS_AVAILABLE
, PURPLE_STATUS_AWAY
,
2100 PURPLE_STATUS_INVISIBLE
, PURPLE_STATUS_OFFLINE
, PURPLE_STATUS_UNSET
};
2102 gnt_combo_box_remove_all(GNT_COMBO_BOX(ggblist
->status
));
2104 for (i
= 0; prims
[i
] != PURPLE_STATUS_UNSET
; i
++)
2106 item
= g_new0(StatusBoxItem
, 1);
2107 item
->type
= STATUS_PRIMITIVE
;
2108 item
->u
.prim
= prims
[i
];
2109 items
= g_list_prepend(items
, item
);
2110 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2111 purple_primitive_get_name_from_type(prims
[i
]));
2114 /* Now the popular statuses */
2115 for (iter
= purple_savedstatuses_get_popular(6); iter
; iter
= g_list_delete_link(iter
, iter
))
2117 item
= g_new0(StatusBoxItem
, 1);
2118 item
->type
= STATUS_SAVED_POPULAR
;
2119 item
->u
.saved
= iter
->data
;
2120 items
= g_list_prepend(items
, item
);
2121 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2122 purple_savedstatus_get_title(iter
->data
));
2125 /* New savedstatus */
2126 item
= g_new0(StatusBoxItem
, 1);
2127 item
->type
= STATUS_SAVED_NEW
;
2128 items
= g_list_prepend(items
, item
);
2129 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2132 /* More savedstatuses */
2133 item
= g_new0(StatusBoxItem
, 1);
2134 item
->type
= STATUS_SAVED_ALL
;
2135 items
= g_list_prepend(items
, item
);
2136 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2139 /* The keys for the combobox are created here, and never used
2140 * anywhere else. So make sure the keys are freed when the widget
2142 g_object_set_data_full(G_OBJECT(ggblist
->status
), "list of statuses",
2143 items
, (GDestroyNotify
)destroy_status_list
);
2147 redraw_blist(const char *name
, PurplePrefType type
, gconstpointer val
, gpointer data
)
2149 PurpleBlistNode
*node
, *sel
;
2150 FinchBlistManager
*manager
;
2152 if (ggblist
== NULL
)
2155 manager
= finch_blist_manager_find(purple_prefs_get_string(PREF_ROOT
"/grouping"));
2156 if (manager
== NULL
)
2157 manager
= &default_manager
;
2158 if (ggblist
->manager
!= manager
) {
2159 if (ggblist
->manager
->uninit
)
2160 ggblist
->manager
->uninit();
2162 ggblist
->manager
= manager
;
2163 if (manager
->can_add_node
== NULL
)
2164 manager
->can_add_node
= default_can_add_node
;
2165 if (manager
->find_parent
== NULL
)
2166 manager
->find_parent
= default_find_parent
;
2167 if (manager
->create_tooltip
== NULL
)
2168 manager
->create_tooltip
= default_create_tooltip
;
2171 if (ggblist
->window
== NULL
)
2174 sel
= gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
));
2175 gnt_tree_remove_all(GNT_TREE(ggblist
->tree
));
2177 node
= purple_blist_get_root();
2178 for (; node
; node
= purple_blist_node_next(node
, TRUE
))
2179 reset_blist_node_ui_data(node
);
2180 populate_buddylist();
2181 gnt_tree_set_selected(GNT_TREE(ggblist
->tree
), sel
);
2182 draw_tooltip(ggblist
);
2185 void finch_blist_init()
2187 color_available
= gnt_style_get_color(NULL
, "color-available");
2188 if (!color_available
)
2189 color_available
= gnt_color_add_pair(COLOR_GREEN
, -1);
2190 color_away
= gnt_style_get_color(NULL
, "color-away");
2192 color_away
= gnt_color_add_pair(COLOR_BLUE
, -1);
2193 color_idle
= gnt_style_get_color(NULL
, "color-idle");
2195 color_idle
= gnt_color_add_pair(COLOR_CYAN
, -1);
2196 color_offline
= gnt_style_get_color(NULL
, "color-offline");
2198 color_offline
= gnt_color_add_pair(COLOR_RED
, -1);
2200 purple_prefs_add_none(PREF_ROOT
);
2201 purple_prefs_add_none(PREF_ROOT
"/size");
2202 purple_prefs_add_int(PREF_ROOT
"/size/width", 20);
2203 purple_prefs_add_int(PREF_ROOT
"/size/height", 17);
2204 purple_prefs_add_none(PREF_ROOT
"/position");
2205 purple_prefs_add_int(PREF_ROOT
"/position/x", 0);
2206 purple_prefs_add_int(PREF_ROOT
"/position/y", 0);
2207 purple_prefs_add_bool(PREF_ROOT
"/idletime", TRUE
);
2208 purple_prefs_add_bool(PREF_ROOT
"/showoffline", FALSE
);
2209 purple_prefs_add_bool(PREF_ROOT
"/emptygroups", FALSE
);
2210 purple_prefs_add_string(PREF_ROOT
"/sort_type", "text");
2211 purple_prefs_add_string(PREF_ROOT
"/grouping", "default");
2213 purple_prefs_connect_callback(finch_blist_get_handle(),
2214 PREF_ROOT
"/emptygroups", redraw_blist
, NULL
);
2215 purple_prefs_connect_callback(finch_blist_get_handle(),
2216 PREF_ROOT
"/showoffline", redraw_blist
, NULL
);
2217 purple_prefs_connect_callback(finch_blist_get_handle(),
2218 PREF_ROOT
"/sort_type", redraw_blist
, NULL
);
2219 purple_prefs_connect_callback(finch_blist_get_handle(),
2220 PREF_ROOT
"/grouping", redraw_blist
, NULL
);
2222 purple_signal_connect_priority(purple_connections_get_handle(),
2223 "autojoin", purple_blist_get_handle(),
2224 G_CALLBACK(account_autojoin_cb
), NULL
,
2225 PURPLE_SIGNAL_PRIORITY_HIGHEST
);
2227 finch_blist_install_manager(&default_manager
);
2233 remove_typing_cb(gpointer null
)
2235 PurpleSavedStatus
*current
;
2236 const char *message
, *newmessage
;
2237 char *escnewmessage
;
2238 PurpleStatusPrimitive prim
, newprim
;
2239 StatusBoxItem
*item
;
2241 current
= purple_savedstatus_get_current();
2242 message
= purple_savedstatus_get_message(current
);
2243 prim
= purple_savedstatus_get_type(current
);
2245 newmessage
= gnt_entry_get_text(GNT_ENTRY(ggblist
->statustext
));
2246 item
= gnt_combo_box_get_selected_data(GNT_COMBO_BOX(ggblist
->status
));
2247 escnewmessage
= newmessage
? g_markup_escape_text(newmessage
, -1) : NULL
;
2249 switch (item
->type
) {
2250 case STATUS_PRIMITIVE
:
2251 newprim
= item
->u
.prim
;
2253 case STATUS_SAVED_POPULAR
:
2254 newprim
= purple_savedstatus_get_type(item
->u
.saved
);
2257 goto end
; /* 'New' or 'Saved' is selected, but this should never happen. */
2260 if (newprim
!= prim
|| ((message
&& !escnewmessage
) ||
2261 (!message
&& escnewmessage
) ||
2262 (message
&& escnewmessage
&& g_utf8_collate(message
, escnewmessage
) != 0)))
2264 PurpleSavedStatus
*status
= purple_savedstatus_find_transient_by_type_and_message(newprim
, escnewmessage
);
2265 /* Holy Crap! That's a LAWNG function name */
2268 status
= purple_savedstatus_new(NULL
, newprim
);
2269 purple_savedstatus_set_message(status
, escnewmessage
);
2272 purple_savedstatus_activate(status
);
2275 gnt_box_give_focus_to_child(GNT_BOX(ggblist
->window
), ggblist
->tree
);
2277 g_free(escnewmessage
);
2278 if (ggblist
->typing
)
2279 purple_timeout_remove(ggblist
->typing
);
2280 ggblist
->typing
= 0;
2285 status_selection_changed(GntComboBox
*box
, StatusBoxItem
*old
, StatusBoxItem
*now
, gpointer null
)
2287 gnt_entry_set_text(GNT_ENTRY(ggblist
->statustext
), NULL
);
2288 if (now
->type
== STATUS_SAVED_POPULAR
)
2290 /* Set the status immediately */
2291 purple_savedstatus_activate(now
->u
.saved
);
2293 else if (now
->type
== STATUS_PRIMITIVE
)
2295 /* Move the focus to the entry box */
2296 /* XXX: Make sure the selected status can have a message */
2297 gnt_box_move_focus(GNT_BOX(ggblist
->window
), 1);
2298 ggblist
->typing
= purple_timeout_add_seconds(TYPING_TIMEOUT_S
, (GSourceFunc
)remove_typing_cb
, NULL
);
2300 else if (now
->type
== STATUS_SAVED_ALL
)
2302 /* Restore the selection to reflect current status. */
2303 savedstatus_changed(purple_savedstatus_get_current(), NULL
);
2304 gnt_box_give_focus_to_child(GNT_BOX(ggblist
->window
), ggblist
->tree
);
2305 finch_savedstatus_show_all();
2307 else if (now
->type
== STATUS_SAVED_NEW
)
2309 savedstatus_changed(purple_savedstatus_get_current(), NULL
);
2310 gnt_box_give_focus_to_child(GNT_BOX(ggblist
->window
), ggblist
->tree
);
2311 finch_savedstatus_edit(NULL
);
2314 g_return_if_reached();
2318 status_text_changed(GntEntry
*entry
, const char *text
, gpointer null
)
2320 if ((text
[0] == 27 || (text
[0] == '\t' && text
[1] == '\0')) && ggblist
->typing
== 0)
2323 if (ggblist
->typing
)
2324 purple_timeout_remove(ggblist
->typing
);
2325 ggblist
->typing
= 0;
2327 if (text
[0] == '\r' && text
[1] == 0)
2329 /* Set the status only after you press 'Enter' */
2330 remove_typing_cb(NULL
);
2334 ggblist
->typing
= purple_timeout_add_seconds(TYPING_TIMEOUT_S
, (GSourceFunc
)remove_typing_cb
, NULL
);
2339 savedstatus_changed(PurpleSavedStatus
*now
, PurpleSavedStatus
*old
)
2342 PurpleStatusPrimitive prim
;
2343 const char *message
;
2344 gboolean found
= FALSE
, saved
= TRUE
;
2349 /* Block the signals we don't want to emit */
2350 g_signal_handlers_block_matched(ggblist
->status
, G_SIGNAL_MATCH_FUNC
,
2351 0, 0, NULL
, status_selection_changed
, NULL
);
2352 g_signal_handlers_block_matched(ggblist
->statustext
, G_SIGNAL_MATCH_FUNC
,
2353 0, 0, NULL
, status_text_changed
, NULL
);
2355 prim
= purple_savedstatus_get_type(now
);
2356 message
= purple_savedstatus_get_message(now
);
2358 /* Rebuild the status dropdown */
2359 populate_status_dropdown();
2362 list
= g_object_get_data(G_OBJECT(ggblist
->status
), "list of statuses");
2363 for (; list
; list
= list
->next
)
2365 StatusBoxItem
*item
= list
->data
;
2366 if ((saved
&& item
->type
!= STATUS_PRIMITIVE
&& item
->u
.saved
== now
) ||
2367 (!saved
&& item
->type
== STATUS_PRIMITIVE
&& item
->u
.prim
== prim
))
2369 char *mess
= purple_unescape_html(message
);
2370 gnt_combo_box_set_selected(GNT_COMBO_BOX(ggblist
->status
), item
);
2371 gnt_entry_set_text(GNT_ENTRY(ggblist
->statustext
), mess
);
2372 gnt_widget_draw(ggblist
->status
);
2383 g_signal_handlers_unblock_matched(ggblist
->status
, G_SIGNAL_MATCH_FUNC
,
2384 0, 0, NULL
, status_selection_changed
, NULL
);
2385 g_signal_handlers_unblock_matched(ggblist
->statustext
, G_SIGNAL_MATCH_FUNC
,
2386 0, 0, NULL
, status_text_changed
, NULL
);
2390 blist_node_compare_position(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2392 while ((n1
= purple_blist_node_get_sibling_prev(n1
)) != NULL
)
2399 blist_node_compare_text(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2401 const char *s1
, *s2
;
2405 if (purple_blist_node_get_type(n1
) != purple_blist_node_get_type(n2
))
2406 return blist_node_compare_position(n1
, n2
);
2408 switch (purple_blist_node_get_type(n1
))
2410 case PURPLE_BLIST_CHAT_NODE
:
2411 s1
= purple_chat_get_name((PurpleChat
*)n1
);
2412 s2
= purple_chat_get_name((PurpleChat
*)n2
);
2414 case PURPLE_BLIST_BUDDY_NODE
:
2415 return purple_presence_compare(purple_buddy_get_presence((PurpleBuddy
*)n1
),
2416 purple_buddy_get_presence((PurpleBuddy
*)n2
));
2418 case PURPLE_BLIST_CONTACT_NODE
:
2419 s1
= purple_contact_get_alias((PurpleContact
*)n1
);
2420 s2
= purple_contact_get_alias((PurpleContact
*)n2
);
2423 return blist_node_compare_position(n1
, n2
);
2426 us1
= g_utf8_strup(s1
, -1);
2427 us2
= g_utf8_strup(s2
, -1);
2428 ret
= g_utf8_collate(us1
, us2
);
2436 blist_node_compare_status(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2440 if (purple_blist_node_get_type(n1
) != purple_blist_node_get_type(n2
))
2441 return blist_node_compare_position(n1
, n2
);
2443 switch (purple_blist_node_get_type(n1
)) {
2444 case PURPLE_BLIST_CONTACT_NODE
:
2445 n1
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(n1
)));
2446 n2
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(n2
)));
2447 /* now compare the presence of the priority buddies */
2448 case PURPLE_BLIST_BUDDY_NODE
:
2449 ret
= purple_presence_compare(purple_buddy_get_presence((PurpleBuddy
*)n1
),
2450 purple_buddy_get_presence((PurpleBuddy
*)n2
));
2455 return blist_node_compare_position(n1
, n2
);
2459 /* Sort alphabetically if presence is not comparable */
2460 ret
= blist_node_compare_text(n1
, n2
);
2466 get_contact_log_size(PurpleBlistNode
*c
)
2469 PurpleBlistNode
*node
;
2471 for (node
= purple_blist_node_get_first_child(c
); node
; node
= purple_blist_node_get_sibling_next(node
)) {
2472 PurpleBuddy
*b
= (PurpleBuddy
*)node
;
2473 log
+= purple_log_get_total_size(PURPLE_LOG_IM
, purple_buddy_get_name(b
),
2474 purple_buddy_get_account(b
));
2481 blist_node_compare_log(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2484 PurpleBuddy
*b1
, *b2
;
2486 if (purple_blist_node_get_type(n1
) != purple_blist_node_get_type(n2
))
2487 return blist_node_compare_position(n1
, n2
);
2489 switch (purple_blist_node_get_type(n1
)) {
2490 case PURPLE_BLIST_BUDDY_NODE
:
2491 b1
= (PurpleBuddy
*)n1
;
2492 b2
= (PurpleBuddy
*)n2
;
2493 ret
= purple_log_get_total_size(PURPLE_LOG_IM
, purple_buddy_get_name(b2
), purple_buddy_get_account(b2
)) -
2494 purple_log_get_total_size(PURPLE_LOG_IM
, purple_buddy_get_name(b1
), purple_buddy_get_account(b1
));
2498 case PURPLE_BLIST_CONTACT_NODE
:
2499 ret
= get_contact_log_size(n2
) - get_contact_log_size(n1
);
2504 return blist_node_compare_position(n1
, n2
);
2506 ret
= blist_node_compare_text(n1
, n2
);
2511 plugin_action(GntMenuItem
*item
, gpointer data
)
2513 PurplePluginAction
*action
= data
;
2514 if (action
&& action
->callback
)
2515 action
->callback(action
);
2519 build_plugin_actions(GntMenuItem
*item
, PurplePlugin
*plugin
, gpointer context
)
2521 GntWidget
*sub
= gnt_menu_new(GNT_MENU_POPUP
);
2523 GntMenuItem
*menuitem
;
2525 gnt_menuitem_set_submenu(item
, GNT_MENU(sub
));
2526 for (actions
= PURPLE_PLUGIN_ACTIONS(plugin
, context
); actions
;
2527 actions
= g_list_delete_link(actions
, actions
)) {
2528 if (actions
->data
) {
2529 PurplePluginAction
*action
= actions
->data
;
2530 action
->plugin
= plugin
;
2531 action
->context
= context
;
2532 menuitem
= gnt_menuitem_new(action
->label
);
2533 gnt_menu_add_item(GNT_MENU(sub
), menuitem
);
2535 gnt_menuitem_set_callback(menuitem
, plugin_action
, action
);
2536 g_object_set_data_full(G_OBJECT(menuitem
), "plugin_action",
2537 action
, (GDestroyNotify
)purple_plugin_action_free
);
2543 buddy_recent_signed_on_off(gpointer data
)
2545 PurpleBlistNode
*node
= data
;
2546 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
2548 purple_timeout_remove(fnode
->signed_timer
);
2549 fnode
->signed_timer
= 0;
2551 if (!ggblist
->manager
->can_add_node(node
)) {
2552 node_remove(purple_get_blist(), node
);
2554 update_node_display(node
, ggblist
);
2555 if (purple_blist_node_get_parent(node
) && PURPLE_BLIST_NODE_IS_CONTACT(purple_blist_node_get_parent(node
)))
2556 update_node_display(purple_blist_node_get_parent(node
), ggblist
);
2563 buddy_signed_on_off_cb(gpointer data
)
2565 PurpleBlistNode
*node
= data
;
2566 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
2567 if (!ggblist
|| !fnode
)
2570 if (fnode
->signed_timer
)
2571 purple_timeout_remove(fnode
->signed_timer
);
2572 fnode
->signed_timer
= purple_timeout_add_seconds(6, (GSourceFunc
)buddy_recent_signed_on_off
, data
);
2573 update_node_display(node
, ggblist
);
2574 if (purple_blist_node_get_parent(node
) && PURPLE_BLIST_NODE_IS_CONTACT(purple_blist_node_get_parent(node
)))
2575 update_node_display(purple_blist_node_get_parent(node
), ggblist
);
2580 buddy_signed_on_off(PurpleBuddy
* buddy
, gpointer null
)
2582 g_idle_add(buddy_signed_on_off_cb
, buddy
);
2586 reconstruct_plugins_menu(void)
2595 if (ggblist
->plugins
== NULL
)
2596 ggblist
->plugins
= gnt_menuitem_new(_("Plugins"));
2598 plg
= ggblist
->plugins
;
2599 sub
= gnt_menu_new(GNT_MENU_POPUP
);
2600 gnt_menuitem_set_submenu(plg
, GNT_MENU(sub
));
2602 for (iter
= purple_plugins_get_loaded(); iter
; iter
= iter
->next
) {
2603 PurplePlugin
*plugin
= iter
->data
;
2605 if (PURPLE_IS_PROTOCOL_PLUGIN(plugin
))
2608 if (!PURPLE_PLUGIN_HAS_ACTIONS(plugin
))
2611 item
= gnt_menuitem_new(_(plugin
->info
->name
));
2612 gnt_menu_add_item(GNT_MENU(sub
), item
);
2613 build_plugin_actions(item
, plugin
, NULL
);
2618 reconstruct_accounts_menu(void)
2621 GntMenuItem
*acc
, *item
;
2627 if (ggblist
->accounts
== NULL
)
2628 ggblist
->accounts
= gnt_menuitem_new(_("Accounts"));
2630 acc
= ggblist
->accounts
;
2631 sub
= gnt_menu_new(GNT_MENU_POPUP
);
2632 gnt_menuitem_set_submenu(acc
, GNT_MENU(sub
));
2634 for (iter
= purple_accounts_get_all_active(); iter
;
2635 iter
= g_list_delete_link(iter
, iter
)) {
2636 PurpleAccount
*account
= iter
->data
;
2637 PurpleConnection
*gc
= purple_account_get_connection(account
);
2640 if (!gc
|| !PURPLE_CONNECTION_IS_CONNECTED(gc
))
2642 prpl
= purple_connection_get_prpl(gc
);
2644 if (PURPLE_PLUGIN_HAS_ACTIONS(prpl
)) {
2645 item
= gnt_menuitem_new(purple_account_get_username(account
));
2646 gnt_menu_add_item(GNT_MENU(sub
), item
);
2647 build_plugin_actions(item
, prpl
, gc
);
2653 reconstruct_grouping_menu(void)
2658 if (!ggblist
|| !ggblist
->grouping
)
2661 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
2662 gnt_menuitem_set_submenu(ggblist
->grouping
, GNT_MENU(subsub
));
2664 for (iter
= managers
; iter
; iter
= iter
->next
) {
2666 FinchBlistManager
*manager
= iter
->data
;
2667 GntMenuItem
*item
= gnt_menuitem_new(_(manager
->name
));
2668 g_snprintf(menuid
, sizeof(menuid
), "grouping-%s", manager
->id
);
2669 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), menuid
);
2670 gnt_menu_add_item(GNT_MENU(subsub
), item
);
2671 g_object_set_data_full(G_OBJECT(item
), "grouping-id", g_strdup(manager
->id
), g_free
);
2672 gnt_menuitem_set_callback(item
, menu_group_set_cb
, NULL
);
2677 auto_join_chats(gpointer data
)
2679 PurpleBlistNode
*node
;
2680 PurpleConnection
*pc
= data
;
2681 PurpleAccount
*account
= purple_connection_get_account(pc
);
2683 for (node
= purple_blist_get_root(); node
;
2684 node
= purple_blist_node_next(node
, FALSE
)) {
2685 if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
2686 PurpleChat
*chat
= (PurpleChat
*)node
;
2687 if (purple_chat_get_account(chat
) == account
&&
2688 purple_blist_node_get_bool(node
, "gnt-autojoin"))
2689 serv_join_chat(purple_account_get_connection(account
), purple_chat_get_components(chat
));
2696 account_autojoin_cb(PurpleConnection
*gc
, gpointer null
)
2698 g_idle_add(auto_join_chats
, gc
);
2702 static void toggle_pref_cb(GntMenuItem
*item
, gpointer n
)
2704 purple_prefs_set_bool(n
, !purple_prefs_get_bool(n
));
2707 static void sort_blist_change_cb(GntMenuItem
*item
, gpointer n
)
2709 purple_prefs_set_string(PREF_ROOT
"/sort_type", n
);
2713 block_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2715 PurpleAccount
*account
= purple_request_fields_get_account(fields
, "account");
2716 const char *name
= purple_request_fields_get_string(fields
, "screenname");
2717 if (account
&& name
&& *name
!= '\0') {
2718 if (purple_request_fields_get_choice(fields
, "block") == 1) {
2719 purple_privacy_deny(account
, name
, FALSE
, FALSE
);
2721 purple_privacy_allow(account
, name
, FALSE
, FALSE
);
2727 block_select(GntMenuItem
*item
, gpointer n
)
2729 PurpleRequestFields
*fields
;
2730 PurpleRequestFieldGroup
*group
;
2731 PurpleRequestField
*field
;
2733 fields
= purple_request_fields_new();
2735 group
= purple_request_field_group_new(NULL
);
2736 purple_request_fields_add_group(fields
, group
);
2738 field
= purple_request_field_string_new("screenname", _("Name"), NULL
, FALSE
);
2739 purple_request_field_set_type_hint(field
, "screenname");
2740 purple_request_field_set_required(field
, TRUE
);
2741 purple_request_field_group_add_field(group
, field
);
2743 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2744 purple_request_field_set_type_hint(field
, "account");
2745 purple_request_field_set_visible(field
,
2746 (purple_connections_get_all() != NULL
&&
2747 purple_connections_get_all()->next
!= NULL
));
2748 purple_request_field_set_required(field
, TRUE
);
2749 purple_request_field_group_add_field(group
, field
);
2751 field
= purple_request_field_choice_new("block", _("Block/Unblock"), 1);
2752 purple_request_field_choice_add(field
, _("Block"));
2753 purple_request_field_choice_add(field
, _("Unblock"));
2754 purple_request_field_group_add_field(group
, field
);
2756 purple_request_fields(purple_get_blist(), _("Block/Unblock"),
2758 _("Please enter the username or alias of the person "
2759 "you would like to Block/Unblock."),
2761 _("OK"), G_CALLBACK(block_select_cb
),
2767 /* send_im_select* -- Xerox */
2769 send_im_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2771 PurpleAccount
*account
;
2772 const char *username
;
2773 PurpleConversation
*conv
;
2775 account
= purple_request_fields_get_account(fields
, "account");
2776 username
= purple_request_fields_get_string(fields
, "screenname");
2778 conv
= purple_conversation_new(PURPLE_CONV_TYPE_IM
, account
, username
);
2779 purple_conversation_present(conv
);
2783 send_im_select(GntMenuItem
*item
, gpointer n
)
2785 PurpleRequestFields
*fields
;
2786 PurpleRequestFieldGroup
*group
;
2787 PurpleRequestField
*field
;
2789 fields
= purple_request_fields_new();
2791 group
= purple_request_field_group_new(NULL
);
2792 purple_request_fields_add_group(fields
, group
);
2794 field
= purple_request_field_string_new("screenname", _("Name"), NULL
, FALSE
);
2795 purple_request_field_set_type_hint(field
, "screenname");
2796 purple_request_field_set_required(field
, TRUE
);
2797 purple_request_field_group_add_field(group
, field
);
2799 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2800 purple_request_field_set_type_hint(field
, "account");
2801 purple_request_field_set_visible(field
,
2802 (purple_connections_get_all() != NULL
&&
2803 purple_connections_get_all()->next
!= NULL
));
2804 purple_request_field_set_required(field
, TRUE
);
2805 purple_request_field_group_add_field(group
, field
);
2807 purple_request_fields(purple_get_blist(), _("New Instant Message"),
2809 _("Please enter the username or alias of the person "
2810 "you would like to IM."),
2812 _("OK"), G_CALLBACK(send_im_select_cb
),
2819 join_chat_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2821 PurpleAccount
*account
;
2823 PurpleConnection
*gc
;
2825 GHashTable
*hash
= NULL
;
2826 PurpleConversation
*conv
;
2828 account
= purple_request_fields_get_account(fields
, "account");
2829 name
= purple_request_fields_get_string(fields
, "chat");
2831 if (!purple_account_is_connected(account
))
2834 gc
= purple_account_get_connection(account
);
2835 /* Create a new conversation now. This will give focus to the new window.
2836 * But it's necessary to pretend that we left the chat, because otherwise
2837 * a new conversation window will pop up when we finally join the chat. */
2838 if (!(conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT
, name
, account
))) {
2839 conv
= purple_conversation_new(PURPLE_CONV_TYPE_CHAT
, account
, name
);
2840 purple_conv_chat_left(PURPLE_CONV_CHAT(conv
));
2842 purple_conversation_present(conv
);
2845 chat
= purple_blist_find_chat(account
, name
);
2847 PurplePluginProtocolInfo
*info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
2848 if (info
->chat_info_defaults
!= NULL
)
2849 hash
= info
->chat_info_defaults(gc
, name
);
2851 hash
= purple_chat_get_components(chat
);
2853 serv_join_chat(gc
, hash
);
2854 if (chat
== NULL
&& hash
!= NULL
)
2855 g_hash_table_destroy(hash
);
2859 join_chat_select(GntMenuItem
*item
, gpointer n
)
2861 PurpleRequestFields
*fields
;
2862 PurpleRequestFieldGroup
*group
;
2863 PurpleRequestField
*field
;
2865 fields
= purple_request_fields_new();
2867 group
= purple_request_field_group_new(NULL
);
2868 purple_request_fields_add_group(fields
, group
);
2870 field
= purple_request_field_string_new("chat", _("Channel"), NULL
, FALSE
);
2871 purple_request_field_set_required(field
, TRUE
);
2872 purple_request_field_group_add_field(group
, field
);
2874 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2875 purple_request_field_set_type_hint(field
, "account");
2876 purple_request_field_set_visible(field
,
2877 (purple_connections_get_all() != NULL
&&
2878 purple_connections_get_all()->next
!= NULL
));
2879 purple_request_field_set_required(field
, TRUE
);
2880 purple_request_field_group_add_field(group
, field
);
2882 purple_request_fields(purple_get_blist(), _("Join a Chat"),
2884 _("Please enter the name of the chat you want to join."),
2886 _("Join"), G_CALLBACK(join_chat_select_cb
),
2893 view_log_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2895 PurpleAccount
*account
;
2898 PurpleContact
*contact
;
2900 account
= purple_request_fields_get_account(fields
, "account");
2901 name
= purple_request_fields_get_string(fields
, "screenname");
2903 buddy
= purple_find_buddy(account
, name
);
2905 contact
= purple_buddy_get_contact(buddy
);
2911 finch_log_show_contact(contact
);
2913 finch_log_show(PURPLE_LOG_IM
, name
, account
);
2918 view_log_cb(GntMenuItem
*item
, gpointer n
)
2920 PurpleRequestFields
*fields
;
2921 PurpleRequestFieldGroup
*group
;
2922 PurpleRequestField
*field
;
2924 fields
= purple_request_fields_new();
2926 group
= purple_request_field_group_new(NULL
);
2927 purple_request_fields_add_group(fields
, group
);
2929 field
= purple_request_field_string_new("screenname", _("Name"), NULL
, FALSE
);
2930 purple_request_field_set_type_hint(field
, "screenname-all");
2931 purple_request_field_set_required(field
, TRUE
);
2932 purple_request_field_group_add_field(group
, field
);
2934 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2935 purple_request_field_set_type_hint(field
, "account");
2936 purple_request_field_set_visible(field
,
2937 (purple_accounts_get_all() != NULL
&&
2938 purple_accounts_get_all()->next
!= NULL
));
2939 purple_request_field_set_required(field
, TRUE
);
2940 purple_request_field_group_add_field(group
, field
);
2941 purple_request_field_account_set_show_all(field
, TRUE
);
2943 purple_request_fields(purple_get_blist(), _("View Log"),
2945 _("Please enter the username or alias of the person "
2946 "whose log you would like to view."),
2948 _("OK"), G_CALLBACK(view_log_select_cb
),
2955 view_all_logs_cb(GntMenuItem
*item
, gpointer n
)
2957 finch_log_show(PURPLE_LOG_IM
, NULL
, NULL
);
2961 menu_add_buddy_cb(GntMenuItem
*item
, gpointer null
)
2963 purple_blist_request_add_buddy(NULL
, NULL
, NULL
, NULL
);
2967 menu_add_chat_cb(GntMenuItem
*item
, gpointer null
)
2969 purple_blist_request_add_chat(NULL
, NULL
, NULL
, NULL
);
2973 menu_add_group_cb(GntMenuItem
*item
, gpointer null
)
2975 purple_blist_request_add_group();
2979 menu_group_set_cb(GntMenuItem
*item
, gpointer null
)
2981 const char *id
= g_object_get_data(G_OBJECT(item
), "grouping-id");
2982 purple_prefs_set_string(PREF_ROOT
"/grouping", id
);
2988 GntWidget
*menu
, *sub
, *subsub
;
2995 window
= GNT_WINDOW(ggblist
->window
);
2996 ggblist
->menu
= menu
= gnt_menu_new(GNT_MENU_TOPLEVEL
);
2997 gnt_window_set_menu(window
, GNT_MENU(menu
));
2999 item
= gnt_menuitem_new(_("Options"));
3000 gnt_menu_add_item(GNT_MENU(menu
), item
);
3002 sub
= gnt_menu_new(GNT_MENU_POPUP
);
3003 gnt_menuitem_set_submenu(item
, GNT_MENU(sub
));
3005 item
= gnt_menuitem_new(_("Send IM..."));
3006 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "send-im");
3007 gnt_menu_add_item(GNT_MENU(sub
), item
);
3008 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), send_im_select
, NULL
);
3010 item
= gnt_menuitem_new(_("Block/Unblock..."));
3011 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "block-unblock");
3012 gnt_menu_add_item(GNT_MENU(sub
), item
);
3013 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), block_select
, NULL
);
3015 item
= gnt_menuitem_new(_("Join Chat..."));
3016 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "join-chat");
3017 gnt_menu_add_item(GNT_MENU(sub
), item
);
3018 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), join_chat_select
, NULL
);
3020 item
= gnt_menuitem_new(_("View Log..."));
3021 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "view-log");
3022 gnt_menu_add_item(GNT_MENU(sub
), item
);
3023 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), view_log_cb
, NULL
);
3025 item
= gnt_menuitem_new(_("View All Logs"));
3026 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "view-all-logs");
3027 gnt_menu_add_item(GNT_MENU(sub
), item
);
3028 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), view_all_logs_cb
, NULL
);
3030 item
= gnt_menuitem_new(_("Show"));
3031 gnt_menu_add_item(GNT_MENU(sub
), item
);
3032 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
3033 gnt_menuitem_set_submenu(item
, GNT_MENU(subsub
));
3035 item
= gnt_menuitem_check_new(_("Empty groups"));
3036 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "show-empty-groups");
3037 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
),
3038 purple_prefs_get_bool(PREF_ROOT
"/emptygroups"));
3039 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3040 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), toggle_pref_cb
, PREF_ROOT
"/emptygroups");
3042 item
= gnt_menuitem_check_new(_("Offline buddies"));
3043 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "show-offline-buddies");
3044 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
),
3045 purple_prefs_get_bool(PREF_ROOT
"/showoffline"));
3046 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3047 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), toggle_pref_cb
, PREF_ROOT
"/showoffline");
3049 item
= gnt_menuitem_new(_("Sort"));
3050 gnt_menu_add_item(GNT_MENU(sub
), item
);
3051 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
3052 gnt_menuitem_set_submenu(item
, GNT_MENU(subsub
));
3054 item
= gnt_menuitem_new(_("By Status"));
3055 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "sort-status");
3056 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3057 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), sort_blist_change_cb
, "status");
3059 item
= gnt_menuitem_new(_("Alphabetically"));
3060 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "sort-alpha");
3061 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3062 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), sort_blist_change_cb
, "text");
3064 item
= gnt_menuitem_new(_("By Log Size"));
3065 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "sort-log");
3066 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3067 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), sort_blist_change_cb
, "log");
3069 item
= gnt_menuitem_new(_("Add"));
3070 gnt_menu_add_item(GNT_MENU(sub
), item
);
3072 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
3073 gnt_menuitem_set_submenu(item
, GNT_MENU(subsub
));
3075 item
= gnt_menuitem_new(_("Buddy"));
3076 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "add-buddy");
3077 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3078 gnt_menuitem_set_callback(item
, menu_add_buddy_cb
, NULL
);
3080 item
= gnt_menuitem_new(_("Chat"));
3081 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "add-chat");
3082 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3083 gnt_menuitem_set_callback(item
, menu_add_chat_cb
, NULL
);
3085 item
= gnt_menuitem_new(_("Group"));
3086 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "add-group");
3087 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3088 gnt_menuitem_set_callback(item
, menu_add_group_cb
, NULL
);
3090 ggblist
->grouping
= item
= gnt_menuitem_new(_("Grouping"));
3091 gnt_menu_add_item(GNT_MENU(sub
), item
);
3092 reconstruct_grouping_menu();
3094 reconstruct_accounts_menu();
3095 gnt_menu_add_item(GNT_MENU(menu
), ggblist
->accounts
);
3097 reconstruct_plugins_menu();
3098 gnt_menu_add_item(GNT_MENU(menu
), ggblist
->plugins
);
3101 void finch_blist_show()
3103 blist_show(purple_get_blist());
3107 group_collapsed(GntWidget
*widget
, PurpleBlistNode
*node
, gboolean collapsed
, gpointer null
)
3109 if (PURPLE_BLIST_NODE_IS_GROUP(node
))
3110 purple_blist_node_set_bool(node
, "collapsed", collapsed
);
3114 blist_show(PurpleBuddyList
*list
)
3116 if (ggblist
== NULL
)
3118 else if (ggblist
->window
) {
3119 gnt_window_present(ggblist
->window
);
3123 ggblist
->window
= gnt_vwindow_new(FALSE
);
3124 gnt_widget_set_name(ggblist
->window
, "buddylist");
3125 gnt_box_set_toplevel(GNT_BOX(ggblist
->window
), TRUE
);
3126 gnt_box_set_title(GNT_BOX(ggblist
->window
), _("Buddy List"));
3127 gnt_box_set_pad(GNT_BOX(ggblist
->window
), 0);
3129 ggblist
->tree
= gnt_tree_new();
3131 GNT_WIDGET_SET_FLAGS(ggblist
->tree
, GNT_WIDGET_NO_BORDER
);
3132 gnt_widget_set_size(ggblist
->tree
, purple_prefs_get_int(PREF_ROOT
"/size/width"),
3133 purple_prefs_get_int(PREF_ROOT
"/size/height"));
3134 gnt_widget_set_position(ggblist
->window
, purple_prefs_get_int(PREF_ROOT
"/position/x"),
3135 purple_prefs_get_int(PREF_ROOT
"/position/y"));
3137 gnt_box_add_widget(GNT_BOX(ggblist
->window
), ggblist
->tree
);
3139 ggblist
->status
= gnt_combo_box_new();
3140 gnt_box_add_widget(GNT_BOX(ggblist
->window
), ggblist
->status
);
3141 ggblist
->statustext
= gnt_entry_new(NULL
);
3142 gnt_box_add_widget(GNT_BOX(ggblist
->window
), ggblist
->statustext
);
3144 gnt_widget_show(ggblist
->window
);
3146 purple_signal_connect(purple_connections_get_handle(), "signed-on", finch_blist_get_handle(),
3147 PURPLE_CALLBACK(reconstruct_accounts_menu
), NULL
);
3148 purple_signal_connect(purple_connections_get_handle(), "signed-off", finch_blist_get_handle(),
3149 PURPLE_CALLBACK(reconstruct_accounts_menu
), NULL
);
3150 purple_signal_connect(purple_accounts_get_handle(), "account-actions-changed", finch_blist_get_handle(),
3151 PURPLE_CALLBACK(reconstruct_accounts_menu
), NULL
);
3152 purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", finch_blist_get_handle(),
3153 PURPLE_CALLBACK(buddy_status_changed
), ggblist
);
3154 purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", finch_blist_get_handle(),
3155 PURPLE_CALLBACK(buddy_idle_changed
), ggblist
);
3157 purple_signal_connect(purple_plugins_get_handle(), "plugin-load", finch_blist_get_handle(),
3158 PURPLE_CALLBACK(reconstruct_plugins_menu
), NULL
);
3159 purple_signal_connect(purple_plugins_get_handle(), "plugin-unload", finch_blist_get_handle(),
3160 PURPLE_CALLBACK(reconstruct_plugins_menu
), NULL
);
3162 purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_blist_get_handle(),
3163 PURPLE_CALLBACK(buddy_signed_on_off
), ggblist
);
3164 purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_blist_get_handle(),
3165 PURPLE_CALLBACK(buddy_signed_on_off
), ggblist
);
3168 /* These I plan to use to indicate unread-messages etc. */
3169 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", finch_blist_get_handle(),
3170 PURPLE_CALLBACK(received_im_msg
), list
);
3171 purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg", finch_blist_get_handle(),
3172 PURPLE_CALLBACK(sent_im_msg
), NULL
);
3174 purple_signal_connect(purple_conversations_get_handle(), "received-chat-msg", finch_blist_get_handle(),
3175 PURPLE_CALLBACK(received_chat_msg
), list
);
3178 g_signal_connect(G_OBJECT(ggblist
->tree
), "selection_changed", G_CALLBACK(selection_changed
), ggblist
);
3179 g_signal_connect(G_OBJECT(ggblist
->tree
), "key_pressed", G_CALLBACK(key_pressed
), ggblist
);
3180 g_signal_connect(G_OBJECT(ggblist
->tree
), "context-menu", G_CALLBACK(context_menu
), ggblist
);
3181 g_signal_connect(G_OBJECT(ggblist
->tree
), "collapse-toggled", G_CALLBACK(group_collapsed
), NULL
);
3182 g_signal_connect(G_OBJECT(ggblist
->tree
), "activate", G_CALLBACK(selection_activate
), ggblist
);
3183 g_signal_connect_data(G_OBJECT(ggblist
->tree
), "gained-focus", G_CALLBACK(draw_tooltip
),
3184 ggblist
, 0, G_CONNECT_AFTER
| G_CONNECT_SWAPPED
);
3185 g_signal_connect_data(G_OBJECT(ggblist
->tree
), "lost-focus", G_CALLBACK(remove_peripherals
),
3186 ggblist
, 0, G_CONNECT_AFTER
| G_CONNECT_SWAPPED
);
3187 g_signal_connect_data(G_OBJECT(ggblist
->window
), "workspace-hidden", G_CALLBACK(remove_peripherals
),
3188 ggblist
, 0, G_CONNECT_AFTER
| G_CONNECT_SWAPPED
);
3189 g_signal_connect(G_OBJECT(ggblist
->tree
), "size_changed", G_CALLBACK(size_changed_cb
), NULL
);
3190 g_signal_connect(G_OBJECT(ggblist
->window
), "position_set", G_CALLBACK(save_position_cb
), NULL
);
3191 g_signal_connect(G_OBJECT(ggblist
->window
), "destroy", G_CALLBACK(reset_blist_window
), NULL
);
3193 /* Status signals */
3194 purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed", finch_blist_get_handle(),
3195 PURPLE_CALLBACK(savedstatus_changed
), NULL
);
3196 g_signal_connect(G_OBJECT(ggblist
->status
), "selection_changed",
3197 G_CALLBACK(status_selection_changed
), NULL
);
3198 g_signal_connect(G_OBJECT(ggblist
->statustext
), "key_pressed",
3199 G_CALLBACK(status_text_changed
), NULL
);
3203 populate_buddylist();
3205 savedstatus_changed(purple_savedstatus_get_current(), NULL
);
3208 void finch_blist_uninit()
3212 gboolean
finch_blist_get_position(int *x
, int *y
)
3214 if (!ggblist
|| !ggblist
->window
)
3216 gnt_widget_get_position(ggblist
->window
, x
, y
);
3220 void finch_blist_set_position(int x
, int y
)
3222 gnt_widget_set_position(ggblist
->window
, x
, y
);
3225 gboolean
finch_blist_get_size(int *width
, int *height
)
3227 if (!ggblist
|| !ggblist
->window
)
3229 gnt_widget_get_size(ggblist
->window
, width
, height
);
3233 void finch_blist_set_size(int width
, int height
)
3235 gnt_widget_set_size(ggblist
->window
, width
, height
);
3238 void finch_blist_install_manager(const FinchBlistManager
*manager
)
3240 if (!g_list_find(managers
, manager
)) {
3241 managers
= g_list_append(managers
, (gpointer
)manager
);
3242 reconstruct_grouping_menu();
3243 if (purple_strequal(manager
->id
, purple_prefs_get_string(PREF_ROOT
"/grouping")))
3244 purple_prefs_trigger_callback(PREF_ROOT
"/grouping");
3248 void finch_blist_uninstall_manager(const FinchBlistManager
*manager
)
3250 if (g_list_find(managers
, manager
)) {
3251 managers
= g_list_remove(managers
, manager
);
3252 reconstruct_grouping_menu();
3253 if (purple_strequal(manager
->id
, purple_prefs_get_string(PREF_ROOT
"/grouping")))
3254 purple_prefs_trigger_callback(PREF_ROOT
"/grouping");
3258 FinchBlistManager
* finch_blist_manager_find(const char *id
)
3260 GList
*iter
= managers
;
3264 for (; iter
; iter
= iter
->next
) {
3265 FinchBlistManager
*m
= iter
->data
;
3266 if (purple_strequal(id
, m
->id
))
3272 GntTree
* finch_blist_get_tree(void)
3274 return ggblist
? GNT_TREE(ggblist
->tree
) : NULL
;