Mercurial > pidgin
annotate src/buddy.c @ 4835:b4e1be581795
[gaim-migrate @ 5160]
some updates on things we've accomplished.
at some point soon, i'm probly going to split this into files so that each
dir has its own todo (esp the prpl dirs), and make use of ChipX86's work
to allow todo files to be linked
committer: Tailor Script <tailor@pidgin.im>
| author | Luke Schierer <lschiere@pidgin.im> |
|---|---|
| date | Thu, 20 Mar 2003 00:00:24 +0000 |
| parents | 0ed37c803503 |
| children | 3411fdaa54fa |
| rev | line source |
|---|---|
| 1 | 1 /* |
| 2 * gaim | |
| 3 * | |
| 4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
| 5 * | |
| 6 * This program is free software; you can redistribute it and/or modify | |
| 7 * it under the terms of the GNU General Public License as published by | |
| 8 * the Free Software Foundation; either version 2 of the License, or | |
| 9 * (at your option) any later version. | |
| 10 * | |
| 11 * This program is distributed in the hope that it will be useful, | |
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 * GNU General Public License for more details. | |
| 15 * | |
| 16 * You should have received a copy of the GNU General Public License | |
| 17 * along with this program; if not, write to the Free Software | |
| 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 * | |
| 20 */ | |
| 21 | |
|
349
b402a23f35df
[gaim-migrate @ 359]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
342
diff
changeset
|
22 #ifdef HAVE_CONFIG_H |
|
2090
b66aca8e8dce
[gaim-migrate @ 2100]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2048
diff
changeset
|
23 #include <config.h> |
|
349
b402a23f35df
[gaim-migrate @ 359]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
342
diff
changeset
|
24 #endif |
|
391
be408b41c172
[gaim-migrate @ 401]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
350
diff
changeset
|
25 #ifdef GAIM_PLUGINS |
| 3630 | 26 #ifndef _WIN32 |
|
391
be408b41c172
[gaim-migrate @ 401]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
350
diff
changeset
|
27 #include <dlfcn.h> |
| 3630 | 28 #endif |
|
391
be408b41c172
[gaim-migrate @ 401]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
350
diff
changeset
|
29 #endif /* GAIM_PLUGINS */ |
| 1 | 30 #include <string.h> |
| 31 #include <stdio.h> | |
| 32 #include <stdlib.h> | |
| 3159 | 33 #include <ctype.h> |
| 1 | 34 #include <math.h> |
| 35 #include <time.h> | |
| 3630 | 36 #include <ctype.h> |
| 37 | |
| 38 #ifdef _WIN32 | |
| 39 #include <gdk/gdkwin32.h> | |
| 40 #else | |
|
1233
728a90516211
[gaim-migrate @ 1243]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1230
diff
changeset
|
41 #include <unistd.h> |
| 3630 | 42 #include <gdk/gdkx.h> |
| 43 #endif | |
| 1 | 44 |
|
1634
d029dc28a61e
[gaim-migrate @ 1644]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1625
diff
changeset
|
45 #include <gdk/gdkkeysyms.h> |
| 1 | 46 #include <gtk/gtk.h> |
|
1030
38452403563b
[gaim-migrate @ 1040]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1002
diff
changeset
|
47 #include "prpl.h" |
| 4561 | 48 #include "sound.h" |
| 1 | 49 #include "gaim.h" |
| 4687 | 50 #include "gtklist.h" |
| 51 #include "gtkft.h" | |
| 3630 | 52 |
| 53 #ifdef _WIN32 | |
| 54 #include "win32dep.h" | |
| 55 #endif | |
| 56 | |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
57 static struct gaim_gtk_buddy_list *gtkblist = NULL; |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
58 |
| 4698 | 59 /* Docklet nonsense */ |
| 60 static gboolean gaim_gtk_blist_obscured = FALSE; | |
| 61 | |
| 4810 | 62 static void gaim_gtk_blist_selection_changed(GtkTreeSelection *selection, gpointer data); |
| 4687 | 63 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node); |
| 4724 | 64 static char *gaim_get_tooltip_text(struct buddy *b); |
| 65 static GdkPixbuf *gaim_gtk_blist_get_status_icon(struct buddy *b, GaimStatusIconSize size); | |
| 4834 | 66 static char *item_factory_translate_func (const char *path, gpointer func_data); |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
67 |
| 4687 | 68 /*************************************************** |
| 69 * Callbacks * | |
| 70 ***************************************************/ | |
| 3869 | 71 |
| 4698 | 72 static void gaim_gtk_blist_destroy_cb() |
| 73 { | |
| 74 if (docklet_count) | |
| 75 gaim_blist_set_visible(FALSE); | |
| 76 else | |
| 77 do_quit(); | |
| 78 } | |
| 79 | |
| 4732 | 80 static void gtk_blist_menu_info_cb(GtkWidget *w, struct buddy *b) |
| 81 { | |
| 82 serv_get_info(b->account->gc, b->name); | |
| 83 } | |
| 84 | |
| 4697 | 85 static void gtk_blist_menu_im_cb(GtkWidget *w, struct buddy *b) |
| 86 { | |
| 87 gaim_conversation_new(GAIM_CONV_IM, b->account, b->name); | |
| 88 } | |
| 89 | |
| 90 static void gtk_blist_menu_alias_cb(GtkWidget *w, struct buddy *b) | |
| 91 { | |
| 92 alias_dialog_bud(b); | |
| 93 } | |
| 94 | |
| 95 static void gtk_blist_menu_bp_cb(GtkWidget *w, struct buddy *b) | |
| 96 { | |
| 97 show_new_bp(b->name, b->account->gc, b->idle, | |
| 98 b->uc & UC_UNAVAILABLE, NULL); | |
| 99 } | |
| 100 | |
| 101 static void gtk_blist_menu_showlog_cb(GtkWidget *w, struct buddy *b) | |
| 102 { | |
| 103 show_log(b->name); | |
| 104 } | |
| 105 | |
| 106 static void gtk_blist_show_systemlog_cb() | |
| 107 { | |
| 108 show_log(NULL); | |
| 109 } | |
| 110 | |
| 4776 | 111 static void gtk_blist_show_onlinehelp_cb() |
| 112 { | |
| 113 open_url(NULL, "http://gaim.sourceforge.net/documentation.php"); | |
| 114 } | |
| 115 | |
| 4692 | 116 static void gtk_blist_button_im_cb(GtkWidget *w, GtkTreeView *tv) |
| 117 { | |
| 118 GtkTreeIter iter; | |
| 119 GtkTreeModel *model = gtk_tree_view_get_model(tv); | |
| 120 GtkTreeSelection *sel = gtk_tree_view_get_selection(tv); | |
| 121 | |
| 122 if(gtk_tree_selection_get_selected(sel, &model, &iter)){ | |
| 123 GaimBlistNode *node; | |
| 124 | |
| 125 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
| 126 if (GAIM_BLIST_NODE_IS_BUDDY(node)) | |
| 127 gaim_conversation_new(GAIM_CONV_IM, ((struct buddy*)node)->account, ((struct buddy*)node)->name); | |
| 128 } | |
| 4694 | 129 } |
| 4692 | 130 |
| 4694 | 131 static void gtk_blist_button_info_cb(GtkWidget *w, GtkTreeView *tv) |
| 132 { | |
| 133 GtkTreeIter iter; | |
| 134 GtkTreeModel *model = gtk_tree_view_get_model(tv); | |
| 135 GtkTreeSelection *sel = gtk_tree_view_get_selection(tv); | |
| 4692 | 136 |
| 4694 | 137 if(gtk_tree_selection_get_selected(sel, &model, &iter)){ |
| 138 GaimBlistNode *node; | |
| 139 | |
| 140 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
| 141 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
| 142 serv_get_info(((struct buddy*)node)->account->gc, ((struct buddy*)node)->name); | |
| 143 return; | |
| 144 } | |
| 145 } | |
| 146 show_info_dialog(); | |
| 147 } | |
| 148 | |
| 149 static void gtk_blist_button_chat_cb(GtkWidget *w, gpointer data) | |
| 150 { | |
| 151 /* FIXME: someday, we can check to see if we've selected a chat node */ | |
| 152 join_chat(); | |
| 153 } | |
| 154 | |
| 155 static void gtk_blist_button_away_cb(GtkWidget *w, gpointer data) | |
| 156 { | |
| 157 gtk_menu_popup(GTK_MENU(awaymenu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); | |
| 4692 | 158 } |
| 159 | |
| 4687 | 160 static void gtk_blist_row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { |
| 161 GaimBlistNode *node; | |
| 162 GtkTreeIter iter; | |
| 163 GValue val = { 0, }; | |
| 3154 | 164 |
| 4687 | 165 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); |
| 166 | |
| 167 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
| 168 node = g_value_get_pointer(&val); | |
| 169 | |
| 170 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
| 171 gaim_conversation_new(GAIM_CONV_IM, ((struct buddy*)node)->account, ((struct buddy*)node)->name); | |
| 4697 | 172 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { |
| 173 if (gtk_tree_view_row_expanded(tv, path)) | |
| 174 gtk_tree_view_collapse_row(tv, path); | |
| 175 else | |
| 176 gtk_tree_view_expand_row(tv,path,FALSE); | |
| 1 | 177 } |
| 178 } | |
| 179 | |
| 4687 | 180 static void gaim_proto_menu_cb(GtkMenuItem *item, struct buddy *b) |
| 1 | 181 { |
| 4687 | 182 struct proto_buddy_menu *pbm = g_object_get_data(G_OBJECT(item), "gaimcallback"); |
| 183 if (pbm->callback) | |
| 184 pbm->callback(pbm->gc, b->name); | |
|
1396
df7c3cacac92
[gaim-migrate @ 1406]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1392
diff
changeset
|
185 } |
| 1 | 186 |
| 4687 | 187 static gboolean gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer null) |
|
1391
d606da211acb
[gaim-migrate @ 1401]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1376
diff
changeset
|
188 { |
| 4687 | 189 GtkTreePath *path; |
| 190 GaimBlistNode *node; | |
| 191 GValue val = { 0, }; | |
| 192 GtkTreeIter iter; | |
| 193 GtkWidget *menu, *menuitem; | |
| 194 GtkWidget *image; | |
| 4702 | 195 GtkTreeSelection *sel; |
| 4687 | 196 GList *list; |
| 197 struct prpl *prpl; | |
|
1391
d606da211acb
[gaim-migrate @ 1401]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1376
diff
changeset
|
198 |
| 4687 | 199 if (event->button != 3) |
| 200 return FALSE; | |
| 4718 | 201 |
| 4687 | 202 /* Here we figure out which node was clicked */ |
| 203 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL)) | |
| 204 return FALSE; | |
| 205 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
| 206 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
| 207 node = g_value_get_pointer(&val); | |
| 4718 | 208 |
| 4721 | 209 if (!GAIM_BLIST_NODE_IS_BUDDY(node)) { |
| 210 gtk_tree_path_free(path); | |
| 4687 | 211 return FALSE; |
| 4721 | 212 } |
| 4718 | 213 |
| 4687 | 214 menu = gtk_menu_new(); |
| 3251 | 215 |
| 4687 | 216 /* Protocol specific options */ |
| 217 prpl = find_prpl(((struct buddy*)node)->account->protocol); | |
| 4732 | 218 |
| 219 if(prpl && prpl->get_info) { | |
| 4813 | 220 menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Get Info")); |
| 4732 | 221 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_blist_menu_info_cb), node); |
| 222 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
| 223 } | |
| 224 | |
| 4813 | 225 menuitem = gtk_image_menu_item_new_with_mnemonic(_("_IM")); |
| 4732 | 226 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_blist_menu_im_cb), node); |
| 227 image = gtk_image_new_from_stock(GAIM_STOCK_IM, GTK_ICON_SIZE_MENU); | |
| 228 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); | |
| 229 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
| 230 | |
| 4813 | 231 menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Alias")); |
| 4732 | 232 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_blist_menu_alias_cb), node); |
| 233 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
| 234 | |
| 4813 | 235 menuitem = gtk_image_menu_item_new_with_mnemonic(_("Add Buddy _Pounce")); |
| 4732 | 236 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_blist_menu_bp_cb), node); |
| 237 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
| 238 | |
| 4813 | 239 menuitem = gtk_image_menu_item_new_with_mnemonic(_("View _Log")); |
| 4732 | 240 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_blist_menu_showlog_cb), node); |
| 241 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
| 242 | |
| 4687 | 243 if (prpl) { |
| 244 list = prpl->buddy_menu(((struct buddy*)node)->account->gc, ((struct buddy*)node)->name); | |
| 245 while (list) { | |
| 246 struct proto_buddy_menu *pbm = list->data; | |
| 247 menuitem = gtk_menu_item_new_with_mnemonic(pbm->label); | |
| 248 g_object_set_data(G_OBJECT(menuitem), "gaimcallback", pbm); | |
| 249 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gaim_proto_menu_cb), node); | |
| 250 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
| 251 list = list->next; | |
| 3313 | 252 } |
| 3251 | 253 } |
| 1 | 254 |
| 4687 | 255 gtk_widget_show_all(menu); |
| 256 | |
| 257 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time); | |
| 1 | 258 |
| 4702 | 259 #if (1) /* This code only exists because GTK doesn't work. If we return FALSE here, as would be normal |
| 260 * the event propoagates down and somehow gets interpreted as the start of a drag event. */ | |
| 261 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); | |
| 262 gtk_tree_selection_select_path(sel, path); | |
| 4721 | 263 gtk_tree_path_free(path); |
| 4702 | 264 return TRUE; |
| 265 #endif | |
| 1 | 266 } |
| 267 | |
| 4687 | 268 /* This is called 10 seconds after the buddy logs in. It removes the "logged in" icon and replaces it with |
| 269 * the normal status icon */ | |
|
1072
81d19577285a
[gaim-migrate @ 1082]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1070
diff
changeset
|
270 |
| 4687 | 271 static gboolean gaim_reset_present_icon(GaimBlistNode *b) |
| 272 { | |
| 273 ((struct buddy*)b)->present = 1; | |
| 274 gaim_gtk_blist_update(NULL, b); | |
| 275 return FALSE; | |
|
577
aa9a8bcddd80
[gaim-migrate @ 587]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
544
diff
changeset
|
276 } |
|
aa9a8bcddd80
[gaim-migrate @ 587]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
544
diff
changeset
|
277 |
| 4687 | 278 static void gaim_gtk_blist_add_buddy_cb() |
|
935
5e6ca3dd4d02
[gaim-migrate @ 945]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
921
diff
changeset
|
279 { |
| 4690 | 280 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)); |
| 4687 | 281 GtkTreeIter iter; |
| 282 GaimBlistNode *node; | |
|
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4349
diff
changeset
|
283 |
| 4692 | 284 if(gtk_tree_selection_get_selected(sel, NULL, &iter)){ |
| 285 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
| 4691 | 286 if (GAIM_BLIST_NODE_IS_BUDDY(node)) |
| 287 show_add_buddy(NULL, NULL, ((struct group*)node->parent)->name, NULL); | |
| 288 else if (GAIM_BLIST_NODE_IS_GROUP(node)) | |
| 289 show_add_buddy(NULL, NULL, ((struct group*)node)->name, NULL); | |
| 290 } | |
| 4697 | 291 else { |
| 4692 | 292 show_add_buddy(NULL, NULL, NULL, NULL); |
| 293 } | |
| 1 | 294 } |
| 295 | |
| 4697 | 296 static void gaim_gtk_blist_update_toolbar_icons (GtkWidget *widget, gpointer data) { |
| 297 if (GTK_IS_IMAGE(widget)) { | |
| 298 if (blist_options & OPT_BLIST_SHOW_BUTTON_XPM) | |
| 299 gtk_widget_show(widget); | |
| 300 else | |
| 301 gtk_widget_hide(widget); | |
| 302 } else if (GTK_IS_CONTAINER(widget)) { | |
| 303 gtk_container_foreach(GTK_CONTAINER(widget), gaim_gtk_blist_update_toolbar_icons, NULL); | |
| 304 } | |
| 305 } | |
| 1 | 306 |
| 4702 | 307 static void gaim_gtk_blist_drag_data_get_cb (GtkWidget *widget, |
| 308 GdkDragContext *dc, | |
| 309 GtkSelectionData *data, | |
| 310 guint info, | |
| 311 guint time, | |
| 312 gpointer *null) | |
| 313 { | |
| 4781 | 314 if (data->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE)) { |
| 4702 | 315 GtkTreeRowReference *ref = g_object_get_data(G_OBJECT(dc), "gtk-tree-view-source-row"); |
| 316 GtkTreePath *sourcerow = gtk_tree_row_reference_get_path(ref); | |
| 317 GtkTreeIter iter; | |
| 318 GaimBlistNode *node = NULL; | |
| 319 GValue val = {0}; | |
| 320 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, sourcerow); | |
| 321 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
| 322 node = g_value_get_pointer(&val); | |
| 4781 | 323 gtk_selection_data_set (data, |
| 324 gdk_atom_intern ("GAIM_BLIST_NODE", FALSE), | |
| 325 8, /* bits */ | |
| 326 (void*)&node, | |
| 327 sizeof (node)); | |
| 328 | |
| 4721 | 329 gtk_tree_path_free(sourcerow); |
| 4702 | 330 } |
| 4781 | 331 |
| 4702 | 332 } |
| 333 | |
| 334 static void gaim_gtk_blist_drag_data_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, | |
| 335 GtkSelectionData *sd, guint info, guint t) | |
| 336 { | |
| 4781 | 337 if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE) && sd->data) { |
| 338 GaimBlistNode *n = NULL; | |
| 4702 | 339 GtkTreePath *path = NULL; |
| 4704 | 340 GtkTreeViewDropPosition position; |
| 4781 | 341 memcpy(&n, sd->data, sizeof(n)); |
| 4704 | 342 if(gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), x, y, &path, &position)) { |
| 343 /* if we're here, I think it means the drop is ok */ | |
| 4770 | 344 GtkTreeIter iter; |
| 345 GaimBlistNode *node; | |
| 346 GValue val = {0}; | |
| 347 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
| 348 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
| 349 node = g_value_get_pointer(&val); | |
| 4781 | 350 |
| 351 if (GAIM_BLIST_NODE_IS_BUDDY(n)) { | |
| 352 struct buddy *b = (struct buddy*)n; | |
| 353 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
| 4795 | 354 switch(position) { |
| 355 case GTK_TREE_VIEW_DROP_AFTER: | |
| 356 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
| 357 gaim_blist_add_buddy(b, (struct group*)node->parent, node); | |
| 358 break; | |
| 359 case GTK_TREE_VIEW_DROP_BEFORE: | |
| 360 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
| 361 gaim_blist_add_buddy(b, (struct group*)node->parent, node->prev); | |
| 362 break; | |
| 4781 | 363 } |
| 364 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
| 365 gaim_blist_add_buddy(b, (struct group*)node, NULL); | |
| 4795 | 366 } |
| 4781 | 367 } else if (GAIM_BLIST_NODE_IS_GROUP(n)) { |
| 368 struct group *g = (struct group*)n; | |
| 369 if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
| 370 switch (position) { | |
| 371 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
| 372 case GTK_TREE_VIEW_DROP_AFTER: | |
| 373 gaim_blist_add_group(g, node); | |
| 374 break; | |
| 375 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
| 376 case GTK_TREE_VIEW_DROP_BEFORE: | |
| 377 gaim_blist_add_group(g, node->prev); | |
| 378 break; | |
| 379 } | |
| 380 | |
| 4770 | 381 } |
| 4781 | 382 |
| 4777 | 383 } |
| 4781 | 384 |
| 4721 | 385 gtk_tree_path_free(path); |
| 4704 | 386 } |
| 4702 | 387 } |
| 388 } | |
| 389 | |
| 4724 | 390 static void gaim_gtk_blist_paint_tip(GtkWidget *widget, GdkEventExpose *event, struct buddy *b) |
| 391 { | |
| 392 GtkStyle *style; | |
| 393 GdkPixbuf *pixbuf = gaim_gtk_blist_get_status_icon(b, GAIM_STATUS_ICON_LARGE); | |
| 394 PangoLayout *layout; | |
| 395 char *tooltiptext = gaim_get_tooltip_text(b); | |
| 396 | |
| 397 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL); | |
| 398 pango_layout_set_markup(layout, tooltiptext, strlen(tooltiptext)); | |
| 4732 | 399 pango_layout_set_wrap(layout, PANGO_WRAP_WORD); |
| 4733 | 400 pango_layout_set_width(layout, 300000); |
| 4724 | 401 style = gtkblist->tipwindow->style; |
| 4732 | 402 |
| 4724 | 403 gtk_paint_flat_box (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, |
| 404 NULL, gtkblist->tipwindow, "tooltip", 0, 0, -1, -1); | |
| 4729 | 405 |
| 406 #if GTK_CHECK_VERSION(2,2,0) | |
| 4724 | 407 gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, pixbuf, |
| 408 0, 0, 4, 4, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0); | |
| 4729 | 409 #else |
| 4758 | 410 gdk_pixbuf_render_to_drawable(pixbuf, GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, 0, 0, 4, 4, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); |
| 4729 | 411 #endif |
| 4724 | 412 |
| 413 gtk_paint_layout (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, TRUE, | |
| 414 NULL, gtkblist->tipwindow, "tooltip", 38, 4, layout); | |
| 415 | |
| 416 g_object_unref (pixbuf); | |
| 417 g_object_unref (layout); | |
| 418 g_free(tooltiptext); | |
| 419 return; | |
| 420 } | |
| 421 | |
| 422 static gboolean gaim_gtk_blist_tooltip_timeout(GtkWidget *tv) | |
| 423 { | |
| 424 GtkTreePath *path; | |
| 425 GtkTreeIter iter; | |
| 426 GaimBlistNode *node; | |
| 427 GValue val = {0}; | |
| 428 | |
| 429 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->rect.x, gtkblist->rect.y, &path, NULL, NULL, NULL)) | |
| 430 return FALSE; | |
| 431 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
| 432 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
| 433 node = g_value_get_pointer(&val); | |
| 434 | |
| 435 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
| 436 int scr_w,scr_h, w, h, x, y; | |
| 437 PangoLayout *layout; | |
| 438 struct buddy *buddy = (struct buddy*)node; | |
| 439 char *tooltiptext = gaim_get_tooltip_text(buddy); | |
| 440 gtkblist->tipwindow = gtk_window_new(GTK_WINDOW_POPUP); | |
| 441 gtk_widget_set_app_paintable(gtkblist->tipwindow, TRUE); | |
| 4729 | 442 gtk_window_set_resizable(GTK_WINDOW(gtkblist->tipwindow), FALSE); |
| 4724 | 443 gtk_widget_set_name(gtkblist->tipwindow, "gtk-tooltips"); |
| 444 g_signal_connect(G_OBJECT(gtkblist->tipwindow), "expose_event", | |
| 445 G_CALLBACK(gaim_gtk_blist_paint_tip), buddy); | |
| 446 gtk_widget_ensure_style (gtkblist->tipwindow); | |
| 447 | |
| 448 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL); | |
| 4733 | 449 pango_layout_set_wrap(layout, PANGO_WRAP_WORD); |
| 450 pango_layout_set_width(layout, 300000); | |
| 4724 | 451 pango_layout_set_markup(layout, tooltiptext, strlen(tooltiptext)); |
| 452 scr_w = gdk_screen_width(); | |
| 453 scr_h = gdk_screen_height(); | |
| 454 pango_layout_get_size (layout, &w, &h); | |
| 455 w = PANGO_PIXELS(w) + 8; | |
| 456 h = PANGO_PIXELS(h) + 8; | |
| 457 | |
| 458 /* 38 is the size of a large status icon plus 4 pixels padding on each side. | |
| 459 I should #define this or something */ | |
| 460 w = w + 38; | |
| 461 h = MAX(h, 38); | |
| 462 | |
| 463 gdk_window_get_pointer(NULL, &x, &y, NULL); | |
| 464 if (GTK_WIDGET_NO_WINDOW(gtkblist->window)) | |
| 465 y+=gtkblist->window->allocation.y; | |
| 466 | |
| 467 x -= ((w >> 1) + 4); | |
| 468 | |
| 469 if ((x + w) > scr_w) | |
| 470 x -= (x + w) - scr_w; | |
| 471 else if (x < 0) | |
| 472 x = 0; | |
| 473 | |
| 474 if ((y + h + 4) > scr_h) | |
| 475 y = y - h; | |
| 476 else | |
| 477 y = y + 6; | |
| 478 g_object_unref (layout); | |
| 479 g_free(tooltiptext); | |
| 480 gtk_widget_set_size_request(gtkblist->tipwindow, w, h); | |
| 4729 | 481 gtk_window_move(GTK_WINDOW(gtkblist->tipwindow), x, y); |
| 4724 | 482 gtk_widget_show(gtkblist->tipwindow); |
| 483 } | |
| 4729 | 484 |
| 4724 | 485 gtk_tree_path_free(path); |
| 486 return FALSE; | |
| 487 } | |
| 488 | |
| 4730 | 489 static gboolean gaim_gtk_blist_motion_cb (GtkWidget *tv, GdkEventMotion *event, gpointer null) |
| 4724 | 490 { |
| 491 GtkTreePath *path; | |
| 492 | |
| 493 if (gtkblist->timeout) { | |
| 494 if ((event->y > gtkblist->rect.y) && ((event->y - gtkblist->rect.height) < gtkblist->rect.y)) | |
| 4732 | 495 return FALSE; |
| 4724 | 496 /* We've left the cell. Remove the timeout and create a new one below */ |
| 497 if (gtkblist->tipwindow) { | |
| 498 gtk_widget_destroy(gtkblist->tipwindow); | |
| 499 gtkblist->tipwindow = NULL; | |
| 500 } | |
| 501 | |
| 502 g_source_remove(gtkblist->timeout); | |
| 503 } | |
| 504 | |
| 505 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL); | |
| 506 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, >kblist->rect); | |
| 507 if (path) | |
| 508 gtk_tree_path_free(path); | |
| 509 gtkblist->timeout = g_timeout_add(500, (GSourceFunc)gaim_gtk_blist_tooltip_timeout, tv); | |
| 4730 | 510 return FALSE; |
| 4724 | 511 } |
| 512 | |
| 513 static void gaim_gtk_blist_leave_cb (GtkWidget *w, GdkEventCrossing *e, gpointer n) | |
| 514 { | |
| 515 if (gtkblist->timeout == 0) | |
| 516 return; | |
| 517 if (gtkblist->tipwindow) { | |
| 518 gtk_widget_destroy(gtkblist->tipwindow); | |
| 519 gtkblist->tipwindow = NULL; | |
| 520 } | |
| 521 g_source_remove(gtkblist->timeout); | |
| 522 gtkblist->timeout = 0; | |
| 523 } | |
| 524 | |
| 4687 | 525 /*************************************************** |
| 526 * Crap * | |
| 527 ***************************************************/ | |
| 528 static GtkItemFactoryEntry blist_menu[] = | |
|
1929
d51ea669d84e
[gaim-migrate @ 1939]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1918
diff
changeset
|
529 { |
| 4687 | 530 /* Buddies menu */ |
| 531 { N_("/_Buddies"), NULL, NULL, 0, "<Branch>" }, | |
| 532 { N_("/Buddies/_Add A Buddy..."), "<CTL>B", gaim_gtk_blist_add_buddy_cb, 0, | |
| 533 "<StockItem>", GTK_STOCK_ADD }, | |
| 534 { N_("/Buddies/New _Instant Message..."), "<CTL>I", show_im_dialog, 0, | |
| 535 "<StockItem>", GAIM_STOCK_IM }, | |
| 536 { N_("/Buddies/Join a _Chat..."), "<CTL>C", join_chat, 0, | |
| 537 "<StockItem>", GAIM_STOCK_CHAT }, | |
| 4834 | 538 { "/Buddies/sep1", NULL, NULL, 0, "<Separator>" }, |
| 4687 | 539 { N_("/Buddies/Get _User Info..."), "<CTL>J", show_info_dialog, 0, |
| 540 "<StockItem>", GAIM_STOCK_INFO }, | |
| 4834 | 541 { "/Buddies/sep2", NULL, NULL, 0, "<Separator>" }, |
| 4687 | 542 { N_("/Buddies/_Signoff"), "<CTL>D", signoff_all, 0, NULL }, |
| 543 { N_("/Buddies/_Quit"), "<CTL>Q", do_quit, 0, | |
| 544 "<StockItem>", GTK_STOCK_QUIT }, | |
|
1929
d51ea669d84e
[gaim-migrate @ 1939]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1918
diff
changeset
|
545 |
| 4687 | 546 /* Tools */ |
| 547 { N_("/_Tools"), NULL, NULL, 0, "<Branch>" }, | |
| 548 { N_("/Tools/_Away"), NULL, NULL, 0, "<Branch>" }, | |
| 549 { N_("/Tools/Buddy _Pounce"), NULL, NULL, 0, "<Branch>" }, | |
| 4834 | 550 { "/Tools/sep1", NULL, NULL, 0, "<Separator>" }, |
| 4687 | 551 { N_("/Tools/A_ccounts"), "<CTL>A", account_editor, 0, NULL }, |
| 4694 | 552 { N_("/Tools/Preferences"), "<CTL>P", show_prefs, 0, |
| 4687 | 553 "<StockItem>", GTK_STOCK_PREFERENCES }, |
| 4698 | 554 { N_("/Tools/_File Transfers"), NULL, gaim_show_xfer_dialog, 0, |
| 4687 | 555 "<StockItem>", GTK_STOCK_REVERT_TO_SAVED }, |
| 4834 | 556 { "/Tools/sep2", NULL, NULL, 0, "<Separator>" }, |
| 4687 | 557 { N_("/Tools/P_rotocol Actions"), NULL, NULL, 0, "<Branch>" }, |
| 558 { N_("/Tools/Pr_ivacy"), NULL, show_privacy_options, 0, NULL }, | |
| 4697 | 559 { N_("/Tools/View System _Log"), NULL, gtk_blist_show_systemlog_cb, 0, NULL }, |
| 3251 | 560 |
| 4687 | 561 /* Help */ |
| 562 { N_("/_Help"), NULL, NULL, 0, "<Branch>" }, | |
| 4776 | 563 { N_("/Help/Online _Help"), "F1", gtk_blist_show_onlinehelp_cb, 0, |
| 4687 | 564 "<StockItem>", GTK_STOCK_HELP }, |
| 4755 | 565 { N_("/Help/_Debug Window"), NULL, toggle_debug, 0, NULL }, |
| 4687 | 566 { N_("/Help/_About"), NULL, show_about, 0, NULL }, |
| 567 | |
| 568 }; | |
|
1929
d51ea669d84e
[gaim-migrate @ 1939]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1918
diff
changeset
|
569 |
| 4687 | 570 /********************************************************* |
| 571 * Private Utility functions * | |
| 572 *********************************************************/ | |
| 573 | |
| 4724 | 574 static char *gaim_get_tooltip_text(struct buddy *b) |
| 575 { | |
| 576 char *text = NULL; | |
| 577 struct prpl* prpl = find_prpl(b->account->protocol); | |
| 578 char *statustext = NULL; | |
| 579 char *warning = NULL, *idletime = NULL; | |
| 580 | |
| 581 if (prpl->tooltip_text) { | |
| 4815 | 582 const char *end; |
| 4732 | 583 statustext = prpl->tooltip_text(b); |
| 4815 | 584 |
| 585 if(statustext && !g_utf8_validate(statustext, -1, &end)) { | |
| 586 char *new = g_strndup(statustext, | |
| 587 g_utf8_pointer_to_offset(statustext, end)); | |
| 588 g_free(statustext); | |
| 589 statustext = new; | |
| 590 } | |
| 4724 | 591 } |
| 4732 | 592 |
| 4724 | 593 if (b->idle) { |
| 594 int ihrs, imin; | |
| 595 time_t t; | |
| 596 time(&t); | |
| 597 ihrs = (t - b->idle) / 3600; | |
| 598 imin = ((t - b->idle) / 60) % 60; | |
| 599 if (ihrs) | |
| 4744 | 600 idletime = g_strdup_printf(_("%dh%02dm"), ihrs, imin); |
| 4724 | 601 else |
| 4744 | 602 idletime = g_strdup_printf(_("%dm"), imin); |
| 4724 | 603 } |
| 4732 | 604 |
| 4724 | 605 if (b->evil > 0) |
| 4744 | 606 warning = g_strdup_printf(_("%d%%"), b->evil); |
| 4732 | 607 |
| 4724 | 608 text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>" |
| 4744 | 609 "%s %s" /* Alias */ |
| 610 "%s %s" /* Nickname */ | |
| 611 "%s %s" /* Idle */ | |
| 612 "%s %s" /* Warning */ | |
| 4741 | 613 "%s%s", /* Status */ |
| 4724 | 614 b->name, |
| 4744 | 615 b->alias && b->alias[0] ? _("\n<b>Alias:</b>") : "", b->alias ? b->alias : "", |
| 616 b->server_alias ? _("\n<b>Nickname:</b>") : "", b->server_alias ? b->server_alias : "", | |
| 617 b->idle ? _("\n<b>Idle:</b>") : "", b->idle ? idletime : "", | |
| 618 b->evil ? _("\n<b>Warned:</b>") : "", b->evil ? warning : "", | |
| 4724 | 619 statustext ? "\n" : "", statustext ? statustext : ""); |
| 4737 | 620 if(warning) |
| 621 g_free(warning); | |
| 622 if(idletime) | |
| 623 g_free(idletime); | |
| 624 if(statustext) | |
| 625 g_free(statustext); | |
| 626 | |
| 4724 | 627 return text; |
| 628 | |
| 629 } | |
| 630 | |
| 631 static GdkPixbuf *gaim_gtk_blist_get_status_icon(struct buddy *b, GaimStatusIconSize size) | |
| 4687 | 632 { |
| 633 GdkPixbuf *status = NULL; | |
| 634 GdkPixbuf *scale = NULL; | |
| 635 GdkPixbuf *emblem = NULL; | |
| 4737 | 636 gchar *filename = NULL; |
| 4687 | 637 const char *protoname = NULL; |
|
1929
d51ea669d84e
[gaim-migrate @ 1939]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1918
diff
changeset
|
638 |
| 4691 | 639 char *se = NULL, *sw = NULL ,*nw = NULL ,*ne = NULL; |
| 4737 | 640 |
| 4687 | 641 int scalesize = 30; |
| 642 | |
| 643 struct prpl* prpl = find_prpl(b->account->protocol); | |
| 644 if (prpl->list_icon) | |
| 645 protoname = prpl->list_icon(b->account, b); | |
| 646 if (prpl->list_emblems) | |
| 647 prpl->list_emblems(b, &se, &sw, &nw, &ne); | |
| 4737 | 648 |
| 4724 | 649 if (size == GAIM_STATUS_ICON_SMALL) { |
| 4687 | 650 scalesize = 15; |
| 651 sw = nw = ne = NULL; /* So that only the se icon will composite */ | |
|
1929
d51ea669d84e
[gaim-migrate @ 1939]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1918
diff
changeset
|
652 } |
|
d51ea669d84e
[gaim-migrate @ 1939]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1918
diff
changeset
|
653 |
| 4701 | 654 |
| 4687 | 655 if (b->present == 2) { |
| 4701 | 656 struct gaim_gtk_blist_node *gtknode; |
| 4687 | 657 /* If b->present is 2, that means this buddy has just signed on. We use the "login" icon for the |
| 658 * status, and we set a timeout to change it to a normal icon after 10 seconds. */ | |
| 659 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "login.png", NULL); | |
| 660 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 661 g_free(filename); | |
| 4701 | 662 |
| 663 gtknode = GAIM_GTK_BLIST_NODE((GaimBlistNode*)b); | |
| 4773 | 664 if (gtknode->timer > 0) |
| 665 g_source_remove(gtknode->timer); | |
| 4701 | 666 gtknode->timer = g_timeout_add(10000, (GSourceFunc)gaim_reset_present_icon, b); |
| 667 | |
| 4737 | 668 /* "Hey, what's all this crap?" you ask. Status icons will be themeable too, and |
| 4687 | 669 then it will look up protoname from the theme */ |
| 670 } else { | |
| 671 char *image = g_strdup_printf("%s.png", protoname); | |
| 672 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); | |
| 673 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 674 g_free(image); | |
| 675 g_free(filename); | |
|
1929
d51ea669d84e
[gaim-migrate @ 1939]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1918
diff
changeset
|
676 |
| 4687 | 677 } |
| 4737 | 678 |
| 4687 | 679 if (!status) |
| 680 return NULL; | |
| 4737 | 681 |
| 4687 | 682 scale = gdk_pixbuf_scale_simple(status, scalesize, scalesize, GDK_INTERP_BILINEAR); |
| 4737 | 683 |
| 684 g_object_unref(G_OBJECT(status)); | |
| 685 | |
| 4687 | 686 /* Emblems */ |
| 4737 | 687 |
| 4687 | 688 /* Each protocol can specify up to four "emblems" to composite over the base icon. "away", "busy", "mobile user" |
| 689 * are all examples of states represented by emblems. I'm not even really sure I like this yet. */ | |
| 4737 | 690 |
| 4687 | 691 /* XXX Clean this crap up, yo. */ |
| 692 if (se) { | |
| 693 char *image = g_strdup_printf("%s.png", se); | |
| 694 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); | |
| 695 g_free(image); | |
| 696 emblem = gdk_pixbuf_new_from_file(filename,NULL); | |
| 697 g_free(filename); | |
| 698 if (emblem) { | |
| 4724 | 699 if (size == GAIM_STATUS_ICON_LARGE) |
| 4687 | 700 gdk_pixbuf_composite (emblem, |
| 701 scale, 15, 15, | |
| 702 15, 15, | |
| 703 15, 15, | |
| 704 1, 1, | |
| 705 GDK_INTERP_BILINEAR, | |
| 706 255); | |
| 707 else | |
| 708 gdk_pixbuf_composite (emblem, | |
| 709 scale, 0, 0, | |
| 710 15, 15, | |
| 711 0, 0, | |
| 712 1, 1, | |
| 713 GDK_INTERP_BILINEAR, | |
| 714 255); | |
| 4737 | 715 g_object_unref(G_OBJECT(emblem)); |
| 4687 | 716 } |
| 717 } | |
| 718 if (sw) { | |
| 719 char *image = g_strdup_printf("%s.png", sw); | |
| 720 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); | |
| 721 g_free(image); | |
| 722 emblem = gdk_pixbuf_new_from_file(filename,NULL); | |
| 723 g_free(filename); | |
| 724 if (emblem) { | |
| 4737 | 725 gdk_pixbuf_composite (emblem, |
| 726 scale, 0, 15, | |
| 727 15, 15, | |
| 728 0, 15, | |
| 729 1, 1, | |
| 730 GDK_INTERP_BILINEAR, | |
| 731 255); | |
| 732 g_object_unref(G_OBJECT(emblem)); | |
| 4687 | 733 } |
| 734 } | |
| 735 if (nw) { | |
| 736 char *image = g_strdup_printf("%s.png", nw); | |
| 737 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); | |
| 738 g_free(image); | |
| 739 emblem = gdk_pixbuf_new_from_file(filename,NULL); | |
| 740 g_free(filename); | |
| 741 if (emblem) { | |
| 742 gdk_pixbuf_composite (emblem, | |
| 743 scale, 0, 0, | |
| 744 15, 15, | |
| 745 0, 0, | |
| 746 1, 1, | |
| 747 GDK_INTERP_BILINEAR, | |
| 748 255); | |
| 4737 | 749 g_object_unref(G_OBJECT(emblem)); |
| 4687 | 750 } |
| 751 } | |
| 752 if (ne) { | |
| 753 char *image = g_strdup_printf("%s.png", ne); | |
| 754 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); | |
| 755 g_free(image); | |
| 756 emblem = gdk_pixbuf_new_from_file(filename,NULL); | |
| 757 g_free(filename); | |
| 758 if (emblem) { | |
| 759 gdk_pixbuf_composite (emblem, | |
| 760 scale, 15, 0, | |
| 761 15, 15, | |
| 762 15, 0, | |
| 763 1, 1, | |
| 764 GDK_INTERP_BILINEAR, | |
| 765 255); | |
| 766 } | |
| 4737 | 767 } |
| 4687 | 768 |
| 4737 | 769 |
| 4718 | 770 /* Idle grey buddies affects the whole row. This converts the status icon to greyscale. */ |
| 4699 | 771 if (b->idle && blist_options & OPT_BLIST_GREY_IDLERS) |
| 4687 | 772 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0, FALSE); |
| 773 return scale; | |
| 1 | 774 } |
| 775 | |
| 4737 | 776 static GdkPixbuf *gaim_gtk_blist_get_buddy_icon(struct buddy *b) |
| 1 | 777 { |
| 4687 | 778 /* This just opens a file from ~/.gaim/icons/screenname. This needs to change to be more gooder. */ |
| 4737 | 779 char *file; |
| 780 GdkPixbuf *buf, *ret; | |
| 781 | |
| 4687 | 782 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) |
| 783 return NULL; | |
| 4737 | 784 |
| 4757 | 785 if ((file = gaim_buddy_get_setting(b, "buddy_icon")) == NULL) |
| 786 return NULL; | |
| 787 | |
| 4737 | 788 buf = gdk_pixbuf_new_from_file(file, NULL); |
| 789 g_free(file); | |
| 790 | |
| 791 | |
| 4687 | 792 if (buf) { |
| 4699 | 793 if (b->idle && blist_options & OPT_BLIST_GREY_IDLERS) { |
| 4687 | 794 gdk_pixbuf_saturate_and_pixelate(buf, buf, 0, FALSE); |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
795 } |
| 4737 | 796 ret = gdk_pixbuf_scale_simple(buf,30,30, GDK_INTERP_BILINEAR); |
| 797 g_object_unref(G_OBJECT(buf)); | |
| 798 return ret; | |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
799 } |
| 4687 | 800 return NULL; |
| 2986 | 801 } |
| 802 | |
| 4810 | 803 static gchar *gaim_gtk_blist_get_name_markup(struct buddy *b, gboolean selected) |
| 1 | 804 { |
| 4687 | 805 char *name = gaim_get_buddy_alias(b); |
| 806 char *esc = g_markup_escape_text(name, strlen(name)), *text = NULL; | |
| 4722 | 807 struct prpl* prpl = find_prpl(b->account->protocol); |
| 808 | |
| 4687 | 809 /* XXX Clean up this crap */ |
| 4699 | 810 |
| 4687 | 811 int ihrs, imin; |
| 4724 | 812 char *idletime = NULL, *warning = NULL, *statustext = NULL; |
| 4732 | 813 time_t t; |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
814 |
| 4687 | 815 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) { |
| 4810 | 816 if (b->idle > 0 && blist_options & OPT_BLIST_GREY_IDLERS && !selected) { |
| 4718 | 817 text = g_strdup_printf("<span color='dim grey'>%s</span>", |
| 4699 | 818 esc); |
| 4687 | 819 g_free(esc); |
| 820 return text; | |
| 821 } else { | |
| 822 return esc; | |
| 823 } | |
| 1 | 824 } |
| 825 | |
| 4687 | 826 time(&t); |
| 827 ihrs = (t - b->idle) / 3600; | |
| 828 imin = ((t - b->idle) / 60) % 60; | |
| 4699 | 829 |
| 4722 | 830 if (prpl->status_text) { |
| 4732 | 831 char *tmp = prpl->status_text(b); |
| 4815 | 832 const char *end; |
| 833 | |
| 834 if(tmp && !g_utf8_validate(tmp, -1, &end)) { | |
| 835 char *new = g_strndup(tmp, | |
| 836 g_utf8_pointer_to_offset(tmp, end)); | |
| 837 g_free(tmp); | |
| 838 tmp = new; | |
| 839 } | |
| 4732 | 840 |
| 841 if(tmp) { | |
| 4806 | 842 g_strdelimit(tmp, "\n", ' '); |
| 4732 | 843 if(strlen(tmp) > 20) |
| 4757 | 844 statustext = g_strdup_printf("%.20s... ", tmp); |
| 4732 | 845 else |
| 4757 | 846 statustext = g_strdup_printf("%s ", tmp); |
| 4732 | 847 g_free(tmp); |
| 848 } | |
| 4722 | 849 } |
| 4732 | 850 |
| 4687 | 851 if (b->idle) { |
| 852 if (ihrs) | |
| 4757 | 853 idletime = g_strdup_printf(_("Idle (%dh%02dm) "), ihrs, imin); |
| 4687 | 854 else |
| 4757 | 855 idletime = g_strdup_printf(_("Idle (%dm) "), imin); |
| 4687 | 856 } |
| 4757 | 857 |
| 4687 | 858 if (b->evil > 0) |
| 4757 | 859 warning = g_strdup_printf(_("Warned (%d%%) "), b->evil); |
| 860 | |
| 4810 | 861 if (b->idle && blist_options & OPT_BLIST_GREY_IDLERS && !selected) { |
| 4757 | 862 text = g_strdup_printf("<span color='dim grey'>%s</span>\n<span color='dim grey' size='smaller'>%s%s%s</span>", |
| 4687 | 863 esc, |
| 4722 | 864 statustext != NULL ? statustext : "", |
| 865 idletime != NULL ? idletime : "", | |
| 866 warning != NULL ? warning : ""); | |
| 4797 | 867 } else if (statustext == NULL && idletime == NULL && warning == NULL) { |
| 868 text = g_strdup_printf("%s", esc); | |
| 869 } else { | |
| 4810 | 870 text = g_strdup_printf("%s\n<span %s size='smaller'>%s%s%s</span>", esc, |
| 871 selected ? "" : "color='dim grey'", | |
| 872 statustext != NULL ? statustext : "", | |
| 873 idletime != NULL ? idletime : "", | |
| 874 warning != NULL ? warning : ""); | |
| 4797 | 875 } |
| 4722 | 876 if (idletime) |
| 4687 | 877 g_free(idletime); |
| 4722 | 878 if (warning) |
| 4687 | 879 g_free(warning); |
| 4722 | 880 if (statustext) |
| 881 g_free(statustext); | |
| 4737 | 882 if (esc) |
| 883 g_free(esc); | |
| 4699 | 884 |
| 4687 | 885 return text; |
| 886 } | |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
887 |
| 4687 | 888 /********************************************************************************** |
| 889 * Public API Functions * | |
| 890 **********************************************************************************/ | |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
891 static void gaim_gtk_blist_new_list(struct gaim_buddy_list *blist) |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
892 { |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
893 blist->ui_data = g_new0(struct gaim_gtk_buddy_list, 1); |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
894 } |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
895 |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
896 static void gaim_gtk_blist_new_node(GaimBlistNode *node) |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
897 { |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
898 node->ui_data = g_new0(struct gaim_gtk_blist_node, 1); |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
899 } |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
900 |
| 4729 | 901 void gaim_gtk_blist_update_columns() |
| 902 { | |
| 903 if (blist_options & OPT_BLIST_SHOW_ICONS) { | |
| 904 gtk_tree_view_column_set_visible(gtkblist->buddy_icon_column, TRUE); | |
| 905 gtk_tree_view_column_set_visible(gtkblist->idle_column, FALSE); | |
| 906 gtk_tree_view_column_set_visible(gtkblist->warning_column, FALSE); | |
| 907 } else { | |
| 908 gtk_tree_view_column_set_visible(gtkblist->idle_column, blist_options & OPT_BLIST_SHOW_IDLETIME); | |
| 909 gtk_tree_view_column_set_visible(gtkblist->warning_column, blist_options & OPT_BLIST_SHOW_WARN); | |
| 910 gtk_tree_view_column_set_visible(gtkblist->buddy_icon_column, FALSE); | |
| 911 } | |
| 912 } | |
| 913 | |
| 4702 | 914 enum {DRAG_BUDDY, DRAG_ROW}; |
| 915 | |
| 4834 | 916 static char * |
| 917 item_factory_translate_func (const char *path, gpointer func_data) | |
| 918 { | |
| 919 return _(path); | |
| 920 } | |
| 921 | |
| 4687 | 922 static void gaim_gtk_blist_show(struct gaim_buddy_list *list) |
| 923 { | |
| 924 GtkItemFactory *ift; | |
| 925 GtkCellRenderer *rend; | |
| 926 GtkTreeViewColumn *column; | |
| 927 GtkWidget *sw; | |
| 928 GtkWidget *button; | |
| 4694 | 929 GtkSizeGroup *sg; |
| 4810 | 930 GtkTreeSelection *selection; |
| 4781 | 931 GtkTargetEntry gte[] = {{"GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW}, |
| 4702 | 932 {"application/x-im-contact", 0, DRAG_BUDDY}}; |
| 4690 | 933 |
| 4745 | 934 if (gtkblist && gtkblist->window) { |
| 4687 | 935 gtk_widget_show(gtkblist->window); |
| 936 return; | |
| 937 } | |
| 4690 | 938 |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
939 gtkblist = GAIM_GTK_BLIST(list); |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
940 |
| 4687 | 941 gtkblist->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| 942 gtk_window_set_title(GTK_WINDOW(gtkblist->window), _("Buddy List")); | |
| 4690 | 943 |
| 4687 | 944 gtkblist->vbox = gtk_vbox_new(FALSE, 6); |
| 945 gtk_container_add(GTK_CONTAINER(gtkblist->window), gtkblist->vbox); | |
| 1 | 946 |
| 4698 | 947 g_signal_connect(G_OBJECT(gtkblist->window), "delete_event", G_CALLBACK(gaim_gtk_blist_destroy_cb), NULL); |
| 948 | |
| 4687 | 949 /******************************* Menu bar *************************************/ |
| 950 ift = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<GaimMain>", NULL); | |
| 4834 | 951 gtk_item_factory_set_translate_func (ift, |
| 952 item_factory_translate_func, | |
| 953 NULL, NULL); | |
| 4687 | 954 gtk_item_factory_create_items(ift, sizeof(blist_menu) / sizeof(*blist_menu), |
| 955 blist_menu, NULL); | |
| 956 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtk_item_factory_get_widget(ift, "<GaimMain>"), FALSE, FALSE, 0); | |
| 1 | 957 |
| 4834 | 958 awaymenu = gtk_item_factory_get_widget(ift, N_("/Tools/Away")); |
| 4694 | 959 do_away_menu(); |
| 960 | |
| 4834 | 961 bpmenu = gtk_item_factory_get_widget(ift, N_("/Tools/Buddy Pounce")); |
| 4696 | 962 do_bp_menu(); |
| 963 | |
| 4834 | 964 protomenu = gtk_item_factory_get_widget(ift, N_("/Tools/Protocol Actions")); |
| 4696 | 965 do_proto_menu(); |
| 966 | |
| 4687 | 967 /****************************** GtkTreeView **********************************/ |
| 968 sw = gtk_scrolled_window_new(NULL,NULL); | |
| 969 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); | |
| 970 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
| 971 | |
| 4729 | 972 gtkblist->treemodel = gtk_tree_store_new(BLIST_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, |
| 4687 | 973 G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER); |
| 4702 | 974 |
| 4687 | 975 gtkblist->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtkblist->treemodel)); |
| 4704 | 976 |
| 4810 | 977 /* Set up selection stuff */ |
| 978 | |
| 979 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)); | |
| 980 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(gaim_gtk_blist_selection_changed), NULL); | |
| 981 | |
| 982 | |
| 4702 | 983 /* Set up dnd */ |
| 984 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(gtkblist->treeview), GDK_BUTTON1_MASK, gte, | |
| 985 2, GDK_ACTION_COPY); | |
| 4704 | 986 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(gtkblist->treeview), gte, 2, |
| 4702 | 987 GDK_ACTION_COPY | GDK_ACTION_MOVE); |
| 4704 | 988 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-received", G_CALLBACK(gaim_gtk_blist_drag_data_rcv_cb), NULL); |
| 989 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-get", G_CALLBACK(gaim_gtk_blist_drag_data_get_cb), NULL); | |
| 990 | |
| 4724 | 991 /* Tooltips */ |
| 992 g_signal_connect(G_OBJECT(gtkblist->treeview), "motion-notify-event", G_CALLBACK(gaim_gtk_blist_motion_cb), NULL); | |
| 993 g_signal_connect(G_OBJECT(gtkblist->treeview), "leave-notify-event", G_CALLBACK(gaim_gtk_blist_leave_cb), NULL); | |
| 4687 | 994 |
| 995 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE); | |
| 1 | 996 |
| 4687 | 997 rend = gtk_cell_renderer_pixbuf_new(); |
| 998 column = gtk_tree_view_column_new_with_attributes("Status", rend, "pixbuf", STATUS_ICON_COLUMN, NULL); | |
| 999 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
| 4796 | 1000 g_object_set(rend, "ypad", 0, NULL); |
| 4706 | 1001 |
| 4687 | 1002 rend = gtk_cell_renderer_text_new(); |
| 1003 column = gtk_tree_view_column_new_with_attributes("Name", rend, "markup", NAME_COLUMN, NULL); | |
| 1004 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
| 4797 | 1005 g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL); |
| 4706 | 1006 |
| 4687 | 1007 rend = gtk_cell_renderer_text_new(); |
| 4725 | 1008 gtkblist->warning_column = gtk_tree_view_column_new_with_attributes("Warning", rend, "markup", WARNING_COLUMN, NULL); |
| 1009 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->warning_column); | |
| 4796 | 1010 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL); |
| 4687 | 1011 |
| 1012 rend = gtk_cell_renderer_text_new(); | |
| 4725 | 1013 gtkblist->idle_column = gtk_tree_view_column_new_with_attributes("Idle", rend, "markup", IDLE_COLUMN, NULL); |
| 1014 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->idle_column); | |
| 4796 | 1015 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL); |
| 1 | 1016 |
| 4687 | 1017 rend = gtk_cell_renderer_pixbuf_new(); |
| 4725 | 1018 gtkblist->buddy_icon_column = gtk_tree_view_column_new_with_attributes("Buddy Icon", rend, "pixbuf", BUDDY_ICON_COLUMN, NULL); |
| 4796 | 1019 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL); |
| 4725 | 1020 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->buddy_icon_column); |
| 4718 | 1021 |
| 4687 | 1022 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL); |
| 1023 g_signal_connect(G_OBJECT(gtkblist->treeview), "button-press-event", G_CALLBACK(gtk_blist_button_press_cb), NULL); | |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
1024 |
| 4687 | 1025 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sw, TRUE, TRUE, 0); |
| 1026 gtk_container_add(GTK_CONTAINER(sw), gtkblist->treeview); | |
| 4725 | 1027 gaim_gtk_blist_update_columns(); |
| 4687 | 1028 /**************************** Button Box **************************************/ |
| 4694 | 1029 |
| 1030 sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH); | |
| 4687 | 1031 gtkblist->bbox = gtk_hbox_new(TRUE, 0); |
| 1032 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->bbox, FALSE, FALSE, 0); | |
| 1033 button = gaim_pixbuf_button_from_stock(_("IM"), GAIM_STOCK_IM, GAIM_BUTTON_VERTICAL); | |
| 1034 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
| 1035 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
| 4694 | 1036 gtk_size_group_add_widget(sg, button); |
| 4692 | 1037 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_im_cb), |
| 4697 | 1038 gtkblist->treeview); |
| 1039 | |
| 4687 | 1040 button = gaim_pixbuf_button_from_stock(_("Get Info"), GAIM_STOCK_INFO, GAIM_BUTTON_VERTICAL); |
| 1041 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
| 1042 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
| 4694 | 1043 gtk_size_group_add_widget(sg, button); |
| 1044 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_info_cb), | |
| 4697 | 1045 gtkblist->treeview); |
| 4729 | 1046 |
| 4687 | 1047 button = gaim_pixbuf_button_from_stock(_("Chat"), GAIM_STOCK_CHAT, GAIM_BUTTON_VERTICAL); |
| 1048 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
| 1049 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
| 4694 | 1050 gtk_size_group_add_widget(sg, button); |
| 1051 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_chat_cb), NULL); | |
| 1052 | |
| 4687 | 1053 button = gaim_pixbuf_button_from_stock(_("Away"), GAIM_STOCK_AWAY, GAIM_BUTTON_VERTICAL); |
| 1054 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
| 1055 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
| 4694 | 1056 gtk_size_group_add_widget(sg, button); |
| 1057 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_away_cb), NULL); | |
| 4687 | 1058 |
| 1059 /* OK... let's show this bad boy. */ | |
| 1060 gaim_gtk_blist_refresh(list); | |
| 1061 gtk_widget_show_all(gtkblist->window); | |
| 4729 | 1062 |
| 4697 | 1063 gaim_gtk_blist_update_toolbar(); |
| 1064 | |
| 4687 | 1065 } |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
1066 |
| 4687 | 1067 void gaim_gtk_blist_refresh(struct gaim_buddy_list *list) |
| 1068 { | |
| 1069 GaimBlistNode *group = list->root; | |
| 1070 GaimBlistNode *buddy; | |
| 4690 | 1071 |
| 4687 | 1072 while (group) { |
| 1073 gaim_gtk_blist_update(list, group); | |
| 1074 buddy = group->child; | |
| 1075 while (buddy) { | |
| 4699 | 1076 gaim_gtk_blist_update(list, buddy); |
| 4687 | 1077 buddy = buddy->next; |
| 1078 } | |
| 1079 group = group->next; | |
| 1080 } | |
| 1081 } | |
| 1 | 1082 |
| 4699 | 1083 static gboolean get_iter_from_node_helper(GaimBlistNode *node, GtkTreeIter *iter, GtkTreeIter *root) { |
| 1084 do { | |
| 1085 GaimBlistNode *n; | |
| 1086 GtkTreeIter child; | |
| 1087 | |
| 1088 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), root, NODE_COLUMN, &n, -1); | |
| 1089 if(n == node) { | |
| 1090 *iter = *root; | |
| 1091 return TRUE; | |
| 1092 } | |
| 1093 | |
| 1094 if(gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &child, root)) { | |
| 1095 if(get_iter_from_node_helper(node,iter,&child)) | |
| 1096 return TRUE; | |
| 1097 } | |
| 1098 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(gtkblist->treemodel), root)); | |
| 1099 | |
| 1100 return FALSE; | |
| 1101 } | |
| 1102 | |
| 1103 static gboolean get_iter_from_node(GaimBlistNode *node, GtkTreeIter *iter) { | |
| 1104 GtkTreeIter root; | |
| 1105 | |
| 1106 if (!gtkblist) | |
| 1107 return FALSE; | |
| 1108 | |
| 1109 if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(gtkblist->treemodel), &root)) | |
| 1110 return FALSE; | |
| 1111 | |
| 1112 return get_iter_from_node_helper(node, iter, &root); | |
| 1113 } | |
| 1114 | |
| 4697 | 1115 void gaim_gtk_blist_update_toolbar() { |
| 1116 if (!gtkblist) | |
| 1117 return; | |
| 4699 | 1118 |
| 4697 | 1119 gtk_container_foreach(GTK_CONTAINER(gtkblist->bbox), gaim_gtk_blist_update_toolbar_icons, NULL); |
| 4699 | 1120 |
| 4697 | 1121 if (blist_options & OPT_BLIST_NO_BUTTONS) |
| 1122 gtk_widget_hide(gtkblist->bbox); | |
| 1123 else | |
| 1124 gtk_widget_show_all(gtkblist->bbox); | |
| 1125 } | |
| 1126 | |
| 4701 | 1127 static void gaim_gtk_blist_remove(struct gaim_buddy_list *list, GaimBlistNode *node) |
| 1128 { | |
| 1129 struct gaim_gtk_blist_node *gtknode; | |
| 1130 GtkTreeIter iter; | |
| 1131 | |
| 1132 if (!node->ui_data) | |
| 1133 return; | |
| 1134 | |
| 1135 gtknode = (struct gaim_gtk_blist_node *)node->ui_data; | |
| 1136 | |
| 1137 if (gtknode->timer > 0) { | |
| 1138 g_source_remove(gtknode->timer); | |
| 1139 gtknode->timer = 0; | |
| 1140 } | |
| 1141 | |
| 4831 | 1142 if(gtkblist->selected_node == node) |
| 1143 gtkblist->selected_node = NULL; | |
| 1144 | |
| 4701 | 1145 if (get_iter_from_node(node, &iter)) { |
| 1146 gtk_tree_store_remove(gtkblist->treemodel, &iter); | |
| 1147 if(GAIM_BLIST_NODE_IS_BUDDY(node) && gaim_blist_get_group_online_count((struct group *)node->parent) == 0) { | |
| 1148 GtkTreeIter groupiter; | |
| 1149 if(get_iter_from_node(node->parent, &groupiter)) | |
| 1150 gtk_tree_store_remove(gtkblist->treemodel, &groupiter); | |
| 1151 } | |
| 1152 } | |
| 1153 } | |
| 1154 | |
| 4810 | 1155 static gboolean do_selection_changed(GaimBlistNode *new_selection) |
| 1156 { | |
| 1157 GaimBlistNode *old_selection = gtkblist->selected_node; | |
| 1158 | |
| 1159 if(new_selection != gtkblist->selected_node) { | |
| 1160 gtkblist->selected_node = new_selection; | |
| 1161 if(new_selection) | |
| 1162 gaim_gtk_blist_update(NULL, new_selection); | |
| 1163 if(old_selection) | |
| 1164 gaim_gtk_blist_update(NULL, old_selection); | |
| 1165 } | |
| 1166 | |
| 1167 return FALSE; | |
| 1168 } | |
| 1169 | |
| 1170 static void gaim_gtk_blist_selection_changed(GtkTreeSelection *selection, gpointer data) | |
| 1171 { | |
| 1172 GaimBlistNode *new_selection = NULL; | |
| 1173 GtkTreeIter iter; | |
| 1174 | |
| 1175 if(gtk_tree_selection_get_selected(selection, NULL, &iter)){ | |
| 1176 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, | |
| 1177 NODE_COLUMN, &new_selection, -1); | |
| 1178 } | |
| 1179 /* we set this up as a timeout, otherwise the blist flickers */ | |
| 1180 g_timeout_add(0, (GSourceFunc)do_selection_changed, new_selection); | |
| 1181 } | |
| 1182 | |
| 4701 | 1183 |
| 4687 | 1184 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node) |
| 1185 { | |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1186 struct gaim_gtk_blist_node *gtknode; |
| 4699 | 1187 GtkTreeIter iter; |
| 4687 | 1188 gboolean expand = FALSE; |
| 4699 | 1189 gboolean new_entry = FALSE; |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
1190 |
| 4687 | 1191 if (!gtkblist) |
| 1192 return; | |
| 4699 | 1193 |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1194 gtknode = GAIM_GTK_BLIST_NODE(node); |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1195 |
| 4690 | 1196 |
| 4699 | 1197 if (!get_iter_from_node(node, &iter)) { /* This is a newly added node */ |
| 1198 new_entry = TRUE; | |
| 4687 | 1199 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { |
| 1200 if (((struct buddy*)node)->present) { | |
| 4699 | 1201 GtkTreeIter groupiter; |
| 1202 GaimBlistNode *oldersibling; | |
| 1203 GtkTreeIter oldersiblingiter; | |
| 4690 | 1204 |
| 4699 | 1205 if(node->parent && !get_iter_from_node(node->parent, &groupiter)) { |
| 1206 /* This buddy's group has not yet been added. We do that here */ | |
| 4757 | 1207 GdkPixbuf *groupicon = gtk_widget_render_icon(gtkblist->treeview, |
| 1208 GTK_STOCK_OPEN, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL); | |
| 4794 | 1209 char *esc = g_markup_escape_text(((struct group*)node->parent)->name, -1); |
| 1210 char *mark = g_strdup_printf("<span weight='bold'>%s</span>", esc); | |
| 1211 g_free(esc); | |
| 4699 | 1212 oldersibling = node->parent->prev; |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
1213 |
| 4687 | 1214 /* We traverse backwards through the buddy list to find the node in the tree to insert it after */ |
| 4699 | 1215 while (oldersibling && !get_iter_from_node(oldersibling, &oldersiblingiter)) |
| 1216 oldersibling = oldersibling->prev; | |
| 4690 | 1217 |
| 4687 | 1218 /* This is where we create the node and add it. */ |
| 4699 | 1219 gtk_tree_store_insert_after(gtkblist->treemodel, &groupiter, NULL, oldersibling ? &oldersiblingiter : NULL); |
| 1220 gtk_tree_store_set(gtkblist->treemodel, &groupiter, | |
| 4757 | 1221 STATUS_ICON_COLUMN, groupicon, |
| 4687 | 1222 NAME_COLUMN, mark, |
| 1223 NODE_COLUMN, node->parent, | |
| 1224 -1); | |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1225 |
| 4737 | 1226 g_free(mark); |
| 4757 | 1227 g_object_unref(G_OBJECT(groupicon)); |
| 4737 | 1228 |
| 4687 | 1229 expand = TRUE; |
| 1230 } | |
| 4810 | 1231 |
| 4699 | 1232 oldersibling = node->prev; |
| 1233 while (oldersibling && !get_iter_from_node(oldersibling, &oldersiblingiter)) | |
| 1234 oldersibling = oldersibling->prev; | |
| 1235 | |
| 1236 gtk_tree_store_insert_after(gtkblist->treemodel, &iter, &groupiter, oldersibling ? &oldersiblingiter : NULL); | |
| 4810 | 1237 |
| 4767 | 1238 if (blist_options & OPT_BLIST_POPUP) |
| 1239 gtk_window_present(GTK_WINDOW(gtkblist->window)); | |
| 4699 | 1240 |
| 4687 | 1241 if (expand) { /* expand was set to true if this is the first element added to a group. In such case |
| 1242 * we expand the group node */ | |
| 4699 | 1243 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter); |
| 1244 gtk_tree_view_expand_row(GTK_TREE_VIEW(gtkblist->treeview), path, TRUE); | |
| 4721 | 1245 gtk_tree_path_free(path); |
| 4687 | 1246 } |
| 4699 | 1247 } |
| 1248 } | |
| 1249 } | |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1250 |
| 4687 | 1251 if (GAIM_BLIST_NODE_IS_BUDDY(node) && ((struct buddy*)node)->present) { |
| 1252 GdkPixbuf *status, *avatar; | |
| 1253 char *mark; | |
| 4697 | 1254 char *warning = NULL, *idle = NULL; |
| 1255 | |
| 4810 | 1256 gboolean selected = (gtkblist->selected_node == node); |
| 1257 | |
| 1258 status = gaim_gtk_blist_get_status_icon((struct buddy*)node, | |
| 4724 | 1259 blist_options & OPT_BLIST_SHOW_ICONS ? GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL); |
| 4687 | 1260 avatar = gaim_gtk_blist_get_buddy_icon((struct buddy*)node); |
| 4810 | 1261 mark = gaim_gtk_blist_get_name_markup((struct buddy*)node, selected); |
| 4697 | 1262 |
| 4725 | 1263 if (((struct buddy*)node)->idle > 0) { |
| 4697 | 1264 time_t t; |
| 1265 int ihrs, imin; | |
| 1266 time(&t); | |
| 1267 ihrs = (t - ((struct buddy *)node)->idle) / 3600; | |
| 1268 imin = ((t - ((struct buddy*)node)->idle) / 60) % 60; | |
| 4718 | 1269 if(ihrs > 0) |
| 1270 idle = g_strdup_printf("(%d:%02d)", ihrs, imin); | |
| 1271 else | |
| 1272 idle = g_strdup_printf("(%d)", imin); | |
| 4697 | 1273 } |
| 1274 | |
| 4725 | 1275 if (((struct buddy*)node)->evil > 0) |
| 4699 | 1276 warning = g_strdup_printf("%d%%", ((struct buddy*)node)->evil); |
| 4810 | 1277 |
| 4697 | 1278 |
| 4718 | 1279 if((blist_options & OPT_BLIST_GREY_IDLERS) |
| 1280 && ((struct buddy *)node)->idle) { | |
| 4810 | 1281 if(warning && !selected) { |
| 4718 | 1282 char *w2 = g_strdup_printf("<span color='dim grey'>%s</span>", |
| 1283 warning); | |
| 1284 g_free(warning); | |
| 1285 warning = w2; | |
| 1286 } | |
| 1287 | |
| 4810 | 1288 if(idle && !selected) { |
| 4718 | 1289 char *i2 = g_strdup_printf("<span color='dim grey'>%s</span>", |
| 1290 idle); | |
| 1291 g_free(idle); | |
| 1292 idle = i2; | |
| 1293 } | |
| 1294 } | |
| 1295 | |
| 1296 | |
| 4699 | 1297 gtk_tree_store_set(gtkblist->treemodel, &iter, |
| 4687 | 1298 STATUS_ICON_COLUMN, status, |
| 1299 NAME_COLUMN, mark, | |
| 4697 | 1300 WARNING_COLUMN, warning, |
| 1301 IDLE_COLUMN, idle, | |
| 4699 | 1302 BUDDY_ICON_COLUMN, avatar, |
| 4687 | 1303 NODE_COLUMN, node, |
| 1304 -1); | |
| 4699 | 1305 |
| 4687 | 1306 g_free(mark); |
| 4697 | 1307 if (idle) |
| 1308 g_free(idle); | |
| 1309 if (warning) | |
| 1310 g_free(warning); | |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1311 |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1312 if (status != NULL) |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1313 g_object_unref(status); |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1314 |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1315 if (avatar != NULL) |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1316 g_object_unref(avatar); |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1317 |
| 4701 | 1318 } else if (GAIM_BLIST_NODE_IS_BUDDY(node) && !new_entry) { |
| 1319 gaim_gtk_blist_remove(list, node); | |
| 4767 | 1320 if (blist_options & OPT_BLIST_POPUP) |
| 1321 gtk_window_present(GTK_WINDOW(gtkblist->window)); | |
| 4781 | 1322 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { |
| 1323 GaimBlistNode *afsad = node->child; | |
| 1324 while (afsad) { | |
| 1325 gaim_gtk_blist_update(list, afsad); | |
| 1326 afsad = afsad->next; | |
| 1327 } | |
| 4687 | 1328 } |
| 4786 | 1329 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(gtkblist->treeview)); |
| 4687 | 1330 } |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
1331 |
| 4687 | 1332 static void gaim_gtk_blist_destroy(struct gaim_buddy_list *list) |
| 1333 { | |
| 4770 | 1334 if (!gtkblist) |
| 1335 return; | |
| 4687 | 1336 gtk_widget_destroy(gtkblist->window); |
| 4745 | 1337 |
| 1338 gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL; | |
| 1339 gtkblist->treemodel = NULL; | |
| 1340 gtkblist->idle_column = NULL; | |
| 1341 gtkblist->warning_column = gtkblist->buddy_icon_column = NULL; | |
| 1342 gtkblist->bbox = gtkblist->tipwindow = NULL; | |
| 1343 protomenu = NULL; | |
| 1344 awaymenu = NULL; | |
| 1345 bpmenu = NULL; | |
| 1346 | |
| 1347 gtkblist->timeout = 0; | |
| 4687 | 1348 } |
| 1 | 1349 |
| 4687 | 1350 static void gaim_gtk_blist_set_visible(struct gaim_buddy_list *list, gboolean show) |
| 1351 { | |
| 4698 | 1352 if (show) { |
| 4699 | 1353 gtk_window_present(GTK_WINDOW(gtkblist->window)); |
| 4698 | 1354 } else { |
| 1355 if (!connections || docklet_count) { | |
| 1356 #ifdef _WIN32 | |
|
4711
0c1f3e651d3e
[gaim-migrate @ 5022]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4706
diff
changeset
|
1357 wgaim_systray_minimize(gtkblist->window); |
| 4698 | 1358 #endif |
| 1359 gtk_widget_hide(gtkblist->window); | |
| 1360 } else { | |
| 1361 gtk_window_iconify(GTK_WINDOW(gtkblist->window)); | |
| 1362 } | |
| 1363 } | |
| 1364 } | |
| 1365 | |
| 1366 void gaim_gtk_blist_docklet_toggle() { | |
| 1367 /* Useful for the docklet plugin and also for the win32 tray icon*/ | |
| 1368 /* This is called when one of those is clicked--it will show/hide the | |
| 1369 buddy list/login window--depending on which is active */ | |
| 1370 if (connections && gtkblist) { | |
| 1371 if (GTK_WIDGET_VISIBLE(gtkblist->window)) { | |
| 1372 gaim_blist_set_visible(GAIM_WINDOW_ICONIFIED(gtkblist->window) || gaim_gtk_blist_obscured); | |
| 1373 } else { | |
| 1374 #if _WIN32 | |
|
4711
0c1f3e651d3e
[gaim-migrate @ 5022]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4706
diff
changeset
|
1375 wgaim_systray_maximize(gtkblist->window); |
| 4698 | 1376 #endif |
| 1377 gaim_blist_set_visible(TRUE); | |
| 1378 } | |
| 1379 } else if (connections) { | |
| 1380 /* we're logging in or something... do nothing */ | |
| 1381 debug_printf("docklet_toggle called with connections but no blist!\n"); | |
| 1382 } else { | |
| 4833 | 1383 if (mainwindow && GTK_WIDGET_VISIBLE(mainwindow)) { |
| 4698 | 1384 if (GAIM_WINDOW_ICONIFIED(mainwindow)) { |
| 1385 gtk_window_present(GTK_WINDOW(mainwindow)); | |
| 1386 } else { | |
| 1387 #if _WIN32 | |
| 1388 wgaim_systray_minimize(mainwindow); | |
| 1389 #endif | |
| 1390 gtk_widget_hide(mainwindow); | |
| 1391 } | |
| 1392 } else { | |
| 1393 #if _WIN32 | |
| 1394 wgaim_systray_maximize(mainwindow); | |
| 1395 #endif | |
| 4833 | 1396 show_login(); |
| 4698 | 1397 } |
| 1398 } | |
| 1399 } | |
| 1400 | |
| 1401 void gaim_gtk_blist_docklet_add() | |
| 1402 { | |
| 1403 docklet_count++; | |
| 1404 } | |
| 1405 | |
| 1406 void gaim_gtk_blist_docklet_remove() | |
| 1407 { | |
| 1408 docklet_count--; | |
| 1409 if (!docklet_count) { | |
| 1410 if (connections) { | |
| 1411 gaim_blist_set_visible(TRUE); | |
| 4745 | 1412 } else if(gtkblist && gtkblist->window) { |
| 4698 | 1413 gtk_window_present(GTK_WINDOW(gtkblist->window)); |
| 1414 } | |
| 1415 } | |
| 4687 | 1416 } |
| 1 | 1417 |
| 4687 | 1418 static struct gaim_blist_ui_ops blist_ui_ops = |
| 1419 { | |
|
4695
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1420 gaim_gtk_blist_new_list, |
|
4bdd9a5fd026
[gaim-migrate @ 5006]
Christian Hammond <chipx86@chipx86.com>
parents:
4694
diff
changeset
|
1421 gaim_gtk_blist_new_node, |
| 4687 | 1422 gaim_gtk_blist_show, |
| 1423 gaim_gtk_blist_update, | |
| 1424 gaim_gtk_blist_remove, | |
| 1425 gaim_gtk_blist_destroy, | |
| 1426 gaim_gtk_blist_set_visible | |
| 1427 }; | |
| 1 | 1428 |
| 1429 | |
| 4687 | 1430 struct gaim_blist_ui_ops *gaim_get_gtk_blist_ui_ops() |
|
2372
2927c2c26fe6
[gaim-migrate @ 2385]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2334
diff
changeset
|
1431 { |
| 4687 | 1432 return &blist_ui_ops; |
|
1037
1c663beef29d
[gaim-migrate @ 1047]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1036
diff
changeset
|
1433 } |
|
1c663beef29d
[gaim-migrate @ 1047]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1036
diff
changeset
|
1434 |
| 3131 | 1435 |
| 1436 | |
| 4687 | 1437 /********************************************************************* |
| 1438 * Public utility functions * | |
| 1439 *********************************************************************/ | |
|
1058
4927ce25d8cc
[gaim-migrate @ 1068]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1057
diff
changeset
|
1440 |
| 4687 | 1441 GdkPixbuf * |
| 1442 create_prpl_icon(struct gaim_account *account) | |
|
4553
d03fcb3f4be2
[gaim-migrate @ 4833]
Christian Hammond <chipx86@chipx86.com>
parents:
4525
diff
changeset
|
1443 { |
| 4687 | 1444 struct prpl *prpl = find_prpl(account->protocol); |
| 1445 GdkPixbuf *status = NULL; | |
| 1446 char *filename = NULL; | |
| 1447 const char *protoname = prpl->list_icon(account, NULL); | |
| 1448 /* "Hey, what's all this crap?" you ask. Status icons will be themeable too, and | |
| 1449 then it will look up protoname from the theme */ | |
| 1450 if (!strcmp(protoname, "aim")) { | |
| 1451 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "aim.png", NULL); | |
| 1452 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1453 g_free(filename); | |
| 1454 } else if (!strcmp(protoname, "yahoo")) { | |
| 1455 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "yahoo.png", NULL); | |
| 1456 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1457 g_free(filename); | |
| 1458 } else if (!strcmp(protoname, "msn")) { | |
| 1459 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "msn.png", NULL); | |
| 1460 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1461 g_free(filename); | |
| 1462 } else if (!strcmp(protoname, "jabber")) { | |
| 1463 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "jabber.png", NULL); | |
| 1464 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1465 g_free(filename); | |
| 1466 } else if (!strcmp(protoname, "icq")) { | |
| 1467 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "icq.png", NULL); | |
| 1468 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1469 g_free(filename); | |
| 1470 } else if (!strcmp(protoname, "gadu-gadu")) { | |
| 1471 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "gadugadu.png", NULL); | |
| 1472 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1473 g_free(filename); | |
| 1474 } else if (!strcmp(protoname, "napster")) { | |
| 1475 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "napster.png", NULL); | |
| 1476 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1477 g_free(filename); | |
| 1478 } else if (!strcmp(protoname, "irc")) { | |
| 1479 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "irc.png", NULL); | |
| 1480 status = gdk_pixbuf_new_from_file(filename,NULL); | |
| 1481 g_free(filename); | |
|
960
fa681641643d
[gaim-migrate @ 970]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
945
diff
changeset
|
1482 } |
| 4687 | 1483 return status; |
| 1 | 1484 } |
| 4699 | 1485 |
