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