src/gtkaccount.c

branch
gaim
changeset 20470
77693555855f
parent 13071
b98e72d4089a
parent 20469
b2836a24d81e
child 20471
1966704b3e42
equal deleted inserted replaced
13071:b98e72d4089a 20470:77693555855f
1 /**
2 * @file gtkaccount.c GTK+ Account Editor UI
3 * @ingroup gtkui
4 *
5 * gaim
6 *
7 * Gaim is the legal property of its developers, whose names are too numerous
8 * to list here. Please refer to the COPYRIGHT file distributed with this
9 * source distribution.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include "internal.h"
27 #include "gtkgaim.h"
28
29 #include "account.h"
30 #include "accountopt.h"
31 #include "core.h"
32 #include "debug.h"
33 #include "notify.h"
34 #include "plugin.h"
35 #include "prefs.h"
36 #include "prpl.h"
37 #include "request.h"
38 #include "savedstatuses.h"
39 #include "signals.h"
40 #include "util.h"
41
42 #include "gtkaccount.h"
43 #include "gtkblist.h"
44 #include "gtkdialogs.h"
45 #include "gtkutils.h"
46 #include "gtkstatusbox.h"
47 #include "gtkstock.h"
48
49 enum
50 {
51 COLUMN_ICON,
52 COLUMN_SCREENNAME,
53 COLUMN_ENABLED,
54 COLUMN_PROTOCOL,
55 COLUMN_DATA,
56 COLUMN_PULSE_DATA,
57 NUM_COLUMNS
58 };
59
60 typedef struct
61 {
62 GaimAccount *account;
63 char *username;
64 char *alias;
65
66 } GaimGtkAccountAddUserData;
67
68 typedef struct
69 {
70 GtkWidget *window;
71 GtkWidget *treeview;
72
73 GtkWidget *modify_button;
74 GtkWidget *delete_button;
75
76 GtkListStore *model;
77 GtkTreeIter drag_iter;
78
79 GtkTreeViewColumn *screenname_col;
80
81 } AccountsWindow;
82
83 typedef struct
84 {
85 GaimGtkAccountDialogType type;
86
87 GaimAccount *account;
88 char *protocol_id;
89 GaimPlugin *plugin;
90 GaimPluginProtocolInfo *prpl_info;
91
92 GaimProxyType new_proxy_type;
93
94 GList *user_split_entries;
95 GList *protocol_opt_entries;
96
97 GtkSizeGroup *sg;
98 GtkWidget *window;
99
100 GtkWidget *top_vbox;
101 GtkWidget *bottom_vbox;
102 GtkWidget *ok_button;
103 GtkWidget *register_button;
104
105 /* Login Options */
106 GtkWidget *login_frame;
107 GtkWidget *protocol_menu;
108 GtkWidget *password_box;
109 GtkWidget *screenname_entry;
110 GtkWidget *password_entry;
111 GtkWidget *alias_entry;
112 GtkWidget *remember_pass_check;
113
114 /* User Options */
115 GtkWidget *user_frame;
116 GtkWidget *new_mail_check;
117 GtkWidget *icon_hbox;
118 GtkWidget *icon_entry;
119 char *icon_path;
120 GtkWidget *icon_filesel;
121 GtkWidget *icon_preview;
122 GtkWidget *icon_text;
123
124 /* Protocol Options */
125 GtkWidget *protocol_frame;
126
127 /* Proxy Options */
128 GtkWidget *proxy_frame;
129 GtkWidget *proxy_vbox;
130 GtkWidget *proxy_dropdown;
131 GtkWidget *proxy_host_entry;
132 GtkWidget *proxy_port_entry;
133 GtkWidget *proxy_user_entry;
134 GtkWidget *proxy_pass_entry;
135
136 } AccountPrefsDialog;
137
138 typedef struct
139 {
140 GdkPixbuf *online_pixbuf;
141 gboolean pulse_to_grey;
142 float pulse_value;
143 int timeout;
144 GaimAccount *account;
145 GtkTreeModel *model;
146
147 } GaimGtkPulseData;
148
149
150 static AccountsWindow *accounts_window = NULL;
151 static GHashTable *account_pref_wins;
152
153 static void add_account_to_liststore(GaimAccount *account, gpointer user_data);
154 static void set_account(GtkListStore *store, GtkTreeIter *iter,
155 GaimAccount *account);
156 static char*
157 convert_buddy_icon(GaimPlugin *plugin, const char *path);
158
159 /**************************************************************************
160 * Add/Modify Account dialog
161 **************************************************************************/
162 static void add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent);
163 static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent);
164 static void add_protocol_options(AccountPrefsDialog *dialog,
165 GtkWidget *parent);
166 static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent);
167
168 static GtkWidget *
169 add_pref_box(AccountPrefsDialog *dialog, GtkWidget *parent,
170 const char *text, GtkWidget *widget)
171 {
172 GtkWidget *hbox;
173 GtkWidget *label;
174
175 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
176 gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
177 gtk_widget_show(hbox);
178
179 label = gtk_label_new_with_mnemonic(text);
180 gtk_size_group_add_widget(dialog->sg, label);
181 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
182 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
183 gtk_widget_show(label);
184
185 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, GAIM_HIG_BORDER);
186 gtk_widget_show(widget);
187 gaim_set_accessible_label (widget, label);
188
189 return hbox;
190 }
191
192 static void
193 set_dialog_icon(AccountPrefsDialog *dialog)
194 {
195 char *filename = gaim_buddy_icons_get_full_path(dialog->icon_path);
196 gtk_image_set_from_file(GTK_IMAGE(dialog->icon_entry), filename);
197 g_free(filename);
198 }
199
200 static void
201 set_account_protocol_cb(GtkWidget *item, const char *id,
202 AccountPrefsDialog *dialog)
203 {
204 GaimPlugin *new_plugin;
205
206 new_plugin = gaim_find_prpl(id);
207
208 if (new_plugin == dialog->plugin)
209 return;
210
211 dialog->plugin = new_plugin;
212
213 if (dialog->plugin != NULL)
214 {
215 dialog->prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(dialog->plugin);
216
217 if (dialog->protocol_id != NULL)
218 g_free(dialog->protocol_id);
219
220 dialog->protocol_id = g_strdup(dialog->plugin->info->id);
221 }
222
223 if (dialog->account != NULL)
224 gaim_account_clear_settings(dialog->account);
225
226 add_login_options(dialog, dialog->top_vbox);
227 add_user_options(dialog, dialog->top_vbox);
228 add_protocol_options(dialog, dialog->bottom_vbox);
229
230 if (!dialog->prpl_info || !dialog->prpl_info->register_user) {
231 gtk_widget_hide(dialog->register_button);
232 } else {
233 if (dialog->prpl_info != NULL &&
234 (dialog->prpl_info->options & OPT_PROTO_REGISTER_NOSCREENNAME)) {
235 gtk_widget_set_sensitive(dialog->register_button, TRUE);
236 } else {
237 gtk_widget_set_sensitive(dialog->register_button, FALSE);
238 }
239 gtk_widget_show(dialog->register_button);
240 }
241 }
242
243 static void
244 screenname_changed_cb(GtkEntry *entry, AccountPrefsDialog *dialog)
245 {
246 if (dialog->ok_button)
247 gtk_widget_set_sensitive(dialog->ok_button,
248 *gtk_entry_get_text(entry) != '\0');
249 if (dialog->register_button) {
250 if (dialog->prpl_info != NULL && (dialog->prpl_info->options & OPT_PROTO_REGISTER_NOSCREENNAME))
251 gtk_widget_set_sensitive(dialog->register_button, TRUE);
252 else
253 gtk_widget_set_sensitive(dialog->register_button,
254 *gtk_entry_get_text(entry) != '\0');
255 }
256 }
257
258 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
259 static void
260 icon_filesel_choose_cb(GtkWidget *widget, gint response, AccountPrefsDialog *dialog)
261 {
262 char *filename, *current_folder;
263
264 if (response != GTK_RESPONSE_ACCEPT) {
265 if (response == GTK_RESPONSE_CANCEL)
266 gtk_widget_destroy(dialog->icon_filesel);
267 dialog->icon_filesel = NULL;
268 return;
269 }
270
271 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog->icon_filesel));
272 current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel));
273 if (current_folder != NULL) {
274 gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder);
275 g_free(current_folder);
276 }
277
278 #else /* FILECHOOSER */
279 static void
280 icon_filesel_choose_cb(GtkWidget *w, AccountPrefsDialog *dialog)
281 {
282 char *filename, *current_folder;
283
284 filename = g_strdup(gtk_file_selection_get_filename(
285 GTK_FILE_SELECTION(dialog->icon_filesel)));
286
287 /* If they typed in a directory, change there */
288 if (gaim_gtk_check_if_dir(filename,
289 GTK_FILE_SELECTION(dialog->icon_filesel)))
290 {
291 g_free(filename);
292 return;
293 }
294
295 current_folder = g_path_get_dirname(filename);
296 if (current_folder != NULL) {
297 gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder);
298 g_free(current_folder);
299 }
300
301 #endif /* FILECHOOSER */
302
303 if (dialog->icon_path)
304 g_free(dialog->icon_path);
305 dialog->icon_path = convert_buddy_icon(dialog->plugin, filename);
306 set_dialog_icon(dialog);
307 gtk_widget_show(dialog->icon_entry);
308
309 gtk_widget_destroy(dialog->icon_filesel);
310 dialog->icon_filesel = NULL;
311 g_free(filename);
312 }
313
314 static void
315 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
316 icon_preview_change_cb(GtkFileChooser *widget, AccountPrefsDialog *dialog)
317 #else /* FILECHOOSER */
318 icon_preview_change_cb(GtkTreeSelection *sel, AccountPrefsDialog *dialog)
319 #endif /* FILECHOOSER */
320 {
321 GdkPixbuf *pixbuf, *scale;
322 int height, width;
323 char *basename, *markup, *size;
324 struct stat st;
325 char *filename;
326
327 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
328 filename = gtk_file_chooser_get_preview_filename(
329 GTK_FILE_CHOOSER(dialog->icon_filesel));
330 #else /* FILECHOOSER */
331 filename = g_strdup(gtk_file_selection_get_filename(
332 GTK_FILE_SELECTION(dialog->icon_filesel)));
333 #endif /* FILECHOOSER */
334
335 if (!filename || g_stat(filename, &st))
336 {
337 g_free(filename);
338 return;
339 }
340
341 pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
342 if (!pixbuf) {
343 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL);
344 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), "");
345 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
346 gtk_file_chooser_set_preview_widget_active(
347 GTK_FILE_CHOOSER(dialog->icon_filesel), FALSE);
348 #endif /* FILECHOOSER */
349 g_free(filename);
350 return;
351 }
352
353 width = gdk_pixbuf_get_width(pixbuf);
354 height = gdk_pixbuf_get_height(pixbuf);
355 basename = g_path_get_basename(filename);
356 size = gaim_str_size_to_units(st.st_size);
357 markup = g_strdup_printf(_("<b>File:</b> %s\n"
358 "<b>File size:</b> %s\n"
359 "<b>Image size:</b> %dx%d"),
360 basename, size, width, height);
361
362 scale = gdk_pixbuf_scale_simple(pixbuf, width * 50 / height,
363 50, GDK_INTERP_BILINEAR);
364 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), scale);
365 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
366 gtk_file_chooser_set_preview_widget_active(
367 GTK_FILE_CHOOSER(dialog->icon_filesel), TRUE);
368 #endif /* FILECHOOSER */
369 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), markup);
370
371 g_object_unref(G_OBJECT(pixbuf));
372 g_object_unref(G_OBJECT(scale));
373 g_free(filename);
374 g_free(basename);
375 g_free(size);
376 g_free(markup);
377 }
378
379 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
380 static void
381 icon_filesel_delete_cb(GtkWidget *w, AccountPrefsDialog *dialog)
382 {
383 if (dialog->icon_filesel != NULL)
384 gtk_widget_destroy(dialog->icon_filesel);
385
386 dialog->icon_filesel = NULL;
387 }
388 #endif /* FILECHOOSER */
389
390 static void
391 icon_select_cb(GtkWidget *button, AccountPrefsDialog *dialog)
392 {
393 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
394 GtkWidget *hbox;
395 GtkWidget *tv;
396 GtkTreeSelection *sel;
397 #endif /* FILECHOOSER */
398 const char *current_folder;
399
400 if (dialog->icon_filesel != NULL) {
401 gtk_window_present(GTK_WINDOW(dialog->icon_filesel));
402 return;
403 }
404
405 current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_icon_folder");
406 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
407 dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"),
408 GTK_WINDOW(dialog->window),
409 GTK_FILE_CHOOSER_ACTION_OPEN,
410 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
411 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
412 NULL);
413 gtk_dialog_set_default_response(GTK_DIALOG(dialog->icon_filesel), GTK_RESPONSE_ACCEPT);
414 if ((current_folder != NULL) && (*current_folder != '\0'))
415 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel),
416 current_folder);
417
418 dialog->icon_preview = gtk_image_new();
419 dialog->icon_text = gtk_label_new(NULL);
420 gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50);
421 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog->icon_filesel),
422 GTK_WIDGET(dialog->icon_preview));
423 g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview",
424 G_CALLBACK(icon_preview_change_cb), dialog);
425 g_signal_connect(G_OBJECT(dialog->icon_filesel), "response",
426 G_CALLBACK(icon_filesel_choose_cb), dialog);
427 icon_preview_change_cb(NULL, dialog);
428 #else /* FILECHOOSER */
429 dialog->icon_filesel = gtk_file_selection_new(_("Buddy Icon"));
430 dialog->icon_preview = gtk_image_new();
431 dialog->icon_text = gtk_label_new(NULL);
432 if ((current_folder != NULL) && (*current_folder != '\0'))
433 gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog->icon_filesel),
434 current_folder);
435
436 gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50);
437 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
438 gtk_box_pack_start(
439 GTK_BOX(GTK_FILE_SELECTION(dialog->icon_filesel)->main_vbox),
440 hbox, FALSE, FALSE, 0);
441 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_preview,
442 FALSE, FALSE, 0);
443 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_text, FALSE, FALSE, 0);
444
445 tv = GTK_FILE_SELECTION(dialog->icon_filesel)->file_list;
446 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
447
448 g_signal_connect(G_OBJECT(sel), "changed",
449 G_CALLBACK(icon_preview_change_cb), dialog);
450 g_signal_connect(
451 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->ok_button),
452 "clicked",
453 G_CALLBACK(icon_filesel_choose_cb), dialog);
454 g_signal_connect(
455 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->cancel_button),
456 "clicked",
457 G_CALLBACK(icon_filesel_delete_cb), dialog);
458 g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy",
459 G_CALLBACK(icon_filesel_delete_cb), dialog);
460 #endif /* FILECHOOSER */
461
462 gtk_widget_show_all(GTK_WIDGET(dialog->icon_filesel));
463 }
464
465 static void
466 icon_reset_cb(GtkWidget *button, AccountPrefsDialog *dialog)
467 {
468 if (dialog->icon_path)
469 g_free(dialog->icon_path);
470 dialog->icon_path = NULL;
471
472 gtk_widget_hide(dialog->icon_entry);
473 }
474
475
476 static void
477 account_dnd_recv(GtkWidget *widget, GdkDragContext *dc, gint x, gint y,
478 GtkSelectionData *sd, guint info, guint t, AccountPrefsDialog *dialog)
479 {
480 gchar *name = (gchar *)sd->data;
481
482 if ((sd->length >= 0) && (sd->format == 8)) {
483 /* Well, it looks like the drag event was cool.
484 * Let's do something with it */
485 if (!g_ascii_strncasecmp(name, "file://", 7)) {
486 GError *converr = NULL;
487 gchar *tmp, *rtmp;
488 /* It looks like we're dealing with a local file. Let's
489 * just untar it in the right place */
490 if(!(tmp = g_filename_from_uri(name, NULL, &converr))) {
491 gaim_debug(GAIM_DEBUG_ERROR, "buddyicon", "%s\n",
492 (converr ? converr->message :
493 "g_filename_from_uri error"));
494 return;
495 }
496 if ((rtmp = strchr(tmp, '\r')) || (rtmp = strchr(tmp, '\n')))
497 *rtmp = '\0';
498 if (dialog->icon_path)
499 g_free(dialog->icon_path);
500 dialog->icon_path = convert_buddy_icon(dialog->plugin, tmp);
501 set_dialog_icon(dialog);
502 gtk_widget_show(dialog->icon_entry);
503 g_free(tmp);
504 }
505 gtk_drag_finish(dc, TRUE, FALSE, t);
506 }
507 gtk_drag_finish(dc, FALSE, FALSE, t);
508 }
509
510
511 #if GTK_CHECK_VERSION(2,2,0)
512 static gboolean
513 str_array_match(char **a, char **b)
514 {
515 int i, j;
516
517 if (!a || !b)
518 return FALSE;
519 for (i = 0; a[i] != NULL; i++)
520 for (j = 0; b[j] != NULL; j++)
521 if (!g_ascii_strcasecmp(a[i], b[j]))
522 return TRUE;
523 return FALSE;
524 }
525 #endif
526
527 static char*
528 convert_buddy_icon(GaimPlugin *plugin, const char *path)
529 {
530 #if GTK_CHECK_VERSION(2,2,0)
531 int width, height;
532 char **pixbuf_formats = NULL;
533 GdkPixbufFormat *format;
534 GdkPixbuf *pixbuf;
535 GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin);
536 char **prpl_formats = g_strsplit (prpl_info->icon_spec.format,",",0);
537 #if !GTK_CHECK_VERSION(2,4,0)
538 GdkPixbufLoader *loader;
539 FILE *file;
540 struct stat st;
541 void *data = NULL;
542 #endif
543 #endif
544 const char *dirname = gaim_buddy_icons_get_cache_dir();
545 char *random = g_strdup_printf("%x", g_random_int());
546 char *filename = g_build_filename(dirname, random, NULL);
547
548 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
549 gaim_debug_info("buddyicon", "Creating icon cache directory.\n");
550
551 if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
552 gaim_debug_error("buddyicon",
553 "Unable to create directory %s: %s\n",
554 dirname, strerror(errno));
555 #if GTK_CHECK_VERSION(2,2,0)
556 g_strfreev(prpl_formats);
557 #endif
558 g_free(random);
559 g_free(filename);
560 return NULL;
561 }
562 }
563
564 #if GTK_CHECK_VERSION(2,2,0)
565 #if GTK_CHECK_VERSION(2,4,0)
566 format = gdk_pixbuf_get_file_info (path, &width, &height);
567 #else
568 loader = gdk_pixbuf_loader_new();
569 if (!g_stat(path, &st) && (file = g_fopen(path, "rb")) != NULL) {
570 data = g_malloc(st.st_size);
571 fread(data, 1, st.st_size, file);
572 fclose(file);
573 gdk_pixbuf_loader_write(loader, data, st.st_size, NULL);
574 g_free(data);
575 }
576 gdk_pixbuf_loader_close(loader, NULL);
577 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
578 width = gdk_pixbuf_get_width(pixbuf);
579 height = gdk_pixbuf_get_height(pixbuf);
580 format = gdk_pixbuf_loader_get_format(loader);
581 g_object_unref(G_OBJECT(loader));
582 #endif
583 pixbuf_formats = gdk_pixbuf_format_get_extensions(format);
584
585 if (str_array_match(pixbuf_formats, prpl_formats) && /* This is an acceptable format AND */
586 (!(prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */
587 (prpl_info->icon_spec.min_width <= width &&
588 prpl_info->icon_spec.max_width >= width &&
589 prpl_info->icon_spec.min_height <= height &&
590 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */
591 #endif
592 {
593 gchar *contents;
594 gsize length;
595 FILE *image;
596
597 #if GTK_CHECK_VERSION(2,2,0)
598 g_strfreev(prpl_formats);
599 g_strfreev(pixbuf_formats);
600 #endif
601
602 /* Copy the image to the cache folder as "filename". */
603
604 if (!g_file_get_contents(path, &contents, &length, NULL) ||
605 (image = g_fopen(filename, "wb")) == NULL)
606 {
607 g_free(random);
608 g_free(filename);
609 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
610 g_object_unref(G_OBJECT(pixbuf));
611 #endif
612 return NULL;
613 }
614
615 if (fwrite(contents, 1, length, image) != length)
616 {
617 fclose(image);
618 g_unlink(filename);
619
620 g_free(random);
621 g_free(filename);
622 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
623 g_object_unref(G_OBJECT(pixbuf));
624 #endif
625 return NULL;
626 }
627 fclose(image);
628
629 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
630 g_object_unref(G_OBJECT(pixbuf));
631 #endif
632
633 g_free(filename);
634 return random;
635 }
636 #if GTK_CHECK_VERSION(2,2,0)
637 else
638 {
639 int i;
640 GError *error = NULL;
641 GdkPixbuf *scale;
642 pixbuf = gdk_pixbuf_new_from_file(path, &error);
643 g_strfreev(pixbuf_formats);
644 if (!error && (prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) &&
645 (width < prpl_info->icon_spec.min_width ||
646 width > prpl_info->icon_spec.max_width ||
647 height < prpl_info->icon_spec.min_height ||
648 height > prpl_info->icon_spec.max_height))
649 {
650 int new_width = width;
651 int new_height = height;
652
653 if(new_width > prpl_info->icon_spec.max_width)
654 new_width = prpl_info->icon_spec.max_width;
655 else if(new_width < prpl_info->icon_spec.min_width)
656 new_width = prpl_info->icon_spec.min_width;
657 if(new_height > prpl_info->icon_spec.max_height)
658 new_height = prpl_info->icon_spec.max_height;
659 else if(new_height < prpl_info->icon_spec.min_height)
660 new_height = prpl_info->icon_spec.min_height;
661
662 /* preserve aspect ratio */
663 if ((double)height * (double)new_width >
664 (double)width * (double)new_height) {
665 new_width = 0.5 + (double)width * (double)new_height / (double)height;
666 } else {
667 new_height = 0.5 + (double)height * (double)new_width / (double)width;
668 }
669
670 scale = gdk_pixbuf_scale_simple (pixbuf, new_width, new_height,
671 GDK_INTERP_HYPER);
672 g_object_unref(G_OBJECT(pixbuf));
673 pixbuf = scale;
674 }
675 if (error) {
676 g_free(random);
677 g_free(filename);
678 gaim_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message);
679 g_error_free(error);
680 g_strfreev(prpl_formats);
681 return NULL;
682 }
683
684 for (i = 0; prpl_formats[i]; i++) {
685 gaim_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename);
686 /* The gdk-pixbuf documentation is wrong. gdk_pixbuf_save returns TRUE if it was successful,
687 * FALSE if an error was set. */
688 if (gdk_pixbuf_save (pixbuf, filename, prpl_formats[i], &error, NULL) == TRUE)
689 break;
690 gaim_debug_warning("buddyicon", "Could not convert to %s: %s\n", prpl_formats[i], error->message);
691 g_error_free(error);
692 error = NULL;
693 }
694 g_strfreev(prpl_formats);
695 if (!error) {
696 g_object_unref(G_OBJECT(pixbuf));
697 g_free(filename);
698 return random;
699 } else {
700 gaim_debug_error("buddyicon", "Could not convert icon to usable format: %s\n", error->message);
701 g_error_free(error);
702 }
703 g_free(random);
704 g_free(filename);
705 g_object_unref(G_OBJECT(pixbuf));
706 }
707 return NULL;
708 #endif
709 }
710
711 static void
712 update_editable(GaimConnection *gc, AccountPrefsDialog *dialog)
713 {
714 gboolean set;
715 GList *l;
716
717 if (dialog->account == NULL)
718 return;
719
720 if (gc != NULL && dialog->account != gaim_connection_get_account(gc))
721 return;
722
723 set = !(gaim_account_is_connected(dialog->account) || gaim_account_is_connecting(dialog->account));
724 gtk_widget_set_sensitive(dialog->protocol_menu, set);
725 gtk_widget_set_sensitive(dialog->screenname_entry, set);
726
727 for (l = dialog->user_split_entries ; l != NULL ; l = l->next)
728 gtk_widget_set_sensitive((GtkWidget *)l->data, set);
729 }
730
731 static void
732 add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent)
733 {
734 GtkWidget *frame;
735 GtkWidget *vbox;
736 GtkWidget *entry;
737 GList *user_splits;
738 GList *l, *l2;
739 char *username = NULL;
740
741 if (dialog->login_frame != NULL)
742 gtk_widget_destroy(dialog->login_frame);
743
744 /* Build the login options frame. */
745 frame = gaim_gtk_make_frame(parent, _("Login Options"));
746
747 /* cringe */
748 dialog->login_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame));
749
750 gtk_box_reorder_child(GTK_BOX(parent), dialog->login_frame, 0);
751 gtk_widget_show(dialog->login_frame);
752
753 /* Main vbox */
754 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
755 gtk_container_add(GTK_CONTAINER(frame), vbox);
756 gtk_widget_show(vbox);
757
758 /* Protocol */
759 dialog->protocol_menu = gaim_gtk_protocol_option_menu_new(
760 dialog->protocol_id, G_CALLBACK(set_account_protocol_cb), dialog);
761
762 add_pref_box(dialog, vbox, _("Protocol:"), dialog->protocol_menu);
763
764 /* Screen name */
765 dialog->screenname_entry = gtk_entry_new();
766
767 add_pref_box(dialog, vbox, _("Screen name:"), dialog->screenname_entry);
768
769 g_signal_connect(G_OBJECT(dialog->screenname_entry), "changed",
770 G_CALLBACK(screenname_changed_cb), dialog);
771
772 /* Do the user split thang */
773 if (dialog->plugin == NULL) /* Yeah right. */
774 user_splits = NULL;
775 else
776 user_splits = dialog->prpl_info->user_splits;
777
778 if (dialog->account != NULL)
779 username = g_strdup(gaim_account_get_username(dialog->account));
780
781 if (dialog->user_split_entries != NULL) {
782 g_list_free(dialog->user_split_entries);
783 dialog->user_split_entries = NULL;
784 }
785
786 for (l = user_splits; l != NULL; l = l->next) {
787 GaimAccountUserSplit *split = l->data;
788 char *buf;
789
790 buf = g_strdup_printf("%s:", gaim_account_user_split_get_text(split));
791
792 entry = gtk_entry_new();
793
794 add_pref_box(dialog, vbox, buf, entry);
795
796 g_free(buf);
797
798 dialog->user_split_entries =
799 g_list_append(dialog->user_split_entries, entry);
800 }
801
802 for (l = g_list_last(dialog->user_split_entries),
803 l2 = g_list_last(user_splits);
804 l != NULL && l2 != NULL;
805 l = l->prev, l2 = l2->prev) {
806
807 GtkWidget *entry = l->data;
808 GaimAccountUserSplit *split = l2->data;
809 const char *value = NULL;
810 char *c;
811
812 if (dialog->account != NULL) {
813 c = strrchr(username,
814 gaim_account_user_split_get_separator(split));
815
816 if (c != NULL) {
817 *c = '\0';
818 c++;
819
820 value = c;
821 }
822 }
823
824 if (value == NULL)
825 value = gaim_account_user_split_get_default_value(split);
826
827 if (value != NULL)
828 gtk_entry_set_text(GTK_ENTRY(entry), value);
829 }
830
831 if (username != NULL)
832 gtk_entry_set_text(GTK_ENTRY(dialog->screenname_entry), username);
833
834 g_free(username);
835
836
837 /* Password */
838 dialog->password_entry = gtk_entry_new();
839 gtk_entry_set_visibility(GTK_ENTRY(dialog->password_entry), FALSE);
840 gtk_entry_set_invisible_char(GTK_ENTRY(dialog->password_entry), GAIM_INVISIBLE_CHAR);
841 dialog->password_box = add_pref_box(dialog, vbox, _("Password:"),
842 dialog->password_entry);
843
844 /* Alias */
845 dialog->alias_entry = gtk_entry_new();
846 add_pref_box(dialog, vbox, _("Alias:"), dialog->alias_entry);
847
848 /* Remember Password */
849 dialog->remember_pass_check =
850 gtk_check_button_new_with_label(_("Remember password"));
851 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->remember_pass_check),
852 FALSE);
853 gtk_box_pack_start(GTK_BOX(vbox), dialog->remember_pass_check,
854 FALSE, FALSE, 0);
855 gtk_widget_show(dialog->remember_pass_check);
856
857 /* Set the fields. */
858 if (dialog->account != NULL) {
859 if (gaim_account_get_password(dialog->account))
860 gtk_entry_set_text(GTK_ENTRY(dialog->password_entry),
861 gaim_account_get_password(dialog->account));
862
863 if (gaim_account_get_alias(dialog->account))
864 gtk_entry_set_text(GTK_ENTRY(dialog->alias_entry),
865 gaim_account_get_alias(dialog->account));
866
867 gtk_toggle_button_set_active(
868 GTK_TOGGLE_BUTTON(dialog->remember_pass_check),
869 gaim_account_get_remember_password(dialog->account));
870 }
871
872 if (dialog->prpl_info != NULL &&
873 (dialog->prpl_info->options & OPT_PROTO_NO_PASSWORD)) {
874
875 gtk_widget_hide(dialog->password_box);
876 gtk_widget_hide(dialog->remember_pass_check);
877 }
878
879 /* Do not let the user change the protocol/screenname while connected. */
880 update_editable(NULL, dialog);
881 gaim_signal_connect(gaim_connections_get_handle(), "signing-on", dialog,
882 G_CALLBACK(update_editable), dialog);
883 gaim_signal_connect(gaim_connections_get_handle(), "signed-off", dialog,
884 G_CALLBACK(update_editable), dialog);
885 }
886
887 static void
888 add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent)
889 {
890 GtkWidget *frame;
891 GtkWidget *vbox;
892 GtkWidget *vbox2;
893 GtkWidget *hbox;
894 GtkWidget *hbox2;
895 GtkWidget *button;
896 GtkWidget *label;
897
898 if (dialog->user_frame != NULL)
899 gtk_widget_destroy(dialog->user_frame);
900
901 /* Build the user options frame. */
902 frame = gaim_gtk_make_frame(parent, _("User Options"));
903 dialog->user_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame));
904
905 gtk_box_reorder_child(GTK_BOX(parent), dialog->user_frame, 1);
906 gtk_widget_show(dialog->user_frame);
907
908 /* Main vbox */
909 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
910 gtk_container_add(GTK_CONTAINER(frame), vbox);
911 gtk_widget_show(vbox);
912
913 /* New mail notifications */
914 dialog->new_mail_check =
915 gtk_check_button_new_with_label(_("New mail notifications"));
916 gtk_box_pack_start(GTK_BOX(vbox), dialog->new_mail_check, FALSE, FALSE, 0);
917 gtk_widget_show(dialog->new_mail_check);
918
919 /* Buddy icon */
920 dialog->icon_hbox = hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
921 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
922 gtk_widget_show(hbox);
923
924 label = gtk_label_new(_("Buddy icon:"));
925 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
926 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
927 gtk_widget_show(label);
928
929 dialog->icon_entry = gtk_image_new();
930 gtk_box_pack_start(GTK_BOX(hbox), dialog->icon_entry,
931 FALSE, FALSE, 0);
932 gtk_widget_show(dialog->icon_entry);
933 gaim_set_accessible_label (dialog->icon_entry, label);
934 dialog->icon_path = NULL;
935
936 vbox2 = gtk_vbox_new(FALSE, 0);
937 gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0);
938 gtk_widget_show(vbox2);
939
940 hbox2 = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
941 gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, GAIM_HIG_BORDER);
942 gtk_widget_show(hbox2);
943
944 button = gtk_button_new_from_stock(GTK_STOCK_OPEN);
945 gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
946 g_signal_connect(G_OBJECT(button), "clicked",
947 G_CALLBACK(icon_select_cb), dialog);
948 gtk_widget_show(button);
949
950 button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
951 g_signal_connect(G_OBJECT(button), "clicked",
952 G_CALLBACK(icon_reset_cb), dialog);
953 gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
954 gtk_widget_show(button);
955
956 if (dialog->prpl_info != NULL) {
957 if (!(dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK))
958 gtk_widget_hide(dialog->new_mail_check);
959
960 if (!(dialog->prpl_info->icon_spec.format != NULL))
961 gtk_widget_hide(dialog->icon_hbox);
962 }
963
964 if (dialog->account != NULL) {
965 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->new_mail_check),
966 gaim_account_get_check_mail(dialog->account));
967
968 if (gaim_account_get_buddy_icon(dialog->account) != NULL) {
969 dialog->icon_path = g_strdup(gaim_account_get_buddy_icon(dialog->account));
970 set_dialog_icon(dialog);
971 }
972 }
973
974 if (!dialog->prpl_info ||
975 (!(dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK) &&
976 (dialog->prpl_info->icon_spec.format == NULL))) {
977
978 /* Nothing to see :( aww. */
979 gtk_widget_hide(dialog->user_frame);
980 }
981 }
982
983 static void
984 add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent)
985 {
986 GaimAccountOption *option;
987 GaimAccount *account;
988 GtkWidget *frame, *vbox, *check, *entry, *combo;
989 const GList *list, *node;
990 gint i, idx, int_value;
991 GtkListStore *model;
992 GtkTreeIter iter;
993 GtkCellRenderer *renderer;
994 GaimKeyValuePair *kvp;
995 GList *l;
996 char buf[1024];
997 char *title;
998 const char *str_value;
999 gboolean bool_value;
1000
1001 if (dialog->protocol_frame != NULL) {
1002 gtk_widget_destroy(dialog->protocol_frame);
1003 dialog->protocol_frame = NULL;
1004 }
1005
1006 if (dialog->prpl_info == NULL ||
1007 dialog->prpl_info->protocol_options == NULL) {
1008
1009 return;
1010 }
1011
1012 account = dialog->account;
1013
1014 /* Build the protocol options frame. */
1015 g_snprintf(buf, sizeof(buf), _("%s Options"), dialog->plugin->info->name);
1016
1017 frame = gaim_gtk_make_frame(parent, buf);
1018 dialog->protocol_frame =
1019 gtk_widget_get_parent(gtk_widget_get_parent(frame));
1020
1021 gtk_box_reorder_child(GTK_BOX(parent), dialog->protocol_frame, 0);
1022 gtk_widget_show(dialog->protocol_frame);
1023
1024 /* Main vbox */
1025 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
1026 gtk_container_add(GTK_CONTAINER(frame), vbox);
1027 gtk_widget_show(vbox);
1028
1029 if (dialog->protocol_opt_entries != NULL) {
1030 g_list_free(dialog->protocol_opt_entries);
1031 dialog->protocol_opt_entries = NULL;
1032 }
1033
1034 for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next)
1035 {
1036 option = (GaimAccountOption *)l->data;
1037
1038 switch (gaim_account_option_get_type(option))
1039 {
1040 case GAIM_PREF_BOOLEAN:
1041 if (account == NULL ||
1042 strcmp(gaim_account_get_protocol_id(account),
1043 dialog->protocol_id))
1044 {
1045 bool_value = gaim_account_option_get_default_bool(option);
1046 }
1047 else
1048 {
1049 bool_value = gaim_account_get_bool(account,
1050 gaim_account_option_get_setting(option),
1051 gaim_account_option_get_default_bool(option));
1052 }
1053
1054 check = gtk_check_button_new_with_label(
1055 gaim_account_option_get_text(option));
1056
1057 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check),
1058 bool_value);
1059
1060 gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);
1061 gtk_widget_show(check);
1062
1063 dialog->protocol_opt_entries =
1064 g_list_append(dialog->protocol_opt_entries, check);
1065
1066 break;
1067
1068 case GAIM_PREF_INT:
1069 if (account == NULL ||
1070 strcmp(gaim_account_get_protocol_id(account),
1071 dialog->protocol_id))
1072 {
1073 int_value = gaim_account_option_get_default_int(option);
1074 }
1075 else
1076 {
1077 int_value = gaim_account_get_int(account,
1078 gaim_account_option_get_setting(option),
1079 gaim_account_option_get_default_int(option));
1080 }
1081
1082 g_snprintf(buf, sizeof(buf), "%d", int_value);
1083
1084 entry = gtk_entry_new();
1085 gtk_entry_set_text(GTK_ENTRY(entry), buf);
1086
1087 title = g_strdup_printf("%s:",
1088 gaim_account_option_get_text(option));
1089
1090 add_pref_box(dialog, vbox, title, entry);
1091
1092 g_free(title);
1093
1094 dialog->protocol_opt_entries =
1095 g_list_append(dialog->protocol_opt_entries, entry);
1096
1097 break;
1098
1099 case GAIM_PREF_STRING:
1100 if (account == NULL ||
1101 strcmp(gaim_account_get_protocol_id(account),
1102 dialog->protocol_id))
1103 {
1104 str_value = gaim_account_option_get_default_string(option);
1105 }
1106 else
1107 {
1108 str_value = gaim_account_get_string(account,
1109 gaim_account_option_get_setting(option),
1110 gaim_account_option_get_default_string(option));
1111 }
1112
1113 entry = gtk_entry_new();
1114 if (gaim_account_option_get_masked(option))
1115 {
1116 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
1117 gtk_entry_set_invisible_char(GTK_ENTRY(entry), GAIM_INVISIBLE_CHAR);
1118 }
1119
1120 if (str_value != NULL)
1121 gtk_entry_set_text(GTK_ENTRY(entry), str_value);
1122
1123 title = g_strdup_printf("%s:",
1124 gaim_account_option_get_text(option));
1125
1126 add_pref_box(dialog, vbox, title, entry);
1127
1128 g_free(title);
1129
1130 dialog->protocol_opt_entries =
1131 g_list_append(dialog->protocol_opt_entries, entry);
1132
1133 break;
1134
1135 case GAIM_PREF_STRING_LIST:
1136 i = 0;
1137 idx = 0;
1138
1139 if (account == NULL ||
1140 strcmp(gaim_account_get_protocol_id(account),
1141 dialog->protocol_id))
1142 {
1143 str_value = gaim_account_option_get_default_list_value(option);
1144 }
1145 else
1146 {
1147 str_value = gaim_account_get_string(account,
1148 gaim_account_option_get_setting(option),
1149 gaim_account_option_get_default_list_value(option));
1150 }
1151
1152 list = gaim_account_option_get_list(option);
1153 model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1154 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
1155
1156 /* Loop through list of GaimKeyValuePair items */
1157 for (node = list; node != NULL; node = node->next) {
1158 if (node->data != NULL) {
1159 kvp = (GaimKeyValuePair *) node->data;
1160 if ((kvp->value != NULL) && (str_value != NULL) &&
1161 !g_utf8_collate(kvp->value, str_value))
1162 idx = i;
1163
1164 gtk_list_store_append(model, &iter);
1165 gtk_list_store_set(model, &iter,
1166 0, kvp->key,
1167 1, kvp->value,
1168 -1);
1169 }
1170
1171 i++;
1172 }
1173
1174 /* Set default */
1175 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), idx);
1176
1177 /* Define renderer */
1178 renderer = gtk_cell_renderer_text_new();
1179 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer,
1180 TRUE);
1181 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),
1182 renderer, "text", 0, NULL);
1183
1184 title = g_strdup_printf("%s:",
1185 gaim_account_option_get_text(option));
1186
1187 add_pref_box(dialog, vbox, title, combo);
1188
1189 g_free(title);
1190
1191 dialog->protocol_opt_entries =
1192 g_list_append(dialog->protocol_opt_entries, combo);
1193
1194 break;
1195
1196
1197 default:
1198 break;
1199 }
1200 }
1201 }
1202
1203 static GtkWidget *
1204 make_proxy_dropdown(void)
1205 {
1206 GtkWidget *dropdown;
1207 GtkListStore *model;
1208 GtkTreeIter iter;
1209 GtkCellRenderer *renderer;
1210
1211 model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
1212 dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
1213
1214 gtk_list_store_append(model, &iter);
1215 gtk_list_store_set(model, &iter,
1216 0, _("Use Global Proxy Settings"),
1217 1, GAIM_PROXY_USE_GLOBAL,
1218 -1);
1219
1220 gtk_list_store_append(model, &iter);
1221 gtk_list_store_set(model, &iter,
1222 0, _("No Proxy"),
1223 1, GAIM_PROXY_NONE,
1224 -1);
1225
1226 gtk_list_store_append(model, &iter);
1227 gtk_list_store_set(model, &iter,
1228 0, _("HTTP"),
1229 1, GAIM_PROXY_HTTP,
1230 -1);
1231
1232 gtk_list_store_append(model, &iter);
1233 gtk_list_store_set(model, &iter,
1234 0, _("SOCKS 4"),
1235 1, GAIM_PROXY_SOCKS4,
1236 -1);
1237
1238 gtk_list_store_append(model, &iter);
1239 gtk_list_store_set(model, &iter,
1240 0, _("SOCKS 5"),
1241 1, GAIM_PROXY_SOCKS5,
1242 -1);
1243
1244 gtk_list_store_append(model, &iter);
1245 gtk_list_store_set(model, &iter,
1246 0, _("Use Environmental Settings"),
1247 1, GAIM_PROXY_USE_ENVVAR,
1248 -1);
1249
1250 renderer = gtk_cell_renderer_text_new();
1251 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE);
1252 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer,
1253 "text", 0, NULL);
1254
1255 return dropdown;
1256 }
1257
1258 static void
1259 proxy_type_changed_cb(GtkWidget *menu, AccountPrefsDialog *dialog)
1260 {
1261 dialog->new_proxy_type =
1262 gtk_combo_box_get_active(GTK_COMBO_BOX(menu)) - 1;
1263
1264 if (dialog->new_proxy_type == GAIM_PROXY_USE_GLOBAL ||
1265 dialog->new_proxy_type == GAIM_PROXY_NONE ||
1266 dialog->new_proxy_type == GAIM_PROXY_USE_ENVVAR) {
1267
1268 gtk_widget_hide_all(dialog->proxy_vbox);
1269 }
1270 else
1271 gtk_widget_show_all(dialog->proxy_vbox);
1272 }
1273
1274 static void
1275 port_popup_cb(GtkWidget *w, GtkMenu *menu, gpointer data)
1276 {
1277 GtkWidget *item;
1278
1279 item = gtk_menu_item_new_with_label(
1280 _("you can see the butterflies mating"));
1281 gtk_widget_show(item);
1282 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item);
1283
1284 item = gtk_menu_item_new_with_label(_("If you look real closely"));
1285 gtk_widget_show(item);
1286 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item);
1287 }
1288
1289 static void
1290 add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent)
1291 {
1292 GaimProxyInfo *proxy_info;
1293 GtkWidget *frame;
1294 GtkWidget *vbox;
1295 GtkWidget *vbox2;
1296
1297 if (dialog->proxy_frame != NULL)
1298 gtk_widget_destroy(dialog->proxy_frame);
1299
1300 frame = gaim_gtk_make_frame(parent, _("Proxy Options"));
1301 dialog->proxy_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame));
1302
1303 gtk_box_reorder_child(GTK_BOX(parent), dialog->proxy_frame, 1);
1304 gtk_widget_show(dialog->proxy_frame);
1305
1306 /* Main vbox */
1307 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
1308 gtk_container_add(GTK_CONTAINER(frame), vbox);
1309 gtk_widget_show(vbox);
1310
1311 /* Proxy Type drop-down. */
1312 dialog->proxy_dropdown = make_proxy_dropdown();
1313
1314 add_pref_box(dialog, vbox, _("Proxy _type:"), dialog->proxy_dropdown);
1315
1316 /* Setup the second vbox, which may be hidden at times. */
1317 dialog->proxy_vbox = vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
1318 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, GAIM_HIG_BORDER);
1319 gtk_widget_show(vbox2);
1320
1321 /* Host */
1322 dialog->proxy_host_entry = gtk_entry_new();
1323 add_pref_box(dialog, vbox2, _("_Host:"), dialog->proxy_host_entry);
1324
1325 /* Port */
1326 dialog->proxy_port_entry = gtk_entry_new();
1327 add_pref_box(dialog, vbox2, _("_Port:"), dialog->proxy_port_entry);
1328
1329 g_signal_connect(G_OBJECT(dialog->proxy_port_entry), "populate-popup",
1330 G_CALLBACK(port_popup_cb), NULL);
1331
1332 /* User */
1333 dialog->proxy_user_entry = gtk_entry_new();
1334
1335 add_pref_box(dialog, vbox2, _("_Username:"), dialog->proxy_user_entry);
1336
1337 /* Password */
1338 dialog->proxy_pass_entry = gtk_entry_new();
1339 gtk_entry_set_visibility(GTK_ENTRY(dialog->proxy_pass_entry), FALSE);
1340 gtk_entry_set_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry), GAIM_INVISIBLE_CHAR);
1341 add_pref_box(dialog, vbox2, _("Pa_ssword:"), dialog->proxy_pass_entry);
1342
1343 if (dialog->account != NULL &&
1344 (proxy_info = gaim_account_get_proxy_info(dialog->account)) != NULL) {
1345
1346 GaimProxyType type = gaim_proxy_info_get_type(proxy_info);
1347
1348 /* Hah! */
1349 /* I dunno what you're laughing about, fuzz ball. */
1350 dialog->new_proxy_type = type;
1351 gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->proxy_dropdown),
1352 type + 1);
1353
1354 if (type == GAIM_PROXY_USE_GLOBAL || type == GAIM_PROXY_NONE ||
1355 type == GAIM_PROXY_USE_ENVVAR) {
1356 gtk_widget_hide_all(vbox2);
1357 }
1358 else {
1359 const char *value;
1360 int int_val;
1361
1362 if ((value = gaim_proxy_info_get_host(proxy_info)) != NULL)
1363 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_host_entry), value);
1364
1365 if ((int_val = gaim_proxy_info_get_port(proxy_info)) != 0) {
1366 char buf[32];
1367
1368 g_snprintf(buf, sizeof(buf), "%d", int_val);
1369
1370 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_port_entry), buf);
1371 }
1372
1373 if ((value = gaim_proxy_info_get_username(proxy_info)) != NULL)
1374 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_user_entry), value);
1375
1376 if ((value = gaim_proxy_info_get_password(proxy_info)) != NULL)
1377 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_pass_entry), value);
1378 }
1379 }
1380 else {
1381 dialog->new_proxy_type = GAIM_PROXY_USE_GLOBAL;
1382 gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->proxy_dropdown),
1383 dialog->new_proxy_type + 1);
1384 gtk_widget_hide_all(vbox2);
1385 }
1386
1387 /* Connect signals. */
1388 g_signal_connect(G_OBJECT(dialog->proxy_dropdown), "changed",
1389 G_CALLBACK(proxy_type_changed_cb), dialog);
1390 }
1391
1392 static void
1393 account_win_destroy_cb(GtkWidget *w, GdkEvent *event,
1394 AccountPrefsDialog *dialog)
1395 {
1396 g_hash_table_remove(account_pref_wins, dialog->account);
1397
1398 gtk_widget_destroy(dialog->window);
1399
1400 if (dialog->user_split_entries != NULL)
1401 g_list_free(dialog->user_split_entries);
1402
1403 if (dialog->protocol_opt_entries != NULL)
1404 g_list_free(dialog->protocol_opt_entries);
1405
1406 if (dialog->protocol_id != NULL)
1407 g_free(dialog->protocol_id);
1408
1409 if (dialog->icon_path != NULL)
1410 {
1411 const char *icon = gaim_account_get_buddy_icon(dialog->account);
1412 if (dialog->icon_path != NULL && (icon == NULL || strcmp(dialog->icon_path, icon)))
1413 {
1414 /* The user set an icon, which would've been cached by convert_buddy_icon,
1415 * but didn't save the changes. Delete the cache file. */
1416 char *filename = g_build_filename(gaim_buddy_icons_get_cache_dir(), dialog->icon_path, NULL);
1417 g_unlink(filename);
1418 g_free(filename);
1419 }
1420
1421 g_free(dialog->icon_path);
1422 }
1423
1424 if (dialog->icon_filesel)
1425 gtk_widget_destroy(dialog->icon_filesel);
1426
1427 gaim_signals_disconnect_by_handle(dialog);
1428
1429 g_free(dialog);
1430 }
1431
1432 static void
1433 cancel_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog)
1434 {
1435 account_win_destroy_cb(NULL, NULL, dialog);
1436 }
1437
1438 static GaimAccount*
1439 ok_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog)
1440 {
1441 GaimProxyInfo *proxy_info = NULL;
1442 GList *l, *l2;
1443 const char *value;
1444 char *username;
1445 char *tmp;
1446 gboolean new = FALSE;
1447 GaimAccount *account;
1448
1449 if (dialog->account == NULL)
1450 {
1451 const char *screenname;
1452
1453 screenname = gtk_entry_get_text(GTK_ENTRY(dialog->screenname_entry));
1454 account = gaim_account_new(screenname, dialog->protocol_id);
1455 new = TRUE;
1456 }
1457 else
1458 {
1459 account = dialog->account;
1460
1461 /* Protocol */
1462 gaim_account_set_protocol_id(account, dialog->protocol_id);
1463 }
1464
1465 /* Alias */
1466 value = gtk_entry_get_text(GTK_ENTRY(dialog->alias_entry));
1467
1468 if (*value != '\0')
1469 gaim_account_set_alias(account, value);
1470 else
1471 gaim_account_set_alias(account, NULL);
1472
1473 /* Buddy Icon */
1474 gaim_account_set_buddy_icon(account, dialog->icon_path);
1475
1476 /* Remember Password */
1477 gaim_account_set_remember_password(account,
1478 gtk_toggle_button_get_active(
1479 GTK_TOGGLE_BUTTON(dialog->remember_pass_check)));
1480
1481 /* Check Mail */
1482 if (dialog->prpl_info && dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK)
1483 gaim_account_set_check_mail(account,
1484 gtk_toggle_button_get_active(
1485 GTK_TOGGLE_BUTTON(dialog->new_mail_check)));
1486
1487 /* Password */
1488 value = gtk_entry_get_text(GTK_ENTRY(dialog->password_entry));
1489
1490 /*
1491 * We set the password if this is a new account because new accounts
1492 * will be set to online, and if the user has entered a password into
1493 * the account editor (but has not checked the 'save' box), then we
1494 * don't want to prompt them.
1495 */
1496 if ((gaim_account_get_remember_password(account) || new) && (*value != '\0'))
1497 gaim_account_set_password(account, value);
1498 else
1499 gaim_account_set_password(account, NULL);
1500
1501 /* Build the username string. */
1502 username =
1503 g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->screenname_entry)));
1504
1505 if (dialog->prpl_info != NULL)
1506 {
1507 for (l = dialog->prpl_info->user_splits,
1508 l2 = dialog->user_split_entries;
1509 l != NULL && l2 != NULL;
1510 l = l->next, l2 = l2->next)
1511 {
1512 GaimAccountUserSplit *split = l->data;
1513 GtkEntry *entry = l2->data;
1514 char sep[2] = " ";
1515
1516 value = gtk_entry_get_text(entry);
1517
1518 *sep = gaim_account_user_split_get_separator(split);
1519
1520 tmp = g_strconcat(username, sep,
1521 (*value ? value :
1522 gaim_account_user_split_get_default_value(split)),
1523 NULL);
1524
1525 g_free(username);
1526 username = tmp;
1527 }
1528 }
1529
1530 gaim_account_set_username(account, username);
1531 g_free(username);
1532
1533 /* Add the protocol settings */
1534 if (dialog->prpl_info) {
1535 for (l = dialog->prpl_info->protocol_options,
1536 l2 = dialog->protocol_opt_entries;
1537 l != NULL && l2 != NULL;
1538 l = l->next, l2 = l2->next) {
1539
1540 GaimPrefType type;
1541 GaimAccountOption *option = l->data;
1542 GtkWidget *widget = l2->data;
1543 GtkTreeIter iter;
1544 const char *setting;
1545 int int_value;
1546 gboolean bool_value;
1547
1548 type = gaim_account_option_get_type(option);
1549
1550 setting = gaim_account_option_get_setting(option);
1551
1552 switch (type) {
1553 case GAIM_PREF_STRING:
1554 value = gtk_entry_get_text(GTK_ENTRY(widget));
1555 gaim_account_set_string(account, setting, value);
1556 break;
1557
1558 case GAIM_PREF_INT:
1559 int_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
1560 gaim_account_set_int(account, setting, int_value);
1561 break;
1562
1563 case GAIM_PREF_BOOLEAN:
1564 bool_value =
1565 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
1566 gaim_account_set_bool(account, setting, bool_value);
1567 break;
1568
1569 case GAIM_PREF_STRING_LIST:
1570 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter);
1571 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)), &iter, 1, &value, -1);
1572 gaim_account_set_string(dialog->account, setting, value);
1573 break;
1574
1575 default:
1576 break;
1577 }
1578 }
1579 }
1580
1581 /* Set the proxy stuff. */
1582 if (dialog->new_proxy_type == GAIM_PROXY_USE_GLOBAL) {
1583 gaim_account_set_proxy_info(account, NULL);
1584 }
1585 else {
1586 proxy_info = gaim_account_get_proxy_info(account);
1587
1588 /* Create the proxy info if it doesn't exist. */
1589 if (proxy_info == NULL) {
1590 proxy_info = gaim_proxy_info_new();
1591 gaim_account_set_proxy_info(account, proxy_info);
1592 }
1593
1594 /* Set the proxy info type. */
1595 gaim_proxy_info_set_type(proxy_info, dialog->new_proxy_type);
1596
1597 /* Host */
1598 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_host_entry));
1599
1600 if (*value != '\0')
1601 gaim_proxy_info_set_host(proxy_info, value);
1602 else
1603 gaim_proxy_info_set_host(proxy_info, NULL);
1604
1605 /* Port */
1606 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_port_entry));
1607
1608 if (*value != '\0')
1609 gaim_proxy_info_set_port(proxy_info, atoi(value));
1610 else
1611 gaim_proxy_info_set_port(proxy_info, 0);
1612
1613 /* Username */
1614 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_user_entry));
1615
1616 if (*value != '\0')
1617 gaim_proxy_info_set_username(proxy_info, value);
1618 else
1619 gaim_proxy_info_set_username(proxy_info, NULL);
1620
1621 /* Password */
1622 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_pass_entry));
1623
1624 if (*value != '\0')
1625 gaim_proxy_info_set_password(proxy_info, value);
1626 else
1627 gaim_proxy_info_set_password(proxy_info, NULL);
1628 }
1629
1630 /* We no longer need the data from the dialog window */
1631 account_win_destroy_cb(NULL, NULL, dialog);
1632
1633 /* If this is a new account, add it to our list */
1634 if (new)
1635 gaim_accounts_add(account);
1636 else
1637 gaim_signal_emit(gaim_gtk_account_get_handle(), "account-modified", account);
1638
1639 /* If this is a new account, then sign on! */
1640 if (new) {
1641 const GaimSavedStatus *saved_status;
1642
1643 saved_status = gaim_savedstatus_get_current();
1644 if (saved_status != NULL) {
1645 gaim_savedstatus_activate_for_account(saved_status, account);
1646 gaim_account_set_enabled(account, GAIM_GTK_UI, TRUE);
1647 }
1648 }
1649
1650 return account;
1651 }
1652
1653 static void
1654 register_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog)
1655 {
1656 GaimAccount *account = ok_account_prefs_cb(NULL, dialog);
1657
1658 gaim_account_register(account);
1659 }
1660
1661
1662 static const GtkTargetEntry dnd_targets[] = {
1663 {"text/plain", 0, 0},
1664 {"text/uri-list", 0, 1},
1665 {"STRING", 0, 2}
1666 };
1667
1668 void
1669 gaim_gtk_account_dialog_show(GaimGtkAccountDialogType type,
1670 GaimAccount *account)
1671 {
1672 AccountPrefsDialog *dialog;
1673 GtkWidget *win;
1674 GtkWidget *main_vbox;
1675 GtkWidget *vbox;
1676 GtkWidget *bbox;
1677 GtkWidget *dbox;
1678 GtkWidget *notebook;
1679 GtkWidget *button;
1680
1681 if (accounts_window != NULL && account != NULL &&
1682 (dialog = g_hash_table_lookup(account_pref_wins, account)) != NULL)
1683 {
1684 gtk_window_present(GTK_WINDOW(dialog->window));
1685 return;
1686 }
1687
1688 dialog = g_new0(AccountPrefsDialog, 1);
1689
1690 if (accounts_window != NULL && account != NULL)
1691 {
1692 g_hash_table_insert(account_pref_wins, account, dialog);
1693 }
1694
1695 dialog->account = account;
1696 dialog->type = type;
1697 dialog->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1698
1699 if (dialog->account == NULL) {
1700 /* Select the first prpl in the list*/
1701 GList *prpl_list = gaim_plugins_get_protocols();
1702 if (prpl_list != NULL)
1703 dialog->protocol_id = g_strdup(((GaimPlugin *) prpl_list->data)->info->id);
1704 }
1705 else
1706 {
1707 dialog->protocol_id =
1708 g_strdup(gaim_account_get_protocol_id(dialog->account));
1709 }
1710
1711 if ((dialog->plugin = gaim_find_prpl(dialog->protocol_id)) != NULL)
1712 dialog->prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(dialog->plugin);
1713
1714
1715 dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1716 gtk_window_set_role(GTK_WINDOW(win), "account");
1717
1718 if (type == GAIM_GTK_ADD_ACCOUNT_DIALOG)
1719 gtk_window_set_title(GTK_WINDOW(win), _("Add Account"));
1720 else
1721 gtk_window_set_title(GTK_WINDOW(win), _("Modify Account"));
1722
1723 gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
1724
1725 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER);
1726
1727 g_signal_connect(G_OBJECT(win), "delete_event",
1728 G_CALLBACK(account_win_destroy_cb), dialog);
1729
1730 /* Setup the vbox */
1731 main_vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
1732 gtk_container_add(GTK_CONTAINER(win), main_vbox);
1733 gtk_widget_show(main_vbox);
1734
1735 notebook = gtk_notebook_new();
1736 gtk_box_pack_start(GTK_BOX(main_vbox), notebook, FALSE, FALSE, 0);
1737 gtk_widget_show(GTK_WIDGET(notebook));
1738
1739 /* Setup the inner vbox */
1740 dialog->top_vbox = vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
1741 gtk_container_set_border_width(GTK_CONTAINER(vbox), GAIM_HIG_BORDER);
1742 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox,
1743 gtk_label_new_with_mnemonic(_("_Basic")));
1744 gtk_widget_show(vbox);
1745
1746 /* Setup the top frames. */
1747 add_login_options(dialog, vbox);
1748 add_user_options(dialog, vbox);
1749
1750 /* Setup the page with 'Advanced'. */
1751 dialog->bottom_vbox = dbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
1752 gtk_container_set_border_width(GTK_CONTAINER(dbox), GAIM_HIG_BORDER);
1753 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dbox,
1754 gtk_label_new_with_mnemonic(_("_Advanced")));
1755 gtk_widget_show(dbox);
1756
1757 /** Setup the bottom frames. */
1758 add_protocol_options(dialog, dbox);
1759 add_proxy_options(dialog, dbox);
1760
1761 /* Setup the button box */
1762 bbox = gtk_hbutton_box_new();
1763 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE);
1764 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1765 gtk_box_pack_end(GTK_BOX(main_vbox), bbox, FALSE, TRUE, 0);
1766 gtk_widget_show(bbox);
1767
1768 /* Register button */
1769 button = gtk_button_new_with_label(_("Register"));
1770 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1771 gtk_widget_show(button);
1772
1773 g_signal_connect(G_OBJECT(button), "clicked",
1774 G_CALLBACK(register_account_prefs_cb), dialog);
1775
1776 dialog->register_button = button;
1777
1778 if (dialog->account == NULL)
1779 gtk_widget_set_sensitive(button, FALSE);
1780
1781 if (!dialog->prpl_info || !dialog->prpl_info->register_user)
1782 gtk_widget_hide(button);
1783
1784 /* Cancel button */
1785 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1786 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1787 gtk_widget_show(button);
1788
1789 g_signal_connect(G_OBJECT(button), "clicked",
1790 G_CALLBACK(cancel_account_prefs_cb), dialog);
1791
1792 /* Save button */
1793 button = gtk_button_new_from_stock(GTK_STOCK_SAVE);
1794 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1795
1796 if (dialog->account == NULL)
1797 gtk_widget_set_sensitive(button, FALSE);
1798
1799 gtk_widget_show(button);
1800
1801 dialog->ok_button = button;
1802
1803 /* Set up DND */
1804 gtk_drag_dest_set(dialog->window,
1805 GTK_DEST_DEFAULT_MOTION |
1806 GTK_DEST_DEFAULT_DROP,
1807 dnd_targets,
1808 sizeof(dnd_targets) / sizeof(GtkTargetEntry),
1809 GDK_ACTION_COPY);
1810
1811 g_signal_connect(G_OBJECT(dialog->window), "drag_data_received",
1812 G_CALLBACK(account_dnd_recv), dialog);
1813
1814 g_signal_connect(G_OBJECT(button), "clicked",
1815 G_CALLBACK(ok_account_prefs_cb), dialog);
1816
1817 /* Show the window. */
1818 gtk_widget_show(win);
1819 }
1820
1821 /**************************************************************************
1822 * Accounts Dialog
1823 **************************************************************************/
1824 static void
1825 signed_on_off_cb(GaimConnection *gc, gpointer user_data)
1826 {
1827 GaimAccount *account;
1828 GaimGtkPulseData *pulse_data;
1829 GtkTreeModel *model;
1830 GtkTreeIter iter;
1831 GdkPixbuf *pixbuf, *scale = NULL;
1832 size_t index;
1833
1834 /* Don't need to do anything if the accounts window is not visible */
1835 if (accounts_window == NULL)
1836 return;
1837
1838 account = gaim_connection_get_account(gc);
1839 model = GTK_TREE_MODEL(accounts_window->model);
1840 index = g_list_index(gaim_accounts_get_all(), account);
1841
1842 if (gtk_tree_model_iter_nth_child(model, &iter, NULL, index))
1843 {
1844 gtk_tree_model_get(GTK_TREE_MODEL(accounts_window->model), &iter,
1845 COLUMN_PULSE_DATA, &pulse_data, -1);
1846
1847 if (pulse_data != NULL)
1848 {
1849 if (pulse_data->timeout > 0)
1850 g_source_remove(pulse_data->timeout);
1851
1852 g_object_unref(G_OBJECT(pulse_data->online_pixbuf));
1853
1854 g_free(pulse_data);
1855 }
1856
1857 pixbuf = gaim_gtk_create_prpl_icon(account);
1858
1859 if (pixbuf != NULL)
1860 {
1861 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16,
1862 GDK_INTERP_BILINEAR);
1863
1864 if (gaim_account_is_disconnected(account))
1865 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE);
1866 }
1867 gtk_list_store_set(accounts_window->model, &iter,
1868 COLUMN_ICON, scale,
1869 COLUMN_PULSE_DATA, NULL,
1870 -1);
1871
1872
1873 if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf));
1874 if (scale != NULL) g_object_unref(G_OBJECT(scale));
1875 }
1876 }
1877
1878 /*
1879 * Get the GtkTreeIter of the specified account in the
1880 * GtkListStore
1881 */
1882 static gboolean
1883 accounts_window_find_account_in_treemodel(GtkTreeIter *iter, GaimAccount *account)
1884 {
1885 GtkTreeModel *model;
1886 GaimAccount *cur;
1887
1888 g_return_val_if_fail(account != NULL, FALSE);
1889 g_return_val_if_fail(accounts_window != NULL, FALSE);
1890
1891 model = GTK_TREE_MODEL(accounts_window->model);
1892
1893 if (!gtk_tree_model_get_iter_first(model, iter))
1894 return FALSE;
1895
1896 gtk_tree_model_get(model, iter, COLUMN_DATA, &cur, -1);
1897 if (cur == account)
1898 return TRUE;
1899
1900 while (gtk_tree_model_iter_next(model, iter))
1901 {
1902 gtk_tree_model_get(model, iter, COLUMN_DATA, &cur, -1);
1903 if (cur == account)
1904 return TRUE;
1905 }
1906
1907 return FALSE;
1908 }
1909
1910 static void
1911 account_removed_cb(GaimAccount *account, gpointer user_data)
1912 {
1913 AccountPrefsDialog *dialog;
1914 GtkTreeIter iter;
1915
1916 /* If the account was being modified, close the edit window */
1917 if ((dialog = g_hash_table_lookup(account_pref_wins, account)) != NULL)
1918 account_win_destroy_cb(NULL, NULL, dialog);
1919
1920 if (accounts_window == NULL)
1921 return;
1922
1923 /* Remove the account from the GtkListStore */
1924 if (accounts_window_find_account_in_treemodel(&iter, account))
1925 gtk_list_store_remove(accounts_window->model, &iter);
1926 }
1927
1928 static void
1929 account_abled_cb(GaimAccount *account, gpointer user_data)
1930 {
1931 GtkTreeIter iter;
1932
1933 if (accounts_window == NULL)
1934 return;
1935
1936 /* update the account in the GtkListStore */
1937 if (accounts_window_find_account_in_treemodel(&iter, account))
1938 gtk_list_store_set(accounts_window->model, &iter,
1939 COLUMN_ENABLED, GPOINTER_TO_INT(user_data),
1940 -1);
1941 }
1942
1943 static void
1944 drag_data_get_cb(GtkWidget *widget, GdkDragContext *ctx,
1945 GtkSelectionData *data, guint info, guint time,
1946 AccountsWindow *dialog)
1947 {
1948 if (data->target == gdk_atom_intern("GAIM_ACCOUNT", FALSE)) {
1949 GtkTreeRowReference *ref;
1950 GtkTreePath *source_row;
1951 GtkTreeIter iter;
1952 GaimAccount *account = NULL;
1953 GValue val;
1954
1955 ref = g_object_get_data(G_OBJECT(ctx), "gtk-tree-view-source-row");
1956 source_row = gtk_tree_row_reference_get_path(ref);
1957
1958 if (source_row == NULL)
1959 return;
1960
1961 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter,
1962 source_row);
1963 val.g_type = 0;
1964 gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
1965 COLUMN_DATA, &val);
1966
1967 dialog->drag_iter = iter;
1968
1969 account = g_value_get_pointer(&val);
1970
1971 gtk_selection_data_set(data, gdk_atom_intern("GAIM_ACCOUNT", FALSE),
1972 8, (void *)&account, sizeof(account));
1973
1974 gtk_tree_path_free(source_row);
1975 }
1976 }
1977
1978 static void
1979 move_account_after(GtkListStore *store, GtkTreeIter *iter,
1980 GtkTreeIter *position)
1981 {
1982 GtkTreeIter new_iter;
1983 GaimAccount *account;
1984
1985 gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
1986 COLUMN_DATA, &account,
1987 -1);
1988
1989 gtk_list_store_insert_after(store, &new_iter, position);
1990
1991 set_account(store, &new_iter, account);
1992
1993 gtk_list_store_remove(store, iter);
1994 }
1995
1996 static void
1997 move_account_before(GtkListStore *store, GtkTreeIter *iter,
1998 GtkTreeIter *position)
1999 {
2000 GtkTreeIter new_iter;
2001 GaimAccount *account;
2002
2003 gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
2004 COLUMN_DATA, &account,
2005 -1);
2006
2007 gtk_list_store_insert_before(store, &new_iter, position);
2008
2009 set_account(store, &new_iter, account);
2010
2011 gtk_list_store_remove(store, iter);
2012 }
2013
2014 static void
2015 drag_data_received_cb(GtkWidget *widget, GdkDragContext *ctx,
2016 guint x, guint y, GtkSelectionData *sd,
2017 guint info, guint t, AccountsWindow *dialog)
2018 {
2019 if (sd->target == gdk_atom_intern("GAIM_ACCOUNT", FALSE) && sd->data) {
2020 gint dest_index;
2021 GaimAccount *a = NULL;
2022 GtkTreePath *path = NULL;
2023 GtkTreeViewDropPosition position;
2024
2025 memcpy(&a, sd->data, sizeof(a));
2026
2027 if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), x, y,
2028 &path, &position)) {
2029
2030 GtkTreeIter iter;
2031 GaimAccount *account;
2032 GValue val;
2033
2034 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path);
2035 val.g_type = 0;
2036 gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
2037 COLUMN_DATA, &val);
2038
2039 account = g_value_get_pointer(&val);
2040
2041 switch (position) {
2042 case GTK_TREE_VIEW_DROP_AFTER:
2043 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2044 move_account_after(dialog->model, &dialog->drag_iter,
2045 &iter);
2046 dest_index = g_list_index(gaim_accounts_get_all(),
2047 account) + 1;
2048 break;
2049
2050 case GTK_TREE_VIEW_DROP_BEFORE:
2051 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2052 dest_index = g_list_index(gaim_accounts_get_all(),
2053 account);
2054
2055 move_account_before(dialog->model, &dialog->drag_iter,
2056 &iter);
2057 break;
2058
2059 default:
2060 return;
2061 }
2062
2063 gaim_accounts_reorder(a, dest_index);
2064 }
2065 }
2066 }
2067
2068 static gint
2069 accedit_win_destroy_cb(GtkWidget *w, GdkEvent *event, AccountsWindow *dialog)
2070 {
2071 gaim_gtk_accounts_window_hide();
2072
2073 return 0;
2074 }
2075
2076 static gboolean
2077 configure_cb(GtkWidget *w, GdkEventConfigure *event, AccountsWindow *dialog)
2078 {
2079 if (GTK_WIDGET_VISIBLE(w)) {
2080 int old_width = gaim_prefs_get_int("/gaim/gtk/accounts/dialog/width");
2081 int col_width;
2082 int difference;
2083
2084 gaim_prefs_set_int("/gaim/gtk/accounts/dialog/width", event->width);
2085 gaim_prefs_set_int("/gaim/gtk/accounts/dialog/height", event->height);
2086
2087 col_width = gtk_tree_view_column_get_width(dialog->screenname_col);
2088
2089 if (col_width == 0)
2090 return FALSE;
2091
2092 difference = (MAX(old_width, event->width) -
2093 MIN(old_width, event->width));
2094
2095 if (difference == 0)
2096 return FALSE;
2097
2098 if (old_width < event->width)
2099 gtk_tree_view_column_set_min_width(dialog->screenname_col,
2100 col_width + difference);
2101 else
2102 gtk_tree_view_column_set_max_width(dialog->screenname_col,
2103 col_width - difference);
2104 }
2105
2106 return FALSE;
2107 }
2108
2109 static void
2110 add_account_cb(GtkWidget *w, AccountsWindow *dialog)
2111 {
2112 gaim_gtk_account_dialog_show(GAIM_GTK_ADD_ACCOUNT_DIALOG, NULL);
2113 }
2114
2115 static void
2116 modify_account_sel(GtkTreeModel *model, GtkTreePath *path,
2117 GtkTreeIter *iter, gpointer data)
2118 {
2119 GaimAccount *account;
2120
2121 gtk_tree_model_get(model, iter, COLUMN_DATA, &account, -1);
2122
2123 if (account != NULL)
2124 gaim_gtk_account_dialog_show(GAIM_GTK_MODIFY_ACCOUNT_DIALOG, account);
2125 }
2126
2127 static void
2128 modify_account_cb(GtkWidget *w, AccountsWindow *dialog)
2129 {
2130 GtkTreeSelection *selection;
2131
2132 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
2133
2134 gtk_tree_selection_selected_foreach(selection, modify_account_sel, dialog);
2135 }
2136
2137 static void
2138 delete_account_cb(GaimAccount *account)
2139 {
2140 gaim_accounts_delete(account);
2141 }
2142
2143 static void
2144 ask_delete_account_sel(GtkTreeModel *model, GtkTreePath *path,
2145 GtkTreeIter *iter, gpointer data)
2146 {
2147 GaimAccount *account;
2148
2149 gtk_tree_model_get(model, iter, COLUMN_DATA, &account, -1);
2150
2151 if (account != NULL) {
2152 char *buf;
2153
2154 buf = g_strdup_printf(_("Are you sure you want to delete %s?"),
2155 gaim_account_get_username(account));
2156
2157 gaim_request_close_with_handle(account);
2158 gaim_request_action(account, NULL, buf, NULL, 0, account, 2,
2159 _("Delete"), delete_account_cb,
2160 _("Cancel"), NULL);
2161 g_free(buf);
2162 }
2163 }
2164
2165 static void
2166 ask_delete_account_cb(GtkWidget *w, AccountsWindow *dialog)
2167 {
2168 GtkTreeSelection *selection;
2169
2170 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
2171
2172 gtk_tree_selection_selected_foreach(selection, ask_delete_account_sel,
2173 dialog);
2174 }
2175
2176 static void
2177 close_accounts_cb(GtkWidget *w, AccountsWindow *dialog)
2178 {
2179 gtk_widget_destroy(dialog->window);
2180
2181 gaim_gtk_accounts_window_hide();
2182 }
2183
2184
2185 static void
2186 enabled_cb(GtkCellRendererToggle *renderer, gchar *path_str,
2187 gpointer data)
2188 {
2189 AccountsWindow *dialog = (AccountsWindow *)data;
2190 GaimAccount *account;
2191 GtkTreeModel *model = GTK_TREE_MODEL(dialog->model);
2192 GtkTreeIter iter;
2193 gboolean enabled;
2194 const GaimSavedStatus *saved_status;
2195
2196 gtk_tree_model_get_iter_from_string(model, &iter, path_str);
2197 gtk_tree_model_get(model, &iter,
2198 COLUMN_DATA, &account,
2199 COLUMN_ENABLED, &enabled,
2200 -1);
2201
2202 /* Set the statuses for this account to the current status */
2203 saved_status = gaim_savedstatus_get_current();
2204 gaim_savedstatus_activate_for_account(saved_status, account);
2205
2206 gaim_account_set_enabled(account, GAIM_GTK_UI, !enabled);
2207 }
2208
2209 static void
2210 add_columns(GtkWidget *treeview, AccountsWindow *dialog)
2211 {
2212 GtkCellRenderer *renderer;
2213 GtkTreeViewColumn *column;
2214
2215 /* Screen Name column */
2216 column = gtk_tree_view_column_new();
2217 gtk_tree_view_column_set_title(column, _("Screen Name"));
2218 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
2219 gtk_tree_view_column_set_resizable(column, TRUE);
2220
2221 /* Icon */
2222 renderer = gtk_cell_renderer_pixbuf_new();
2223 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2224 gtk_tree_view_column_add_attribute(column, renderer,
2225 "pixbuf", COLUMN_ICON);
2226
2227 /* Screen Name */
2228 renderer = gtk_cell_renderer_text_new();
2229 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2230 gtk_tree_view_column_add_attribute(column, renderer,
2231 "text", COLUMN_SCREENNAME);
2232 dialog->screenname_col = column;
2233
2234 /* Enabled */
2235 renderer = gtk_cell_renderer_toggle_new();
2236
2237 g_signal_connect(G_OBJECT(renderer), "toggled",
2238 G_CALLBACK(enabled_cb), dialog);
2239
2240 column = gtk_tree_view_column_new_with_attributes(_("Enabled"),
2241 renderer, "active", COLUMN_ENABLED, NULL);
2242
2243 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
2244 gtk_tree_view_column_set_resizable(column, TRUE);
2245
2246 /* Protocol name */
2247 column = gtk_tree_view_column_new();
2248 gtk_tree_view_column_set_title(column, _("Protocol"));
2249 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
2250 gtk_tree_view_column_set_resizable(column, TRUE);
2251
2252 renderer = gtk_cell_renderer_text_new();
2253 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2254 gtk_tree_view_column_add_attribute(column, renderer,
2255 "text", COLUMN_PROTOCOL);
2256 }
2257
2258 static void
2259 set_account(GtkListStore *store, GtkTreeIter *iter, GaimAccount *account)
2260 {
2261 GdkPixbuf *pixbuf;
2262 GdkPixbuf *scale;
2263
2264 scale = NULL;
2265
2266 pixbuf = gaim_gtk_create_prpl_icon(account);
2267
2268 if (pixbuf != NULL)
2269 {
2270 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR);
2271
2272 if (gaim_account_is_disconnected(account))
2273 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE);
2274 }
2275
2276 gtk_list_store_set(store, iter,
2277 COLUMN_ICON, scale,
2278 COLUMN_SCREENNAME, gaim_account_get_username(account),
2279 COLUMN_ENABLED, gaim_account_get_enabled(account, GAIM_GTK_UI),
2280 COLUMN_PROTOCOL, gaim_account_get_protocol_name(account),
2281 COLUMN_DATA, account,
2282 -1);
2283
2284 if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf));
2285 if (scale != NULL) g_object_unref(G_OBJECT(scale));
2286 }
2287
2288 static void
2289 add_account_to_liststore(GaimAccount *account, gpointer user_data)
2290 {
2291 GtkTreeIter iter;
2292
2293 if (accounts_window == NULL)
2294 return;
2295
2296 gtk_list_store_append(accounts_window->model, &iter);
2297
2298 set_account(accounts_window->model, &iter, account);
2299 }
2300
2301 static void
2302 populate_accounts_list(AccountsWindow *dialog)
2303 {
2304 GList *l;
2305
2306 gtk_list_store_clear(dialog->model);
2307
2308 for (l = gaim_accounts_get_all(); l != NULL; l = l->next)
2309 add_account_to_liststore((GaimAccount *)l->data, NULL);
2310 }
2311
2312 #if !GTK_CHECK_VERSION(2,2,0)
2313 static void
2314 get_selected_helper(GtkTreeModel *model, GtkTreePath *path,
2315 GtkTreeIter *iter, gpointer user_data)
2316 {
2317 *((gboolean *)user_data) = TRUE;
2318 }
2319 #endif
2320
2321 static void
2322 account_selected_cb(GtkTreeSelection *sel, AccountsWindow *dialog)
2323 {
2324 gboolean selected = FALSE;
2325
2326 #if GTK_CHECK_VERSION(2,2,0)
2327 selected = (gtk_tree_selection_count_selected_rows(sel) > 0);
2328 #else
2329 gtk_tree_selection_selected_foreach(sel, get_selected_helper, &selected);
2330 #endif
2331
2332 gtk_widget_set_sensitive(dialog->modify_button, selected);
2333 gtk_widget_set_sensitive(dialog->delete_button, selected);
2334 }
2335
2336 static gboolean
2337 account_treeview_double_click_cb(GtkTreeView *treeview, GdkEventButton *event, gpointer user_data)
2338 {
2339 AccountsWindow *dialog;
2340 GtkTreePath *path;
2341 GtkTreeViewColumn *column;
2342 GtkTreeIter iter;
2343 GaimAccount *account;
2344 const gchar *title;
2345
2346 dialog = (AccountsWindow *)user_data;
2347
2348 /* Figure out which node was clicked */
2349 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dialog->treeview), event->x, event->y, &path, &column, NULL, NULL))
2350 return FALSE;
2351 title = gtk_tree_view_column_get_title(column);
2352 /* The -1 is required because the first two columns of the list
2353 * store are displayed as only one column in the tree view. */
2354 column = gtk_tree_view_get_column(treeview, COLUMN_ENABLED-1);
2355 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path);
2356 gtk_tree_path_free(path);
2357 gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_DATA, &account, -1);
2358
2359 if ((account != NULL) && (event->button == 1) &&
2360 (event->type == GDK_2BUTTON_PRESS) &&
2361 (strcmp(gtk_tree_view_column_get_title(column), title)))
2362 {
2363 gaim_gtk_account_dialog_show(GAIM_GTK_MODIFY_ACCOUNT_DIALOG, account);
2364 return TRUE;
2365 }
2366
2367 return FALSE;
2368 }
2369
2370 static GtkWidget *
2371 create_accounts_list(AccountsWindow *dialog)
2372 {
2373 GtkWidget *sw;
2374 GtkWidget *treeview;
2375 GtkTreeSelection *sel;
2376 GtkTargetEntry gte[] = {{"GAIM_ACCOUNT", GTK_TARGET_SAME_APP, 0}};
2377
2378 /* Create the scrolled window. */
2379 sw = gtk_scrolled_window_new(0, 0);
2380 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
2381 GTK_POLICY_AUTOMATIC,
2382 GTK_POLICY_ALWAYS);
2383 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
2384 GTK_SHADOW_IN);
2385 gtk_widget_show(sw);
2386
2387 /* Create the list model. */
2388 dialog->model = gtk_list_store_new(NUM_COLUMNS,
2389 GDK_TYPE_PIXBUF, G_TYPE_STRING,
2390 G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER,
2391 G_TYPE_POINTER);
2392
2393 /* And now the actual treeview */
2394 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
2395 dialog->treeview = treeview;
2396 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
2397
2398 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
2399 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
2400 g_signal_connect(G_OBJECT(sel), "changed",
2401 G_CALLBACK(account_selected_cb), dialog);
2402
2403 /* Handle double-clicking */
2404 g_signal_connect(G_OBJECT(treeview), "button_press_event",
2405 G_CALLBACK(account_treeview_double_click_cb), dialog);
2406
2407 gtk_container_add(GTK_CONTAINER(sw), treeview);
2408 gtk_widget_show(treeview);
2409
2410 add_columns(treeview, dialog);
2411
2412 populate_accounts_list(dialog);
2413
2414 /* Setup DND. I wanna be an orc! */
2415 gtk_tree_view_enable_model_drag_source(
2416 GTK_TREE_VIEW(treeview), GDK_BUTTON1_MASK, gte,
2417 1, GDK_ACTION_COPY);
2418 gtk_tree_view_enable_model_drag_dest(
2419 GTK_TREE_VIEW(treeview), gte, 1,
2420 GDK_ACTION_COPY | GDK_ACTION_MOVE);
2421
2422 g_signal_connect(G_OBJECT(treeview), "drag-data-received",
2423 G_CALLBACK(drag_data_received_cb), dialog);
2424 g_signal_connect(G_OBJECT(treeview), "drag-data-get",
2425 G_CALLBACK(drag_data_get_cb), dialog);
2426
2427 return sw;
2428 }
2429
2430 static void
2431 account_modified_cb(GaimAccount *account, AccountsWindow *window)
2432 {
2433 GtkTreeIter iter;
2434
2435 if (!accounts_window_find_account_in_treemodel(&iter, account))
2436 return;
2437
2438 set_account(window->model, &iter, account);
2439 }
2440
2441 void
2442 gaim_gtk_accounts_window_show(void)
2443 {
2444 AccountsWindow *dialog;
2445 GtkWidget *win;
2446 GtkWidget *vbox;
2447 GtkWidget *bbox;
2448 GtkWidget *sw;
2449 GtkWidget *button;
2450 int width, height;
2451
2452 if (accounts_window != NULL) {
2453 gtk_window_present(GTK_WINDOW(accounts_window->window));
2454 return;
2455 }
2456
2457 accounts_window = dialog = g_new0(AccountsWindow, 1);
2458
2459 width = gaim_prefs_get_int("/gaim/gtk/accounts/dialog/width");
2460 height = gaim_prefs_get_int("/gaim/gtk/accounts/dialog/height");
2461
2462 dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2463 gtk_window_set_default_size(GTK_WINDOW(win), width, height);
2464 gtk_window_set_role(GTK_WINDOW(win), "accounts");
2465 gtk_window_set_title(GTK_WINDOW(win), _("Accounts"));
2466 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER);
2467
2468 g_signal_connect(G_OBJECT(win), "delete_event",
2469 G_CALLBACK(accedit_win_destroy_cb), accounts_window);
2470 g_signal_connect(G_OBJECT(win), "configure_event",
2471 G_CALLBACK(configure_cb), accounts_window);
2472
2473 /* Setup the vbox */
2474 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
2475 gtk_container_add(GTK_CONTAINER(win), vbox);
2476 gtk_widget_show(vbox);
2477
2478 /* Setup the scrolled window that will contain the list of accounts. */
2479 sw = create_accounts_list(dialog);
2480 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
2481 gtk_widget_show(sw);
2482
2483 /* Button box. */
2484 bbox = gtk_hbutton_box_new();
2485 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE);
2486 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
2487 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
2488 gtk_widget_show(bbox);
2489
2490 /* Add button */
2491 button = gtk_button_new_from_stock(GTK_STOCK_ADD);
2492 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
2493 gtk_widget_show(button);
2494
2495 g_signal_connect(G_OBJECT(button), "clicked",
2496 G_CALLBACK(add_account_cb), dialog);
2497
2498 /* Modify button */
2499 button = gtk_button_new_from_stock(GAIM_STOCK_MODIFY);
2500 dialog->modify_button = button;
2501 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
2502 gtk_widget_set_sensitive(button, FALSE);
2503 gtk_widget_show(button);
2504
2505 g_signal_connect(G_OBJECT(button), "clicked",
2506 G_CALLBACK(modify_account_cb), dialog);
2507
2508 /* Delete button */
2509 button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
2510 dialog->delete_button = button;
2511 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
2512 gtk_widget_set_sensitive(button, FALSE);
2513 gtk_widget_show(button);
2514
2515 g_signal_connect(G_OBJECT(button), "clicked",
2516 G_CALLBACK(ask_delete_account_cb), dialog);
2517
2518 /* Close button */
2519 button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
2520 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
2521 gtk_widget_show(button);
2522
2523 g_signal_connect(G_OBJECT(button), "clicked",
2524 G_CALLBACK(close_accounts_cb), dialog);
2525
2526 gaim_signal_connect(gaim_gtk_account_get_handle(), "account-modified",
2527 accounts_window,
2528 GAIM_CALLBACK(account_modified_cb), accounts_window);
2529
2530 gtk_widget_show(win);
2531 }
2532
2533 void
2534 gaim_gtk_accounts_window_hide(void)
2535 {
2536 if (accounts_window == NULL)
2537 return;
2538
2539 gaim_signals_disconnect_by_handle(accounts_window);
2540
2541 g_free(accounts_window);
2542 accounts_window = NULL;
2543
2544 /* See if we're the main window here. */
2545 if (GAIM_GTK_BLIST(gaim_get_blist())->window == NULL &&
2546 gaim_connections_get_all() == NULL) {
2547
2548 gaim_core_quit();
2549 }
2550 }
2551
2552 static void
2553 free_add_user_data(GaimGtkAccountAddUserData *data)
2554 {
2555 g_free(data->username);
2556
2557 if (data->alias != NULL)
2558 g_free(data->alias);
2559
2560 g_free(data);
2561 }
2562
2563 static void
2564 add_user_cb(GaimGtkAccountAddUserData *data)
2565 {
2566 GaimConnection *gc = gaim_account_get_connection(data->account);
2567
2568 if (g_list_find(gaim_connections_get_all(), gc))
2569 {
2570 gaim_blist_request_add_buddy(data->account, data->username,
2571 NULL, data->alias);
2572 }
2573
2574 free_add_user_data(data);
2575 }
2576
2577 static char *
2578 make_info(GaimAccount *account, GaimConnection *gc, const char *remote_user,
2579 const char *id, const char *alias, const char *msg)
2580 {
2581 if (msg != NULL && *msg == '\0')
2582 msg = NULL;
2583
2584 return g_strdup_printf(_("%s%s%s%s has made %s his or her buddy%s%s"),
2585 remote_user,
2586 (alias != NULL ? " (" : ""),
2587 (alias != NULL ? alias : ""),
2588 (alias != NULL ? ")" : ""),
2589 (id != NULL
2590 ? id
2591 : (gaim_connection_get_display_name(gc) != NULL
2592 ? gaim_connection_get_display_name(gc)
2593 : gaim_account_get_username(account))),
2594 (msg != NULL ? ": " : "."),
2595 (msg != NULL ? msg : ""));
2596 }
2597
2598 static void
2599 gaim_gtk_accounts_notify_added(GaimAccount *account, const char *remote_user,
2600 const char *id, const char *alias,
2601 const char *msg)
2602 {
2603 char *buffer;
2604 GaimConnection *gc;
2605
2606 gc = gaim_account_get_connection(account);
2607
2608 buffer = make_info(account, gc, remote_user, id, alias, msg);
2609
2610 gaim_notify_info(NULL, NULL, buffer, NULL);
2611
2612 g_free(buffer);
2613 }
2614
2615 static void
2616 gaim_gtk_accounts_request_add(GaimAccount *account, const char *remote_user,
2617 const char *id, const char *alias,
2618 const char *msg)
2619 {
2620 char *buffer;
2621 GaimConnection *gc;
2622 GaimGtkAccountAddUserData *data;
2623
2624 gc = gaim_account_get_connection(account);
2625
2626 data = g_new0(GaimGtkAccountAddUserData, 1);
2627 data->account = account;
2628 data->username = g_strdup(remote_user);
2629 data->alias = (alias != NULL ? g_strdup(alias) : NULL);
2630
2631 buffer = make_info(account, gc, remote_user, id, alias, msg);
2632
2633 gaim_request_action(NULL, NULL, _("Add buddy to your list?"),
2634 buffer, GAIM_DEFAULT_ACTION_NONE, data, 2,
2635 _("Add"), G_CALLBACK(add_user_cb),
2636 _("Cancel"), G_CALLBACK(free_add_user_data));
2637
2638 g_free(buffer);
2639 }
2640
2641 static GaimAccountUiOps ui_ops =
2642 {
2643 gaim_gtk_accounts_notify_added,
2644 NULL,
2645 gaim_gtk_accounts_request_add
2646 };
2647
2648 GaimAccountUiOps *
2649 gaim_gtk_accounts_get_ui_ops(void)
2650 {
2651 return &ui_ops;
2652 }
2653
2654 void *
2655 gaim_gtk_account_get_handle(void) {
2656 static int handle;
2657
2658 return &handle;
2659 }
2660
2661 void
2662 gaim_gtk_account_init(void)
2663 {
2664 gaim_prefs_add_none("/gaim/gtk/accounts");
2665 gaim_prefs_add_none("/gaim/gtk/accounts/dialog");
2666 gaim_prefs_add_int("/gaim/gtk/accounts/dialog/width", 520);
2667 gaim_prefs_add_int("/gaim/gtk/accounts/dialog/height", 321);
2668
2669 gaim_signal_register(gaim_gtk_account_get_handle(), "account-modified",
2670 gaim_marshal_VOID__POINTER, NULL, 1,
2671 gaim_value_new(GAIM_TYPE_SUBTYPE,
2672 GAIM_SUBTYPE_ACCOUNT));
2673
2674 /* Setup some gaim signal handlers. */
2675 gaim_signal_connect(gaim_connections_get_handle(), "signed-on",
2676 gaim_gtk_account_get_handle(),
2677 GAIM_CALLBACK(signed_on_off_cb), NULL);
2678 gaim_signal_connect(gaim_connections_get_handle(), "signed-off",
2679 gaim_gtk_account_get_handle(),
2680 GAIM_CALLBACK(signed_on_off_cb), NULL);
2681 gaim_signal_connect(gaim_accounts_get_handle(), "account-added",
2682 gaim_gtk_account_get_handle(),
2683 GAIM_CALLBACK(add_account_to_liststore), NULL);
2684 gaim_signal_connect(gaim_accounts_get_handle(), "account-removed",
2685 gaim_gtk_account_get_handle(),
2686 GAIM_CALLBACK(account_removed_cb), NULL);
2687 gaim_signal_connect(gaim_accounts_get_handle(), "account-disabled",
2688 gaim_gtk_account_get_handle(),
2689 GAIM_CALLBACK(account_abled_cb), GINT_TO_POINTER(FALSE));
2690 gaim_signal_connect(gaim_accounts_get_handle(), "account-enabled",
2691 gaim_gtk_account_get_handle(),
2692 GAIM_CALLBACK(account_abled_cb), GINT_TO_POINTER(TRUE));
2693
2694 account_pref_wins =
2695 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
2696 }
2697
2698 void
2699 gaim_gtk_account_uninit(void)
2700 {
2701 /*
2702 * TODO: Need to free all the dialogs in here. Could probably create
2703 * a callback function to use for the free-some-data-function
2704 * parameter of g_hash_table_new_full, above.
2705 */
2706 g_hash_table_destroy(account_pref_wins);
2707
2708 gaim_signals_disconnect_by_handle(gaim_gtk_account_get_handle());
2709 gaim_signals_unregister_by_instance(gaim_gtk_account_get_handle());
2710 }
2711

mercurial