Mercurial > pidgin.yaz
annotate src/gtkblist.c @ 8252:10a41e67a800
[gaim-migrate @ 8975]
I'm tired, so I probably broke something...
1. clean up warnings trying to put chats into the blist before the blist is there to put chats in
2. clean up warnings trying to mess with the buddy pounce menu before the buddy pounce menu is there to be messed with
3. clean up warnings with reconnecting and the progress bars in the connection dialog, i think
4. re-order things so the tab doesn't go grey if it's already red. this annoyed me.
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Fri, 13 Feb 2004 07:48:19 +0000 |
parents | 63c7a16a2c09 |
children | 8a9a6eb3ded0 |
rev | line source |
---|---|
5228 | 1 /* |
2 * gaim | |
3 * | |
8046 | 4 * Gaim is the legal property of its developers, whose names are too numerous |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
5228 | 7 * |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
7620 | 23 #include "gtkinternal.h" |
24 | |
25 #include "account.h" | |
26 #include "core.h" | |
27 #include "debug.h" | |
28 #include "multi.h" | |
29 #include "notify.h" | |
30 #include "prpl.h" | |
31 #include "prefs.h" | |
32 #include "request.h" | |
33 #include "signals.h" | |
34 #include "sound.h" | |
35 #include "stock.h" | |
36 #include "util.h" | |
37 | |
38 #include "gtkaccount.h" | |
39 #include "gtkblist.h" | |
40 #include "gtkconv.h" | |
41 #include "gtkdebug.h" | |
42 #include "gtkft.h" | |
43 #include "gtklog.h" | |
44 #include "gtkpounce.h" | |
45 #include "gtkprefs.h" | |
46 #include "gtkprivacy.h" | |
8113 | 47 #include "gtkroomlist.h" |
7620 | 48 #include "gtkutils.h" |
49 | |
50 #include "ui.h" | |
51 | |
52 #include "gaim.h" | |
5228 | 53 |
54 #include <gdk/gdkkeysyms.h> | |
55 #include <gtk/gtk.h> | |
7620 | 56 #include <gdk/gdk.h> |
57 | |
7662 | 58 #if (GTK_CHECK_VERSION(2,2,0) && !(defined(__APPLE__) && defined(__MACH__))) |
59 #define WANT_DROP_SHADOW | |
60 #endif | |
61 | |
7620 | 62 typedef struct |
63 { | |
64 GaimAccount *account; | |
65 | |
66 GtkWidget *window; | |
67 GtkWidget *combo; | |
68 GtkWidget *entry; | |
69 GtkWidget *entry_for_alias; | |
70 GtkWidget *account_box; | |
71 | |
72 } GaimGtkAddBuddyData; | |
73 | |
74 typedef struct | |
75 { | |
76 GaimAccount *account; | |
77 | |
78 GtkWidget *window; | |
79 GtkWidget *account_menu; | |
80 GtkWidget *alias_entry; | |
81 GtkWidget *group_combo; | |
82 GtkWidget *entries_box; | |
83 GtkSizeGroup *sg; | |
84 | |
85 GList *entries; | |
86 | |
87 } GaimGtkAddChatData; | |
88 | |
89 | |
90 static GtkWidget *protomenu = NULL; | |
5228 | 91 |
5422 | 92 GSList *gaim_gtk_blist_sort_methods = NULL; |
93 static struct gaim_gtk_blist_sort_method *current_sort_method = NULL; | |
7620 | 94 static GtkTreeIter sort_method_none(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur); |
95 | |
96 /* The functions we use for sorting aren't available in gtk 2.0.x, and | |
97 * segfault in 2.2.0. 2.2.1 is known to work, so I'll require that */ | |
98 #if GTK_CHECK_VERSION(2,2,1) | |
99 static GtkTreeIter sort_method_alphabetical(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur); | |
100 static GtkTreeIter sort_method_status(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur); | |
101 static GtkTreeIter sort_method_log(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur); | |
102 #endif | |
103 static GaimGtkBuddyList *gtkblist = NULL; | |
5228 | 104 |
105 /* part of the best damn Docklet code this side of Tahiti */ | |
106 static gboolean gaim_gtk_blist_obscured = FALSE; | |
107 | |
108 static void gaim_gtk_blist_selection_changed(GtkTreeSelection *selection, gpointer data); | |
7620 | 109 static void gaim_gtk_blist_update(GaimBuddyList *list, GaimBlistNode *node); |
5234 | 110 static char *gaim_get_tooltip_text(GaimBlistNode *node); |
5228 | 111 static char *item_factory_translate_func (const char *path, gpointer func_data); |
5273 | 112 static gboolean get_iter_from_node(GaimBlistNode *node, GtkTreeIter *iter); |
7620 | 113 static void redo_buddy_list(GaimBuddyList *list, gboolean remove); |
114 static void gaim_gtk_blist_collapse_contact_cb(GtkWidget *w, GaimBlistNode *node); | |
115 | |
116 static void show_rename_group(GtkWidget *unused, GaimGroup *g); | |
5422 | 117 |
5256 | 118 struct _gaim_gtk_blist_node { |
119 GtkTreeRowReference *row; | |
7620 | 120 gboolean contact_expanded; |
5256 | 121 }; |
122 | |
7662 | 123 #ifdef WANT_DROP_SHADOW |
7620 | 124 /**************************** Weird drop shadow stuff *******************/ |
125 /* This is based on a patch for drop shadows in GTK menus available at http://www.xfce.org/gtkmenu-shadow/ */ | |
126 | |
127 enum side { | |
128 EAST_SIDE, | |
129 SOUTH_SIDE | |
130 }; | |
131 | |
132 const double shadow_strip_l[5] = { | |
133 .937, .831, .670, .478, .180 | |
134 }; | |
135 | |
136 const double bottom_left_corner[25] = { | |
137 1.00, .682, .423, .333, .258, | |
138 1.00, .898, .800, .682, .584, | |
139 1.00, .937, .874, .800, .737, | |
140 1.00, .968, .937, .898, .866, | |
141 1.00, .988, .976, .960, .945 | |
142 }; | |
143 | |
144 const double bottom_right_corner[25] = { | |
145 .258, .584, .737, .866, .945, | |
146 .584, .682, .800, .898, .960, | |
147 .737, .800, .874, .937, .976, | |
148 .866, .898, .937, .968, .988, | |
149 .945, .960, .976, .988, .996 | |
150 }; | |
151 | |
152 const double top_right_corner[25] = { | |
153 1.00, 1.00, 1.00, 1.00, 1.00, | |
154 .686, .898, .937, .968, .988, | |
155 .423, .803, .874, .937, .976, | |
156 .333, .686, .800, .898, .960, | |
157 .258, .584, .737, .866, .945 | |
158 }; | |
159 | |
160 const double top_left_corner[25] = { | |
161 .988, .968, .937, .898, .498, | |
162 .976, .937, .874, .803, .423, | |
163 .960, .898, .800, .686, .333, | |
164 .945, .866, .737, .584, .258, | |
165 .941, .847, .698, .521, .215 | |
166 }; | |
167 | |
168 | |
169 static GdkPixbuf * | |
170 get_pixbuf (GtkWidget *menu, | |
171 int x, | |
172 int y, | |
173 int width, | |
174 int height) | |
175 { | |
176 GdkPixbuf *dest, *src; | |
177 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET(menu)); | |
178 GdkWindow *root = gdk_screen_get_root_window (screen); | |
179 gint screen_height = gdk_screen_get_height (screen); | |
180 gint screen_width = gdk_screen_get_width (screen); | |
181 gint original_width = width; | |
182 gint original_height = height; | |
183 | |
184 #ifdef _WIN32 | |
185 /* In Win32, GDK gets the workarea that isn't occupied by toolbars | |
186 (including the taskbar) and uses that region as the screen size. | |
187 GTK returns positions based on a screen size that ignores these | |
188 toolbars. Since we want a pixmap with real X,Y coordinates, we | |
189 need to find out the offset from GTK's screen to GDK's screen, | |
190 and adjust the pixmaps we grab accordingly. GDK will not deal | |
191 with toolbar position updates, so we're stuck restarting Gaim | |
192 if that happens. */ | |
193 RECT *workarea = g_malloc(sizeof(RECT)); | |
194 SystemParametersInfo(SPI_GETWORKAREA, 0, (void *)workarea, 0); | |
195 x += (workarea->left); | |
196 y += (workarea->top); | |
197 g_free(workarea); | |
198 #endif | |
199 | |
200 if (x < 0) | |
201 { | |
202 width += x; | |
203 x = 0; | |
204 } | |
205 | |
206 if (y < 0) | |
207 { | |
208 height += y; | |
209 y = 0; | |
210 } | |
211 | |
212 if (x + width > screen_width) | |
213 { | |
214 width = screen_width - x; | |
215 } | |
216 | |
217 if (y + height > screen_height) | |
218 { | |
219 height = screen_height - y; | |
220 } | |
221 | |
222 if (width <= 0 || height <= 0) | |
223 return NULL; | |
224 | |
225 dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, | |
226 original_width, original_height); | |
227 src = gdk_pixbuf_get_from_drawable (NULL, root, NULL, x, y, 0, 0, | |
228 width, height); | |
229 gdk_pixbuf_copy_area (src, 0, 0, width, height, dest, 0, 0); | |
230 | |
231 g_object_unref (G_OBJECT (src)); | |
232 | |
233 return dest; | |
234 } | |
235 | |
236 static void | |
237 shadow_paint(GaimGtkBuddyList *blist, GdkRectangle *area, enum side shadow) | |
238 { | |
239 gint width, height; | |
240 GdkGC *gc = gtkblist->tipwindow->style->black_gc; | |
241 | |
242 switch (shadow) | |
243 { | |
244 case EAST_SIDE: | |
245 if (gtkblist->east != NULL) | |
246 { | |
247 if (area) | |
248 gdk_gc_set_clip_rectangle (gc, area); | |
249 | |
250 width = gdk_pixbuf_get_width (gtkblist->east); | |
251 height = gdk_pixbuf_get_height (gtkblist->east); | |
252 | |
253 gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->east_shadow), gc, | |
254 gtkblist->east, 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, | |
255 0, 0); | |
256 | |
257 if (area) | |
258 gdk_gc_set_clip_rectangle (gc, NULL); | |
259 } | |
260 break; | |
261 case SOUTH_SIDE: | |
262 if (blist->south != NULL) | |
263 { | |
264 if (area) | |
265 gdk_gc_set_clip_rectangle (gc, area); | |
266 | |
267 width = gdk_pixbuf_get_width (gtkblist->south); | |
268 height = gdk_pixbuf_get_height (gtkblist->south); | |
269 gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->south_shadow), gc, gtkblist->south, | |
270 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0); | |
8040 | 271 |
7620 | 272 if (area) |
273 gdk_gc_set_clip_rectangle (gc, NULL); | |
274 } | |
275 break; | |
276 default: | |
277 break; | |
278 } | |
279 } | |
280 | |
281 static void | |
282 pixbuf_add_shadow (GdkPixbuf *pb, | |
283 enum side shadow) | |
284 { | |
285 gint width, rowstride, height; | |
286 gint i; | |
287 guchar *pixels, *p; | |
288 | |
289 width = gdk_pixbuf_get_width (pb); | |
290 height = gdk_pixbuf_get_height (pb); | |
291 rowstride = gdk_pixbuf_get_rowstride (pb); | |
292 pixels = gdk_pixbuf_get_pixels (pb); | |
293 | |
294 switch (shadow) | |
295 { | |
296 case EAST_SIDE: | |
297 if (height > 5) | |
298 { | |
299 for (i = 0; i < width; i++) | |
300 { | |
301 gint j, k; | |
302 | |
303 p = pixels + (i * rowstride); | |
304 for (j = 0, k = 0; j < 3 * width; j += 3, k++) | |
305 { | |
306 p[j] = (guchar) (p[j] * top_right_corner [i * width + k]); | |
307 p[j + 1] = (guchar) (p[j + 1] * top_right_corner [i * width + k]); | |
308 p[j + 2] = (guchar) (p[j + 2] * top_right_corner [i * width + k]); | |
309 } | |
310 } | |
311 | |
312 i = 5; | |
313 } | |
314 else | |
315 { | |
316 i = 0; | |
317 } | |
318 | |
319 for (;i < height; i++) | |
320 { | |
321 gint j, k; | |
322 | |
323 p = pixels + (i * rowstride); | |
324 for (j = 0, k = 0; j < 3 * width; j += 3, k++) | |
325 { | |
326 p[j] = (guchar) (p[j] * shadow_strip_l[width - 1 - k]); | |
327 p[j + 1] = (guchar) (p[j + 1] * shadow_strip_l[width - 1 - k]); | |
328 p[j + 2] = (guchar) (p[j + 2] * shadow_strip_l[width - 1 - k]); | |
329 } | |
330 } | |
331 break; | |
332 | |
333 case SOUTH_SIDE: | |
334 for (i = 0; i < height; i++) | |
335 { | |
336 gint j, k; | |
337 | |
338 p = pixels + (i * rowstride); | |
339 for (j = 0, k = 0; j < 3 * height; j += 3, k++) | |
340 { | |
341 p[j] = (guchar) (p[j] * bottom_left_corner[i * height + k]); | |
342 p[j + 1] = (guchar) (p[j + 1] * bottom_left_corner[i * height + k]); | |
343 p[j + 2] = (guchar) (p[j + 2] * bottom_left_corner[i * height + k]); | |
344 } | |
345 | |
346 p = pixels + (i * rowstride) + 3 * height; | |
347 for (j = 0, k = 0; j < (width * 3) - (6 * height); j += 3, k++) | |
348 { | |
349 p[j] = (guchar) (p[j] * bottom_right_corner [i * height]); | |
350 p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner [i * height]); | |
351 p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner [i * height]); | |
352 } | |
353 | |
354 p = pixels + (i * rowstride) + ((width * 3) - (3 * height)); | |
355 for (j = 0, k = 0; j < 3 * height; j += 3, k++) | |
356 { | |
357 p[j] = (guchar) (p[j] * bottom_right_corner[i * height + k]); | |
358 p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner[i * height + k]); | |
359 p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner[i * height + k]); | |
360 } | |
361 } | |
362 break; | |
363 | |
364 default: | |
365 break; | |
366 } | |
367 } | |
368 | |
369 static gboolean | |
370 map_shadow_windows (gpointer data) | |
371 { | |
372 GaimGtkBuddyList *blist = (GaimGtkBuddyList*)data; | |
373 GtkWidget *widget = blist->tipwindow; | |
374 GdkPixbuf *pixbuf; | |
375 int x, y; | |
376 | |
377 gtk_window_get_position(GTK_WINDOW(widget), &x, &y); | |
378 pixbuf = get_pixbuf (widget, | |
379 x + widget->allocation.width, y, | |
380 5, widget->allocation.height + 5); | |
381 if (pixbuf != NULL) | |
382 { | |
383 pixbuf_add_shadow (pixbuf, EAST_SIDE); | |
384 if (blist->east != NULL) | |
385 { | |
386 g_object_unref (G_OBJECT (blist->east)); | |
387 } | |
388 blist->east = pixbuf; | |
389 } | |
390 | |
391 pixbuf = get_pixbuf (widget, | |
392 x, y + widget->allocation.height, | |
393 widget->allocation.width + 5, 5); | |
394 if (pixbuf != NULL) | |
395 { | |
396 pixbuf_add_shadow (pixbuf, SOUTH_SIDE); | |
397 if (blist->south != NULL) | |
398 { | |
399 g_object_unref (G_OBJECT (blist->south)); | |
400 } | |
401 blist->south = pixbuf; | |
402 } | |
403 | |
404 gdk_window_move_resize (blist->east_shadow, | |
405 x + widget->allocation.width, y, | |
406 5, widget->allocation.height); | |
407 | |
408 gdk_window_move_resize (blist->south_shadow, | |
409 x, y + widget->allocation.height, | |
410 widget->allocation.width + 5, 5); | |
411 gdk_window_show (blist->east_shadow); | |
412 gdk_window_show (blist->south_shadow); | |
413 shadow_paint(blist, NULL, EAST_SIDE); | |
414 shadow_paint(blist, NULL, SOUTH_SIDE); | |
415 | |
416 return FALSE; | |
417 } | |
418 | |
419 /**************** END WEIRD DROP SHADOW STUFF ***********************************/ | |
420 #endif | |
421 static GSList *blist_prefs_callbacks = NULL; | |
422 | |
5228 | 423 /*************************************************** |
424 * Callbacks * | |
425 ***************************************************/ | |
426 | |
427 static gboolean gtk_blist_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data) | |
428 { | |
429 if (docklet_count) | |
430 gaim_blist_set_visible(FALSE); | |
431 else | |
7620 | 432 gaim_core_quit(); |
5228 | 433 |
434 /* we handle everything, event should not propogate further */ | |
435 return TRUE; | |
436 } | |
437 | |
438 static gboolean gtk_blist_configure_cb(GtkWidget *w, GdkEventConfigure *event, gpointer data) | |
439 { | |
440 /* unfortunately GdkEventConfigure ignores the window gravity, but * | |
441 * the only way we have of setting the position doesn't. we have to * | |
7620 | 442 * call get_position because it does pay attention to the gravity. * |
443 * this is inefficient and I agree it sucks, but it's more likely * | |
444 * to work correctly. - Robot101 */ | |
5228 | 445 gint x, y; |
446 | |
447 /* check for visibility because when we aren't visible, this will * | |
448 * give us bogus (0,0) coordinates. - xOr */ | |
7620 | 449 if (GTK_WIDGET_VISIBLE(w)) |
5228 | 450 gtk_window_get_position(GTK_WINDOW(w), &x, &y); |
7620 | 451 else |
452 return FALSE; /* carry on normally */ | |
453 | |
454 /* don't save if nothing changed */ | |
455 if (x == gaim_prefs_get_int("/gaim/gtk/blist/x") && | |
456 y == gaim_prefs_get_int("/gaim/gtk/blist/y") && | |
457 event->width == gaim_prefs_get_int("/gaim/gtk/blist/width") && | |
458 event->height == gaim_prefs_get_int("/gaim/gtk/blist/height")) { | |
459 | |
460 return FALSE; /* carry on normally */ | |
5228 | 461 } |
462 | |
7620 | 463 /* don't save off-screen positioning */ |
464 if (x + event->width < 0 || | |
465 y + event->height < 0 || | |
466 x > gdk_screen_width() || | |
467 y > gdk_screen_height()) { | |
468 | |
469 return FALSE; /* carry on normally */ | |
470 } | |
471 | |
472 /* store the position */ | |
473 gaim_prefs_set_int("/gaim/gtk/blist/x", x); | |
474 gaim_prefs_set_int("/gaim/gtk/blist/y", y); | |
475 gaim_prefs_set_int("/gaim/gtk/blist/width", event->width); | |
476 gaim_prefs_set_int("/gaim/gtk/blist/height", event->height); | |
477 | |
5228 | 478 /* continue to handle event normally */ |
479 return FALSE; | |
480 } | |
481 | |
482 static gboolean gtk_blist_visibility_cb(GtkWidget *w, GdkEventVisibility *event, gpointer data) | |
483 { | |
484 if (event->state == GDK_VISIBILITY_FULLY_OBSCURED) | |
485 gaim_gtk_blist_obscured = TRUE; | |
486 else | |
487 gaim_gtk_blist_obscured = FALSE; | |
488 | |
489 /* continue to handle event normally */ | |
490 return FALSE; | |
491 } | |
492 | |
7620 | 493 static void gtk_blist_menu_info_cb(GtkWidget *w, GaimBuddy *b) |
5228 | 494 { |
495 serv_get_info(b->account->gc, b->name); | |
496 } | |
497 | |
7620 | 498 static void gtk_blist_menu_im_cb(GtkWidget *w, GaimBuddy *b) |
5228 | 499 { |
7620 | 500 GaimConversation *conv = gaim_conversation_new(GAIM_CONV_IM, b->account, |
501 b->name); | |
502 | |
503 if(conv) { | |
504 GaimConvWindow *win = gaim_conversation_get_window(conv); | |
505 | |
506 gaim_conv_window_raise(win); | |
507 gaim_conv_window_switch_conversation( | |
508 gaim_conversation_get_window(conv), | |
509 gaim_conversation_get_index(conv)); | |
510 | |
511 if (GAIM_IS_GTK_WINDOW(win)) | |
512 gtk_window_present(GTK_WINDOW(GAIM_GTK_WINDOW(win)->window)); | |
513 } | |
5228 | 514 } |
515 | |
7620 | 516 static void gtk_blist_menu_autojoin_cb(GtkWidget *w, GaimChat *chat) |
517 { | |
7693 | 518 gaim_blist_node_set_bool((GaimBlistNode*)chat, "gtk-autojoin", |
519 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))); | |
7620 | 520 |
521 gaim_blist_save(); | |
522 } | |
523 | |
524 static void gtk_blist_menu_join_cb(GtkWidget *w, GaimChat *chat) | |
5228 | 525 { |
5234 | 526 serv_join_chat(chat->account->gc, chat->components); |
527 } | |
528 | |
529 static void gtk_blist_menu_alias_cb(GtkWidget *w, GaimBlistNode *node) | |
530 { | |
531 if(GAIM_BLIST_NODE_IS_BUDDY(node)) | |
7620 | 532 alias_dialog_bud((GaimBuddy*)node); |
533 else if(GAIM_BLIST_NODE_IS_CONTACT(node)) | |
534 alias_dialog_contact((GaimContact*)node); | |
5234 | 535 else if(GAIM_BLIST_NODE_IS_CHAT(node)) |
7620 | 536 alias_dialog_blist_chat((GaimChat*)node); |
5228 | 537 } |
538 | |
7620 | 539 static void gtk_blist_menu_bp_cb(GtkWidget *w, GaimBuddy *b) |
5228 | 540 { |
7620 | 541 gaim_gtkpounce_dialog_show(b->account, b->name, NULL); |
5228 | 542 } |
543 | |
7620 | 544 static void gtk_blist_menu_showlog_cb(GtkWidget *w, GaimBuddy *b) |
5228 | 545 { |
7620 | 546 gaim_gtk_log_show(b->name, b->account); |
547 } | |
548 | |
8003 | 549 #if 0 |
5228 | 550 static void gtk_blist_show_systemlog_cb() |
551 { | |
7620 | 552 /* LOG show_log(NULL); */ |
5228 | 553 } |
8003 | 554 #endif |
5228 | 555 |
556 static void gtk_blist_show_onlinehelp_cb() | |
557 { | |
7620 | 558 gaim_notify_uri(NULL, GAIM_WEBSITE "documentation.php"); |
5228 | 559 } |
560 | |
561 static void gtk_blist_button_im_cb(GtkWidget *w, GtkTreeView *tv) | |
562 { | |
563 GtkTreeIter iter; | |
564 GtkTreeModel *model = gtk_tree_view_get_model(tv); | |
565 GtkTreeSelection *sel = gtk_tree_view_get_selection(tv); | |
566 | |
567 if(gtk_tree_selection_get_selected(sel, &model, &iter)){ | |
568 GaimBlistNode *node; | |
569 | |
570 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
571 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
7620 | 572 gaim_conversation_new(GAIM_CONV_IM, ((GaimBuddy*)node)->account, ((GaimBuddy*)node)->name); |
573 return; | |
574 } else if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
575 GaimBuddy *buddy = | |
576 gaim_contact_get_priority_buddy((GaimContact*)node); | |
577 gaim_conversation_new(GAIM_CONV_IM, buddy->account, buddy->name); | |
5228 | 578 return; |
579 } | |
580 } | |
581 show_im_dialog(); | |
582 } | |
583 | |
584 static void gtk_blist_button_info_cb(GtkWidget *w, GtkTreeView *tv) | |
585 { | |
586 GtkTreeIter iter; | |
587 GtkTreeModel *model = gtk_tree_view_get_model(tv); | |
588 GtkTreeSelection *sel = gtk_tree_view_get_selection(tv); | |
589 | |
590 if(gtk_tree_selection_get_selected(sel, &model, &iter)){ | |
591 GaimBlistNode *node; | |
592 | |
593 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
594 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
7620 | 595 serv_get_info(((GaimBuddy*)node)->account->gc, ((GaimBuddy*)node)->name); |
596 return; | |
597 } else if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
598 GaimBuddy *buddy = gaim_contact_get_priority_buddy((GaimContact*)node); | |
599 serv_get_info(buddy->account->gc, buddy->name); | |
5228 | 600 return; |
601 } | |
602 } | |
603 show_info_dialog(); | |
604 } | |
605 | |
5234 | 606 static void gtk_blist_button_chat_cb(GtkWidget *w, GtkTreeView *tv) |
5228 | 607 { |
5234 | 608 GtkTreeIter iter; |
609 GtkTreeModel *model = gtk_tree_view_get_model(tv); | |
610 GtkTreeSelection *sel = gtk_tree_view_get_selection(tv); | |
611 | |
612 if(gtk_tree_selection_get_selected(sel, &model, &iter)){ | |
613 GaimBlistNode *node; | |
614 | |
615 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
616 if (GAIM_BLIST_NODE_IS_CHAT(node)) { | |
7620 | 617 serv_join_chat(((GaimChat *)node)->account->gc, ((GaimChat *)node)->components); |
5234 | 618 return; |
619 } | |
620 } | |
5228 | 621 join_chat(); |
622 } | |
623 | |
624 static void gtk_blist_button_away_cb(GtkWidget *w, gpointer data) | |
625 { | |
626 gtk_menu_popup(GTK_MENU(awaymenu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); | |
627 } | |
628 | |
629 static void gtk_blist_row_expanded_cb(GtkTreeView *tv, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { | |
630 GaimBlistNode *node; | |
631 GValue val = {0,}; | |
632 | |
633 gtk_tree_model_get_value(GTK_TREE_MODEL(gtkblist->treemodel), iter, NODE_COLUMN, &val); | |
634 | |
635 node = g_value_get_pointer(&val); | |
636 | |
637 if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
7693 | 638 gaim_blist_node_set_bool(node, "collapsed", FALSE); |
5228 | 639 gaim_blist_save(); |
640 } | |
641 } | |
642 | |
643 static void gtk_blist_row_collapsed_cb(GtkTreeView *tv, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { | |
644 GaimBlistNode *node; | |
645 GValue val = {0,}; | |
646 | |
647 gtk_tree_model_get_value(GTK_TREE_MODEL(gtkblist->treemodel), iter, NODE_COLUMN, &val); | |
648 | |
649 node = g_value_get_pointer(&val); | |
650 | |
651 if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
7693 | 652 gaim_blist_node_set_bool(node, "collapsed", TRUE); |
5228 | 653 gaim_blist_save(); |
7620 | 654 } else if(GAIM_BLIST_NODE_IS_CONTACT(node)) { |
655 gaim_gtk_blist_collapse_contact_cb(NULL, node); | |
5228 | 656 } |
657 } | |
658 | |
659 static void gtk_blist_row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { | |
660 GaimBlistNode *node; | |
661 GtkTreeIter iter; | |
662 GValue val = { 0, }; | |
663 | |
664 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
665 | |
666 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
667 node = g_value_get_pointer(&val); | |
668 | |
7620 | 669 if(GAIM_BLIST_NODE_IS_CONTACT(node) || GAIM_BLIST_NODE_IS_BUDDY(node)) { |
670 GaimBuddy *buddy; | |
671 GaimConversation *conv; | |
672 | |
673 if(GAIM_BLIST_NODE_IS_CONTACT(node)) | |
674 buddy = gaim_contact_get_priority_buddy((GaimContact*)node); | |
675 else | |
676 buddy = (GaimBuddy*)node; | |
677 | |
678 conv = gaim_conversation_new(GAIM_CONV_IM, buddy->account, buddy->name); | |
5489
5b5aa701d46b
[gaim-migrate @ 5885]
Christian Hammond <chipx86@chipx86.com>
parents:
5451
diff
changeset
|
679 |
5228 | 680 if(conv) { |
7620 | 681 GaimConvWindow *win = gaim_conversation_get_window(conv); |
682 | |
683 gaim_conv_window_raise(win); | |
684 gaim_conv_window_switch_conversation( | |
5228 | 685 gaim_conversation_get_window(conv), |
686 gaim_conversation_get_index(conv)); | |
5489
5b5aa701d46b
[gaim-migrate @ 5885]
Christian Hammond <chipx86@chipx86.com>
parents:
5451
diff
changeset
|
687 |
5b5aa701d46b
[gaim-migrate @ 5885]
Christian Hammond <chipx86@chipx86.com>
parents:
5451
diff
changeset
|
688 if (GAIM_IS_GTK_WINDOW(win)) |
5b5aa701d46b
[gaim-migrate @ 5885]
Christian Hammond <chipx86@chipx86.com>
parents:
5451
diff
changeset
|
689 gtk_window_present(GTK_WINDOW(GAIM_GTK_WINDOW(win)->window)); |
5228 | 690 } |
5234 | 691 } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { |
7620 | 692 serv_join_chat(((GaimChat *)node)->account->gc, ((GaimChat *)node)->components); |
5228 | 693 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { |
694 if (gtk_tree_view_row_expanded(tv, path)) | |
695 gtk_tree_view_collapse_row(tv, path); | |
696 else | |
697 gtk_tree_view_expand_row(tv,path,FALSE); | |
698 } | |
699 } | |
700 | |
5234 | 701 static void gaim_gtk_blist_add_chat_cb() |
702 { | |
703 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)); | |
704 GtkTreeIter iter; | |
705 GaimBlistNode *node; | |
706 | |
707 if(gtk_tree_selection_get_selected(sel, NULL, &iter)){ | |
708 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
7620 | 709 if (GAIM_BLIST_NODE_IS_BUDDY(node)) |
7859 | 710 gaim_blist_request_add_chat(NULL, (GaimGroup*)node->parent->parent, NULL); |
7620 | 711 if (GAIM_BLIST_NODE_IS_CONTACT(node) || GAIM_BLIST_NODE_IS_CHAT(node)) |
7859 | 712 gaim_blist_request_add_chat(NULL, (GaimGroup*)node->parent, NULL); |
5234 | 713 else if (GAIM_BLIST_NODE_IS_GROUP(node)) |
7859 | 714 gaim_blist_request_add_chat(NULL, (GaimGroup*)node, NULL); |
5234 | 715 } |
716 else { | |
7859 | 717 gaim_blist_request_add_chat(NULL, NULL, NULL); |
5234 | 718 } |
719 } | |
720 | |
5228 | 721 static void gaim_gtk_blist_add_buddy_cb() |
722 { | |
723 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)); | |
724 GtkTreeIter iter; | |
725 GaimBlistNode *node; | |
726 | |
727 if(gtk_tree_selection_get_selected(sel, NULL, &iter)){ | |
728 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1); | |
7620 | 729 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { |
730 gaim_blist_request_add_buddy(NULL, NULL, ((GaimGroup*)node->parent->parent)->name, | |
731 NULL); | |
732 } else if (GAIM_BLIST_NODE_IS_CONTACT(node) | |
733 || GAIM_BLIST_NODE_IS_CHAT(node)) { | |
734 gaim_blist_request_add_buddy(NULL, NULL, ((GaimGroup*)node->parent)->name, NULL); | |
735 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
736 gaim_blist_request_add_buddy(NULL, NULL, ((GaimGroup*)node)->name, NULL); | |
737 } | |
5228 | 738 } |
739 else { | |
7620 | 740 gaim_blist_request_add_buddy(NULL, NULL, NULL, NULL); |
741 } | |
742 } | |
743 | |
744 static void | |
745 gaim_gtk_blist_remove_cb (GtkWidget *w, GaimBlistNode *node) | |
746 { | |
747 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
748 show_confirm_del((GaimBuddy*)node); | |
749 } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { | |
750 show_confirm_del_blist_chat((GaimChat*)node); | |
751 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
752 show_confirm_del_group((GaimGroup*)node); | |
753 } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
754 show_confirm_del_contact((GaimContact*)node); | |
5228 | 755 } |
756 } | |
757 | |
758 static void | |
7620 | 759 gaim_gtk_blist_expand_contact_cb(GtkWidget *w, GaimBlistNode *node) |
5228 | 760 { |
7620 | 761 struct _gaim_gtk_blist_node *gtknode; |
762 GaimBlistNode *bnode; | |
763 | |
764 if(!GAIM_BLIST_NODE_IS_CONTACT(node)) | |
765 return; | |
766 | |
767 gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; | |
768 | |
769 gtknode->contact_expanded = TRUE; | |
770 | |
771 for(bnode = node->child; bnode; bnode = bnode->next) { | |
772 gaim_gtk_blist_update(NULL, bnode); | |
773 } | |
774 gaim_gtk_blist_update(NULL, node); | |
775 } | |
776 | |
777 static void | |
778 gaim_gtk_blist_collapse_contact_cb(GtkWidget *w, GaimBlistNode *node) | |
779 { | |
780 GaimBlistNode *bnode; | |
781 struct _gaim_gtk_blist_node *gtknode; | |
782 | |
783 if(!GAIM_BLIST_NODE_IS_CONTACT(node)) | |
784 return; | |
785 | |
786 gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; | |
787 | |
788 gtknode->contact_expanded = FALSE; | |
789 | |
790 for(bnode = node->child; bnode; bnode = bnode->next) { | |
791 gaim_gtk_blist_update(NULL, bnode); | |
5228 | 792 } |
793 } | |
794 | |
7620 | 795 static void gaim_proto_menu_cb(GtkMenuItem *item, GaimBuddy *b) |
5228 | 796 { |
797 struct proto_buddy_menu *pbm = g_object_get_data(G_OBJECT(item), "gaimcallback"); | |
798 if (pbm->callback) | |
799 pbm->callback(pbm->gc, b->name); | |
800 } | |
801 | |
7620 | 802 static void make_buddy_menu(GtkWidget *menu, GaimPluginProtocolInfo *prpl_info, GaimBuddy *b) |
803 { | |
804 GList *list; | |
805 GtkWidget *menuitem; | |
806 | |
807 if (prpl_info && prpl_info->get_info) { | |
8137 | 808 gaim_new_item_from_stock(menu, _("Get _Info"), GAIM_STOCK_INFO, |
7620 | 809 G_CALLBACK(gtk_blist_menu_info_cb), b, 0, 0, NULL); |
810 } | |
8137 | 811 gaim_new_item_from_stock(menu, _("I_M"), GAIM_STOCK_IM, |
7620 | 812 G_CALLBACK(gtk_blist_menu_im_cb), b, 0, 0, NULL); |
813 gaim_new_item_from_stock(menu, _("Add Buddy _Pounce"), NULL, | |
814 G_CALLBACK(gtk_blist_menu_bp_cb), b, 0, 0, NULL); | |
815 gaim_new_item_from_stock(menu, _("View _Log"), NULL, | |
816 G_CALLBACK(gtk_blist_menu_showlog_cb), b, 0, 0, NULL); | |
817 | |
818 if (prpl_info && prpl_info->buddy_menu) { | |
819 list = prpl_info->buddy_menu(b->account->gc, b->name); | |
820 while (list) { | |
821 struct proto_buddy_menu *pbm = list->data; | |
822 menuitem = gtk_menu_item_new_with_mnemonic(pbm->label); | |
823 g_object_set_data(G_OBJECT(menuitem), "gaimcallback", pbm); | |
824 g_signal_connect(G_OBJECT(menuitem), "activate", | |
825 G_CALLBACK(gaim_proto_menu_cb), b); | |
826 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
827 list = list->next; | |
828 } | |
829 } | |
830 | |
831 gaim_signal_emit(GAIM_GTK_BLIST(gaim_get_blist()), | |
832 "drawing-menu", menu, b); | |
833 | |
834 gaim_separator(menu); | |
7843 | 835 gaim_new_item_from_stock(menu, _("_Alias..."), GAIM_STOCK_EDIT, |
7620 | 836 G_CALLBACK(gtk_blist_menu_alias_cb), b, 0, 0, NULL); |
837 gaim_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, | |
838 G_CALLBACK(gaim_gtk_blist_remove_cb), b, | |
839 0, 0, NULL); | |
840 } | |
841 | |
842 static gboolean gtk_blist_key_press_cb(GtkWidget *tv, GdkEventKey *event, | |
843 gpointer null) | |
844 { | |
845 GaimBlistNode *node; | |
846 GValue val = { 0, }; | |
847 GtkTreeIter iter; | |
848 GtkTreeSelection *sel; | |
849 | |
850 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); | |
851 if(!gtk_tree_selection_get_selected(sel, NULL, &iter)) | |
852 return FALSE; | |
853 | |
854 gtk_tree_model_get_value(GTK_TREE_MODEL(gtkblist->treemodel), &iter, | |
855 NODE_COLUMN, &val); | |
856 node = g_value_get_pointer(&val); | |
857 | |
858 if(event->state & GDK_CONTROL_MASK && | |
859 (event->keyval == 'o' || event->keyval == 'O')) { | |
860 GaimBuddy *buddy; | |
861 | |
862 if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
863 buddy = gaim_contact_get_priority_buddy((GaimContact*)node); | |
864 } else if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
865 buddy = (GaimBuddy*)node; | |
866 } else { | |
867 return FALSE; | |
868 } | |
869 if(buddy) | |
870 serv_get_info(buddy->account->gc, buddy->name); | |
871 } | |
872 | |
873 return FALSE; | |
874 } | |
875 | |
8143 | 876 static GtkWidget * |
877 create_group_menu (GaimBlistNode *node) | |
878 { | |
879 GtkWidget *menu; | |
880 | |
881 menu = gtk_menu_new(); | |
882 gaim_new_item_from_stock(menu, _("Add a _Buddy"), GTK_STOCK_ADD, | |
883 G_CALLBACK(gaim_gtk_blist_add_buddy_cb), node, 0, 0, NULL); | |
884 gaim_new_item_from_stock(menu, _("Add a C_hat"), GTK_STOCK_ADD, | |
885 G_CALLBACK(gaim_gtk_blist_add_chat_cb), node, 0, 0, NULL); | |
886 gaim_new_item_from_stock(menu, _("_Delete Group"), GTK_STOCK_REMOVE, | |
887 G_CALLBACK(gaim_gtk_blist_remove_cb), node, 0, 0, NULL); | |
888 gaim_new_item_from_stock(menu, _("_Rename"), NULL, | |
889 G_CALLBACK(show_rename_group), node, 0, 0, NULL); | |
890 return menu; | |
891 } | |
892 | |
893 static GtkWidget * | |
894 create_chat_menu (GaimBlistNode *node) | |
895 { | |
896 GtkWidget *menu; | |
8197 | 897 gboolean autojoin = (gaim_blist_node_get_bool(node, |
8198 | 898 "gtk-autojoin") || (gaim_blist_node_get_string(node, |
899 "gtk-autojoin") != NULL)); | |
8143 | 900 |
901 menu = gtk_menu_new(); | |
902 gaim_new_item_from_stock(menu, _("_Join"), GAIM_STOCK_CHAT, | |
903 G_CALLBACK(gtk_blist_menu_join_cb), node, 0, 0, NULL); | |
904 gaim_new_check_item(menu, _("Auto-Join"), | |
905 G_CALLBACK(gtk_blist_menu_autojoin_cb), node, | |
906 autojoin); | |
907 gaim_new_item_from_stock(menu, _("_Alias..."), GAIM_STOCK_EDIT, | |
908 G_CALLBACK(gtk_blist_menu_alias_cb), node, 0, 0, NULL); | |
909 gaim_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, | |
910 G_CALLBACK(gaim_gtk_blist_remove_cb), node, 0, 0, NULL); | |
911 return menu; | |
912 } | |
913 | |
914 static GtkWidget * | |
915 create_contact_menu (GaimBlistNode *node) | |
916 { | |
917 GtkWidget *menu; | |
918 | |
919 menu = gtk_menu_new(); | |
920 gaim_new_item_from_stock(menu, _("_Alias..."), GAIM_STOCK_EDIT, | |
921 G_CALLBACK(gtk_blist_menu_alias_cb), node, 0, 0, NULL); | |
922 gaim_new_item_from_stock(menu, _("_Collapse"), GTK_STOCK_ZOOM_OUT, | |
923 G_CALLBACK(gaim_gtk_blist_collapse_contact_cb), | |
924 node, 0, 0, NULL); | |
925 gaim_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, | |
926 G_CALLBACK(gaim_gtk_blist_remove_cb), node, 0, 0, NULL); | |
927 return menu; | |
928 } | |
929 | |
930 static GtkWidget * | |
931 create_buddy_menu (GaimBlistNode *node, | |
932 GaimBuddy *b, | |
933 GaimPlugin *prpl, | |
934 GaimPluginProtocolInfo *prpl_info) | |
935 { | |
936 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; | |
937 GtkWidget *menu; | |
938 GtkWidget *menuitem; | |
939 gboolean show_offline = gaim_prefs_get_bool("/gaim/gtk/blist/show_offline_buddies"); | |
940 | |
941 menu = gtk_menu_new(); | |
942 make_buddy_menu(menu, prpl_info, b); | |
943 | |
944 if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
945 gaim_separator(menu); | |
946 | |
947 if(gtknode->contact_expanded) { | |
948 gaim_new_item_from_stock(menu, _("_Collapse"), | |
949 GTK_STOCK_ZOOM_OUT, | |
950 G_CALLBACK(gaim_gtk_blist_collapse_contact_cb), | |
951 node, 0, 0, NULL); | |
952 } else { | |
953 gaim_new_item_from_stock(menu, _("_Expand"), | |
954 GTK_STOCK_ZOOM_IN, | |
955 G_CALLBACK(gaim_gtk_blist_expand_contact_cb), node, | |
956 0, 0, NULL); | |
957 } | |
958 if(node->child->next) { | |
959 GaimBlistNode *bnode; | |
960 | |
961 for(bnode = node->child; bnode; bnode = bnode->next) { | |
962 GaimBuddy *buddy = (GaimBuddy*)bnode; | |
963 GtkWidget *submenu; | |
964 GtkWidget *image; | |
965 | |
966 if(buddy == b) | |
967 continue; | |
968 if(!buddy->account->gc) | |
969 continue; | |
970 if(!show_offline && !GAIM_BUDDY_IS_ONLINE(buddy)) | |
971 continue; | |
972 | |
973 menuitem = gtk_image_menu_item_new_with_label(buddy->name); | |
974 image = gtk_image_new_from_pixbuf( | |
975 gaim_gtk_blist_get_status_icon(bnode, | |
976 GAIM_STATUS_ICON_SMALL)); | |
977 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), | |
978 image); | |
979 gtk_widget_show(image); | |
980 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
981 gtk_widget_show(menuitem); | |
982 | |
983 submenu = gtk_menu_new(); | |
984 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); | |
985 gtk_widget_show(submenu); | |
986 | |
987 prpl = gaim_find_prpl(gaim_account_get_protocol_id(buddy->account)); | |
988 prpl_info = prpl ? GAIM_PLUGIN_PROTOCOL_INFO(prpl) : NULL; | |
989 | |
990 make_buddy_menu(submenu, prpl_info, buddy); | |
991 } | |
992 } | |
993 } | |
994 return menu; | |
995 } | |
996 | |
997 static gboolean | |
998 gaim_gtk_blist_show_context_menu(GaimBlistNode *node, | |
999 GtkMenuPositionFunc func, | |
1000 GtkWidget *tv, | |
1001 guint button, | |
1002 guint32 time) | |
1003 { | |
1004 struct _gaim_gtk_blist_node *gtknode; | |
1005 GtkWidget *menu = NULL; | |
1006 gboolean handled = FALSE; | |
1007 | |
1008 gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; | |
1009 | |
1010 /* Create a menu based on the thing we right-clicked on */ | |
1011 if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
1012 menu = create_group_menu(node); | |
1013 } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { | |
1014 menu = create_chat_menu(node); | |
1015 } else if ((GAIM_BLIST_NODE_IS_CONTACT(node)) && (gtknode->contact_expanded)) { | |
1016 menu = create_contact_menu(node); | |
1017 } else if (GAIM_BLIST_NODE_IS_CONTACT(node) || GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
1018 GaimBuddy *b; | |
1019 GaimPlugin *prpl = NULL; | |
1020 GaimPluginProtocolInfo *prpl_info = NULL; | |
1021 | |
1022 if (GAIM_BLIST_NODE_IS_CONTACT(node)) | |
1023 b = gaim_contact_get_priority_buddy((GaimContact*)node); | |
1024 else | |
1025 b = (GaimBuddy *)node; | |
1026 | |
1027 prpl = gaim_find_prpl(gaim_account_get_protocol_id(b->account)); | |
1028 if (prpl != NULL) | |
1029 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); | |
1030 menu = create_buddy_menu(node, b, prpl, prpl_info); | |
1031 } | |
1032 | |
1033 /* Now display the menu */ | |
1034 if (menu != NULL) { | |
1035 gtk_widget_show_all(menu); | |
1036 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, func, tv, button, time); | |
1037 handled = TRUE; | |
1038 } | |
1039 | |
1040 return handled; | |
1041 } | |
1042 | |
1043 static gboolean gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer user_data) | |
5228 | 1044 { |
1045 GtkTreePath *path; | |
1046 GaimBlistNode *node; | |
1047 GValue val = { 0, }; | |
1048 GtkTreeIter iter; | |
1049 GtkTreeSelection *sel; | |
1050 GaimPlugin *prpl = NULL; | |
1051 GaimPluginProtocolInfo *prpl_info = NULL; | |
7620 | 1052 struct _gaim_gtk_blist_node *gtknode; |
1053 gboolean handled = FALSE; | |
5228 | 1054 |
1055 /* Here we figure out which node was clicked */ | |
1056 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL)) | |
1057 return FALSE; | |
1058 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
8143 | 1059 gtk_tree_model_get_value(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); |
5228 | 1060 node = g_value_get_pointer(&val); |
7620 | 1061 gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; |
1062 | |
8143 | 1063 /* Right click draws a context menu */ |
1064 if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS)) { | |
1065 handled = gaim_gtk_blist_show_context_menu(node, NULL, tv, 3, event->time); | |
1066 | |
1067 /* CTRL+middle click expands or collapse a contact */ | |
1068 } else if ((event->button == 2) && (event->type == GDK_BUTTON_PRESS) && | |
1069 (event->state & GDK_CONTROL_MASK) && (GAIM_BLIST_NODE_IS_CONTACT(node))) { | |
1070 if (gtknode->contact_expanded) | |
7620 | 1071 gaim_gtk_blist_collapse_contact_cb(NULL, node); |
1072 else | |
1073 gaim_gtk_blist_expand_contact_cb(NULL, node); | |
1074 handled = TRUE; | |
8143 | 1075 |
1076 /* Double middle click gets info */ | |
1077 } else if ((event->button == 2) && (event->type == GDK_2BUTTON_PRESS) && | |
1078 ((GAIM_BLIST_NODE_IS_CONTACT(node)) || (GAIM_BLIST_NODE_IS_BUDDY(node)))) { | |
7620 | 1079 GaimBuddy *b; |
1080 if(GAIM_BLIST_NODE_IS_CONTACT(node)) | |
1081 b = gaim_contact_get_priority_buddy((GaimContact*)node); | |
1082 else | |
1083 b = (GaimBuddy *)node; | |
1084 | |
7956 | 1085 prpl = gaim_find_prpl(gaim_account_get_protocol_id(b->account)); |
5228 | 1086 if (prpl != NULL) |
1087 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); | |
1088 | |
8143 | 1089 if (prpl && prpl_info->get_info) |
1090 serv_get_info(b->account->gc, b->name); | |
1091 handled = TRUE; | |
5228 | 1092 } |
1093 | |
8143 | 1094 #if (1) |
1095 /* | |
1096 * This code only exists because GTK doesn't work. If we return | |
1097 * FALSE here, as would be normal the event propoagates down and | |
1098 * somehow gets interpreted as the start of a drag event. | |
1099 * | |
1100 * Um, isn't it _normal_ to return TRUE here? Since the event | |
1101 * was handled? --Mark | |
1102 */ | |
7620 | 1103 if(handled) { |
1104 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); | |
1105 gtk_tree_selection_select_path(sel, path); | |
1106 gtk_tree_path_free(path); | |
1107 return TRUE; | |
1108 } | |
5228 | 1109 #endif |
7753 | 1110 gtk_tree_path_free(path); |
8143 | 1111 |
7620 | 1112 return FALSE; |
5228 | 1113 } |
1114 | |
8143 | 1115 static gboolean |
1116 gaim_gtk_blist_popup_menu_cb(GtkWidget *tv, void *user_data) | |
1117 { | |
1118 GaimBlistNode *node; | |
1119 GValue val = { 0, }; | |
1120 GtkTreeIter iter; | |
1121 GtkTreeSelection *sel; | |
1122 gboolean handled = FALSE; | |
1123 | |
1124 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); | |
1125 if (!gtk_tree_selection_get_selected(sel, NULL, &iter)) | |
1126 return FALSE; | |
1127 | |
1128 gtk_tree_model_get_value(GTK_TREE_MODEL(gtkblist->treemodel), | |
1129 &iter, NODE_COLUMN, &val); | |
1130 node = g_value_get_pointer(&val); | |
1131 | |
1132 /* Shift+F10 draws a context menu */ | |
1133 handled = gaim_gtk_blist_show_context_menu(node, gaim_gtk_treeview_popup_menu_position_func, tv, 0, GDK_CURRENT_TIME); | |
1134 | |
1135 return handled; | |
1136 } | |
1137 | |
5228 | 1138 static void gaim_gtk_blist_show_empty_groups_cb(gpointer data, guint action, GtkWidget *item) |
1139 { | |
7620 | 1140 gaim_prefs_set_bool("/gaim/gtk/blist/show_empty_groups", |
1141 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item))); | |
5228 | 1142 } |
1143 | |
1144 static void gaim_gtk_blist_edit_mode_cb(gpointer callback_data, guint callback_action, | |
1145 GtkWidget *checkitem) { | |
1146 if(gtkblist->window->window) { | |
1147 GdkCursor *cursor = gdk_cursor_new(GDK_WATCH); | |
1148 gdk_window_set_cursor(gtkblist->window->window, cursor); | |
1149 while (gtk_events_pending()) | |
1150 gtk_main_iteration(); | |
1151 gdk_cursor_unref(cursor); | |
1152 } | |
1153 | |
7620 | 1154 gaim_prefs_set_bool("/gaim/gtk/blist/show_offline_buddies", |
1155 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(checkitem))); | |
5228 | 1156 |
1157 if(gtkblist->window->window) { | |
1158 GdkCursor *cursor = gdk_cursor_new(GDK_LEFT_PTR); | |
1159 gdk_window_set_cursor(gtkblist->window->window, cursor); | |
1160 gdk_cursor_unref(cursor); | |
1161 } | |
1162 } | |
1163 | |
8089 | 1164 static void |
1165 add_buddies_from_vcard(const char *prpl_id, GaimGroup *group, GList *list, | |
1166 const char *alias) | |
1167 { | |
1168 GList *l; | |
1169 GaimAccount *account = NULL; | |
1170 GaimConnection *gc; | |
1171 | |
1172 if (list == NULL) | |
1173 return; | |
1174 | |
1175 for (l = gaim_connections_get_all(); l != NULL; l = l->next) | |
1176 { | |
1177 gc = (GaimConnection *)l->data; | |
1178 account = gaim_connection_get_account(gc); | |
1179 | |
1180 if (!strcmp(gaim_account_get_protocol_id(account), prpl_id)) | |
1181 break; | |
1182 | |
1183 account = NULL; | |
1184 } | |
1185 | |
1186 if (account != NULL) | |
1187 { | |
1188 for (l = list; l != NULL; l = l->next) | |
1189 { | |
1190 gaim_blist_request_add_buddy(account, l->data, | |
1191 (group ? group->name : NULL), | |
1192 alias); | |
1193 } | |
1194 } | |
1195 | |
1196 g_list_foreach(list, (GFunc)g_free, NULL); | |
1197 g_list_free(list); | |
1198 } | |
1199 | |
1200 static gboolean | |
1201 parse_vcard(const char *vcard, GaimGroup *group) | |
1202 { | |
1203 char *temp_vcard; | |
1204 char *s, *c; | |
1205 char *alias = NULL; | |
1206 GList *aims = NULL; | |
1207 GList *icqs = NULL; | |
1208 GList *yahoos = NULL; | |
1209 GList *msns = NULL; | |
1210 GList *jabbers = NULL; | |
1211 | |
1212 s = temp_vcard = g_strdup(vcard); | |
1213 | |
1214 while (*s != '\0' && strncmp(s, "END:vCard", strlen("END:vCard"))) | |
1215 { | |
1216 char *field, *value; | |
1217 | |
1218 field = s; | |
1219 | |
1220 /* Grab the field */ | |
1221 while (*s != '\r' && *s != '\n' && *s != '\0' && *s != ':') | |
1222 s++; | |
1223 | |
1224 if (*s == '\r') s++; | |
1225 if (*s == '\n') | |
1226 { | |
1227 s++; | |
1228 continue; | |
1229 } | |
1230 | |
1231 if (*s != '\0') *s++ = '\0'; | |
1232 | |
1233 if ((c = strchr(field, ';')) != NULL) | |
1234 *c = '\0'; | |
1235 | |
1236 /* Proceed to the end of the line */ | |
1237 value = s; | |
1238 | |
1239 while (*s != '\r' && *s != '\n' && *s != '\0') | |
1240 s++; | |
1241 | |
1242 if (*s == '\r') *s++ = '\0'; | |
1243 if (*s == '\n') *s++ = '\0'; | |
1244 | |
1245 /* We only want to worry about a few fields here. */ | |
1246 if (!strcmp(field, "FN")) | |
1247 alias = g_strdup(value); | |
1248 else if (!strcmp(field, "X-AIM") || !strcmp(field, "X-ICQ") || | |
1249 !strcmp(field, "X-YAHOO") || !strcmp(field, "X-MSN") || | |
1250 !strcmp(field, "X-JABBER")) | |
1251 { | |
1252 char **values = g_strsplit(value, ":", 0); | |
1253 char **im; | |
1254 | |
1255 for (im = values; *im != NULL; im++) | |
1256 { | |
1257 if (!strcmp(field, "X-AIM")) | |
1258 aims = g_list_append(aims, g_strdup(*im)); | |
1259 else if (!strcmp(field, "X-ICQ")) | |
1260 icqs = g_list_append(icqs, g_strdup(*im)); | |
1261 else if (!strcmp(field, "X-YAHOO")) | |
1262 yahoos = g_list_append(yahoos, g_strdup(*im)); | |
1263 else if (!strcmp(field, "X-MSN")) | |
1264 msns = g_list_append(msns, g_strdup(*im)); | |
1265 else if (!strcmp(field, "X-JABBER")) | |
1266 jabbers = g_list_append(jabbers, g_strdup(*im)); | |
1267 } | |
1268 | |
1269 g_strfreev(values); | |
1270 } | |
1271 } | |
1272 | |
1273 g_free(temp_vcard); | |
1274 | |
1275 if (aims == NULL && icqs == NULL && yahoos == NULL && | |
1276 msns == NULL && jabbers == NULL) | |
1277 { | |
1278 if (alias != NULL) | |
1279 g_free(alias); | |
1280 | |
1281 return FALSE; | |
1282 } | |
1283 | |
1284 add_buddies_from_vcard("prpl-oscar", group, aims, alias); | |
1285 add_buddies_from_vcard("prpl-oscar", group, icqs, alias); | |
1286 add_buddies_from_vcard("prpl-yahoo", group, yahoos, alias); | |
1287 add_buddies_from_vcard("prpl-msn", group, msns, alias); | |
1288 add_buddies_from_vcard("prpl-jabber", group, jabbers, alias); | |
1289 | |
1290 if (alias != NULL) | |
1291 g_free(alias); | |
1292 | |
1293 return TRUE; | |
1294 } | |
1295 | |
5228 | 1296 static void gaim_gtk_blist_drag_data_get_cb (GtkWidget *widget, |
1297 GdkDragContext *dc, | |
1298 GtkSelectionData *data, | |
1299 guint info, | |
1300 guint time, | |
1301 gpointer *null) | |
1302 { | |
8089 | 1303 if (data->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE)) |
1304 { | |
5228 | 1305 GtkTreeRowReference *ref = g_object_get_data(G_OBJECT(dc), "gtk-tree-view-source-row"); |
1306 GtkTreePath *sourcerow = gtk_tree_row_reference_get_path(ref); | |
1307 GtkTreeIter iter; | |
1308 GaimBlistNode *node = NULL; | |
1309 GValue val = {0}; | |
5273 | 1310 if(!sourcerow) |
1311 return; | |
5228 | 1312 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, sourcerow); |
1313 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
1314 node = g_value_get_pointer(&val); | |
1315 gtk_selection_data_set (data, | |
1316 gdk_atom_intern ("GAIM_BLIST_NODE", FALSE), | |
1317 8, /* bits */ | |
1318 (void*)&node, | |
1319 sizeof (node)); | |
5273 | 1320 |
5228 | 1321 gtk_tree_path_free(sourcerow); |
1322 } | |
8089 | 1323 else if (data->target == gdk_atom_intern("application/x-im-contact", FALSE)) |
1324 { | |
7706 | 1325 GtkTreeRowReference *ref; |
1326 GtkTreePath *sourcerow; | |
1327 GtkTreeIter iter; | |
1328 GaimBlistNode *node = NULL; | |
1329 GaimBuddy *buddy; | |
1330 GaimConnection *gc; | |
1331 GValue val = {0}; | |
1332 GString *str; | |
1333 const char *protocol; | |
1334 char *mime_str; | |
1335 | |
1336 ref = g_object_get_data(G_OBJECT(dc), "gtk-tree-view-source-row"); | |
1337 sourcerow = gtk_tree_row_reference_get_path(ref); | |
1338 | |
1339 if (!sourcerow) | |
1340 return; | |
1341 | |
1342 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, | |
1343 sourcerow); | |
1344 gtk_tree_model_get_value(GTK_TREE_MODEL(gtkblist->treemodel), &iter, | |
1345 NODE_COLUMN, &val); | |
1346 | |
1347 node = g_value_get_pointer(&val); | |
1348 | |
1349 if (GAIM_BLIST_NODE_IS_CONTACT(node)) | |
1350 { | |
1351 buddy = gaim_contact_get_priority_buddy((GaimContact *)node); | |
1352 } | |
1353 else if (!GAIM_BLIST_NODE_IS_BUDDY(node)) | |
1354 { | |
1355 gtk_tree_path_free(sourcerow); | |
1356 return; | |
1357 } | |
1358 else | |
1359 { | |
1360 buddy = (GaimBuddy *)node; | |
1361 } | |
1362 | |
1363 gc = gaim_account_get_connection(buddy->account); | |
1364 | |
1365 if (gc == NULL) | |
1366 { | |
1367 gtk_tree_path_free(sourcerow); | |
1368 return; | |
1369 } | |
1370 | |
1371 protocol = | |
1372 GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->list_icon(buddy->account, | |
1373 buddy); | |
1374 | |
1375 str = g_string_new(NULL); | |
1376 g_string_printf(str, | |
1377 "MIME-Version: 1.0\r\n" | |
1378 "Content-Type: application/x-im-contact\r\n" | |
1379 "X-IM-Protocol: %s\r\n" | |
1380 "X-IM-Username: %s\r\n", | |
1381 protocol, | |
1382 buddy->name); | |
1383 | |
1384 if (buddy->alias != NULL) | |
1385 { | |
1386 g_string_append_printf(str, | |
1387 "X-IM-Alias: %s\r\n", | |
1388 buddy->alias); | |
1389 } | |
1390 | |
1391 str = g_string_append(str, "\r\n"); | |
1392 | |
1393 mime_str = g_string_free(str, FALSE); | |
1394 | |
1395 gtk_selection_data_set(data, | |
1396 gdk_atom_intern("application/x-im-contact", FALSE), | |
1397 8, /* bits */ | |
1398 mime_str, | |
1399 strlen(mime_str) + 1); | |
1400 | |
1401 g_free(mime_str); | |
1402 gtk_tree_path_free(sourcerow); | |
1403 } | |
5228 | 1404 } |
1405 | |
1406 static void gaim_gtk_blist_drag_data_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, | |
1407 GtkSelectionData *sd, guint info, guint t) | |
7620 | 1408 { |
5228 | 1409 if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE) && sd->data) { |
1410 GaimBlistNode *n = NULL; | |
1411 GtkTreePath *path = NULL; | |
1412 GtkTreeViewDropPosition position; | |
1413 memcpy(&n, sd->data, sizeof(n)); | |
1414 if(gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), x, y, &path, &position)) { | |
7636 | 1415 /* if we're here, I think it means the drop is ok */ |
7642 | 1416 GtkTreeIter iter; |
5228 | 1417 GaimBlistNode *node; |
1418 GValue val = {0}; | |
7620 | 1419 struct _gaim_gtk_blist_node *gtknode; |
1420 | |
1421 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), | |
1422 &iter, path); | |
1423 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), | |
1424 &iter, NODE_COLUMN, &val); | |
5228 | 1425 node = g_value_get_pointer(&val); |
7620 | 1426 gtknode = node->ui_data; |
1427 | |
1428 if (GAIM_BLIST_NODE_IS_CONTACT(n)) { | |
1429 GaimContact *c = (GaimContact*)n; | |
1430 if (GAIM_BLIST_NODE_IS_CONTACT(node) && gtknode->contact_expanded) { | |
1431 gaim_blist_merge_contact(c, node); | |
1432 } else if (GAIM_BLIST_NODE_IS_CONTACT(node) || | |
5234 | 1433 GAIM_BLIST_NODE_IS_CHAT(node)) { |
5228 | 1434 switch(position) { |
1435 case GTK_TREE_VIEW_DROP_AFTER: | |
1436 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
7620 | 1437 gaim_blist_add_contact(c, (GaimGroup*)node->parent, |
1438 node); | |
1439 break; | |
1440 case GTK_TREE_VIEW_DROP_BEFORE: | |
1441 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
1442 gaim_blist_add_contact(c, (GaimGroup*)node->parent, | |
1443 node->prev); | |
1444 break; | |
1445 } | |
1446 } else if(GAIM_BLIST_NODE_IS_GROUP(node)) { | |
1447 gaim_blist_add_contact(c, (GaimGroup*)node, NULL); | |
1448 } else if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
1449 gaim_blist_merge_contact(c, node); | |
1450 } | |
1451 } else if (GAIM_BLIST_NODE_IS_BUDDY(n)) { | |
1452 GaimBuddy *b = (GaimBuddy*)n; | |
1453 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
1454 switch(position) { | |
1455 case GTK_TREE_VIEW_DROP_AFTER: | |
1456 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
1457 gaim_blist_add_buddy(b, (GaimContact*)node->parent, | |
1458 (GaimGroup*)node->parent->parent, node); | |
5228 | 1459 break; |
1460 case GTK_TREE_VIEW_DROP_BEFORE: | |
1461 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
7620 | 1462 gaim_blist_add_buddy(b, (GaimContact*)node->parent, |
1463 (GaimGroup*)node->parent->parent, | |
1464 node->prev); | |
5228 | 1465 break; |
1466 } | |
7620 | 1467 } else if(GAIM_BLIST_NODE_IS_CHAT(node)) { |
1468 gaim_blist_add_buddy(b, NULL, (GaimGroup*)node->parent, | |
1469 NULL); | |
5228 | 1470 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { |
7620 | 1471 gaim_blist_add_buddy(b, NULL, (GaimGroup*)node, NULL); |
1472 } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
1473 if(gtknode->contact_expanded) { | |
1474 switch(position) { | |
1475 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
1476 case GTK_TREE_VIEW_DROP_AFTER: | |
1477 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
1478 gaim_blist_add_buddy(b, (GaimContact*)node, | |
1479 (GaimGroup*)node->parent, NULL); | |
1480 break; | |
1481 case GTK_TREE_VIEW_DROP_BEFORE: | |
1482 gaim_blist_add_buddy(b, NULL, | |
1483 (GaimGroup*)node->parent, node->prev); | |
1484 break; | |
1485 } | |
1486 } else { | |
1487 switch(position) { | |
1488 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
1489 case GTK_TREE_VIEW_DROP_AFTER: | |
1490 gaim_blist_add_buddy(b, NULL, | |
1491 (GaimGroup*)node->parent, NULL); | |
1492 break; | |
1493 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
1494 case GTK_TREE_VIEW_DROP_BEFORE: | |
1495 gaim_blist_add_buddy(b, NULL, | |
1496 (GaimGroup*)node->parent, node->prev); | |
1497 break; | |
1498 } | |
1499 } | |
5228 | 1500 } |
5234 | 1501 } else if (GAIM_BLIST_NODE_IS_CHAT(n)) { |
7620 | 1502 GaimChat *chat = (GaimChat *)n; |
1503 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
1504 switch(position) { | |
1505 case GTK_TREE_VIEW_DROP_AFTER: | |
1506 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
1507 gaim_blist_add_chat(chat, | |
1508 (GaimGroup*)node->parent->parent, node); | |
1509 break; | |
1510 case GTK_TREE_VIEW_DROP_BEFORE: | |
1511 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
1512 gaim_blist_add_chat(chat, | |
1513 (GaimGroup*)node->parent->parent, | |
1514 node->prev); | |
1515 break; | |
1516 } | |
1517 } else if(GAIM_BLIST_NODE_IS_CONTACT(node) || | |
5234 | 1518 GAIM_BLIST_NODE_IS_CHAT(node)) { |
1519 switch(position) { | |
1520 case GTK_TREE_VIEW_DROP_AFTER: | |
1521 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
7620 | 1522 gaim_blist_add_chat(chat, (GaimGroup*)node->parent, node); |
5234 | 1523 break; |
1524 case GTK_TREE_VIEW_DROP_BEFORE: | |
1525 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
7620 | 1526 gaim_blist_add_chat(chat, (GaimGroup*)node->parent, node->prev); |
5234 | 1527 break; |
1528 } | |
1529 } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { | |
7620 | 1530 gaim_blist_add_chat(chat, (GaimGroup*)node, NULL); |
5234 | 1531 } |
5228 | 1532 } else if (GAIM_BLIST_NODE_IS_GROUP(n)) { |
7620 | 1533 GaimGroup *g = (GaimGroup*)n; |
5228 | 1534 if (GAIM_BLIST_NODE_IS_GROUP(node)) { |
1535 switch (position) { | |
1536 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: | |
1537 case GTK_TREE_VIEW_DROP_AFTER: | |
1538 gaim_blist_add_group(g, node); | |
1539 break; | |
1540 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: | |
1541 case GTK_TREE_VIEW_DROP_BEFORE: | |
1542 gaim_blist_add_group(g, node->prev); | |
1543 break; | |
1544 } | |
7620 | 1545 } else if(GAIM_BLIST_NODE_IS_BUDDY(node)) { |
1546 gaim_blist_add_group(g, node->parent->parent); | |
1547 } else if(GAIM_BLIST_NODE_IS_CONTACT(node) || | |
5234 | 1548 GAIM_BLIST_NODE_IS_CHAT(node)) { |
5228 | 1549 gaim_blist_add_group(g, node->parent); |
1550 } | |
1551 } | |
1552 | |
1553 gtk_tree_path_free(path); | |
7620 | 1554 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); |
1555 | |
5228 | 1556 gaim_blist_save(); |
1557 } | |
1558 } | |
7706 | 1559 else if (sd->target == gdk_atom_intern("application/x-im-contact", |
1560 FALSE) && sd->data) | |
1561 { | |
1562 GaimGroup *group = NULL; | |
1563 GtkTreePath *path = NULL; | |
1564 GtkTreeViewDropPosition position; | |
7712
2823111061ba
[gaim-migrate @ 8357]
Christian Hammond <chipx86@chipx86.com>
parents:
7706
diff
changeset
|
1565 GaimAccount *account; |
7706 | 1566 char *protocol = NULL; |
1567 char *username = NULL; | |
1568 char *alias = NULL; | |
1569 | |
1570 if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), | |
1571 x, y, &path, &position)) | |
1572 { | |
1573 GtkTreeIter iter; | |
1574 GaimBlistNode *node; | |
1575 GValue val = {0}; | |
1576 | |
1577 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), | |
1578 &iter, path); | |
1579 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), | |
1580 &iter, NODE_COLUMN, &val); | |
1581 node = g_value_get_pointer(&val); | |
1582 | |
1583 if (GAIM_BLIST_NODE_IS_BUDDY(node)) | |
1584 { | |
1585 group = (GaimGroup *)node->parent->parent; | |
1586 } | |
1587 else if (GAIM_BLIST_NODE_IS_CHAT(node) || | |
1588 GAIM_BLIST_NODE_IS_CONTACT(node)) | |
1589 { | |
1590 group = (GaimGroup *)node->parent; | |
1591 } | |
1592 else if (GAIM_BLIST_NODE_IS_GROUP(node)) | |
1593 { | |
1594 group = (GaimGroup *)node; | |
1595 } | |
1596 } | |
1597 | |
7712
2823111061ba
[gaim-migrate @ 8357]
Christian Hammond <chipx86@chipx86.com>
parents:
7706
diff
changeset
|
1598 if (gaim_gtk_parse_x_im_contact(sd->data, FALSE, &account, |
2823111061ba
[gaim-migrate @ 8357]
Christian Hammond <chipx86@chipx86.com>
parents:
7706
diff
changeset
|
1599 &protocol, &username, &alias)) |
7706 | 1600 { |
1601 if (account == NULL) | |
1602 { | |
1603 gaim_notify_error(NULL, NULL, | |
1604 _("You are not currently signed on with an account that " | |
1605 "can add that buddy."), NULL); | |
1606 } | |
1607 else | |
1608 { | |
1609 gaim_blist_request_add_buddy(account, username, | |
1610 (group ? group->name : NULL), | |
1611 alias); | |
1612 } | |
1613 } | |
1614 | |
1615 if (username != NULL) g_free(username); | |
1616 if (protocol != NULL) g_free(protocol); | |
1617 if (alias != NULL) g_free(alias); | |
1618 | |
1619 if (path != NULL) | |
1620 gtk_tree_path_free(path); | |
1621 | |
1622 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); | |
1623 } | |
8089 | 1624 else if (sd->target == gdk_atom_intern("text/x-vcard", FALSE) && sd->data) |
1625 { | |
1626 gboolean result; | |
1627 GaimGroup *group = NULL; | |
1628 GtkTreePath *path = NULL; | |
1629 GtkTreeViewDropPosition position; | |
1630 | |
1631 if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), | |
1632 x, y, &path, &position)) | |
1633 { | |
1634 GtkTreeIter iter; | |
1635 GaimBlistNode *node; | |
1636 GValue val = {0}; | |
1637 | |
1638 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), | |
1639 &iter, path); | |
1640 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), | |
1641 &iter, NODE_COLUMN, &val); | |
1642 node = g_value_get_pointer(&val); | |
1643 | |
1644 if (GAIM_BLIST_NODE_IS_BUDDY(node)) | |
1645 { | |
1646 group = (GaimGroup *)node->parent->parent; | |
1647 } | |
1648 else if (GAIM_BLIST_NODE_IS_CHAT(node) || | |
1649 GAIM_BLIST_NODE_IS_CONTACT(node)) | |
1650 { | |
1651 group = (GaimGroup *)node->parent; | |
1652 } | |
1653 else if (GAIM_BLIST_NODE_IS_GROUP(node)) | |
1654 { | |
1655 group = (GaimGroup *)node; | |
1656 } | |
1657 } | |
1658 | |
1659 result = parse_vcard(sd->data, group); | |
1660 | |
1661 gtk_drag_finish(dc, result, (dc->action == GDK_ACTION_MOVE), t); | |
1662 } | |
5228 | 1663 } |
1664 | |
5234 | 1665 static void gaim_gtk_blist_paint_tip(GtkWidget *widget, GdkEventExpose *event, GaimBlistNode *node) |
5228 | 1666 { |
1667 GtkStyle *style; | |
5234 | 1668 GdkPixbuf *pixbuf = gaim_gtk_blist_get_status_icon(node, GAIM_STATUS_ICON_LARGE); |
5228 | 1669 PangoLayout *layout; |
5234 | 1670 char *tooltiptext = gaim_get_tooltip_text(node); |
5228 | 1671 |
7620 | 1672 if(!tooltiptext) |
1673 return; | |
1674 | |
5228 | 1675 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL); |
1676 pango_layout_set_markup(layout, tooltiptext, strlen(tooltiptext)); | |
1677 pango_layout_set_wrap(layout, PANGO_WRAP_WORD); | |
1678 pango_layout_set_width(layout, 300000); | |
1679 style = gtkblist->tipwindow->style; | |
1680 | |
1681 gtk_paint_flat_box (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, | |
1682 NULL, gtkblist->tipwindow, "tooltip", 0, 0, -1, -1); | |
1683 | |
1684 #if GTK_CHECK_VERSION(2,2,0) | |
1685 gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, pixbuf, | |
1686 0, 0, 4, 4, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0); | |
1687 #else | |
1688 gdk_pixbuf_render_to_drawable(pixbuf, GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, 0, 0, 4, 4, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); | |
1689 #endif | |
1690 | |
1691 gtk_paint_layout (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, TRUE, | |
1692 NULL, gtkblist->tipwindow, "tooltip", 38, 4, layout); | |
1693 | |
1694 g_object_unref (pixbuf); | |
1695 g_object_unref (layout); | |
1696 g_free(tooltiptext); | |
7620 | 1697 |
7662 | 1698 #ifdef WANT_DROP_SHADOW |
8040 | 1699 shadow_paint(gtkblist, NULL, EAST_SIDE); |
1700 shadow_paint(gtkblist, NULL, SOUTH_SIDE); | |
7620 | 1701 #endif |
1702 | |
5228 | 1703 return; |
1704 } | |
1705 | |
1706 static gboolean gaim_gtk_blist_tooltip_timeout(GtkWidget *tv) | |
1707 { | |
1708 GtkTreePath *path; | |
1709 GtkTreeIter iter; | |
1710 GaimBlistNode *node; | |
1711 GValue val = {0}; | |
5234 | 1712 int scr_w,scr_h, w, h, x, y; |
1713 PangoLayout *layout; | |
7636 | 1714 gboolean tooltip_top = FALSE; |
5234 | 1715 char *tooltiptext = NULL; |
7636 | 1716 struct _gaim_gtk_blist_node *gtknode; |
7662 | 1717 #ifdef WANT_DROP_SHADOW |
7620 | 1718 GdkWindowAttr attr; |
1719 #endif | |
5228 | 1720 |
7636 | 1721 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y, &path, NULL, NULL, NULL)) |
5228 | 1722 return FALSE; |
1723 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
1724 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
1725 node = g_value_get_pointer(&val); | |
7620 | 1726 |
1727 if(!GAIM_BLIST_NODE_IS_CONTACT(node) && !GAIM_BLIST_NODE_IS_BUDDY(node) | |
1728 && !GAIM_BLIST_NODE_IS_CHAT(node)) | |
5234 | 1729 return FALSE; |
5228 | 1730 |
7636 | 1731 gtknode = node->ui_data; |
1732 | |
7731 | 1733 if (node->child && GAIM_BLIST_NODE_IS_CONTACT(node) && |
1734 ((GaimContact*)node)->online > 1 && !gtknode->contact_expanded && | |
1735 gaim_prefs_get_bool("/gaim/gtk/blist/auto_expand_contacts")) { | |
7719 | 1736 GtkTreeIter i; |
7636 | 1737 gaim_gtk_blist_expand_contact_cb(NULL, node); |
8083 | 1738 tooltip_top = TRUE; /* When the person expands, the new screennames will be below. |
1739 We'll draw the tip above the cursor so that the user can see | |
1740 the included buddies */ | |
1741 | |
7636 | 1742 while (gtk_events_pending()) |
1743 gtk_main_iteration(); | |
1744 | |
8083 | 1745 /* we check to see if we're still supposed to be moving, now that gtk events have |
1746 * happened, and the mouse might not still be in the buddy list */ | |
1747 if(!gtkblist->timeout) { | |
1748 gaim_gtk_blist_collapse_contact_cb(NULL, node); | |
1749 return FALSE; | |
1750 } | |
1751 | |
7636 | 1752 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, >kblist->contact_rect); |
7720 | 1753 gdk_drawable_get_size(GDK_DRAWABLE(tv->window), &(gtkblist->contact_rect.width), NULL); |
7636 | 1754 gtkblist->mouseover_contact = node; |
1755 gtk_tree_path_down (path); | |
7719 | 1756 while (gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &i, path)) { |
7636 | 1757 GdkRectangle rect; |
1758 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect); | |
1759 gtkblist->contact_rect.height += rect.height; | |
1760 gtk_tree_path_next(path); | |
1761 } | |
1762 } | |
1763 | |
1764 gtk_tree_path_free(path); | |
1765 | |
5234 | 1766 tooltiptext = gaim_get_tooltip_text(node); |
7620 | 1767 |
1768 if(!tooltiptext) | |
1769 return FALSE; | |
1770 | |
7837 | 1771 if(gtkblist->tipwindow) |
1772 gtk_widget_destroy(gtkblist->tipwindow); | |
5234 | 1773 gtkblist->tipwindow = gtk_window_new(GTK_WINDOW_POPUP); |
1774 gtk_widget_set_app_paintable(gtkblist->tipwindow, TRUE); | |
1775 gtk_window_set_resizable(GTK_WINDOW(gtkblist->tipwindow), FALSE); | |
1776 gtk_widget_set_name(gtkblist->tipwindow, "gtk-tooltips"); | |
1777 g_signal_connect(G_OBJECT(gtkblist->tipwindow), "expose_event", | |
1778 G_CALLBACK(gaim_gtk_blist_paint_tip), node); | |
1779 gtk_widget_ensure_style (gtkblist->tipwindow); | |
7837 | 1780 |
7662 | 1781 #ifdef WANT_DROP_SHADOW |
7620 | 1782 attr.window_type = GDK_WINDOW_TEMP; |
1783 attr.override_redirect = TRUE; | |
1784 attr.x = gtkblist->tipwindow->allocation.x; | |
1785 attr.y = gtkblist->tipwindow->allocation.y; | |
1786 attr.width = gtkblist->tipwindow->allocation.width; | |
1787 attr.height = gtkblist->tipwindow->allocation.height; | |
1788 attr.wclass = GDK_INPUT_OUTPUT; | |
1789 attr.visual = gtk_widget_get_visual (gtkblist->window); | |
1790 attr.colormap = gtk_widget_get_colormap (gtkblist->window); | |
1791 | |
1792 attr.event_mask = gtk_widget_get_events (gtkblist->tipwindow); | |
1793 | |
1794 attr.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | | |
1795 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK ); | |
7897 | 1796 if(gtkblist->east_shadow) { |
1797 gdk_window_set_user_data (gtkblist->east_shadow, NULL); | |
1798 gdk_window_destroy (gtkblist->east_shadow); | |
1799 } | |
7620 | 1800 gtkblist->east_shadow = gdk_window_new(gtk_widget_get_root_window(gtkblist->tipwindow), &attr, |
1801 GDK_WA_NOREDIR | GDK_WA_VISUAL | GDK_WA_COLORMAP); | |
1802 gdk_window_set_user_data (gtkblist->east_shadow, gtkblist->tipwindow); | |
1803 gdk_window_set_back_pixmap (gtkblist->east_shadow, NULL, FALSE); | |
1804 | |
7897 | 1805 if(gtkblist->south_shadow) { |
1806 gdk_window_set_user_data (gtkblist->south_shadow, NULL); | |
1807 gdk_window_destroy (gtkblist->south_shadow); | |
1808 } | |
7620 | 1809 gtkblist->south_shadow = gdk_window_new(gtk_widget_get_root_window(gtkblist->tipwindow), &attr, |
1810 GDK_WA_NOREDIR | GDK_WA_VISUAL | GDK_WA_COLORMAP); | |
1811 gdk_window_set_user_data (gtkblist->south_shadow, gtkblist->tipwindow); | |
1812 gdk_window_set_back_pixmap (gtkblist->south_shadow, NULL, FALSE); | |
1813 #endif | |
1814 | |
5234 | 1815 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL); |
1816 pango_layout_set_wrap(layout, PANGO_WRAP_WORD); | |
1817 pango_layout_set_width(layout, 300000); | |
1818 pango_layout_set_markup(layout, tooltiptext, strlen(tooltiptext)); | |
1819 scr_w = gdk_screen_width(); | |
1820 scr_h = gdk_screen_height(); | |
1821 pango_layout_get_size (layout, &w, &h); | |
1822 w = PANGO_PIXELS(w) + 8; | |
1823 h = PANGO_PIXELS(h) + 8; | |
5228 | 1824 |
5234 | 1825 /* 38 is the size of a large status icon plus 4 pixels padding on each side. |
1826 * I should #define this or something */ | |
1827 w = w + 38; | |
1828 h = MAX(h, 38); | |
1829 | |
1830 gdk_window_get_pointer(NULL, &x, &y, NULL); | |
1831 if (GTK_WIDGET_NO_WINDOW(gtkblist->window)) | |
1832 y+=gtkblist->window->allocation.y; | |
1833 | |
1834 x -= ((w >> 1) + 4); | |
5228 | 1835 |
7636 | 1836 if ((y + h + 4) > scr_h || tooltip_top) |
7620 | 1837 y = y - h - 5; |
5234 | 1838 else |
1839 y = y + 6; | |
7620 | 1840 |
7719 | 1841 if (y < 0) |
1842 y = 0; | |
1843 | |
1844 if (y != 0) { | |
1845 if ((x + w) > scr_w) | |
1846 x -= (x + w + 5) - scr_w; | |
1847 else if (x < 0) | |
1848 x = 0; | |
1849 } else { | |
1850 x -= (w / 2 + 10); | |
1851 if (x < 0) | |
1852 x += w + 15; | |
1853 } | |
1854 | |
5234 | 1855 g_object_unref (layout); |
1856 g_free(tooltiptext); | |
1857 gtk_widget_set_size_request(gtkblist->tipwindow, w, h); | |
1858 gtk_window_move(GTK_WINDOW(gtkblist->tipwindow), x, y); | |
1859 gtk_widget_show(gtkblist->tipwindow); | |
5228 | 1860 |
7662 | 1861 #ifdef WANT_DROP_SHADOW |
7620 | 1862 map_shadow_windows(gtkblist); |
1863 #endif | |
1864 | |
5228 | 1865 return FALSE; |
1866 } | |
1867 | |
1868 static gboolean gaim_gtk_blist_motion_cb (GtkWidget *tv, GdkEventMotion *event, gpointer null) | |
1869 { | |
1870 GtkTreePath *path; | |
8083 | 1871 |
5228 | 1872 if (gtkblist->timeout) { |
7636 | 1873 if ((event->y > gtkblist->tip_rect.y) && ((event->y - gtkblist->tip_rect.height) < gtkblist->tip_rect.y)) |
5228 | 1874 return FALSE; |
1875 /* We've left the cell. Remove the timeout and create a new one below */ | |
1876 if (gtkblist->tipwindow) { | |
1877 gtk_widget_destroy(gtkblist->tipwindow); | |
7662 | 1878 #ifdef WANT_DROP_SHADOW |
7620 | 1879 gdk_window_set_user_data (gtkblist->east_shadow, NULL); |
1880 gdk_window_destroy (gtkblist->east_shadow); | |
1881 gtkblist->east_shadow = NULL; | |
1882 | |
1883 gdk_window_set_user_data (gtkblist->south_shadow, NULL); | |
1884 gdk_window_destroy (gtkblist->south_shadow); | |
1885 gtkblist->south_shadow = NULL; | |
1886 #endif | |
5228 | 1887 gtkblist->tipwindow = NULL; |
1888 } | |
7620 | 1889 |
5228 | 1890 g_source_remove(gtkblist->timeout); |
1891 } | |
1892 | |
1893 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL); | |
7636 | 1894 gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, >kblist->tip_rect); |
5228 | 1895 if (path) |
1896 gtk_tree_path_free(path); | |
1897 gtkblist->timeout = g_timeout_add(500, (GSourceFunc)gaim_gtk_blist_tooltip_timeout, tv); | |
7636 | 1898 |
1899 if (gtkblist->mouseover_contact) { | |
1900 if ((event->y < gtkblist->contact_rect.y) || ((event->y - gtkblist->contact_rect.height) > gtkblist->contact_rect.y)) { | |
1901 gaim_gtk_blist_collapse_contact_cb(NULL, gtkblist->mouseover_contact); | |
1902 gtkblist->mouseover_contact = NULL; | |
1903 } | |
1904 } | |
1905 | |
5228 | 1906 return FALSE; |
1907 } | |
1908 | |
1909 static void gaim_gtk_blist_leave_cb (GtkWidget *w, GdkEventCrossing *e, gpointer n) | |
1910 { | |
8083 | 1911 |
5228 | 1912 if (gtkblist->timeout) { |
1913 g_source_remove(gtkblist->timeout); | |
1914 gtkblist->timeout = 0; | |
1915 } | |
1916 if (gtkblist->tipwindow) { | |
1917 gtk_widget_destroy(gtkblist->tipwindow); | |
7662 | 1918 #ifdef WANT_DROP_SHADOW |
7897 | 1919 gdk_window_set_user_data (gtkblist->east_shadow, NULL); |
1920 gdk_window_destroy (gtkblist->east_shadow); | |
1921 gtkblist->east_shadow = NULL; | |
1922 | |
1923 gdk_window_set_user_data (gtkblist->south_shadow, NULL); | |
1924 gdk_window_destroy (gtkblist->south_shadow); | |
1925 gtkblist->south_shadow = NULL; | |
7620 | 1926 #endif |
5228 | 1927 gtkblist->tipwindow = NULL; |
1928 } | |
7720 | 1929 |
1930 if (gtkblist->mouseover_contact && | |
1931 !((e->x > gtkblist->contact_rect.x) && (e->x < (gtkblist->contact_rect.x + gtkblist->contact_rect.width)) && | |
1932 (e->y > gtkblist->contact_rect.y) && (e->y < (gtkblist->contact_rect.y + gtkblist->contact_rect.height)))) { | |
1933 gaim_gtk_blist_collapse_contact_cb(NULL, gtkblist->mouseover_contact); | |
7636 | 1934 gtkblist->mouseover_contact = NULL; |
1935 } | |
5228 | 1936 } |
1937 | |
1938 static void | |
1939 toggle_debug(void) | |
1940 { | |
7620 | 1941 gaim_prefs_set_bool("/gaim/gtk/debug/enabled", |
1942 !gaim_prefs_get_bool("/gaim/gtk/debug/enabled")); | |
5228 | 1943 } |
1944 | |
1945 | |
1946 /*************************************************** | |
1947 * Crap * | |
1948 ***************************************************/ | |
1949 static GtkItemFactoryEntry blist_menu[] = | |
1950 { | |
1951 /* Buddies menu */ | |
1952 { N_("/_Buddies"), NULL, NULL, 0, "<Branch>" }, | |
7887 | 1953 { N_("/Buddies/New Instant _Message..."), "<CTL>M", show_im_dialog, 0, "<StockItem>", GAIM_STOCK_IM }, |
5228 | 1954 { N_("/Buddies/Join a _Chat..."), "<CTL>C", join_chat, 0, "<StockItem>", GAIM_STOCK_CHAT }, |
8143 | 1955 { N_("/Buddies/Get User _Info..."), "<CTL>I", show_info_dialog, 0, "<StockItem>", GAIM_STOCK_INFO }, |
5228 | 1956 { "/Buddies/sep1", NULL, NULL, 0, "<Separator>" }, |
5398 | 1957 { N_("/Buddies/Show _Offline Buddies"), NULL, gaim_gtk_blist_edit_mode_cb, 1, "<CheckItem>"}, |
5228 | 1958 { N_("/Buddies/Show _Empty Groups"), NULL, gaim_gtk_blist_show_empty_groups_cb, 1, "<CheckItem>"}, |
7853 | 1959 { N_("/Buddies/_Add Buddy..."), "<CTL>B", gaim_gtk_blist_add_buddy_cb, 0, "<StockItem>", GTK_STOCK_ADD }, |
1960 { N_("/Buddies/Add C_hat..."), NULL, gaim_gtk_blist_add_chat_cb, 0, "<StockItem>", GTK_STOCK_ADD }, | |
1961 { N_("/Buddies/Add _Group..."), NULL, gaim_blist_request_add_group, 0, "<StockItem>", GTK_STOCK_ADD }, | |
5228 | 1962 { "/Buddies/sep2", NULL, NULL, 0, "<Separator>" }, |
7620 | 1963 { N_("/Buddies/_Signoff"), "<CTL>D", gaim_connections_disconnect_all, 0, "<StockItem>", GAIM_STOCK_SIGN_OFF }, |
1964 { N_("/Buddies/_Quit"), "<CTL>Q", gaim_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, | |
5228 | 1965 |
1966 /* Tools */ | |
1967 { N_("/_Tools"), NULL, NULL, 0, "<Branch>" }, | |
1968 { N_("/Tools/_Away"), NULL, NULL, 0, "<Branch>" }, | |
1969 { N_("/Tools/Buddy _Pounce"), NULL, NULL, 0, "<Branch>" }, | |
1970 { N_("/Tools/P_rotocol Actions"), NULL, NULL, 0, "<Branch>" }, | |
1971 { "/Tools/sep1", NULL, NULL, 0, "<Separator>" }, | |
7620 | 1972 { N_("/Tools/A_ccounts"), "<CTL>A", gaim_gtk_accounts_window_show, 0, "<StockItem>", GAIM_STOCK_ACCOUNTS }, |
7737 | 1973 { N_("/Tools/_File Transfers"), NULL, gaim_show_xfer_dialog, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER }, |
8113 | 1974 { N_("/Tools/R_oom List"), NULL, gaim_gtk_roomlist_dialog_show, 0, NULL }, |
7870 | 1975 { N_("/Tools/Pr_eferences"), "<CTL>P", gaim_gtk_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES }, |
7856 | 1976 { N_("/Tools/Pr_ivacy"), NULL, gaim_gtk_privacy_dialog_show, 0, NULL }, |
8022 | 1977 #if 0 |
5228 | 1978 { "/Tools/sep2", NULL, NULL, 0, "<Separator>" }, |
7620 | 1979 { N_("/Tools/View System _Log"), NULL, gtk_blist_show_systemlog_cb, 0, NULL }, |
8003 | 1980 #endif |
5228 | 1981 |
1982 /* Help */ | |
1983 { N_("/_Help"), NULL, NULL, 0, "<Branch>" }, | |
1984 { N_("/Help/Online _Help"), "F1", gtk_blist_show_onlinehelp_cb, 0, "<StockItem>", GTK_STOCK_HELP }, | |
7620 | 1985 { N_("/Help/_Debug Window"), NULL, toggle_debug, 0, NULL }, |
1986 { N_("/Help/_About"), NULL, show_about, 0, "<StockItem>", GAIM_STOCK_ABOUT }, | |
5228 | 1987 }; |
1988 | |
1989 /********************************************************* | |
1990 * Private Utility functions * | |
1991 *********************************************************/ | |
7620 | 1992 static void |
1993 rename_group_cb(GaimGroup *g, const char *new_name) | |
1994 { | |
1995 gaim_blist_rename_group(g, new_name); | |
1996 gaim_blist_save(); | |
1997 } | |
1998 | |
1999 static void | |
2000 show_rename_group(GtkWidget *unused, GaimGroup *g) | |
2001 { | |
2002 gaim_request_input(NULL, _("Rename Group"), _("New group name"), | |
2003 _("Please enter a new name for the selected group."), | |
2004 g->name, FALSE, FALSE, | |
2005 _("OK"), G_CALLBACK(rename_group_cb), | |
2006 _("Cancel"), NULL, g); | |
2007 } | |
5228 | 2008 |
5234 | 2009 static char *gaim_get_tooltip_text(GaimBlistNode *node) |
5228 | 2010 { |
5237 | 2011 GaimPlugin *prpl; |
2012 GaimPluginProtocolInfo *prpl_info = NULL; | |
5228 | 2013 char *text = NULL; |
7956 | 2014 |
5234 | 2015 if(GAIM_BLIST_NODE_IS_CHAT(node)) { |
7620 | 2016 GaimChat *chat = (GaimChat *)node; |
5237 | 2017 char *name = NULL; |
5274 | 2018 struct proto_chat_entry *pce; |
2019 GList *parts, *tmp; | |
2020 GString *parts_text = g_string_new(""); | |
2021 | |
7956 | 2022 prpl = gaim_find_prpl(gaim_account_get_protocol_id(chat->account)); |
5274 | 2023 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); |
2024 | |
2025 parts = prpl_info->chat_info(chat->account->gc); | |
5237 | 2026 |
7620 | 2027 name = g_markup_escape_text(gaim_chat_get_name(chat), -1); |
2028 | |
2029 if(g_list_length(gaim_connections_get_all()) > 1) { | |
5274 | 2030 char *account = g_markup_escape_text(chat->account->username, -1); |
2031 g_string_append_printf(parts_text, _("\n<b>Account:</b> %s"), | |
2032 account); | |
2033 g_free(account); | |
5237 | 2034 } |
5274 | 2035 for(tmp = parts; tmp; tmp = tmp->next) { |
7889 | 2036 char *label, *tmp2, *value; |
5274 | 2037 pce = tmp->data; |
5237 | 2038 |
8020 | 2039 if(!pce->secret) { |
2040 | |
2041 tmp2 = g_markup_escape_text(pce->label, -1); | |
2042 label = gaim_text_strip_mnemonic(tmp2); | |
2043 g_free(tmp2); | |
2044 | |
2045 value = g_markup_escape_text(g_hash_table_lookup(chat->components, | |
2046 pce->identifier), -1); | |
2047 | |
2048 g_string_append_printf(parts_text, "\n<b>%s</b> %s", label, value); | |
2049 g_free(label); | |
2050 g_free(value); | |
2051 } | |
5274 | 2052 g_free(pce); |
2053 } | |
2054 g_list_free(parts); | |
2055 | |
2056 text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>%s", | |
2057 name, parts_text->str); | |
2058 g_string_free(parts_text, TRUE); | |
5237 | 2059 g_free(name); |
7620 | 2060 } else if(GAIM_BLIST_NODE_IS_CONTACT(node) || |
2061 GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
2062 GaimBuddy *b; | |
5234 | 2063 char *statustext = NULL; |
7620 | 2064 char *contactaliastext = NULL; |
5234 | 2065 char *aliastext = NULL, *nicktext = NULL; |
7950 | 2066 char *loggedin = NULL, *idletime = NULL; |
2067 char *warning = NULL; | |
5274 | 2068 char *accounttext = NULL; |
5228 | 2069 |
7620 | 2070 if(GAIM_BLIST_NODE_IS_CONTACT(node)) { |
2071 GaimContact *contact = (GaimContact*)node; | |
2072 b = gaim_contact_get_priority_buddy(contact); | |
2073 if(contact->alias) | |
2074 contactaliastext = g_markup_escape_text(contact->alias, -1); | |
2075 } else { | |
2076 b = (GaimBuddy *)node; | |
2077 } | |
2078 | |
7956 | 2079 prpl = gaim_find_prpl(gaim_account_get_protocol_id(b->account)); |
5234 | 2080 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); |
2081 | |
7620 | 2082 if (prpl_info && prpl_info->tooltip_text) { |
5234 | 2083 const char *end; |
2084 statustext = prpl_info->tooltip_text(b); | |
5228 | 2085 |
5234 | 2086 if(statustext && !g_utf8_validate(statustext, -1, &end)) { |
2087 char *new = g_strndup(statustext, | |
2088 g_utf8_pointer_to_offset(statustext, end)); | |
2089 g_free(statustext); | |
2090 statustext = new; | |
2091 } | |
2092 } | |
2093 | |
2094 if (!statustext && !GAIM_BUDDY_IS_ONLINE(b)) | |
2095 statustext = g_strdup(_("<b>Status:</b> Offline")); | |
5228 | 2096 |
7950 | 2097 if (b->signon > 0) |
2098 loggedin = gaim_str_seconds_to_string(time(NULL) - b->signon); | |
2099 | |
5341 | 2100 if (b->idle > 0) |
7620 | 2101 idletime = gaim_str_seconds_to_string(time(NULL) - b->idle); |
5228 | 2102 |
5234 | 2103 if(b->alias && b->alias[0]) |
2104 aliastext = g_markup_escape_text(b->alias, -1); | |
5228 | 2105 |
5234 | 2106 if(b->server_alias) |
2107 nicktext = g_markup_escape_text(b->server_alias, -1); | |
5228 | 2108 |
5234 | 2109 if (b->evil > 0) |
2110 warning = g_strdup_printf(_("%d%%"), b->evil); | |
5228 | 2111 |
7620 | 2112 if(g_list_length(gaim_connections_get_all()) > 1) |
5274 | 2113 accounttext = g_markup_escape_text(b->account->username, -1); |
2114 | |
5234 | 2115 text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>" |
5438 | 2116 "%s %s" /* Account */ |
7620 | 2117 "%s %s" /* Contact Alias */ |
5438 | 2118 "%s %s" /* Alias */ |
2119 "%s %s" /* Nickname */ | |
7950 | 2120 "%s %s" /* Logged In */ |
5438 | 2121 "%s %s" /* Idle */ |
2122 "%s %s" /* Warning */ | |
2123 "%s%s" /* Status */ | |
2124 "%s", | |
2125 b->name, | |
2126 accounttext ? _("\n<b>Account:</b>") : "", accounttext ? accounttext : "", | |
7620 | 2127 contactaliastext ? _("\n<b>Contact Alias:</b>") : "", contactaliastext ? contactaliastext : "", |
5438 | 2128 aliastext ? _("\n<b>Alias:</b>") : "", aliastext ? aliastext : "", |
2129 nicktext ? _("\n<b>Nickname:</b>") : "", nicktext ? nicktext : "", | |
7950 | 2130 loggedin ? _("\n<b>Logged In:</b>") : "", loggedin ? loggedin : "", |
5438 | 2131 idletime ? _("\n<b>Idle:</b>") : "", idletime ? idletime : "", |
2132 b->evil ? _("\n<b>Warned:</b>") : "", b->evil ? warning : "", | |
2133 statustext ? "\n" : "", statustext ? statustext : "", | |
2134 !g_ascii_strcasecmp(b->name, "robflynn") ? _("\n<b>Description:</b> Spooky") : | |
7620 | 2135 !g_ascii_strcasecmp(b->name, "seanegn") ? _("\n<b>Status</b>: Awesome") : |
2136 !g_ascii_strcasecmp(b->name, "chipx86") ? _("\n<b>Status</b>: Rockin'") : ""); | |
5234 | 2137 |
2138 if(warning) | |
2139 g_free(warning); | |
7950 | 2140 if(loggedin) |
2141 g_free(loggedin); | |
5234 | 2142 if(idletime) |
2143 g_free(idletime); | |
2144 if(statustext) | |
2145 g_free(statustext); | |
2146 if(nicktext) | |
2147 g_free(nicktext); | |
2148 if(aliastext) | |
2149 g_free(aliastext); | |
5274 | 2150 if(accounttext) |
2151 g_free(accounttext); | |
5234 | 2152 } |
5228 | 2153 |
2154 return text; | |
2155 } | |
2156 | |
7620 | 2157 struct _emblem_data { |
2158 char *filename; | |
2159 int x; | |
2160 int y; | |
2161 }; | |
2162 | |
5234 | 2163 GdkPixbuf *gaim_gtk_blist_get_status_icon(GaimBlistNode *node, GaimStatusIconSize size) |
5228 | 2164 { |
7620 | 2165 GdkPixbuf *scale, *status = NULL; |
2166 int i, scalesize = 30; | |
2167 char *filename; | |
5228 | 2168 const char *protoname = NULL; |
7620 | 2169 struct _gaim_gtk_blist_node *gtknode = node->ui_data; |
2170 struct _emblem_data emblems[4] = {{NULL, 15, 15}, {NULL, 0, 15}, | |
2171 {NULL, 0, 0}, {NULL, 15, 0}}; | |
2172 | |
2173 GaimBuddy *buddy = NULL; | |
2174 GaimChat *chat = NULL; | |
2175 | |
2176 if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
2177 if(!gtknode->contact_expanded) | |
2178 buddy = gaim_contact_get_priority_buddy((GaimContact*)node); | |
2179 } else if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
2180 buddy = (GaimBuddy*)node; | |
2181 } else if(GAIM_BLIST_NODE_IS_CHAT(node)) { | |
2182 chat = (GaimChat*)node; | |
2183 } else { | |
5228 | 2184 return NULL; |
5234 | 2185 } |
2186 | |
7620 | 2187 if(buddy || chat) { |
2188 GaimAccount *account; | |
2189 GaimPlugin *prpl; | |
2190 GaimPluginProtocolInfo *prpl_info; | |
2191 | |
2192 if(buddy) | |
2193 account = buddy->account; | |
2194 else | |
2195 account = chat->account; | |
2196 | |
7956 | 2197 prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); |
7620 | 2198 if(!prpl) |
2199 return NULL; | |
2200 | |
2201 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); | |
2202 | |
2203 if(prpl_info && prpl_info->list_icon) { | |
2204 protoname = prpl_info->list_icon(account, buddy); | |
2205 } | |
2206 if(prpl_info && prpl_info->list_emblems && buddy) { | |
2207 if(buddy->present != GAIM_BUDDY_SIGNING_OFF) | |
2208 prpl_info->list_emblems(buddy, &emblems[0].filename, | |
2209 &emblems[1].filename, &emblems[2].filename, | |
2210 &emblems[3].filename); | |
2211 } | |
5234 | 2212 } |
5228 | 2213 |
7620 | 2214 if(size == GAIM_STATUS_ICON_SMALL) { |
5228 | 2215 scalesize = 15; |
7620 | 2216 /* So that only the se icon will composite */ |
2217 emblems[1].filename = emblems[2].filename = emblems[3].filename = NULL; | |
5228 | 2218 } |
2219 | |
7620 | 2220 if(buddy && buddy->present == GAIM_BUDDY_SIGNING_ON) { |
2221 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "login.png", NULL); | |
2222 } else if(buddy && buddy->present == GAIM_BUDDY_SIGNING_OFF) { | |
2223 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "logout.png", NULL); | |
2224 } else if(buddy || chat) { | |
5228 | 2225 char *image = g_strdup_printf("%s.png", protoname); |
2226 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); | |
2227 g_free(image); | |
7620 | 2228 } else { |
2229 /* gaim dude */ | |
2230 filename = g_build_filename(DATADIR, "pixmaps", "gaim.png", NULL); | |
5228 | 2231 } |
7620 | 2232 |
2233 status = gdk_pixbuf_new_from_file(filename, NULL); | |
2234 g_free(filename); | |
2235 | |
2236 if(!status) | |
2237 return NULL; | |
2238 | |
2239 scale = gdk_pixbuf_scale_simple(status, scalesize, scalesize, | |
2240 GDK_INTERP_BILINEAR); | |
2241 g_object_unref(status); | |
2242 | |
2243 for(i=0; i<4; i++) { | |
2244 if(emblems[i].filename) { | |
2245 GdkPixbuf *emblem; | |
2246 char *image = g_strdup_printf("%s.png", emblems[i].filename); | |
2247 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); | |
2248 g_free(image); | |
2249 emblem = gdk_pixbuf_new_from_file(filename, NULL); | |
2250 g_free(filename); | |
2251 if(emblem) { | |
2252 if(i == 0 && size == GAIM_STATUS_ICON_SMALL) { | |
2253 gdk_pixbuf_composite(emblem, | |
2254 scale, 5, 5, | |
2255 10, 10, | |
2256 5, 5, | |
2257 .6, .6, | |
2258 GDK_INTERP_BILINEAR, | |
2259 255); | |
2260 } else { | |
2261 gdk_pixbuf_composite(emblem, | |
2262 scale, emblems[i].x, emblems[i].y, | |
2263 15, 15, | |
2264 emblems[i].x, emblems[i].y, | |
2265 1, 1, | |
2266 GDK_INTERP_BILINEAR, | |
2267 255); | |
2268 } | |
2269 g_object_unref(emblem); | |
2270 } | |
5228 | 2271 } |
2272 } | |
7620 | 2273 |
2274 if(buddy) { | |
2275 if(buddy->present == GAIM_BUDDY_OFFLINE) | |
2276 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE); | |
2277 else if(buddy->idle && | |
2278 gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies")) | |
2279 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.25, FALSE); | |
5228 | 2280 } |
7620 | 2281 |
5228 | 2282 return scale; |
2283 } | |
2284 | |
7620 | 2285 static GdkPixbuf *gaim_gtk_blist_get_buddy_icon(GaimBuddy *b) |
5228 | 2286 { |
7620 | 2287 const char *file; |
5228 | 2288 GdkPixbuf *buf, *ret; |
2289 | |
7620 | 2290 if (!gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")) |
5228 | 2291 return NULL; |
2292 | |
7693 | 2293 if ((file = gaim_blist_node_get_string((GaimBlistNode*)b, "buddy_icon")) == NULL) |
5228 | 2294 return NULL; |
2295 | |
2296 buf = gdk_pixbuf_new_from_file(file, NULL); | |
2297 | |
2298 | |
2299 if (buf) { | |
2300 if (!GAIM_BUDDY_IS_ONLINE(b)) | |
2301 gdk_pixbuf_saturate_and_pixelate(buf, buf, 0.0, FALSE); | |
7620 | 2302 if (b->idle && gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies")) |
5228 | 2303 gdk_pixbuf_saturate_and_pixelate(buf, buf, 0.25, FALSE); |
2304 | |
2305 ret = gdk_pixbuf_scale_simple(buf,30,30, GDK_INTERP_BILINEAR); | |
2306 g_object_unref(G_OBJECT(buf)); | |
2307 return ret; | |
2308 } | |
2309 return NULL; | |
2310 } | |
2311 | |
7620 | 2312 static gchar *gaim_gtk_blist_get_name_markup(GaimBuddy *b, gboolean selected) |
5228 | 2313 { |
7620 | 2314 const char *name; |
2315 char *esc, *text = NULL; | |
5228 | 2316 GaimPlugin *prpl; |
2317 GaimPluginProtocolInfo *prpl_info = NULL; | |
7620 | 2318 GaimContact *contact; |
2319 struct _gaim_gtk_blist_node *gtkcontactnode = NULL; | |
5228 | 2320 int ihrs, imin; |
2321 char *idletime = NULL, *warning = NULL, *statustext = NULL; | |
2322 time_t t; | |
7620 | 2323 /* XXX Clean up this crap */ |
2324 | |
2325 contact = (GaimContact*)((GaimBlistNode*)b)->parent; | |
2326 if(contact) | |
2327 gtkcontactnode = ((GaimBlistNode*)contact)->ui_data; | |
2328 | |
2329 if(gtkcontactnode && !gtkcontactnode->contact_expanded && contact->alias) | |
2330 name = contact->alias; | |
2331 else | |
2332 name = gaim_get_buddy_alias(b); | |
2333 esc = g_markup_escape_text(name, strlen(name)); | |
2334 | |
7956 | 2335 prpl = gaim_find_prpl(gaim_account_get_protocol_id(b->account)); |
5228 | 2336 |
2337 if (prpl != NULL) | |
2338 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); | |
2339 | |
7620 | 2340 if (!gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")) { |
2341 if ((b->idle && !selected && | |
2342 gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies")) || | |
2343 !GAIM_BUDDY_IS_ONLINE(b)) { | |
2344 if (selected) | |
2345 text = g_strdup(esc); | |
2346 else | |
2347 text = g_strdup_printf("<span color='dim grey'>%s</span>", | |
2348 esc); | |
5228 | 2349 g_free(esc); |
2350 return text; | |
7620 | 2351 } |
2352 else { | |
5228 | 2353 return esc; |
2354 } | |
2355 } | |
2356 | |
2357 time(&t); | |
2358 ihrs = (t - b->idle) / 3600; | |
2359 imin = ((t - b->idle) / 60) % 60; | |
2360 | |
8122
36674144c510
[gaim-migrate @ 8826]
Christian Hammond <chipx86@chipx86.com>
parents:
8113
diff
changeset
|
2361 if (prpl_info && prpl_info->status_text && b->account->gc) { |
5228 | 2362 char *tmp = prpl_info->status_text(b); |
2363 const char *end; | |
2364 | |
2365 if(tmp && !g_utf8_validate(tmp, -1, &end)) { | |
2366 char *new = g_strndup(tmp, | |
2367 g_utf8_pointer_to_offset(tmp, end)); | |
2368 g_free(tmp); | |
2369 tmp = new; | |
2370 } | |
2371 | |
2372 if(tmp) { | |
2373 char buf[32]; | |
2374 char *c = tmp; | |
2375 int length = 0, vis=0; | |
2376 gboolean inside = FALSE; | |
2377 g_strdelimit(tmp, "\n", ' '); | |
7620 | 2378 gaim_str_strip_cr(tmp); |
5228 | 2379 |
2380 while(*c && vis < 20) { | |
2381 if(*c == '&') | |
2382 inside = TRUE; | |
2383 else if(*c == ';') | |
2384 inside = FALSE; | |
2385 if(!inside) | |
2386 vis++; | |
7620 | 2387 c = g_utf8_next_char(c); /* this is fun */ |
5228 | 2388 } |
2389 | |
7620 | 2390 length = c - tmp; |
2391 | |
5228 | 2392 if(vis == 20) |
2393 g_snprintf(buf, sizeof(buf), "%%.%ds...", length); | |
2394 else | |
2395 g_snprintf(buf, sizeof(buf), "%%s "); | |
2396 | |
2397 statustext = g_strdup_printf(buf, tmp); | |
2398 | |
2399 g_free(tmp); | |
2400 } | |
2401 } | |
2402 | |
7620 | 2403 if (b->idle > 0 && |
2404 gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time")) { | |
5228 | 2405 if (ihrs) |
2406 idletime = g_strdup_printf(_("Idle (%dh%02dm) "), ihrs, imin); | |
2407 else | |
2408 idletime = g_strdup_printf(_("Idle (%dm) "), imin); | |
2409 } | |
2410 | |
7620 | 2411 if (b->evil > 0 && |
2412 gaim_prefs_get_bool("/gaim/gtk/blist/show_warning_level")) | |
5228 | 2413 warning = g_strdup_printf(_("Warned (%d%%) "), b->evil); |
2414 | |
2415 if(!GAIM_BUDDY_IS_ONLINE(b) && !statustext) | |
7620 | 2416 statustext = g_strdup(_("Offline ")); |
2417 | |
2418 if (b->idle && !selected && | |
2419 gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies")) { | |
2420 | |
5228 | 2421 text = g_strdup_printf("<span color='dim grey'>%s</span>\n" |
2422 "<span color='dim grey' size='smaller'>%s%s%s</span>", | |
2423 esc, | |
2424 statustext != NULL ? statustext : "", | |
2425 idletime != NULL ? idletime : "", | |
2426 warning != NULL ? warning : ""); | |
7620 | 2427 } else if (statustext == NULL && idletime == NULL && warning == NULL && |
2428 GAIM_BUDDY_IS_ONLINE(b)) { | |
5228 | 2429 text = g_strdup(esc); |
2430 } else { | |
2431 text = g_strdup_printf("%s\n" | |
2432 "<span %s size='smaller'>%s%s%s</span>", esc, | |
2433 selected ? "" : "color='dim grey'", | |
2434 statustext != NULL ? statustext : "", | |
7620 | 2435 idletime != NULL ? idletime : "", |
5228 | 2436 warning != NULL ? warning : ""); |
2437 } | |
2438 if (idletime) | |
2439 g_free(idletime); | |
2440 if (warning) | |
2441 g_free(warning); | |
2442 if (statustext) | |
2443 g_free(statustext); | |
2444 if (esc) | |
2445 g_free(esc); | |
2446 | |
2447 return text; | |
2448 } | |
2449 | |
2450 static void gaim_gtk_blist_restore_position() | |
2451 { | |
7620 | 2452 int blist_x, blist_y, blist_width, blist_height; |
2453 | |
2454 blist_width = gaim_prefs_get_int("/gaim/gtk/blist/width"); | |
2455 | |
2456 /* if the window exists, is hidden, we're saving positions, and the | |
2457 * position is sane... */ | |
2458 if (gtkblist && gtkblist->window && | |
2459 !GTK_WIDGET_VISIBLE(gtkblist->window) && blist_width != 0) { | |
2460 | |
2461 blist_x = gaim_prefs_get_int("/gaim/gtk/blist/x"); | |
2462 blist_y = gaim_prefs_get_int("/gaim/gtk/blist/y"); | |
2463 blist_height = gaim_prefs_get_int("/gaim/gtk/blist/height"); | |
2464 | |
5228 | 2465 /* ...check position is on screen... */ |
7620 | 2466 if (blist_x >= gdk_screen_width()) |
2467 blist_x = gdk_screen_width() - 100; | |
2468 else if (blist_x + blist_width < 0) | |
2469 blist_x = 100; | |
2470 | |
2471 if (blist_y >= gdk_screen_height()) | |
2472 blist_y = gdk_screen_height() - 100; | |
2473 else if (blist_y + blist_height < 0) | |
2474 blist_y = 100; | |
2475 | |
5228 | 2476 /* ...and move it back. */ |
7620 | 2477 gtk_window_move(GTK_WINDOW(gtkblist->window), blist_x, blist_y); |
2478 gtk_window_resize(GTK_WINDOW(gtkblist->window), blist_width, blist_height); | |
5228 | 2479 } |
2480 } | |
2481 | |
7620 | 2482 static gboolean gaim_gtk_blist_refresh_timer(GaimBuddyList *list) |
5228 | 2483 { |
7620 | 2484 GaimBlistNode *gnode, *cnode; |
2485 | |
2486 for(gnode = list->root; gnode; gnode = gnode->next) { | |
2487 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
5234 | 2488 continue; |
7620 | 2489 for(cnode = gnode->child; cnode; cnode = cnode->next) { |
2490 if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) { | |
2491 GaimBuddy *buddy = gaim_contact_get_priority_buddy((GaimContact*)cnode); | |
2492 if(buddy && buddy->idle) | |
2493 gaim_gtk_blist_update(list, cnode); | |
2494 } | |
5228 | 2495 } |
2496 } | |
2497 | |
2498 /* keep on going */ | |
2499 return TRUE; | |
2500 } | |
2501 | |
7620 | 2502 static void gaim_gtk_blist_hide_node(GaimBuddyList *list, GaimBlistNode *node) |
5260 | 2503 { |
2504 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; | |
2505 GtkTreeIter iter; | |
2506 | |
2507 if (!gtknode || !gtknode->row || !gtkblist) | |
2508 return; | |
2509 | |
2510 if(gtkblist->selected_node == node) | |
2511 gtkblist->selected_node = NULL; | |
2512 | |
2513 if (get_iter_from_node(node, &iter)) { | |
2514 gtk_tree_store_remove(gtkblist->treemodel, &iter); | |
7620 | 2515 if(GAIM_BLIST_NODE_IS_CONTACT(node) || GAIM_BLIST_NODE_IS_BUDDY(node) |
2516 || GAIM_BLIST_NODE_IS_CHAT(node)) { | |
5260 | 2517 gaim_gtk_blist_update(list, node->parent); |
2518 } | |
2519 } | |
2520 gtk_tree_row_reference_free(gtknode->row); | |
2521 gtknode->row = NULL; | |
2522 } | |
2523 | |
7620 | 2524 static void |
2525 signed_on_off_cb(GaimConnection *gc, GaimBuddyList *blist) | |
2526 { | |
8235 | 2527 GaimGtkBuddyList *gtkblist = blist->ui_data; |
2528 | |
7620 | 2529 gaim_gtk_blist_update_protocol_actions(); |
8235 | 2530 gaim_gtkpounce_menu_build(gtkblist->bpmenu); |
7620 | 2531 } |
2532 | |
2533 /* this is called on all sorts of signals, and we have no reason to pass | |
2534 * it anything, so it remains without arguments. If you need anything | |
2535 * more specific, do as below, and create another callback that calls | |
2536 * this */ | |
2537 static void | |
2538 raise_on_events_cb() | |
2539 { | |
2540 if(gtkblist && gtkblist->window && | |
2541 gaim_prefs_get_bool("/gaim/gtk/blist/raise_on_events")) { | |
2542 gtk_widget_show(gtkblist->window); | |
2543 gtk_window_deiconify(GTK_WINDOW(gtkblist->window)); | |
2544 gdk_window_raise(gtkblist->window->window); | |
2545 } | |
2546 } | |
2547 | |
5260 | 2548 |
5228 | 2549 /********************************************************************************** |
2550 * Public API Functions * | |
2551 **********************************************************************************/ | |
7620 | 2552 static void gaim_gtk_blist_new_list(GaimBuddyList *blist) |
5228 | 2553 { |
7620 | 2554 GaimGtkBuddyList *gtkblist; |
2555 | |
2556 gtkblist = g_new0(GaimGtkBuddyList, 1); | |
2557 blist->ui_data = gtkblist; | |
2558 | |
2559 /* Setup some gaim signal handlers. */ | |
2560 gaim_signal_connect(gaim_connections_get_handle(), "signing-on", | |
2561 gtkblist, GAIM_CALLBACK(signed_on_off_cb), blist); | |
2562 gaim_signal_connect(gaim_connections_get_handle(), "signing-off", | |
2563 gtkblist, GAIM_CALLBACK(signed_on_off_cb), blist); | |
2564 | |
2565 /* Register some of our own. */ | |
2566 gaim_signal_register(gtkblist, "drawing-menu", | |
2567 gaim_marshal_VOID__POINTER_POINTER, NULL, 2, | |
2568 gaim_value_new(GAIM_TYPE_BOXED, "GtkMenu"), | |
2569 gaim_value_new(GAIM_TYPE_SUBTYPE, | |
2570 GAIM_SUBTYPE_BLIST_BUDDY)); | |
2571 | |
2572 /* All of these signal handlers are for the "Raise on Events" option */ | |
2573 gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-on", | |
2574 gtkblist, GAIM_CALLBACK(raise_on_events_cb), NULL); | |
2575 gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-off", | |
2576 gtkblist, GAIM_CALLBACK(raise_on_events_cb), NULL); | |
5228 | 2577 } |
2578 | |
5256 | 2579 static void gaim_gtk_blist_new_node(GaimBlistNode *node) |
2580 { | |
2581 node->ui_data = g_new0(struct _gaim_gtk_blist_node, 1); | |
2582 } | |
2583 | |
5228 | 2584 void gaim_gtk_blist_update_columns() |
2585 { | |
2586 if(!gtkblist) | |
2587 return; | |
2588 | |
7620 | 2589 if (gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")) { |
5228 | 2590 gtk_tree_view_column_set_visible(gtkblist->buddy_icon_column, TRUE); |
2591 gtk_tree_view_column_set_visible(gtkblist->idle_column, FALSE); | |
2592 gtk_tree_view_column_set_visible(gtkblist->warning_column, FALSE); | |
2593 } else { | |
7620 | 2594 gtk_tree_view_column_set_visible(gtkblist->idle_column, |
2595 gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time")); | |
2596 gtk_tree_view_column_set_visible(gtkblist->warning_column, | |
2597 gaim_prefs_get_bool("/gaim/gtk/blist/show_warning_level")); | |
5228 | 2598 gtk_tree_view_column_set_visible(gtkblist->buddy_icon_column, FALSE); |
2599 } | |
2600 } | |
2601 | |
8089 | 2602 enum {DRAG_BUDDY, DRAG_ROW, DRAG_VCARD}; |
5228 | 2603 |
2604 static char * | |
2605 item_factory_translate_func (const char *path, gpointer func_data) | |
2606 { | |
7620 | 2607 return _((char *)path); |
5228 | 2608 } |
2609 | |
5422 | 2610 void gaim_gtk_blist_setup_sort_methods() |
2611 { | |
7620 | 2612 gaim_gtk_blist_sort_method_reg("none", _("None"), sort_method_none); |
2613 #if GTK_CHECK_VERSION(2,2,1) | |
2614 gaim_gtk_blist_sort_method_reg("alphabetical", _("Alphabetical"), sort_method_alphabetical); | |
2615 gaim_gtk_blist_sort_method_reg("status", _("By status"), sort_method_status); | |
2616 gaim_gtk_blist_sort_method_reg("log_size", _("By log size"), sort_method_log); | |
2617 #endif | |
2618 gaim_gtk_blist_sort_method_set(gaim_prefs_get_string("/gaim/gtk/blist/sort_type")); | |
2619 } | |
2620 | |
2621 static void _prefs_change_redo_list() { | |
2622 redo_buddy_list(gaim_get_blist(), TRUE); | |
2623 } | |
2624 | |
2625 static void _prefs_change_sort_method(const char *pref_name, GaimPrefType type, | |
2626 gpointer val, gpointer data) { | |
2627 if(!strcmp(pref_name, "/gaim/gtk/blist/sort_type")) | |
2628 gaim_gtk_blist_sort_method_set(val); | |
2629 } | |
2630 | |
2631 static void gaim_gtk_blist_show(GaimBuddyList *list) | |
5228 | 2632 { |
2633 GtkCellRenderer *rend; | |
2634 GtkTreeViewColumn *column; | |
2635 GtkWidget *sw; | |
2636 GtkWidget *button; | |
2637 GtkSizeGroup *sg; | |
2638 GtkAccelGroup *accel_group; | |
2639 GtkTreeSelection *selection; | |
2640 GtkTargetEntry gte[] = {{"GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW}, | |
8089 | 2641 {"application/x-im-contact", 0, DRAG_BUDDY}, |
2642 {"text/x-vcard", 0, DRAG_VCARD }}; | |
5228 | 2643 |
2644 if (gtkblist && gtkblist->window) { | |
2645 gtk_widget_show(gtkblist->window); | |
2646 return; | |
2647 } | |
2648 | |
2649 gtkblist = GAIM_GTK_BLIST(list); | |
2650 | |
2651 gtkblist->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
2652 gtk_window_set_role(GTK_WINDOW(gtkblist->window), "buddy_list"); | |
2653 gtk_window_set_title(GTK_WINDOW(gtkblist->window), _("Buddy List")); | |
2654 | |
2655 GTK_WINDOW(gtkblist->window)->allow_shrink = TRUE; | |
2656 | |
2657 gtkblist->vbox = gtk_vbox_new(FALSE, 0); | |
2658 gtk_container_add(GTK_CONTAINER(gtkblist->window), gtkblist->vbox); | |
2659 | |
2660 g_signal_connect(G_OBJECT(gtkblist->window), "delete_event", G_CALLBACK(gtk_blist_delete_cb), NULL); | |
2661 g_signal_connect(G_OBJECT(gtkblist->window), "configure_event", G_CALLBACK(gtk_blist_configure_cb), NULL); | |
2662 g_signal_connect(G_OBJECT(gtkblist->window), "visibility_notify_event", G_CALLBACK(gtk_blist_visibility_cb), NULL); | |
2663 gtk_widget_add_events(gtkblist->window, GDK_VISIBILITY_NOTIFY_MASK); | |
2664 | |
2665 /******************************* Menu bar *************************************/ | |
2666 accel_group = gtk_accel_group_new(); | |
2667 gtk_window_add_accel_group(GTK_WINDOW (gtkblist->window), accel_group); | |
2668 g_object_unref(accel_group); | |
5427 | 2669 gtkblist->ift = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<GaimMain>", accel_group); |
2670 gtk_item_factory_set_translate_func (gtkblist->ift, | |
5228 | 2671 item_factory_translate_func, |
2672 NULL, NULL); | |
5427 | 2673 gtk_item_factory_create_items(gtkblist->ift, sizeof(blist_menu) / sizeof(*blist_menu), |
5228 | 2674 blist_menu, NULL); |
7620 | 2675 gaim_gtk_load_accels(); |
2676 g_signal_connect(G_OBJECT(accel_group), "accel-changed", | |
2677 G_CALLBACK(gaim_gtk_save_accels_cb), NULL); | |
5427 | 2678 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtk_item_factory_get_widget(gtkblist->ift, "<GaimMain>"), FALSE, FALSE, 0); |
5228 | 2679 |
5427 | 2680 awaymenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Away")); |
5228 | 2681 do_away_menu(); |
2682 | |
5427 | 2683 gtkblist->bpmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Buddy Pounce")); |
5228 | 2684 gaim_gtkpounce_menu_build(gtkblist->bpmenu); |
2685 | |
5427 | 2686 protomenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Protocol Actions")); |
7620 | 2687 gaim_gtk_blist_update_protocol_actions(); |
5228 | 2688 /****************************** GtkTreeView **********************************/ |
2689 sw = gtk_scrolled_window_new(NULL,NULL); | |
2690 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); | |
2691 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
2692 | |
7620 | 2693 gtkblist->treemodel = gtk_tree_store_new(BLIST_COLUMNS, |
2694 GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, G_TYPE_STRING, | |
2695 G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER); | |
5228 | 2696 |
2697 gtkblist->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtkblist->treemodel)); | |
2698 gtk_widget_set_size_request(gtkblist->treeview, -1, 200); | |
2699 | |
2700 /* Set up selection stuff */ | |
2701 | |
2702 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)); | |
2703 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(gaim_gtk_blist_selection_changed), NULL); | |
2704 | |
2705 | |
2706 /* Set up dnd */ | |
7650 | 2707 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(gtkblist->treeview), |
8089 | 2708 GDK_BUTTON1_MASK, gte, 3, |
7650 | 2709 GDK_ACTION_COPY); |
2710 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(gtkblist->treeview), | |
8089 | 2711 gte, 3, |
7650 | 2712 GDK_ACTION_COPY | GDK_ACTION_MOVE); |
7636 | 2713 |
2714 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-received", G_CALLBACK(gaim_gtk_blist_drag_data_rcv_cb), NULL); | |
5228 | 2715 g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-get", G_CALLBACK(gaim_gtk_blist_drag_data_get_cb), NULL); |
2716 | |
2717 /* Tooltips */ | |
2718 g_signal_connect(G_OBJECT(gtkblist->treeview), "motion-notify-event", G_CALLBACK(gaim_gtk_blist_motion_cb), NULL); | |
2719 g_signal_connect(G_OBJECT(gtkblist->treeview), "leave-notify-event", G_CALLBACK(gaim_gtk_blist_leave_cb), NULL); | |
2720 | |
2721 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE); | |
2722 | |
2723 column = gtk_tree_view_column_new (); | |
2724 | |
2725 rend = gtk_cell_renderer_pixbuf_new(); | |
2726 gtk_tree_view_column_pack_start (column, rend, FALSE); | |
7620 | 2727 gtk_tree_view_column_set_attributes (column, rend, |
5228 | 2728 "pixbuf", STATUS_ICON_COLUMN, |
2729 "visible", STATUS_ICON_VISIBLE_COLUMN, | |
2730 NULL); | |
2731 g_object_set(rend, "xalign", 0.0, "ypad", 0, NULL); | |
2732 | |
2733 rend = gtk_cell_renderer_text_new(); | |
2734 gtk_tree_view_column_pack_start (column, rend, TRUE); | |
7620 | 2735 gtk_tree_view_column_set_attributes (column, rend, |
5228 | 2736 "markup", NAME_COLUMN, |
2737 NULL); | |
2738 g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL); | |
2739 | |
2740 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
2741 | |
2742 rend = gtk_cell_renderer_text_new(); | |
2743 gtkblist->warning_column = gtk_tree_view_column_new_with_attributes("Warning", rend, "markup", WARNING_COLUMN, NULL); | |
2744 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->warning_column); | |
2745 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL); | |
2746 | |
2747 rend = gtk_cell_renderer_text_new(); | |
2748 gtkblist->idle_column = gtk_tree_view_column_new_with_attributes("Idle", rend, "markup", IDLE_COLUMN, NULL); | |
2749 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->idle_column); | |
2750 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL); | |
2751 | |
2752 rend = gtk_cell_renderer_pixbuf_new(); | |
2753 gtkblist->buddy_icon_column = gtk_tree_view_column_new_with_attributes("Buddy Icon", rend, "pixbuf", BUDDY_ICON_COLUMN, NULL); | |
2754 g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL); | |
2755 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->buddy_icon_column); | |
2756 | |
2757 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL); | |
2758 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-expanded", G_CALLBACK(gtk_blist_row_expanded_cb), NULL); | |
2759 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-collapsed", G_CALLBACK(gtk_blist_row_collapsed_cb), NULL); | |
2760 g_signal_connect(G_OBJECT(gtkblist->treeview), "button-press-event", G_CALLBACK(gtk_blist_button_press_cb), NULL); | |
7620 | 2761 g_signal_connect(G_OBJECT(gtkblist->treeview), "key-press-event", G_CALLBACK(gtk_blist_key_press_cb), NULL); |
8143 | 2762 g_signal_connect(G_OBJECT(gtkblist->treeview), "popup-menu", G_CALLBACK(gaim_gtk_blist_popup_menu_cb), NULL); |
5228 | 2763 |
5419 | 2764 /* Enable CTRL+F searching */ |
2765 gtk_tree_view_set_search_column(GTK_TREE_VIEW(gtkblist->treeview), NAME_COLUMN); | |
2766 | |
5228 | 2767 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sw, TRUE, TRUE, 0); |
2768 gtk_container_add(GTK_CONTAINER(sw), gtkblist->treeview); | |
2769 gaim_gtk_blist_update_columns(); | |
2770 | |
2771 /* set the Show Offline Buddies option. must be done | |
2772 * after the treeview or faceprint gets mad. -Robot101 | |
2773 */ | |
5427 | 2774 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show Offline Buddies"))), |
7620 | 2775 gaim_prefs_get_bool("/gaim/gtk/blist/show_offline_buddies")); |
5427 | 2776 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show Empty Groups"))), |
7620 | 2777 gaim_prefs_get_bool("/gaim/gtk/blist/show_empty_groups")); |
5228 | 2778 |
2779 /* OK... let's show this bad boy. */ | |
2780 gaim_gtk_blist_refresh(list); | |
2781 gaim_gtk_blist_restore_position(); | |
2782 gtk_widget_show_all(gtkblist->window); | |
2783 | |
2784 /**************************** Button Box **************************************/ | |
2785 /* add this afterwards so it doesn't force up the width of the window */ | |
2786 | |
2787 gtkblist->tooltips = gtk_tooltips_new(); | |
2788 | |
2789 sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH); | |
2790 gtkblist->bbox = gtk_hbox_new(TRUE, 0); | |
2791 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->bbox, FALSE, FALSE, 0); | |
2792 gtk_widget_show(gtkblist->bbox); | |
2793 | |
8137 | 2794 button = gaim_pixbuf_button_from_stock(_("I_M"), GAIM_STOCK_IM, GAIM_BUTTON_VERTICAL); |
5228 | 2795 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); |
2796 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
2797 gtk_size_group_add_widget(sg, button); | |
2798 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_im_cb), | |
2799 gtkblist->treeview); | |
2800 gtk_tooltips_set_tip(GTK_TOOLTIPS(gtkblist->tooltips), button, _("Send a message to the selected buddy"), NULL); | |
2801 gtk_widget_show(button); | |
2802 | |
8137 | 2803 button = gaim_pixbuf_button_from_stock(_("Get _Info"), GAIM_STOCK_INFO, GAIM_BUTTON_VERTICAL); |
5228 | 2804 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); |
2805 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
2806 gtk_size_group_add_widget(sg, button); | |
2807 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_info_cb), | |
2808 gtkblist->treeview); | |
2809 gtk_tooltips_set_tip(GTK_TOOLTIPS(gtkblist->tooltips), button, _("Get information on the selected buddy"), NULL); | |
2810 gtk_widget_show(button); | |
2811 | |
8137 | 2812 button = gaim_pixbuf_button_from_stock(_("_Chat"), GAIM_STOCK_CHAT, GAIM_BUTTON_VERTICAL); |
5228 | 2813 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); |
2814 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
2815 gtk_size_group_add_widget(sg, button); | |
5234 | 2816 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_chat_cb), gtkblist->treeview); |
5228 | 2817 gtk_tooltips_set_tip(GTK_TOOLTIPS(gtkblist->tooltips), button, _("Join a chat room"), NULL); |
2818 gtk_widget_show(button); | |
2819 | |
8137 | 2820 button = gaim_pixbuf_button_from_stock(_("_Away"), GAIM_STOCK_ICON_AWAY, GAIM_BUTTON_VERTICAL); |
5228 | 2821 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); |
2822 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
2823 gtk_size_group_add_widget(sg, button); | |
2824 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_blist_button_away_cb), NULL); | |
2825 gtk_tooltips_set_tip(GTK_TOOLTIPS(gtkblist->tooltips), button, _("Set an away message"), NULL); | |
2826 gtk_widget_show(button); | |
2827 | |
2828 /* this will show the right image/label widgets for us */ | |
2829 gaim_gtk_blist_update_toolbar(); | |
2830 | |
2831 /* start the refresh timer */ | |
7620 | 2832 if (gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time") || |
2833 gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")) { | |
2834 | |
2835 gtkblist->refresh_timer = g_timeout_add(30000, | |
2836 (GSourceFunc)gaim_gtk_blist_refresh_timer, list); | |
2837 } | |
2838 | |
2839 /* attach prefs callbacks */ | |
2840 /* for the toolbar buttons */ | |
2841 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2842 GINT_TO_POINTER( | |
2843 gaim_prefs_connect_callback("/gaim/gtk/blist/button_style", | |
2844 gaim_gtk_blist_update_toolbar, NULL))); | |
2845 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2846 GINT_TO_POINTER( | |
2847 gaim_prefs_connect_callback("/gaim/gtk/blist/show_buttons", | |
2848 gaim_gtk_blist_update_toolbar, NULL))); | |
2849 | |
2850 /* things that affect how buddies are displayed */ | |
2851 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2852 GINT_TO_POINTER( | |
2853 gaim_prefs_connect_callback("/gaim/gtk/blist/grey_idle_buddies", | |
2854 _prefs_change_redo_list, NULL))); | |
2855 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2856 GINT_TO_POINTER( | |
2857 gaim_prefs_connect_callback("/gaim/gtk/blist/show_buddy_icons", | |
2858 _prefs_change_redo_list, NULL))); | |
2859 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2860 GINT_TO_POINTER( | |
2861 gaim_prefs_connect_callback("/gaim/gtk/blist/show_warning_level", | |
2862 _prefs_change_redo_list, NULL))); | |
2863 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2864 GINT_TO_POINTER( | |
2865 gaim_prefs_connect_callback("/gaim/gtk/blist/show_idle_time", | |
2866 _prefs_change_redo_list, NULL))); | |
2867 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2868 GINT_TO_POINTER( | |
2869 gaim_prefs_connect_callback("/gaim/gtk/blist/show_empty_groups", | |
2870 _prefs_change_redo_list, NULL))); | |
2871 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2872 GINT_TO_POINTER( | |
2873 gaim_prefs_connect_callback("/gaim/gtk/blist/show_group_count", | |
2874 _prefs_change_redo_list, NULL))); | |
2875 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2876 GINT_TO_POINTER( | |
2877 gaim_prefs_connect_callback("/gaim/gtk/blist/show_offline_buddies", | |
2878 _prefs_change_redo_list, NULL))); | |
2879 | |
2880 /* sorting */ | |
2881 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2882 GINT_TO_POINTER( | |
2883 gaim_prefs_connect_callback("/gaim/gtk/blist/sort_type", | |
2884 _prefs_change_sort_method, NULL))); | |
2885 | |
2886 /* things that affect what columns are displayed */ | |
2887 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2888 GINT_TO_POINTER( | |
2889 gaim_prefs_connect_callback("/gaim/gtk/blist/show_buddy_icons", | |
2890 gaim_gtk_blist_update_columns, NULL))); | |
2891 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2892 GINT_TO_POINTER( | |
2893 gaim_prefs_connect_callback("/gaim/gtk/blist/show_idle_time", | |
2894 gaim_gtk_blist_update_columns, NULL))); | |
2895 blist_prefs_callbacks = g_slist_prepend(blist_prefs_callbacks, | |
2896 GINT_TO_POINTER( | |
2897 gaim_prefs_connect_callback("/gaim/gtk/blist/show_warning_level", | |
2898 gaim_gtk_blist_update_columns, NULL))); | |
5228 | 2899 } |
2900 | |
7620 | 2901 /* XXX: does this need fixing? */ |
2902 static void redo_buddy_list(GaimBuddyList *list, gboolean remove) | |
5228 | 2903 { |
7620 | 2904 GaimBlistNode *gnode, *cnode, *bnode; |
2905 | |
2906 for(gnode = list->root; gnode; gnode = gnode->next) { | |
2907 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
5234 | 2908 continue; |
7620 | 2909 for(cnode = gnode->child; cnode; cnode = cnode->next) { |
2910 if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) { | |
2911 if(remove) | |
2912 gaim_gtk_blist_hide_node(list, cnode); | |
2913 | |
2914 for(bnode = cnode->child; bnode; bnode = bnode->next) { | |
2915 if(!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
2916 continue; | |
2917 if(remove) | |
2918 gaim_gtk_blist_hide_node(list, bnode); | |
2919 gaim_gtk_blist_update(list, bnode); | |
2920 } | |
2921 | |
2922 gaim_gtk_blist_update(list, cnode); | |
2923 } else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) { | |
2924 if(remove) | |
2925 gaim_gtk_blist_hide_node(list, cnode); | |
2926 | |
2927 gaim_gtk_blist_update(list, cnode); | |
2928 } | |
5228 | 2929 } |
7620 | 2930 gaim_gtk_blist_update(list, gnode); |
5228 | 2931 } |
2932 } | |
2933 | |
7620 | 2934 void gaim_gtk_blist_refresh(GaimBuddyList *list) |
5422 | 2935 { |
2936 redo_buddy_list(list, FALSE); | |
2937 } | |
2938 | |
5297 | 2939 void |
2940 gaim_gtk_blist_update_refresh_timeout() | |
2941 { | |
7620 | 2942 GaimBuddyList *blist; |
2943 GaimGtkBuddyList *gtkblist; | |
5297 | 2944 |
2945 blist = gaim_get_blist(); | |
2946 gtkblist = GAIM_GTK_BLIST(gaim_get_blist()); | |
2947 | |
7620 | 2948 if (gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time") || |
2949 gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")) { | |
2950 | |
2951 gtkblist->refresh_timer = g_timeout_add(30000, | |
2952 (GSourceFunc)gaim_gtk_blist_refresh_timer, blist); | |
5297 | 2953 } else { |
2954 g_source_remove(gtkblist->refresh_timer); | |
2955 gtkblist->refresh_timer = 0; | |
2956 } | |
2957 } | |
2958 | |
5256 | 2959 static gboolean get_iter_from_node(GaimBlistNode *node, GtkTreeIter *iter) { |
2960 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; | |
2961 GtkTreePath *path; | |
5228 | 2962 |
7620 | 2963 /* XXX: why do we assume we have a buddy here? */ |
5263 | 2964 if (!gtknode) { |
7620 | 2965 #if 0 |
2966 gaim_debug(GAIM_DEBUG_ERROR, "gtkblist", "buddy %s has no ui_data\n", ((GaimBuddy *)node)->name); | |
2967 #endif | |
5263 | 2968 return FALSE; |
2969 } | |
2970 | |
2971 if (!gtkblist) { | |
2972 gaim_debug(GAIM_DEBUG_ERROR, "gtkblist", "get_iter_from_node was called, but we don't seem to have a blist\n"); | |
2973 return FALSE; | |
2974 } | |
2975 | |
2976 if (!gtknode->row) | |
5228 | 2977 return FALSE; |
2978 | |
5256 | 2979 if ((path = gtk_tree_row_reference_get_path(gtknode->row)) == NULL) |
5228 | 2980 return FALSE; |
5256 | 2981 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), iter, path)) { |
2982 gtk_tree_path_free(path); | |
2983 return FALSE; | |
2984 } | |
2985 gtk_tree_path_free(path); | |
2986 return TRUE; | |
5228 | 2987 } |
2988 | |
7620 | 2989 static void |
2990 gaim_gtk_blist_update_toolbar_icons (GtkWidget *widget, gpointer data) | |
2991 { | |
2992 GaimButtonStyle style = gaim_prefs_get_int("/gaim/gtk/blist/button_style"); | |
2993 | |
5228 | 2994 if (GTK_IS_IMAGE(widget)) { |
7620 | 2995 if (style == GAIM_BUTTON_IMAGE || style == GAIM_BUTTON_TEXT_IMAGE) |
5228 | 2996 gtk_widget_show(widget); |
2997 else | |
2998 gtk_widget_hide(widget); | |
7620 | 2999 } |
3000 else if (GTK_IS_LABEL(widget)) { | |
3001 if (style == GAIM_BUTTON_IMAGE) | |
5228 | 3002 gtk_widget_hide(widget); |
3003 else | |
3004 gtk_widget_show(widget); | |
7620 | 3005 } |
3006 else if (GTK_IS_CONTAINER(widget)) { | |
3007 gtk_container_foreach(GTK_CONTAINER(widget), | |
3008 gaim_gtk_blist_update_toolbar_icons, NULL); | |
5228 | 3009 } |
3010 } | |
3011 | |
3012 void gaim_gtk_blist_update_toolbar() { | |
3013 if (!gtkblist) | |
3014 return; | |
3015 | |
7620 | 3016 if (gaim_prefs_get_int("/gaim/gtk/blist/button_style") == GAIM_BUTTON_NONE) |
5228 | 3017 gtk_widget_hide(gtkblist->bbox); |
3018 else { | |
7620 | 3019 gtk_container_foreach(GTK_CONTAINER(gtkblist->bbox), |
3020 gaim_gtk_blist_update_toolbar_icons, NULL); | |
5228 | 3021 gtk_widget_show(gtkblist->bbox); |
3022 } | |
3023 } | |
3024 | |
7620 | 3025 static void gaim_gtk_blist_remove(GaimBuddyList *list, GaimBlistNode *node) |
5228 | 3026 { |
5260 | 3027 gaim_gtk_blist_hide_node(list, node); |
5228 | 3028 |
7620 | 3029 if(node->parent) |
3030 gaim_gtk_blist_update(list, node->parent); | |
3031 | |
5263 | 3032 /* There's something I don't understand here */ |
3033 /* g_free(node->ui_data); | |
3034 node->ui_data = NULL; */ | |
5228 | 3035 } |
3036 | |
3037 static gboolean do_selection_changed(GaimBlistNode *new_selection) | |
3038 { | |
5254 | 3039 GaimBlistNode *old_selection = NULL; |
5228 | 3040 |
5254 | 3041 /* test for gtkblist because crazy timeout means we can be called after the blist is gone */ |
3042 if (gtkblist && new_selection != gtkblist->selected_node) { | |
3043 old_selection = gtkblist->selected_node; | |
5228 | 3044 gtkblist->selected_node = new_selection; |
3045 if(new_selection) | |
3046 gaim_gtk_blist_update(NULL, new_selection); | |
3047 if(old_selection) | |
3048 gaim_gtk_blist_update(NULL, old_selection); | |
3049 } | |
3050 | |
3051 return FALSE; | |
3052 } | |
3053 | |
3054 static void gaim_gtk_blist_selection_changed(GtkTreeSelection *selection, gpointer data) | |
3055 { | |
3056 GaimBlistNode *new_selection = NULL; | |
3057 GtkTreeIter iter; | |
3058 | |
3059 if(gtk_tree_selection_get_selected(selection, NULL, &iter)){ | |
3060 gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, | |
3061 NODE_COLUMN, &new_selection, -1); | |
3062 } | |
5254 | 3063 |
5228 | 3064 /* we set this up as a timeout, otherwise the blist flickers */ |
3065 g_timeout_add(0, (GSourceFunc)do_selection_changed, new_selection); | |
3066 } | |
3067 | |
8252 | 3068 static gboolean insert_node(GaimBuddyList *list, GaimBlistNode *node, GtkTreeIter *iter) |
7620 | 3069 { |
3070 GtkTreeIter parent_iter, cur, *curptr = NULL; | |
3071 struct _gaim_gtk_blist_node *gtknode = node->ui_data; | |
5256 | 3072 GtkTreePath *newpath; |
7620 | 3073 |
3074 if(!gtknode || !iter) | |
8252 | 3075 return FALSE; |
7620 | 3076 |
3077 if(node->parent && !get_iter_from_node(node->parent, &parent_iter)) | |
8252 | 3078 return FALSE; |
7620 | 3079 |
3080 if(get_iter_from_node(node, &cur)) | |
3081 curptr = &cur; | |
3082 | |
3083 if(GAIM_BLIST_NODE_IS_CONTACT(node) || GAIM_BLIST_NODE_IS_CHAT(node)) { | |
3084 *iter = current_sort_method->func(node, list, parent_iter, curptr); | |
3085 } else { | |
3086 *iter = sort_method_none(node, list, parent_iter, curptr); | |
5228 | 3087 } |
3088 | |
7620 | 3089 gtk_tree_row_reference_free(gtknode->row); |
3090 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), | |
3091 iter); | |
3092 gtknode->row = | |
3093 gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), | |
3094 newpath); | |
5256 | 3095 gtk_tree_path_free(newpath); |
3096 | |
5228 | 3097 gtk_tree_store_set(gtkblist->treemodel, iter, |
3098 NODE_COLUMN, node, | |
3099 -1); | |
7620 | 3100 |
3101 if(node->parent) { | |
3102 GtkTreePath *expand = NULL; | |
3103 struct _gaim_gtk_blist_node *gtkparentnode = node->parent->ui_data; | |
3104 | |
3105 if(GAIM_BLIST_NODE_IS_GROUP(node->parent)) { | |
7693 | 3106 if(!gaim_blist_node_get_bool(node->parent, "collapsed")) |
7620 | 3107 expand = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &parent_iter); |
3108 } else if(GAIM_BLIST_NODE_IS_CONTACT(node->parent) && | |
3109 gtkparentnode->contact_expanded) { | |
3110 expand = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &parent_iter); | |
3111 } | |
3112 if(expand) { | |
7693 | 3113 gtk_tree_view_expand_row(GTK_TREE_VIEW(gtkblist->treeview), expand, FALSE); |
7620 | 3114 gtk_tree_path_free(expand); |
3115 } | |
3116 } | |
3117 | |
8252 | 3118 return TRUE; |
5228 | 3119 } |
3120 | |
7620 | 3121 static void gaim_gtk_blist_update_group(GaimBuddyList *list, GaimBlistNode *node) |
3122 { | |
3123 GaimGroup *group; | |
8203 | 3124 int count; |
7620 | 3125 |
3126 g_return_if_fail(GAIM_BLIST_NODE_IS_GROUP(node)); | |
3127 | |
3128 group = (GaimGroup*)node; | |
3129 | |
8203 | 3130 if(gaim_prefs_get_bool("/gaim/gtk/blist/show_offline_buddies")) |
3131 count = gaim_blist_get_group_size(group, FALSE); | |
3132 else | |
3133 count = gaim_blist_get_group_online_count(group); | |
3134 if(gaim_prefs_get_bool("/gaim/gtk/blist/show_empty_groups") || count > 0) { | |
7620 | 3135 char *mark, *esc; |
3136 GtkTreeIter iter; | |
3137 | |
8252 | 3138 if(!insert_node(list, node, &iter)) |
3139 return; | |
7620 | 3140 |
3141 esc = g_markup_escape_text(group->name, -1); | |
3142 if(gaim_prefs_get_bool("/gaim/gtk/blist/show_group_count")) { | |
3143 mark = g_strdup_printf("<span weight='bold'>%s</span> (%d/%d)", | |
3144 esc, gaim_blist_get_group_online_count(group), | |
3145 gaim_blist_get_group_size(group, FALSE)); | |
3146 } else { | |
3147 mark = g_strdup_printf("<span weight='bold'>%s</span>", esc); | |
3148 } | |
3149 g_free(esc); | |
3150 | |
3151 gtk_tree_store_set(gtkblist->treemodel, &iter, | |
3152 STATUS_ICON_COLUMN, NULL, | |
3153 STATUS_ICON_VISIBLE_COLUMN, FALSE, | |
3154 NAME_COLUMN, mark, | |
3155 NODE_COLUMN, node, | |
3156 -1); | |
3157 g_free(mark); | |
3158 } else { | |
3159 gaim_gtk_blist_hide_node(list, node); | |
3160 } | |
3161 } | |
3162 | |
3163 static void buddy_node(GaimBuddy *buddy, GtkTreeIter *iter, GaimBlistNode *node) | |
5228 | 3164 { |
7620 | 3165 GdkPixbuf *status, *avatar; |
3166 char *mark; | |
3167 char *warning = NULL, *idle = NULL; | |
3168 | |
3169 gboolean selected = (gtkblist->selected_node == node); | |
3170 | |
3171 status = gaim_gtk_blist_get_status_icon((GaimBlistNode*)buddy, | |
3172 (gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons") | |
3173 ? GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL)); | |
3174 | |
3175 avatar = gaim_gtk_blist_get_buddy_icon(buddy); | |
3176 mark = gaim_gtk_blist_get_name_markup(buddy, selected); | |
3177 | |
3178 if (buddy->idle > 0) { | |
3179 time_t t; | |
3180 int ihrs, imin; | |
3181 time(&t); | |
3182 ihrs = (t - buddy->idle) / 3600; | |
3183 imin = ((t - buddy->idle) / 60) % 60; | |
3184 if(ihrs > 0) | |
3185 idle = g_strdup_printf("(%d:%02d)", ihrs, imin); | |
3186 else | |
3187 idle = g_strdup_printf("(%d)", imin); | |
3188 } | |
3189 | |
3190 if (buddy->evil > 0) | |
3191 warning = g_strdup_printf("%d%%", buddy->evil); | |
3192 | |
3193 if (gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies") && | |
3194 buddy->idle) { | |
3195 | |
3196 if(warning && !selected) { | |
3197 char *w2 = g_strdup_printf("<span color='dim grey'>%s</span>", | |
3198 warning); | |
3199 g_free(warning); | |
3200 warning = w2; | |
3201 } | |
3202 | |
3203 if(idle && !selected) { | |
3204 char *i2 = g_strdup_printf("<span color='dim grey'>%s</span>", | |
3205 idle); | |
3206 g_free(idle); | |
3207 idle = i2; | |
5228 | 3208 } |
7620 | 3209 } |
3210 | |
3211 gtk_tree_store_set(gtkblist->treemodel, iter, | |
3212 STATUS_ICON_COLUMN, status, | |
3213 STATUS_ICON_VISIBLE_COLUMN, TRUE, | |
3214 NAME_COLUMN, mark, | |
3215 WARNING_COLUMN, warning, | |
3216 IDLE_COLUMN, idle, | |
3217 BUDDY_ICON_COLUMN, avatar, | |
3218 -1); | |
3219 | |
3220 g_free(mark); | |
3221 if(idle) | |
3222 g_free(idle); | |
3223 if(warning) | |
3224 g_free(warning); | |
3225 if(status) | |
3226 g_object_unref(status); | |
3227 if(avatar) | |
3228 g_object_unref(avatar); | |
3229 } | |
3230 | |
3231 static void gaim_gtk_blist_update_contact(GaimBuddyList *list, GaimBlistNode *node) | |
3232 { | |
3233 GaimContact *contact; | |
3234 GaimBuddy *buddy; | |
3235 struct _gaim_gtk_blist_node *gtknode; | |
3236 | |
3237 g_return_if_fail(GAIM_BLIST_NODE_IS_CONTACT(node)); | |
3238 | |
3239 /* First things first, update the group */ | |
3240 gaim_gtk_blist_update_group(list, node->parent); | |
3241 | |
3242 gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; | |
3243 contact = (GaimContact*)node; | |
3244 buddy = gaim_contact_get_priority_buddy(contact); | |
3245 | |
3246 if(buddy && (buddy->present != GAIM_BUDDY_OFFLINE || | |
3247 (gaim_account_is_connected(buddy->account) && | |
3248 gaim_prefs_get_bool("/gaim/gtk/blist/show_offline_buddies")))) { | |
3249 GtkTreeIter iter; | |
3250 | |
8252 | 3251 if(!insert_node(list, node, &iter)) |
3252 return; | |
7620 | 3253 |
3254 if(gtknode->contact_expanded) { | |
3255 GdkPixbuf *status; | |
5228 | 3256 char *mark; |
3257 | |
7620 | 3258 status = gaim_gtk_blist_get_status_icon(node, |
3259 (gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons") ? | |
3260 GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL)); | |
3261 | |
3262 mark = g_markup_escape_text(gaim_contact_get_alias(contact), -1); | |
3263 | |
5228 | 3264 gtk_tree_store_set(gtkblist->treemodel, &iter, |
7620 | 3265 STATUS_ICON_COLUMN, status, |
3266 STATUS_ICON_VISIBLE_COLUMN, TRUE, | |
5228 | 3267 NAME_COLUMN, mark, |
7620 | 3268 WARNING_COLUMN, NULL, |
3269 IDLE_COLUMN, NULL, | |
3270 BUDDY_ICON_COLUMN, NULL, | |
5228 | 3271 -1); |
3272 g_free(mark); | |
7620 | 3273 if(status) |
3274 g_object_unref(status); | |
3275 } else { | |
3276 buddy_node(buddy, &iter, node); | |
5228 | 3277 } |
7620 | 3278 } else { |
3279 gaim_gtk_blist_hide_node(list, node); | |
5228 | 3280 } |
7620 | 3281 } |
3282 | |
3283 static void gaim_gtk_blist_update_buddy(GaimBuddyList *list, GaimBlistNode *node) | |
3284 { | |
3285 GaimContact *contact; | |
3286 GaimBuddy *buddy; | |
3287 struct _gaim_gtk_blist_node *gtkparentnode; | |
3288 | |
3289 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
3290 | |
3291 buddy = (GaimBuddy*)node; | |
3292 contact = (GaimContact*)node->parent; | |
3293 gtkparentnode = (struct _gaim_gtk_blist_node *)node->parent->ui_data; | |
3294 | |
3295 /* First things first, update the contact */ | |
3296 gaim_gtk_blist_update_contact(list, node->parent); | |
3297 | |
3298 if(gtkparentnode->contact_expanded && | |
3299 (buddy->present != GAIM_BUDDY_OFFLINE || | |
3300 (gaim_account_is_connected(buddy->account) && | |
3301 gaim_prefs_get_bool("/gaim/gtk/blist/show_offline_buddies")))) { | |
3302 GtkTreeIter iter; | |
3303 | |
8252 | 3304 if(!insert_node(list, node, &iter)) |
3305 return; | |
3306 | |
7620 | 3307 buddy_node(buddy, &iter, node); |
3308 | |
3309 } else { | |
3310 gaim_gtk_blist_hide_node(list, node); | |
3311 } | |
3312 | |
3313 } | |
3314 | |
3315 static void gaim_gtk_blist_update_chat(GaimBuddyList *list, GaimBlistNode *node) | |
3316 { | |
3317 GaimChat *chat; | |
3318 | |
3319 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node)); | |
3320 | |
3321 /* First things first, update the group */ | |
3322 gaim_gtk_blist_update_group(list, node->parent); | |
3323 | |
3324 chat = (GaimChat*)node; | |
3325 | |
3326 if(gaim_account_is_connected(chat->account)) { | |
3327 GtkTreeIter iter; | |
5234 | 3328 GdkPixbuf *status; |
7620 | 3329 char *mark; |
3330 | |
8252 | 3331 if(!insert_node(list, node, &iter)) |
3332 return; | |
5234 | 3333 |
3334 status = gaim_gtk_blist_get_status_icon(node, | |
7620 | 3335 (gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons") ? |
3336 GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL)); | |
3337 | |
3338 mark = g_markup_escape_text(gaim_chat_get_name(chat), -1); | |
5234 | 3339 |
3340 gtk_tree_store_set(gtkblist->treemodel, &iter, | |
7620 | 3341 STATUS_ICON_COLUMN, status, |
3342 STATUS_ICON_VISIBLE_COLUMN, TRUE, | |
3343 NAME_COLUMN, mark, | |
3344 -1); | |
5228 | 3345 |
3346 g_free(mark); | |
7620 | 3347 if(status) |
5228 | 3348 g_object_unref(status); |
7620 | 3349 } else { |
5260 | 3350 gaim_gtk_blist_hide_node(list, node); |
5228 | 3351 } |
7620 | 3352 } |
3353 | |
3354 static void gaim_gtk_blist_update(GaimBuddyList *list, GaimBlistNode *node) | |
3355 { | |
3356 if(!gtkblist) | |
3357 return; | |
3358 | |
3359 switch(node->type) { | |
3360 case GAIM_BLIST_GROUP_NODE: | |
3361 gaim_gtk_blist_update_group(list, node); | |
3362 break; | |
3363 case GAIM_BLIST_CONTACT_NODE: | |
3364 gaim_gtk_blist_update_contact(list, node); | |
3365 break; | |
3366 case GAIM_BLIST_BUDDY_NODE: | |
3367 gaim_gtk_blist_update_buddy(list, node); | |
3368 break; | |
3369 case GAIM_BLIST_CHAT_NODE: | |
3370 gaim_gtk_blist_update_chat(list, node); | |
3371 break; | |
3372 case GAIM_BLIST_OTHER_NODE: | |
3373 return; | |
3374 } | |
5234 | 3375 |
5228 | 3376 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(gtkblist->treeview)); |
3377 } | |
3378 | |
7620 | 3379 |
3380 static void gaim_gtk_blist_destroy(GaimBuddyList *list) | |
5228 | 3381 { |
3382 if (!gtkblist) | |
3383 return; | |
3384 | |
3385 gtk_widget_destroy(gtkblist->window); | |
7620 | 3386 |
3387 if (gtkblist->tipwindow) | |
3388 gtk_widget_destroy(gtkblist->tipwindow); | |
3389 | |
5228 | 3390 gtk_object_sink(GTK_OBJECT(gtkblist->tooltips)); |
3391 | |
3392 if (gtkblist->refresh_timer) | |
3393 g_source_remove(gtkblist->refresh_timer); | |
3394 if (gtkblist->timeout) | |
3395 g_source_remove(gtkblist->timeout); | |
3396 | |
3397 gtkblist->refresh_timer = 0; | |
3398 gtkblist->timeout = 0; | |
3399 gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL; | |
3400 gtkblist->treemodel = NULL; | |
3401 gtkblist->idle_column = NULL; | |
3402 gtkblist->warning_column = gtkblist->buddy_icon_column = NULL; | |
3403 gtkblist->bbox = gtkblist->tipwindow = NULL; | |
5427 | 3404 g_object_unref(G_OBJECT(gtkblist->ift)); |
5228 | 3405 protomenu = NULL; |
3406 awaymenu = NULL; | |
3407 gtkblist = NULL; | |
7620 | 3408 |
3409 while(blist_prefs_callbacks) { | |
3410 gaim_prefs_disconnect_callback(GPOINTER_TO_INT(blist_prefs_callbacks->data)); | |
3411 blist_prefs_callbacks = g_slist_remove(blist_prefs_callbacks, blist_prefs_callbacks->data); | |
3412 } | |
5228 | 3413 } |
3414 | |
7620 | 3415 static void gaim_gtk_blist_set_visible(GaimBuddyList *list, gboolean show) |
5228 | 3416 { |
3417 if (!(gtkblist && gtkblist->window)) | |
3418 return; | |
3419 | |
3420 if (show) { | |
3421 gaim_gtk_blist_restore_position(); | |
3422 gtk_window_present(GTK_WINDOW(gtkblist->window)); | |
3423 } else { | |
7620 | 3424 if (!gaim_connections_get_all() || docklet_count) { |
5228 | 3425 #ifdef _WIN32 |
3426 wgaim_systray_minimize(gtkblist->window); | |
3427 #endif | |
3428 gtk_widget_hide(gtkblist->window); | |
3429 } else { | |
3430 gtk_window_iconify(GTK_WINDOW(gtkblist->window)); | |
3431 } | |
3432 } | |
3433 } | |
3434 | |
7620 | 3435 static GList * |
3436 groups_tree(void) | |
3437 { | |
3438 GList *tmp = NULL; | |
3439 char *tmp2; | |
3440 GaimGroup *g; | |
3441 GaimBlistNode *gnode; | |
3442 | |
3443 if (gaim_get_blist()->root == NULL) | |
3444 { | |
3445 tmp2 = g_strdup(_("Buddies")); | |
3446 tmp = g_list_append(tmp, tmp2); | |
3447 } | |
3448 else | |
3449 { | |
3450 for (gnode = gaim_get_blist()->root; | |
3451 gnode != NULL; | |
3452 gnode = gnode->next) | |
3453 { | |
3454 if (GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
3455 { | |
3456 g = (GaimGroup *)gnode; | |
3457 tmp2 = g->name; | |
3458 tmp = g_list_append(tmp, tmp2); | |
3459 } | |
3460 } | |
3461 } | |
3462 | |
3463 return tmp; | |
3464 } | |
3465 | |
3466 static void | |
3467 add_buddy_select_account_cb(GObject *w, GaimAccount *account, | |
3468 GaimGtkAddBuddyData *data) | |
3469 { | |
3470 /* Save our account */ | |
3471 data->account = account; | |
3472 } | |
3473 | |
3474 static void | |
3475 destroy_add_buddy_dialog_cb(GtkWidget *win, GaimGtkAddBuddyData *data) | |
3476 { | |
3477 g_free(data); | |
3478 } | |
3479 | |
3480 static void | |
3481 add_buddy_cb(GtkWidget *w, int resp, GaimGtkAddBuddyData *data) | |
3482 { | |
3483 const char *grp, *who, *whoalias; | |
3484 GaimConversation *c; | |
3485 GaimBuddy *b; | |
3486 GaimGroup *g; | |
3487 | |
3488 if (resp == GTK_RESPONSE_OK) | |
3489 { | |
3490 who = gtk_entry_get_text(GTK_ENTRY(data->entry)); | |
3491 grp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(data->combo)->entry)); | |
3492 whoalias = gtk_entry_get_text(GTK_ENTRY(data->entry_for_alias)); | |
3493 | |
3494 c = gaim_find_conversation_with_account(who, data->account); | |
3495 | |
3496 if ((g = gaim_find_group(grp)) == NULL) | |
3497 { | |
3498 g = gaim_group_new(grp); | |
3499 gaim_blist_add_group(g, NULL); | |
3500 } | |
3501 | |
3502 b = gaim_buddy_new(data->account, who, whoalias); | |
3503 gaim_blist_add_buddy(b, NULL, g, NULL); | |
3504 serv_add_buddy(gaim_account_get_connection(data->account), who, g); | |
3505 | |
7887 | 3506 /* |
3507 * It really seems like it would be better if the call to serv_add_buddy() | |
3508 * and gaim_conversation_update() were done in blist.c, possibly in the | |
3509 * gaim_blist_add_buddy() function. Maybe serv_add_buddy() should be | |
3510 * renamed to gaim_blist_add_new_buddy() or something, and have it call | |
3511 * gaim_blist_add_buddy() after it creates it. --Mark | |
3512 */ | |
3513 | |
7620 | 3514 if (c != NULL) { |
3515 gaim_buddy_icon_update(gaim_conv_im_get_icon(GAIM_CONV_IM(c))); | |
3516 gaim_conversation_update(c, GAIM_CONV_UPDATE_ADD); | |
3517 } | |
3518 | |
3519 gaim_blist_save(); | |
3520 } | |
3521 | |
3522 gtk_widget_destroy(data->window); | |
3523 } | |
3524 | |
3525 static void | |
3526 gaim_gtk_blist_request_add_buddy(GaimAccount *account, const char *username, | |
3527 const char *group, const char *alias) | |
3528 { | |
3529 GtkWidget *table; | |
3530 GtkWidget *label; | |
3531 GtkWidget *hbox; | |
3532 GtkWidget *vbox; | |
3533 GtkWidget *img; | |
3534 GaimGtkBuddyList *gtkblist; | |
3535 GaimGtkAddBuddyData *data = g_new0(GaimGtkAddBuddyData, 1); | |
3536 | |
3537 data->account = | |
3538 (account != NULL | |
3539 ? account | |
3540 : gaim_connection_get_account(gaim_connections_get_all()->data)); | |
3541 | |
3542 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, | |
3543 GTK_ICON_SIZE_DIALOG); | |
3544 | |
3545 gtkblist = GAIM_GTK_BLIST(gaim_get_blist()); | |
3546 | |
3547 data->window = gtk_dialog_new_with_buttons(_("Add Buddy"), | |
8222 | 3548 NULL, 0, |
7620 | 3549 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
3550 GTK_STOCK_ADD, GTK_RESPONSE_OK, | |
3551 NULL); | |
3552 | |
3553 gtk_dialog_set_default_response(GTK_DIALOG(data->window), GTK_RESPONSE_OK); | |
3554 gtk_container_set_border_width(GTK_CONTAINER(data->window), 6); | |
3555 gtk_window_set_resizable(GTK_WINDOW(data->window), FALSE); | |
3556 gtk_dialog_set_has_separator(GTK_DIALOG(data->window), FALSE); | |
3557 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(data->window)->vbox), 12); | |
3558 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), 6); | |
3559 gtk_window_set_role(GTK_WINDOW(data->window), "add_buddy"); | |
3560 | |
3561 hbox = gtk_hbox_new(FALSE, 12); | |
3562 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), hbox); | |
3563 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); | |
3564 gtk_misc_set_alignment(GTK_MISC(img), 0, 0); | |
3565 | |
3566 vbox = gtk_vbox_new(FALSE, 0); | |
3567 gtk_container_add(GTK_CONTAINER(hbox), vbox); | |
3568 | |
3569 label = gtk_label_new( | |
3570 _("Please enter the screen name of the person you would like " | |
3571 "to add to your buddy list. You may optionally enter an alias, " | |
3572 "or nickname, for the buddy. The alias will be displayed in " | |
3573 "place of the screen name whenever possible.\n")); | |
3574 | |
3575 gtk_widget_set_size_request(GTK_WIDGET(label), 400, -1); | |
3576 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); | |
3577 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); | |
3578 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); | |
3579 | |
3580 hbox = gtk_hbox_new(FALSE, 6); | |
3581 gtk_container_add(GTK_CONTAINER(vbox), hbox); | |
3582 | |
3583 g_signal_connect(G_OBJECT(data->window), "destroy", | |
3584 G_CALLBACK(destroy_add_buddy_dialog_cb), data); | |
3585 | |
3586 table = gtk_table_new(4, 2, FALSE); | |
3587 gtk_table_set_row_spacings(GTK_TABLE(table), 5); | |
3588 gtk_table_set_col_spacings(GTK_TABLE(table), 5); | |
3589 gtk_container_set_border_width(GTK_CONTAINER(table), 0); | |
3590 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); | |
3591 | |
3592 label = gtk_label_new(_("Screen Name:")); | |
3593 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
3594 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); | |
3595 | |
3596 data->entry = gtk_entry_new(); | |
3597 gtk_table_attach_defaults(GTK_TABLE(table), data->entry, 1, 2, 0, 1); | |
3598 gtk_widget_grab_focus(data->entry); | |
3599 | |
3600 if (username != NULL) | |
3601 gtk_entry_set_text(GTK_ENTRY(data->entry), username); | |
3602 | |
3603 gtk_entry_set_activates_default (GTK_ENTRY(data->entry), TRUE); | |
8137 | 3604 gaim_set_accessible_label (data->entry, label); |
7620 | 3605 |
3606 label = gtk_label_new(_("Alias:")); | |
3607 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
3608 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); | |
3609 | |
3610 data->entry_for_alias = gtk_entry_new(); | |
3611 gtk_table_attach_defaults(GTK_TABLE(table), | |
3612 data->entry_for_alias, 1, 2, 1, 2); | |
3613 | |
3614 if (alias != NULL) | |
3615 gtk_entry_set_text(GTK_ENTRY(data->entry_for_alias), alias); | |
3616 | |
3617 gtk_entry_set_activates_default (GTK_ENTRY(data->entry_for_alias), TRUE); | |
8137 | 3618 gaim_set_accessible_label (data->entry_for_alias, label); |
7620 | 3619 |
3620 label = gtk_label_new(_("Group:")); | |
3621 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
3622 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); | |
3623 | |
3624 data->combo = gtk_combo_new(); | |
3625 gtk_combo_set_popdown_strings(GTK_COMBO(data->combo), groups_tree()); | |
3626 gtk_table_attach_defaults(GTK_TABLE(table), data->combo, 1, 2, 2, 3); | |
8137 | 3627 gaim_set_accessible_label (data->combo, label); |
7620 | 3628 |
3629 /* Set up stuff for the account box */ | |
3630 label = gtk_label_new(_("Account:")); | |
3631 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
3632 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4); | |
3633 | |
3634 data->account_box = gaim_gtk_account_option_menu_new(account, FALSE, | |
3635 G_CALLBACK(add_buddy_select_account_cb), NULL, data); | |
3636 | |
3637 gtk_table_attach_defaults(GTK_TABLE(table), data->account_box, 1, 2, 3, 4); | |
8137 | 3638 gaim_set_accessible_label (data->account_box, label); |
7620 | 3639 |
3640 /* End of account box */ | |
3641 | |
3642 g_signal_connect(G_OBJECT(data->window), "response", | |
3643 G_CALLBACK(add_buddy_cb), data); | |
3644 | |
3645 gtk_widget_show_all(data->window); | |
3646 | |
3647 if (group != NULL) | |
3648 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(data->combo)->entry), group); | |
3649 } | |
3650 | |
3651 static void | |
3652 add_chat_cb(GtkWidget *w, GaimGtkAddChatData *data) | |
3653 { | |
3654 GHashTable *components; | |
3655 GList *tmp; | |
3656 GaimChat *chat; | |
3657 GaimGroup *group; | |
3658 const char *group_name; | |
3659 | |
3660 components = g_hash_table_new_full(g_str_hash, g_str_equal, | |
3661 g_free, g_free); | |
3662 | |
3663 for (tmp = data->entries; tmp; tmp = tmp->next) | |
3664 { | |
3665 if (g_object_get_data(tmp->data, "is_spin")) | |
3666 { | |
3667 g_hash_table_replace(components, | |
3668 g_strdup(g_object_get_data(tmp->data, "identifier")), | |
3669 g_strdup_printf("%d", | |
3670 gtk_spin_button_get_value_as_int(tmp->data))); | |
3671 } | |
3672 else | |
3673 { | |
3674 g_hash_table_replace(components, | |
3675 g_strdup(g_object_get_data(tmp->data, "identifier")), | |
3676 g_strdup(gtk_entry_get_text(tmp->data))); | |
3677 } | |
3678 } | |
3679 | |
3680 chat = gaim_chat_new(data->account, | |
3681 gtk_entry_get_text(GTK_ENTRY(data->alias_entry)), | |
3682 components); | |
3683 | |
3684 group_name = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(data->group_combo)->entry)); | |
3685 | |
3686 if ((group = gaim_find_group(group_name)) == NULL) | |
3687 { | |
3688 group = gaim_group_new(group_name); | |
3689 gaim_blist_add_group(group, NULL); | |
3690 } | |
3691 | |
3692 if (chat != NULL) | |
3693 { | |
3694 gaim_blist_add_chat(chat, group, NULL); | |
3695 gaim_blist_save(); | |
3696 } | |
3697 | |
3698 gtk_widget_destroy(data->window); | |
3699 g_list_free(data->entries); | |
3700 | |
3701 g_free(data); | |
3702 } | |
3703 | |
3704 static void | |
3705 add_chat_resp_cb(GtkWidget *w, int resp, GaimGtkAddChatData *data) | |
3706 { | |
3707 if (resp == GTK_RESPONSE_OK) | |
3708 { | |
3709 add_chat_cb(NULL, data); | |
3710 } | |
3711 else | |
3712 { | |
3713 gtk_widget_destroy(data->window); | |
3714 g_list_free(data->entries); | |
3715 g_free(data); | |
3716 } | |
3717 } | |
3718 | |
3719 static void | |
3720 rebuild_addchat_entries(GaimGtkAddChatData *data) | |
3721 { | |
3722 GaimConnection *gc; | |
3723 GList *list, *tmp; | |
3724 struct proto_chat_entry *pce; | |
3725 gboolean focus = TRUE; | |
3726 | |
3727 gc = gaim_account_get_connection(data->account); | |
3728 | |
3729 while (GTK_BOX(data->entries_box)->children) | |
3730 { | |
3731 gtk_container_remove(GTK_CONTAINER(data->entries_box), | |
3732 ((GtkBoxChild *)GTK_BOX(data->entries_box)->children->data)->widget); | |
3733 } | |
3734 | |
3735 if (data->entries != NULL) | |
3736 g_list_free(data->entries); | |
3737 | |
3738 data->entries = NULL; | |
3739 | |
3740 list = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info(gc); | |
3741 | |
3742 for (tmp = list; tmp; tmp = tmp->next) | |
3743 { | |
3744 GtkWidget *label; | |
3745 GtkWidget *rowbox; | |
3746 | |
3747 pce = tmp->data; | |
3748 | |
3749 rowbox = gtk_hbox_new(FALSE, 5); | |
3750 gtk_box_pack_start(GTK_BOX(data->entries_box), rowbox, FALSE, FALSE, 0); | |
3751 | |
7889 | 3752 label = gtk_label_new_with_mnemonic(pce->label); |
7620 | 3753 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
3754 gtk_size_group_add_widget(data->sg, label); | |
3755 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); | |
3756 | |
3757 if (pce->is_int) | |
3758 { | |
3759 GtkObject *adjust; | |
3760 GtkWidget *spin; | |
3761 adjust = gtk_adjustment_new(pce->min, pce->min, pce->max, | |
3762 1, 10, 10); | |
3763 spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0); | |
3764 g_object_set_data(G_OBJECT(spin), "is_spin", GINT_TO_POINTER(TRUE)); | |
3765 g_object_set_data(G_OBJECT(spin), "identifier", pce->identifier); | |
3766 data->entries = g_list_append(data->entries, spin); | |
3767 gtk_widget_set_size_request(spin, 50, -1); | |
3768 gtk_box_pack_end(GTK_BOX(rowbox), spin, FALSE, FALSE, 0); | |
7891 | 3769 gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin); |
8137 | 3770 gaim_set_accessible_label (spin, label); |
7620 | 3771 } |
3772 else | |
3773 { | |
3774 GtkWidget *entry = gtk_entry_new(); | |
3775 | |
3776 g_object_set_data(G_OBJECT(entry), "identifier", pce->identifier); | |
3777 data->entries = g_list_append(data->entries, entry); | |
3778 | |
3779 if (pce->def) | |
3780 gtk_entry_set_text(GTK_ENTRY(entry), pce->def); | |
3781 | |
3782 if (focus) | |
3783 { | |
3784 gtk_widget_grab_focus(entry); | |
3785 focus = FALSE; | |
3786 } | |
3787 | |
3788 if (pce->secret) | |
3789 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); | |
3790 | |
3791 gtk_box_pack_end(GTK_BOX(rowbox), entry, TRUE, TRUE, 0); | |
3792 | |
3793 g_signal_connect(G_OBJECT(entry), "activate", | |
3794 G_CALLBACK(add_chat_cb), data); | |
7891 | 3795 gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); |
8137 | 3796 gaim_set_accessible_label (entry, label); |
7620 | 3797 } |
3798 | |
3799 g_free(pce); | |
3800 } | |
3801 | |
3802 g_list_free(list); | |
3803 | |
3804 gtk_widget_show_all(data->entries_box); | |
3805 } | |
3806 | |
3807 static void | |
3808 add_chat_select_account_cb(GObject *w, GaimAccount *account, | |
3809 GaimGtkAddChatData *data) | |
3810 { | |
3811 if (gaim_account_get_protocol(data->account) == | |
3812 gaim_account_get_protocol(account)) | |
3813 { | |
3814 data->account = account; | |
3815 } | |
3816 else | |
3817 { | |
3818 data->account = account; | |
3819 rebuild_addchat_entries(data); | |
3820 } | |
3821 } | |
3822 | |
3823 static gboolean | |
3824 add_chat_check_account_func(GaimAccount *account) | |
3825 { | |
3826 GaimConnection *gc = gaim_account_get_connection(account); | |
3827 | |
3828 return (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL); | |
3829 } | |
3830 | |
3831 void | |
7859 | 3832 gaim_gtk_blist_request_add_chat(GaimAccount *account, GaimGroup *group, |
3833 const char *alias) | |
7620 | 3834 { |
3835 GaimGtkAddChatData *data; | |
3836 GaimGtkBuddyList *gtkblist; | |
3837 GList *l; | |
3838 GaimConnection *gc; | |
3839 GtkWidget *label; | |
3840 GtkWidget *rowbox; | |
3841 GtkWidget *hbox; | |
3842 GtkWidget *vbox; | |
3843 GtkWidget *img; | |
3844 | |
3845 data = g_new0(GaimGtkAddChatData, 1); | |
3846 | |
3847 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, | |
3848 GTK_ICON_SIZE_DIALOG); | |
3849 | |
3850 gtkblist = GAIM_GTK_BLIST(gaim_get_blist()); | |
3851 | |
3852 if (account != NULL) | |
3853 { | |
3854 data->account = account; | |
3855 } | |
3856 else | |
3857 { | |
3858 /* Select an account with chat capabilities */ | |
3859 for (l = gaim_connections_get_all(); l != NULL; l = l->next) | |
3860 { | |
3861 gc = (GaimConnection *)l->data; | |
3862 | |
3863 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->join_chat != NULL) | |
3864 { | |
3865 data->account = gaim_connection_get_account(gc); | |
3866 break; | |
3867 } | |
3868 } | |
3869 } | |
3870 | |
3871 if (data->account == NULL) | |
3872 { | |
3873 gaim_notify_error(NULL, NULL, | |
3874 _("You are not currently signed on with any " | |
3875 "protocols that have the ability to chat."), NULL); | |
3876 return; | |
3877 } | |
3878 | |
3879 data->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); | |
3880 | |
3881 data->window = gtk_dialog_new_with_buttons(_("Add Chat"), | |
8222 | 3882 NULL, 0, |
7620 | 3883 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
3884 GTK_STOCK_ADD, GTK_RESPONSE_OK, | |
3885 NULL); | |
3886 | |
3887 gtk_dialog_set_default_response(GTK_DIALOG(data->window), GTK_RESPONSE_OK); | |
3888 gtk_container_set_border_width(GTK_CONTAINER(data->window), 6); | |
3889 gtk_window_set_resizable(GTK_WINDOW(data->window), FALSE); | |
3890 gtk_dialog_set_has_separator(GTK_DIALOG(data->window), FALSE); | |
3891 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(data->window)->vbox), 12); | |
3892 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), 6); | |
3893 gtk_window_set_role(GTK_WINDOW(data->window), "add_chat"); | |
3894 | |
3895 hbox = gtk_hbox_new(FALSE, 12); | |
3896 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), hbox); | |
3897 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); | |
3898 gtk_misc_set_alignment(GTK_MISC(img), 0, 0); | |
3899 | |
3900 vbox = gtk_vbox_new(FALSE, 5); | |
3901 gtk_container_add(GTK_CONTAINER(hbox), vbox); | |
3902 | |
3903 label = gtk_label_new( | |
3904 _("Please enter an alias, and the appropriate information " | |
3905 "about the chat you would like to add to your buddy list.\n")); | |
3906 gtk_widget_set_size_request(label, 400, -1); | |
3907 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); | |
3908 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); | |
3909 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); | |
3910 | |
3911 rowbox = gtk_hbox_new(FALSE, 5); | |
3912 gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); | |
3913 | |
3914 label = gtk_label_new(_("Account:")); | |
3915 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
3916 gtk_size_group_add_widget(data->sg, label); | |
3917 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); | |
3918 | |
3919 data->account_menu = gaim_gtk_account_option_menu_new(account, FALSE, | |
3920 G_CALLBACK(add_chat_select_account_cb), | |
3921 add_chat_check_account_func, data); | |
3922 gtk_box_pack_start(GTK_BOX(rowbox), data->account_menu, TRUE, TRUE, 0); | |
8137 | 3923 gaim_set_accessible_label (data->account_menu, label); |
7620 | 3924 |
3925 data->entries_box = gtk_vbox_new(FALSE, 5); | |
3926 gtk_container_set_border_width(GTK_CONTAINER(data->entries_box), 0); | |
3927 gtk_box_pack_start(GTK_BOX(vbox), data->entries_box, TRUE, TRUE, 0); | |
3928 | |
3929 rebuild_addchat_entries(data); | |
3930 | |
3931 rowbox = gtk_hbox_new(FALSE, 5); | |
3932 gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); | |
3933 | |
3934 label = gtk_label_new(_("Alias:")); | |
3935 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
3936 gtk_size_group_add_widget(data->sg, label); | |
3937 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); | |
3938 | |
3939 data->alias_entry = gtk_entry_new(); | |
7859 | 3940 if (alias != NULL) |
3941 gtk_entry_set_text(GTK_ENTRY(data->alias_entry), alias); | |
7620 | 3942 gtk_box_pack_end(GTK_BOX(rowbox), data->alias_entry, TRUE, TRUE, 0); |
8137 | 3943 gaim_set_accessible_label (data->alias_entry, label); |
7620 | 3944 |
3945 rowbox = gtk_hbox_new(FALSE, 5); | |
3946 gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); | |
3947 | |
3948 label = gtk_label_new(_("Group:")); | |
3949 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
3950 gtk_size_group_add_widget(data->sg, label); | |
3951 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); | |
3952 | |
3953 data->group_combo = gtk_combo_new(); | |
3954 gtk_combo_set_popdown_strings(GTK_COMBO(data->group_combo), groups_tree()); | |
3955 gtk_box_pack_end(GTK_BOX(rowbox), data->group_combo, TRUE, TRUE, 0); | |
3956 | |
3957 if (group) | |
3958 { | |
3959 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(data->group_combo)->entry), | |
3960 group->name); | |
3961 } | |
8137 | 3962 gaim_set_accessible_label (data->group_combo, label); |
7620 | 3963 |
3964 g_signal_connect(G_OBJECT(data->window), "response", | |
3965 G_CALLBACK(add_chat_resp_cb), data); | |
3966 | |
3967 gtk_widget_show_all(data->window); | |
3968 } | |
3969 | |
3970 static void | |
3971 add_group_cb(GaimConnection *gc, const char *group_name) | |
3972 { | |
3973 GaimGroup *g; | |
3974 | |
3975 g = gaim_group_new(group_name); | |
3976 gaim_blist_add_group(g, NULL); | |
3977 gaim_blist_save(); | |
3978 } | |
3979 | |
3980 void | |
3981 gaim_gtk_blist_request_add_group(void) | |
3982 { | |
7853 | 3983 gaim_request_input(NULL, _("Add Group"), NULL, |
7620 | 3984 _("Please enter the name of the group to be added."), |
3985 NULL, FALSE, FALSE, | |
3986 _("Add"), G_CALLBACK(add_group_cb), | |
3987 _("Cancel"), NULL, NULL); | |
3988 } | |
3989 | |
5228 | 3990 void gaim_gtk_blist_docklet_toggle() { |
3991 /* Useful for the docklet plugin and also for the win32 tray icon*/ | |
3992 /* This is called when one of those is clicked--it will show/hide the | |
3993 buddy list/login window--depending on which is active */ | |
7620 | 3994 if (gaim_connections_get_all()) { |
5228 | 3995 if (gtkblist && gtkblist->window) { |
3996 if (GTK_WIDGET_VISIBLE(gtkblist->window)) { | |
3997 gaim_blist_set_visible(GAIM_WINDOW_ICONIFIED(gtkblist->window) || gaim_gtk_blist_obscured); | |
3998 } else { | |
3999 #if _WIN32 | |
4000 wgaim_systray_maximize(gtkblist->window); | |
4001 #endif | |
4002 gaim_blist_set_visible(TRUE); | |
4003 } | |
4004 } else { | |
4005 /* we're logging in or something... do nothing */ | |
4006 /* or should I make the blist? */ | |
4007 gaim_debug(GAIM_DEBUG_WARNING, "blist", | |
7620 | 4008 "docklet_toggle called with gaim_connections_get_all() " |
5228 | 4009 "but no blist!\n"); |
4010 } | |
4011 } else if (mainwindow) { | |
4012 if (GTK_WIDGET_VISIBLE(mainwindow)) { | |
4013 if (GAIM_WINDOW_ICONIFIED(mainwindow)) { | |
4014 gtk_window_present(GTK_WINDOW(mainwindow)); | |
4015 } else { | |
4016 #if _WIN32 | |
4017 wgaim_systray_minimize(mainwindow); | |
4018 #endif | |
4019 gtk_widget_hide(mainwindow); | |
4020 } | |
4021 } else { | |
4022 #if _WIN32 | |
4023 wgaim_systray_maximize(mainwindow); | |
4024 #endif | |
4025 show_login(); | |
4026 } | |
4027 } else { | |
4028 show_login(); | |
4029 } | |
4030 } | |
4031 | |
4032 void gaim_gtk_blist_docklet_add() | |
4033 { | |
4034 docklet_count++; | |
4035 } | |
4036 | |
4037 void gaim_gtk_blist_docklet_remove() | |
4038 { | |
4039 docklet_count--; | |
4040 if (!docklet_count) { | |
7620 | 4041 if (gaim_connections_get_all()) |
5228 | 4042 gaim_blist_set_visible(TRUE); |
4043 else if (mainwindow) | |
4044 gtk_window_present(GTK_WINDOW(mainwindow)); | |
4045 else | |
4046 show_login(); | |
4047 } | |
4048 } | |
4049 | |
7620 | 4050 static GaimBlistUiOps blist_ui_ops = |
5228 | 4051 { |
4052 gaim_gtk_blist_new_list, | |
5256 | 4053 gaim_gtk_blist_new_node, |
5228 | 4054 gaim_gtk_blist_show, |
4055 gaim_gtk_blist_update, | |
4056 gaim_gtk_blist_remove, | |
4057 gaim_gtk_blist_destroy, | |
7620 | 4058 gaim_gtk_blist_set_visible, |
4059 gaim_gtk_blist_request_add_buddy, | |
4060 gaim_gtk_blist_request_add_chat, | |
4061 gaim_gtk_blist_request_add_group | |
5228 | 4062 }; |
4063 | |
4064 | |
7620 | 4065 GaimBlistUiOps * |
4066 gaim_gtk_blist_get_ui_ops(void) | |
5228 | 4067 { |
4068 return &blist_ui_ops; | |
4069 } | |
4070 | |
7620 | 4071 static void account_signon_cb(GaimConnection *gc, gpointer z) |
4072 { | |
4073 GaimAccount *account = gaim_connection_get_account(gc); | |
4074 GaimBlistNode *gnode, *cnode; | |
4075 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) | |
4076 { | |
4077 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
4078 continue; | |
4079 for(cnode = gnode->child; cnode; cnode = cnode->next) | |
4080 { | |
4081 GaimChat *chat; | |
4082 | |
4083 if(!GAIM_BLIST_NODE_IS_CHAT(cnode)) | |
4084 continue; | |
4085 | |
4086 chat = (GaimChat *)cnode; | |
4087 | |
4088 if(chat->account != account) | |
4089 continue; | |
4090 | |
8197 | 4091 if(gaim_blist_node_get_bool((GaimBlistNode*)chat, "gtk-autojoin") || |
8198 | 4092 (gaim_blist_node_get_string((GaimBlistNode*)chat, |
4093 "gtk-autojoin") != NULL)) | |
7620 | 4094 serv_join_chat(gc, chat->components); |
4095 } | |
4096 } | |
4097 } | |
4098 | |
4099 void gaim_gtk_blist_init(void) | |
4100 { | |
4101 /* XXX */ | |
4102 static int gtk_blist_handle; | |
4103 | |
4104 gaim_signal_connect(gaim_connections_get_handle(), "signed-on", | |
4105 >k_blist_handle, GAIM_CALLBACK(account_signon_cb), | |
4106 NULL); | |
7731 | 4107 |
4108 /* Initialize prefs */ | |
4109 gaim_prefs_add_none("/gaim/gtk/blist"); | |
4110 gaim_prefs_add_bool("/gaim/gtk/blist/auto_expand_contacts", TRUE); | |
4111 gaim_prefs_add_int("/gaim/gtk/blist/button_style", GAIM_BUTTON_TEXT_IMAGE); | |
4112 gaim_prefs_add_bool("/gaim/gtk/blist/grey_idle_buddies", TRUE); | |
4113 gaim_prefs_add_bool("/gaim/gtk/blist/raise_on_events", FALSE); | |
4114 gaim_prefs_add_bool("/gaim/gtk/blist/show_buddy_icons", TRUE); | |
4115 gaim_prefs_add_bool("/gaim/gtk/blist/show_empty_groups", FALSE); | |
4116 gaim_prefs_add_bool("/gaim/gtk/blist/show_group_count", TRUE); | |
4117 gaim_prefs_add_bool("/gaim/gtk/blist/show_idle_time", TRUE); | |
4118 gaim_prefs_add_bool("/gaim/gtk/blist/show_offline_buddies", FALSE); | |
4119 gaim_prefs_add_bool("/gaim/gtk/blist/show_warning_level", TRUE); | |
4120 gaim_prefs_add_string("/gaim/gtk/blist/sort_type", ""); | |
4121 gaim_prefs_add_int("/gaim/gtk/blist/x", 0); | |
4122 gaim_prefs_add_int("/gaim/gtk/blist/y", 0); | |
4123 gaim_prefs_add_int("/gaim/gtk/blist/width", 0); | |
4124 gaim_prefs_add_int("/gaim/gtk/blist/height", 0); | |
4125 | |
7620 | 4126 } |
4127 | |
5228 | 4128 |
4129 | |
4130 /********************************************************************* | |
4131 * Public utility functions * | |
4132 *********************************************************************/ | |
4133 | |
4134 GdkPixbuf * | |
7620 | 4135 create_prpl_icon(GaimAccount *account) |
5228 | 4136 { |
4137 GaimPlugin *prpl; | |
4138 GaimPluginProtocolInfo *prpl_info = NULL; | |
4139 GdkPixbuf *status = NULL; | |
4140 char *filename = NULL; | |
4141 const char *protoname = NULL; | |
4142 char buf[256]; | |
4143 | |
7956 | 4144 prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); |
5228 | 4145 |
4146 if (prpl != NULL) { | |
4147 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); | |
4148 | |
4149 if (prpl_info->list_icon != NULL) | |
4150 protoname = prpl_info->list_icon(account, NULL); | |
4151 } | |
4152 | |
4153 if (protoname == NULL) | |
4154 return NULL; | |
4155 | |
4156 /* | |
4157 * Status icons will be themeable too, and then it will look up | |
4158 * protoname from the theme | |
4159 */ | |
4160 g_snprintf(buf, sizeof(buf), "%s.png", protoname); | |
4161 | |
4162 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", | |
4163 "default", buf, NULL); | |
4164 status = gdk_pixbuf_new_from_file(filename, NULL); | |
4165 g_free(filename); | |
4166 | |
4167 return status; | |
4168 } | |
4169 | |
5422 | 4170 |
4171 /********************************************************************* | |
4172 * Buddy List sorting functions * | |
4173 *********************************************************************/ | |
4174 | |
7620 | 4175 void gaim_gtk_blist_sort_method_reg(const char *id, const char *name, gaim_gtk_blist_sort_function func) |
5422 | 4176 { |
4177 struct gaim_gtk_blist_sort_method *method = g_new0(struct gaim_gtk_blist_sort_method, 1); | |
7620 | 4178 method->id = g_strdup(id); |
5422 | 4179 method->name = g_strdup(name); |
7620 | 4180 method->func = func;; |
5422 | 4181 gaim_gtk_blist_sort_methods = g_slist_append(gaim_gtk_blist_sort_methods, method); |
4182 } | |
4183 | |
7620 | 4184 void gaim_gtk_blist_sort_method_unreg(const char *id){ |
4185 GSList *l = gaim_gtk_blist_sort_methods; | |
4186 | |
4187 while(l) { | |
4188 struct gaim_gtk_blist_sort_method *method = l->data; | |
4189 if(!strcmp(method->id, id)) { | |
4190 gaim_gtk_blist_sort_methods = g_slist_remove(gaim_gtk_blist_sort_methods, method); | |
4191 g_free(method->id); | |
4192 g_free(method->name); | |
4193 g_free(method); | |
4194 break; | |
4195 } | |
4196 } | |
5422 | 4197 } |
4198 | |
7620 | 4199 void gaim_gtk_blist_sort_method_set(const char *id){ |
5422 | 4200 GSList *l = gaim_gtk_blist_sort_methods; |
7620 | 4201 |
4202 if(!id) | |
4203 id = "none"; | |
4204 | |
4205 while (l && strcmp(((struct gaim_gtk_blist_sort_method*)l->data)->id, id)) | |
5422 | 4206 l = l->next; |
7620 | 4207 |
5422 | 4208 if (l) { |
4209 current_sort_method = l->data; | |
4210 } else if (!current_sort_method) { | |
7620 | 4211 gaim_gtk_blist_sort_method_set("none"); |
5422 | 4212 return; |
4213 } | |
4214 redo_buddy_list(gaim_get_blist(), TRUE); | |
4215 | |
4216 } | |
4217 | |
4218 /****************************************** | |
4219 ** Sort Methods | |
4220 ******************************************/ | |
4221 | |
7620 | 4222 static GtkTreeIter sort_method_none(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter parent_iter, GtkTreeIter *cur) |
5422 | 4223 { |
7620 | 4224 GtkTreeIter iter; |
4225 GaimBlistNode *sibling = node->prev; | |
4226 GtkTreeIter sibling_iter; | |
4227 | |
4228 if(cur) | |
5422 | 4229 return *cur; |
7620 | 4230 |
4231 while (sibling && !get_iter_from_node(sibling, &sibling_iter)) { | |
4232 sibling = sibling->prev; | |
5422 | 4233 } |
7620 | 4234 |
4235 gtk_tree_store_insert_after(gtkblist->treemodel, &iter, | |
4236 node->parent ? &parent_iter : NULL, | |
4237 sibling ? &sibling_iter : NULL); | |
4238 | |
5422 | 4239 return iter; |
4240 } | |
4241 | |
7620 | 4242 #if GTK_CHECK_VERSION(2,2,1) |
4243 | |
4244 static GtkTreeIter sort_method_alphabetical(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur) | |
5422 | 4245 { |
4246 GtkTreeIter more_z, iter; | |
4247 GaimBlistNode *n; | |
4248 GValue val = {0,}; | |
7620 | 4249 |
4250 const char *my_name; | |
4251 | |
4252 if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
4253 my_name = gaim_contact_get_alias((GaimContact*)node); | |
4254 } else if(GAIM_BLIST_NODE_IS_CHAT(node)) { | |
4255 my_name = gaim_chat_get_name((GaimChat*)node); | |
4256 } else { | |
4257 return sort_method_none(node, blist, groupiter, cur); | |
4258 } | |
4259 | |
5422 | 4260 |
4261 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) { | |
4262 gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0); | |
7620 | 4263 return iter; |
4264 } | |
4265 | |
4266 do { | |
4267 const char *this_name; | |
4268 int cmp; | |
4269 | |
4270 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val); | |
4271 n = g_value_get_pointer(&val); | |
4272 | |
4273 if(GAIM_BLIST_NODE_IS_CONTACT(n)) { | |
4274 this_name = gaim_contact_get_alias((GaimContact*)n); | |
4275 } else if(GAIM_BLIST_NODE_IS_CHAT(n)) { | |
4276 this_name = gaim_chat_get_name((GaimChat*)n); | |
4277 } else { | |
4278 this_name = NULL; | |
4279 } | |
4280 | |
4281 cmp = gaim_utf8_strcasecmp(my_name, this_name); | |
4282 | |
4283 if(this_name && (cmp < 0 || (cmp == 0 && node < n))) { | |
4284 if(cur) { | |
4285 gtk_tree_store_move_before(gtkblist->treemodel, cur, &more_z); | |
4286 return *cur; | |
4287 } else { | |
4288 gtk_tree_store_insert_before(gtkblist->treemodel, &iter, | |
4289 &groupiter, &more_z); | |
4290 return iter; | |
4291 } | |
4292 } | |
4293 g_value_unset(&val); | |
4294 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z)); | |
4295 | |
4296 if(cur) { | |
4297 gtk_tree_store_move_before(gtkblist->treemodel, cur, NULL); | |
4298 return *cur; | |
4299 } else { | |
4300 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter); | |
4301 return iter; | |
4302 } | |
4303 } | |
4304 | |
4305 static GtkTreeIter sort_method_status(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur) | |
4306 { | |
4307 GtkTreeIter more_z, iter; | |
4308 GaimBlistNode *n; | |
4309 GValue val = {0,}; | |
4310 | |
4311 GaimBuddy *my_buddy, *this_buddy; | |
4312 | |
4313 if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
4314 my_buddy = gaim_contact_get_priority_buddy((GaimContact*)node); | |
4315 } else if(GAIM_BLIST_NODE_IS_CHAT(node)) { | |
4316 if(cur) | |
4317 return *cur; | |
4318 | |
4319 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter); | |
4320 return iter; | |
4321 } else { | |
4322 return sort_method_none(node, blist, groupiter, cur); | |
4323 } | |
4324 | |
4325 | |
4326 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) { | |
4327 gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0); | |
5422 | 4328 return iter; |
4329 } | |
4330 | |
4331 do { | |
7620 | 4332 int cmp; |
4333 | |
5422 | 4334 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val); |
4335 n = g_value_get_pointer(&val); | |
7620 | 4336 |
4337 if(GAIM_BLIST_NODE_IS_CONTACT(n)) { | |
4338 this_buddy = gaim_contact_get_priority_buddy((GaimContact*)n); | |
4339 } else { | |
4340 this_buddy = NULL; | |
4341 } | |
4342 | |
4343 cmp = gaim_utf8_strcasecmp(my_buddy ? | |
4344 gaim_contact_get_alias(gaim_buddy_get_contact(my_buddy)) | |
4345 : NULL, this_buddy ? | |
4346 gaim_contact_get_alias(gaim_buddy_get_contact(this_buddy)) | |
4347 : NULL); | |
4348 | |
4349 /* Hideous */ | |
4350 if(!this_buddy || | |
4351 ((my_buddy->present > this_buddy->present) || | |
4352 (my_buddy->present == this_buddy->present && | |
4353 (((my_buddy->uc & UC_UNAVAILABLE) < (this_buddy->uc & UC_UNAVAILABLE)) || | |
4354 (((my_buddy->uc & UC_UNAVAILABLE) == (this_buddy->uc & UC_UNAVAILABLE)) && | |
4355 (((my_buddy->idle == 0) && (this_buddy->idle != 0)) || | |
4356 (this_buddy->idle && (my_buddy->idle > this_buddy->idle)) || | |
4357 ((my_buddy->idle == this_buddy->idle) && | |
4358 (cmp < 0 || (cmp == 0 && node < n))))))))) { | |
4359 if(cur) { | |
4360 gtk_tree_store_move_before(gtkblist->treemodel, cur, &more_z); | |
4361 return *cur; | |
4362 } else { | |
4363 gtk_tree_store_insert_before(gtkblist->treemodel, &iter, | |
4364 &groupiter, &more_z); | |
4365 return iter; | |
4366 } | |
5422 | 4367 } |
4368 g_value_unset(&val); | |
4369 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z)); | |
7620 | 4370 |
4371 if(cur) { | |
4372 gtk_tree_store_move_before(gtkblist->treemodel, cur, NULL); | |
4373 return *cur; | |
4374 } else { | |
4375 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter); | |
4376 return iter; | |
4377 } | |
5422 | 4378 } |
4379 | |
7620 | 4380 static GtkTreeIter sort_method_log(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur) |
5422 | 4381 { |
4382 GtkTreeIter more_z, iter; | |
7620 | 4383 GaimBlistNode *n = NULL, *n2; |
5422 | 4384 GValue val = {0,}; |
7620 | 4385 |
4386 int log_size = 0, this_log_size = 0; | |
4387 const char *buddy_name, *this_buddy_name; | |
4388 | |
4389 if(cur && (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter) == 1)) | |
4390 return *cur; | |
4391 | |
4392 if(GAIM_BLIST_NODE_IS_CONTACT(node)) { | |
4393 for (n = node->child; n; n = n->next) | |
4394 log_size += gaim_log_get_total_size(((GaimBuddy*)(n))->name, ((GaimBuddy*)(n))->account); | |
4395 buddy_name = gaim_contact_get_alias((GaimContact*)node); | |
4396 } else if(GAIM_BLIST_NODE_IS_CHAT(node)) { | |
4397 /* we don't have a reliable way of getting the log filename | |
4398 * from the chat info in the blist, yet */ | |
4399 if(cur) | |
4400 return *cur; | |
4401 | |
4402 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter); | |
4403 return iter; | |
4404 } else { | |
4405 return sort_method_none(node, blist, groupiter, cur); | |
4406 } | |
4407 | |
4408 | |
5422 | 4409 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) { |
4410 gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0); | |
4411 return iter; | |
4412 } | |
4413 | |
4414 do { | |
7620 | 4415 int cmp; |
4416 | |
5422 | 4417 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val); |
4418 n = g_value_get_pointer(&val); | |
7620 | 4419 this_log_size = 0; |
4420 | |
4421 if(GAIM_BLIST_NODE_IS_CONTACT(n)) { | |
4422 for (n2 = n->child; n2; n2 = n2->next) | |
4423 this_log_size += gaim_log_get_total_size(((GaimBuddy*)(n2))->name, ((GaimBuddy*)(n2))->account); | |
4424 this_buddy_name = gaim_contact_get_alias((GaimContact*)n); | |
4425 } else { | |
4426 this_buddy_name = NULL; | |
5422 | 4427 } |
7620 | 4428 |
4429 cmp = gaim_utf8_strcasecmp(buddy_name, this_buddy_name); | |
4430 | |
4431 if (!GAIM_BLIST_NODE_IS_CONTACT(n) || log_size > this_log_size || | |
4432 ((log_size == this_log_size) && | |
4433 (cmp < 0 || (cmp == 0 && node < n)))) { | |
4434 if(cur) { | |
4435 gtk_tree_store_move_before(gtkblist->treemodel, cur, &more_z); | |
4436 return *cur; | |
4437 } else { | |
4438 gtk_tree_store_insert_before(gtkblist->treemodel, &iter, | |
4439 &groupiter, &more_z); | |
4440 return iter; | |
4441 } | |
5422 | 4442 } |
4443 g_value_unset(&val); | |
4444 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z)); | |
7620 | 4445 |
4446 if(cur) { | |
4447 gtk_tree_store_move_before(gtkblist->treemodel, cur, NULL); | |
4448 return *cur; | |
4449 } else { | |
4450 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter); | |
4451 return iter; | |
4452 } | |
4453 } | |
4454 | |
4455 #endif | |
4456 | |
4457 static void | |
4458 proto_act(GtkObject *obj, struct proto_actions_menu *pam) | |
4459 { | |
4460 if (pam->callback && pam->gc) | |
4461 pam->callback(pam->gc); | |
5422 | 4462 } |
7620 | 4463 |
4464 void | |
4465 gaim_gtk_blist_update_protocol_actions(void) | |
4466 { | |
4467 GtkWidget *menuitem; | |
4468 GtkWidget *submenu; | |
4469 GaimPluginProtocolInfo *prpl_info = NULL; | |
4470 GList *l; | |
4471 GList *c; | |
4472 struct proto_actions_menu *pam; | |
4473 GaimConnection *gc = NULL; | |
4474 int count = 0; | |
4475 char buf[256]; | |
4476 | |
4477 if (!protomenu) | |
4478 return; | |
4479 | |
4480 for (l = gtk_container_get_children(GTK_CONTAINER(protomenu)); | |
4481 l != NULL; | |
4482 l = l->next) { | |
4483 | |
4484 menuitem = l->data; | |
4485 pam = g_object_get_data(G_OBJECT(menuitem), "proto_actions_menu"); | |
4486 | |
4487 if (pam) | |
4488 g_free(pam); | |
4489 | |
4490 gtk_container_remove(GTK_CONTAINER(protomenu), GTK_WIDGET(menuitem)); | |
4491 } | |
4492 | |
4493 for (c = gaim_connections_get_all(); c != NULL; c = c->next) { | |
4494 gc = c->data; | |
4495 | |
4496 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
4497 | |
4498 if (prpl_info->actions && gc->login_time) | |
4499 count++; | |
4500 } | |
4501 | |
4502 if (!count) { | |
4503 g_snprintf(buf, sizeof(buf), _("No actions available")); | |
4504 menuitem = gtk_menu_item_new_with_label(buf); | |
4505 gtk_menu_shell_append(GTK_MENU_SHELL(protomenu), menuitem); | |
4506 gtk_widget_show(menuitem); | |
4507 return; | |
4508 } | |
4509 | |
4510 if (count == 1) { | |
4511 GList *act; | |
4512 | |
4513 for (c = gaim_connections_get_all(); c != NULL; c = c->next) { | |
4514 gc = c->data; | |
4515 | |
4516 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
4517 | |
4518 if (prpl_info->actions && gc->login_time) | |
4519 break; | |
4520 } | |
4521 | |
4522 for (act = prpl_info->actions(gc); act != NULL; act = act->next) { | |
4523 if (act->data) { | |
4524 struct proto_actions_menu *pam = act->data; | |
4525 menuitem = gtk_menu_item_new_with_label(pam->label); | |
4526 gtk_menu_shell_append(GTK_MENU_SHELL(protomenu), menuitem); | |
4527 g_signal_connect(G_OBJECT(menuitem), "activate", | |
4528 G_CALLBACK(proto_act), pam); | |
4529 g_object_set_data(G_OBJECT(menuitem), "proto_actions_menu", pam); | |
4530 gtk_widget_show(menuitem); | |
4531 } | |
4532 else | |
4533 gaim_separator(protomenu); | |
4534 } | |
4535 } | |
4536 else { | |
4537 for (c = gaim_connections_get_all(); c != NULL; c = c->next) { | |
4538 GaimAccount *account; | |
4539 GList *act; | |
4540 GdkPixbuf *pixbuf, *scale; | |
4541 GtkWidget *image; | |
4542 | |
4543 gc = c->data; | |
4544 | |
4545 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
4546 | |
4547 if (!prpl_info->actions || !gc->login_time) | |
4548 continue; | |
4549 | |
4550 account = gaim_connection_get_account(gc); | |
4551 | |
4552 g_snprintf(buf, sizeof(buf), "%s (%s)", | |
4553 gaim_account_get_username(account), | |
4554 gc->prpl->info->name); | |
4555 | |
4556 menuitem = gtk_image_menu_item_new_with_label(buf); | |
4557 | |
4558 pixbuf = create_prpl_icon(gc->account); | |
4559 if(pixbuf) { | |
4560 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, | |
4561 GDK_INTERP_BILINEAR); | |
4562 image = gtk_image_new_from_pixbuf(scale); | |
4563 g_object_unref(G_OBJECT(pixbuf)); | |
4564 g_object_unref(G_OBJECT(scale)); | |
4565 gtk_widget_show(image); | |
4566 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), | |
4567 image); | |
4568 } | |
4569 | |
4570 gtk_menu_shell_append(GTK_MENU_SHELL(protomenu), menuitem); | |
4571 gtk_widget_show(menuitem); | |
4572 | |
4573 submenu = gtk_menu_new(); | |
4574 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); | |
4575 gtk_widget_show(submenu); | |
4576 | |
4577 for (act = prpl_info->actions(gc); act != NULL; act = act->next) { | |
4578 if (act->data) { | |
4579 struct proto_actions_menu *pam = act->data; | |
4580 menuitem = gtk_menu_item_new_with_label(pam->label); | |
4581 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem); | |
4582 g_signal_connect(G_OBJECT(menuitem), "activate", | |
4583 G_CALLBACK(proto_act), pam); | |
4584 g_object_set_data(G_OBJECT(menuitem), "proto_actions_menu", | |
4585 pam); | |
4586 gtk_widget_show(menuitem); | |
4587 } | |
4588 else | |
4589 gaim_separator(submenu); | |
4590 } | |
4591 } | |
4592 } | |
4593 } |