Mercurial > pidgin
comparison src/buddy.c @ 4687:283fb289c510
[gaim-migrate @ 4998]
This is a new buddy list.
Lots of things about it just Don't Work. I probably already know about those
things, and you'd just be wasting my time in submitting a bug report about it.
I decided that instead of getting it to all work perfectly before committing,
that I'd get it in cvs, and slowly fix it with regular commits. That way, it's
easier to keep track of things, and other developers can help. Plus, I'm getting
pissed off at the buddy list and want it to die. It's kinda boring, and doing nothing
but the buddy list for such a long time has just gotten me very bitter.
After 0.60 is released later this week, Gaim will resume being fun. This week is
going to be very stressful, though, I'm sure.
Things you ought to know about this buddy list:
- It crashes
- It leaks
- There's no way to edit the buddy list, or access offline buddies
- Most of the menus and buttons and whatnot just plain ol' don't work.
- Status icons are only implemented for AIM.
That's mostly just because I'm lazy. As such, you may want to be wary of updating this.
If you do decide to update this, you may want to learn "cvs update -D yesterday" as well :)
All the art there is just placeholder art.
You probably won't really have as many problems as it sounds like you will from reading this.
This message is extra-negative to stress that I don't want to be bothered with complaints about
something not working about it :). I'll repeat: If something doesn't work, I probably already
know about it.
If you want to actually help with something, I'd be delighted to have it. IM me.
-s.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Mon, 10 Mar 2003 05:30:31 +0000 |
parents | 42d53c416bb9 |
children | e19f91053ad0 |
comparison
equal
deleted
inserted
replaced
4686:a1de8a9c99ba | 4687:283fb289c510 |
---|---|
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 |
22 #ifdef GTK_DISABLE_DEPRECATED | |
23 #undef GTK_DISABLE_DEPRECATED | |
24 #endif | |
25 | |
26 #define GTK_ENABLE_BROKEN | |
27 | |
28 #ifdef HAVE_CONFIG_H | 22 #ifdef HAVE_CONFIG_H |
29 #include <config.h> | 23 #include <config.h> |
30 #endif | 24 #endif |
31 #ifdef GAIM_PLUGINS | 25 #ifdef GAIM_PLUGINS |
32 #ifndef _WIN32 | 26 #ifndef _WIN32 |
39 #include <ctype.h> | 33 #include <ctype.h> |
40 #include <math.h> | 34 #include <math.h> |
41 #include <time.h> | 35 #include <time.h> |
42 #include <ctype.h> | 36 #include <ctype.h> |
43 | 37 |
38 #include "pixmaps/no_icon.xpm" | |
39 | |
44 #ifdef _WIN32 | 40 #ifdef _WIN32 |
45 #include <gdk/gdkwin32.h> | 41 #include <gdk/gdkwin32.h> |
46 #else | 42 #else |
47 #include <unistd.h> | 43 #include <unistd.h> |
48 #include <gdk/gdkx.h> | 44 #include <gdk/gdkx.h> |
51 #include <gdk/gdkkeysyms.h> | 47 #include <gdk/gdkkeysyms.h> |
52 #include <gtk/gtk.h> | 48 #include <gtk/gtk.h> |
53 #include "prpl.h" | 49 #include "prpl.h" |
54 #include "sound.h" | 50 #include "sound.h" |
55 #include "gaim.h" | 51 #include "gaim.h" |
52 #include "gtklist.h" | |
53 #include "gtkft.h" | |
56 | 54 |
57 #ifdef _WIN32 | 55 #ifdef _WIN32 |
58 #include "win32dep.h" | 56 #include "win32dep.h" |
59 #endif | 57 #endif |
60 | 58 |
61 #include "pixmaps/login_icon.xpm" | 59 static gboolean obscured = FALSE; |
62 #include "pixmaps/logout_icon.xpm" | 60 |
63 #include "pixmaps/no_icon.xpm" | 61 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node); |
64 | 62 |
65 #include "pixmaps/away_big.xpm" | 63 /*************************************************** |
66 | 64 * Callbacks * |
67 #include "pixmaps/group.xpm" | 65 ***************************************************/ |
68 | 66 |
69 #include "pixmaps/arrow_down.xpm" | 67 static void gtk_blist_row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { |
70 #include "pixmaps/arrow_right.xpm" | 68 GaimBlistNode *node; |
71 | 69 GtkTreeIter iter; |
72 static GtkTooltips *tips; | 70 GValue val = { 0, }; |
73 static GtkAccelGroup *accel; | 71 |
74 static GtkWidget *editpane; | 72 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); |
75 static GtkWidget *buddypane; | 73 |
76 static GtkWidget *imchatbox; | 74 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); |
77 static GtkWidget *edittree; | 75 node = g_value_get_pointer(&val); |
78 static GtkWidget *imbutton, *infobutton, *chatbutton, *awaybutton; | 76 |
79 static GtkWidget *addbutton, *groupbutton, *rembutton; | 77 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { |
80 | 78 gaim_conversation_new(GAIM_CONV_IM, ((struct buddy*)node)->account, ((struct buddy*)node)->name); |
81 GtkWidget *blist = NULL; | 79 } |
82 GtkWidget *bpmenu; | 80 } |
83 GtkWidget *buddies; | 81 |
84 | 82 static void gaim_proto_menu_cb(GtkMenuItem *item, struct buddy *b) |
85 typedef struct _GtkTreePixmaps GtkTreePixmaps; | 83 { |
86 | 84 struct proto_buddy_menu *pbm = g_object_get_data(G_OBJECT(item), "gaimcallback"); |
87 struct buddy_show { | 85 if (pbm->callback) |
88 GtkWidget *item; | 86 pbm->callback(pbm->gc, b->name); |
89 GtkWidget *pix; | 87 } |
90 GtkWidget *label; | 88 |
91 GtkWidget *warn; | 89 static gboolean gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer null) |
92 GtkWidget *idle; | 90 { |
93 char *name; | 91 GtkTreePath *path; |
94 GSList *connlist; | 92 GaimBlistNode *node; |
95 guint log_timer; | 93 GValue val = { 0, }; |
96 gint sound; | 94 GtkTreeIter iter; |
95 GtkWidget *menu, *menuitem; | |
96 GtkWidget *image; | |
97 GList *list; | |
98 struct prpl *prpl; | |
99 | |
100 if (event->button != 3) | |
101 return FALSE; | |
102 | |
103 /* Here we figure out which node was clicked */ | |
104 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL)) | |
105 return FALSE; | |
106 gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); | |
107 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
108 node = g_value_get_pointer(&val); | |
109 | |
110 if (!GAIM_BLIST_NODE_IS_BUDDY(node)) | |
111 return FALSE; | |
112 | |
113 menu = gtk_menu_new(); | |
114 | |
115 /* Protocol specific options */ | |
116 prpl = find_prpl(((struct buddy*)node)->account->protocol); | |
117 if (prpl) { | |
118 list = prpl->buddy_menu(((struct buddy*)node)->account->gc, ((struct buddy*)node)->name); | |
119 while (list) { | |
120 struct proto_buddy_menu *pbm = list->data; | |
121 menuitem = gtk_menu_item_new_with_mnemonic(pbm->label); | |
122 g_object_set_data(G_OBJECT(menuitem), "gaimcallback", pbm); | |
123 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gaim_proto_menu_cb), node); | |
124 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
125 list = list->next; | |
126 } | |
127 } | |
128 | |
129 menuitem = gtk_image_menu_item_new_with_mnemonic("_IM"); | |
130 image = gtk_image_new_from_stock(GAIM_STOCK_IM, GTK_ICON_SIZE_MENU); | |
131 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); | |
132 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
133 | |
134 menuitem = gtk_image_menu_item_new_with_mnemonic("_Alias"); | |
135 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
136 | |
137 menuitem = gtk_image_menu_item_new_with_mnemonic("Add Buddy _Pounce"); | |
138 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
139 | |
140 menuitem = gtk_image_menu_item_new_with_mnemonic("View _Log"); | |
141 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
142 | |
143 gtk_widget_show_all(menu); | |
144 | |
145 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time); | |
146 | |
147 return FALSE; | |
148 } | |
149 | |
150 static void gaim_gtk_blist_reordered_cb(GtkTreeModel *model, | |
151 GtkTreePath *path, | |
152 GtkTreeIter *iter, | |
153 gint *neworder, | |
154 gpointer null) | |
155 { | |
156 debug_printf("This doesn't work because GTK is broken\n"); | |
157 | |
158 } | |
159 | |
160 /* This is called 10 seconds after the buddy logs in. It removes the "logged in" icon and replaces it with | |
161 * the normal status icon */ | |
162 | |
163 static gboolean gaim_reset_present_icon(GaimBlistNode *b) | |
164 { | |
165 ((struct buddy*)b)->present = 1; | |
166 gaim_gtk_blist_update(NULL, b); | |
167 return FALSE; | |
168 } | |
169 | |
170 static void gaim_gtk_blist_add_buddy_cb() | |
171 { | |
172 GtkTreeSelection *sel = gtk_tree_view_get_selection(gtkblist->treeview); | |
173 GtkTreeIter iter; | |
174 GaimBlistNode *node; | |
175 GValue val; | |
176 | |
177 gtk_tree_selection_get_selected(sel, NULL, &iter); | |
178 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val); | |
179 node = g_value_get_pointer(&val); | |
180 | |
181 if (GAIM_BLIST_NODE_IS_BUDDY(node)) | |
182 show_add_buddy(NULL, NULL, ((struct group*)node->parent)->name, NULL); | |
183 else if (GAIM_BLIST_NODE_IS_GROUP(node)) | |
184 show_add_buddy(NULL, NULL, ((struct group*)node)->name, NULL); | |
185 | |
186 } | |
187 | |
188 | |
189 /*************************************************** | |
190 * Crap * | |
191 ***************************************************/ | |
192 static GtkItemFactoryEntry blist_menu[] = | |
193 { | |
194 /* Buddies menu */ | |
195 { N_("/_Buddies"), NULL, NULL, 0, "<Branch>" }, | |
196 { N_("/Buddies/_Add A Buddy..."), "<CTL>B", gaim_gtk_blist_add_buddy_cb, 0, | |
197 "<StockItem>", GTK_STOCK_ADD }, | |
198 { N_("/Buddies/New _Instant Message..."), "<CTL>I", show_im_dialog, 0, | |
199 "<StockItem>", GAIM_STOCK_IM }, | |
200 { N_("/Buddies/Join a _Chat..."), "<CTL>C", join_chat, 0, | |
201 "<StockItem>", GAIM_STOCK_CHAT }, | |
202 { N_("/Buddies/sep1"), NULL, NULL, 0, "<Separator>" }, | |
203 { N_("/Buddies/Get _User Info..."), "<CTL>J", show_info_dialog, 0, | |
204 "<StockItem>", GAIM_STOCK_INFO }, | |
205 { N_("/Buddies/sep2"), NULL, NULL, 0, "<Separator>" }, | |
206 { N_("/Buddies/_Signoff"), "<CTL>D", signoff_all, 0, NULL }, | |
207 { N_("/Buddies/_Quit"), "<CTL>Q", do_quit, 0, | |
208 "<StockItem>", GTK_STOCK_QUIT }, | |
209 | |
210 /* Tools */ | |
211 { N_("/_Tools"), NULL, NULL, 0, "<Branch>" }, | |
212 { N_("/Tools/_Away"), NULL, NULL, 0, "<Branch>" }, | |
213 { N_("/Tools/Buddy _Pounce"), NULL, NULL, 0, "<Branch>" }, | |
214 { N_("/Tools/sep1"), NULL, NULL, 0, "<Separator>" }, | |
215 { N_("/Tools/A_ccounts"), "<CTL>A", account_editor, 0, NULL }, | |
216 { N_("/Tools/Preferences"), "<CTL>P", show_prefs, 0, | |
217 "<StockItem>", GTK_STOCK_PREFERENCES }, | |
218 { N_("/Tools/_File Transfers"), NULL, NULL, 0, | |
219 "<StockItem>", GTK_STOCK_REVERT_TO_SAVED }, | |
220 { N_("/Tools/sep2"), NULL, NULL, 0, "<Separator>" }, | |
221 { N_("/Tools/P_rotocol Actions"), NULL, NULL, 0, "<Branch>" }, | |
222 { N_("/Tools/Pr_ivacy"), NULL, show_privacy_options, 0, NULL }, | |
223 { N_("/Tools/View System _Log"), NULL, NULL, 0, NULL }, | |
224 | |
225 /* Help */ | |
226 { N_("/_Help"), NULL, NULL, 0, "<Branch>" }, | |
227 { N_("/Help/Online _Help"), "F1", NULL, 0, | |
228 "<StockItem>", GTK_STOCK_HELP }, | |
229 { N_("/Help/_Debug Window"), NULL, NULL, 0, NULL }, | |
230 { N_("/Help/_About"), NULL, show_about, 0, NULL }, | |
231 | |
97 }; | 232 }; |
98 | 233 |
99 /* stuff for actual display of buddy list */ | 234 /********************************************************* |
100 struct group_show { | 235 * Private Utility functions * |
101 GtkWidget *item; | 236 *********************************************************/ |
102 GtkWidget *label; | 237 |
103 GtkWidget *tree; | 238 static GdkPixbuf *gaim_gtk_blist_get_status_icon(struct buddy *b) |
104 GSList *members; | 239 { |
105 char *name; | 240 GdkPixbuf *status = NULL; |
106 }; | 241 GdkPixbuf *scale = NULL; |
107 static GSList *shows = NULL; | 242 GdkPixbuf *emblem = NULL; |
108 | 243 gchar *filename = NULL; |
109 int docklet_count = 0; | 244 const char *protoname = NULL; |
110 static gboolean obscured = FALSE; | 245 |
111 | 246 char *se,*sw,*nw,*ne; |
112 /* Predefine some functions */ | 247 |
113 static void new_bp_callback(GtkWidget *w, struct buddy *bs); | 248 int scalesize = 30; |
114 static struct group_show *find_group_show(char *group); | 249 |
115 static struct buddy_show *find_buddy_show(struct group_show *gs, char *name); | 250 struct prpl* prpl = find_prpl(b->account->protocol); |
116 static int group_number(char *group); | 251 if (prpl->list_icon) |
117 static int buddy_number(char *group, char *buddy); | 252 protoname = prpl->list_icon(b->account, b); |
118 static struct group_show *new_group_show(char *group); | 253 if (prpl->list_emblems) |
119 static struct buddy_show *new_buddy_show(struct group_show *gs, struct buddy *buddy, char **xpm); | 254 prpl->list_emblems(b, &se, &sw, &nw, &ne); |
120 static void remove_buddy_show(struct group_show *gs, struct buddy_show *bs); | 255 |
121 static struct group_show *find_gs_by_bs(struct buddy_show *b); | 256 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) { |
122 static void update_num_group(struct group_show *gs); | 257 scalesize = 15; |
123 static void update_idle_time(struct buddy_show *bs); | 258 sw = nw = ne = NULL; /* So that only the se icon will composite */ |
124 | 259 } |
125 void handle_group_rename(struct group *g, char *prevname) | 260 |
126 { | 261 |
127 struct group_show *gs, *new_gs; | 262 if (b->present == 2) { |
128 GtkCTreeNode *c; | 263 /* If b->present is 2, that means this buddy has just signed on. We use the "login" icon for the |
129 | 264 * status, and we set a timeout to change it to a normal icon after 10 seconds. */ |
130 c = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, g); | 265 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "login.png", NULL); |
131 gtk_ctree_node_set_text(GTK_CTREE(edittree), c, 0, g->name); | 266 status = gdk_pixbuf_new_from_file(filename,NULL); |
132 | 267 g_free(filename); |
133 gs = find_group_show(prevname); | 268 g_timeout_add(10000, (GSourceFunc)gaim_reset_present_icon, b); |
134 if (!gs) { | 269 |
135 return; | 270 /* "Hey, what's all this crap?" you ask. Status icons will be themeable too, and |
136 } | 271 then it will look up protoname from the theme */ |
137 new_gs = find_group_show(g->name); | |
138 if (new_gs) { | |
139 /* transfer everything that was in gs and is in the same gaim_conn as g | |
140 * over to new_gs. */ | |
141 while (gs->members) { | |
142 new_gs->members = g_slist_append(new_gs->members, gs->members->data); | |
143 gs->members = g_slist_remove(gs->members, gs->members->data); | |
144 | |
145 } | |
146 shows = g_slist_remove(shows, gs); | |
147 gtk_tree_remove_item(GTK_TREE(buddies), gs->item); | |
148 g_free(gs->name); | |
149 g_free(gs); | |
150 update_num_group(new_gs); | |
151 } else { | 272 } else { |
152 g_free(gs->name); | 273 char *image = g_strdup_printf("%s.png", protoname); |
153 gs->name = g_strdup(g->name); | 274 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); |
154 update_num_group(gs); | 275 status = gdk_pixbuf_new_from_file(filename,NULL); |
155 } | 276 g_free(image); |
156 } | 277 g_free(filename); |
157 | 278 |
158 void handle_buddy_rename(struct buddy *b, char *prevname) | 279 } |
159 { | 280 |
160 struct gaim_conversation *cnv; | 281 if (!status) |
161 struct buddy_show *bs; | 282 return NULL; |
162 struct group_show *gs; | 283 |
163 struct group *g; | 284 scale = gdk_pixbuf_scale_simple(status, scalesize, scalesize, GDK_INTERP_BILINEAR); |
164 GtkCTreeNode *c; | 285 |
165 char buf[256]; | 286 /* Emblems */ |
166 | 287 |
167 c = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, b); | 288 /* Each protocol can specify up to four "emblems" to composite over the base icon. "away", "busy", "mobile user" |
168 if (get_buddy_alias_only(b)) | 289 * are all examples of states represented by emblems. I'm not even really sure I like this yet. */ |
169 g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b)); | 290 |
170 else | 291 /* XXX Clean this crap up, yo. */ |
171 g_snprintf(buf, sizeof(buf), "%s", b->name); | 292 if (se) { |
172 gtk_ctree_node_set_text(GTK_CTREE(edittree), c, 0, buf); | 293 char *image = g_strdup_printf("%s.png", se); |
173 | 294 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); |
174 if ((cnv = gaim_find_conversation(b->name)) != NULL) | 295 g_free(image); |
175 gaim_conversation_autoset_title(cnv); | 296 emblem = gdk_pixbuf_new_from_file(filename,NULL); |
176 | 297 g_free(filename); |
177 g = find_group_by_buddy(b); | 298 if (emblem) { |
178 if (!g) { | 299 if (blist_options & OPT_BLIST_SHOW_ICONS) |
179 /* shouldn't happen */ | 300 gdk_pixbuf_composite (emblem, |
180 return; | 301 scale, 15, 15, |
181 } | 302 15, 15, |
182 gs = find_group_show(g->name); | 303 15, 15, |
183 if (!gs) { | 304 1, 1, |
184 return; | 305 GDK_INTERP_BILINEAR, |
185 } | 306 255); |
186 bs = find_buddy_show(gs, prevname); | |
187 if (!bs) { | |
188 /* buddy's offline */ | |
189 return; | |
190 } | |
191 | |
192 if (g_strcasecmp(b->name, prevname)) { | |
193 bs->connlist = g_slist_remove(bs->connlist, b->account->gc); | |
194 if (!bs->connlist) { | |
195 gs->members = g_slist_remove(gs->members, bs); | |
196 if (bs->log_timer > 0) | |
197 g_source_remove(bs->log_timer); | |
198 bs->log_timer = 0; | |
199 remove_buddy_show(gs, bs); | |
200 g_free(bs->name); | |
201 g_free(bs); | |
202 } | |
203 update_num_group(gs); | |
204 } else { | |
205 gtk_label_set_text(GTK_LABEL(bs->label), get_buddy_alias(b)); | |
206 update_idle_time(bs); | |
207 } | |
208 } | |
209 | |
210 void destroy_buddy() | |
211 { | |
212 GSList *s = shows; | |
213 struct group_show *g; | |
214 GSList *m; | |
215 struct buddy_show *b; | |
216 while (s) { | |
217 g = (struct group_show *)s->data; | |
218 debug_printf("group_show still exists: %s\n", g->name); | |
219 m = g->members; | |
220 while (m) { | |
221 b = (struct buddy_show *)m->data; | |
222 debug_printf("buddy_show still exists: %s\n", b->name); | |
223 m = g_slist_remove(m, b); | |
224 if (b->log_timer > 0) | |
225 g_source_remove(b->log_timer); | |
226 b->log_timer = 0; | |
227 gtk_tree_remove_item(GTK_TREE(g->tree), b->item); | |
228 g_free(b->name); | |
229 g_free(b); | |
230 } | |
231 gtk_tree_remove_item(GTK_TREE(buddies), g->item); | |
232 s = g_slist_remove(s, g); | |
233 g_free(g->name); | |
234 g_free(g); | |
235 } | |
236 shows = NULL; | |
237 | |
238 if (blist) | |
239 gtk_widget_destroy(blist); | |
240 blist = NULL; | |
241 imchatbox = NULL; | |
242 awaymenu = NULL; | |
243 protomenu = NULL; | |
244 } | |
245 | |
246 static void adjust_pic(GtkWidget *button, const char *c, gchar **xpm) | |
247 { | |
248 GdkPixmap *pm; | |
249 GdkBitmap *bm; | |
250 GtkWidget *pic; | |
251 GtkWidget *label; | |
252 | |
253 /*if the user had opted to put pictures on the buttons */ | |
254 if (blist_options & OPT_BLIST_SHOW_BUTTON_XPM && xpm) { | |
255 pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm); | |
256 pic = gtk_pixmap_new(pm, bm); | |
257 gtk_widget_show(pic); | |
258 gdk_pixmap_unref(pm); | |
259 gdk_bitmap_unref(bm); | |
260 label = GTK_BIN(button)->child; | |
261 gtk_container_remove(GTK_CONTAINER(button), label); | |
262 gtk_container_add(GTK_CONTAINER(button), pic); | |
263 } else { | |
264 label = gtk_label_new(c); | |
265 gtk_widget_show(label); | |
266 pic = GTK_BIN(button)->child; | |
267 gtk_container_remove(GTK_CONTAINER(button), pic); | |
268 gtk_container_add(GTK_CONTAINER(button), label); | |
269 } | |
270 | |
271 } | |
272 | |
273 /* This will remain here until we phase out the others */ | |
274 static void adjust_pic2(GtkWidget *button, const char *c, gchar *icon) | |
275 { | |
276 GtkWidget *pic; | |
277 GtkWidget *label; | |
278 | |
279 /*if the user had opted to put pictures on the buttons */ | |
280 if (blist_options & OPT_BLIST_SHOW_BUTTON_XPM && icon) { | |
281 label = GTK_BIN(button)->child; | |
282 gtk_container_remove(GTK_CONTAINER(button), label); | |
283 gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_stock(icon, GTK_ICON_SIZE_BUTTON)); | |
284 gtk_widget_show_all(button); | |
285 } else { | |
286 label = gtk_label_new(c); | |
287 gtk_widget_show(label); | |
288 pic = GTK_BIN(button)->child; | |
289 gtk_container_remove(GTK_CONTAINER(button), pic); | |
290 gtk_container_add(GTK_CONTAINER(button), label); | |
291 } | |
292 | |
293 } | |
294 | |
295 | |
296 void toggle_show_empty_groups() | |
297 { | |
298 if (blist_options & OPT_BLIST_NO_MT_GRP) { | |
299 /* remove any group_shows with empty members */ | |
300 GSList *s = shows; | |
301 struct group_show *g; | |
302 | |
303 while (s) { | |
304 g = (struct group_show *)s->data; | |
305 if (!g_slist_length(g->members)) { | |
306 shows = g_slist_remove(shows, g); | |
307 s = shows; | |
308 gtk_tree_remove_item(GTK_TREE(buddies), g->item); | |
309 g_free(g->name); | |
310 g_free(g); | |
311 } else | |
312 s = g_slist_next(s); | |
313 } | |
314 | |
315 } else { | |
316 /* put back all groups */ | |
317 GSList *m = groups; | |
318 | |
319 while (m) { | |
320 struct group *g = (struct group *)m->data; | |
321 if (!find_group_show(g->name) && gaim_group_on_account(g, NULL)) | |
322 new_group_show(g->name); | |
323 m = g_slist_next(m); | |
324 } | |
325 } | |
326 } | |
327 | |
328 void toggle_buddy_pixmaps() | |
329 { | |
330 GSList *s = shows; | |
331 struct group_show *g; | |
332 GSList *m; | |
333 struct buddy_show *b; | |
334 | |
335 while (s) { | |
336 g = s->data; | |
337 m = g->members; | |
338 while (m) { | |
339 b = m->data; | |
340 if (blist_options & OPT_BLIST_SHOW_PIXMAPS) | |
341 gtk_widget_show(b->pix); | |
342 else | 307 else |
343 gtk_widget_hide(b->pix); | 308 gdk_pixbuf_composite (emblem, |
344 m = m->next; | 309 scale, 0, 0, |
345 } | 310 15, 15, |
346 s = s->next; | 311 0, 0, |
347 } | 312 1, 1, |
348 } | 313 GDK_INTERP_BILINEAR, |
349 | 314 255); |
350 static void update_num_group(struct group_show *gs) | 315 } |
351 { | 316 } |
352 GSList *c = connections; | 317 if (sw) { |
353 struct group *g = find_group(gs->name); | 318 char *image = g_strdup_printf("%s.png", sw); |
354 struct buddy *b; | 319 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); |
355 int total = 0, on = 0; | 320 g_free(image); |
356 char buf[256]; | 321 emblem = gdk_pixbuf_new_from_file(filename,NULL); |
357 | 322 g_free(filename); |
358 if (!g_slist_find(shows, gs)) { | 323 if (emblem) { |
359 debug_printf("update_num_group called for unfound group_show %s\n", gs->name); | 324 gdk_pixbuf_composite (emblem, |
360 return; | 325 scale, 0, 15, |
361 } | 326 15, 15, |
362 if (g) { | 327 0, 15, |
363 for (c = g->members; c; c = c->next) { | 328 1, 1, |
364 b = c->data; | 329 GDK_INTERP_BILINEAR, |
365 if(b->account->gc) { | 330 255); |
366 if(b->present) | 331 } |
367 on++; | 332 } |
368 total++; | 333 if (nw) { |
369 } | 334 char *image = g_strdup_printf("%s.png", nw); |
370 } | 335 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); |
371 } | 336 g_free(image); |
372 | 337 emblem = gdk_pixbuf_new_from_file(filename,NULL); |
373 if (blist_options & OPT_BLIST_SHOW_GRPNUM) | 338 g_free(filename); |
374 g_snprintf(buf, sizeof buf, "%s (%d/%d)", gs->name, on, total); | 339 if (emblem) { |
375 else | 340 gdk_pixbuf_composite (emblem, |
376 g_snprintf(buf, sizeof buf, "%s", gs->name); | 341 scale, 0, 0, |
377 | 342 15, 15, |
378 gtk_label_set_text(GTK_LABEL(gs->label), buf); | 343 0, 0, |
379 } | 344 1, 1, |
380 | 345 GDK_INTERP_BILINEAR, |
381 void update_num_groups(void) | 346 255); |
382 { | 347 } |
383 GSList *s = shows; | 348 } |
384 struct group_show *g; | 349 if (ne) { |
385 | 350 char *image = g_strdup_printf("%s.png", ne); |
386 while (s) { | 351 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL); |
387 g = (struct group_show *)s->data; | 352 g_free(image); |
388 update_num_group(g); | 353 emblem = gdk_pixbuf_new_from_file(filename,NULL); |
389 s = g_slist_next(s); | 354 g_free(filename); |
390 } | 355 if (emblem) { |
391 } | 356 gdk_pixbuf_composite (emblem, |
392 | 357 scale, 15, 0, |
393 void update_button_pix() | 358 15, 15, |
394 { | 359 15, 0, |
395 | 360 1, 1, |
396 adjust_pic2(addbutton, _("Add"), GTK_STOCK_ADD); | 361 GDK_INTERP_BILINEAR, |
397 adjust_pic(groupbutton, _("Group"), (gchar **)group_xpm); | 362 255); |
398 adjust_pic2(rembutton, _("Remove"), GTK_STOCK_REMOVE); | 363 } |
399 | 364 } |
400 if (!(blist_options & OPT_BLIST_NO_BUTTONS)) { | 365 |
401 adjust_pic(awaybutton, _("Away"), (gchar **)away_big_xpm); | 366 |
402 adjust_pic2(chatbutton, _("Chat"), GTK_STOCK_JUMP_TO); | 367 /* Idle gray buddies affects the whole row. This converts the status icon to greyscale. */ |
403 adjust_pic2(imbutton, _("IM"), GTK_STOCK_CONVERT); | 368 if (b->idle) |
404 adjust_pic2(infobutton, _("Info"), GTK_STOCK_FIND); | 369 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0, FALSE); |
405 } | 370 return scale; |
406 gtk_widget_hide(addbutton->parent); | 371 } |
407 gtk_widget_show(addbutton->parent); | 372 |
408 if (!(blist_options & OPT_BLIST_NO_BUTTONS)) { | 373 static GdkPixbuf *gaim_gtk_blist_get_buddy_icon(struct buddy *b) |
409 gtk_widget_hide(chatbutton->parent); | 374 { |
410 gtk_widget_show(chatbutton->parent); | 375 /* This just opens a file from ~/.gaim/icons/screenname. This needs to change to be more gooder. */ |
411 } | 376 char *file = g_build_filename(gaim_user_dir(), "icons", normalize(b->name), NULL); |
412 } | 377 GdkPixbuf *buf = gdk_pixbuf_new_from_file(file, NULL); |
413 | 378 |
414 void set_blist_tab() | 379 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) |
415 { | 380 return NULL; |
416 GtkWidget *blist_notebook; | 381 |
417 if (!buddypane) | 382 if (buf) { |
418 return; | 383 if (b->idle) { |
419 | 384 gdk_pixbuf_saturate_and_pixelate(buf, buf, 0, FALSE); |
420 blist_notebook = buddypane->parent; /* The "Online" Page */ | 385 } |
421 | 386 return gdk_pixbuf_scale_simple(buf,30,30, GDK_INTERP_BILINEAR); |
422 debug_printf("blist_options = %d\n", blist_options); | 387 } |
423 if((blist_options & OPT_BLIST_BOTTOM_TAB)) | 388 return NULL; |
424 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(blist_notebook), GTK_POS_BOTTOM); | 389 } |
425 else | 390 |
426 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(blist_notebook), GTK_POS_TOP); | 391 static gchar *gaim_gtk_blist_get_name_markup(struct buddy *b) |
427 | 392 { |
428 } | 393 char *name = gaim_get_buddy_alias(b); |
429 | 394 char *esc = g_markup_escape_text(name, strlen(name)), *text = NULL; |
430 | 395 /* XXX Clean up this crap */ |
431 static int handle_click_group(GtkWidget *widget, GdkEventButton *event, struct group *g) | 396 |
432 { | 397 int ihrs, imin; |
433 if (event->type == GDK_2BUTTON_PRESS) { | 398 char *idletime = ""; |
434 if (GTK_TREE_ITEM(widget)->expanded) | 399 char *warning = idletime; |
435 gtk_tree_item_collapse(GTK_TREE_ITEM(widget)); | 400 time_t t; |
436 else | 401 |
437 gtk_tree_item_expand(GTK_TREE_ITEM(widget)); | 402 if (!(blist_options & OPT_BLIST_SHOW_ICONS)) { |
438 return TRUE; | 403 if (b->idle > 0) { |
439 } | 404 text = g_strdup_printf("<span color='gray'>%s</span>", |
440 | 405 esc); |
441 return FALSE; | 406 g_free(esc); |
442 } | 407 return text; |
443 | |
444 void pressed_im_bud(GtkWidget *widget, struct buddy *b) | |
445 { | |
446 struct gaim_conversation *c; | |
447 | |
448 c = gaim_find_conversation(b->name); | |
449 | |
450 if (c != NULL) | |
451 gaim_window_show(gaim_conversation_get_window(c)); | |
452 else | |
453 c = gaim_conversation_new(GAIM_CONV_IM, b->account, b->name); | |
454 } | |
455 | |
456 void pressed_im(GtkWidget *widget, struct buddy_show *b) | |
457 { | |
458 struct gaim_conversation *c; | |
459 | |
460 c = gaim_find_conversation(b->name); | |
461 | |
462 if (c != NULL) { | |
463 gaim_window_show(gaim_conversation_get_window(c)); | |
464 } else { | |
465 struct gaim_account *account; | |
466 | |
467 account = ((struct gaim_connection *)b->connlist->data)->account; | |
468 c = gaim_conversation_new(GAIM_CONV_IM, account, b->name); | |
469 } | |
470 } | |
471 | |
472 void pressed_log(GtkWidget *widget, char *name) | |
473 { | |
474 show_log(name); | |
475 } | |
476 | |
477 void show_syslog() | |
478 { | |
479 show_log(NULL); | |
480 } | |
481 | |
482 void pressed_alias_bs(GtkWidget *widget, struct buddy_show *bs) | |
483 { | |
484 struct gaim_connection *gc = bs->connlist->data; | |
485 alias_dialog_bud(find_buddy(gc->account, bs->name)); | |
486 } | |
487 | |
488 void pressed_alias_bud(GtkWidget *widget, struct buddy *b) | |
489 { | |
490 alias_dialog_bud(b); | |
491 } | |
492 | |
493 static void menu_click(GtkObject *obj, char *who) | |
494 { | |
495 GList *list = gtk_object_get_user_data(obj); | |
496 struct proto_buddy_menu *pbm = list->data; | |
497 if (pbm->callback) | |
498 pbm->callback(pbm->gc, who); | |
499 } | |
500 | |
501 static int handle_click_buddy(GtkWidget *widget, GdkEventButton *event, struct buddy_show *b) | |
502 { | |
503 if (!b->connlist) | |
504 return FALSE; | |
505 | |
506 if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { | |
507 struct gaim_conversation *c; | |
508 struct gaim_account *account; | |
509 | |
510 account = ((struct gaim_connection *)b->connlist->data)->account; | |
511 | |
512 c = gaim_find_conversation(b->name); | |
513 | |
514 if (c != NULL) { | |
515 struct gaim_window *win = gaim_conversation_get_window(c); | |
516 size_t index = gaim_conversation_get_index(c); | |
517 | |
518 gaim_window_switch_conversation(win, index); | |
519 gaim_window_show(win); | |
520 | |
521 gaim_conversation_set_account(c, account); | |
522 } | |
523 else | |
524 c = gaim_conversation_new(GAIM_CONV_IM, account, b->name); | |
525 | |
526 gaim_window_switch_conversation(gaim_conversation_get_window(c), | |
527 gaim_conversation_get_index(c)); | |
528 | |
529 gaim_window_raise(gaim_conversation_get_window(c)); | |
530 | |
531 /* XXX-GTK gtk_widget_grab_focus(c->entry); */ | |
532 } else if (event->type == GDK_BUTTON_PRESS && event->button == 3) { | |
533 static GtkWidget *menu = NULL; | |
534 static GList *mo_top = NULL; | |
535 GtkWidget *button; | |
536 GtkWidget *menuitem; | |
537 GtkWidget *conmenu; | |
538 GSList *cn = b->connlist; | |
539 struct gaim_connection *g; | |
540 /* We're gonna make us a menu right here */ | |
541 | |
542 /* | |
543 * If a menu already exists, destroy it before creating a new one, | |
544 * thus freeing-up the memory it occupied. Same for its associated | |
545 * (prpl menu items) GList. | |
546 */ | |
547 if(menu) { | |
548 gtk_widget_destroy(menu); | |
549 if(mo_top) { | |
550 g_list_foreach(mo_top, (GFunc)g_free, NULL); | |
551 g_list_free(mo_top); | |
552 mo_top = NULL; | |
553 } | |
554 } | |
555 | |
556 menu = gtk_menu_new(); | |
557 | |
558 button = gtk_menu_item_new_with_label(_("IM")); | |
559 g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(pressed_im), b); | |
560 gtk_menu_append(GTK_MENU(menu), button); | |
561 gtk_widget_show(button); | |
562 | |
563 button = gtk_menu_item_new_with_label(_("Alias")); | |
564 g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(pressed_alias_bs), b); | |
565 gtk_menu_append(GTK_MENU(menu), button); | |
566 gtk_widget_show(button); | |
567 | |
568 button = gtk_menu_item_new_with_label(_("Add Buddy Pounce")); | |
569 g_signal_connect(GTK_OBJECT(button), "activate", | |
570 G_CALLBACK(new_bp_callback), | |
571 cn ? find_buddy(((struct gaim_connection *)cn->data)->account, b->name) : NULL); | |
572 gtk_menu_append(GTK_MENU(menu), button); | |
573 gtk_widget_show(button); | |
574 | |
575 button = gtk_menu_item_new_with_label(_("View Log")); | |
576 g_signal_connect(GTK_OBJECT(button), "activate", | |
577 G_CALLBACK(pressed_log), b->name); | |
578 gtk_menu_append(GTK_MENU(menu), button); | |
579 gtk_widget_show(button); | |
580 | |
581 if (g_slist_length(cn) > 1) { | |
582 while (cn) { | |
583 g = (struct gaim_connection *)cn->data; | |
584 if (g->prpl->buddy_menu) { | |
585 GList *mo = mo_top = g->prpl->buddy_menu(g, b->name); | |
586 | |
587 menuitem = gtk_menu_item_new_with_label(g->username); | |
588 gtk_menu_append(GTK_MENU(menu), menuitem); | |
589 gtk_widget_show(menuitem); | |
590 | |
591 conmenu = gtk_menu_new(); | |
592 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), conmenu); | |
593 gtk_widget_show(conmenu); | |
594 | |
595 while (mo) { | |
596 struct proto_buddy_menu *pbm = mo->data; | |
597 GtkWidget *button; | |
598 | |
599 button = gtk_menu_item_new_with_label(pbm->label); | |
600 g_signal_connect(GTK_OBJECT(button), "activate", | |
601 G_CALLBACK(menu_click), b->name); | |
602 gtk_object_set_user_data(GTK_OBJECT(button), mo); | |
603 gtk_menu_append(GTK_MENU(conmenu), button); | |
604 gtk_widget_show(button); | |
605 | |
606 mo = mo->next; | |
607 } | |
608 } | |
609 cn = g_slist_next(cn); | |
610 } | |
611 } else { | 408 } else { |
612 g = (struct gaim_connection *)cn->data; | 409 return esc; |
613 if (g->prpl->buddy_menu) { | 410 } |
614 GList *mo = mo_top = g->prpl->buddy_menu(g, b->name); | 411 } |
615 | |
616 while (mo) { | |
617 struct proto_buddy_menu *pbm = mo->data; | |
618 GtkWidget *button; | |
619 | |
620 button = gtk_menu_item_new_with_label(pbm->label); | |
621 g_signal_connect(GTK_OBJECT(button), "activate", | |
622 G_CALLBACK(menu_click), b->name); | |
623 gtk_object_set_user_data(GTK_OBJECT(button), mo); | |
624 gtk_menu_append(GTK_MENU(menu), button); | |
625 gtk_widget_show(button); | |
626 | |
627 mo = mo->next; | |
628 } | |
629 } | |
630 } | |
631 | |
632 /* we send the menu widget so we can add menuitems within a plugin */ | |
633 plugin_event(event_draw_menu, menu, b->name); | |
634 | |
635 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); | |
636 | |
637 } else if (event->type == GDK_3BUTTON_PRESS && event->button == 2) { | |
638 if (!g_strcasecmp("zilding", normalize (b->name))) | |
639 show_ee_dialog(0); | |
640 else if (!g_strcasecmp("robflynn", normalize (b->name))) | |
641 show_ee_dialog(1); | |
642 else if (!g_strcasecmp("flynorange", normalize (b->name))) | |
643 show_ee_dialog(2); | |
644 else if (!g_strcasecmp("ewarmenhoven", normalize (b->name))) | |
645 show_ee_dialog(3); | |
646 else if (!g_strcasecmp("markster97", normalize (b->name))) | |
647 show_ee_dialog(4); | |
648 else if (!g_strcasecmp("seanegn", normalize (b->name))) | |
649 show_ee_dialog(5); | |
650 else if (!g_strcasecmp("chipx86", normalize (b->name))) | |
651 show_ee_dialog(6); | |
652 else if (!g_strcasecmp("kingant", normalize (b->name))) | |
653 show_ee_dialog(7); | |
654 else if (!g_strcasecmp("lschiere", normalize (b->name))) | |
655 show_ee_dialog(8); | |
656 | |
657 } else { | |
658 | |
659 /* Anything for other buttons? :) */ | |
660 } | |
661 | |
662 return FALSE; | |
663 } | |
664 | |
665 static void un_alias(GtkWidget *a, struct buddy *b) | |
666 { | |
667 b->alias[0] = '\0'; | |
668 handle_buddy_rename(b, b->name); /* make me a sammich! */ | |
669 serv_alias_buddy(b); | |
670 gaim_blist_save(); | |
671 } | |
672 | |
673 static gboolean click_edit_tree(GtkWidget *widget, GdkEventButton *event, gpointer data) | |
674 { | |
675 GtkCTreeNode *node; | |
676 int *type; | |
677 int row, column; | |
678 static GtkWidget *menu = NULL; | |
679 GtkWidget *button; | |
680 static GList *mo_top = NULL; | |
681 | |
682 if (event->button != 3 || event->type != GDK_BUTTON_PRESS) | |
683 return FALSE; | |
684 | |
685 if (!gtk_clist_get_selection_info(GTK_CLIST(edittree), event->x, event->y, &row, &column)) | |
686 return FALSE; | |
687 | |
688 node = gtk_ctree_node_nth(GTK_CTREE(edittree), row); | |
689 type = gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node); | |
690 | |
691 /* | |
692 * If a menu already exists, destroy it before creating a new one, | |
693 * thus freeing-up the memory it occupied. | |
694 */ | |
695 if(menu) { | |
696 gtk_widget_destroy(menu); | |
697 menu = NULL; /* safety measure */ | |
698 if(mo_top) { | |
699 g_list_foreach(mo_top, (GFunc)g_free, NULL); | |
700 g_list_free(mo_top); | |
701 mo_top = NULL; | |
702 } | |
703 } | |
704 | |
705 if (*type == EDIT_GROUP) { | |
706 struct group *group = (struct group *)type; | |
707 menu = gtk_menu_new(); | |
708 | |
709 button = gtk_menu_item_new_with_label(_("Rename")); | |
710 g_signal_connect(GTK_OBJECT(button), "activate", | |
711 G_CALLBACK(show_rename_group), group); | |
712 gtk_menu_append(GTK_MENU(menu), button); | |
713 gtk_widget_show(button); | |
714 | |
715 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); | |
716 | |
717 return TRUE; | |
718 } else if (*type == EDIT_BUDDY) { | |
719 struct buddy *b = (struct buddy *)type; | |
720 menu = gtk_menu_new(); | |
721 | |
722 button = gtk_menu_item_new_with_label(_("IM")); | |
723 g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(pressed_im_bud), b); | |
724 gtk_menu_append(GTK_MENU(menu), button); | |
725 gtk_widget_show(button); | |
726 | |
727 button = gtk_menu_item_new_with_label(_("Alias")); | |
728 g_signal_connect(GTK_OBJECT(button), "activate", | |
729 G_CALLBACK(pressed_alias_bud), b); | |
730 gtk_menu_append(GTK_MENU(menu), button); | |
731 gtk_widget_show(button); | |
732 | |
733 if (b->alias[0]) { | |
734 button = gtk_menu_item_new_with_label(_("Un-Alias")); | |
735 g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(un_alias), b); | |
736 gtk_menu_append(GTK_MENU(menu), button); | |
737 gtk_widget_show(button); | |
738 } | |
739 | |
740 button = gtk_menu_item_new_with_label(_("Rename")); | |
741 g_signal_connect(GTK_OBJECT(button), "activate", | |
742 G_CALLBACK(show_rename_buddy), b); | |
743 gtk_menu_append(GTK_MENU(menu), button); | |
744 gtk_widget_show(button); | |
745 | |
746 button = gtk_menu_item_new_with_label(_("Add Buddy Pounce")); | |
747 g_signal_connect(GTK_OBJECT(button), "activate", | |
748 G_CALLBACK(new_bp_callback), b); | |
749 gtk_menu_append(GTK_MENU(menu), button); | |
750 gtk_widget_show(button); | |
751 | |
752 button = gtk_menu_item_new_with_label(_("View Log")); | |
753 g_signal_connect(GTK_OBJECT(button), "activate", | |
754 G_CALLBACK(pressed_log), b->name); | |
755 gtk_menu_append(GTK_MENU(menu), button); | |
756 gtk_widget_show(button); | |
757 | |
758 /* | |
759 * Add protocol-specific edit buddy menu items if they exist | |
760 */ | |
761 if (b->account->gc && b->account->gc->prpl->edit_buddy_menu) { | |
762 GList *mo = mo_top = b->account->gc->prpl->edit_buddy_menu(b->account->gc, b->name); | |
763 | |
764 while (mo) { | |
765 struct proto_buddy_menu *pbm = mo->data; | |
766 GtkWidget *button; | |
767 | |
768 button = gtk_menu_item_new_with_label(pbm->label); | |
769 g_signal_connect(GTK_OBJECT(button), "activate", | |
770 G_CALLBACK(menu_click), b->name); | |
771 gtk_object_set_user_data(GTK_OBJECT(button), mo); | |
772 gtk_menu_append(GTK_MENU(menu), button); | |
773 gtk_widget_show(button); | |
774 | |
775 mo = mo->next; | |
776 } | |
777 } | |
778 | |
779 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); | |
780 | |
781 return TRUE; | |
782 } | |
783 | |
784 return FALSE; | |
785 } | |
786 | |
787 | |
788 /* | |
789 * Find and remove CTree node associated with buddylist entry | |
790 */ | |
791 static void ui_remove_buddy_node(struct group *rem_g, struct buddy *rem_b) | |
792 { | |
793 GtkCTreeNode *gnode = NULL, *bnode; | |
794 | |
795 if((gnode = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, rem_g)) != NULL && | |
796 (bnode = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), gnode, rem_b)) != NULL) | |
797 { | |
798 gtk_ctree_remove_node(GTK_CTREE(edittree), bnode); | |
799 } | |
800 } | |
801 | |
802 void ui_remove_buddy(struct buddy *rem_b) | |
803 { | |
804 struct gaim_conversation *c; | |
805 struct group *rem_g = find_group_by_buddy(rem_b); | |
806 struct group_show *gs; | |
807 struct buddy_show *bs; | |
808 | |
809 gs = find_group_show(rem_g->name); | |
810 if (gs) { | |
811 bs = find_buddy_show(gs, rem_b->name); | |
812 if (bs) { | |
813 if (g_slist_find(bs->connlist, rem_b->account->gc)) { | |
814 bs->connlist = g_slist_remove(bs->connlist, rem_b->account->gc); | |
815 if (!g_slist_length(bs->connlist)) { | |
816 gs->members = g_slist_remove(gs->members, bs); | |
817 if (bs->log_timer > 0) | |
818 g_source_remove(bs->log_timer); | |
819 bs->log_timer = 0; | |
820 remove_buddy_show(gs, bs); | |
821 g_free(bs->name); | |
822 g_free(bs); | |
823 if (!g_slist_length(gs->members) && | |
824 (blist_options & OPT_BLIST_NO_MT_GRP)) { | |
825 shows = g_slist_remove(shows, gs); | |
826 gtk_tree_remove_item(GTK_TREE(buddies), gs->item); | |
827 g_free(gs->name); | |
828 g_free(gs); | |
829 gs = NULL; | |
830 } | |
831 } | |
832 } | |
833 } | |
834 if (gs) | |
835 update_num_group(gs); | |
836 } | |
837 | |
838 c = gaim_find_conversation(rem_b->name); | |
839 | |
840 if (c) | |
841 gaim_conversation_update(c, GAIM_CONV_UPDATE_REMOVE); | |
842 | |
843 /* CONVXXX update_buttons_by_protocol(c); */ | |
844 | |
845 /* Remove CTree node for buddy */ | |
846 ui_remove_buddy_node(rem_g, rem_b); | |
847 | |
848 } | |
849 | |
850 void ui_remove_group(struct group *rem_g) | |
851 { | |
852 struct group_show *gs; | |
853 GtkCTreeNode *gnode = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, rem_g); | |
854 gtk_ctree_remove_node(GTK_CTREE(edittree), gnode); | |
855 | |
856 | |
857 if ((gs = find_group_show(rem_g->name)) != NULL) { | |
858 shows = g_slist_remove(shows, gs); | |
859 gtk_tree_remove_item(GTK_TREE(buddies), gs->item); | |
860 g_free(gs->name); | |
861 g_free(gs); | |
862 } | |
863 } | |
864 | |
865 gboolean edit_drag_compare_func(GtkCTree *ctree, GtkCTreeNode *source_node, | |
866 GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling) | |
867 { | |
868 int *type; | |
869 | |
870 type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), source_node); | |
871 | |
872 if (*type == EDIT_GROUP) { | |
873 if (!new_parent) | |
874 return TRUE; | |
875 } else if (*type == EDIT_BUDDY) { | |
876 if (new_parent) { | |
877 type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), new_parent); | |
878 if (*type == EDIT_GROUP) | |
879 return TRUE; | |
880 } | |
881 } | |
882 | |
883 return FALSE; | |
884 } | |
885 | |
886 | |
887 /* you really shouldn't call this function */ | |
888 void redo_buddy_list() | |
889 { | |
890 /* so here we can safely assume that we don't have to add or delete anything, we | |
891 * just have to go through and reorder everything. remember, nothing is going to | |
892 * change connections, so we can assume that we don't have to change any user | |
893 * data or anything. this is just a simple reordering. so calm down. */ | |
894 /* note: we only have to do this if we want to strongly enforce order; however, | |
895 * order doesn't particularly matter to the stability of the program. but, it's | |
896 * kind of nice to have */ | |
897 /* the easy way to implement this is just to go through shows and destroy all the | |
898 * group_shows, then go through the connections and put everything back. though, | |
899 * there are slight complications with that; most of them deal with timeouts and | |
900 * people not seeing the login icon for the full 10 seconds. butt fuck them. */ | |
901 GSList *s = shows; | |
902 struct group_show *gs; | |
903 GSList *m; | |
904 struct buddy_show *bs; | |
905 GSList *gr; | |
906 struct group *g; | |
907 struct buddy *b; | |
908 | |
909 if (!blist) | |
910 return; | |
911 | |
912 while (s) { | |
913 gs = (struct group_show *)s->data; | |
914 s = g_slist_remove(s, gs); | |
915 m = gs->members; | |
916 gtk_tree_remove_item(GTK_TREE(buddies), gs->item); | |
917 while (m) { | |
918 bs = (struct buddy_show *)m->data; | |
919 m = g_slist_remove(m, bs); | |
920 if (bs->log_timer > 0) | |
921 g_source_remove(bs->log_timer); | |
922 g_free(bs->name); | |
923 g_free(bs); | |
924 } | |
925 g_free(gs->name); | |
926 g_free(gs); | |
927 } | |
928 shows = NULL; | |
929 gr = groups; | |
930 while (gr) { | |
931 g = (struct group *)gr->data; | |
932 gr = gr->next; | |
933 gs = find_group_show(g->name); | |
934 if (!gs && !(blist_options & OPT_BLIST_NO_MT_GRP) | |
935 && gaim_group_on_account(g, NULL)) | |
936 gs = new_group_show(g->name); | |
937 m = g->members; | |
938 while (m) { | |
939 b = (struct buddy *)m->data; | |
940 m = m->next; | |
941 if (b->present) { | |
942 if (!gs) | |
943 gs = new_group_show(g->name); | |
944 bs = find_buddy_show(gs, b->name); | |
945 if (!bs) { | |
946 if (b->account->gc->prpl->list_icon) | |
947 bs = new_buddy_show(gs, b, | |
948 b->account->gc->prpl->list_icon(b-> | |
949 uc)); | |
950 else | |
951 bs = new_buddy_show(gs, b, (char **)no_icon_xpm); | |
952 } | |
953 bs->connlist = g_slist_append(bs->connlist, b->account->gc); | |
954 update_num_group(gs); | |
955 } | |
956 } | |
957 } | |
958 update_idle_times(); | |
959 } | |
960 | |
961 static void edit_tree_move(GtkCTree *ctree, GtkCTreeNode *child, | |
962 GtkCTreeNode *parent, GtkCTreeNode *sibling, | |
963 gpointer data) | |
964 { | |
965 int *ctype, *ptype = NULL, *stype = NULL; | |
966 | |
967 ctype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), child); | |
968 | |
969 if (parent) | |
970 ptype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), parent); | |
971 | |
972 if (sibling) | |
973 stype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), sibling); | |
974 | |
975 if (*ctype == EDIT_BUDDY) { | |
976 /* we moved a buddy. hopefully we just changed groups or positions or something. | |
977 * if we changed connections, we copy the buddy to the new connection. if the new | |
978 * connection already had the buddy in its buddy list but in a different group, | |
979 * we change the group that the buddy is in */ | |
980 struct group *old_g, *new_g = (struct group *)ptype; | |
981 struct buddy *s = NULL, *buddy = (struct buddy *)ctype; | |
982 int pos; | |
983 | |
984 old_g = find_group_by_buddy(buddy); | |
985 | |
986 old_g->members = g_slist_remove(old_g->members, buddy); | |
987 | |
988 if (sibling) { | |
989 s = (struct buddy *)stype; | |
990 pos = g_slist_index(new_g->members, s); | |
991 if (pos) | |
992 new_g->members = g_slist_insert(new_g->members, buddy, pos); | |
993 else | |
994 new_g->members = g_slist_prepend(new_g->members, buddy); | |
995 } else | |
996 new_g->members = g_slist_append(new_g->members, buddy); | |
997 | |
998 serv_move_buddy(buddy, old_g, new_g); | |
999 | |
1000 gaim_blist_save(); | |
1001 } else { /* group */ | |
1002 | |
1003 /* move the group. if moving connections, copy the group, and each buddy in the | |
1004 * group. if the buddy exists in the new connection, leave it where it is. */ | |
1005 | |
1006 struct group *g, *g2, *group; | |
1007 int pos; | |
1008 | |
1009 group = (struct group *)ctype; | |
1010 | |
1011 g = group; | |
1012 | |
1013 groups = g_slist_remove(groups, g); | |
1014 | |
1015 if (sibling) { | |
1016 g2 = (struct group *)stype; | |
1017 pos = g_slist_index(groups, g2); | |
1018 if (pos) | |
1019 groups = g_slist_insert(groups, g, pos); | |
1020 else | |
1021 groups = g_slist_prepend(groups, g); | |
1022 } else | |
1023 groups = g_slist_append(groups, g); | |
1024 | |
1025 gaim_blist_save(); | |
1026 } | |
1027 | |
1028 redo_buddy_list(); | |
1029 update_num_groups(); | |
1030 } | |
1031 | |
1032 void | |
1033 create_prpl_icon(GtkWidget *widget, struct gaim_connection *gc, | |
1034 GdkPixmap **pixmap, GdkBitmap **mask) | |
1035 { | |
1036 /* This whole thing is a hack--but it looks nice. | |
1037 * Probably should have a prpl->icon(struct gaim_connection *) to | |
1038 * do this. */ | |
1039 GtkStyle *style; | |
1040 char **xpm = NULL; | |
1041 | |
1042 if (widget == NULL || gc == NULL || pixmap == NULL || mask == NULL) | |
1043 return; | |
1044 | |
1045 style = gtk_widget_get_style( widget ); | |
1046 | |
1047 if (gc->prpl->list_icon) { | |
1048 if (gc->prpl->protocol == PROTO_OSCAR) { | |
1049 if (isdigit(*gc->username)) { | |
1050 xpm = gc->prpl->list_icon(0); | |
1051 } else { | |
1052 xpm = gc->prpl->list_icon(0x10); | |
1053 } | |
1054 } else { | |
1055 xpm = gc->prpl->list_icon (0); | |
1056 } | |
1057 } | |
1058 if (xpm == NULL) | |
1059 xpm = (char **)no_icon_xpm; | |
1060 | |
1061 *pixmap = gdk_pixmap_create_from_xpm_d(widget->window, mask, &style->bg[GTK_STATE_NORMAL], xpm); | |
1062 } | |
1063 | |
1064 void build_edit_tree() | |
1065 { | |
1066 GtkCTreeNode *p = NULL, *n; | |
1067 GSList *grp; | |
1068 GSList *mem; | |
1069 struct group *g; | |
1070 struct buddy *b; | |
1071 char *text[1]; | |
1072 | |
1073 if (!blist) | |
1074 return; | |
1075 | |
1076 gtk_clist_freeze(GTK_CLIST(edittree)); | |
1077 gtk_clist_clear(GTK_CLIST(edittree)); | |
1078 | |
1079 | |
1080 grp = groups; | |
1081 | |
1082 while (grp) { | |
1083 | |
1084 g = (struct group *)grp->data; | |
1085 | |
1086 text[0] = g->name; | |
1087 | |
1088 p = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL, | |
1089 NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1); | |
1090 | |
1091 gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g); | |
1092 | |
1093 n = NULL; | |
1094 | |
1095 mem = g->members; | |
1096 | |
1097 while (mem) { | |
1098 char buf[256]; | |
1099 b = (struct buddy *)mem->data; | |
1100 if(b->account->gc) { | |
1101 if (get_buddy_alias_only(b)) { | |
1102 g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b)); | |
1103 text[0] = buf; | |
1104 } else | |
1105 text[0] = b->name; | |
1106 | |
1107 n = gtk_ctree_insert_node(GTK_CTREE(edittree), | |
1108 p, NULL, text, 5, | |
1109 NULL, NULL, NULL, NULL, 1, 1); | |
1110 | |
1111 gtk_ctree_node_set_row_data(GTK_CTREE(edittree), n, b); | |
1112 } | |
1113 | |
1114 mem = mem->next; | |
1115 } | |
1116 grp = g_slist_next(grp); | |
1117 } | |
1118 | |
1119 gtk_clist_thaw(GTK_CLIST(edittree)); | |
1120 | |
1121 } | |
1122 | |
1123 void ui_add_buddy(struct gaim_connection *gc, struct group *g, struct buddy *b) | |
1124 { | |
1125 GtkCTreeNode *p = NULL, *n; | |
1126 char *text[1]; | |
1127 char buf[256]; | |
1128 struct group_show *gs = find_group_show(g->name); | |
1129 | |
1130 b->edittype = EDIT_BUDDY; | |
1131 | |
1132 if (gs) | |
1133 update_num_group(gs); | |
1134 | |
1135 if (!blist) | |
1136 return; | |
1137 | |
1138 if(!b->account->gc) | |
1139 return; | |
1140 | |
1141 p = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, g); | |
1142 if (get_buddy_alias_only(b)) { | |
1143 g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b)); | |
1144 text[0] = buf; | |
1145 } else | |
1146 text[0] = b->name; | |
1147 | |
1148 n = gtk_ctree_insert_node(GTK_CTREE(edittree), p, NULL, text, 5, NULL, NULL, NULL, NULL, 1, 1); | |
1149 gtk_ctree_node_set_row_data(GTK_CTREE(edittree), n, b); | |
1150 } | |
1151 | |
1152 void ui_add_group(struct group *g) | |
1153 { | |
1154 GtkCTreeNode *p; | |
1155 char *text[1]; | |
1156 | |
1157 g->edittype = EDIT_GROUP; | |
1158 | |
1159 if (!blist) | |
1160 return; | |
1161 | |
1162 text[0] = g->name; | |
1163 p = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL, NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1); | |
1164 gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g); | |
1165 | |
1166 if (!(blist_options & OPT_BLIST_NO_MT_GRP) && !find_group_show(g->name) | |
1167 && gaim_group_on_account(g, NULL)) | |
1168 new_group_show(g->name); | |
1169 } | |
1170 | |
1171 | |
1172 static void do_del_buddy(GtkWidget *w, GtkCTree *ctree) | |
1173 { | |
1174 GtkCTreeNode *node; | |
1175 struct buddy *b; | |
1176 struct group *g; | |
1177 int *type; | |
1178 GList *i; | |
1179 | |
1180 i = GTK_CLIST(edittree)->selection; | |
1181 if (i) { | |
1182 node = i->data; | |
1183 type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node); | |
1184 | |
1185 if (*type == EDIT_BUDDY) { | |
1186 b = (struct buddy *)type; | |
1187 g = find_group_by_buddy(b); | |
1188 serv_remove_buddy(b->account->gc, b->name, g->name); | |
1189 remove_buddy(b); | |
1190 gaim_blist_save(); | |
1191 } else if (*type == EDIT_GROUP) { | |
1192 remove_group((struct group *)type); | |
1193 gaim_blist_save(); | |
1194 } | |
1195 | |
1196 } else { | |
1197 /* Nothing selected. */ | |
1198 } | |
1199 } | |
1200 | |
1201 | |
1202 void import_callback(GtkWidget *widget, void *null) | |
1203 { | |
1204 show_import_dialog(); | |
1205 } | |
1206 | |
1207 void add_buddy_callback(GtkWidget *widget, void *dummy) | |
1208 { | |
1209 char *grp = NULL; | |
1210 GtkCTreeNode *node; | |
1211 GList *i; | |
1212 struct gaim_connection *gc = NULL; | |
1213 int *type; | |
1214 | |
1215 i = GTK_CLIST(edittree)->selection; | |
1216 if (i) { | |
1217 node = i->data; | |
1218 type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node); | |
1219 | |
1220 if (*type == EDIT_BUDDY) { | |
1221 struct buddy *b = (struct buddy *)type; | |
1222 struct group *g = find_group_by_buddy(b); | |
1223 grp = g->name; | |
1224 gc = b->account->gc; | |
1225 } else if (*type == EDIT_GROUP) { | |
1226 struct group *g = (struct group *)type; | |
1227 grp = g->name; | |
1228 if(g->members) | |
1229 gc = ((struct buddy *)g->members->data)->account->gc; | |
1230 else | |
1231 gc = connections->data; | |
1232 } else { | |
1233 gc = (struct gaim_connection *)type; | |
1234 } | |
1235 } | |
1236 show_add_buddy(gc, NULL, grp, NULL); | |
1237 | |
1238 } | |
1239 | |
1240 void add_group_callback(GtkWidget *widget, void *dummy) | |
1241 { | |
1242 GtkCTreeNode *node; | |
1243 GList *i; | |
1244 struct gaim_connection *gc = NULL; | |
1245 int *type; | |
1246 | |
1247 i = GTK_CLIST(edittree)->selection; | |
1248 if (i) { | |
1249 node = i->data; | |
1250 type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node); | |
1251 if (*type == EDIT_BUDDY) | |
1252 gc = ((struct buddy *)type)->account->gc; | |
1253 else if (*type == EDIT_GROUP) | |
1254 gc = connections->data; | |
1255 else | |
1256 gc = (struct gaim_connection *)type; | |
1257 } | |
1258 show_add_group(gc); | |
1259 } | |
1260 | |
1261 static void im_callback(GtkWidget *widget, GtkTree *tree) | |
1262 { | |
1263 GList *i; | |
1264 struct buddy_show *b = NULL; | |
1265 struct gaim_conversation *c; | |
1266 struct gaim_account *account; | |
1267 | |
1268 i = GTK_TREE_SELECTION_OLD(tree); | |
1269 if (i) { | |
1270 b = gtk_object_get_user_data(GTK_OBJECT(i->data)); | |
1271 } | |
1272 if (!i || !b) { | |
1273 show_im_dialog(); | |
1274 return; | |
1275 } | |
1276 if (!b->name) | |
1277 return; | |
1278 | |
1279 account = ((struct gaim_connection *)b->connlist->data)->account; | |
1280 | |
1281 c = gaim_find_conversation(b->name); | |
1282 | |
1283 if (c == NULL) | |
1284 c = gaim_conversation_new(GAIM_CONV_IM, account, b->name); | |
1285 else { | |
1286 gaim_conversation_set_account(c, account); | |
1287 gaim_window_raise(gaim_conversation_get_window(c)); | |
1288 } | |
1289 } | |
1290 | |
1291 static void info_callback(GtkWidget *widget, GtkTree *tree) | |
1292 { | |
1293 GList *i; | |
1294 struct buddy_show *b = NULL; | |
1295 i = GTK_TREE_SELECTION_OLD(tree); | |
1296 if (i) { | |
1297 b = gtk_object_get_user_data(GTK_OBJECT(i->data)); | |
1298 } | |
1299 if (!i || !b) { | |
1300 show_info_dialog(); | |
1301 return; | |
1302 } | |
1303 if (!b->name) | |
1304 return; | |
1305 if (b->connlist) | |
1306 serv_get_info(b->connlist->data, b->name); | |
1307 } | |
1308 | |
1309 | |
1310 void chat_callback(GtkWidget *widget, GtkTree *tree) | |
1311 { | |
1312 join_chat(); | |
1313 } | |
1314 | |
1315 static void away_callback(GtkWidget *widget, GtkTree *tree) | |
1316 { | |
1317 GSList *awy = away_messages; | |
1318 static GtkWidget *menu = NULL; | |
1319 GtkWidget *menuitem; | |
1320 | |
1321 if (!awy) | |
1322 return; | |
1323 | |
1324 /* | |
1325 * If a menu already exists, destroy it before creating a new one, | |
1326 * thus freeing-up the memory it occupied. | |
1327 */ | |
1328 if(menu) | |
1329 gtk_widget_destroy(menu); | |
1330 | |
1331 menu = gtk_menu_new(); | |
1332 | |
1333 while (awy) { | |
1334 struct away_message *a = awy->data; | |
1335 | |
1336 menuitem = gtk_menu_item_new_with_label(a->name); | |
1337 gtk_menu_append(GTK_MENU(menu), menuitem); | |
1338 g_signal_connect(GTK_OBJECT(menuitem), "activate", | |
1339 G_CALLBACK(do_away_message), a); | |
1340 gtk_widget_show(menuitem); | |
1341 awy = awy->next; | |
1342 } | |
1343 | |
1344 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME ); | |
1345 } | |
1346 | |
1347 void rem_bp(GtkWidget *w, struct buddy_pounce *b) | |
1348 { | |
1349 buddy_pounces = g_list_remove(buddy_pounces, b); | |
1350 do_bp_menu(); | |
1351 save_prefs(); | |
1352 } | |
1353 | |
1354 void do_pounce(struct gaim_connection *gc, char *name, int when) | |
1355 { | |
1356 char *who; | |
1357 | |
1358 struct buddy_pounce *b; | |
1359 struct gaim_conversation *c; | |
1360 struct gaim_account *account; | |
1361 | |
1362 GList *bp = buddy_pounces; | |
1363 | |
1364 who = g_strdup(normalize (name)); | |
1365 | |
1366 while (bp) { | |
1367 b = (struct buddy_pounce *)bp->data; | |
1368 bp = bp->next; /* increment the list here because rem_bp can make our handle bad */ | |
1369 | |
1370 if (!(b->options & when)) | |
1371 continue; | |
1372 | |
1373 account = gaim_account_find(b->pouncer, b->protocol); /* find our user */ | |
1374 if (account == NULL) | |
1375 continue; | |
1376 | |
1377 /* check and see if we're signed on as the pouncer */ | |
1378 if (account->gc != gc) | |
1379 continue; | |
1380 | |
1381 if (!g_strcasecmp(who, normalize (b->name))) { /* find someone to pounce */ | |
1382 if (b->options & OPT_POUNCE_POPUP) { | |
1383 c = gaim_find_conversation(name); | |
1384 | |
1385 if (c == NULL) | |
1386 c = gaim_conversation_new(GAIM_CONV_IM, account, name); | |
1387 else | |
1388 gaim_conversation_set_account(c, account); | |
1389 } | |
1390 if (b->options & OPT_POUNCE_NOTIFY) { | |
1391 char tmp[1024]; | |
1392 | |
1393 /* I know the line below is really ugly. I only did it this way | |
1394 * because I thought it'd be funny :-) */ | |
1395 | |
1396 g_snprintf(tmp, sizeof(tmp), | |
1397 (when & OPT_POUNCE_TYPING) ? _("%s has started typing to you") : | |
1398 (when & OPT_POUNCE_SIGNON) ? _("%s has signed on") : | |
1399 (when & OPT_POUNCE_UNIDLE) ? _("%s has returned from being idle") : | |
1400 _("%s has returned from being away"), name); | |
1401 | |
1402 do_error_dialog(tmp, NULL, GAIM_INFO); | |
1403 } | |
1404 if (b->options & OPT_POUNCE_SEND_IM) { | |
1405 if (strlen(b->message) > 0) { | |
1406 c = gaim_find_conversation(name); | |
1407 | |
1408 if (c == NULL) | |
1409 c = gaim_conversation_new(GAIM_CONV_IM, account, name); | |
1410 else | |
1411 gaim_conversation_set_account(c, account); | |
1412 | |
1413 gaim_conversation_write(c, NULL, b->message, -1, | |
1414 WFLAG_SEND, time(NULL)); | |
1415 | |
1416 serv_send_im(account->gc, name, b->message, -1, 0); | |
1417 } | |
1418 } | |
1419 if (b->options & OPT_POUNCE_COMMAND) { | |
1420 #ifndef _WIN32 | |
1421 int pid = fork(); | |
1422 | |
1423 if (pid == 0) { | |
1424 char *args[4]; | |
1425 args[0] = "sh"; | |
1426 args[1] = "-c"; | |
1427 args[2] = b->command; | |
1428 args[3] = NULL; | |
1429 execvp(args[0], args); | |
1430 _exit(0); | |
1431 } | |
1432 #else | |
1433 STARTUPINFO si; | |
1434 PROCESS_INFORMATION pi; | |
1435 | |
1436 ZeroMemory( &si, sizeof(si) ); | |
1437 si.cb = sizeof(si); | |
1438 ZeroMemory( &pi, sizeof(pi) ); | |
1439 | |
1440 CreateProcess( NULL, b->command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); | |
1441 CloseHandle( pi.hProcess ); | |
1442 CloseHandle( pi.hThread ); | |
1443 #endif /*_WIN32*/ | |
1444 } | |
1445 if (b->options & OPT_POUNCE_SOUND) { | |
1446 if (strlen(b->sound)) | |
1447 gaim_sound_play_file(b->sound); | |
1448 else | |
1449 gaim_sound_play_event(GAIM_SOUND_POUNCE_DEFAULT); | |
1450 } | |
1451 | |
1452 if (!(b->options & OPT_POUNCE_SAVE)) | |
1453 rem_bp(NULL, b); | |
1454 | |
1455 } | |
1456 } | |
1457 g_free(who); | |
1458 } | |
1459 | |
1460 static void new_bp_callback(GtkWidget *w, struct buddy *b) | |
1461 { | |
1462 if (b) | |
1463 show_new_bp(b->name, b->account->gc, b->idle, b->uc & UC_UNAVAILABLE, NULL); | |
1464 else | |
1465 show_new_bp(NULL, NULL, 0, 0, NULL); | |
1466 } | |
1467 | |
1468 static void edit_bp_callback(GtkWidget *w, struct buddy_pounce *b) | |
1469 { | |
1470 show_new_bp(NULL, NULL, 0, 0, b); | |
1471 } | |
1472 | |
1473 static GtkTooltips *bp_tooltip = NULL; | |
1474 void do_bp_menu() | |
1475 { | |
1476 GtkWidget *menuitem, *mess, *messmenu; | |
1477 static GtkWidget *remmenu; | |
1478 GtkWidget *remitem; | |
1479 GtkWidget *sep; | |
1480 GList *l; | |
1481 struct buddy_pounce *b; | |
1482 GList *bp = buddy_pounces; | |
1483 | |
1484 /* Tooltip for editing bp's */ | |
1485 if(!bp_tooltip) | |
1486 bp_tooltip = gtk_tooltips_new(); | |
1487 | |
1488 l = gtk_container_children(GTK_CONTAINER(bpmenu)); | |
1489 | |
1490 while (l) { | |
1491 gtk_widget_destroy(GTK_WIDGET(l->data)); | |
1492 l = l->next; | |
1493 } | |
1494 | |
1495 remmenu = gtk_menu_new(); | |
1496 | |
1497 menuitem = gtk_menu_item_new_with_label(_("New Buddy Pounce")); | |
1498 gtk_menu_append(GTK_MENU(bpmenu), menuitem); | |
1499 gtk_widget_show(menuitem); | |
1500 g_signal_connect(GTK_OBJECT(menuitem), "activate", G_CALLBACK(new_bp_callback), NULL); | |
1501 | |
1502 | |
1503 while (bp) { | |
1504 | |
1505 b = (struct buddy_pounce *)bp->data; | |
1506 remitem = gtk_menu_item_new_with_label(b->name); | |
1507 gtk_menu_append(GTK_MENU(remmenu), remitem); | |
1508 gtk_widget_show(remitem); | |
1509 g_signal_connect(GTK_OBJECT(remitem), "activate", G_CALLBACK(rem_bp), b); | |
1510 | |
1511 bp = bp->next; | |
1512 | |
1513 } | |
1514 | |
1515 menuitem = gtk_menu_item_new_with_label(_("Remove Buddy Pounce")); | |
1516 gtk_menu_append(GTK_MENU(bpmenu), menuitem); | |
1517 gtk_widget_show(menuitem); | |
1518 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), remmenu); | |
1519 gtk_widget_show(remmenu); | |
1520 | |
1521 sep = gtk_hseparator_new(); | |
1522 menuitem = gtk_menu_item_new(); | |
1523 gtk_menu_append(GTK_MENU(bpmenu), menuitem); | |
1524 gtk_container_add(GTK_CONTAINER(menuitem), sep); | |
1525 gtk_widget_set_sensitive(menuitem, FALSE); | |
1526 gtk_widget_show(menuitem); | |
1527 gtk_widget_show(sep); | |
1528 | |
1529 bp = buddy_pounces; | |
1530 | |
1531 while (bp) { | |
1532 | |
1533 b = (struct buddy_pounce *)bp->data; | |
1534 | |
1535 menuitem = gtk_menu_item_new_with_label(b->name); | |
1536 gtk_menu_append(GTK_MENU(bpmenu), menuitem); | |
1537 messmenu = gtk_menu_new(); | |
1538 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), messmenu); | |
1539 gtk_widget_show(menuitem); | |
1540 | |
1541 if (strlen(b->message)) | |
1542 mess = gtk_menu_item_new_with_label(b->message); | |
1543 else | |
1544 mess = gtk_menu_item_new_with_label(_("[no message]")); | |
1545 gtk_menu_append(GTK_MENU(messmenu), mess); | |
1546 gtk_tooltips_set_tip(bp_tooltip, GTK_WIDGET(mess), _("[Click to edit]"), NULL); | |
1547 gtk_widget_show(mess); | |
1548 g_signal_connect(GTK_OBJECT(mess), "activate", G_CALLBACK(edit_bp_callback), b); | |
1549 bp = bp->next; | |
1550 | |
1551 } | |
1552 | |
1553 } | |
1554 | |
1555 | |
1556 static struct group_show *find_group_show(char *group) | |
1557 { | |
1558 GSList *m = shows; | |
1559 struct group_show *g = NULL; | |
1560 char *who = g_strdup(normalize (group)); | |
1561 | |
1562 while (m) { | |
1563 g = (struct group_show *)m->data; | |
1564 if (!g_strcasecmp(normalize (g->name), who)) | |
1565 break; | |
1566 g = NULL; | |
1567 m = m->next; | |
1568 } | |
1569 g_free(who); | |
1570 | |
1571 return g; | |
1572 } | |
1573 | |
1574 static struct buddy_show *find_buddy_show(struct group_show *gs, char *name) | |
1575 { | |
1576 GSList *m = gs->members; | |
1577 struct buddy_show *b = NULL; | |
1578 char *who = g_strdup(normalize (name)); | |
1579 | |
1580 while (m) { | |
1581 b = (struct buddy_show *)m->data; | |
1582 if (!g_strcasecmp(normalize (b->name), who)) | |
1583 break; | |
1584 b = NULL; | |
1585 m = m->next; | |
1586 } | |
1587 g_free(who); | |
1588 | |
1589 return b; | |
1590 } | |
1591 | |
1592 static int group_number(char *group) | |
1593 { | |
1594 GSList *m; | |
1595 struct group *p; | |
1596 int pos = 0; | |
1597 | |
1598 m = groups; | |
1599 while (m) { | |
1600 p = (struct group *)m->data; | |
1601 if (!strcmp(p->name, group)) | |
1602 return pos; | |
1603 if (find_group_show(p->name)) | |
1604 pos++; | |
1605 m = m->next; | |
1606 } | |
1607 /* um..... we'll never get here */ | |
1608 return -1; | |
1609 } | |
1610 | |
1611 static int buddy_number(char *group, char *buddy) | |
1612 { | |
1613 struct group *p; | |
1614 GSList *z; | |
1615 struct buddy *b; | |
1616 int pos = 0; | |
1617 char *tmp1 = g_strdup(normalize (buddy)); | |
1618 struct group_show *gs = find_group_show(group); | |
1619 struct buddy_show *bs; | |
1620 GSList *seen = NULL; | |
1621 | |
1622 p = find_group(group); | |
1623 if(p) { | |
1624 z = p->members; | |
1625 while (z) { | |
1626 b = (struct buddy *)z->data; | |
1627 if (!strcmp(tmp1, normalize (b->name))) { | |
1628 g_free(tmp1); | |
1629 g_slist_free(seen); | |
1630 return pos; | |
1631 } | |
1632 if ((bs = find_buddy_show(gs, b->name))) { | |
1633 if(!g_slist_find(seen, bs)) { | |
1634 seen = g_slist_append(seen, bs); | |
1635 pos++; | |
1636 } | |
1637 } | |
1638 z = z->next; | |
1639 } | |
1640 } | |
1641 /* we shouldn't ever get here */ | |
1642 debug_printf("got to bad place in buddy_number\n"); | |
1643 g_free(tmp1); | |
1644 g_slist_free(seen); | |
1645 return -1; | |
1646 } | |
1647 | |
1648 | |
1649 | |
1650 static struct group_show *new_group_show(char *group) | |
1651 { | |
1652 struct group_show *g = g_new0(struct group_show, 1); | |
1653 int pos = group_number(group); | |
1654 GdkPixmap *pm; | |
1655 GdkBitmap *bm; | |
1656 GtkStyle *style; | |
1657 GtkStyle *style2; | |
1658 | |
1659 g->name = g_strdup(group); | |
1660 | |
1661 g->item = gtk_tree_item_new(); | |
1662 | |
1663 g_signal_connect(GTK_OBJECT(g->item), "button_press_event", | |
1664 G_CALLBACK(handle_click_group), g); | |
1665 | |
1666 gtk_tree_insert(GTK_TREE(buddies), g->item, pos); | |
1667 | |
1668 gtk_widget_show(g->item); | |
1669 | |
1670 g->label = gtk_label_new(group); | |
1671 gtk_misc_set_alignment(GTK_MISC(g->label), 0.0, 0.5); | |
1672 gtk_widget_show(g->label); | |
1673 | |
1674 gtk_container_add(GTK_CONTAINER(g->item), g->label); | |
1675 | |
1676 shows = g_slist_insert(shows, g, pos); | |
1677 | |
1678 /* Rob does drugs - this is still evil, damn you becausse I SAID SO! */ | |
1679 | |
1680 pm = gdk_pixmap_create_from_xpm_d(g->item->window, | |
1681 &bm, NULL, arrow_down_xpm); | |
1682 | |
1683 gtk_pixmap_set(GTK_PIXMAP(GTK_TREE_ITEM(g->item)->minus_pix_widget), | |
1684 pm, bm); | |
1685 | |
1686 gdk_pixmap_unref(pm); | |
1687 gdk_bitmap_unref(bm); | |
1688 | |
1689 pm = gdk_pixmap_create_from_xpm_d(buddies->window, | |
1690 &bm, NULL, arrow_right_xpm); | |
1691 | |
1692 gtk_pixmap_set(GTK_PIXMAP(GTK_TREE_ITEM(g->item)->plus_pix_widget), | |
1693 pm, bm); | |
1694 | |
1695 gdk_pixmap_unref(pm); | |
1696 gdk_bitmap_unref(bm); | |
1697 | |
1698 // style = gtk_widget_get_style(GTK_TREE_ITEM(g->item)->pixmaps_box); | |
1699 style2 = gtk_style_copy(gtk_widget_get_style(g->item)); | |
1700 style = gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(g->label))); | |
1701 | |
1702 style->bg[0] = style2->base[0]; | |
1703 gtk_widget_set_style(GTK_TREE_ITEM(g->item)->pixmaps_box, style); | |
1704 | |
1705 gtk_style_unref(style); | |
1706 gtk_style_unref(style2); | |
1707 | |
1708 /* bad drugs */ | |
1709 | |
1710 update_num_group(g); | |
1711 | |
1712 return g; | |
1713 } | |
1714 | |
1715 static struct buddy_show *new_buddy_show(struct group_show *gs, struct buddy *buddy, char **xpm) | |
1716 { | |
1717 struct buddy_show *b = g_new0(struct buddy_show, 1); | |
1718 GtkWidget *box; | |
1719 GdkPixmap *pm; | |
1720 GdkBitmap *bm; | |
1721 int pos = buddy_number(gs->name, buddy->name); | |
1722 b->sound = 0; | |
1723 | |
1724 if (gs->members == NULL) { | |
1725 gs->tree = gtk_tree_new(); | |
1726 gtk_tree_item_set_subtree(GTK_TREE_ITEM(gs->item), gs->tree); | |
1727 gtk_tree_item_expand(GTK_TREE_ITEM(gs->item)); | |
1728 gtk_widget_show(gs->tree); | |
1729 } | |
1730 | |
1731 b->name = g_strdup(buddy->name); | |
1732 | |
1733 b->item = gtk_tree_item_new(); | |
1734 gtk_tree_insert(GTK_TREE(gs->tree), b->item, pos); | |
1735 gtk_object_set_user_data(GTK_OBJECT(b->item), b); | |
1736 g_signal_connect(GTK_OBJECT(b->item), "button_press_event", | |
1737 G_CALLBACK(handle_click_buddy), b); | |
1738 gtk_widget_show(b->item); | |
1739 | |
1740 box = gtk_hbox_new(FALSE, 1); | |
1741 gtk_container_add(GTK_CONTAINER(b->item), box); | |
1742 gtk_widget_show(box); | |
1743 | |
1744 pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm ? xpm : no_icon_xpm); | |
1745 b->pix = gtk_pixmap_new(pm, bm); | |
1746 gtk_box_pack_start(GTK_BOX(box), b->pix, FALSE, FALSE, 1); | |
1747 gtk_widget_show(b->pix); | |
1748 if (!(blist_options & OPT_BLIST_SHOW_PIXMAPS)) | |
1749 gtk_widget_hide(b->pix); | |
1750 gdk_pixmap_unref(pm); | |
1751 gdk_bitmap_unref(bm); | |
1752 | |
1753 b->label = gtk_label_new(get_buddy_alias(buddy)); | |
1754 gtk_misc_set_alignment(GTK_MISC(b->label), 0.0, 0.5); | |
1755 gtk_box_pack_start(GTK_BOX(box), b->label, FALSE, FALSE, 1); | |
1756 gtk_widget_show(b->label); | |
1757 | |
1758 b->warn = gtk_label_new(""); | |
1759 gtk_box_pack_start(GTK_BOX(box), b->warn, FALSE, FALSE, 1); | |
1760 gtk_widget_show(b->warn); | |
1761 | |
1762 b->idle = gtk_label_new(""); | |
1763 gtk_box_pack_end(GTK_BOX(box), b->idle, FALSE, FALSE, 1); | |
1764 gtk_widget_show(b->idle); | |
1765 | |
1766 gs->members = g_slist_insert(gs->members, b, pos); | |
1767 update_num_group(gs); | |
1768 return b; | |
1769 } | |
1770 | |
1771 static void remove_buddy_show(struct group_show *gs, struct buddy_show *bs) | |
1772 { | |
1773 /* the name of this function may be misleading, but don't let it fool you. the point | |
1774 * of this is to remove bs->item from gs->tree, and make sure gs->tree still exists | |
1775 * and is a valid tree afterwards. Otherwise, Bad Things will happen. */ | |
1776 gtk_tree_remove_item(GTK_TREE(gs->tree), bs->item); | |
1777 bs->item = NULL; | |
1778 } | |
1779 | |
1780 static struct group_show *find_gs_by_bs(struct buddy_show *b) | |
1781 { | |
1782 GSList *m, *n; | |
1783 struct group_show *g = NULL; | |
1784 struct buddy_show *h; | |
1785 | |
1786 m = shows; | |
1787 while (m) { | |
1788 g = (struct group_show *)m->data; | |
1789 n = g->members; | |
1790 while (n) { | |
1791 h = (struct buddy_show *)n->data; | |
1792 if (h == b) | |
1793 return g; | |
1794 n = n->next; | |
1795 } | |
1796 g = NULL; | |
1797 m = m->next; | |
1798 } | |
1799 | |
1800 return g; | |
1801 } | |
1802 | |
1803 /* used by this file, and by iconaway.so */ | |
1804 void hide_buddy_list() { | |
1805 if (blist) { | |
1806 if (!connections || docklet_count) { | |
1807 #ifdef _WIN32 | |
1808 /* minimize to systray with effects */ | |
1809 wgaim_systray_minimize(blist); | |
1810 #endif | |
1811 gtk_widget_hide(blist); | |
1812 } else { | |
1813 gtk_window_iconify(GTK_WINDOW(blist)); | |
1814 } | |
1815 } | |
1816 } | |
1817 | |
1818 /* mostly used by code in this file */ | |
1819 void unhide_buddy_list() { | |
1820 if (blist) { | |
1821 if (!GTK_WIDGET_VISIBLE(blist) && blist_options & OPT_BLIST_SAVED_WINDOWS && | |
1822 blist_pos.width != 0) { | |
1823 /* don't move it off screen */ | |
1824 if (blist_pos.x >= gdk_screen_width()) { | |
1825 blist_pos.x = gdk_screen_width() - 100; | |
1826 } else if (blist_pos.x < 0) { | |
1827 blist_pos.x = 100; | |
1828 } | |
1829 | |
1830 if (blist_pos.y >= gdk_screen_height()) { | |
1831 blist_pos.y = gdk_screen_height() - 100; | |
1832 } else if (blist_pos.y < 0) { | |
1833 blist_pos.y = 100; | |
1834 } | |
1835 | |
1836 gtk_window_move(GTK_WINDOW(blist), blist_pos.x, blist_pos.y); | |
1837 gtk_window_resize(GTK_WINDOW(blist), blist_pos.width, blist_pos.height); | |
1838 } | |
1839 | |
1840 gtk_window_present(GTK_WINDOW(blist)); | |
1841 } | |
1842 } | |
1843 | |
1844 /* for the delete_event handler */ | |
1845 static void close_buddy_list() { | |
1846 if (docklet_count) { | |
1847 hide_buddy_list(); | |
1848 } else { | |
1849 do_quit(); | |
1850 } | |
1851 } | |
1852 | |
1853 void docklet_add() { | |
1854 docklet_count++; | |
1855 debug_printf("docklet_count: %d\n",docklet_count); | |
1856 } | |
1857 | |
1858 void docklet_remove() { | |
1859 docklet_count--; | |
1860 debug_printf("docklet_count: %d\n",docklet_count); | |
1861 if (!docklet_count) { | |
1862 if (connections) { | |
1863 unhide_buddy_list(); | |
1864 } else { | |
1865 gtk_window_present(GTK_WINDOW(mainwindow)); | |
1866 } | |
1867 } | |
1868 } | |
1869 | |
1870 void docklet_toggle() { | |
1871 /* Useful for the docklet plugin and also for the win32 tray icon*/ | |
1872 /* This is called when one of those is clicked--it will show/hide the | |
1873 buddy list/login window--depending on which is active */ | |
1874 if (connections && blist) { | |
1875 if (GTK_WIDGET_VISIBLE(blist)) { | |
1876 if (GAIM_WINDOW_ICONIFIED(blist) || obscured) { | |
1877 unhide_buddy_list(); | |
1878 } else { | |
1879 hide_buddy_list(); | |
1880 } | |
1881 } else { | |
1882 #if _WIN32 | |
1883 wgaim_systray_maximize(blist); | |
1884 #endif | |
1885 unhide_buddy_list(); | |
1886 } | |
1887 } else if (connections) { | |
1888 /* we're logging in or something... do nothing */ | |
1889 debug_printf("docklet_toggle called with connections but no blist!\n"); | |
1890 } else { | |
1891 if (GTK_WIDGET_VISIBLE(mainwindow)) { | |
1892 if (GAIM_WINDOW_ICONIFIED(mainwindow)) { | |
1893 gtk_window_present(GTK_WINDOW(mainwindow)); | |
1894 } else { | |
1895 #if _WIN32 | |
1896 wgaim_systray_minimize(mainwindow); | |
1897 #endif | |
1898 gtk_widget_hide(mainwindow); | |
1899 } | |
1900 } else { | |
1901 #if _WIN32 | |
1902 wgaim_systray_maximize(mainwindow); | |
1903 #endif | |
1904 gtk_window_present(GTK_WINDOW(mainwindow)); | |
1905 } | |
1906 } | |
1907 } | |
1908 | |
1909 static gboolean log_timeout(gpointer data) | |
1910 { | |
1911 struct buddy_show *b = data; | |
1912 /* this part is really just a bad hack because of a bug I can't find */ | |
1913 GSList *s = shows; | |
1914 while (s) { | |
1915 struct group_show *gs = s->data; | |
1916 GSList *m = gs->members; | |
1917 while (m) { | |
1918 if (b == m->data) | |
1919 break; | |
1920 m = m->next; | |
1921 } | |
1922 if (m != NULL) | |
1923 break; | |
1924 s = s->next; | |
1925 } | |
1926 if (!s) | |
1927 return FALSE; | |
1928 | |
1929 /* this is the real part. */ | |
1930 if (!b->connlist) { | |
1931 struct group_show *g = find_gs_by_bs(b); | |
1932 g->members = g_slist_remove(g->members, b); | |
1933 if (blist) | |
1934 remove_buddy_show(g, b); | |
1935 else | |
1936 debug_printf("log_timeout but buddy list not available\n"); | |
1937 if ((g->members == NULL) && (blist_options & OPT_BLIST_NO_MT_GRP)) { | |
1938 shows = g_slist_remove(shows, g); | |
1939 if (blist) | |
1940 gtk_tree_remove_item(GTK_TREE(buddies), g->item); | |
1941 g_free(g->name); | |
1942 g_free(g); | |
1943 } | |
1944 g_source_remove(b->log_timer); | |
1945 b->log_timer = 0; | |
1946 g_free(b->name); | |
1947 g_free(b); | |
1948 } else { | |
1949 /* um.... what do we have to do here? just update the pixmap? */ | |
1950 GdkPixmap *pm; | |
1951 GdkBitmap *bm; | |
1952 gchar **xpm = NULL; | |
1953 struct gaim_connection *gc = b->connlist->data; | |
1954 struct buddy *light = find_buddy(gc->account, b->name); | |
1955 if (gc->prpl->list_icon) | |
1956 xpm = gc->prpl->list_icon(light->uc); | |
1957 if (xpm == NULL) | |
1958 xpm = (char **)no_icon_xpm; | |
1959 pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm); | |
1960 gtk_widget_hide(b->pix); | |
1961 gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm); | |
1962 gtk_widget_show(b->pix); | |
1963 if (!(blist_options & OPT_BLIST_SHOW_PIXMAPS)) | |
1964 gtk_widget_hide(b->pix); | |
1965 gdk_pixmap_unref(pm); | |
1966 gdk_bitmap_unref(bm); | |
1967 g_source_remove(b->log_timer); | |
1968 b->log_timer = 0; | |
1969 b->sound = 0; | |
1970 } | |
1971 return FALSE; | |
1972 } | |
1973 | |
1974 static char *caps_string(guint caps) | |
1975 { | |
1976 static char buf[256], *tmp; | |
1977 int count = 0, i = 0; | |
1978 guint bit = 1; | |
1979 while (bit <= 0x10000) { | |
1980 if (bit & caps) { | |
1981 switch (bit) { | |
1982 case 0x1: | |
1983 tmp = _("Buddy Icon"); | |
1984 break; | |
1985 case 0x2: | |
1986 tmp = _("Voice"); | |
1987 break; | |
1988 case 0x4: | |
1989 tmp = _("IM Image"); | |
1990 break; | |
1991 case 0x8: | |
1992 tmp = _("Chat"); | |
1993 break; | |
1994 case 0x10: | |
1995 tmp = _("Get File"); | |
1996 break; | |
1997 case 0x20: | |
1998 tmp = _("Send File"); | |
1999 break; | |
2000 case 0x40: | |
2001 case 0x200: | |
2002 tmp = _("Games"); | |
2003 break; | |
2004 case 0x80: | |
2005 tmp = _("Stocks"); | |
2006 break; | |
2007 case 0x100: | |
2008 tmp = _("Send Buddy List"); | |
2009 break; | |
2010 case 0x400: | |
2011 tmp = _("EveryBuddy Bug"); | |
2012 break; | |
2013 case 0x800: | |
2014 tmp = _("AP User"); | |
2015 break; | |
2016 case 0x1000: | |
2017 tmp = _("ICQ RTF"); | |
2018 break; | |
2019 case 0x2000: | |
2020 tmp = _("Nihilist"); | |
2021 break; | |
2022 case 0x4000: | |
2023 tmp = _("ICQ Server Relay"); | |
2024 break; | |
2025 case 0x8000: | |
2026 tmp = _("ICQ Unknown"); | |
2027 break; | |
2028 case 0x10000: | |
2029 tmp = _("Trillian Encryption"); | |
2030 break; | |
2031 default: | |
2032 tmp = NULL; | |
2033 break; | |
2034 } | |
2035 if (tmp) | |
2036 i += g_snprintf(buf + i, sizeof(buf) - i, "%s%s", (count ? ", " : ""), | |
2037 tmp); | |
2038 count++; | |
2039 } | |
2040 bit <<= 1; | |
2041 } | |
2042 return buf; | |
2043 } | |
2044 | |
2045 /* for this we're just going to assume the first connection that registered the buddy. | |
2046 * if it's not the one you were hoping for then you're shit out of luck */ | |
2047 static void update_idle_time(struct buddy_show *bs) | |
2048 { | |
2049 /* this also updates the tooltip since that has idle time in it */ | |
2050 char idlet[16], warnl[16]; | |
2051 time_t t; | |
2052 int ihrs, imin; | |
2053 struct buddy *b; | |
2054 GtkStyle *style; | |
2055 | |
2056 char infotip[2048]; | |
2057 char warn[256]; | |
2058 char caps[256]; | |
2059 char alias[512]; | |
2060 char serv_alias[512]; | |
2061 char *sotime = NULL, *itime; | |
2062 | |
2063 struct gaim_connection *gc; | |
2064 | |
2065 int i; | |
2066 | 412 |
2067 time(&t); | 413 time(&t); |
2068 if (!bs->connlist) | |
2069 return; | |
2070 gc = bs->connlist->data; | |
2071 b = find_buddy(gc->account, bs->name); | |
2072 if (!b) | |
2073 return; | |
2074 ihrs = (t - b->idle) / 3600; | 414 ihrs = (t - b->idle) / 3600; |
2075 imin = ((t - b->idle) / 60) % 60; | 415 imin = ((t - b->idle) / 60) % 60; |
2076 | 416 |
2077 if (ihrs) | 417 if (b->idle) { |
2078 g_snprintf(idlet, sizeof idlet, "(%d:%02d)", ihrs, imin); | 418 if (ihrs) |
419 idletime = g_strdup_printf(_("Idle (%dh%02dm)"), ihrs, imin); | |
420 else | |
421 idletime = g_strdup_printf(_("Idle (%dm)"), imin); | |
422 } | |
423 | |
424 if (b->evil > 0) | |
425 warning = g_strdup_printf(_("Warned (%d%%)"), b->evil); | |
426 | |
427 if (b->idle) | |
428 text = g_strdup_printf("<span color='grey'>%s</span>\n<span color='gray' size='smaller'>%s %s</span>", | |
429 esc, | |
430 idletime, warning); | |
2079 else | 431 else |
2080 g_snprintf(idlet, sizeof idlet, "(%d)", imin); | 432 text = g_strdup_printf("%s\n<span color='gray' size='smaller'>%s</span>", esc, warning); |
2081 | 433 |
2082 gtk_widget_hide(bs->idle); | 434 if (idletime[0]) |
2083 if (b->idle) | 435 g_free(idletime); |
2084 gtk_label_set(GTK_LABEL(bs->idle), idlet); | 436 if (warning[0]) |
437 g_free(warning); | |
438 | |
439 return text; | |
440 } | |
441 | |
442 /********************************************************************************** | |
443 * Public API Functions * | |
444 **********************************************************************************/ | |
445 static void gaim_gtk_blist_show(struct gaim_buddy_list *list) | |
446 { | |
447 GtkItemFactory *ift; | |
448 GtkCellRenderer *rend; | |
449 GtkTreeViewColumn *column; | |
450 GtkWidget *sw; | |
451 GtkWidget *button; | |
452 GValue *val; | |
453 GtkTreeIter iter; | |
454 | |
455 if (gtkblist) { | |
456 gtk_widget_show(gtkblist->window); | |
457 return; | |
458 } | |
459 | |
460 gtkblist = g_new0(struct gaim_gtk_buddy_list , 1); | |
461 gtkblist->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
462 gtk_window_set_title(GTK_WINDOW(gtkblist->window), _("Buddy List")); | |
463 | |
464 gtkblist->vbox = gtk_vbox_new(FALSE, 6); | |
465 gtk_container_add(GTK_CONTAINER(gtkblist->window), gtkblist->vbox); | |
466 | |
467 /******************************* Menu bar *************************************/ | |
468 ift = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<GaimMain>", NULL); | |
469 gtk_item_factory_create_items(ift, sizeof(blist_menu) / sizeof(*blist_menu), | |
470 blist_menu, NULL); | |
471 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtk_item_factory_get_widget(ift, "<GaimMain>"), FALSE, FALSE, 0); | |
472 | |
473 /****************************** GtkTreeView **********************************/ | |
474 sw = gtk_scrolled_window_new(NULL,NULL); | |
475 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); | |
476 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
477 gtk_widget_set_usize(sw, 200, 200); | |
478 | |
479 gtkblist->treemodel = gtk_tree_store_new(BLIST_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, | |
480 G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER); | |
481 /* This is broken because GTK is broken | |
482 g_signal_connect(G_OBJECT(gtkblist->treemodel), "row-reordered", gaim_gtk_blist_reordered_cb, NULL); */ | |
483 | |
484 gtkblist->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtkblist->treemodel)); | |
485 | |
486 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE); | |
487 | |
488 rend = gtk_cell_renderer_pixbuf_new(); | |
489 column = gtk_tree_view_column_new_with_attributes("Status", rend, "pixbuf", STATUS_ICON_COLUMN, NULL); | |
490 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
491 | |
492 rend = gtk_cell_renderer_text_new(); | |
493 column = gtk_tree_view_column_new_with_attributes("Name", rend, "markup", NAME_COLUMN, NULL); | |
494 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
495 | |
496 rend = gtk_cell_renderer_text_new(); | |
497 column = gtk_tree_view_column_new_with_attributes("Warning", rend, "text", WARNING_COLUMN, NULL); | |
498 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
499 | |
500 rend = gtk_cell_renderer_text_new(); | |
501 column = gtk_tree_view_column_new_with_attributes("Idle", rend, "text", IDLE_COLUMN, NULL); | |
502 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
503 | |
504 rend = gtk_cell_renderer_pixbuf_new(); | |
505 column = gtk_tree_view_column_new_with_attributes("Buddy Icon", rend, "pixbuf", BUDDY_ICON_COLUMN, NULL); | |
506 g_object_set(rend, "xalign", 1.0, NULL); | |
507 gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column); | |
508 | |
509 g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL); | |
510 g_signal_connect(G_OBJECT(gtkblist->treeview), "button-press-event", G_CALLBACK(gtk_blist_button_press_cb), NULL); | |
511 | |
512 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sw, TRUE, TRUE, 0); | |
513 gtk_container_add(GTK_CONTAINER(sw), gtkblist->treeview); | |
514 | |
515 /**************************** Button Box **************************************/ | |
516 gtkblist->bbox = gtk_hbox_new(TRUE, 0); | |
517 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->bbox, FALSE, FALSE, 0); | |
518 button = gaim_pixbuf_button_from_stock(_("IM"), GAIM_STOCK_IM, GAIM_BUTTON_VERTICAL); | |
519 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
520 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
521 button = gaim_pixbuf_button_from_stock(_("Get Info"), GAIM_STOCK_INFO, GAIM_BUTTON_VERTICAL); | |
522 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
523 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
524 button = gaim_pixbuf_button_from_stock(_("Chat"), GAIM_STOCK_CHAT, GAIM_BUTTON_VERTICAL); | |
525 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
526 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
527 button = gaim_pixbuf_button_from_stock(_("Away"), GAIM_STOCK_AWAY, GAIM_BUTTON_VERTICAL); | |
528 gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0); | |
529 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
530 | |
531 /* OK... let's show this bad boy. */ | |
532 gaim_gtk_blist_refresh(list); | |
533 gtk_widget_show_all(gtkblist->window); | |
534 } | |
535 | |
536 void gaim_gtk_blist_refresh(struct gaim_buddy_list *list) | |
537 { | |
538 GaimBlistNode *group = list->root; | |
539 GaimBlistNode *buddy; | |
540 | |
541 while (group) { | |
542 gaim_gtk_blist_update(list, group); | |
543 buddy = group->child; | |
544 while (buddy) { | |
545 gaim_gtk_blist_update(list, buddy); | |
546 buddy = buddy->next; | |
547 } | |
548 group = group->next; | |
549 } | |
550 } | |
551 | |
552 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node) | |
553 { | |
554 GtkTreeIter *iter = node->ui_data; | |
555 GtkTreePath *path; | |
556 GdkPixbuf *buf = NULL; | |
557 gboolean expand = FALSE; | |
558 | |
559 if (!gtkblist) | |
560 return; | |
561 | |
562 if (!iter) { /* This is a newly added node */ | |
563 if (GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
564 if (((struct buddy*)node)->present) { | |
565 if(node->parent && node->parent && !node->parent->ui_data) { | |
566 | |
567 /* This buddy's group has not yet been added. We do that here */ | |
568 | |
569 char *mark = g_strdup_printf("<span weight='bold'>%s</span>", ((struct group*)node->parent)->name); | |
570 GtkTreeIter *iter2 = g_new0(GtkTreeIter, 1); | |
571 GaimBlistNode *insertat = node->parent->prev; | |
572 GtkTreeIter *insertatiter = NULL; | |
573 | |
574 /* We traverse backwards through the buddy list to find the node in the tree to insert it after */ | |
575 while (insertat && !insertat->ui_data) | |
576 insertat = insertat->prev; | |
577 if (insertat) | |
578 insertatiter = insertat->ui_data; | |
579 | |
580 /* This is where we create the node and add it. */ | |
581 gtk_tree_store_insert_after(gtkblist->treemodel, iter2, | |
582 node->parent->parent ? node->parent->parent->ui_data : NULL, insertatiter); | |
583 gtk_tree_store_set(gtkblist->treemodel, iter2, | |
584 STATUS_ICON_COLUMN, gtk_widget_render_icon | |
585 (gtkblist->treeview,GTK_STOCK_OPEN,GTK_ICON_SIZE_LARGE_TOOLBAR,NULL), | |
586 NAME_COLUMN, mark, | |
587 NODE_COLUMN, node->parent, | |
588 -1); | |
589 node->parent->ui_data = iter2; | |
590 expand = TRUE; | |
591 } | |
592 iter = g_new0(GtkTreeIter, 1); | |
593 node->ui_data = iter; | |
594 | |
595 gtk_tree_store_insert_after (gtkblist->treemodel, iter, node->parent ? node->parent->ui_data : NULL, | |
596 node->prev ? node->prev->ui_data : NULL); | |
597 | |
598 | |
599 if (expand) { /* expand was set to true if this is the first element added to a group. In such case | |
600 * we expand the group node */ | |
601 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), node->parent->ui_data); | |
602 gtk_tree_view_expand_row(GTK_TREE_VIEW(gtkblist->treeview), path, TRUE); | |
603 } | |
604 node->ui_data = iter; | |
605 } | |
606 } | |
607 } | |
608 | |
609 if (GAIM_BLIST_NODE_IS_BUDDY(node) && ((struct buddy*)node)->present) { | |
610 GdkPixbuf *status, *avatar; | |
611 char *mark; | |
612 | |
613 status = gaim_gtk_blist_get_status_icon((struct buddy*)node); | |
614 avatar = gaim_gtk_blist_get_buddy_icon((struct buddy*)node); | |
615 mark = gaim_gtk_blist_get_name_markup((struct buddy*)node); | |
616 | |
617 gtk_tree_store_set(gtkblist->treemodel, iter, | |
618 STATUS_ICON_COLUMN, status, | |
619 NAME_COLUMN, mark, | |
620 WARNING_COLUMN, "", | |
621 IDLE_COLUMN, "", | |
622 BUDDY_ICON_COLUMN, avatar, | |
623 NODE_COLUMN, node, | |
624 -1); | |
625 | |
626 g_free(mark); | |
627 g_object_unref(status); | |
628 if (avatar) { | |
629 g_object_unref(avatar); | |
630 } | |
631 } else if (GAIM_BLIST_NODE_IS_BUDDY(node) && node->ui_data){ | |
632 gtk_tree_store_remove(GTK_TREE_STORE(gtkblist->treemodel), (GtkTreeIter*)(node->ui_data)); | |
633 g_free(node->ui_data); | |
634 node->ui_data = NULL; | |
635 } | |
636 | |
637 } | |
638 | |
639 static void gaim_gtk_blist_remove(struct gaim_buddy_list *list, GaimBlistNode *node) | |
640 { | |
641 if (!node->ui_data) | |
642 return; | |
643 gtk_tree_store_remove(gtkblist->treemodel, (GtkTreeIter*)(node->ui_data)); | |
644 } | |
645 | |
646 static void gaim_gtk_blist_destroy(struct gaim_buddy_list *list) | |
647 { | |
648 gtk_widget_destroy(gtkblist->window); | |
649 } | |
650 | |
651 static void gaim_gtk_blist_set_visible(struct gaim_buddy_list *list, gboolean show) | |
652 { | |
653 if (show) | |
654 gtk_widget_show(gtkblist->window); | |
2085 else | 655 else |
2086 gtk_label_set(GTK_LABEL(bs->idle), ""); | 656 gtk_widget_hide(gtkblist->window); |
2087 if (blist_options & OPT_BLIST_SHOW_IDLETIME) | 657 } |
2088 gtk_widget_show(bs->idle); | 658 |
2089 | 659 static struct gaim_blist_ui_ops blist_ui_ops = |
2090 style = gtk_style_new(); | 660 { |
2091 gtk_style_set_font(style, gdk_font_ref(gtk_style_get_font(bs->label->style))); | 661 gaim_gtk_blist_show, |
2092 for (i = 0; i < 5; i++) | 662 gaim_gtk_blist_update, |
2093 style->fg[i] = bs->idle->style->fg[i]; | 663 gaim_gtk_blist_remove, |
2094 if ((blist_options & OPT_BLIST_GREY_IDLERS) && (b->idle)) { | 664 gaim_gtk_blist_destroy, |
2095 style->fg[GTK_STATE_NORMAL].red = | 665 gaim_gtk_blist_set_visible |
2096 (style->fg[GTK_STATE_NORMAL].red / 2) + (style->base[GTK_STATE_NORMAL].red / 2); | 666 }; |
2097 style->fg[GTK_STATE_NORMAL].green = | 667 |
2098 (style->fg[GTK_STATE_NORMAL].green / 2) + (style->base[GTK_STATE_NORMAL].green / 2); | 668 |
2099 style->fg[GTK_STATE_NORMAL].blue = | 669 struct gaim_blist_ui_ops *gaim_get_gtk_blist_ui_ops() |
2100 (style->fg[GTK_STATE_NORMAL].blue / 2) + (style->base[GTK_STATE_NORMAL].blue / 2); | 670 { |
2101 } | 671 return &blist_ui_ops; |
2102 gtk_widget_set_style(bs->label, style); | 672 } |
2103 gtk_style_unref(style); | 673 |
2104 | 674 |
2105 /* now we do the tooltip */ | 675 |
2106 if (b->signon) { | 676 /********************************************************************* |
2107 char *stime = sec_to_text(t - b->signon + | 677 * Public utility functions * |
2108 ((struct gaim_connection *)bs->connlist->data)-> | 678 *********************************************************************/ |
2109 correction_time); | 679 |
2110 sotime = g_strdup_printf(_("Logged in: %s\n"), stime); | 680 GdkPixbuf * |
2111 g_free(stime); | 681 create_prpl_icon(struct gaim_account *account) |
2112 } | 682 { |
2113 | 683 struct prpl *prpl = find_prpl(account->protocol); |
2114 if (b->idle) | 684 GdkPixbuf *status = NULL; |
2115 itime = sec_to_text(t - b->idle); | 685 char *filename = NULL; |
2116 else { | 686 const char *protoname = prpl->list_icon(account, NULL); |
2117 itime = g_malloc(1); | 687 /* "Hey, what's all this crap?" you ask. Status icons will be themeable too, and |
2118 itime[0] = 0; | 688 then it will look up protoname from the theme */ |
2119 } | 689 if (!strcmp(protoname, "aim")) { |
2120 | 690 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "aim.png", NULL); |
2121 if (b->evil) { | 691 status = gdk_pixbuf_new_from_file(filename,NULL); |
2122 g_snprintf(warn, sizeof warn, _("Warnings: %d%%\n"), b->evil); | 692 g_free(filename); |
2123 g_snprintf(warnl, sizeof warnl, "(%d%%)", b->evil); | 693 } else if (!strcmp(protoname, "yahoo")) { |
2124 } else { | 694 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "yahoo.png", NULL); |
2125 warn[0] = '\0'; | 695 status = gdk_pixbuf_new_from_file(filename,NULL); |
2126 warnl[0] = '\0'; | 696 g_free(filename); |
2127 } | 697 } else if (!strcmp(protoname, "msn")) { |
2128 gtk_widget_hide(bs->warn); | 698 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "msn.png", NULL); |
2129 gtk_label_set(GTK_LABEL(bs->warn), warnl); | 699 status = gdk_pixbuf_new_from_file(filename,NULL); |
2130 if (blist_options & OPT_BLIST_SHOW_WARN) | 700 g_free(filename); |
2131 gtk_widget_show(bs->warn); | 701 } else if (!strcmp(protoname, "jabber")) { |
2132 | 702 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "jabber.png", NULL); |
2133 if (b->caps) | 703 status = gdk_pixbuf_new_from_file(filename,NULL); |
2134 g_snprintf(caps, sizeof caps, _("Capabilities: %s\n"), caps_string(b->caps)); | 704 g_free(filename); |
2135 else | 705 } else if (!strcmp(protoname, "icq")) { |
2136 caps[0] = '\0'; | 706 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "icq.png", NULL); |
2137 | 707 status = gdk_pixbuf_new_from_file(filename,NULL); |
2138 if (b->alias[0]) | 708 g_free(filename); |
2139 g_snprintf(alias, sizeof alias, _("Alias: %s\n"), b->alias); | 709 } else if (!strcmp(protoname, "gadu-gadu")) { |
2140 else | 710 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "gadugadu.png", NULL); |
2141 alias[0] = '\0'; | 711 status = gdk_pixbuf_new_from_file(filename,NULL); |
2142 | 712 g_free(filename); |
2143 if (b->server_alias[0]) | 713 } else if (!strcmp(protoname, "napster")) { |
2144 g_snprintf(serv_alias, sizeof serv_alias, _("Nickname: %s\n"), | 714 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "napster.png", NULL); |
2145 b->server_alias); | 715 status = gdk_pixbuf_new_from_file(filename,NULL); |
2146 else | 716 g_free(filename); |
2147 serv_alias[0] = '\0'; | 717 } else if (!strcmp(protoname, "irc")) { |
2148 | 718 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "irc.png", NULL); |
2149 g_snprintf(infotip, sizeof infotip, _("%s%sScreen Name: %s\n%s%s%s%s%s%s"), | 719 status = gdk_pixbuf_new_from_file(filename,NULL); |
2150 alias, serv_alias, b->name, (b->signon ? sotime : ""), warn, | 720 g_free(filename); |
2151 (b->idle ? _("Idle: ") : ""), itime, (b->idle ? "\n" : ""), caps); | 721 } |
2152 | 722 return status; |
2153 gtk_tooltips_set_tip(tips, GTK_WIDGET(bs->item), infotip, ""); | 723 } |
2154 | |
2155 if (b->signon) | |
2156 g_free(sotime); | |
2157 g_free(itime); | |
2158 } | |
2159 | |
2160 void update_idle_times() | |
2161 { | |
2162 GSList *grp = shows; | |
2163 GSList *mem; | |
2164 struct buddy_show *b; | |
2165 struct group_show *g; | |
2166 | |
2167 while (grp) { | |
2168 g = (struct group_show *)grp->data; | |
2169 mem = g->members; | |
2170 while (mem) { | |
2171 b = (struct buddy_show *)mem->data; | |
2172 update_idle_time(b); | |
2173 mem = mem->next; | |
2174 } | |
2175 grp = grp->next; | |
2176 } | |
2177 } | |
2178 | |
2179 void set_buddy(struct gaim_connection *gc, struct buddy *b) | |
2180 { | |
2181 struct group *g = find_group_by_buddy(b); | |
2182 struct group_show *gs; | |
2183 struct buddy_show *bs; | |
2184 GdkPixmap *pm; | |
2185 GdkBitmap *bm; | |
2186 char **xpm = NULL; | |
2187 | |
2188 if (!blist) | |
2189 return; | |
2190 | |
2191 if (b->present) { | |
2192 if ((gs = find_group_show(g->name)) == NULL) | |
2193 gs = new_group_show(g->name); | |
2194 if ((bs = find_buddy_show(gs, b->name)) == NULL) | |
2195 bs = new_buddy_show(gs, b, (char **)login_icon_xpm); | |
2196 if (!g_slist_find(bs->connlist, gc)) { | |
2197 bs->connlist = g_slist_append(bs->connlist, gc); | |
2198 update_num_group(gs); | |
2199 } | |
2200 if (b->present == 1) { | |
2201 if (bs->sound != 2) | |
2202 gaim_sound_play_event(GAIM_SOUND_BUDDY_ARRIVE); | |
2203 if (blist_options & OPT_BLIST_POPUP) | |
2204 gdk_window_show(blist->window); | |
2205 pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, | |
2206 NULL, (char **)login_icon_xpm); | |
2207 gtk_widget_hide(bs->pix); | |
2208 gtk_pixmap_set(GTK_PIXMAP(bs->pix), pm, bm); | |
2209 gtk_widget_show(bs->pix); | |
2210 gdk_pixmap_unref(pm); | |
2211 gdk_bitmap_unref(bm); | |
2212 b->present = 2; | |
2213 if (bs->log_timer > 0) | |
2214 g_source_remove(bs->log_timer); | |
2215 bs->log_timer = g_timeout_add(10000, log_timeout, bs); | |
2216 if ((bs->sound != 2) && (im_options & OPT_IM_LOGON)) { | |
2217 struct gaim_conversation *c = gaim_find_conversation(b->name); | |
2218 if (c) { | |
2219 char tmp[1024]; | |
2220 g_snprintf(tmp, sizeof(tmp), _("%s logged in."), | |
2221 get_buddy_alias(b)); | |
2222 gaim_conversation_write(c, NULL, tmp, -1, | |
2223 WFLAG_SYSTEM, time(NULL)); | |
2224 } else if (awayqueue && find_queue_total_by_name(b->name)) { | |
2225 struct queued_message *qm = g_new0(struct queued_message, 1); | |
2226 g_snprintf(qm->name, sizeof(qm->name), "%s", b->name); | |
2227 qm->message = g_strdup_printf(_("%s logged in."), | |
2228 get_buddy_alias(b)); | |
2229 qm->account = gc->account; | |
2230 qm->tm = time(NULL); | |
2231 qm->flags = WFLAG_SYSTEM; | |
2232 qm->len = -1; | |
2233 message_queue = g_slist_append(message_queue, qm); | |
2234 } | |
2235 } | |
2236 bs->sound = 2; | |
2237 } else if (bs->log_timer == 0) { | |
2238 if (gc->prpl->list_icon) | |
2239 xpm = gc->prpl->list_icon(b->uc); | |
2240 if (xpm == NULL) | |
2241 xpm = (char **)no_icon_xpm; | |
2242 pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm); | |
2243 gtk_widget_hide(bs->pix); | |
2244 gtk_pixmap_set(GTK_PIXMAP(bs->pix), pm, bm); | |
2245 gtk_widget_show(bs->pix); | |
2246 if (!(blist_options & OPT_BLIST_SHOW_PIXMAPS)) | |
2247 gtk_widget_hide(bs->pix); | |
2248 gdk_pixmap_unref(pm); | |
2249 gdk_bitmap_unref(bm); | |
2250 } | |
2251 update_idle_time(bs); | |
2252 } else { | |
2253 gs = find_group_show(g->name); | |
2254 if (!gs) | |
2255 return; | |
2256 bs = find_buddy_show(gs, b->name); | |
2257 if (!bs) | |
2258 return; | |
2259 if (!bs->connlist) | |
2260 return; /* we won't do signoff updates for | |
2261 buddies that have already signed | |
2262 off */ | |
2263 if (bs->sound != 1) | |
2264 gaim_sound_play_event(GAIM_SOUND_BUDDY_LEAVE); | |
2265 if (blist_options & OPT_BLIST_POPUP) | |
2266 gdk_window_show(blist->window); | |
2267 bs->connlist = g_slist_remove(bs->connlist, gc); | |
2268 update_num_group(gs); | |
2269 if (bs->log_timer > 0) | |
2270 g_source_remove(bs->log_timer); | |
2271 bs->log_timer = g_timeout_add(10000, log_timeout, bs); | |
2272 pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, logout_icon_xpm); | |
2273 gtk_widget_hide(bs->pix); | |
2274 gtk_pixmap_set(GTK_PIXMAP(bs->pix), pm, bm); | |
2275 gtk_widget_show(bs->pix); | |
2276 gdk_pixmap_unref(pm); | |
2277 gdk_bitmap_unref(bm); | |
2278 if ((bs->sound != 1) && (im_options & OPT_IM_LOGON)) { | |
2279 struct gaim_conversation *c = gaim_find_conversation(b->name); | |
2280 if (c) { | |
2281 char tmp[1024]; | |
2282 g_snprintf(tmp, sizeof(tmp), _("%s logged out."), | |
2283 get_buddy_alias(b)); | |
2284 gaim_conversation_write(c, NULL, tmp, -1, | |
2285 WFLAG_SYSTEM, time(NULL)); | |
2286 } else if (awayqueue && find_queue_total_by_name(b->name)) { | |
2287 struct queued_message *qm = g_new0(struct queued_message, 1); | |
2288 g_snprintf(qm->name, sizeof(qm->name), "%s", | |
2289 get_buddy_alias(b)); | |
2290 qm->message = g_strdup_printf(_("%s logged out."), | |
2291 get_buddy_alias(b)); | |
2292 qm->account = gc->account; | |
2293 qm->tm = time(NULL); | |
2294 qm->flags = WFLAG_SYSTEM; | |
2295 qm->len = -1; | |
2296 message_queue = g_slist_append(message_queue, qm); | |
2297 } | |
2298 } | |
2299 | |
2300 bs->sound = 1; | |
2301 } | |
2302 } | |
2303 | |
2304 static gboolean delayed_save_prefs(gpointer data) { | |
2305 save_prefs(); | |
2306 return FALSE; | |
2307 } | |
2308 | |
2309 static gboolean configure_blist_window(GtkWidget *w, GdkEventConfigure *event, gpointer data) { | |
2310 /* unfortunately GdkEventConfigure ignores the window gravity, but * | |
2311 * the only way we have of setting the position doesn't. we have to * | |
2312 * call get_position and get_size because they do pay attention to * | |
2313 * the gravity. this is inefficient and I agree it sucks, but it's * | |
2314 * more likely to work correctly. - Robot101 */ | |
2315 gint x, y; | |
2316 | |
2317 /* check for visibility because when we aren't visible, this will * | |
2318 * give us bogus (0,0) coordinates. - xOr */ | |
2319 if (GTK_WIDGET_VISIBLE(blist)) { | |
2320 gtk_window_get_position(GTK_WINDOW(blist), &x, &y); | |
2321 | |
2322 if (x != blist_pos.x || | |
2323 y != blist_pos.y || | |
2324 event->width != blist_pos.width || | |
2325 event->height != blist_pos.height) { | |
2326 blist_pos.x = x; | |
2327 blist_pos.y = y; | |
2328 blist_pos.width = event->width; | |
2329 blist_pos.height = event->height; | |
2330 | |
2331 if (!g_main_context_find_source_by_user_data(NULL, &delayed_save_prefs)) { | |
2332 debug_printf("queueing save of blist prefs\n"); | |
2333 g_timeout_add(5000, delayed_save_prefs, &delayed_save_prefs); | |
2334 } | |
2335 } | |
2336 } | |
2337 | |
2338 return FALSE; | |
2339 } | |
2340 | |
2341 static void visibility_blist_window(GtkWidget *w, GdkEventVisibility *event, void *data) { | |
2342 if (event->state == GDK_VISIBILITY_FULLY_OBSCURED) { | |
2343 obscured = TRUE; | |
2344 } else { | |
2345 obscured = FALSE; | |
2346 } | |
2347 } | |
2348 | |
2349 /******************************************************************* | |
2350 * | |
2351 * Helper funs for making the menu | |
2352 * | |
2353 *******************************************************************/ | |
2354 | |
2355 void gaim_separator(GtkWidget *menu) | |
2356 { | |
2357 GtkWidget *menuitem; | |
2358 | |
2359 menuitem = gtk_separator_menu_item_new(); | |
2360 gtk_widget_show(menuitem); | |
2361 gtk_menu_append(GTK_MENU(menu), menuitem); | |
2362 } | |
2363 | |
2364 | |
2365 void build_imchat_box(gboolean on) | |
2366 { | |
2367 if (on) { | |
2368 if (imchatbox) | |
2369 return; | |
2370 | |
2371 imbutton = gtk_button_new_with_label(_("IM")); | |
2372 infobutton = gtk_button_new_with_label(_("Info")); | |
2373 chatbutton = gtk_button_new_with_label(_("Chat")); | |
2374 awaybutton = gtk_button_new_with_label(_("Away")); | |
2375 | |
2376 imchatbox = gtk_hbox_new(TRUE, 10); | |
2377 | |
2378 gtk_button_set_relief(GTK_BUTTON(imbutton), GTK_RELIEF_NONE); | |
2379 gtk_button_set_relief(GTK_BUTTON(infobutton), GTK_RELIEF_NONE); | |
2380 gtk_button_set_relief(GTK_BUTTON(chatbutton), GTK_RELIEF_NONE); | |
2381 gtk_button_set_relief(GTK_BUTTON(awaybutton), GTK_RELIEF_NONE); | |
2382 | |
2383 /* Put the buttons in the hbox */ | |
2384 gtk_widget_show(imbutton); | |
2385 gtk_widget_show(infobutton); | |
2386 gtk_widget_show(chatbutton); | |
2387 gtk_widget_show(awaybutton); | |
2388 | |
2389 gtk_box_pack_start(GTK_BOX(imchatbox), imbutton, TRUE, TRUE, 0); | |
2390 gtk_box_pack_start(GTK_BOX(imchatbox), infobutton, TRUE, TRUE, 0); | |
2391 gtk_box_pack_start(GTK_BOX(imchatbox), chatbutton, TRUE, TRUE, 0); | |
2392 gtk_box_pack_start(GTK_BOX(imchatbox), awaybutton, TRUE, TRUE, 0); | |
2393 gtk_container_border_width(GTK_CONTAINER(imchatbox), 5); | |
2394 | |
2395 g_signal_connect(GTK_OBJECT(imbutton), "clicked", G_CALLBACK(im_callback), | |
2396 buddies); | |
2397 g_signal_connect(GTK_OBJECT(infobutton), "clicked", G_CALLBACK(info_callback), | |
2398 buddies); | |
2399 g_signal_connect(GTK_OBJECT(chatbutton), "clicked", G_CALLBACK(chat_callback), | |
2400 buddies); | |
2401 g_signal_connect(GTK_OBJECT(awaybutton), "clicked", G_CALLBACK(away_callback), | |
2402 buddies); | |
2403 | |
2404 gtk_tooltips_set_tip(tips, infobutton, _("Information on selected Buddy"), "Penguin"); | |
2405 gtk_tooltips_set_tip(tips, imbutton, _("Send Instant Message"), "Penguin"); | |
2406 gtk_tooltips_set_tip(tips, chatbutton, _("Start/join a Buddy Chat"), "Penguin"); | |
2407 gtk_tooltips_set_tip(tips, awaybutton, _("Activate Away Message"), "Penguin"); | |
2408 | |
2409 gtk_box_pack_start(GTK_BOX(buddypane), imchatbox, FALSE, FALSE, 0); | |
2410 | |
2411 gtk_widget_show(imchatbox); | |
2412 } else { | |
2413 if (imchatbox) | |
2414 gtk_widget_destroy(imchatbox); | |
2415 imchatbox = NULL; | |
2416 } | |
2417 } | |
2418 | |
2419 extern GtkWidget *debugbutton; | |
2420 void clicked_debug (GtkWidget *widg, gpointer pntr) | |
2421 { | |
2422 if (debugbutton) | |
2423 gtk_button_clicked(GTK_BUTTON(debugbutton)); | |
2424 else { | |
2425 misc_options ^= OPT_MISC_DEBUG; | |
2426 show_debug(); | |
2427 } | |
2428 } | |
2429 | |
2430 void | |
2431 show_xfer_dialog(GtkMenuItem *item, gpointer user_data) | |
2432 { | |
2433 struct gaim_gtkxfer_dialog *dialog; | |
2434 | |
2435 dialog = gaim_get_gtkxfer_dialog(); | |
2436 | |
2437 if (dialog == NULL) { | |
2438 dialog = gaim_gtkxfer_dialog_new(); | |
2439 | |
2440 gaim_set_gtkxfer_dialog(dialog); | |
2441 } | |
2442 | |
2443 gaim_gtkxfer_dialog_show(dialog); | |
2444 } | |
2445 | |
2446 void make_buddy_list() | |
2447 { | |
2448 | |
2449 /* Build the buddy list, based on *config */ | |
2450 | |
2451 GtkWidget *sw; | |
2452 GtkWidget *menu; | |
2453 #ifdef NO_MULTI | |
2454 GtkWidget *setmenu; | |
2455 GtkWidget *findmenu; | |
2456 #endif | |
2457 GtkWidget *menubar; | |
2458 GtkWidget *vbox; | |
2459 GtkWidget *menuitem; | |
2460 GtkWidget *notebook; | |
2461 GtkWidget *label; | |
2462 GtkWidget *bbox; | |
2463 GtkWidget *tbox; | |
2464 | |
2465 if (blist) { | |
2466 return; | |
2467 } | |
2468 | |
2469 blist = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
2470 | |
2471 gtk_window_set_gravity(GTK_WINDOW(blist), GDK_GRAVITY_NORTH_WEST); | |
2472 gtk_window_set_policy(GTK_WINDOW(blist), TRUE, TRUE, TRUE); | |
2473 gtk_window_set_title(GTK_WINDOW(blist), _("Gaim - Buddy List")); | |
2474 gtk_window_set_role(GTK_WINDOW(blist), "buddy_list"); | |
2475 | |
2476 gtk_widget_realize(blist); | |
2477 | |
2478 accel = gtk_accel_group_new(); | |
2479 gtk_window_add_accel_group(GTK_WINDOW(blist), accel); | |
2480 | |
2481 menubar = gtk_menu_bar_new(); | |
2482 | |
2483 menu = gtk_menu_new(); | |
2484 gtk_menu_set_accel_group(GTK_MENU(menu), accel); | |
2485 | |
2486 menuitem = gaim_new_item(NULL, _("File")); | |
2487 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); | |
2488 gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuitem); | |
2489 | |
2490 gaim_new_item_from_stock(menu, _("_Add A Buddy"), GTK_STOCK_ADD, | |
2491 G_CALLBACK(add_buddy_callback), NULL, 'b', GDK_CONTROL_MASK, "Ctl+B"); | |
2492 gaim_new_item_from_stock(menu, _("_Join A Chat"), GTK_STOCK_JUMP_TO, | |
2493 G_CALLBACK(chat_callback), NULL, 'c', GDK_CONTROL_MASK, "Ctl+C"); | |
2494 gaim_new_item_from_stock(menu, _("_New Message"), GTK_STOCK_CONVERT, | |
2495 G_CALLBACK(show_im_dialog), NULL, 'i', GDK_CONTROL_MASK, "Ctl+I"); | |
2496 gaim_new_item_from_stock(menu, _("_Get User Info"), GTK_STOCK_FIND, | |
2497 G_CALLBACK(show_info_dialog), NULL, 'j', GDK_CONTROL_MASK, "Ctl+J"); | |
2498 | |
2499 gaim_separator(menu); | |
2500 | |
2501 gaim_new_item_from_pixbuf(menu, _("Import Buddy List"), "import-menu.png", | |
2502 G_CALLBACK(import_callback), NULL, 0, 0, 0); | |
2503 | |
2504 gaim_separator(menu); | |
2505 | |
2506 gaim_new_item_from_stock(menu, _("Signoff"), NULL, | |
2507 G_CALLBACK(signoff_all), (void*)1, 'd', GDK_CONTROL_MASK, "Ctl+D"); | |
2508 gaim_new_item_from_stock(menu, _("Hide"), NULL, | |
2509 G_CALLBACK(hide_buddy_list), NULL, 'h', GDK_CONTROL_MASK, "Ctl+H"); | |
2510 gaim_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT, | |
2511 G_CALLBACK(do_quit), NULL, 'q', GDK_CONTROL_MASK, "Ctl+Q"); | |
2512 | |
2513 menu = gtk_menu_new(); | |
2514 | |
2515 menuitem = gaim_new_item(NULL, _("Tools")); | |
2516 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); | |
2517 gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuitem); | |
2518 | |
2519 awaymenu = gtk_menu_new(); | |
2520 menuitem = gaim_new_item_from_stock(menu, _("Away"), NULL, NULL, NULL, 0, 0, 0); | |
2521 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), awaymenu); | |
2522 do_away_menu(); | |
2523 | |
2524 bpmenu = gtk_menu_new(); | |
2525 menuitem = gaim_new_item_from_stock(menu, _("Buddy Pounce"), NULL, NULL, NULL, 0, 0, 0); | |
2526 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), bpmenu); | |
2527 do_bp_menu(); | |
2528 | |
2529 gaim_separator(menu); | |
2530 | |
2531 #ifndef NO_MULTI | |
2532 gaim_new_item_from_pixbuf(menu, _("_Accounts..."), "accounts-menu.png", | |
2533 G_CALLBACK(account_editor), NULL, 'a', GDK_CONTROL_MASK, "Ctl+A"); | |
2534 #endif | |
2535 gaim_new_item_from_stock(menu, _("_Preferences..."), GTK_STOCK_PREFERENCES, | |
2536 G_CALLBACK(show_prefs), NULL, 'p', GDK_CONTROL_MASK, "Ctl+P"); | |
2537 | |
2538 gaim_new_item_from_stock(menu, _("_File Transfers..."), GTK_STOCK_REVERT_TO_SAVED, | |
2539 G_CALLBACK(show_xfer_dialog), NULL, 0, 0, NULL); | |
2540 | |
2541 gaim_separator(menu); | |
2542 | |
2543 protomenu = gtk_menu_new(); | |
2544 menuitem = gaim_new_item_from_stock(menu, _("Protocol Actions"), NULL, NULL, NULL, 0, 0, 0); | |
2545 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), protomenu); | |
2546 do_proto_menu(); | |
2547 | |
2548 gaim_new_item_from_stock(menu, _("Pr_ivacy..."), NULL, | |
2549 G_CALLBACK(show_privacy_options), NULL, 0, 0, 0); | |
2550 | |
2551 gaim_new_item_from_stock(menu, _("_View System Log..."), NULL, | |
2552 G_CALLBACK(show_syslog), NULL, 0, 0, 0); | |
2553 | |
2554 menu = gtk_menu_new(); | |
2555 | |
2556 menuitem = gaim_new_item(NULL, _("Help")); | |
2557 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); | |
2558 gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuitem); | |
2559 | |
2560 gaim_new_item_from_stock(menu, _("Online Help"), GTK_STOCK_HELP, G_CALLBACK(open_url), WEBSITE"documentation.php", GDK_F1, 0, NULL); | |
2561 gaim_new_item_from_stock(menu, _("Debug Window"), NULL, G_CALLBACK(clicked_debug), NULL, 0, 0, NULL); | |
2562 | |
2563 gaim_separator(menu); | |
2564 | |
2565 gaim_new_item_from_pixbuf(menu, _("About Gaim"), "about_menu.png", G_CALLBACK(show_about), NULL, GDK_F1, GDK_CONTROL_MASK, NULL); | |
2566 | |
2567 gtk_widget_show(menubar); | |
2568 | |
2569 vbox = gtk_vbox_new(FALSE, 0); | |
2570 | |
2571 notebook = gtk_notebook_new(); | |
2572 | |
2573 /* Do buddy list stuff */ | |
2574 /* FIXME: spacing on both panes is ad hoc */ | |
2575 buddypane = gtk_vbox_new(FALSE, 1); | |
2576 | |
2577 buddies = gtk_tree_new(); | |
2578 gtk_tree_set_view_lines(GTK_TREE(buddies), FALSE); | |
2579 sw = gtk_scrolled_window_new(NULL, NULL); | |
2580 | |
2581 tips = gtk_tooltips_new(); | |
2582 gtk_object_set_data(GTK_OBJECT(blist), _("Buddy List"), tips); | |
2583 | |
2584 /* Now the buddy list */ | |
2585 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), buddies); | |
2586 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
2587 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
2588 gtk_widget_set_usize(sw, 200, 200); | |
2589 gtk_widget_show(buddies); | |
2590 gtk_widget_show(sw); | |
2591 | |
2592 gtk_box_pack_start(GTK_BOX(buddypane), sw, TRUE, TRUE, 0); | |
2593 gtk_widget_show(buddypane); | |
2594 | |
2595 if (!(blist_options & OPT_BLIST_NO_BUTTONS)) | |
2596 build_imchat_box(TRUE); | |
2597 | |
2598 /* Swing the edit buddy */ | |
2599 editpane = gtk_vbox_new(FALSE, 1); | |
2600 | |
2601 edittree = gtk_ctree_new(1, 0); | |
2602 gtk_ctree_set_line_style(GTK_CTREE(edittree), GTK_CTREE_LINES_SOLID);; | |
2603 gtk_ctree_set_expander_style(GTK_CTREE(edittree), GTK_CTREE_EXPANDER_SQUARE); | |
2604 gtk_clist_set_reorderable(GTK_CLIST(edittree), TRUE); | |
2605 g_signal_connect(GTK_OBJECT(edittree), "button_press_event", | |
2606 G_CALLBACK(click_edit_tree), NULL); | |
2607 | |
2608 gtk_ctree_set_drag_compare_func(GTK_CTREE(edittree), | |
2609 (GtkCTreeCompareDragFunc) edit_drag_compare_func); | |
2610 | |
2611 | |
2612 g_signal_connect_after(GTK_OBJECT(edittree), "tree_move", | |
2613 G_CALLBACK(edit_tree_move), NULL); | |
2614 | |
2615 | |
2616 bbox = gtk_hbox_new(TRUE, 5); | |
2617 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5); | |
2618 tbox = gtk_scrolled_window_new(NULL, NULL); | |
2619 | |
2620 /* buttons */ | |
2621 addbutton = gtk_button_new_with_label(_("Add")); | |
2622 groupbutton = gtk_button_new_with_label(_("Group")); | |
2623 rembutton = gtk_button_new_with_label(_("Remove")); | |
2624 | |
2625 gtk_button_set_relief(GTK_BUTTON(addbutton), GTK_RELIEF_NONE); | |
2626 gtk_button_set_relief(GTK_BUTTON(groupbutton), GTK_RELIEF_NONE); | |
2627 gtk_button_set_relief(GTK_BUTTON(rembutton), GTK_RELIEF_NONE); | |
2628 | |
2629 gtk_box_pack_start(GTK_BOX(bbox), addbutton, TRUE, TRUE, 0); | |
2630 gtk_box_pack_start(GTK_BOX(bbox), groupbutton, TRUE, TRUE, 0); | |
2631 gtk_box_pack_start(GTK_BOX(bbox), rembutton, TRUE, TRUE, 0); | |
2632 | |
2633 gtk_tooltips_set_tip(tips, addbutton, _("Add a new Buddy"), "Penguin"); | |
2634 gtk_tooltips_set_tip(tips, groupbutton, _("Add a new Group"), "Penguin"); | |
2635 gtk_tooltips_set_tip(tips, rembutton, _("Remove selected Buddy/Group"), "Penguin"); | |
2636 | |
2637 g_signal_connect(G_OBJECT(rembutton), "clicked", G_CALLBACK(do_del_buddy), edittree); | |
2638 g_signal_connect(G_OBJECT(addbutton), "clicked", G_CALLBACK(add_buddy_callback), NULL); | |
2639 g_signal_connect(G_OBJECT(groupbutton), "clicked", G_CALLBACK(add_group_callback), NULL); | |
2640 | |
2641 /* And the boxes in the box */ | |
2642 gtk_box_pack_start(GTK_BOX(editpane), tbox, TRUE, TRUE, 0); | |
2643 gtk_box_pack_start(GTK_BOX(editpane), bbox, FALSE, FALSE, 0); | |
2644 | |
2645 /* Finish up */ | |
2646 gtk_widget_show(addbutton); | |
2647 gtk_widget_show(groupbutton); | |
2648 gtk_widget_show(rembutton); | |
2649 gtk_widget_show(edittree); | |
2650 gtk_widget_show(tbox); | |
2651 gtk_widget_show(bbox); | |
2652 gtk_widget_show(editpane); | |
2653 | |
2654 update_button_pix(); | |
2655 | |
2656 label = gtk_label_new(_("Online")); | |
2657 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), buddypane, label); | |
2658 label = gtk_label_new(_("Edit Buddies")); | |
2659 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), editpane, label); | |
2660 | |
2661 if(blist_options & OPT_BLIST_BOTTOM_TAB) | |
2662 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM); | |
2663 | |
2664 gtk_widget_show_all(notebook); | |
2665 | |
2666 /* Pack things in the vbox */ | |
2667 gtk_widget_show(vbox); | |
2668 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0); | |
2669 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | |
2670 gtk_container_add(GTK_CONTAINER(blist), vbox); | |
2671 | |
2672 g_signal_connect(G_OBJECT(blist), "delete_event", G_CALLBACK(close_buddy_list), NULL); | |
2673 g_signal_connect(G_OBJECT(blist), "configure_event", G_CALLBACK(configure_blist_window), NULL); | |
2674 g_signal_connect(G_OBJECT(blist), "visibility_notify_event", G_CALLBACK(visibility_blist_window), NULL); | |
2675 | |
2676 gtk_widget_add_events(blist, GDK_VISIBILITY_NOTIFY_MASK); | |
2677 | |
2678 /* The edit tree */ | |
2679 gtk_container_add(GTK_CONTAINER(tbox), edittree); | |
2680 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tbox), | |
2681 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
2682 | |
2683 #ifdef _WIN32 | |
2684 /* Register newly created window with systray module */ | |
2685 wgaim_created_blistwin(GTK_WIDGET(blist)); | |
2686 #endif | |
2687 | |
2688 /* Houston, we are go for launch. */ | |
2689 unhide_buddy_list(); | |
2690 } | |
2691 | |
2692 void show_buddy_list() | |
2693 { | |
2694 make_buddy_list(); | |
2695 build_edit_tree(); | |
2696 update_button_pix(); | |
2697 } |