Mercurial > pidgin.yaz
view src/gtkaccount.c @ 12116:e75ef7aa913e
[gaim-migrate @ 14416]
" This patch implements a replacement for the queuing
system from 1.x. It also obsoletes a previous patch
[#1338873] I submitted to prioritize the unseen states
in gtk conversations.
The attached envelope.png is ripped from the
msgunread.png already included in gaim. It should be
dropped in the pixmaps directory (Makefile.am is
updated accordingly in this patch).
The two separate queuing preferences from 1.x, queuing
messages while away and queuing all new messages (from
docklet), are replaced with a single 3-way preference
for conversations. The new preference is "Hide new IM
conversations". This preference can be set to never,
away and always.
When a gtk conversation is created, it may be placed in
a hidden conversation window instead of being placed
normally. This decision is based upon the preference
and possibly the away state of the account the
conversation is being created for. This *will* effect
conversations the user explicitly requests to be
created, so in these cases the caller must be sure to
present the conversation to the user, using
gaim_gtkconv_present_conversation(). This is done
already in gtkdialogs.c which handles creating
conversations requested by the user from gaim proper
(menus, double-clicking on budy in blist, etc.).
The main advantage to not queuing messages is that the
conversations exist, the message is written to the
conversation (and logged if appropriate) and the unseen
state is set on the conversation. This means no
additional features are needed to track whether there
are queued messages or not, just use the unseen state
on conversations.
Since conversations may not be visible (messages
"queued"), gaim proper needs some notification that
there are messages waiting. I opted for a menutray icon
that shows up when an im conversation has an unseen
message. Clicking this icon will focus (and show if
hidden) the first conversation with an unseen message.
This is essentially the same behavior of the docklet in
cvs right now, except that the icon is only visible
when there is a conversation with an unread message.
The api that is added is flexible enough to allow
either the docklet or the new blist menutray icon to be
visible for conversations of any/all types and for
unseen messages >= any state. Currently they are set to
only IM conversations and only unseen states >= TEXT
(system messages and no log messages will not trigger
blinking the docklet or showing the blist tray icon),
but these could be made preferences relatively easily
in the future. Other plugins could probably benefit as
well: gaim_gtk_conversations_get_first_unseen().
There is probably some limit to comment size, so I'll
stop rambling now. If anyone has more
questions/comments, catch me in #gaim, here or on
gaim-devel."
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Wed, 16 Nov 2005 18:17:01 +0000 |
parents | 36a0c8719af3 |
children | 943307dd6ee9 |
line wrap: on
line source
/** * @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 "internal.h" #include "gtkgaim.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 "savedstatuses.h" #include "signals.h" #include "util.h" #include "gtkaccount.h" #include "gtkblist.h" #include "gtkdialogs.h" #include "gtkutils.h" #include "gtkstatusbox.h" #include "gtkstock.h" enum { COLUMN_ICON, COLUMN_SCREENNAME, COLUMN_ENABLED, 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; } 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; /* 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; 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 GHashTable *account_pref_wins; static void add_account_to_liststore(GaimAccount *account, gpointer user_data); static void set_account(GtkListStore *store, GtkTreeIter *iter, GaimAccount *account); static char* convert_buddy_icon(GaimPlugin *plugin, const char *path); /************************************************************************** * 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, GAIM_HIG_BOX_SPACE); 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, GAIM_HIG_BORDER); gtk_widget_show(widget); gaim_set_accessible_label (widget, label); return hbox; } static void set_dialog_icon(AccountPrefsDialog *dialog) { char *filename = gaim_buddy_icons_get_full_path(dialog->icon_path); gtk_image_set_from_file(GTK_IMAGE(dialog->icon_entry), filename); g_free(filename); } 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 { if (dialog->prpl_info != NULL && (dialog->prpl_info->options & OPT_PROTO_REGISTER_NOSCREENNAME)) { gtk_widget_set_sensitive(dialog->register_button, TRUE); } else { gtk_widget_set_sensitive(dialog->register_button, FALSE); } 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) { if (dialog->prpl_info != NULL && (dialog->prpl_info->options & OPT_PROTO_REGISTER_NOSCREENNAME)) gtk_widget_set_sensitive(dialog->register_button, TRUE); else 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) { char *filename, *current_folder; 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)); current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel)); if (current_folder != NULL) { gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder); g_free(current_folder); } #else /* FILECHOOSER */ static void icon_filesel_choose_cb(GtkWidget *w, AccountPrefsDialog *dialog) { char *filename, *current_folder; filename = g_strdup(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))) { g_free(filename); return; } current_folder = g_path_get_dirname(filename); if (current_folder != NULL) { gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder); g_free(current_folder); } #endif /* FILECHOOSER */ if (dialog->icon_path) g_free(dialog->icon_path); dialog->icon_path = convert_buddy_icon(dialog->plugin, filename); set_dialog_icon(dialog); gtk_widget_show(dialog->icon_entry); gtk_widget_destroy(dialog->icon_filesel); dialog->icon_filesel = NULL; g_free(filename); } 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; 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 = g_strdup(gtk_file_selection_get_filename( GTK_FILE_SELECTION(dialog->icon_filesel))); #endif /* FILECHOOSER */ if (!filename || g_stat(filename, &st)) { g_free(filename); 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 */ g_free(filename); 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(_("<b>File:</b> %s\n" "<b>File size:</b> %s\n" "<b>Image size:</b> %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(filename); 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 */ const char *current_folder; if (dialog->icon_filesel != NULL) { gtk_window_present(GTK_WINDOW(dialog->icon_filesel)); return; } current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_icon_folder"); #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); if ((current_folder != NULL) && (*current_folder != '\0')) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel), current_folder); 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); if ((current_folder != NULL) && (*current_folder != '\0')) gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog->icon_filesel), current_folder); gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50); hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); 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 = (gchar *)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->plugin, tmp); set_dialog_icon(dialog); 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(GaimPlugin *plugin, 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(plugin); 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 #endif const char *dirname = gaim_buddy_icons_get_cache_dir(); char *random = g_strdup_printf("%x", g_random_int()); char *filename = g_build_filename(dirname, random, NULL); if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) { gaim_debug_info("buddyicon", "Creating icon cache directory.\n"); if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) { gaim_debug_error("buddyicon", "Unable to create directory %s: %s\n", dirname, strerror(errno)); #if GTK_CHECK_VERSION(2,2,0) g_strfreev(prpl_formats); #endif g_free(random); g_free(filename); return NULL; } } #if GTK_CHECK_VERSION(2,2,0) #if GTK_CHECK_VERSION(2,4,0) format = gdk_pixbuf_get_file_info (path, &width, &height); #else loader = gdk_pixbuf_loader_new(); if (!g_stat(path, &st) && (file = g_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 { gchar *contents; gsize length; FILE *image; #if GTK_CHECK_VERSION(2,2,0) g_strfreev(prpl_formats); g_strfreev(pixbuf_formats); #endif /* Copy the image to the cache folder as "filename". */ if (!g_file_get_contents(path, &contents, &length, NULL) || (image = g_fopen(filename, "wb")) == NULL) { g_free(random); g_free(filename); #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) g_object_unref(G_OBJECT(pixbuf)); #endif return NULL; } if (fwrite(contents, 1, length, image) != length) { fclose(image); g_unlink(filename); g_free(random); g_free(filename); #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) g_object_unref(G_OBJECT(pixbuf)); #endif return NULL; } fclose(image); #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) g_object_unref(G_OBJECT(pixbuf)); #endif g_free(filename); return random; } #if GTK_CHECK_VERSION(2,2,0) else { int i; GError *error = NULL; GdkPixbuf *scale; pixbuf = gdk_pixbuf_new_from_file(path, &error); g_strfreev(pixbuf_formats); if (!error && (prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) && (width < prpl_info->icon_spec.min_width || width > prpl_info->icon_spec.max_width || height < prpl_info->icon_spec.min_height || height > prpl_info->icon_spec.max_height)) { int new_width = width; int new_height = height; 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; /* preserve aspect ratio */ if ((double)height * (double)new_width > (double)width * (double)new_height) { new_width = 0.5 + (double)width * (double)new_height / (double)height; } else { new_height = 0.5 + (double)height * (double)new_width / (double)width; } 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(random); g_free(filename); gaim_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); g_error_free(error); g_strfreev(prpl_formats); 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; gaim_debug_warning("buddyicon", "Could not convert to %s: %s\n", prpl_formats[i], error->message); g_error_free(error); error = NULL; } g_strfreev(prpl_formats); if (!error) { g_object_unref(G_OBJECT(pixbuf)); g_free(filename); return random; } else { gaim_debug_error("buddyicon", "Could not convert icon to usable format: %s\n", error->message); g_error_free(error); } g_free(random); g_free(filename); 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, GAIM_HIG_BOX_SPACE); 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); gtk_entry_set_invisible_char(GTK_ENTRY(dialog->password_entry), GAIM_INVISIBLE_CHAR); 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); /* 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)); } 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, GAIM_HIG_BOX_SPACE); 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, GAIM_HIG_BOX_SPACE); 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, GAIM_HIG_BOX_SPACE); gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, GAIM_HIG_BORDER); 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)); set_dialog_icon(dialog); } } 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; GtkWidget *combo; GList *list; GList *node; gint i, idx; GtkListStore *model; GtkTreeIter iter; GtkCellRenderer *renderer; GaimKeyValuePair *kvp; 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, GAIM_HIG_BOX_SPACE); 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 (gaim_account_option_get_masked(option)) { gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); gtk_entry_set_invisible_char(GTK_ENTRY(entry), GAIM_INVISIBLE_CHAR); } 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; case GAIM_PREF_STRING_LIST: i = 0; idx = -1; 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)); } list = gaim_account_option_get_list(option); model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); //if (gaim_account_option_get_masked(option)) //gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); /* Loop through list of GaimKeyValuePair items */ for (node = list; node != NULL; node = node->next) { if (node->data != NULL) { kvp = (GaimKeyValuePair *) node->data; if ((idx < 0) && (kvp->value != NULL) && (str_value != NULL)) if (!g_utf8_collate(kvp->value, str_value)) idx = i; gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, kvp->key, 1, kvp->value, -1); } i++; } /* Set default */ if (idx >= 0) gtk_combo_box_set_active(GTK_COMBO_BOX(combo), idx); /* Define renderer */ renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "text", 0, NULL); title = g_strdup_printf("%s:", gaim_account_option_get_text(option)); add_pref_box(dialog, vbox, title, combo); g_free(title); dialog->protocol_opt_entries = g_list_append(dialog->protocol_opt_entries, combo); break; default: break; } } } static GtkWidget * make_proxy_dropdown(void) { GtkWidget *dropdown; 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); return dropdown; } static void proxy_type_changed_cb(GtkWidget *menu, AccountPrefsDialog *dialog) { dialog->new_proxy_type = gtk_combo_box_get_active(GTK_COMBO_BOX(menu)) - 1; 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, GAIM_HIG_BOX_SPACE); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); /* Proxy Type drop-down. */ dialog->proxy_dropdown = make_proxy_dropdown(); 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, GAIM_HIG_BOX_SPACE); gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, GAIM_HIG_BORDER); 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); gtk_entry_set_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry), GAIM_INVISIBLE_CHAR); 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; gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->proxy_dropdown), type + 1); 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; gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->proxy_dropdown), dialog->new_proxy_type + 1); 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) { g_hash_table_remove(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_path != NULL) { const char *icon = gaim_account_get_buddy_icon(dialog->account); if (dialog->icon_path != NULL && (icon == NULL || strcmp(dialog->icon_path, icon))) { /* The user set an icon, which would've been cached by convert_buddy_icon, * but didn't save the changes. Delete the cache file. */ char *filename = g_build_filename(gaim_buddy_icons_get_cache_dir(), dialog->icon_path, NULL); g_unlink(filename); g_free(filename); } g_free(dialog->icon_path); } 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; gboolean new = FALSE; GaimAccount *account; if (dialog->account == NULL) { const char *screenname; screenname = gtk_entry_get_text(GTK_ENTRY(dialog->screenname_entry)); account = gaim_account_new(screenname, dialog->protocol_id); new = TRUE; } else { account = dialog->account; /* Protocol */ gaim_account_set_protocol_id(account, dialog->protocol_id); } /* Alias */ value = gtk_entry_get_text(GTK_ENTRY(dialog->alias_entry)); if (*value != '\0') gaim_account_set_alias(account, value); else gaim_account_set_alias(account, NULL); /* Buddy Icon */ gaim_account_set_buddy_icon(account, dialog->icon_path); /* Remember Password */ gaim_account_set_remember_password(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(account, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(dialog->new_mail_check))); /* Password */ value = gtk_entry_get_text(GTK_ENTRY(dialog->password_entry)); /* * We set the password if this is a new account because new accounts * will be set to online, and if the user has entered a password into * the account editor (but has not checked the 'save' box), then we * don't want to prompt them. */ if ((gaim_account_get_remember_password(account) || new) && (*value != '\0')) gaim_account_set_password(account, value); else gaim_account_set_password(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(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; GtkTreeIter iter; 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(account, setting, value); break; case GAIM_PREF_INT: int_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget))); gaim_account_set_int(account, setting, int_value); break; case GAIM_PREF_BOOLEAN: bool_value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); gaim_account_set_bool(account, setting, bool_value); break; case GAIM_PREF_STRING_LIST: gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter); gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)), &iter, 1, &value, -1); gaim_account_set_string(dialog->account, setting, value); break; default: break; } } } /* Set the proxy stuff. */ if (dialog->new_proxy_type == GAIM_PROXY_USE_GLOBAL) { gaim_account_set_proxy_info(account, NULL); } else { proxy_info = gaim_account_get_proxy_info(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(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); } /* We no longer need the data from the dialog window */ account_win_destroy_cb(NULL, NULL, dialog); /* If this is a new account, add it to our list */ if (new) gaim_accounts_add(account); else gaim_signal_emit(gaim_gtk_account_get_handle(), "account-modified", account); /* If this is a new account, then sign on! */ if (new) { const char *current_savedstatus_name; const GaimSavedStatus *saved_status; gaim_account_set_enabled(account, GAIM_GTK_UI, TRUE); current_savedstatus_name = gaim_prefs_get_string("/core/status/current"); saved_status = gaim_savedstatus_find(current_savedstatus_name); gaim_savedstatus_activate_for_account(saved_status, account); } return account; } 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 *notebook; GtkWidget *button; if (accounts_window != NULL && account != NULL && (dialog = g_hash_table_lookup(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(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) { /* Select the first prpl in the list*/ GList *prpl_list = gaim_plugins_get_protocols(); if (prpl_list != NULL) dialog->protocol_id = g_strdup(((GaimPlugin *) prpl_list->data)->info->id); } 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), GAIM_HIG_BORDER); g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(account_win_destroy_cb), dialog); /* Setup the vbox */ main_vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); gtk_container_add(GTK_CONTAINER(win), main_vbox); gtk_widget_show(main_vbox); notebook = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX(main_vbox), notebook, FALSE, FALSE, 0); gtk_widget_show(GTK_WIDGET(notebook)); /* Setup the inner vbox */ dialog->top_vbox = vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); gtk_container_set_border_width(GTK_CONTAINER(vbox), GAIM_HIG_BORDER); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, gtk_label_new_with_mnemonic("_Basic")); gtk_widget_show(vbox); /* Setup the top frames. */ add_login_options(dialog, vbox); add_user_options(dialog, vbox); /* Setup the page with 'Advanced'. */ dialog->bottom_vbox = dbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); gtk_container_set_border_width(GTK_CONTAINER(dbox), GAIM_HIG_BORDER); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dbox, gtk_label_new_with_mnemonic("_Advanced")); gtk_widget_show(dbox); /** Setup the bottom frames. */ add_protocol_options(dialog, dbox); add_proxy_options(dialog, dbox); /* Setup the button box */ bbox = gtk_hbutton_box_new(); gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); 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 signed_on_off_cb(GaimConnection *gc, gpointer user_data) { GaimAccount *account; GaimGtkPulseData *pulse_data; GtkTreeModel *model; GtkTreeIter iter; GdkPixbuf *pixbuf, *scale = NULL; size_t index; /* Don't need to do anything if the accounts window is not visible */ if (accounts_window == NULL) return; account = gaim_connection_get_account(gc); model = GTK_TREE_MODEL(accounts_window->model); 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(accounts_window->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 = gaim_gtk_create_prpl_icon(account); if (pixbuf != NULL) { scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); if (gaim_account_is_disconnected(account)) gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE); } gtk_list_store_set(accounts_window->model, &iter, COLUMN_ICON, scale, COLUMN_PULSE_DATA, NULL, -1); if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); if (scale != NULL) g_object_unref(G_OBJECT(scale)); } } /* * Get the GtkTreeIter of the specified account in the * GtkListStore */ static gboolean accounts_window_find_account_in_treemodel(GtkTreeIter *iter, GaimAccount *account) { GtkTreeModel *model; GaimAccount *cur; g_return_val_if_fail(account != NULL, FALSE); g_return_val_if_fail(accounts_window != NULL, FALSE); model = GTK_TREE_MODEL(accounts_window->model); if (!gtk_tree_model_get_iter_first(model, iter)) return FALSE; gtk_tree_model_get(model, iter, COLUMN_DATA, &cur, -1); if (cur == account) return TRUE; while (gtk_tree_model_iter_next(model, iter)) { gtk_tree_model_get(model, iter, COLUMN_DATA, &cur, -1); if (cur == account) return TRUE; } return FALSE; } static void account_removed_cb(GaimAccount *account, gpointer user_data) { AccountPrefsDialog *dialog; GtkTreeIter iter; /* If the account was being modified, close the edit window */ if ((dialog = g_hash_table_lookup(account_pref_wins, account)) != NULL) account_win_destroy_cb(NULL, NULL, dialog); if (accounts_window == NULL) return; /* Remove the account from the GtkListStore */ if (accounts_window_find_account_in_treemodel(&iter, account)) gtk_list_store_remove(accounts_window->model, &iter); } static void account_abled_cb(GaimAccount *account, gpointer user_data) { GtkTreeIter iter; if (accounts_window == NULL) return; /* update the account in the GtkListStore */ if (accounts_window_find_account_in_treemodel(&iter, account)) gtk_list_store_set(accounts_window->model, &iter, COLUMN_ENABLED, GPOINTER_TO_INT(user_data), -1); } 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) { 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_close_with_handle(account); gaim_request_action(account, NULL, buf, NULL, 0, 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 enabled_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data) { AccountsWindow *dialog = (AccountsWindow *)data; GaimAccount *account; GtkTreeModel *model = GTK_TREE_MODEL(dialog->model); GtkTreeIter iter; gboolean enabled; const char *current_savedstatus_name; const GaimSavedStatus *saved_status; gtk_tree_model_get_iter_from_string(model, &iter, path_str); gtk_tree_model_get(model, &iter, COLUMN_DATA, &account, COLUMN_ENABLED, &enabled, -1); /* Set the statuses for this account to the current status */ current_savedstatus_name = gaim_prefs_get_string("/core/status/current"); saved_status = gaim_savedstatus_find(current_savedstatus_name); gaim_savedstatus_activate_for_account(saved_status, account); gaim_account_set_enabled(account, GAIM_GTK_UI, !enabled); } 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; /* Enabled */ renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(enabled_cb), dialog); column = gtk_tree_view_column_new_with_attributes(_("Enabled"), renderer, "active", COLUMN_ENABLED, 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 = gaim_gtk_create_prpl_icon(account); if (pixbuf != NULL) { scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); if (gaim_account_is_disconnected(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_ENABLED, gaim_account_get_enabled(account, GAIM_GTK_UI), COLUMN_PROTOCOL, gaim_account_get_protocol_name(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_to_liststore(GaimAccount *account, gpointer user_data) { GtkTreeIter iter; if (accounts_window == NULL) return; gtk_list_store_append(accounts_window->model, &iter); set_account(accounts_window->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_to_liststore((GaimAccount *)l->data, NULL); } #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 gboolean account_treeview_double_click_cb(GtkTreeView *treeview, GdkEventButton *event, gpointer user_data) { AccountsWindow *dialog; GtkTreePath *path; GtkTreeViewColumn *column; GtkTreeIter iter; GaimAccount *account; const gchar *title; dialog = (AccountsWindow *)user_data; /* Figure out which node was clicked */ if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dialog->treeview), event->x, event->y, &path, &column, NULL, NULL)) return FALSE; title = gtk_tree_view_column_get_title(column); column = gtk_tree_view_get_column(treeview, COLUMN_ENABLED-1); /* -1 required by weirdness in GtkTreeView */ gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_DATA, &account, -1); if ((account != NULL) && (event->button == 1) && (event->type == GDK_2BUTTON_PRESS) && (strcmp(gtk_tree_view_column_get_title(column), title))) { gaim_gtk_account_dialog_show(GAIM_GTK_MODIFY_ACCOUNT_DIALOG, account); return TRUE; } return FALSE; } 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_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); sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(account_selected_cb), dialog); /* Handle double-clicking */ g_signal_connect(G_OBJECT(treeview), "button_press_event", G_CALLBACK(account_treeview_double_click_cb), dialog); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); add_columns(treeview, dialog); populate_accounts_list(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 *button; int width, height; if (accounts_window != NULL) { gtk_window_present(GTK_WINDOW(accounts_window->window)); return; } accounts_window = dialog = g_new0(AccountsWindow, 1); 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), GAIM_HIG_BORDER); 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, GAIM_HIG_BORDER); 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); /* Button box. */ bbox = gtk_hbutton_box_new(); gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); 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); gtk_widget_show(win); } void gaim_gtk_accounts_window_hide(void) { if (accounts_window == NULL) return; gaim_signals_disconnect_by_handle(accounts_window); g_free(accounts_window); accounts_window = NULL; /* See if we're the main window here. */ if (GAIM_GTK_BLIST(gaim_get_blist())->window == 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, buffer, NULL); } else { gaim_request_action(NULL, NULL, _("Add buddy to your list?"), buffer, GAIM_DEFAULT_ACTION_NONE, 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, NULL }; 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_prefs_add_none("/gaim/gtk/accounts"); gaim_prefs_add_none("/gaim/gtk/accounts/dialog"); gaim_prefs_add_int("/gaim/gtk/accounts/dialog/width", 550); gaim_prefs_add_int("/gaim/gtk/accounts/dialog/height", 250); 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)); /* Setup some gaim signal handlers. */ gaim_signal_connect(gaim_connections_get_handle(), "signed-on", gaim_gtk_account_get_handle(), GAIM_CALLBACK(signed_on_off_cb), NULL); gaim_signal_connect(gaim_connections_get_handle(), "signed-off", gaim_gtk_account_get_handle(), GAIM_CALLBACK(signed_on_off_cb), NULL); gaim_signal_connect(gaim_accounts_get_handle(), "account-added", gaim_gtk_account_get_handle(), GAIM_CALLBACK(add_account_to_liststore), NULL); gaim_signal_connect(gaim_accounts_get_handle(), "account-removed", gaim_gtk_account_get_handle(), GAIM_CALLBACK(account_removed_cb), NULL); gaim_signal_connect(gaim_accounts_get_handle(), "account-disabled", gaim_gtk_account_get_handle(), GAIM_CALLBACK(account_abled_cb), GINT_TO_POINTER(FALSE)); gaim_signal_connect(gaim_accounts_get_handle(), "account-enabled", gaim_gtk_account_get_handle(), GAIM_CALLBACK(account_abled_cb), GINT_TO_POINTER(TRUE)); account_pref_wins = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); } void gaim_gtk_account_uninit(void) { /* * TODO: Need to free all the dialogs in here. Could probably create * a callback function to use for the free-some-data-function * parameter of g_hash_table_new_full, above. */ g_hash_table_destroy(account_pref_wins); gaim_signals_disconnect_by_handle(gaim_gtk_account_get_handle()); gaim_signals_unregister_by_instance(gaim_gtk_account_get_handle()); }