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 void account_signed_on_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 PurpleAccount
*account
= purple_request_fields_get_account(allfields
, "account");
630 const char *error
= NULL
;
635 error
= _("You must provide a username for the buddy.");
637 error
= _("You must provide a group.");
639 error
= _("You must select an account.");
640 else if (!purple_account_is_connected(account
))
641 error
= _("The selected account is not online.");
645 finch_request_add_buddy(account
, username
, group
, alias
);
646 purple_notify_error(NULL
, _("Error"), _("Error adding buddy"), error
);
650 grp
= purple_find_group(group
);
653 grp
= purple_group_new(group
);
654 purple_blist_add_group(grp
, NULL
);
657 /* XXX: Ask to merge if there's already a buddy with the same alias in the same group (#4553) */
659 if ((buddy
= purple_find_buddy_in_group(account
, username
, grp
)) == NULL
)
661 buddy
= purple_buddy_new(account
, username
, alias
);
662 purple_blist_add_buddy(buddy
, NULL
, grp
, NULL
);
665 purple_account_add_buddy(account
, buddy
);
669 finch_request_add_buddy(PurpleAccount
*account
, const char *username
, const char *grp
, const char *alias
)
671 PurpleRequestFields
*fields
= purple_request_fields_new();
672 PurpleRequestFieldGroup
*group
= purple_request_field_group_new(NULL
);
673 PurpleRequestField
*field
;
675 purple_request_fields_add_group(fields
, group
);
677 field
= purple_request_field_string_new("screenname", _("Username"), username
, FALSE
);
678 purple_request_field_group_add_field(group
, field
);
680 field
= purple_request_field_string_new("alias", _("Alias (optional)"), alias
, FALSE
);
681 purple_request_field_group_add_field(group
, field
);
683 field
= purple_request_field_string_new("group", _("Add in group"), grp
, FALSE
);
684 purple_request_field_group_add_field(group
, field
);
685 purple_request_field_set_type_hint(field
, "group");
687 field
= purple_request_field_account_new("account", _("Account"), NULL
);
688 purple_request_field_account_set_show_all(field
, FALSE
);
690 purple_request_field_account_set_value(field
, account
);
691 purple_request_field_group_add_field(group
, field
);
693 purple_request_fields(NULL
, _("Add Buddy"), NULL
, _("Please enter buddy information."),
695 _("Add"), G_CALLBACK(add_buddy_cb
),
702 join_chat(PurpleChat
*chat
)
704 PurpleAccount
*account
= purple_chat_get_account(chat
);
706 PurpleConversation
*conv
;
709 /* This hack here is to work around the fact that there's no good way of
710 * getting the actual name of a chat. I don't understand why we return
711 * the alias for a chat when all we want is the name. */
714 name
= purple_chat_get_name(chat
);
715 conv
= purple_find_conversation_with_account(
716 PURPLE_CONV_TYPE_CHAT
, name
, account
);
717 chat
->alias
= (char *)alias
;
719 if (!conv
|| purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv
))) {
720 serv_join_chat(purple_account_get_connection(account
),
721 purple_chat_get_components(chat
));
723 purple_conversation_present(conv
);
728 add_chat_cb(void *data
, PurpleRequestFields
*allfields
)
730 PurpleAccount
*account
;
731 const char *alias
, *name
, *group
;
734 GHashTable
*hash
= NULL
;
735 PurpleConnection
*gc
;
737 PurplePluginProtocolInfo
*info
;
739 account
= purple_request_fields_get_account(allfields
, "account");
740 name
= purple_request_fields_get_string(allfields
, "name");
741 alias
= purple_request_fields_get_string(allfields
, "alias");
742 group
= purple_request_fields_get_string(allfields
, "group");
743 autojoin
= purple_request_fields_get_bool(allfields
, "autojoin");
745 if (!purple_account_is_connected(account
) || !name
|| !*name
)
748 if (!group
|| !*group
)
751 gc
= purple_account_get_connection(account
);
752 info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
753 if (info
->chat_info_defaults
!= NULL
)
754 hash
= info
->chat_info_defaults(gc
, name
);
756 chat
= purple_chat_new(account
, name
, hash
);
759 if ((grp
= purple_find_group(group
)) == NULL
) {
760 grp
= purple_group_new(group
);
761 purple_blist_add_group(grp
, NULL
);
763 purple_blist_add_chat(chat
, grp
, NULL
);
764 purple_blist_alias_chat(chat
, alias
);
765 purple_blist_node_set_bool((PurpleBlistNode
*)chat
, "gnt-autojoin", autojoin
);
773 finch_request_add_chat(PurpleAccount
*account
, PurpleGroup
*grp
, const char *alias
, const char *name
)
775 PurpleRequestFields
*fields
= purple_request_fields_new();
776 PurpleRequestFieldGroup
*group
= purple_request_field_group_new(NULL
);
777 PurpleRequestField
*field
;
779 purple_request_fields_add_group(fields
, group
);
781 field
= purple_request_field_account_new("account", _("Account"), NULL
);
782 purple_request_field_account_set_show_all(field
, FALSE
);
784 purple_request_field_account_set_value(field
, account
);
785 purple_request_field_group_add_field(group
, field
);
787 field
= purple_request_field_string_new("name", _("Name"), name
, FALSE
);
788 purple_request_field_group_add_field(group
, field
);
790 field
= purple_request_field_string_new("alias", _("Alias"), alias
, FALSE
);
791 purple_request_field_group_add_field(group
, field
);
793 field
= purple_request_field_string_new("group", _("Group"), grp
? purple_group_get_name(grp
) : NULL
, FALSE
);
794 purple_request_field_group_add_field(group
, field
);
795 purple_request_field_set_type_hint(field
, "group");
797 field
= purple_request_field_bool_new("autojoin", _("Auto-join"), FALSE
);
798 purple_request_field_group_add_field(group
, field
);
800 purple_request_fields(NULL
, _("Add Chat"), NULL
,
801 _("You can edit more information from the context menu later."),
802 fields
, _("Add"), G_CALLBACK(add_chat_cb
), _("Cancel"), NULL
,
808 add_group_cb(gpointer null
, const char *group
)
812 if (!group
|| !*group
) {
813 purple_notify_error(NULL
, _("Error"), _("Error adding group"),
814 _("You must give a name for the group to add."));
818 grp
= purple_find_group(group
);
820 grp
= purple_group_new(group
);
821 purple_blist_add_group(grp
, NULL
);
827 /* Treat the group as a new group even if it had existed before. This should
828 * make things easier to add buddies to empty groups (new or old) without having
829 * to turn on 'show empty groups' setting */
830 ggblist
->new_group
= g_list_prepend(ggblist
->new_group
, grp
);
831 if (ggblist
->new_group_timeout
)
832 purple_timeout_remove(ggblist
->new_group_timeout
);
833 ggblist
->new_group_timeout
= purple_timeout_add_seconds(SHOW_EMPTY_GROUP_TIMEOUT
,
834 remove_new_empty_group
, NULL
);
836 /* Select the group */
838 FinchBlistNode
*fnode
= FINCH_GET_DATA((PurpleBlistNode
*)grp
);
840 add_node((PurpleBlistNode
*)grp
, ggblist
);
841 gnt_tree_set_selected(GNT_TREE(ggblist
->tree
), grp
);
846 finch_request_add_group(void)
848 purple_request_input(NULL
, _("Add Group"), NULL
, _("Enter the name of the group"),
849 NULL
, FALSE
, FALSE
, NULL
,
850 _("Add"), G_CALLBACK(add_group_cb
), _("Cancel"), NULL
,
855 static PurpleBlistUiOps blist_ui_ops
=
864 finch_request_add_buddy
,
865 finch_request_add_chat
,
866 finch_request_add_group
,
874 finch_blist_get_handle(void)
882 add_group(PurpleGroup
*group
, FinchBlist
*ggblist
)
885 PurpleBlistNode
*node
= (PurpleBlistNode
*)group
;
886 if (FINCH_GET_DATA(node
))
888 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)group
);
889 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), group
,
890 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), get_display_name(node
)),
892 gnt_tree_set_expanded(GNT_TREE(ggblist
->tree
), node
,
893 !purple_blist_node_get_bool(node
, "collapsed"));
897 get_display_name(PurpleBlistNode
*node
)
899 static char text
[2096];
900 char status
[8] = " ";
901 const char *name
= NULL
;
903 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
904 node
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
))); /* XXX: this can return NULL?! */
909 if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
911 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
912 PurpleStatusPrimitive prim
;
913 PurplePresence
*presence
;
915 gboolean ascii
= gnt_ascii_only();
917 presence
= purple_buddy_get_presence(buddy
);
918 if (purple_presence_is_status_primitive_active(presence
, PURPLE_STATUS_MOBILE
))
919 strncpy(status
, ascii
? ":" : "☎", sizeof(status
) - 1);
921 now
= purple_presence_get_active_status(presence
);
923 prim
= purple_status_type_get_primitive(purple_status_get_type(now
));
926 case PURPLE_STATUS_OFFLINE
:
927 strncpy(status
, ascii
? "x" : "⊗", sizeof(status
) - 1);
929 case PURPLE_STATUS_AVAILABLE
:
930 strncpy(status
, ascii
? "o" : "â—¯", sizeof(status
) - 1);
933 strncpy(status
, ascii
? "." : "⊖", sizeof(status
) - 1);
937 name
= purple_buddy_get_alias(buddy
);
939 else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
941 PurpleChat
*chat
= (PurpleChat
*)node
;
942 name
= purple_chat_get_name(chat
);
944 strncpy(status
, "~", sizeof(status
) - 1);
946 else if (PURPLE_BLIST_NODE_IS_GROUP(node
))
947 return purple_group_get_name((PurpleGroup
*)node
);
949 g_snprintf(text
, sizeof(text
) - 1, "%s %s", status
, name
);
955 add_chat(PurpleChat
*chat
, FinchBlist
*ggblist
)
958 PurpleBlistNode
*node
= (PurpleBlistNode
*)chat
;
959 if (FINCH_GET_DATA(node
))
961 if (!purple_account_is_connected(purple_chat_get_account(chat
)))
964 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)chat
);
966 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), chat
,
967 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), get_display_name(node
)),
972 add_contact(PurpleContact
*contact
, FinchBlist
*ggblist
)
975 PurpleBlistNode
*node
= (PurpleBlistNode
*)contact
;
978 if (FINCH_GET_DATA(node
))
981 name
= get_display_name(node
);
985 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)contact
);
987 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), contact
,
988 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), name
),
991 gnt_tree_set_expanded(GNT_TREE(ggblist
->tree
), contact
, FALSE
);
995 add_buddy(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
998 PurpleBlistNode
*node
= (PurpleBlistNode
*)buddy
;
999 PurpleContact
*contact
;
1001 if (FINCH_GET_DATA(node
))
1004 contact
= purple_buddy_get_contact(buddy
);
1005 parent
= ggblist
->manager
->find_parent((PurpleBlistNode
*)buddy
);
1007 create_finch_blist_node(node
, gnt_tree_add_row_after(GNT_TREE(ggblist
->tree
), buddy
,
1008 gnt_tree_create_row(GNT_TREE(ggblist
->tree
), get_display_name(node
)),
1011 blist_update_row_flags((PurpleBlistNode
*)buddy
);
1012 if (buddy
== purple_contact_get_priority_buddy(contact
))
1013 blist_update_row_flags((PurpleBlistNode
*)contact
);
1018 buddy_signed_on(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
1020 add_node((PurpleBlistNode
*)buddy
, ggblist
);
1024 buddy_signed_off(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
1026 node_remove(purple_get_blist(), (PurpleBlistNode
*)buddy
);
1030 PurpleBlistUiOps
*finch_blist_get_ui_ops()
1032 return &blist_ui_ops
;
1036 selection_activate(GntWidget
*widget
, FinchBlist
*ggblist
)
1038 GntTree
*tree
= GNT_TREE(ggblist
->tree
);
1039 PurpleBlistNode
*node
= gnt_tree_get_selection_data(tree
);
1044 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1045 node
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)));
1047 if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
1049 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
1050 PurpleConversation
*conv
;
1051 conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM
,
1052 purple_buddy_get_name(buddy
),
1053 purple_buddy_get_account(buddy
));
1055 conv
= purple_conversation_new(PURPLE_CONV_TYPE_IM
,
1056 purple_buddy_get_account(buddy
),
1057 purple_buddy_get_name(buddy
));
1059 FinchConv
*ggconv
= FINCH_GET_DATA(conv
);
1060 gnt_window_present(ggconv
->window
);
1062 finch_conversation_set_active(conv
);
1064 else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
1066 join_chat((PurpleChat
*)node
);
1071 context_menu_callback(GntMenuItem
*item
, gpointer data
)
1073 PurpleMenuAction
*action
= data
;
1074 PurpleBlistNode
*node
= ggblist
->cnode
;
1076 void (*callback
)(PurpleBlistNode
*, gpointer
);
1077 callback
= (void (*)(PurpleBlistNode
*, gpointer
))action
->callback
;
1079 callback(node
, action
->data
);
1086 gnt_append_menu_action(GntMenu
*menu
, PurpleMenuAction
*action
, gpointer parent
)
1094 item
= gnt_menuitem_new(action
->label
);
1095 if (action
->callback
)
1096 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), context_menu_callback
, action
);
1097 gnt_menu_add_item(menu
, GNT_MENU_ITEM(item
));
1099 if (action
->children
) {
1100 GntWidget
*sub
= gnt_menu_new(GNT_MENU_POPUP
);
1101 gnt_menuitem_set_submenu(item
, GNT_MENU(sub
));
1102 for (list
= action
->children
; list
; list
= list
->next
)
1103 gnt_append_menu_action(GNT_MENU(sub
), list
->data
, action
);
1108 append_proto_menu(GntMenu
*menu
, PurpleConnection
*gc
, PurpleBlistNode
*node
)
1111 PurplePluginProtocolInfo
*prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1113 if(!prpl_info
|| !prpl_info
->blist_node_menu
)
1116 for(list
= prpl_info
->blist_node_menu(node
); list
;
1117 list
= g_list_delete_link(list
, list
))
1119 PurpleMenuAction
*act
= (PurpleMenuAction
*) list
->data
;
1121 gnt_append_menu_action(menu
, act
, NULL
);
1126 add_custom_action(GntMenu
*menu
, const char *label
, PurpleCallback callback
,
1129 PurpleMenuAction
*action
= purple_menu_action_new(label
, callback
, data
, NULL
);
1130 gnt_append_menu_action(menu
, action
, NULL
);
1131 g_signal_connect_swapped(G_OBJECT(menu
), "destroy",
1132 G_CALLBACK(purple_menu_action_free
), action
);
1136 chat_components_edit_ok(PurpleChat
*chat
, PurpleRequestFields
*allfields
)
1138 GList
*groups
, *fields
;
1140 for (groups
= purple_request_fields_get_groups(allfields
); groups
; groups
= groups
->next
) {
1141 fields
= purple_request_field_group_get_fields(groups
->data
);
1142 for (; fields
; fields
= fields
->next
) {
1143 PurpleRequestField
*field
= fields
->data
;
1147 id
= purple_request_field_get_id(field
);
1148 if (purple_request_field_get_type(field
) == PURPLE_REQUEST_FIELD_INTEGER
)
1149 val
= g_strdup_printf("%d", purple_request_field_int_get_value(field
));
1151 val
= g_strdup(purple_request_field_string_get_value(field
));
1154 g_hash_table_remove(purple_chat_get_components(chat
), id
);
1156 g_hash_table_replace(purple_chat_get_components(chat
), g_strdup(id
), val
); /* val should not be free'd */
1163 chat_components_edit(PurpleBlistNode
*selected
, PurpleChat
*chat
)
1165 PurpleRequestFields
*fields
= purple_request_fields_new();
1166 PurpleRequestFieldGroup
*group
= purple_request_field_group_new(NULL
);
1167 PurpleRequestField
*field
;
1168 GList
*parts
, *iter
;
1169 struct proto_chat_entry
*pce
;
1170 PurpleConnection
*gc
;
1172 purple_request_fields_add_group(fields
, group
);
1174 gc
= purple_account_get_connection(purple_chat_get_account(chat
));
1175 parts
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
))->chat_info(gc
);
1177 for (iter
= parts
; iter
; iter
= iter
->next
) {
1181 const char *str
= g_hash_table_lookup(purple_chat_get_components(chat
), pce
->identifier
);
1182 if (!str
|| sscanf(str
, "%d", &val
) != 1)
1184 field
= purple_request_field_int_new(pce
->identifier
, pce
->label
, val
);
1186 field
= purple_request_field_string_new(pce
->identifier
, pce
->label
,
1187 g_hash_table_lookup(purple_chat_get_components(chat
), pce
->identifier
), FALSE
);
1189 purple_request_field_string_set_masked(field
, TRUE
);
1193 purple_request_field_set_required(field
, TRUE
);
1195 purple_request_field_group_add_field(group
, field
);
1201 purple_request_fields(NULL
, _("Edit Chat"), NULL
, _("Please Update the necessary fields."),
1202 fields
, _("Edit"), G_CALLBACK(chat_components_edit_ok
), _("Cancel"), NULL
,
1208 autojoin_toggled(GntMenuItem
*item
, gpointer data
)
1210 PurpleMenuAction
*action
= data
;
1211 purple_blist_node_set_bool(action
->data
, "gnt-autojoin",
1212 gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item
)));
1216 create_chat_menu(GntMenu
*menu
, PurpleChat
*chat
)
1218 PurpleMenuAction
*action
= purple_menu_action_new(_("Auto-join"), NULL
, chat
, NULL
);
1219 GntMenuItem
*check
= gnt_menuitem_check_new(action
->label
);
1220 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(check
),
1221 purple_blist_node_get_bool((PurpleBlistNode
*)chat
, "gnt-autojoin"));
1222 gnt_menu_add_item(menu
, check
);
1223 gnt_menuitem_set_callback(check
, autojoin_toggled
, action
);
1224 g_signal_connect_swapped(G_OBJECT(menu
), "destroy",
1225 G_CALLBACK(purple_menu_action_free
), action
);
1227 add_custom_action(menu
, _("Edit Settings"), (PurpleCallback
)chat_components_edit
, chat
);
1231 finch_add_buddy(PurpleBlistNode
*selected
, PurpleGroup
*grp
)
1233 purple_blist_request_add_buddy(NULL
, NULL
, grp
? purple_group_get_name(grp
) : NULL
, NULL
);
1237 finch_add_group(PurpleBlistNode
*selected
, PurpleGroup
*grp
)
1239 purple_blist_request_add_group();
1243 finch_add_chat(PurpleBlistNode
*selected
, PurpleGroup
*grp
)
1245 purple_blist_request_add_chat(NULL
, grp
, NULL
, NULL
);
1249 create_group_menu(GntMenu
*menu
, PurpleGroup
*group
)
1251 add_custom_action(menu
, _("Add Buddy"),
1252 PURPLE_CALLBACK(finch_add_buddy
), group
);
1253 add_custom_action(menu
, _("Add Chat"),
1254 PURPLE_CALLBACK(finch_add_chat
), group
);
1255 add_custom_action(menu
, _("Add Group"),
1256 PURPLE_CALLBACK(finch_add_group
), group
);
1259 gpointer
finch_retrieve_user_info(PurpleConnection
*conn
, const char *name
)
1261 PurpleNotifyUserInfo
*info
= purple_notify_user_info_new();
1263 purple_notify_user_info_add_pair(info
, _("Information"), _("Retrieving..."));
1264 uihandle
= purple_notify_userinfo(conn
, name
, info
, NULL
, NULL
);
1265 purple_notify_user_info_destroy(info
);
1267 serv_get_info(conn
, name
);
1272 finch_blist_get_buddy_info_cb(PurpleBlistNode
*selected
, PurpleBuddy
*buddy
)
1274 finch_retrieve_user_info(purple_account_get_connection(purple_buddy_get_account(buddy
)), purple_buddy_get_name(buddy
));
1278 finch_blist_menu_send_file_cb(PurpleBlistNode
*selected
, PurpleBuddy
*buddy
)
1280 serv_send_file(purple_account_get_connection(purple_buddy_get_account(buddy
)), purple_buddy_get_name(buddy
), NULL
);
1284 finch_blist_pounce_node_cb(PurpleBlistNode
*selected
, PurpleBlistNode
*node
)
1287 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1288 b
= purple_contact_get_priority_buddy((PurpleContact
*)node
);
1290 b
= (PurpleBuddy
*)node
;
1291 finch_pounce_editor_show(purple_buddy_get_account(b
), purple_buddy_get_name(b
), NULL
);
1295 toggle_block_buddy(GntMenuItem
*item
, gpointer buddy
)
1297 gboolean block
= gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item
));
1298 PurpleAccount
*account
= purple_buddy_get_account(buddy
);
1299 const char *name
= purple_buddy_get_name(buddy
);
1301 block
? purple_privacy_deny(account
, name
, FALSE
, FALSE
) :
1302 purple_privacy_allow(account
, name
, FALSE
, FALSE
);
1306 toggle_show_offline(GntMenuItem
*item
, gpointer buddy
)
1308 purple_blist_node_set_bool(buddy
, "show_offline",
1309 !purple_blist_node_get_bool(buddy
, "show_offline"));
1310 if (!ggblist
->manager
->can_add_node(buddy
))
1311 node_remove(purple_get_blist(), buddy
);
1313 node_update(purple_get_blist(), buddy
);
1317 create_buddy_menu(GntMenu
*menu
, PurpleBuddy
*buddy
)
1319 PurpleAccount
*account
;
1322 PurplePluginProtocolInfo
*prpl_info
;
1323 PurpleConnection
*gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
1325 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1326 if (prpl_info
&& prpl_info
->get_info
)
1328 add_custom_action(menu
, _("Get Info"),
1329 PURPLE_CALLBACK(finch_blist_get_buddy_info_cb
), buddy
);
1332 add_custom_action(menu
, _("Add Buddy Pounce"),
1333 PURPLE_CALLBACK(finch_blist_pounce_node_cb
), buddy
);
1335 if (prpl_info
&& prpl_info
->send_file
)
1337 if (!prpl_info
->can_receive_file
||
1338 prpl_info
->can_receive_file(gc
, purple_buddy_get_name(buddy
)))
1339 add_custom_action(menu
, _("Send File"),
1340 PURPLE_CALLBACK(finch_blist_menu_send_file_cb
), buddy
);
1343 account
= purple_buddy_get_account(buddy
);
1344 permitted
= purple_privacy_check(account
, purple_buddy_get_name(buddy
));
1346 item
= gnt_menuitem_check_new(_("Blocked"));
1347 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
), !permitted
);
1348 gnt_menuitem_set_callback(item
, toggle_block_buddy
, buddy
);
1349 gnt_menu_add_item(menu
, item
);
1351 item
= gnt_menuitem_check_new(_("Show when offline"));
1352 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
), purple_blist_node_get_bool((PurpleBlistNode
*)buddy
, "show_offline"));
1353 gnt_menuitem_set_callback(item
, toggle_show_offline
, buddy
);
1354 gnt_menu_add_item(menu
, item
);
1356 /* Protocol actions */
1357 append_proto_menu(menu
,
1358 purple_account_get_connection(purple_buddy_get_account(buddy
)),
1359 (PurpleBlistNode
*)buddy
);
1363 append_extended_menu(GntMenu
*menu
, PurpleBlistNode
*node
)
1367 for (iter
= purple_blist_node_get_extended_menu(node
);
1368 iter
; iter
= g_list_delete_link(iter
, iter
))
1370 gnt_append_menu_action(menu
, iter
->data
, NULL
);
1374 /* Xerox'd from gtkdialogs.c:purple_gtkdialogs_remove_contact_cb */
1376 remove_contact(PurpleContact
*contact
)
1378 PurpleBlistNode
*bnode
, *cnode
;
1381 cnode
= (PurpleBlistNode
*)contact
;
1382 group
= (PurpleGroup
*)purple_blist_node_get_parent(cnode
);
1383 for (bnode
= purple_blist_node_get_first_child(cnode
); bnode
; bnode
= purple_blist_node_get_sibling_next(bnode
)) {
1384 PurpleBuddy
*buddy
= (PurpleBuddy
*)bnode
;
1385 PurpleAccount
*account
= purple_buddy_get_account(buddy
);
1386 if (purple_account_is_connected(account
))
1387 purple_account_remove_buddy(account
, buddy
, group
);
1389 purple_blist_remove_contact(contact
);
1393 rename_blist_node(PurpleBlistNode
*node
, const char *newname
)
1395 const char *name
= newname
;
1399 if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1400 PurpleContact
*contact
= (PurpleContact
*)node
;
1401 PurpleBuddy
*buddy
= purple_contact_get_priority_buddy(contact
);
1402 purple_blist_alias_contact(contact
, name
);
1403 purple_blist_alias_buddy(buddy
, name
);
1404 serv_alias_buddy(buddy
);
1405 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1406 purple_blist_alias_buddy((PurpleBuddy
*)node
, name
);
1407 serv_alias_buddy((PurpleBuddy
*)node
);
1408 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
1409 purple_blist_alias_chat((PurpleChat
*)node
, name
);
1410 else if (PURPLE_BLIST_NODE_IS_GROUP(node
) && (name
!= NULL
))
1411 purple_blist_rename_group((PurpleGroup
*)node
, name
);
1413 g_return_if_reached();
1417 finch_blist_rename_node_cb(PurpleBlistNode
*selected
, PurpleBlistNode
*node
)
1419 const char *name
= NULL
;
1423 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1424 name
= purple_contact_get_alias((PurpleContact
*)node
);
1425 else if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
1426 name
= purple_buddy_get_contact_alias((PurpleBuddy
*)node
);
1427 else if (PURPLE_BLIST_NODE_IS_CHAT(node
))
1428 name
= purple_chat_get_name((PurpleChat
*)node
);
1429 else if (PURPLE_BLIST_NODE_IS_GROUP(node
))
1430 name
= purple_group_get_name((PurpleGroup
*)node
);
1432 g_return_if_reached();
1434 prompt
= g_strdup_printf(_("Please enter the new name for %s"), name
);
1436 text
= PURPLE_BLIST_NODE_IS_GROUP(node
) ? _("Rename") : _("Set Alias");
1437 purple_request_input(node
, text
, prompt
, _("Enter empty string to reset the name."),
1438 name
, FALSE
, FALSE
, NULL
, text
, G_CALLBACK(rename_blist_node
),
1447 static void showlog_cb(PurpleBlistNode
*sel
, PurpleBlistNode
*node
)
1450 PurpleAccount
*account
;
1453 if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1454 PurpleBuddy
*b
= (PurpleBuddy
*) node
;
1455 type
= PURPLE_LOG_IM
;
1456 name
= g_strdup(purple_buddy_get_name(b
));
1457 account
= purple_buddy_get_account(b
);
1458 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1459 PurpleChat
*c
= (PurpleChat
*) node
;
1460 PurplePluginProtocolInfo
*prpl_info
= NULL
;
1461 type
= PURPLE_LOG_CHAT
;
1462 account
= purple_chat_get_account(c
);
1463 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account
)));
1464 if (prpl_info
&& prpl_info
->get_chat_name
) {
1465 name
= prpl_info
->get_chat_name(purple_chat_get_components(c
));
1467 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1468 finch_log_show_contact((PurpleContact
*)node
);
1471 /* This callback should not have been registered for a node
1472 * that doesn't match the type of one of the blocks above. */
1473 g_return_if_reached();
1476 if (name
&& account
) {
1477 finch_log_show(type
, name
, account
);
1483 /* Xeroxed from gtkdialogs.c:purple_gtkdialogs_remove_group_cb*/
1485 remove_group(PurpleGroup
*group
)
1487 PurpleBlistNode
*cnode
, *bnode
;
1489 cnode
= purple_blist_node_get_first_child(((PurpleBlistNode
*)group
));
1492 if (PURPLE_BLIST_NODE_IS_CONTACT(cnode
)) {
1493 bnode
= purple_blist_node_get_first_child(cnode
);
1494 cnode
= purple_blist_node_get_sibling_next(cnode
);
1497 if (PURPLE_BLIST_NODE_IS_BUDDY(bnode
)) {
1498 PurpleAccount
*account
;
1499 buddy
= (PurpleBuddy
*)bnode
;
1500 bnode
= purple_blist_node_get_sibling_next(bnode
);
1501 account
= purple_buddy_get_account(buddy
);
1502 if (purple_account_is_connected(account
)) {
1503 purple_account_remove_buddy(account
, buddy
, group
);
1504 purple_blist_remove_buddy(buddy
);
1507 bnode
= purple_blist_node_get_sibling_next(bnode
);
1510 } else if (PURPLE_BLIST_NODE_IS_CHAT(cnode
)) {
1511 PurpleChat
*chat
= (PurpleChat
*)cnode
;
1512 cnode
= purple_blist_node_get_sibling_next(cnode
);
1513 if (purple_account_is_connected(purple_chat_get_account(chat
)))
1514 purple_blist_remove_chat(chat
);
1516 cnode
= purple_blist_node_get_sibling_next(cnode
);
1520 purple_blist_remove_group(group
);
1524 finch_blist_remove_node(PurpleBlistNode
*node
)
1526 if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1527 remove_contact((PurpleContact
*)node
);
1528 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1529 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
1530 PurpleGroup
*group
= purple_buddy_get_group(buddy
);
1531 purple_account_remove_buddy(purple_buddy_get_account(buddy
), buddy
, group
);
1532 purple_blist_remove_buddy(buddy
);
1533 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1534 purple_blist_remove_chat((PurpleChat
*)node
);
1535 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1536 remove_group((PurpleGroup
*)node
);
1541 finch_blist_remove_node_cb(PurpleBlistNode
*selected
, PurpleBlistNode
*node
)
1543 PurpleAccount
*account
= NULL
;
1545 const char *name
, *sec
= NULL
;
1547 if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1548 PurpleContact
*c
= (PurpleContact
*)node
;
1549 name
= purple_contact_get_alias(c
);
1550 if (c
->totalsize
> 1)
1551 sec
= _("Removing this contact will also remove all the buddies in the contact");
1552 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1553 name
= purple_buddy_get_name((PurpleBuddy
*)node
);
1554 account
= purple_buddy_get_account((PurpleBuddy
*)node
);
1555 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1556 name
= purple_chat_get_name((PurpleChat
*)node
);
1557 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1558 name
= purple_group_get_name((PurpleGroup
*)node
);
1559 sec
= _("Removing this group will also remove all the buddies in the group");
1564 primary
= g_strdup_printf(_("Are you sure you want to remove %s?"), name
);
1566 /* XXX: anything to do with the returned ui-handle? */
1567 purple_request_action(node
, _("Confirm Remove"),
1570 account
, name
, NULL
,
1572 _("Remove"), finch_blist_remove_node
,
1578 finch_blist_toggle_tag_buddy(PurpleBlistNode
*node
)
1583 if (ggblist
->tagged
&& (iter
= g_list_find(ggblist
->tagged
, node
)) != NULL
) {
1584 ggblist
->tagged
= g_list_delete_link(ggblist
->tagged
, iter
);
1586 ggblist
->tagged
= g_list_prepend(ggblist
->tagged
, node
);
1588 if (PURPLE_BLIST_NODE_IS_CONTACT(node
))
1589 update_buddy_display(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)), ggblist
);
1590 else if (PURPLE_BLIST_NODE_IS_BUDDY(node
))
1591 update_buddy_display((PurpleBuddy
*)node
, ggblist
);
1593 update_node_display(node
, ggblist
);
1597 finch_blist_place_tagged(PurpleBlistNode
*target
)
1599 PurpleGroup
*tg
= NULL
;
1600 PurpleContact
*tc
= NULL
;
1602 if (target
== NULL
||
1603 purple_blist_node_get_type(target
) == PURPLE_BLIST_OTHER_NODE
)
1606 if (PURPLE_BLIST_NODE_IS_GROUP(target
))
1607 tg
= (PurpleGroup
*)target
;
1608 else if (PURPLE_BLIST_NODE_IS_BUDDY(target
)) {
1609 tc
= (PurpleContact
*)purple_blist_node_get_parent(target
);
1610 tg
= (PurpleGroup
*)purple_blist_node_get_parent((PurpleBlistNode
*)tc
);
1612 if (PURPLE_BLIST_NODE_IS_CONTACT(target
))
1613 tc
= (PurpleContact
*)target
;
1614 tg
= (PurpleGroup
*)purple_blist_node_get_parent(target
);
1617 if (ggblist
->tagged
) {
1618 GList
*list
= ggblist
->tagged
;
1619 ggblist
->tagged
= NULL
;
1621 PurpleBlistNode
*node
= list
->data
;
1622 list
= g_list_delete_link(list
, list
);
1624 if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1625 update_node_display(node
, ggblist
);
1626 /* Add the group after the current group */
1627 purple_blist_add_group((PurpleGroup
*)node
, (PurpleBlistNode
*)tg
);
1628 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1629 update_buddy_display(purple_contact_get_priority_buddy((PurpleContact
*)node
), ggblist
);
1630 if (PURPLE_BLIST_NODE(tg
) == target
) {
1631 /* The target is a group, just add the contact to the group. */
1632 purple_blist_add_contact((PurpleContact
*)node
, tg
, NULL
);
1634 /* The target is either a buddy, or a contact. Merge with that contact. */
1635 purple_blist_merge_contact((PurpleContact
*)node
, (PurpleBlistNode
*)tc
);
1637 /* The target is a chat. Add the contact to the group after this chat. */
1638 purple_blist_add_contact((PurpleContact
*)node
, NULL
, target
);
1640 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1641 update_buddy_display((PurpleBuddy
*)node
, ggblist
);
1642 if (PURPLE_BLIST_NODE(tg
) == target
) {
1643 /* The target is a group. Add this buddy in a new contact under this group. */
1644 purple_blist_add_buddy((PurpleBuddy
*)node
, NULL
, tg
, NULL
);
1645 } else if (PURPLE_BLIST_NODE_IS_CONTACT(target
)) {
1646 /* Add to the contact. */
1647 purple_blist_add_buddy((PurpleBuddy
*)node
, tc
, NULL
, NULL
);
1648 } else if (PURPLE_BLIST_NODE_IS_BUDDY(target
)) {
1649 /* Add to the contact after the selected buddy. */
1650 purple_blist_add_buddy((PurpleBuddy
*)node
, NULL
, NULL
, target
);
1651 } else if (PURPLE_BLIST_NODE_IS_CHAT(target
)) {
1652 /* Add to the selected chat's group. */
1653 purple_blist_add_buddy((PurpleBuddy
*)node
, NULL
, tg
, NULL
);
1655 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1656 update_node_display(node
, ggblist
);
1657 if (PURPLE_BLIST_NODE(tg
) == target
)
1658 purple_blist_add_chat((PurpleChat
*)node
, tg
, NULL
);
1660 purple_blist_add_chat((PurpleChat
*)node
, NULL
, target
);
1667 context_menu_destroyed(GntWidget
*widget
, FinchBlist
*ggblist
)
1669 ggblist
->context
= NULL
;
1673 draw_context_menu(FinchBlist
*ggblist
)
1675 PurpleBlistNode
*node
= NULL
;
1676 GntWidget
*context
= NULL
;
1677 GntTree
*tree
= NULL
;
1678 int x
, y
, top
, width
;
1681 if (ggblist
->context
)
1684 tree
= GNT_TREE(ggblist
->tree
);
1686 node
= gnt_tree_get_selection_data(tree
);
1687 if (node
&& purple_blist_node_get_type(node
) == PURPLE_BLIST_OTHER_NODE
)
1690 if (ggblist
->tooltip
)
1691 remove_tooltip(ggblist
);
1693 ggblist
->cnode
= node
;
1695 ggblist
->context
= context
= gnt_menu_new(GNT_MENU_POPUP
);
1696 g_signal_connect(G_OBJECT(context
), "destroy", G_CALLBACK(context_menu_destroyed
), ggblist
);
1697 g_signal_connect(G_OBJECT(context
), "hide", G_CALLBACK(gnt_widget_destroy
), NULL
);
1700 create_group_menu(GNT_MENU(context
), NULL
);
1701 title
= g_strdup(_("Buddy List"));
1702 } else if (PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1703 ggblist
->cnode
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node
)));
1704 create_buddy_menu(GNT_MENU(context
), (PurpleBuddy
*)ggblist
->cnode
);
1705 title
= g_strdup(purple_contact_get_alias((PurpleContact
*)node
));
1706 } else if (PURPLE_BLIST_NODE_IS_BUDDY(node
)) {
1707 PurpleBuddy
*buddy
= (PurpleBuddy
*)node
;
1708 create_buddy_menu(GNT_MENU(context
), buddy
);
1709 title
= g_strdup(purple_buddy_get_name(buddy
));
1710 } else if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
1711 PurpleChat
*chat
= (PurpleChat
*)node
;
1712 create_chat_menu(GNT_MENU(context
), chat
);
1713 title
= g_strdup(purple_chat_get_name(chat
));
1714 } else if (PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1715 PurpleGroup
*group
= (PurpleGroup
*)node
;
1716 create_group_menu(GNT_MENU(context
), group
);
1717 title
= g_strdup(purple_group_get_name(group
));
1720 append_extended_menu(GNT_MENU(context
), node
);
1722 /* These are common for everything */
1724 add_custom_action(GNT_MENU(context
),
1725 PURPLE_BLIST_NODE_IS_GROUP(node
) ? _("Rename") : _("Alias"),
1726 PURPLE_CALLBACK(finch_blist_rename_node_cb
), node
);
1727 add_custom_action(GNT_MENU(context
), _("Remove"),
1728 PURPLE_CALLBACK(finch_blist_remove_node_cb
), node
);
1730 if (ggblist
->tagged
&& (PURPLE_BLIST_NODE_IS_CONTACT(node
)
1731 || PURPLE_BLIST_NODE_IS_GROUP(node
))) {
1732 add_custom_action(GNT_MENU(context
), _("Place tagged"),
1733 PURPLE_CALLBACK(finch_blist_place_tagged
), node
);
1736 if (PURPLE_BLIST_NODE_IS_BUDDY(node
) || PURPLE_BLIST_NODE_IS_CONTACT(node
)) {
1737 add_custom_action(GNT_MENU(context
), _("Toggle Tag"),
1738 PURPLE_CALLBACK(finch_blist_toggle_tag_buddy
), node
);
1740 if (!PURPLE_BLIST_NODE_IS_GROUP(node
)) {
1741 add_custom_action(GNT_MENU(context
), _("View Log"),
1742 PURPLE_CALLBACK(showlog_cb
), node
);
1746 /* Set the position for the popup */
1747 gnt_widget_get_position(GNT_WIDGET(tree
), &x
, &y
);
1748 gnt_widget_get_size(GNT_WIDGET(tree
), &width
, NULL
);
1749 top
= gnt_tree_get_selection_visible_line(tree
);
1754 gnt_widget_set_position(context
, x
, y
);
1755 gnt_screen_menu_show(GNT_MENU(context
));
1760 tooltip_for_buddy(PurpleBuddy
*buddy
, GString
*str
, gboolean full
)
1763 PurplePluginProtocolInfo
*prpl_info
;
1764 PurpleAccount
*account
;
1765 PurpleNotifyUserInfo
*user_info
;
1766 PurplePresence
*presence
;
1767 const char *alias
= purple_buddy_get_alias(buddy
);
1770 user_info
= purple_notify_user_info_new();
1772 account
= purple_buddy_get_account(buddy
);
1773 presence
= purple_buddy_get_presence(buddy
);
1775 if (!full
|| g_utf8_collate(purple_buddy_get_name(buddy
), alias
)) {
1776 char *esc
= g_markup_escape_text(alias
, -1);
1777 purple_notify_user_info_add_pair(user_info
, _("Nickname"), esc
);
1781 tmp
= g_strdup_printf("%s (%s)",
1782 purple_account_get_username(account
),
1783 purple_account_get_protocol_name(account
));
1784 purple_notify_user_info_add_pair(user_info
, _("Account"), tmp
);
1787 prpl
= purple_find_prpl(purple_account_get_protocol_id(account
));
1788 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(prpl
);
1789 if (prpl_info
&& prpl_info
->tooltip_text
) {
1790 prpl_info
->tooltip_text(buddy
, user_info
, full
);
1793 if (purple_prefs_get_bool("/finch/blist/idletime")) {
1794 PurplePresence
*pre
= purple_buddy_get_presence(buddy
);
1795 if (purple_presence_is_idle(pre
)) {
1796 time_t idle
= purple_presence_get_idle_time(pre
);
1798 char *st
= purple_str_seconds_to_string(time(NULL
) - idle
);
1799 purple_notify_user_info_add_pair(user_info
, _("Idle"), st
);
1805 tmp
= purple_notify_user_info_get_text_with_newline(user_info
, "<BR>");
1806 purple_notify_user_info_destroy(user_info
);
1808 strip
= purple_markup_strip_html(tmp
);
1809 g_string_append(str
, strip
);
1811 if (purple_presence_is_status_primitive_active(presence
, PURPLE_STATUS_MOBILE
)) {
1812 g_string_append(str
, "\n");
1813 g_string_append(str
, _("On Mobile"));
1821 make_sure_text_fits(GString
*string
)
1823 int maxw
= getmaxx(stdscr
) - 3;
1824 char *str
= gnt_util_onscreen_fit_string(string
->str
, maxw
);
1825 string
= g_string_assign(string
, str
);
1831 draw_tooltip_real(FinchBlist
*ggblist
)
1833 PurpleBlistNode
*node
;
1834 int x
, y
, top
, width
, w
, h
;
1835 GString
*str
= NULL
;
1837 GntWidget
*widget
, *box
, *tv
;
1840 widget
= ggblist
->tree
;
1841 tree
= GNT_TREE(widget
);
1843 if (!gnt_widget_has_focus(ggblist
->tree
) ||
1844 (ggblist
->context
&& !GNT_WIDGET_IS_FLAG_SET(ggblist
->context
, GNT_WIDGET_INVISIBLE
)))
1847 if (ggblist
->tooltip
)
1849 /* XXX: Once we can properly redraw on expose events, this can be removed at the end
1850 * to avoid the blinking*/
1851 remove_tooltip(ggblist
);
1854 node
= gnt_tree_get_selection_data(tree
);
1858 if (!ggblist
->manager
->create_tooltip(node
, &str
, &title
))
1861 gnt_widget_get_position(widget
, &x
, &y
);
1862 gnt_widget_get_size(widget
, &width
, NULL
);
1863 top
= gnt_tree_get_selection_visible_line(tree
);
1868 box
= gnt_box_new(FALSE
, FALSE
);
1869 gnt_box_set_toplevel(GNT_BOX(box
), TRUE
);
1870 GNT_WIDGET_SET_FLAGS(box
, GNT_WIDGET_NO_SHADOW
);
1871 gnt_box_set_title(GNT_BOX(box
), title
);
1873 str
= make_sure_text_fits(str
);
1874 gnt_util_get_text_bound(str
->str
, &w
, &h
);
1876 tv
= gnt_text_view_new();
1877 gnt_widget_set_size(tv
, w
+ 1, h
);
1878 gnt_text_view_set_flag(GNT_TEXT_VIEW(tv
), GNT_TEXT_VIEW_NO_SCROLL
);
1879 gnt_box_add_widget(GNT_BOX(box
), tv
);
1881 if (x
+ w
>= getmaxx(stdscr
))
1883 gnt_widget_set_position(box
, x
, y
);
1884 GNT_WIDGET_UNSET_FLAGS(box
, GNT_WIDGET_CAN_TAKE_FOCUS
);
1885 GNT_WIDGET_SET_FLAGS(box
, GNT_WIDGET_TRANSIENT
);
1886 gnt_widget_draw(box
);
1888 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv
), str
->str
, GNT_TEXT_FLAG_NORMAL
);
1889 gnt_text_view_scroll(GNT_TEXT_VIEW(tv
), 0);
1892 g_string_free(str
, TRUE
);
1893 ggblist
->tooltip
= box
;
1894 ggblist
->tnode
= node
;
1896 gnt_widget_set_name(ggblist
->tooltip
, "tooltip");
1901 draw_tooltip(FinchBlist
*ggblist
)
1903 /* When an account has signed off, it removes one buddy at a time.
1904 * Drawing the tooltip after removing each buddy is expensive. On
1905 * top of that, if the selected buddy belongs to the disconnected
1906 * account, then retreiving the tooltip for that causes crash. So
1907 * let's make sure we wait for all the buddies to be removed first.*/
1908 int id
= g_timeout_add(0, (GSourceFunc
)draw_tooltip_real
, ggblist
);
1909 g_object_set_data_full(G_OBJECT(ggblist
->window
), "draw_tooltip_calback",
1910 GINT_TO_POINTER(id
), (GDestroyNotify
)g_source_remove
);
1914 selection_changed(GntWidget
*widget
, gpointer old
, gpointer current
, FinchBlist
*ggblist
)
1916 remove_peripherals(ggblist
);
1917 draw_tooltip(ggblist
);
1921 context_menu(GntWidget
*widget
, FinchBlist
*ggblist
)
1923 draw_context_menu(ggblist
);
1928 key_pressed(GntWidget
*widget
, const char *text
, FinchBlist
*ggblist
)
1930 if (text
[0] == 27 && text
[1] == 0) {
1931 /* Escape was pressed */
1932 if (gnt_tree_is_searching(GNT_TREE(ggblist
->tree
)))
1933 gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist
->tree
), "end-search", NULL
);
1934 remove_peripherals(ggblist
);
1935 } else if (strcmp(text
, GNT_KEY_INS
) == 0) {
1936 PurpleBlistNode
*node
= gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
));
1937 purple_blist_request_add_buddy(NULL
, NULL
,
1938 node
&& PURPLE_BLIST_NODE_IS_GROUP(node
) ? purple_group_get_name(PURPLE_GROUP(node
)) : NULL
,
1940 } else if (!gnt_tree_is_searching(GNT_TREE(ggblist
->tree
))) {
1941 if (strcmp(text
, "t") == 0) {
1942 finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
)));
1943 gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist
->tree
), "move-down", NULL
);
1944 } else if (strcmp(text
, "a") == 0) {
1945 finch_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
)));
1955 update_node_display(PurpleBlistNode
*node
, FinchBlist
*ggblist
)
1957 GntTextFormatFlags flag
= get_blist_node_flag(node
);
1958 gnt_tree_set_row_flags(GNT_TREE(ggblist
->tree
), node
, flag
);
1962 update_buddy_display(PurpleBuddy
*buddy
, FinchBlist
*ggblist
)
1964 PurpleContact
*contact
;
1966 contact
= purple_buddy_get_contact(buddy
);
1968 gnt_tree_change_text(GNT_TREE(ggblist
->tree
), buddy
, 0, get_display_name((PurpleBlistNode
*)buddy
));
1969 gnt_tree_change_text(GNT_TREE(ggblist
->tree
), contact
, 0, get_display_name((PurpleBlistNode
*)contact
));
1971 blist_update_row_flags((PurpleBlistNode
*)buddy
);
1972 if (buddy
== purple_contact_get_priority_buddy(contact
))
1973 blist_update_row_flags((PurpleBlistNode
*)contact
);
1975 if (ggblist
->tnode
== (PurpleBlistNode
*)buddy
)
1976 draw_tooltip(ggblist
);
1980 buddy_status_changed(PurpleBuddy
*buddy
, PurpleStatus
*old
, PurpleStatus
*now
, FinchBlist
*ggblist
)
1982 update_buddy_display(buddy
, ggblist
);
1986 buddy_idle_changed(PurpleBuddy
*buddy
, int old
, int new, FinchBlist
*ggblist
)
1988 update_buddy_display(buddy
, ggblist
);
1992 remove_peripherals(FinchBlist
*ggblist
)
1994 if (ggblist
->tooltip
)
1995 remove_tooltip(ggblist
);
1996 else if (ggblist
->context
)
1997 gnt_widget_destroy(ggblist
->context
);
2001 size_changed_cb(GntWidget
*w
, int wi
, int h
)
2004 gnt_widget_get_size(w
, &width
, &height
);
2005 purple_prefs_set_int(PREF_ROOT
"/size/width", width
);
2006 purple_prefs_set_int(PREF_ROOT
"/size/height", height
);
2010 save_position_cb(GntWidget
*w
, int x
, int y
)
2012 purple_prefs_set_int(PREF_ROOT
"/position/x", x
);
2013 purple_prefs_set_int(PREF_ROOT
"/position/y", y
);
2017 reset_blist_window(GntWidget
*window
, gpointer null
)
2019 PurpleBlistNode
*node
;
2020 purple_signals_disconnect_by_handle(finch_blist_get_handle());
2021 FINCH_SET_DATA(purple_get_blist(), NULL
);
2023 node
= purple_blist_get_root();
2025 reset_blist_node_ui_data(node
);
2026 node
= purple_blist_node_next(node
, TRUE
);
2029 if (ggblist
->typing
)
2030 purple_timeout_remove(ggblist
->typing
);
2031 remove_peripherals(ggblist
);
2032 if (ggblist
->tagged
)
2033 g_list_free(ggblist
->tagged
);
2035 if (ggblist
->new_group_timeout
)
2036 purple_timeout_remove(ggblist
->new_group_timeout
);
2037 if (ggblist
->new_group
)
2038 g_list_free(ggblist
->new_group
);
2045 populate_buddylist(void)
2047 PurpleBlistNode
*node
;
2048 PurpleBuddyList
*list
;
2050 if (ggblist
->manager
->init
)
2051 ggblist
->manager
->init();
2053 if (strcmp(purple_prefs_get_string(PREF_ROOT
"/sort_type"), "text") == 0) {
2054 gnt_tree_set_compare_func(GNT_TREE(ggblist
->tree
),
2055 (GCompareFunc
)blist_node_compare_text
);
2056 } else if (strcmp(purple_prefs_get_string(PREF_ROOT
"/sort_type"), "status") == 0) {
2057 gnt_tree_set_compare_func(GNT_TREE(ggblist
->tree
),
2058 (GCompareFunc
)blist_node_compare_status
);
2059 } else if (strcmp(purple_prefs_get_string(PREF_ROOT
"/sort_type"), "log") == 0) {
2060 gnt_tree_set_compare_func(GNT_TREE(ggblist
->tree
),
2061 (GCompareFunc
)blist_node_compare_log
);
2064 list
= purple_get_blist();
2065 node
= purple_blist_get_root();
2068 node_update(list
, node
);
2069 node
= purple_blist_node_next(node
, FALSE
);
2074 destroy_status_list(GList
*list
)
2076 g_list_foreach(list
, (GFunc
)g_free
, NULL
);
2081 populate_status_dropdown(void)
2085 GList
*items
= NULL
;
2086 StatusBoxItem
*item
= NULL
;
2088 /* First the primitives */
2089 PurpleStatusPrimitive prims
[] = {PURPLE_STATUS_AVAILABLE
, PURPLE_STATUS_AWAY
,
2090 PURPLE_STATUS_INVISIBLE
, PURPLE_STATUS_OFFLINE
, PURPLE_STATUS_UNSET
};
2092 gnt_combo_box_remove_all(GNT_COMBO_BOX(ggblist
->status
));
2094 for (i
= 0; prims
[i
] != PURPLE_STATUS_UNSET
; i
++)
2096 item
= g_new0(StatusBoxItem
, 1);
2097 item
->type
= STATUS_PRIMITIVE
;
2098 item
->u
.prim
= prims
[i
];
2099 items
= g_list_prepend(items
, item
);
2100 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2101 purple_primitive_get_name_from_type(prims
[i
]));
2104 /* Now the popular statuses */
2105 for (iter
= purple_savedstatuses_get_popular(6); iter
; iter
= g_list_delete_link(iter
, iter
))
2107 item
= g_new0(StatusBoxItem
, 1);
2108 item
->type
= STATUS_SAVED_POPULAR
;
2109 item
->u
.saved
= iter
->data
;
2110 items
= g_list_prepend(items
, item
);
2111 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2112 purple_savedstatus_get_title(iter
->data
));
2115 /* New savedstatus */
2116 item
= g_new0(StatusBoxItem
, 1);
2117 item
->type
= STATUS_SAVED_NEW
;
2118 items
= g_list_prepend(items
, item
);
2119 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2122 /* More savedstatuses */
2123 item
= g_new0(StatusBoxItem
, 1);
2124 item
->type
= STATUS_SAVED_ALL
;
2125 items
= g_list_prepend(items
, item
);
2126 gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist
->status
), item
,
2129 /* The keys for the combobox are created here, and never used
2130 * anywhere else. So make sure the keys are freed when the widget
2132 g_object_set_data_full(G_OBJECT(ggblist
->status
), "list of statuses",
2133 items
, (GDestroyNotify
)destroy_status_list
);
2137 redraw_blist(const char *name
, PurplePrefType type
, gconstpointer val
, gpointer data
)
2139 PurpleBlistNode
*node
, *sel
;
2140 FinchBlistManager
*manager
;
2142 if (ggblist
== NULL
)
2145 manager
= finch_blist_manager_find(purple_prefs_get_string(PREF_ROOT
"/grouping"));
2146 if (manager
== NULL
)
2147 manager
= &default_manager
;
2148 if (ggblist
->manager
!= manager
) {
2149 if (ggblist
->manager
->uninit
)
2150 ggblist
->manager
->uninit();
2152 ggblist
->manager
= manager
;
2153 if (manager
->can_add_node
== NULL
)
2154 manager
->can_add_node
= default_can_add_node
;
2155 if (manager
->find_parent
== NULL
)
2156 manager
->find_parent
= default_find_parent
;
2157 if (manager
->create_tooltip
== NULL
)
2158 manager
->create_tooltip
= default_create_tooltip
;
2161 if (ggblist
->window
== NULL
)
2164 sel
= gnt_tree_get_selection_data(GNT_TREE(ggblist
->tree
));
2165 gnt_tree_remove_all(GNT_TREE(ggblist
->tree
));
2167 node
= purple_blist_get_root();
2168 for (; node
; node
= purple_blist_node_next(node
, TRUE
))
2169 reset_blist_node_ui_data(node
);
2170 populate_buddylist();
2171 gnt_tree_set_selected(GNT_TREE(ggblist
->tree
), sel
);
2172 draw_tooltip(ggblist
);
2175 void finch_blist_init()
2177 color_available
= gnt_style_get_color(NULL
, "color-available");
2178 if (!color_available
)
2179 color_available
= gnt_color_add_pair(COLOR_GREEN
, -1);
2180 color_away
= gnt_style_get_color(NULL
, "color-away");
2182 color_away
= gnt_color_add_pair(COLOR_BLUE
, -1);
2183 color_idle
= gnt_style_get_color(NULL
, "color-idle");
2185 color_idle
= gnt_color_add_pair(COLOR_CYAN
, -1);
2186 color_offline
= gnt_style_get_color(NULL
, "color-offline");
2188 color_offline
= gnt_color_add_pair(COLOR_RED
, -1);
2190 purple_prefs_add_none(PREF_ROOT
);
2191 purple_prefs_add_none(PREF_ROOT
"/size");
2192 purple_prefs_add_int(PREF_ROOT
"/size/width", 20);
2193 purple_prefs_add_int(PREF_ROOT
"/size/height", 17);
2194 purple_prefs_add_none(PREF_ROOT
"/position");
2195 purple_prefs_add_int(PREF_ROOT
"/position/x", 0);
2196 purple_prefs_add_int(PREF_ROOT
"/position/y", 0);
2197 purple_prefs_add_bool(PREF_ROOT
"/idletime", TRUE
);
2198 purple_prefs_add_bool(PREF_ROOT
"/showoffline", FALSE
);
2199 purple_prefs_add_bool(PREF_ROOT
"/emptygroups", FALSE
);
2200 purple_prefs_add_string(PREF_ROOT
"/sort_type", "text");
2201 purple_prefs_add_string(PREF_ROOT
"/grouping", "default");
2203 purple_prefs_connect_callback(finch_blist_get_handle(),
2204 PREF_ROOT
"/emptygroups", redraw_blist
, NULL
);
2205 purple_prefs_connect_callback(finch_blist_get_handle(),
2206 PREF_ROOT
"/showoffline", redraw_blist
, NULL
);
2207 purple_prefs_connect_callback(finch_blist_get_handle(),
2208 PREF_ROOT
"/sort_type", redraw_blist
, NULL
);
2209 purple_prefs_connect_callback(finch_blist_get_handle(),
2210 PREF_ROOT
"/grouping", redraw_blist
, NULL
);
2212 purple_signal_connect(purple_connections_get_handle(), "signed-on", purple_blist_get_handle(),
2213 G_CALLBACK(account_signed_on_cb
), NULL
);
2215 finch_blist_install_manager(&default_manager
);
2221 remove_typing_cb(gpointer null
)
2223 PurpleSavedStatus
*current
;
2224 const char *message
, *newmessage
;
2225 char *escnewmessage
;
2226 PurpleStatusPrimitive prim
, newprim
;
2227 StatusBoxItem
*item
;
2229 current
= purple_savedstatus_get_current();
2230 message
= purple_savedstatus_get_message(current
);
2231 prim
= purple_savedstatus_get_type(current
);
2233 newmessage
= gnt_entry_get_text(GNT_ENTRY(ggblist
->statustext
));
2234 item
= gnt_combo_box_get_selected_data(GNT_COMBO_BOX(ggblist
->status
));
2235 escnewmessage
= newmessage
? g_markup_escape_text(newmessage
, -1) : NULL
;
2237 switch (item
->type
) {
2238 case STATUS_PRIMITIVE
:
2239 newprim
= item
->u
.prim
;
2241 case STATUS_SAVED_POPULAR
:
2242 newprim
= purple_savedstatus_get_type(item
->u
.saved
);
2245 goto end
; /* 'New' or 'Saved' is selected, but this should never happen. */
2248 if (newprim
!= prim
|| ((message
&& !escnewmessage
) ||
2249 (!message
&& escnewmessage
) ||
2250 (message
&& escnewmessage
&& g_utf8_collate(message
, escnewmessage
) != 0)))
2252 PurpleSavedStatus
*status
= purple_savedstatus_find_transient_by_type_and_message(newprim
, escnewmessage
);
2253 /* Holy Crap! That's a LAWNG function name */
2256 status
= purple_savedstatus_new(NULL
, newprim
);
2257 purple_savedstatus_set_message(status
, escnewmessage
);
2260 purple_savedstatus_activate(status
);
2263 gnt_box_give_focus_to_child(GNT_BOX(ggblist
->window
), ggblist
->tree
);
2265 g_free(escnewmessage
);
2266 if (ggblist
->typing
)
2267 purple_timeout_remove(ggblist
->typing
);
2268 ggblist
->typing
= 0;
2273 status_selection_changed(GntComboBox
*box
, StatusBoxItem
*old
, StatusBoxItem
*now
, gpointer null
)
2275 gnt_entry_set_text(GNT_ENTRY(ggblist
->statustext
), NULL
);
2276 if (now
->type
== STATUS_SAVED_POPULAR
)
2278 /* Set the status immediately */
2279 purple_savedstatus_activate(now
->u
.saved
);
2281 else if (now
->type
== STATUS_PRIMITIVE
)
2283 /* Move the focus to the entry box */
2284 /* XXX: Make sure the selected status can have a message */
2285 gnt_box_move_focus(GNT_BOX(ggblist
->window
), 1);
2286 ggblist
->typing
= purple_timeout_add_seconds(TYPING_TIMEOUT_S
, (GSourceFunc
)remove_typing_cb
, NULL
);
2288 else if (now
->type
== STATUS_SAVED_ALL
)
2290 /* Restore the selection to reflect current status. */
2291 savedstatus_changed(purple_savedstatus_get_current(), NULL
);
2292 gnt_box_give_focus_to_child(GNT_BOX(ggblist
->window
), ggblist
->tree
);
2293 finch_savedstatus_show_all();
2295 else if (now
->type
== STATUS_SAVED_NEW
)
2297 savedstatus_changed(purple_savedstatus_get_current(), NULL
);
2298 gnt_box_give_focus_to_child(GNT_BOX(ggblist
->window
), ggblist
->tree
);
2299 finch_savedstatus_edit(NULL
);
2302 g_return_if_reached();
2306 status_text_changed(GntEntry
*entry
, const char *text
, gpointer null
)
2308 if ((text
[0] == 27 || (text
[0] == '\t' && text
[1] == '\0')) && ggblist
->typing
== 0)
2311 if (ggblist
->typing
)
2312 purple_timeout_remove(ggblist
->typing
);
2313 ggblist
->typing
= 0;
2315 if (text
[0] == '\r' && text
[1] == 0)
2317 /* Set the status only after you press 'Enter' */
2318 remove_typing_cb(NULL
);
2322 ggblist
->typing
= purple_timeout_add_seconds(TYPING_TIMEOUT_S
, (GSourceFunc
)remove_typing_cb
, NULL
);
2327 savedstatus_changed(PurpleSavedStatus
*now
, PurpleSavedStatus
*old
)
2330 PurpleStatusPrimitive prim
;
2331 const char *message
;
2332 gboolean found
= FALSE
, saved
= TRUE
;
2337 /* Block the signals we don't want to emit */
2338 g_signal_handlers_block_matched(ggblist
->status
, G_SIGNAL_MATCH_FUNC
,
2339 0, 0, NULL
, status_selection_changed
, NULL
);
2340 g_signal_handlers_block_matched(ggblist
->statustext
, G_SIGNAL_MATCH_FUNC
,
2341 0, 0, NULL
, status_text_changed
, NULL
);
2343 prim
= purple_savedstatus_get_type(now
);
2344 message
= purple_savedstatus_get_message(now
);
2346 /* Rebuild the status dropdown */
2347 populate_status_dropdown();
2350 list
= g_object_get_data(G_OBJECT(ggblist
->status
), "list of statuses");
2351 for (; list
; list
= list
->next
)
2353 StatusBoxItem
*item
= list
->data
;
2354 if ((saved
&& item
->type
!= STATUS_PRIMITIVE
&& item
->u
.saved
== now
) ||
2355 (!saved
&& item
->type
== STATUS_PRIMITIVE
&& item
->u
.prim
== prim
))
2357 char *mess
= purple_unescape_html(message
);
2358 gnt_combo_box_set_selected(GNT_COMBO_BOX(ggblist
->status
), item
);
2359 gnt_entry_set_text(GNT_ENTRY(ggblist
->statustext
), mess
);
2360 gnt_widget_draw(ggblist
->status
);
2371 g_signal_handlers_unblock_matched(ggblist
->status
, G_SIGNAL_MATCH_FUNC
,
2372 0, 0, NULL
, status_selection_changed
, NULL
);
2373 g_signal_handlers_unblock_matched(ggblist
->statustext
, G_SIGNAL_MATCH_FUNC
,
2374 0, 0, NULL
, status_text_changed
, NULL
);
2378 blist_node_compare_position(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2380 while ((n1
= purple_blist_node_get_sibling_prev(n1
)) != NULL
)
2387 blist_node_compare_text(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2389 const char *s1
, *s2
;
2393 if (purple_blist_node_get_type(n1
) != purple_blist_node_get_type(n2
))
2394 return blist_node_compare_position(n1
, n2
);
2396 switch (purple_blist_node_get_type(n1
))
2398 case PURPLE_BLIST_CHAT_NODE
:
2399 s1
= purple_chat_get_name((PurpleChat
*)n1
);
2400 s2
= purple_chat_get_name((PurpleChat
*)n2
);
2402 case PURPLE_BLIST_BUDDY_NODE
:
2403 return purple_presence_compare(purple_buddy_get_presence((PurpleBuddy
*)n1
),
2404 purple_buddy_get_presence((PurpleBuddy
*)n2
));
2406 case PURPLE_BLIST_CONTACT_NODE
:
2407 s1
= purple_contact_get_alias((PurpleContact
*)n1
);
2408 s2
= purple_contact_get_alias((PurpleContact
*)n2
);
2411 return blist_node_compare_position(n1
, n2
);
2414 us1
= g_utf8_strup(s1
, -1);
2415 us2
= g_utf8_strup(s2
, -1);
2416 ret
= g_utf8_collate(us1
, us2
);
2424 blist_node_compare_status(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2428 if (purple_blist_node_get_type(n1
) != purple_blist_node_get_type(n2
))
2429 return blist_node_compare_position(n1
, n2
);
2431 switch (purple_blist_node_get_type(n1
)) {
2432 case PURPLE_BLIST_CONTACT_NODE
:
2433 n1
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(n1
)));
2434 n2
= PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(n2
)));
2435 /* now compare the presence of the priority buddies */
2436 case PURPLE_BLIST_BUDDY_NODE
:
2437 ret
= purple_presence_compare(purple_buddy_get_presence((PurpleBuddy
*)n1
),
2438 purple_buddy_get_presence((PurpleBuddy
*)n2
));
2443 return blist_node_compare_position(n1
, n2
);
2447 /* Sort alphabetically if presence is not comparable */
2448 ret
= blist_node_compare_text(n1
, n2
);
2454 get_contact_log_size(PurpleBlistNode
*c
)
2457 PurpleBlistNode
*node
;
2459 for (node
= purple_blist_node_get_first_child(c
); node
; node
= purple_blist_node_get_sibling_next(node
)) {
2460 PurpleBuddy
*b
= (PurpleBuddy
*)node
;
2461 log
+= purple_log_get_total_size(PURPLE_LOG_IM
, purple_buddy_get_name(b
),
2462 purple_buddy_get_account(b
));
2469 blist_node_compare_log(PurpleBlistNode
*n1
, PurpleBlistNode
*n2
)
2472 PurpleBuddy
*b1
, *b2
;
2474 if (purple_blist_node_get_type(n1
) != purple_blist_node_get_type(n2
))
2475 return blist_node_compare_position(n1
, n2
);
2477 switch (purple_blist_node_get_type(n1
)) {
2478 case PURPLE_BLIST_BUDDY_NODE
:
2479 b1
= (PurpleBuddy
*)n1
;
2480 b2
= (PurpleBuddy
*)n2
;
2481 ret
= purple_log_get_total_size(PURPLE_LOG_IM
, purple_buddy_get_name(b2
), purple_buddy_get_account(b2
)) -
2482 purple_log_get_total_size(PURPLE_LOG_IM
, purple_buddy_get_name(b1
), purple_buddy_get_account(b1
));
2486 case PURPLE_BLIST_CONTACT_NODE
:
2487 ret
= get_contact_log_size(n2
) - get_contact_log_size(n1
);
2492 return blist_node_compare_position(n1
, n2
);
2494 ret
= blist_node_compare_text(n1
, n2
);
2499 plugin_action(GntMenuItem
*item
, gpointer data
)
2501 PurplePluginAction
*action
= data
;
2502 if (action
&& action
->callback
)
2503 action
->callback(action
);
2507 build_plugin_actions(GntMenuItem
*item
, PurplePlugin
*plugin
, gpointer context
)
2509 GntWidget
*sub
= gnt_menu_new(GNT_MENU_POPUP
);
2511 GntMenuItem
*menuitem
;
2513 gnt_menuitem_set_submenu(item
, GNT_MENU(sub
));
2514 for (actions
= PURPLE_PLUGIN_ACTIONS(plugin
, context
); actions
;
2515 actions
= g_list_delete_link(actions
, actions
)) {
2516 if (actions
->data
) {
2517 PurplePluginAction
*action
= actions
->data
;
2518 action
->plugin
= plugin
;
2519 action
->context
= context
;
2520 menuitem
= gnt_menuitem_new(action
->label
);
2521 gnt_menu_add_item(GNT_MENU(sub
), menuitem
);
2523 gnt_menuitem_set_callback(menuitem
, plugin_action
, action
);
2524 g_object_set_data_full(G_OBJECT(menuitem
), "plugin_action",
2525 action
, (GDestroyNotify
)purple_plugin_action_free
);
2531 buddy_recent_signed_on_off(gpointer data
)
2533 PurpleBlistNode
*node
= data
;
2534 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
2536 purple_timeout_remove(fnode
->signed_timer
);
2537 fnode
->signed_timer
= 0;
2539 if (!ggblist
->manager
->can_add_node(node
)) {
2540 node_remove(purple_get_blist(), node
);
2542 update_node_display(node
, ggblist
);
2543 if (purple_blist_node_get_parent(node
) && PURPLE_BLIST_NODE_IS_CONTACT(purple_blist_node_get_parent(node
)))
2544 update_node_display(purple_blist_node_get_parent(node
), ggblist
);
2551 buddy_signed_on_off_cb(gpointer data
)
2553 PurpleBlistNode
*node
= data
;
2554 FinchBlistNode
*fnode
= FINCH_GET_DATA(node
);
2555 if (!ggblist
|| !fnode
)
2558 if (fnode
->signed_timer
)
2559 purple_timeout_remove(fnode
->signed_timer
);
2560 fnode
->signed_timer
= purple_timeout_add_seconds(6, (GSourceFunc
)buddy_recent_signed_on_off
, data
);
2561 update_node_display(node
, ggblist
);
2562 if (purple_blist_node_get_parent(node
) && PURPLE_BLIST_NODE_IS_CONTACT(purple_blist_node_get_parent(node
)))
2563 update_node_display(purple_blist_node_get_parent(node
), ggblist
);
2568 buddy_signed_on_off(PurpleBuddy
* buddy
, gpointer null
)
2570 g_idle_add(buddy_signed_on_off_cb
, buddy
);
2574 reconstruct_plugins_menu(void)
2583 if (ggblist
->plugins
== NULL
)
2584 ggblist
->plugins
= gnt_menuitem_new(_("Plugins"));
2586 plg
= ggblist
->plugins
;
2587 sub
= gnt_menu_new(GNT_MENU_POPUP
);
2588 gnt_menuitem_set_submenu(plg
, GNT_MENU(sub
));
2590 for (iter
= purple_plugins_get_loaded(); iter
; iter
= iter
->next
) {
2591 PurplePlugin
*plugin
= iter
->data
;
2593 if (PURPLE_IS_PROTOCOL_PLUGIN(plugin
))
2596 if (!PURPLE_PLUGIN_HAS_ACTIONS(plugin
))
2599 item
= gnt_menuitem_new(_(plugin
->info
->name
));
2600 gnt_menu_add_item(GNT_MENU(sub
), item
);
2601 build_plugin_actions(item
, plugin
, NULL
);
2606 reconstruct_accounts_menu(void)
2609 GntMenuItem
*acc
, *item
;
2615 if (ggblist
->accounts
== NULL
)
2616 ggblist
->accounts
= gnt_menuitem_new(_("Accounts"));
2618 acc
= ggblist
->accounts
;
2619 sub
= gnt_menu_new(GNT_MENU_POPUP
);
2620 gnt_menuitem_set_submenu(acc
, GNT_MENU(sub
));
2622 for (iter
= purple_accounts_get_all_active(); iter
;
2623 iter
= g_list_delete_link(iter
, iter
)) {
2624 PurpleAccount
*account
= iter
->data
;
2625 PurpleConnection
*gc
= purple_account_get_connection(account
);
2628 if (!gc
|| !PURPLE_CONNECTION_IS_CONNECTED(gc
))
2630 prpl
= purple_connection_get_prpl(gc
);
2632 if (PURPLE_PLUGIN_HAS_ACTIONS(prpl
)) {
2633 item
= gnt_menuitem_new(purple_account_get_username(account
));
2634 gnt_menu_add_item(GNT_MENU(sub
), item
);
2635 build_plugin_actions(item
, prpl
, gc
);
2641 reconstruct_grouping_menu(void)
2646 if (!ggblist
|| !ggblist
->grouping
)
2649 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
2650 gnt_menuitem_set_submenu(ggblist
->grouping
, GNT_MENU(subsub
));
2652 for (iter
= managers
; iter
; iter
= iter
->next
) {
2654 FinchBlistManager
*manager
= iter
->data
;
2655 GntMenuItem
*item
= gnt_menuitem_new(_(manager
->name
));
2656 g_snprintf(menuid
, sizeof(menuid
), "grouping-%s", manager
->id
);
2657 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), menuid
);
2658 gnt_menu_add_item(GNT_MENU(subsub
), item
);
2659 g_object_set_data_full(G_OBJECT(item
), "grouping-id", g_strdup(manager
->id
), g_free
);
2660 gnt_menuitem_set_callback(item
, menu_group_set_cb
, NULL
);
2665 auto_join_chats(gpointer data
)
2667 PurpleBlistNode
*node
;
2668 PurpleConnection
*pc
= data
;
2669 PurpleAccount
*account
= purple_connection_get_account(pc
);
2671 for (node
= purple_blist_get_root(); node
;
2672 node
= purple_blist_node_next(node
, FALSE
)) {
2673 if (PURPLE_BLIST_NODE_IS_CHAT(node
)) {
2674 PurpleChat
*chat
= (PurpleChat
*)node
;
2675 if (purple_chat_get_account(chat
) == account
&&
2676 purple_blist_node_get_bool(node
, "gnt-autojoin"))
2677 serv_join_chat(purple_account_get_connection(account
), purple_chat_get_components(chat
));
2684 account_signed_on_cb(PurpleConnection
*gc
, gpointer null
)
2686 g_idle_add(auto_join_chats
, gc
);
2689 static void toggle_pref_cb(GntMenuItem
*item
, gpointer n
)
2691 purple_prefs_set_bool(n
, !purple_prefs_get_bool(n
));
2694 static void sort_blist_change_cb(GntMenuItem
*item
, gpointer n
)
2696 purple_prefs_set_string(PREF_ROOT
"/sort_type", n
);
2700 block_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2702 PurpleAccount
*account
= purple_request_fields_get_account(fields
, "account");
2703 const char *name
= purple_request_fields_get_string(fields
, "screenname");
2704 if (account
&& name
&& *name
!= '\0') {
2705 if (purple_request_fields_get_choice(fields
, "block") == 1) {
2706 purple_privacy_deny(account
, name
, FALSE
, FALSE
);
2708 purple_privacy_allow(account
, name
, FALSE
, FALSE
);
2714 block_select(GntMenuItem
*item
, gpointer n
)
2716 PurpleRequestFields
*fields
;
2717 PurpleRequestFieldGroup
*group
;
2718 PurpleRequestField
*field
;
2720 fields
= purple_request_fields_new();
2722 group
= purple_request_field_group_new(NULL
);
2723 purple_request_fields_add_group(fields
, group
);
2725 field
= purple_request_field_string_new("screenname", _("Name"), NULL
, FALSE
);
2726 purple_request_field_set_type_hint(field
, "screenname");
2727 purple_request_field_set_required(field
, TRUE
);
2728 purple_request_field_group_add_field(group
, field
);
2730 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2731 purple_request_field_set_type_hint(field
, "account");
2732 purple_request_field_set_visible(field
,
2733 (purple_connections_get_all() != NULL
&&
2734 purple_connections_get_all()->next
!= NULL
));
2735 purple_request_field_set_required(field
, TRUE
);
2736 purple_request_field_group_add_field(group
, field
);
2738 field
= purple_request_field_choice_new("block", _("Block/Unblock"), 1);
2739 purple_request_field_choice_add(field
, _("Block"));
2740 purple_request_field_choice_add(field
, _("Unblock"));
2741 purple_request_field_group_add_field(group
, field
);
2743 purple_request_fields(purple_get_blist(), _("Block/Unblock"),
2745 _("Please enter the username or alias of the person "
2746 "you would like to Block/Unblock."),
2748 _("OK"), G_CALLBACK(block_select_cb
),
2754 /* send_im_select* -- Xerox */
2756 send_im_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2758 PurpleAccount
*account
;
2759 const char *username
;
2760 PurpleConversation
*conv
;
2762 account
= purple_request_fields_get_account(fields
, "account");
2763 username
= purple_request_fields_get_string(fields
, "screenname");
2765 conv
= purple_conversation_new(PURPLE_CONV_TYPE_IM
, account
, username
);
2766 purple_conversation_present(conv
);
2770 send_im_select(GntMenuItem
*item
, gpointer n
)
2772 PurpleRequestFields
*fields
;
2773 PurpleRequestFieldGroup
*group
;
2774 PurpleRequestField
*field
;
2776 fields
= purple_request_fields_new();
2778 group
= purple_request_field_group_new(NULL
);
2779 purple_request_fields_add_group(fields
, group
);
2781 field
= purple_request_field_string_new("screenname", _("Name"), NULL
, FALSE
);
2782 purple_request_field_set_type_hint(field
, "screenname");
2783 purple_request_field_set_required(field
, TRUE
);
2784 purple_request_field_group_add_field(group
, field
);
2786 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2787 purple_request_field_set_type_hint(field
, "account");
2788 purple_request_field_set_visible(field
,
2789 (purple_connections_get_all() != NULL
&&
2790 purple_connections_get_all()->next
!= NULL
));
2791 purple_request_field_set_required(field
, TRUE
);
2792 purple_request_field_group_add_field(group
, field
);
2794 purple_request_fields(purple_get_blist(), _("New Instant Message"),
2796 _("Please enter the username or alias of the person "
2797 "you would like to IM."),
2799 _("OK"), G_CALLBACK(send_im_select_cb
),
2806 join_chat_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2808 PurpleAccount
*account
;
2810 PurpleConnection
*gc
;
2812 GHashTable
*hash
= NULL
;
2813 PurpleConversation
*conv
;
2815 account
= purple_request_fields_get_account(fields
, "account");
2816 name
= purple_request_fields_get_string(fields
, "chat");
2818 if (!purple_account_is_connected(account
))
2821 gc
= purple_account_get_connection(account
);
2822 /* Create a new conversation now. This will give focus to the new window.
2823 * But it's necessary to pretend that we left the chat, because otherwise
2824 * a new conversation window will pop up when we finally join the chat. */
2825 if (!(conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT
, name
, account
))) {
2826 conv
= purple_conversation_new(PURPLE_CONV_TYPE_CHAT
, account
, name
);
2827 purple_conv_chat_left(PURPLE_CONV_CHAT(conv
));
2829 purple_conversation_present(conv
);
2832 chat
= purple_blist_find_chat(account
, name
);
2834 PurplePluginProtocolInfo
*info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
2835 if (info
->chat_info_defaults
!= NULL
)
2836 hash
= info
->chat_info_defaults(gc
, name
);
2838 hash
= purple_chat_get_components(chat
);
2840 serv_join_chat(gc
, hash
);
2841 if (chat
== NULL
&& hash
!= NULL
)
2842 g_hash_table_destroy(hash
);
2846 join_chat_select(GntMenuItem
*item
, gpointer n
)
2848 PurpleRequestFields
*fields
;
2849 PurpleRequestFieldGroup
*group
;
2850 PurpleRequestField
*field
;
2852 fields
= purple_request_fields_new();
2854 group
= purple_request_field_group_new(NULL
);
2855 purple_request_fields_add_group(fields
, group
);
2857 field
= purple_request_field_string_new("chat", _("Channel"), NULL
, FALSE
);
2858 purple_request_field_set_required(field
, TRUE
);
2859 purple_request_field_group_add_field(group
, field
);
2861 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2862 purple_request_field_set_type_hint(field
, "account");
2863 purple_request_field_set_visible(field
,
2864 (purple_connections_get_all() != NULL
&&
2865 purple_connections_get_all()->next
!= NULL
));
2866 purple_request_field_set_required(field
, TRUE
);
2867 purple_request_field_group_add_field(group
, field
);
2869 purple_request_fields(purple_get_blist(), _("Join a Chat"),
2871 _("Please enter the name of the chat you want to join."),
2873 _("Join"), G_CALLBACK(join_chat_select_cb
),
2880 view_log_select_cb(gpointer data
, PurpleRequestFields
*fields
)
2882 PurpleAccount
*account
;
2885 PurpleContact
*contact
;
2887 account
= purple_request_fields_get_account(fields
, "account");
2888 name
= purple_request_fields_get_string(fields
, "screenname");
2890 buddy
= purple_find_buddy(account
, name
);
2892 contact
= purple_buddy_get_contact(buddy
);
2898 finch_log_show_contact(contact
);
2900 finch_log_show(PURPLE_LOG_IM
, name
, account
);
2905 view_log_cb(GntMenuItem
*item
, gpointer n
)
2907 PurpleRequestFields
*fields
;
2908 PurpleRequestFieldGroup
*group
;
2909 PurpleRequestField
*field
;
2911 fields
= purple_request_fields_new();
2913 group
= purple_request_field_group_new(NULL
);
2914 purple_request_fields_add_group(fields
, group
);
2916 field
= purple_request_field_string_new("screenname", _("Name"), NULL
, FALSE
);
2917 purple_request_field_set_type_hint(field
, "screenname-all");
2918 purple_request_field_set_required(field
, TRUE
);
2919 purple_request_field_group_add_field(group
, field
);
2921 field
= purple_request_field_account_new("account", _("Account"), NULL
);
2922 purple_request_field_set_type_hint(field
, "account");
2923 purple_request_field_set_visible(field
,
2924 (purple_accounts_get_all() != NULL
&&
2925 purple_accounts_get_all()->next
!= NULL
));
2926 purple_request_field_set_required(field
, TRUE
);
2927 purple_request_field_group_add_field(group
, field
);
2928 purple_request_field_account_set_show_all(field
, TRUE
);
2930 purple_request_fields(purple_get_blist(), _("View Log"),
2932 _("Please enter the username or alias of the person "
2933 "whose log you would like to view."),
2935 _("OK"), G_CALLBACK(view_log_select_cb
),
2942 view_all_logs_cb(GntMenuItem
*item
, gpointer n
)
2944 finch_log_show(PURPLE_LOG_IM
, NULL
, NULL
);
2948 menu_add_buddy_cb(GntMenuItem
*item
, gpointer null
)
2950 purple_blist_request_add_buddy(NULL
, NULL
, NULL
, NULL
);
2954 menu_add_chat_cb(GntMenuItem
*item
, gpointer null
)
2956 purple_blist_request_add_chat(NULL
, NULL
, NULL
, NULL
);
2960 menu_add_group_cb(GntMenuItem
*item
, gpointer null
)
2962 purple_blist_request_add_group();
2966 menu_group_set_cb(GntMenuItem
*item
, gpointer null
)
2968 const char *id
= g_object_get_data(G_OBJECT(item
), "grouping-id");
2969 purple_prefs_set_string(PREF_ROOT
"/grouping", id
);
2975 GntWidget
*menu
, *sub
, *subsub
;
2982 window
= GNT_WINDOW(ggblist
->window
);
2983 ggblist
->menu
= menu
= gnt_menu_new(GNT_MENU_TOPLEVEL
);
2984 gnt_window_set_menu(window
, GNT_MENU(menu
));
2986 item
= gnt_menuitem_new(_("Options"));
2987 gnt_menu_add_item(GNT_MENU(menu
), item
);
2989 sub
= gnt_menu_new(GNT_MENU_POPUP
);
2990 gnt_menuitem_set_submenu(item
, GNT_MENU(sub
));
2992 item
= gnt_menuitem_new(_("Send IM..."));
2993 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "send-im");
2994 gnt_menu_add_item(GNT_MENU(sub
), item
);
2995 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), send_im_select
, NULL
);
2997 item
= gnt_menuitem_new(_("Block/Unblock..."));
2998 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "block-unblock");
2999 gnt_menu_add_item(GNT_MENU(sub
), item
);
3000 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), block_select
, NULL
);
3002 item
= gnt_menuitem_new(_("Join Chat..."));
3003 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "join-chat");
3004 gnt_menu_add_item(GNT_MENU(sub
), item
);
3005 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), join_chat_select
, NULL
);
3007 item
= gnt_menuitem_new(_("View Log..."));
3008 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "view-log");
3009 gnt_menu_add_item(GNT_MENU(sub
), item
);
3010 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), view_log_cb
, NULL
);
3012 item
= gnt_menuitem_new(_("View All Logs"));
3013 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "view-all-logs");
3014 gnt_menu_add_item(GNT_MENU(sub
), item
);
3015 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), view_all_logs_cb
, NULL
);
3017 item
= gnt_menuitem_new(_("Show"));
3018 gnt_menu_add_item(GNT_MENU(sub
), item
);
3019 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
3020 gnt_menuitem_set_submenu(item
, GNT_MENU(subsub
));
3022 item
= gnt_menuitem_check_new(_("Empty groups"));
3023 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "show-empty-groups");
3024 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
),
3025 purple_prefs_get_bool(PREF_ROOT
"/emptygroups"));
3026 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3027 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), toggle_pref_cb
, PREF_ROOT
"/emptygroups");
3029 item
= gnt_menuitem_check_new(_("Offline buddies"));
3030 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "show-offline-buddies");
3031 gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item
),
3032 purple_prefs_get_bool(PREF_ROOT
"/showoffline"));
3033 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3034 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), toggle_pref_cb
, PREF_ROOT
"/showoffline");
3036 item
= gnt_menuitem_new(_("Sort"));
3037 gnt_menu_add_item(GNT_MENU(sub
), item
);
3038 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
3039 gnt_menuitem_set_submenu(item
, GNT_MENU(subsub
));
3041 item
= gnt_menuitem_new(_("By Status"));
3042 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "sort-status");
3043 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3044 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), sort_blist_change_cb
, "status");
3046 item
= gnt_menuitem_new(_("Alphabetically"));
3047 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "sort-alpha");
3048 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3049 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), sort_blist_change_cb
, "text");
3051 item
= gnt_menuitem_new(_("By Log Size"));
3052 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "sort-log");
3053 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3054 gnt_menuitem_set_callback(GNT_MENU_ITEM(item
), sort_blist_change_cb
, "log");
3056 item
= gnt_menuitem_new(_("Add"));
3057 gnt_menu_add_item(GNT_MENU(sub
), item
);
3059 subsub
= gnt_menu_new(GNT_MENU_POPUP
);
3060 gnt_menuitem_set_submenu(item
, GNT_MENU(subsub
));
3062 item
= gnt_menuitem_new(_("Buddy"));
3063 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "add-buddy");
3064 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3065 gnt_menuitem_set_callback(item
, menu_add_buddy_cb
, NULL
);
3067 item
= gnt_menuitem_new(_("Chat"));
3068 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "add-chat");
3069 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3070 gnt_menuitem_set_callback(item
, menu_add_chat_cb
, NULL
);
3072 item
= gnt_menuitem_new(_("Group"));
3073 gnt_menuitem_set_id(GNT_MENU_ITEM(item
), "add-group");
3074 gnt_menu_add_item(GNT_MENU(subsub
), item
);
3075 gnt_menuitem_set_callback(item
, menu_add_group_cb
, NULL
);
3077 ggblist
->grouping
= item
= gnt_menuitem_new(_("Grouping"));
3078 gnt_menu_add_item(GNT_MENU(sub
), item
);
3079 reconstruct_grouping_menu();
3081 reconstruct_accounts_menu();
3082 gnt_menu_add_item(GNT_MENU(menu
), ggblist
->accounts
);
3084 reconstruct_plugins_menu();
3085 gnt_menu_add_item(GNT_MENU(menu
), ggblist
->plugins
);
3088 void finch_blist_show()
3090 blist_show(purple_get_blist());
3094 group_collapsed(GntWidget
*widget
, PurpleBlistNode
*node
, gboolean collapsed
, gpointer null
)
3096 if (PURPLE_BLIST_NODE_IS_GROUP(node
))
3097 purple_blist_node_set_bool(node
, "collapsed", collapsed
);
3101 blist_show(PurpleBuddyList
*list
)
3103 if (ggblist
== NULL
)
3105 else if (ggblist
->window
) {
3106 gnt_window_present(ggblist
->window
);
3110 ggblist
->window
= gnt_vwindow_new(FALSE
);
3111 gnt_widget_set_name(ggblist
->window
, "buddylist");
3112 gnt_box_set_toplevel(GNT_BOX(ggblist
->window
), TRUE
);
3113 gnt_box_set_title(GNT_BOX(ggblist
->window
), _("Buddy List"));
3114 gnt_box_set_pad(GNT_BOX(ggblist
->window
), 0);
3116 ggblist
->tree
= gnt_tree_new();
3118 GNT_WIDGET_SET_FLAGS(ggblist
->tree
, GNT_WIDGET_NO_BORDER
);
3119 gnt_widget_set_size(ggblist
->tree
, purple_prefs_get_int(PREF_ROOT
"/size/width"),
3120 purple_prefs_get_int(PREF_ROOT
"/size/height"));
3121 gnt_widget_set_position(ggblist
->window
, purple_prefs_get_int(PREF_ROOT
"/position/x"),
3122 purple_prefs_get_int(PREF_ROOT
"/position/y"));
3124 gnt_box_add_widget(GNT_BOX(ggblist
->window
), ggblist
->tree
);
3126 ggblist
->status
= gnt_combo_box_new();
3127 gnt_box_add_widget(GNT_BOX(ggblist
->window
), ggblist
->status
);
3128 ggblist
->statustext
= gnt_entry_new(NULL
);
3129 gnt_box_add_widget(GNT_BOX(ggblist
->window
), ggblist
->statustext
);
3131 gnt_widget_show(ggblist
->window
);
3133 purple_signal_connect(purple_connections_get_handle(), "signed-on", finch_blist_get_handle(),
3134 PURPLE_CALLBACK(reconstruct_accounts_menu
), NULL
);
3135 purple_signal_connect(purple_connections_get_handle(), "signed-off", finch_blist_get_handle(),
3136 PURPLE_CALLBACK(reconstruct_accounts_menu
), NULL
);
3137 purple_signal_connect(purple_accounts_get_handle(), "account-actions-changed", finch_blist_get_handle(),
3138 PURPLE_CALLBACK(reconstruct_accounts_menu
), NULL
);
3139 purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", finch_blist_get_handle(),
3140 PURPLE_CALLBACK(buddy_status_changed
), ggblist
);
3141 purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", finch_blist_get_handle(),
3142 PURPLE_CALLBACK(buddy_idle_changed
), ggblist
);
3144 purple_signal_connect(purple_plugins_get_handle(), "plugin-load", finch_blist_get_handle(),
3145 PURPLE_CALLBACK(reconstruct_plugins_menu
), NULL
);
3146 purple_signal_connect(purple_plugins_get_handle(), "plugin-unload", finch_blist_get_handle(),
3147 PURPLE_CALLBACK(reconstruct_plugins_menu
), NULL
);
3149 purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_blist_get_handle(),
3150 PURPLE_CALLBACK(buddy_signed_on_off
), ggblist
);
3151 purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_blist_get_handle(),
3152 PURPLE_CALLBACK(buddy_signed_on_off
), ggblist
);
3155 /* These I plan to use to indicate unread-messages etc. */
3156 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", finch_blist_get_handle(),
3157 PURPLE_CALLBACK(received_im_msg
), list
);
3158 purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg", finch_blist_get_handle(),
3159 PURPLE_CALLBACK(sent_im_msg
), NULL
);
3161 purple_signal_connect(purple_conversations_get_handle(), "received-chat-msg", finch_blist_get_handle(),
3162 PURPLE_CALLBACK(received_chat_msg
), list
);
3165 g_signal_connect(G_OBJECT(ggblist
->tree
), "selection_changed", G_CALLBACK(selection_changed
), ggblist
);
3166 g_signal_connect(G_OBJECT(ggblist
->tree
), "key_pressed", G_CALLBACK(key_pressed
), ggblist
);
3167 g_signal_connect(G_OBJECT(ggblist
->tree
), "context-menu", G_CALLBACK(context_menu
), ggblist
);
3168 g_signal_connect(G_OBJECT(ggblist
->tree
), "collapse-toggled", G_CALLBACK(group_collapsed
), NULL
);
3169 g_signal_connect(G_OBJECT(ggblist
->tree
), "activate", G_CALLBACK(selection_activate
), ggblist
);
3170 g_signal_connect_data(G_OBJECT(ggblist
->tree
), "gained-focus", G_CALLBACK(draw_tooltip
),
3171 ggblist
, 0, G_CONNECT_AFTER
| G_CONNECT_SWAPPED
);
3172 g_signal_connect_data(G_OBJECT(ggblist
->tree
), "lost-focus", G_CALLBACK(remove_peripherals
),
3173 ggblist
, 0, G_CONNECT_AFTER
| G_CONNECT_SWAPPED
);
3174 g_signal_connect_data(G_OBJECT(ggblist
->window
), "workspace-hidden", G_CALLBACK(remove_peripherals
),
3175 ggblist
, 0, G_CONNECT_AFTER
| G_CONNECT_SWAPPED
);
3176 g_signal_connect(G_OBJECT(ggblist
->tree
), "size_changed", G_CALLBACK(size_changed_cb
), NULL
);
3177 g_signal_connect(G_OBJECT(ggblist
->window
), "position_set", G_CALLBACK(save_position_cb
), NULL
);
3178 g_signal_connect(G_OBJECT(ggblist
->window
), "destroy", G_CALLBACK(reset_blist_window
), NULL
);
3180 /* Status signals */
3181 purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed", finch_blist_get_handle(),
3182 PURPLE_CALLBACK(savedstatus_changed
), NULL
);
3183 g_signal_connect(G_OBJECT(ggblist
->status
), "selection_changed",
3184 G_CALLBACK(status_selection_changed
), NULL
);
3185 g_signal_connect(G_OBJECT(ggblist
->statustext
), "key_pressed",
3186 G_CALLBACK(status_text_changed
), NULL
);
3190 populate_buddylist();
3192 savedstatus_changed(purple_savedstatus_get_current(), NULL
);
3195 void finch_blist_uninit()
3199 gboolean
finch_blist_get_position(int *x
, int *y
)
3201 if (!ggblist
|| !ggblist
->window
)
3203 gnt_widget_get_position(ggblist
->window
, x
, y
);
3207 void finch_blist_set_position(int x
, int y
)
3209 gnt_widget_set_position(ggblist
->window
, x
, y
);
3212 gboolean
finch_blist_get_size(int *width
, int *height
)
3214 if (!ggblist
|| !ggblist
->window
)
3216 gnt_widget_get_size(ggblist
->window
, width
, height
);
3220 void finch_blist_set_size(int width
, int height
)
3222 gnt_widget_set_size(ggblist
->window
, width
, height
);
3225 void finch_blist_install_manager(const FinchBlistManager
*manager
)
3227 if (!g_list_find(managers
, manager
)) {
3228 managers
= g_list_append(managers
, (gpointer
)manager
);
3229 reconstruct_grouping_menu();
3230 if (strcmp(manager
->id
, purple_prefs_get_string(PREF_ROOT
"/grouping")) == 0)
3231 purple_prefs_trigger_callback(PREF_ROOT
"/grouping");
3235 void finch_blist_uninstall_manager(const FinchBlistManager
*manager
)
3237 if (g_list_find(managers
, manager
)) {
3238 managers
= g_list_remove(managers
, manager
);
3239 reconstruct_grouping_menu();
3240 if (strcmp(manager
->id
, purple_prefs_get_string(PREF_ROOT
"/grouping")) == 0)
3241 purple_prefs_trigger_callback(PREF_ROOT
"/grouping");
3245 FinchBlistManager
* finch_blist_manager_find(const char *id
)
3247 GList
*iter
= managers
;
3251 for (; iter
; iter
= iter
->next
) {
3252 FinchBlistManager
*m
= iter
->data
;
3253 if (strcmp(id
, m
->id
) == 0)
3259 GntTree
* finch_blist_get_tree(void)
3261 return ggblist
? GNT_TREE(ggblist
->tree
) : NULL
;