/** * @file gtkaccount.c GTK+ Account Editor UI * @ingroup gtkui * * gaim * * Gaim is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "gtkinternal.h" #include "account.h" #include "accountopt.h" #include "core.h" #include "debug.h" #include "notify.h" #include "plugin.h" #include "prefs.h" #include "prpl.h" #include "request.h" #include "signals.h" #include "util.h" #include "gaim-disclosure.h" #include "gtkaccount.h" #include "gtkblist.h" #include "gtkutils.h" #include "stock.h" #include "ui.h" enum { COLUMN_ICON, COLUMN_SCREENNAME, COLUMN_ONLINE, COLUMN_AUTOLOGIN, COLUMN_PROTOCOL, COLUMN_DATA, COLUMN_PULSE_DATA, NUM_COLUMNS }; typedef struct { GaimAccount *account; char *username; char *alias; } GaimGtkAccountAddUserData; typedef struct { GtkWidget *window; GtkWidget *treeview; GtkWidget *modify_button; GtkWidget *delete_button; GtkListStore *model; GtkTreeIter drag_iter; GtkTreeViewColumn *screenname_col; GHashTable *account_pref_wins; } AccountsWindow; typedef struct { GaimGtkAccountDialogType type; GaimAccount *account; char *protocol_id; GaimPlugin *plugin; GaimPluginProtocolInfo *prpl_info; GaimProxyType new_proxy_type; GList *user_split_entries; GList *protocol_opt_entries; GtkSizeGroup *sg; GtkWidget *window; GtkWidget *top_vbox; GtkWidget *bottom_vbox; GtkWidget *ok_button; GtkWidget *register_button; /* Login Options */ GtkWidget *login_frame; GtkWidget *protocol_menu; GtkWidget *password_box; GtkWidget *screenname_entry; GtkWidget *password_entry; GtkWidget *alias_entry; GtkWidget *remember_pass_check; GtkWidget *auto_login_check; /* User Options */ GtkWidget *user_frame; GtkWidget *new_mail_check; GtkWidget *icon_hbox; GtkWidget *icon_entry; char *icon_path; GtkWidget *icon_filesel; GtkWidget *icon_preview; GtkWidget *icon_text; /* Protocol Options */ GtkWidget *protocol_frame; /* Proxy Options */ GtkWidget *proxy_frame; GtkWidget *proxy_vbox; GtkWidget *proxy_dropdown; #if !GTK_CHECK_VERSION(2,4,0) GtkWidget *proxy_menu; #endif GtkWidget *proxy_host_entry; GtkWidget *proxy_port_entry; GtkWidget *proxy_user_entry; GtkWidget *proxy_pass_entry; } AccountPrefsDialog; typedef struct { GdkPixbuf *online_pixbuf; gboolean pulse_to_grey; float pulse_value; int timeout; GaimAccount *account; GtkTreeModel *model; } GaimGtkPulseData; static AccountsWindow *accounts_window = NULL; static void add_account(AccountsWindow *dialog, GaimAccount *account); static void set_account(GtkListStore *store, GtkTreeIter *iter, GaimAccount *account); static char* convert_buddy_icon(GaimAccount *account, const char *path); static char * proto_name(const char *id) { GaimPlugin *p = gaim_find_prpl(id); return ((p && p->info->name) ? _(p->info->name) : _("Unknown")); } /************************************************************************** * Add/Modify Account dialog **************************************************************************/ static void add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent); static GtkWidget * add_pref_box(AccountPrefsDialog *dialog, GtkWidget *parent, const char *text, GtkWidget *widget) { GtkWidget *hbox; GtkWidget *label; hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); label = gtk_label_new_with_mnemonic(text); gtk_size_group_add_widget(dialog->sg, label); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); gtk_widget_show(widget); gaim_set_accessible_label (widget, label); return hbox; } static void set_account_protocol_cb(GtkWidget *item, const char *id, AccountPrefsDialog *dialog) { GaimPlugin *new_plugin; new_plugin = gaim_find_prpl(id); if (new_plugin == dialog->plugin) return; dialog->plugin = new_plugin; if (dialog->plugin != NULL) { dialog->prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(dialog->plugin); if (dialog->protocol_id != NULL) g_free(dialog->protocol_id); dialog->protocol_id = g_strdup(dialog->plugin->info->id); } if (dialog->account != NULL) gaim_account_clear_settings(dialog->account); add_login_options(dialog, dialog->top_vbox); add_user_options(dialog, dialog->top_vbox); add_protocol_options(dialog, dialog->bottom_vbox); if (!dialog->prpl_info || !dialog->prpl_info->register_user) gtk_widget_hide(dialog->register_button); else gtk_widget_show(dialog->register_button); } static void screenname_changed_cb(GtkEntry *entry, AccountPrefsDialog *dialog) { if (dialog->ok_button) gtk_widget_set_sensitive(dialog->ok_button, *gtk_entry_get_text(entry) != '\0'); if (dialog->register_button) gtk_widget_set_sensitive(dialog->register_button, *gtk_entry_get_text(entry) != '\0'); } #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ static void icon_filesel_choose_cb(GtkWidget *widget, gint response, AccountPrefsDialog *dialog) { const char *filename; if (response != GTK_RESPONSE_ACCEPT) { if (response == GTK_RESPONSE_CANCEL) gtk_widget_destroy(dialog->icon_filesel); dialog->icon_filesel = NULL; return; } filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog->icon_filesel)); #else /* FILECHOOSER */ static void icon_filesel_choose_cb(GtkWidget *w, AccountPrefsDialog *dialog) { const char *filename; filename = gtk_file_selection_get_filename( GTK_FILE_SELECTION(dialog->icon_filesel)); /* If they typed in a directory, change there */ if (gaim_gtk_check_if_dir(filename, GTK_FILE_SELECTION(dialog->icon_filesel))) { return; } #endif /* FILECHOOSER */ if (dialog->icon_path) g_free(dialog->icon_path); dialog->icon_path = convert_buddy_icon(dialog->account, filename); gtk_image_set_from_file(GTK_IMAGE(dialog->icon_entry), dialog->icon_path); gtk_widget_show(dialog->icon_entry); gtk_widget_destroy(dialog->icon_filesel); dialog->icon_filesel = NULL; } static void #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ icon_preview_change_cb(GtkFileChooser *widget, AccountPrefsDialog *dialog) #else /* FILECHOOSER */ icon_preview_change_cb(GtkTreeSelection *sel, AccountPrefsDialog *dialog) #endif /* FILECHOOSER */ { GdkPixbuf *pixbuf, *scale; int height, width; char *basename, *markup, *size; struct stat st; const char *filename; #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ filename = gtk_file_chooser_get_preview_filename( GTK_FILE_CHOOSER(dialog->icon_filesel)); #else /* FILECHOOSER */ filename = gtk_file_selection_get_filename( GTK_FILE_SELECTION(dialog->icon_filesel)); #endif /* FILECHOOSER */ if (!filename || stat(filename, &st)) return; pixbuf = gdk_pixbuf_new_from_file(filename, NULL); if (!pixbuf) { gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL); gtk_label_set_markup(GTK_LABEL(dialog->icon_text), ""); #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER(dialog->icon_filesel), FALSE); #endif /* FILECHOOSER */ return; } width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); basename = g_path_get_basename(filename); size = gaim_str_size_to_units(st.st_size); markup = g_strdup_printf(_("File: %s\n" "File size: %s\n" "Image size: %dx%d"), basename, size, width, height); scale = gdk_pixbuf_scale_simple(pixbuf, width * 50 / height, 50, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), scale); #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER(dialog->icon_filesel), TRUE); #endif /* FILECHOOSER */ gtk_label_set_markup(GTK_LABEL(dialog->icon_text), markup); g_object_unref(G_OBJECT(pixbuf)); g_object_unref(G_OBJECT(scale)); g_free(basename); g_free(size); g_free(markup); } #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ static void icon_filesel_delete_cb(GtkWidget *w, AccountPrefsDialog *dialog) { if (dialog->icon_filesel != NULL) gtk_widget_destroy(dialog->icon_filesel); dialog->icon_filesel = NULL; } #endif /* FILECHOOSER */ static void icon_select_cb(GtkWidget *button, AccountPrefsDialog *dialog) { #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ GtkWidget *hbox; GtkWidget *tv; GtkTreeSelection *sel; #endif /* FILECHOOSER */ if (dialog->icon_filesel != NULL) { gtk_window_present(GTK_WINDOW(dialog->icon_filesel)); return; } #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"), GTK_WINDOW(dialog->window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response(GTK_DIALOG(dialog->icon_filesel), GTK_RESPONSE_ACCEPT); /* I removed code to set the current path to the current icon in the old file selector so I figure * it shouldn't be here either. The reason is because the icon will potentially converted and won't * be anything near what the user selected last time (which is the advantage to doing it this way. * The solution is to create a new pref to specify the last chosen buddy icon. This would also have the * advantage (?) of not being account-specific. if (dialog->icon_path != NULL) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog->icon_filesel), dialog->icon_path); */ dialog->icon_preview = gtk_image_new(); dialog->icon_text = gtk_label_new(NULL); gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50); gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog->icon_filesel), GTK_WIDGET(dialog->icon_preview)); g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview", G_CALLBACK(icon_preview_change_cb), dialog); g_signal_connect(G_OBJECT(dialog->icon_filesel), "response", G_CALLBACK(icon_filesel_choose_cb), dialog); icon_preview_change_cb(NULL, dialog); #else /* FILECHOOSER */ dialog->icon_filesel = gtk_file_selection_new(_("Buddy Icon")); dialog->icon_preview = gtk_image_new(); dialog->icon_text = gtk_label_new(NULL); gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50); hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start( GTK_BOX(GTK_FILE_SELECTION(dialog->icon_filesel)->main_vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_preview, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_text, FALSE, FALSE, 0); tv = GTK_FILE_SELECTION(dialog->icon_filesel)->file_list; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(icon_preview_change_cb), dialog); g_signal_connect( G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->ok_button), "clicked", G_CALLBACK(icon_filesel_choose_cb), dialog); g_signal_connect( G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->cancel_button), "clicked", G_CALLBACK(icon_filesel_delete_cb), dialog); g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy", G_CALLBACK(icon_filesel_delete_cb), dialog); #endif /* FILECHOOSER */ gtk_widget_show_all(GTK_WIDGET(dialog->icon_filesel)); } static void icon_reset_cb(GtkWidget *button, AccountPrefsDialog *dialog) { if (dialog->icon_path) g_free(dialog->icon_path); dialog->icon_path = NULL; gtk_widget_hide(dialog->icon_entry); } static void account_dnd_recv(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *sd, guint info, guint t, AccountPrefsDialog *dialog) { gchar *name = sd->data; if ((sd->length >= 0) && (sd->format == 8)) { /* Well, it looks like the drag event was cool. * Let's do something with it */ if (!g_ascii_strncasecmp(name, "file://", 7)) { GError *converr = NULL; gchar *tmp, *rtmp; /* It looks like we're dealing with a local file. Let's * just untar it in the right place */ if(!(tmp = g_filename_from_uri(name, NULL, &converr))) { gaim_debug(GAIM_DEBUG_ERROR, "buddyicon", "%s\n", (converr ? converr->message : "g_filename_from_uri error")); return; } if ((rtmp = strchr(tmp, '\r')) || (rtmp = strchr(tmp, '\n'))) *rtmp = '\0'; if (dialog->icon_path) g_free(dialog->icon_path); dialog->icon_path = convert_buddy_icon(dialog->account, tmp); gtk_image_set_from_file(GTK_IMAGE(dialog->icon_entry), dialog->icon_path); gtk_widget_show(dialog->icon_entry); g_free(tmp); } gtk_drag_finish(dc, TRUE, FALSE, t); } gtk_drag_finish(dc, FALSE, FALSE, t); } #if GTK_CHECK_VERSION(2,2,0) static gboolean str_array_match(char **a, char **b) { int i, j; if (!a || !b) return FALSE; for (i = 0; a[i] != NULL; i++) for (j = 0; b[j] != NULL; j++) if (!g_ascii_strcasecmp(a[i], b[j])) return TRUE; return FALSE; } #endif static char* convert_buddy_icon(GaimAccount *account, const char *path) { #if GTK_CHECK_VERSION(2,2,0) int width, height; char **pixbuf_formats = NULL; GdkPixbufFormat *format; GdkPixbuf *pixbuf; GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gaim_find_prpl(account->protocol_id)); char **prpl_formats = g_strsplit (prpl_info->icon_spec.format,",",0); #if !GTK_CHECK_VERSION(2,4,0) GdkPixbufLoader *loader; FILE *file; struct stat st; void *data = NULL; #endif #if GTK_CHECK_VERSION(2,4,0) format = gdk_pixbuf_get_file_info (path, &width, &height); #else loader = gdk_pixbuf_loader_new(); if (!stat(path, &st) && (file = fopen(path, "rb")) != NULL) { data = g_malloc(st.st_size); fread(data, 1, st.st_size, file); fclose(file); gdk_pixbuf_loader_write(loader, data, st.st_size, NULL); g_free(data); } pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); format = gdk_pixbuf_loader_get_format(loader); gdk_pixbuf_loader_close(loader, NULL); g_object_unref(G_OBJECT(loader)); #endif pixbuf_formats = gdk_pixbuf_format_get_extensions(format); if (str_array_match(pixbuf_formats, prpl_formats) && /* This is an acceptable format AND */ (!(prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */ (prpl_info->icon_spec.min_width <= width && prpl_info->icon_spec.max_width >= width && prpl_info->icon_spec.min_height <= height && prpl_info->icon_spec.max_height >= height))) { /* The icon is the correct size */ #endif return g_strdup(path); #if GTK_CHECK_VERSION(2,2,0) } else { int i; GError *error = NULL; GdkPixbuf *scale; char *random = g_strdup_printf("%x", g_random_int()); const char *dirname = gaim_buddy_icons_get_cache_dir(); char *filename = g_build_filename(dirname, random, NULL); pixbuf = gdk_pixbuf_new_from_file(path, &error); if (!error && prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) { int new_width = gdk_pixbuf_get_width(pixbuf); int new_height = gdk_pixbuf_get_height(pixbuf); if(new_width > prpl_info->icon_spec.max_width) new_width = prpl_info->icon_spec.max_width; else if(new_width < prpl_info->icon_spec.min_width) new_width = prpl_info->icon_spec.min_width; if(new_height > prpl_info->icon_spec.max_height) new_height = prpl_info->icon_spec.max_height; else if(new_height < prpl_info->icon_spec.min_height) new_height = prpl_info->icon_spec.min_height; scale = gdk_pixbuf_scale_simple (pixbuf, new_width, new_height, GDK_INTERP_HYPER); g_object_unref(G_OBJECT(pixbuf)); pixbuf = scale; } if (error) { g_free(filename); g_free(random); gaim_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); g_error_free(error); return NULL; } for (i = 0; prpl_formats[i]; i++) { gaim_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename); /* The gdk-pixbuf documentation is wrong. gdk_pixbuf_save returns TRUE if it was successful, * FALSE if an error was set. */ if (gdk_pixbuf_save (pixbuf, filename, prpl_formats[i], &error, NULL) == TRUE) break; } if (!error) { g_free(random); g_object_unref(G_OBJECT(pixbuf)); return filename; } else { gaim_debug_error("buddyicon", "Could not convert icon to usable format: %s\n", error->message); g_error_free(error); } g_free(filename); g_free(random); g_object_unref(G_OBJECT(pixbuf)); } return NULL; #endif } static void add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent) { GtkWidget *frame; GtkWidget *vbox; GtkWidget *entry; GList *user_splits; GList *l, *l2; char *username = NULL; if (dialog->login_frame != NULL) gtk_widget_destroy(dialog->login_frame); /* Build the login options frame. */ frame = gaim_gtk_make_frame(parent, _("Login Options")); /* cringe */ dialog->login_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame)); gtk_box_reorder_child(GTK_BOX(parent), dialog->login_frame, 0); gtk_widget_show(dialog->login_frame); /* Main vbox */ vbox = gtk_vbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); /* Protocol */ dialog->protocol_menu = gaim_gtk_protocol_option_menu_new( dialog->protocol_id, G_CALLBACK(set_account_protocol_cb), dialog); add_pref_box(dialog, vbox, _("Protocol:"), dialog->protocol_menu); /* Screen Name */ dialog->screenname_entry = gtk_entry_new(); add_pref_box(dialog, vbox, _("Screen Name:"), dialog->screenname_entry); g_signal_connect(G_OBJECT(dialog->screenname_entry), "changed", G_CALLBACK(screenname_changed_cb), dialog); /* Do the user split thang */ if (dialog->plugin == NULL) /* Yeah right. */ user_splits = NULL; else user_splits = dialog->prpl_info->user_splits; if (dialog->account != NULL) username = g_strdup(gaim_account_get_username(dialog->account)); if (dialog->user_split_entries != NULL) { g_list_free(dialog->user_split_entries); dialog->user_split_entries = NULL; } for (l = user_splits; l != NULL; l = l->next) { GaimAccountUserSplit *split = l->data; char *buf; buf = g_strdup_printf("%s:", gaim_account_user_split_get_text(split)); entry = gtk_entry_new(); add_pref_box(dialog, vbox, buf, entry); g_free(buf); dialog->user_split_entries = g_list_append(dialog->user_split_entries, entry); } for (l = g_list_last(dialog->user_split_entries), l2 = g_list_last(user_splits); l != NULL && l2 != NULL; l = l->prev, l2 = l2->prev) { GtkWidget *entry = l->data; GaimAccountUserSplit *split = l2->data; const char *value = NULL; char *c; if (dialog->account != NULL) { c = strrchr(username, gaim_account_user_split_get_separator(split)); if (c != NULL) { *c = '\0'; c++; value = c; } } if (value == NULL) value = gaim_account_user_split_get_default_value(split); if (value != NULL) gtk_entry_set_text(GTK_ENTRY(entry), value); } if (username != NULL) gtk_entry_set_text(GTK_ENTRY(dialog->screenname_entry), username); g_free(username); /* Password */ dialog->password_entry = gtk_entry_new(); gtk_entry_set_visibility(GTK_ENTRY(dialog->password_entry), FALSE); dialog->password_box = add_pref_box(dialog, vbox, _("Password:"), dialog->password_entry); /* Alias */ dialog->alias_entry = gtk_entry_new(); add_pref_box(dialog, vbox, _("Alias:"), dialog->alias_entry); /* Remember Password */ dialog->remember_pass_check = gtk_check_button_new_with_label(_("Remember password")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->remember_pass_check), FALSE); gtk_box_pack_start(GTK_BOX(vbox), dialog->remember_pass_check, FALSE, FALSE, 0); gtk_widget_show(dialog->remember_pass_check); /* Auto-Login */ dialog->auto_login_check = gtk_check_button_new_with_label(_("Auto-login")); gtk_box_pack_start(GTK_BOX(vbox), dialog->auto_login_check, FALSE, FALSE, 0); gtk_widget_show(dialog->auto_login_check); /* Set the fields. */ if (dialog->account != NULL) { if (gaim_account_get_password(dialog->account)) gtk_entry_set_text(GTK_ENTRY(dialog->password_entry), gaim_account_get_password(dialog->account)); if (gaim_account_get_alias(dialog->account)) gtk_entry_set_text(GTK_ENTRY(dialog->alias_entry), gaim_account_get_alias(dialog->account)); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(dialog->remember_pass_check), gaim_account_get_remember_password(dialog->account)); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(dialog->auto_login_check), gaim_account_get_auto_login(dialog->account, GAIM_GTK_UI)); } if (dialog->prpl_info != NULL && (dialog->prpl_info->options & OPT_PROTO_NO_PASSWORD)) { gtk_widget_hide(dialog->password_box); gtk_widget_hide(dialog->remember_pass_check); } } static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent) { GtkWidget *frame; GtkWidget *vbox; GtkWidget *vbox2; GtkWidget *hbox; GtkWidget *hbox2; GtkWidget *button; GtkWidget *label; if (dialog->user_frame != NULL) gtk_widget_destroy(dialog->user_frame); /* Build the user options frame. */ frame = gaim_gtk_make_frame(parent, _("User Options")); dialog->user_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame)); gtk_box_reorder_child(GTK_BOX(parent), dialog->user_frame, 1); gtk_widget_show(dialog->user_frame); /* Main vbox */ vbox = gtk_vbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); /* New mail notifications */ dialog->new_mail_check = gtk_check_button_new_with_label(_("New mail notifications")); gtk_box_pack_start(GTK_BOX(vbox), dialog->new_mail_check, FALSE, FALSE, 0); gtk_widget_show(dialog->new_mail_check); /* Buddy icon */ dialog->icon_hbox = hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); label = gtk_label_new(_("Buddy icon:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_widget_show(label); dialog->icon_entry = gtk_image_new(); gtk_box_pack_start(GTK_BOX(hbox), dialog->icon_entry, FALSE, FALSE, 0); gtk_widget_show(dialog->icon_entry); gaim_set_accessible_label (dialog->icon_entry, label); dialog->icon_path = NULL; vbox2 = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0); gtk_widget_show(vbox2); hbox2 = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0); gtk_widget_show(hbox2); button = gtk_button_new_from_stock(GTK_STOCK_OPEN); gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(icon_select_cb), dialog); gtk_widget_show(button); button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(icon_reset_cb), dialog); gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0); gtk_widget_show(button); if (dialog->prpl_info != NULL) { if (!(dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK)) gtk_widget_hide(dialog->new_mail_check); if (!(dialog->prpl_info->icon_spec.format != NULL)) gtk_widget_hide(dialog->icon_hbox); } if (dialog->account != NULL) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->new_mail_check), gaim_account_get_check_mail(dialog->account)); if (gaim_account_get_buddy_icon(dialog->account) != NULL) { dialog->icon_path = g_strdup(gaim_account_get_buddy_icon(dialog->account)); gtk_image_set_from_file(GTK_IMAGE(dialog->icon_entry),dialog->icon_path); } } if (!dialog->prpl_info || (!(dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK) && (dialog->prpl_info->icon_spec.format == NULL))) { /* Nothing to see :( aww. */ gtk_widget_hide(dialog->user_frame); } } static void add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent) { GaimAccountOption *option; GaimAccount *account; GtkWidget *frame; GtkWidget *vbox; GtkWidget *check; GtkWidget *entry; GList *l; char buf[1024]; char *title; const char *str_value; gboolean bool_value; int int_value; if (dialog->protocol_frame != NULL) { gtk_widget_destroy(dialog->protocol_frame); dialog->protocol_frame = NULL; } if (dialog->prpl_info == NULL || dialog->prpl_info->protocol_options == NULL) { return; } account = dialog->account; /* Build the protocol options frame. */ g_snprintf(buf, sizeof(buf), _("%s Options"), dialog->plugin->info->name); frame = gaim_gtk_make_frame(parent, buf); dialog->protocol_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame)); gtk_box_reorder_child(GTK_BOX(parent), dialog->protocol_frame, 0); gtk_widget_show(dialog->protocol_frame); /* Main vbox */ vbox = gtk_vbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); if (dialog->protocol_opt_entries != NULL) { g_list_free(dialog->protocol_opt_entries); dialog->protocol_opt_entries = NULL; } for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next) { option = (GaimAccountOption *)l->data; switch (gaim_account_option_get_type(option)) { case GAIM_PREF_BOOLEAN: if (account == NULL || strcmp(gaim_account_get_protocol_id(account), dialog->protocol_id)) { bool_value = gaim_account_option_get_default_bool(option); } else { bool_value = gaim_account_get_bool(account, gaim_account_option_get_setting(option), gaim_account_option_get_default_bool(option)); } check = gtk_check_button_new_with_label( gaim_account_option_get_text(option)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), bool_value); gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); gtk_widget_show(check); dialog->protocol_opt_entries = g_list_append(dialog->protocol_opt_entries, check); break; case GAIM_PREF_INT: if (account == NULL || strcmp(gaim_account_get_protocol_id(account), dialog->protocol_id)) { int_value = gaim_account_option_get_default_int(option); } else { int_value = gaim_account_get_int(account, gaim_account_option_get_setting(option), gaim_account_option_get_default_int(option)); } g_snprintf(buf, sizeof(buf), "%d", int_value); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), buf); title = g_strdup_printf("%s:", gaim_account_option_get_text(option)); add_pref_box(dialog, vbox, title, entry); g_free(title); dialog->protocol_opt_entries = g_list_append(dialog->protocol_opt_entries, entry); break; case GAIM_PREF_STRING: if (account == NULL || strcmp(gaim_account_get_protocol_id(account), dialog->protocol_id)) { str_value = gaim_account_option_get_default_string(option); } else { str_value = gaim_account_get_string(account, gaim_account_option_get_setting(option), gaim_account_option_get_default_string(option)); } entry = gtk_entry_new(); if (str_value != NULL) gtk_entry_set_text(GTK_ENTRY(entry), str_value); title = g_strdup_printf("%s:", gaim_account_option_get_text(option)); add_pref_box(dialog, vbox, title, entry); g_free(title); dialog->protocol_opt_entries = g_list_append(dialog->protocol_opt_entries, entry); break; default: break; } } } static GtkWidget * make_proxy_dropdown(void) { GtkWidget *dropdown; #if GTK_CHECK_VERSION(2,4,0) GtkListStore *model; GtkTreeIter iter; GtkCellRenderer *renderer; model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, _("Use Global Proxy Settings"), 1, GAIM_PROXY_USE_GLOBAL, -1); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, _("No Proxy"), 1, GAIM_PROXY_NONE, -1); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, _("HTTP"), 1, GAIM_PROXY_HTTP, -1); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, _("SOCKS 4"), 1, GAIM_PROXY_SOCKS4, -1); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, _("SOCKS 5"), 1, GAIM_PROXY_SOCKS5, -1); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, _("Use Environmental Settings"), 1, GAIM_PROXY_USE_ENVVAR, -1); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer, "text", 0, NULL); #else GtkWidget *menu; GtkWidget *item; dropdown = gtk_option_menu_new(); menu = gtk_menu_new(); /* Use Global Proxy Settings */ item = gtk_menu_item_new_with_label(_("Use Global Proxy Settings")); g_object_set_data(G_OBJECT(item), "proxytype", GINT_TO_POINTER(GAIM_PROXY_USE_GLOBAL)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); /* No Proxy */ item = gtk_menu_item_new_with_label(_("No Proxy")); g_object_set_data(G_OBJECT(item), "proxytype", GINT_TO_POINTER(GAIM_PROXY_NONE)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); /* HTTP */ item = gtk_menu_item_new_with_label(_("HTTP")); g_object_set_data(G_OBJECT(item), "proxytype", GINT_TO_POINTER(GAIM_PROXY_HTTP)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); /* SOCKS 4 */ item = gtk_menu_item_new_with_label(_("SOCKS 4")); g_object_set_data(G_OBJECT(item), "proxytype", GINT_TO_POINTER(GAIM_PROXY_SOCKS4)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); /* SOCKS 5 */ item = gtk_menu_item_new_with_label(_("SOCKS 5")); g_object_set_data(G_OBJECT(item), "proxytype", GINT_TO_POINTER(GAIM_PROXY_SOCKS5)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); /* Use Environmental Settings */ item = gtk_menu_item_new_with_label(_("Use Environmental Settings")); g_object_set_data(G_OBJECT(item), "proxytype", GINT_TO_POINTER(GAIM_PROXY_USE_ENVVAR)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu); #endif return dropdown; } static void proxy_type_changed_cb(GtkWidget *menu, AccountPrefsDialog *dialog) { #if GTK_CHECK_VERSION(2,4,0) dialog->new_proxy_type = gtk_combo_box_get_active(GTK_COMBO_BOX(menu)) - 1; #else dialog->new_proxy_type = gtk_option_menu_get_history(GTK_OPTION_MENU(menu)) - 1; #endif if (dialog->new_proxy_type == GAIM_PROXY_USE_GLOBAL || dialog->new_proxy_type == GAIM_PROXY_NONE || dialog->new_proxy_type == GAIM_PROXY_USE_ENVVAR) { gtk_widget_hide_all(dialog->proxy_vbox); } else gtk_widget_show_all(dialog->proxy_vbox); } static void port_popup_cb(GtkWidget *w, GtkMenu *menu, gpointer data) { GtkWidget *item; item = gtk_menu_item_new_with_label( _("you can see the butterflies mating")); gtk_widget_show(item); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item); item = gtk_menu_item_new_with_label(_("If you look real closely")); gtk_widget_show(item); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item); } static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent) { GaimProxyInfo *proxy_info; GtkWidget *frame; GtkWidget *vbox; GtkWidget *vbox2; if (dialog->proxy_frame != NULL) gtk_widget_destroy(dialog->proxy_frame); frame = gaim_gtk_make_frame(parent, _("Proxy Options")); dialog->proxy_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame)); gtk_box_reorder_child(GTK_BOX(parent), dialog->proxy_frame, 1); gtk_widget_show(dialog->proxy_frame); /* Main vbox */ vbox = gtk_vbox_new(FALSE, 6); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); /* Proxy Type drop-down. */ dialog->proxy_dropdown = make_proxy_dropdown(); #if !GTK_CHECK_VERSION(2,4,0) dialog->proxy_menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->proxy_dropdown)); #endif add_pref_box(dialog, vbox, _("Proxy _type:"), dialog->proxy_dropdown); /* Setup the second vbox, which may be hidden at times. */ dialog->proxy_vbox = vbox2 = gtk_vbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0); gtk_widget_show(vbox2); /* Host */ dialog->proxy_host_entry = gtk_entry_new(); add_pref_box(dialog, vbox2, _("_Host:"), dialog->proxy_host_entry); /* Port */ dialog->proxy_port_entry = gtk_entry_new(); add_pref_box(dialog, vbox2, _("_Port:"), dialog->proxy_port_entry); g_signal_connect(G_OBJECT(dialog->proxy_port_entry), "populate-popup", G_CALLBACK(port_popup_cb), NULL); /* User */ dialog->proxy_user_entry = gtk_entry_new(); add_pref_box(dialog, vbox2, _("_Username:"), dialog->proxy_user_entry); /* Password */ dialog->proxy_pass_entry = gtk_entry_new(); gtk_entry_set_visibility(GTK_ENTRY(dialog->proxy_pass_entry), FALSE); add_pref_box(dialog, vbox2, _("Pa_ssword:"), dialog->proxy_pass_entry); if (dialog->account != NULL && (proxy_info = gaim_account_get_proxy_info(dialog->account)) != NULL) { GaimProxyType type = gaim_proxy_info_get_type(proxy_info); /* Hah! */ /* I dunno what you're laughing about, fuzz ball. */ dialog->new_proxy_type = type; #if GTK_CHECK_VERSION(2,4,0) gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->proxy_dropdown), type + 1); #else gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->proxy_dropdown), (int)type + 1); #endif if (type == GAIM_PROXY_USE_GLOBAL || type == GAIM_PROXY_NONE || type == GAIM_PROXY_USE_ENVVAR) { gtk_widget_hide_all(vbox2); } else { const char *value; int int_val; if ((value = gaim_proxy_info_get_host(proxy_info)) != NULL) gtk_entry_set_text(GTK_ENTRY(dialog->proxy_host_entry), value); if ((int_val = gaim_proxy_info_get_port(proxy_info)) != 0) { char buf[32]; g_snprintf(buf, sizeof(buf), "%d", int_val); gtk_entry_set_text(GTK_ENTRY(dialog->proxy_port_entry), buf); } if ((value = gaim_proxy_info_get_username(proxy_info)) != NULL) gtk_entry_set_text(GTK_ENTRY(dialog->proxy_user_entry), value); if ((value = gaim_proxy_info_get_password(proxy_info)) != NULL) gtk_entry_set_text(GTK_ENTRY(dialog->proxy_pass_entry), value); } } else { dialog->new_proxy_type = GAIM_PROXY_USE_GLOBAL; #if GTK_CHECK_VERSION(2,4,0) gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->proxy_dropdown), dialog->new_proxy_type + 1); #else gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->proxy_dropdown), dialog->new_proxy_type + 1); #endif gtk_widget_hide_all(vbox2); } /* Connect signals. */ g_signal_connect(G_OBJECT(dialog->proxy_dropdown), "changed", G_CALLBACK(proxy_type_changed_cb), dialog); } static void account_win_destroy_cb(GtkWidget *w, GdkEvent *event, AccountPrefsDialog *dialog) { if (accounts_window != NULL) g_hash_table_remove(accounts_window->account_pref_wins, dialog->account); gtk_widget_destroy(dialog->window); if (dialog->user_split_entries != NULL) g_list_free(dialog->user_split_entries); if (dialog->protocol_opt_entries != NULL) g_list_free(dialog->protocol_opt_entries); if (dialog->protocol_id != NULL) g_free(dialog->protocol_id); if (dialog->icon_filesel) gtk_widget_destroy(dialog->icon_filesel); g_free(dialog); } static void cancel_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog) { account_win_destroy_cb(NULL, NULL, dialog); } static GaimAccount* ok_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog) { GaimProxyInfo *proxy_info = NULL; GList *l, *l2; const char *value; char *username; char *tmp; size_t index; GtkTreeIter iter; GaimAccount *ret; if (dialog->account == NULL) { const char *screenname; screenname = gtk_entry_get_text(GTK_ENTRY(dialog->screenname_entry)); dialog->account = gaim_account_new(screenname, dialog->protocol_id); } else { /* Protocol */ gaim_account_set_protocol_id(dialog->account, dialog->protocol_id); } /* Alias */ value = gtk_entry_get_text(GTK_ENTRY(dialog->alias_entry)); if (*value != '\0') gaim_account_set_alias(dialog->account, value); else gaim_account_set_alias(dialog->account, NULL); /* Buddy Icon */ value = dialog->icon_path; gaim_account_set_buddy_icon(dialog->account, value); /* Remember Password */ gaim_account_set_remember_password(dialog->account, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(dialog->remember_pass_check))); /* Check Mail */ if (dialog->prpl_info && dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK) gaim_account_set_check_mail(dialog->account, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(dialog->new_mail_check))); /* Auto Login */ gaim_account_set_auto_login(dialog->account, GAIM_GTK_UI, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(dialog->auto_login_check))); /* Password */ value = gtk_entry_get_text(GTK_ENTRY(dialog->password_entry)); if (gaim_account_get_remember_password(dialog->account) && *value != '\0') gaim_account_set_password(dialog->account, value); else gaim_account_set_password(dialog->account, NULL); /* Build the username string. */ username = g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->screenname_entry))); if (dialog->prpl_info != NULL) { for (l = dialog->prpl_info->user_splits, l2 = dialog->user_split_entries; l != NULL && l2 != NULL; l = l->next, l2 = l2->next) { GaimAccountUserSplit *split = l->data; GtkEntry *entry = l2->data; char sep[2] = " "; value = gtk_entry_get_text(entry); *sep = gaim_account_user_split_get_separator(split); tmp = g_strconcat(username, sep, (*value ? value : gaim_account_user_split_get_default_value(split)), NULL); g_free(username); username = tmp; } } gaim_account_set_username(dialog->account, username); g_free(username); /* Add the protocol settings */ if(dialog->prpl_info) { for (l = dialog->prpl_info->protocol_options, l2 = dialog->protocol_opt_entries; l != NULL && l2 != NULL; l = l->next, l2 = l2->next) { GaimPrefType type; GaimAccountOption *option = l->data; GtkWidget *widget = l2->data; const char *setting; int int_value; gboolean bool_value; type = gaim_account_option_get_type(option); setting = gaim_account_option_get_setting(option); switch (type) { case GAIM_PREF_STRING: value = gtk_entry_get_text(GTK_ENTRY(widget)); gaim_account_set_string(dialog->account, setting, value); break; case GAIM_PREF_INT: int_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget))); gaim_account_set_int(dialog->account, setting, int_value); break; case GAIM_PREF_BOOLEAN: bool_value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); gaim_account_set_bool(dialog->account, setting, bool_value); break; default: break; } } } /* Set the proxy stuff. */ if (dialog->new_proxy_type == GAIM_PROXY_USE_GLOBAL) { gaim_account_set_proxy_info(dialog->account, NULL); } else { proxy_info = gaim_account_get_proxy_info(dialog->account); /* Create the proxy info if it doesn't exist. */ if (proxy_info == NULL) { proxy_info = gaim_proxy_info_new(); gaim_account_set_proxy_info(dialog->account, proxy_info); } /* Set the proxy info type. */ gaim_proxy_info_set_type(proxy_info, dialog->new_proxy_type); /* Host */ value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_host_entry)); if (*value != '\0') gaim_proxy_info_set_host(proxy_info, value); else gaim_proxy_info_set_host(proxy_info, NULL); /* Port */ value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_port_entry)); if (*value != '\0') gaim_proxy_info_set_port(proxy_info, atoi(value)); else gaim_proxy_info_set_port(proxy_info, 0); /* Username */ value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_user_entry)); if (*value != '\0') gaim_proxy_info_set_username(proxy_info, value); else gaim_proxy_info_set_username(proxy_info, NULL); /* Password */ value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_pass_entry)); if (*value != '\0') gaim_proxy_info_set_password(proxy_info, value); else gaim_proxy_info_set_password(proxy_info, NULL); } /* Adds the account to the list, or modify the existing entry. */ if (accounts_window != NULL) { index = g_list_index(gaim_accounts_get_all(), dialog->account); if (index != -1 && (gtk_tree_model_iter_nth_child( GTK_TREE_MODEL(accounts_window->model), &iter, NULL, index))) { set_account(accounts_window->model, &iter, dialog->account); } else { add_account(accounts_window, dialog->account); gaim_accounts_add(dialog->account); } } ret = dialog->account; account_win_destroy_cb(NULL, NULL, dialog); gaim_signal_emit(gaim_gtk_account_get_handle(), "account-modified", ret); return ret; } static void register_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog) { GaimAccount *account = ok_account_prefs_cb(NULL, dialog); gaim_account_register(account); } static const GtkTargetEntry dnd_targets[] = { {"text/plain", 0, 0}, {"text/uri-list", 0, 1}, {"STRING", 0, 2} }; void gaim_gtk_account_dialog_show(GaimGtkAccountDialogType type, GaimAccount *account) { AccountPrefsDialog *dialog; GtkWidget *win; GtkWidget *main_vbox; GtkWidget *vbox; GtkWidget *bbox; GtkWidget *dbox; GtkWidget *disclosure; GtkWidget *sep; GtkWidget *button; if (accounts_window != NULL && account != NULL && (dialog = g_hash_table_lookup(accounts_window->account_pref_wins, account)) != NULL) { gtk_window_present(GTK_WINDOW(dialog->window)); return; } dialog = g_new0(AccountPrefsDialog, 1); if (accounts_window != NULL && account != NULL) { g_hash_table_insert(accounts_window->account_pref_wins, account, dialog); } dialog->account = account; dialog->type = type; dialog->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); if (dialog->account == NULL) dialog->protocol_id = g_strdup(GAIM_PROTO_DEFAULT); else { dialog->protocol_id = g_strdup(gaim_account_get_protocol_id(dialog->account)); } if ((dialog->plugin = gaim_find_prpl(dialog->protocol_id)) != NULL) dialog->prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(dialog->plugin); dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_role(GTK_WINDOW(win), "account"); if (type == GAIM_GTK_ADD_ACCOUNT_DIALOG) gtk_window_set_title(GTK_WINDOW(win), _("Add Account")); else gtk_window_set_title(GTK_WINDOW(win), _("Modify Account")); gtk_window_set_resizable(GTK_WINDOW(win), FALSE); gtk_container_set_border_width(GTK_CONTAINER(win), 12); g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(account_win_destroy_cb), dialog); /* Setup the vbox */ main_vbox = gtk_vbox_new(FALSE, 12); gtk_container_add(GTK_CONTAINER(win), main_vbox); gtk_widget_show(main_vbox); /* Setup the inner vbox */ dialog->top_vbox = vbox = gtk_vbox_new(FALSE, 18); gtk_box_pack_start(GTK_BOX(main_vbox), vbox, FALSE, FALSE, 0); gtk_widget_show(vbox); /* Setup the top frames. */ add_login_options(dialog, vbox); add_user_options(dialog, vbox); /* Add the disclosure */ disclosure = gaim_disclosure_new(_("Show more options"), _("Show fewer options")); gtk_box_pack_start(GTK_BOX(vbox), disclosure, FALSE, FALSE, 0); gtk_widget_show(disclosure); /* Setup the box that the disclosure will cover. */ dialog->bottom_vbox = dbox = gtk_vbox_new(FALSE, 18); gtk_box_pack_start(GTK_BOX(vbox), dbox, FALSE, FALSE, 0); gaim_disclosure_set_container(GAIM_DISCLOSURE(disclosure), dbox); /** Setup the bottom frames. */ add_protocol_options(dialog, dbox); add_proxy_options(dialog, dbox); /* Separator... */ sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(main_vbox), sep, FALSE, FALSE, 0); gtk_widget_show(sep); /* Setup the button box */ bbox = gtk_hbutton_box_new(); gtk_box_set_spacing(GTK_BOX(bbox), 6); gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); gtk_box_pack_end(GTK_BOX(main_vbox), bbox, FALSE, TRUE, 0); gtk_widget_show(bbox); /* Register button */ button = gtk_button_new_with_label(_("Register")); gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(register_account_prefs_cb), dialog); dialog->register_button = button; if (dialog->account == NULL) gtk_widget_set_sensitive(button, FALSE); if (!dialog->prpl_info || !dialog->prpl_info->register_user) gtk_widget_hide(button); /* Cancel button */ button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(cancel_account_prefs_cb), dialog); /* Save button */ button = gtk_button_new_from_stock(GTK_STOCK_SAVE); gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); if (dialog->account == NULL) gtk_widget_set_sensitive(button, FALSE); gtk_widget_show(button); dialog->ok_button = button; /* Set up DND */ gtk_drag_dest_set(dialog->window, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, dnd_targets, sizeof(dnd_targets) / sizeof(GtkTargetEntry), GDK_ACTION_COPY); g_signal_connect(G_OBJECT(dialog->window), "drag_data_received", G_CALLBACK(account_dnd_recv), dialog); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(ok_account_prefs_cb), dialog); /* Show the window. */ gtk_widget_show(win); } /************************************************************************** * Accounts Dialog **************************************************************************/ static void account_pulse_update(GaimGtkPulseData *pulse_data) { GdkPixbuf *pixbuf; GtkTreeIter iter; size_t index = g_list_index(gaim_accounts_get_all(), pulse_data->account); if (gtk_tree_model_iter_nth_child(pulse_data->model, &iter, NULL, index)) { pixbuf = gdk_pixbuf_copy(pulse_data->online_pixbuf); gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, pulse_data->pulse_value, FALSE); if (pulse_data->pulse_to_grey) pulse_data->pulse_value += 0.20; else pulse_data->pulse_value -= 0.20; if (pulse_data->pulse_value >= 1) pulse_data->pulse_to_grey = FALSE; else if (pulse_data->pulse_value <= 0) pulse_data->pulse_to_grey = TRUE; gtk_list_store_set(GTK_LIST_STORE(pulse_data->model), &iter, COLUMN_ICON, pixbuf, -1); if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); } } static void signed_on_off_cb(GaimConnection *gc, AccountsWindow *dialog) { GaimAccount *account = gaim_connection_get_account(gc); GaimGtkPulseData *pulse_data; GtkTreeModel *model = GTK_TREE_MODEL(dialog->model); GtkTreeIter iter; GdkPixbuf *pixbuf, *scale = NULL; size_t index = g_list_index(gaim_accounts_get_all(), account); if (gtk_tree_model_iter_nth_child(model, &iter, NULL, index)) { gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_PULSE_DATA, &pulse_data, -1); if (pulse_data != NULL) { if (pulse_data->timeout > 0) g_source_remove(pulse_data->timeout); g_object_unref(G_OBJECT(pulse_data->online_pixbuf)); g_free(pulse_data); } pixbuf = create_prpl_icon(account); if (pixbuf != NULL) { scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); if (!gaim_account_is_connected(account)) gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE); } gtk_list_store_set(dialog->model, &iter, COLUMN_ICON, scale, COLUMN_ONLINE, gaim_account_is_connected(account), COLUMN_PULSE_DATA, NULL, -1); if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); if (scale != NULL) g_object_unref(G_OBJECT(scale)); } } static void drag_data_get_cb(GtkWidget *widget, GdkDragContext *ctx, GtkSelectionData *data, guint info, guint time, AccountsWindow *dialog) { if (data->target == gdk_atom_intern("GAIM_ACCOUNT", FALSE)) { GtkTreeRowReference *ref; GtkTreePath *source_row; GtkTreeIter iter; GaimAccount *account = NULL; GValue val = {0}; ref = g_object_get_data(G_OBJECT(ctx), "gtk-tree-view-source-row"); source_row = gtk_tree_row_reference_get_path(ref); if (source_row == NULL) return; gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, source_row); gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_DATA, &val); dialog->drag_iter = iter; account = g_value_get_pointer(&val); gtk_selection_data_set(data, gdk_atom_intern("GAIM_ACCOUNT", FALSE), 8, (void *)&account, sizeof(account)); gtk_tree_path_free(source_row); } } static void move_account_after(GtkListStore *store, GtkTreeIter *iter, GtkTreeIter *position) { GtkTreeIter new_iter; GaimAccount *account; gtk_tree_model_get(GTK_TREE_MODEL(store), iter, COLUMN_DATA, &account, -1); gtk_list_store_insert_after(store, &new_iter, position); set_account(store, &new_iter, account); gtk_list_store_remove(store, iter); } static void move_account_before(GtkListStore *store, GtkTreeIter *iter, GtkTreeIter *position) { GtkTreeIter new_iter; GaimAccount *account; gtk_tree_model_get(GTK_TREE_MODEL(store), iter, COLUMN_DATA, &account, -1); gtk_list_store_insert_before(store, &new_iter, position); set_account(store, &new_iter, account); gtk_list_store_remove(store, iter); } static void drag_data_received_cb(GtkWidget *widget, GdkDragContext *ctx, guint x, guint y, GtkSelectionData *sd, guint info, guint t, AccountsWindow *dialog) { if (sd->target == gdk_atom_intern("GAIM_ACCOUNT", FALSE) && sd->data) { size_t dest_index; GaimAccount *a = NULL; GtkTreePath *path = NULL; GtkTreeViewDropPosition position; memcpy(&a, sd->data, sizeof(a)); if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), x, y, &path, &position)) { GtkTreeIter iter; GaimAccount *account; GValue val = {0}; gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_DATA, &val); account = g_value_get_pointer(&val); switch (position) { case GTK_TREE_VIEW_DROP_AFTER: case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: move_account_after(dialog->model, &dialog->drag_iter, &iter); dest_index = g_list_index(gaim_accounts_get_all(), account) + 1; break; case GTK_TREE_VIEW_DROP_BEFORE: case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: dest_index = g_list_index(gaim_accounts_get_all(), account); move_account_before(dialog->model, &dialog->drag_iter, &iter); break; default: return; } gaim_accounts_reorder(a, dest_index); } } } static gint accedit_win_destroy_cb(GtkWidget *w, GdkEvent *event, AccountsWindow *dialog) { gaim_gtk_accounts_window_hide(); return 0; } static gboolean configure_cb(GtkWidget *w, GdkEventConfigure *event, AccountsWindow *dialog) { if (GTK_WIDGET_VISIBLE(w)) { int old_width = gaim_prefs_get_int("/gaim/gtk/accounts/dialog/width"); int col_width; int difference; gaim_prefs_set_int("/gaim/gtk/accounts/dialog/width", event->width); gaim_prefs_set_int("/gaim/gtk/accounts/dialog/height", event->height); col_width = gtk_tree_view_column_get_width(dialog->screenname_col); if (col_width == 0) return FALSE; difference = (MAX(old_width, event->width) - MIN(old_width, event->width)); if (difference == 0) return FALSE; if (old_width < event->width) gtk_tree_view_column_set_min_width(dialog->screenname_col, col_width + difference); else gtk_tree_view_column_set_max_width(dialog->screenname_col, col_width - difference); } return FALSE; } static void add_account_cb(GtkWidget *w, AccountsWindow *dialog) { gaim_gtk_account_dialog_show(GAIM_GTK_ADD_ACCOUNT_DIALOG, NULL); } static void modify_account_sel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GaimAccount *account; gtk_tree_model_get(model, iter, COLUMN_DATA, &account, -1); if (account != NULL) gaim_gtk_account_dialog_show(GAIM_GTK_MODIFY_ACCOUNT_DIALOG, account); } static void modify_account_cb(GtkWidget *w, AccountsWindow *dialog) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); gtk_tree_selection_selected_foreach(selection, modify_account_sel, dialog); } static void delete_account_cb(GaimAccount *account) { size_t index; GtkTreeIter iter; index = g_list_index(gaim_accounts_get_all(), account); if (accounts_window != NULL) { AccountPrefsDialog *dialog; if (gtk_tree_model_iter_nth_child( GTK_TREE_MODEL(accounts_window->model), &iter, NULL, index)) { gtk_list_store_remove(accounts_window->model, &iter); } if ((dialog = g_hash_table_lookup(accounts_window->account_pref_wins, account)) != NULL) { account_win_destroy_cb(NULL, NULL, dialog); } } gaim_accounts_delete(account); } static void ask_delete_account_sel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GaimAccount *account; gtk_tree_model_get(model, iter, COLUMN_DATA, &account, -1); if (account != NULL) { char *buf; buf = g_strdup_printf(_("Are you sure you want to delete %s?"), gaim_account_get_username(account)); gaim_request_action(NULL, NULL, buf, NULL, 1, account, 2, _("Delete"), delete_account_cb, _("Cancel"), NULL); g_free(buf); } } static void ask_delete_account_cb(GtkWidget *w, AccountsWindow *dialog) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); gtk_tree_selection_selected_foreach(selection, ask_delete_account_sel, dialog); } static void close_accounts_cb(GtkWidget *w, AccountsWindow *dialog) { gtk_widget_destroy(dialog->window); gaim_gtk_accounts_window_hide(); } static void online_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data) { AccountsWindow *dialog = (AccountsWindow *)data; GaimAccount *account; GtkTreeModel *model = GTK_TREE_MODEL(dialog->model); GtkTreeIter iter; GaimGtkPulseData *pulse_data; gboolean online; gtk_tree_model_get_iter_from_string(model, &iter, path_str); gtk_tree_model_get(model, &iter, COLUMN_DATA, &account, COLUMN_ONLINE, &online, -1); if (online) { account->gc->wants_to_die = TRUE; gaim_account_disconnect(account); } else { GdkPixbuf *pixbuf; pulse_data = g_new0(GaimGtkPulseData, 1); pulse_data->pulse_to_grey = TRUE; pulse_data->pulse_value = 0; pulse_data->account = account; pulse_data->model = model; pixbuf = create_prpl_icon(account); if (pixbuf != NULL) { pulse_data->online_pixbuf = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); g_object_unref(G_OBJECT(pixbuf)); } if (pulse_data->online_pixbuf == NULL) { g_free(pulse_data); } else { pulse_data->timeout = g_timeout_add(100, (GSourceFunc)account_pulse_update, pulse_data); gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_PULSE_DATA, pulse_data, -1); } gaim_account_connect(account); } } static void autologin_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data) { AccountsWindow *dialog = (AccountsWindow *)data; GaimAccount *account; GtkTreeModel *model = GTK_TREE_MODEL(dialog->model); GtkTreeIter iter; gboolean autologin; gtk_tree_model_get_iter_from_string(model, &iter, path_str); gtk_tree_model_get(model, &iter, COLUMN_DATA, &account, COLUMN_AUTOLOGIN, &autologin, -1); gaim_account_set_auto_login(account, GAIM_GTK_UI, !autologin); gtk_list_store_set(dialog->model, &iter, COLUMN_AUTOLOGIN, !autologin, -1); } static void add_columns(GtkWidget *treeview, AccountsWindow *dialog) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; /* Screen name column */ column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Screen Name")); gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1); gtk_tree_view_column_set_resizable(column, TRUE); /* Icon */ renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", COLUMN_ICON); /* Screen name */ renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", COLUMN_SCREENNAME); dialog->screenname_col = column; /* Online? */ renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(online_cb), dialog); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, _("Online"), renderer, "active", COLUMN_ONLINE, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 1); gtk_tree_view_column_set_resizable(column, TRUE); /* Auto-login? */ renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(autologin_cb), dialog); column = gtk_tree_view_column_new_with_attributes(_("Auto-login"), renderer, "active", COLUMN_AUTOLOGIN, NULL); gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1); gtk_tree_view_column_set_resizable(column, TRUE); /* Protocol name */ column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Protocol")); gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1); gtk_tree_view_column_set_resizable(column, TRUE); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", COLUMN_PROTOCOL); } static void set_account(GtkListStore *store, GtkTreeIter *iter, GaimAccount *account) { GdkPixbuf *pixbuf; GdkPixbuf *scale; scale = NULL; pixbuf = create_prpl_icon(account); if (pixbuf != NULL) { scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); if (!gaim_account_is_connected(account)) gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE); } gtk_list_store_set(store, iter, COLUMN_ICON, scale, COLUMN_SCREENNAME, gaim_account_get_username(account), COLUMN_ONLINE, gaim_account_is_connected(account), COLUMN_AUTOLOGIN, gaim_account_get_auto_login(account, GAIM_GTK_UI), COLUMN_PROTOCOL, proto_name(gaim_account_get_protocol_id(account)), COLUMN_DATA, account, -1); if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); if (scale != NULL) g_object_unref(G_OBJECT(scale)); } static void add_account(AccountsWindow *dialog, GaimAccount *account) { GtkTreeIter iter; gtk_list_store_append(dialog->model, &iter); set_account(dialog->model, &iter, account); } static void populate_accounts_list(AccountsWindow *dialog) { GList *l; gtk_list_store_clear(dialog->model); for (l = gaim_accounts_get_all(); l != NULL; l = l->next) add_account(dialog, (GaimAccount *)l->data); } #if !GTK_CHECK_VERSION(2,2,0) static void get_selected_helper(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { *((gboolean *)user_data) = TRUE; } #endif static void account_selected_cb(GtkTreeSelection *sel, AccountsWindow *dialog) { gboolean selected = FALSE; #if GTK_CHECK_VERSION(2,2,0) selected = (gtk_tree_selection_count_selected_rows(sel) > 0); #else gtk_tree_selection_selected_foreach(sel, get_selected_helper, &selected); #endif gtk_widget_set_sensitive(dialog->modify_button, selected); gtk_widget_set_sensitive(dialog->delete_button, selected); } static GtkWidget * create_accounts_list(AccountsWindow *dialog) { GtkWidget *sw; GtkWidget *treeview; GtkTreeSelection *sel; GtkTargetEntry gte[] = {{"GAIM_ACCOUNT", GTK_TARGET_SAME_APP, 0}}; /* Create the scrolled window. */ sw = gtk_scrolled_window_new(0, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); gtk_widget_show(sw); /* Create the list model. */ dialog->model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER); /* And now the actual treeview */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); dialog->treeview = treeview; gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_selection_set_mode( gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_MULTIPLE); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); add_columns(treeview, dialog); populate_accounts_list(dialog); sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(account_selected_cb), dialog); /* Setup DND. I wanna be an orc! */ gtk_tree_view_enable_model_drag_source( GTK_TREE_VIEW(treeview), GDK_BUTTON1_MASK, gte, 1, GDK_ACTION_COPY); gtk_tree_view_enable_model_drag_dest( GTK_TREE_VIEW(treeview), gte, 1, GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect(G_OBJECT(treeview), "drag-data-received", G_CALLBACK(drag_data_received_cb), dialog); g_signal_connect(G_OBJECT(treeview), "drag-data-get", G_CALLBACK(drag_data_get_cb), dialog); return sw; } void gaim_gtk_accounts_window_show(void) { AccountsWindow *dialog; GtkWidget *win; GtkWidget *vbox; GtkWidget *bbox; GtkWidget *sw; GtkWidget *sep; GtkWidget *button; int width, height; if (accounts_window != NULL) { gtk_window_present(GTK_WINDOW(accounts_window->window)); return; } accounts_window = dialog = g_new0(AccountsWindow, 1); accounts_window->account_pref_wins = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); width = gaim_prefs_get_int("/gaim/gtk/accounts/dialog/width"); height = gaim_prefs_get_int("/gaim/gtk/accounts/dialog/height"); dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(win), width, height); gtk_window_set_role(GTK_WINDOW(win), "accounts"); gtk_window_set_title(GTK_WINDOW(win), _("Accounts")); gtk_container_set_border_width(GTK_CONTAINER(win), 12); g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(accedit_win_destroy_cb), accounts_window); g_signal_connect(G_OBJECT(win), "configure_event", G_CALLBACK(configure_cb), accounts_window); /* Setup the vbox */ vbox = gtk_vbox_new(FALSE, 12); gtk_container_add(GTK_CONTAINER(win), vbox); gtk_widget_show(vbox); /* Setup the scrolled window that will contain the list of accounts. */ sw = create_accounts_list(dialog); gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); gtk_widget_show(sw); /* Separator... */ sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); gtk_widget_show(sep); /* Button box. */ bbox = gtk_hbutton_box_new(); gtk_box_set_spacing(GTK_BOX(bbox), 6); gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); gtk_widget_show(bbox); /* Add button */ button = gtk_button_new_from_stock(GTK_STOCK_ADD); gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(add_account_cb), dialog); /* Modify button */ button = gtk_button_new_from_stock(GAIM_STOCK_MODIFY); dialog->modify_button = button; gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_set_sensitive(button, FALSE); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(modify_account_cb), dialog); /* Delete button */ button = gtk_button_new_from_stock(GTK_STOCK_DELETE); dialog->delete_button = button; gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_set_sensitive(button, FALSE); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(ask_delete_account_cb), dialog); /* Close button */ button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(close_accounts_cb), dialog); /* Setup some gaim signal handlers. */ gaim_signal_connect(gaim_connections_get_handle(), "signed-on", dialog, GAIM_CALLBACK(signed_on_off_cb), dialog); gaim_signal_connect(gaim_connections_get_handle(), "signed-off", dialog, GAIM_CALLBACK(signed_on_off_cb), dialog); gtk_widget_show(win); } void gaim_gtk_accounts_window_hide(void) { if (accounts_window == NULL) return; gaim_signals_disconnect_by_handle(accounts_window); g_hash_table_destroy(accounts_window->account_pref_wins); g_free(accounts_window); accounts_window = NULL; /* See if we're the main window here. */ if (GAIM_GTK_BLIST(gaim_get_blist())->window == NULL && mainwindow == NULL && gaim_connections_get_all() == NULL) { gaim_core_quit(); } } static void free_add_user_data(GaimGtkAccountAddUserData *data) { g_free(data->username); if (data->alias != NULL) g_free(data->alias); g_free(data); } static void add_user_cb(GaimGtkAccountAddUserData *data) { GaimConnection *gc = gaim_account_get_connection(data->account); if (g_list_find(gaim_connections_get_all(), gc)) { gaim_blist_request_add_buddy(data->account, data->username, NULL, data->alias); } free_add_user_data(data); } static void gaim_gtk_accounts_notify_added(GaimAccount *account, const char *remote_user, const char *id, const char *alias, const char *msg) { char *buffer; GaimConnection *gc; GaimGtkAccountAddUserData *data; GaimBuddy *buddy; gc = gaim_account_get_connection(account); buddy = gaim_find_buddy(account, remote_user); data = g_new0(GaimGtkAccountAddUserData, 1); data->account = account; data->username = g_strdup(remote_user); data->alias = (alias != NULL ? g_strdup(alias) : NULL); buffer = g_strdup_printf(_("%s%s%s%s has made %s his or her buddy%s%s%s"), remote_user, (alias != NULL ? " (" : ""), (alias != NULL ? alias : ""), (alias != NULL ? ")" : ""), (id != NULL ? id : (gaim_connection_get_display_name(gc) != NULL ? gaim_connection_get_display_name(gc) : gaim_account_get_username(account))), (msg != NULL ? ": " : "."), (msg != NULL ? msg : ""), (buddy != NULL ? "" : _("\n\nDo you wish to add him or her to your buddy list?"))); if (buddy != NULL) { gaim_notify_info(NULL, NULL, _("Information"), buffer); } else { gaim_request_action(NULL, NULL, _("Add buddy to your list?"), buffer, 0, data, 2, _("Add"), G_CALLBACK(add_user_cb), _("Cancel"), G_CALLBACK(free_add_user_data)); } g_free(buffer); } static GaimAccountUiOps ui_ops = { gaim_gtk_accounts_notify_added }; GaimAccountUiOps * gaim_gtk_accounts_get_ui_ops(void) { return &ui_ops; } void * gaim_gtk_account_get_handle() { static int handle; return &handle; } void gaim_gtk_account_init(void) { gaim_signal_register(gaim_gtk_account_get_handle(), "account-modified", gaim_marshal_VOID__POINTER, NULL, 1, gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_ACCOUNT)); } void gaim_gtk_account_uninit(void) { gaim_signals_unregister_by_instance(gaim_gtk_account_get_handle()); }