comparison src/gtkblist.c @ 7620:4f41c4aa9913

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