Renamed gtkft.[ch] to gtkxfer.[ch] soc.2013.gobjectification

Fri, 06 Sep 2013 17:32:12 +0530

author
Ankit Vani <a@nevitus.org>
date
Fri, 06 Sep 2013 17:32:12 +0530
branch
soc.2013.gobjectification
changeset 34929
4deeac0840fe
parent 34928
0d75a8dc179c
child 34930
3ae4a3bfbb33
child 36688
e49025233301

Renamed gtkft.[ch] to gtkxfer.[ch]

pidgin/Makefile.am file | annotate | diff | comparison | revisions
pidgin/gtkft.c file | annotate | diff | comparison | revisions
pidgin/gtkft.h file | annotate | diff | comparison | revisions
pidgin/gtkxfer.c file | annotate | diff | comparison | revisions
pidgin/gtkxfer.h file | annotate | diff | comparison | revisions
--- a/pidgin/Makefile.am	Fri Sep 06 17:29:25 2013 +0530
+++ b/pidgin/Makefile.am	Fri Sep 06 17:32:12 2013 +0530
@@ -57,7 +57,6 @@
 	gtkdnd-hints.c \
 	gtkdocklet.c \
 	gtkeventloop.c \
-	gtkft.c \
 	gtkicon-theme.c \
 	gtkicon-theme-loader.c \
 	gtkidle.c \
@@ -90,6 +89,7 @@
 	gtkwebview.c \
 	gtkwebviewtoolbar.c \
 	gtkwhiteboard.c \
+	gtkxfer.c \
 	minidialog.c \
 	pidgintooltip.c \
 	smileyparser.c
@@ -111,7 +111,6 @@
 	gtkdnd-hints.h \
 	gtkdocklet.h \
 	gtkeventloop.h \
-	gtkft.h \
 	gtkicon-theme.h \
 	gtkicon-theme-loader.h \
 	gtkidle.h \
@@ -145,6 +144,7 @@
 	gtkwebview.h \
 	gtkwebviewtoolbar.h \
 	gtkwhiteboard.h \
+	gtkxfer.h \
 	minidialog.h \
 	pidgintooltip.h \
 	pidgin.h \
--- a/pidgin/gtkft.c	Fri Sep 06 17:29:25 2013 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1247 +0,0 @@
-/**
- * @file gtkft.c GTK+ File Transfer UI
- * @ingroup pidgin
- */
-
-/* pidgin
- *
- * Pidgin 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#include "internal.h"
-#include "pidgin.h"
-
-#include "debug.h"
-#include "notify.h"
-#include "xfer.h"
-#include "prpl.h"
-#include "util.h"
-
-#include "gtkxfer.h"
-#include "prefs.h"
-#include "pidginstock.h"
-#include "gtkutils.h"
-
-/* the maximum size of files we will try to make a thumbnail for */
-#define PIDGIN_XFER_MAX_SIZE_IMAGE_THUMBNAIL 10 * 1024 * 1024
-
-struct _PidginXferDialog
-{
-	gboolean keep_open;
-	gboolean auto_clear;
-
-	gint num_transfers;
-
-	PurpleXfer *selected_xfer;
-
-	GtkWidget *window;
-	GtkWidget *tree;
-	GtkListStore *model;
-
-	GtkWidget *expander;
-
-	GtkWidget *table;
-
-	GtkWidget *local_user_desc_label;
-	GtkWidget *local_user_label;
-	GtkWidget *remote_user_desc_label;
-	GtkWidget *remote_user_label;
-	GtkWidget *protocol_label;
-	GtkWidget *filename_label;
-	GtkWidget *localfile_label;
-	GtkWidget *status_label;
-	GtkWidget *speed_label;
-	GtkWidget *time_elapsed_label;
-	GtkWidget *time_remaining_label;
-
-	GtkWidget *progress;
-
-	/* Buttons */
-	GtkWidget *open_button;
-	GtkWidget *remove_button;
-	GtkWidget *stop_button;
-	GtkWidget *close_button;
-};
-
-typedef struct
-{
-	GtkTreeIter iter;
-	time_t last_updated_time;
-	gboolean in_list;
-
-	char *name;
-
-} PidginXferUiData;
-
-static PidginXferDialog *xfer_dialog = NULL;
-
-enum
-{
-	COLUMN_STATUS = 0,
-	COLUMN_PROGRESS,
-	COLUMN_FILENAME,
-	COLUMN_SIZE,
-	COLUMN_REMAINING,
-	COLUMN_DATA,
-	NUM_COLUMNS
-};
-
-
-/**************************************************************************
- * Utility Functions
- **************************************************************************/
-static void
-get_xfer_info_strings(PurpleXfer *xfer, char **kbsec, char **time_elapsed,
-					  char **time_remaining)
-{
-	double kb_sent, kb_rem;
-	double kbps = 0.0;
-	time_t elapsed, now;
-
-	now = purple_xfer_get_end_time(xfer);
-	if (now == 0)
-		now = time(NULL);
-
-	kb_sent = purple_xfer_get_bytes_sent(xfer) / 1024.0;
-	kb_rem  = purple_xfer_get_bytes_remaining(xfer) / 1024.0;
-	elapsed = purple_xfer_get_start_time(xfer);
-	if (elapsed > 0)
-		elapsed = now - elapsed;
-	else
-		elapsed = 0;
-	kbps    = (elapsed > 0 ? (kb_sent / elapsed) : 0);
-
-	if (kbsec != NULL) {
-		*kbsec = g_strdup_printf(_("%.2f KiB/s"), kbps);
-	}
-
-	if (time_elapsed != NULL)
-	{
-		int h, m, s;
-		int secs_elapsed;
-
-		if (purple_xfer_get_start_time(xfer) > 0)
-		{
-			secs_elapsed = now - purple_xfer_get_start_time(xfer);
-
-			h = secs_elapsed / 3600;
-			m = (secs_elapsed % 3600) / 60;
-			s = secs_elapsed % 60;
-
-			*time_elapsed = g_strdup_printf("%d:%02d:%02d", h, m, s);
-		}
-		else
-		{
-			*time_elapsed = g_strdup(_("Not started"));
-		}
-	}
-
-	if (time_remaining != NULL) {
-		if (purple_xfer_is_completed(xfer)) {
-			*time_remaining = g_strdup(_("Finished"));
-		}
-		else if (purple_xfer_is_cancelled(xfer)) {
-			*time_remaining = g_strdup(_("Cancelled"));
-		}
-		else if (purple_xfer_get_size(xfer) == 0 || (kb_sent > 0 && kbps < 0.001)) {
-			*time_remaining = g_strdup(_("Unknown"));
-		}
-		else if (kb_sent <= 0) {
-			*time_remaining = g_strdup(_("Waiting for transfer to begin"));
-		}
-		else {
-			int h, m, s;
-			int secs_remaining;
-
-			secs_remaining = (int)(kb_rem / kbps);
-
-			h = secs_remaining / 3600;
-			m = (secs_remaining % 3600) / 60;
-			s = secs_remaining % 60;
-
-			*time_remaining = g_strdup_printf("%d:%02d:%02d", h, m, s);
-		}
-	}
-}
-
-static void
-update_title_progress(PidginXferDialog *dialog)
-{
-	gboolean valid;
-	GtkTreeIter iter;
-	int num_active_xfers = 0;
-	guint64 total_bytes_xferred = 0;
-	guint64 total_file_size = 0;
-
-	if (dialog->window == NULL)
-		return;
-
-	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->model), &iter);
-
-	/* Find all active transfers */
-	while (valid) {
-		GValue val;
-		PurpleXfer *xfer = NULL;
-
-		val.g_type = 0;
-		gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model),
-				&iter, COLUMN_DATA, &val);
-
-		xfer = g_value_get_pointer(&val);
-		if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_STARTED) {
-			num_active_xfers++;
-			total_bytes_xferred += purple_xfer_get_bytes_sent(xfer);
-			total_file_size += purple_xfer_get_size(xfer);
-		}
-
-		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(dialog->model), &iter);
-	}
-
-	/* Update the title */
-	if (num_active_xfers > 0)
-	{
-		gchar *title;
-		int total_pct = 0;
-
-		if (total_file_size > 0) {
-			total_pct = 100 * total_bytes_xferred / total_file_size;
-		}
-
-		title = g_strdup_printf(ngettext("File Transfers - %d%% of %d file",
-						 "File Transfers - %d%% of %d files",
-						 num_active_xfers),
-					total_pct, num_active_xfers);
-		gtk_window_set_title(GTK_WINDOW(dialog->window), title);
-		g_free(title);
-	} else {
-		gtk_window_set_title(GTK_WINDOW(dialog->window), _("File Transfers"));
-	}
-}
-
-static void
-update_detailed_info(PidginXferDialog *dialog, PurpleXfer *xfer)
-{
-	PidginXferUiData *data;
-	char *kbsec, *time_elapsed, *time_remaining;
-	char *status, *utf8;
-
-	if (dialog == NULL || xfer == NULL)
-		return;
-
-	data = purple_xfer_get_ui_data(xfer);
-
-	get_xfer_info_strings(xfer, &kbsec, &time_elapsed, &time_remaining);
-
-	status = g_strdup_printf("%d%% (%" G_GOFFSET_FORMAT " of %" G_GOFFSET_FORMAT " bytes)",
-							 (int)(purple_xfer_get_progress(xfer)*100),
-							 purple_xfer_get_bytes_sent(xfer),
-							 purple_xfer_get_size(xfer));
-
-	if (purple_xfer_is_completed(xfer)) {
-
-		GdkPixbuf *pixbuf = NULL;
-
-		pixbuf = gtk_widget_render_icon(xfer_dialog->window,
-										PIDGIN_STOCK_FILE_DONE,
-										GTK_ICON_SIZE_MENU, NULL);
-
-		gtk_list_store_set(GTK_LIST_STORE(xfer_dialog->model), &data->iter,
-						   COLUMN_STATUS, pixbuf,
-						   -1);
-
-		g_object_unref(pixbuf);
-	}
-
-	if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
-		gtk_label_set_markup(GTK_LABEL(dialog->local_user_desc_label),
-							 _("<b>Receiving As:</b>"));
-		gtk_label_set_markup(GTK_LABEL(dialog->remote_user_desc_label),
-							 _("<b>Receiving From:</b>"));
-	}
-	else {
-		gtk_label_set_markup(GTK_LABEL(dialog->remote_user_desc_label),
-							 _("<b>Sending To:</b>"));
-		gtk_label_set_markup(GTK_LABEL(dialog->local_user_desc_label),
-							 _("<b>Sending As:</b>"));
-	}
-
-	gtk_label_set_text(GTK_LABEL(dialog->local_user_label),
-								 purple_account_get_username(purple_xfer_get_account(xfer)));
-	gtk_label_set_text(GTK_LABEL(dialog->remote_user_label), purple_xfer_get_remote_user(xfer));
-	gtk_label_set_text(GTK_LABEL(dialog->protocol_label),
-								 purple_account_get_protocol_name(purple_xfer_get_account(xfer)));
-
-	if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
-		gtk_label_set_text(GTK_LABEL(dialog->filename_label),
-					   purple_xfer_get_filename(xfer));
-	} else {
-		char *tmp;
-
-		tmp = g_path_get_basename(purple_xfer_get_local_filename(xfer));
-		utf8 = g_filename_to_utf8(tmp, -1, NULL, NULL, NULL);
-		g_free(tmp);
-
-		gtk_label_set_text(GTK_LABEL(dialog->filename_label), utf8);
-		g_free(utf8);
-	}
-
-	utf8 = g_filename_to_utf8((purple_xfer_get_local_filename(xfer)), -1, NULL, NULL, NULL);
-	gtk_label_set_text(GTK_LABEL(dialog->localfile_label), utf8);
-	g_free(utf8);
-
-	gtk_label_set_text(GTK_LABEL(dialog->status_label), status);
-
-	gtk_label_set_text(GTK_LABEL(dialog->speed_label), kbsec);
-	gtk_label_set_text(GTK_LABEL(dialog->time_elapsed_label), time_elapsed);
-	gtk_label_set_text(GTK_LABEL(dialog->time_remaining_label),
-					   time_remaining);
-
-	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress),
-								  purple_xfer_get_progress(xfer));
-
-	g_free(kbsec);
-	g_free(time_elapsed);
-	g_free(time_remaining);
-	g_free(status);
-}
-
-static void
-update_buttons(PidginXferDialog *dialog, PurpleXfer *xfer)
-{
-	if (dialog->selected_xfer == NULL) {
-		gtk_widget_set_sensitive(dialog->expander, FALSE);
-		gtk_widget_set_sensitive(dialog->open_button, FALSE);
-		gtk_widget_set_sensitive(dialog->stop_button, FALSE);
-
-		gtk_widget_show(dialog->stop_button);
-		gtk_widget_hide(dialog->remove_button);
-
-		return;
-	}
-
-	if (dialog->selected_xfer != xfer)
-		return;
-
-	if (purple_xfer_is_completed(xfer)) {
-		gtk_widget_hide(dialog->stop_button);
-		gtk_widget_show(dialog->remove_button);
-
-#ifdef _WIN32
-		/* If using Win32... */
-		if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
-			gtk_widget_set_sensitive(dialog->open_button, TRUE);
-		} else {
-			gtk_widget_set_sensitive(dialog->open_button, FALSE);
-		}
-#else
-		if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
-			gtk_widget_set_sensitive(dialog->open_button, TRUE);
-		} else {
-			gtk_widget_set_sensitive (dialog->open_button, FALSE);
-		}
-#endif
-
-		gtk_widget_set_sensitive(dialog->remove_button, TRUE);
-	} else if (purple_xfer_is_cancelled(xfer)) {
-		gtk_widget_hide(dialog->stop_button);
-		gtk_widget_show(dialog->remove_button);
-
-		gtk_widget_set_sensitive(dialog->open_button,  FALSE);
-
-		gtk_widget_set_sensitive(dialog->remove_button, TRUE);
-	} else {
-		gtk_widget_show(dialog->stop_button);
-		gtk_widget_hide(dialog->remove_button);
-
-		gtk_widget_set_sensitive(dialog->open_button,  FALSE);
-		gtk_widget_set_sensitive(dialog->stop_button,   TRUE);
-	}
-}
-
-static void
-ensure_row_selected(PidginXferDialog *dialog)
-{
-	GtkTreeIter iter;
-	GtkTreeSelection *selection;
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree));
-
-	if (gtk_tree_selection_get_selected(selection, NULL, &iter))
-		return;
-
-	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->model), &iter))
-		gtk_tree_selection_select_iter(selection, &iter);
-}
-
-/**************************************************************************
- * Callbacks
- **************************************************************************/
-static gint
-delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
-{
-	PidginXferDialog *dialog;
-
-	dialog = (PidginXferDialog *)d;
-
-	pidgin_xfer_dialog_hide(dialog);
-
-	return TRUE;
-}
-
-static void
-toggle_keep_open_cb(GtkWidget *w, PidginXferDialog *dialog)
-{
-	dialog->keep_open = !dialog->keep_open;
-	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/filetransfer/keep_open",
-						dialog->keep_open);
-}
-
-static void
-toggle_clear_finished_cb(GtkWidget *w, PidginXferDialog *dialog)
-{
-	dialog->auto_clear = !dialog->auto_clear;
-	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/filetransfer/clear_finished",
-						dialog->auto_clear);
-}
-
-static void
-selection_changed_cb(GtkTreeSelection *selection, PidginXferDialog *dialog)
-{
-	GtkTreeIter iter;
-	PurpleXfer *xfer = NULL;
-
-	if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
-		GValue val;
-
-		gtk_widget_set_sensitive(dialog->expander, TRUE);
-
-		val.g_type = 0;
-		gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model),
-								 &iter, COLUMN_DATA, &val);
-
-		xfer = g_value_get_pointer(&val);
-
-		update_detailed_info(dialog, xfer);
-
-		dialog->selected_xfer = xfer;
-	}
-	else {
-		gtk_expander_set_expanded(GTK_EXPANDER(dialog->expander),
-									 FALSE);
-
-		gtk_widget_set_sensitive(dialog->expander, FALSE);
-
-		dialog->selected_xfer = NULL;
-	}
-
-	update_buttons(dialog, xfer);
-}
-
-static void
-open_button_cb(GtkButton *button, PidginXferDialog *dialog)
-{
-#ifdef _WIN32
-	/* If using Win32... */
-	int code;
-	wchar_t *wc_filename = g_utf8_to_utf16(
-			purple_xfer_get_local_filename(
-				dialog->selected_xfer),
-			-1, NULL, NULL, NULL);
-
-	code = (int) ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL,
-			SW_SHOW);
-
-	g_free(wc_filename);
-
-	if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC)
-	{
-		purple_notify_error(dialog, NULL,
-				_("There is no application configured to open this type of file."), NULL);
-	}
-	else if (code < 32)
-	{
-		purple_notify_error(dialog, NULL,
-				_("An error occurred while opening the file."), NULL);
-		purple_debug_warning("ft", "filename: %s; code: %d\n",
-				purple_xfer_get_local_filename(dialog->selected_xfer), code);
-	}
-#else
-	const char *filename = purple_xfer_get_local_filename(dialog->selected_xfer);
-	char *command = NULL;
-	char *tmp = NULL;
-	GError *error = NULL;
-
-	if (purple_running_gnome())
-	{
-		char *escaped = g_shell_quote(filename);
-		command = g_strdup_printf("gnome-open %s", escaped);
-		g_free(escaped);
-	}
-	else if (purple_running_kde())
-	{
-		char *escaped = g_shell_quote(filename);
-
-		if (purple_str_has_suffix(filename, ".desktop"))
-			command = g_strdup_printf("kfmclient openURL %s 'text/plain'", escaped);
-		else
-			command = g_strdup_printf("kfmclient openURL %s", escaped);
-		g_free(escaped);
-	}
-	else
-	{
-		purple_notify_uri(NULL, filename);
-		return;
-	}
-
-	if (purple_program_is_valid(command))
-	{
-		gint exit_status;
-		if (!g_spawn_command_line_sync(command, NULL, NULL, &exit_status, &error))
-		{
-			tmp = g_strdup_printf(_("Error launching %s: %s"),
-							purple_xfer_get_local_filename(dialog->selected_xfer),
-							error->message);
-			purple_notify_error(dialog, NULL, _("Unable to open file."), tmp);
-			g_free(tmp);
-			g_error_free(error);
-		}
-		if (exit_status != 0)
-		{
-			char *primary = g_strdup_printf(_("Error running %s"), command);
-			char *secondary = g_strdup_printf(_("Process returned error code %d"),
-									exit_status);
-			purple_notify_error(dialog, NULL, primary, secondary);
-			g_free(tmp);
-		}
-	}
-#endif
-}
-
-static void
-remove_button_cb(GtkButton *button, PidginXferDialog *dialog)
-{
-	pidgin_xfer_dialog_remove_xfer(dialog, dialog->selected_xfer);
-}
-
-static void
-stop_button_cb(GtkButton *button, PidginXferDialog *dialog)
-{
-	purple_xfer_cancel_local(dialog->selected_xfer);
-}
-
-static void
-close_button_cb(GtkButton *button, PidginXferDialog *dialog)
-{
-	pidgin_xfer_dialog_hide(dialog);
-}
-
-
-/**************************************************************************
- * Dialog Building Functions
- **************************************************************************/
-static GtkWidget *
-setup_tree(PidginXferDialog *dialog)
-{
-	GtkWidget *tree;
-	GtkListStore *model;
-	GtkCellRenderer *renderer;
-	GtkTreeViewColumn *column;
-	GtkTreeSelection *selection;
-
-	/* Build the tree model */
-	/* Transfer type, Progress Bar, Filename, Size, Remaining */
-	model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_INT,
-							   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-							   G_TYPE_POINTER);
-	dialog->model = model;
-
-	/* Create the treeview */
-	dialog->tree = tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
-	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
-	/* gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); */
-
-	gtk_widget_show(tree);
-
-	g_signal_connect(G_OBJECT(selection), "changed",
-					 G_CALLBACK(selection_changed_cb), dialog);
-
-	g_object_unref(G_OBJECT(model));
-
-
-	/* Columns */
-
-	/* Transfer Type column */
-	renderer = gtk_cell_renderer_pixbuf_new();
-	column = gtk_tree_view_column_new_with_attributes(NULL, renderer,
-				"pixbuf", COLUMN_STATUS, NULL);
-	gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
-									GTK_TREE_VIEW_COLUMN_FIXED);
-	gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(column), 25);
-	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
-
-	/* Progress bar column */
-	renderer = gtk_cell_renderer_progress_new();
-	column = gtk_tree_view_column_new_with_attributes(_("Progress"), renderer,
-				"value", COLUMN_PROGRESS, NULL);
-	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
-
-	/* Filename column */
-	renderer = gtk_cell_renderer_text_new();
-	column = gtk_tree_view_column_new_with_attributes(_("Filename"), renderer,
-				"text", COLUMN_FILENAME, NULL);
-	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
-
-	/* File Size column */
-	renderer = gtk_cell_renderer_text_new();
-	column = gtk_tree_view_column_new_with_attributes(_("Size"), renderer,
-				"text", COLUMN_SIZE, NULL);
-	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
-
-	/* Bytes Remaining column */
-	renderer = gtk_cell_renderer_text_new();
-	column = gtk_tree_view_column_new_with_attributes(_("Remaining"),
-				renderer, "text", COLUMN_REMAINING, NULL);
-	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
-
-	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree));
-
-	gtk_widget_show(tree);
-
-	return tree;
-}
-
-static GtkWidget *
-make_info_table(PidginXferDialog *dialog)
-{
-	GtkWidget *table;
-	GtkWidget *label;
-	gsize i;
-
-	struct
-	{
-		GtkWidget **desc_label;
-		GtkWidget **val_label;
-		const char *desc;
-
-	} labels[] =
-	{
-		{ &dialog->local_user_desc_label, &dialog->local_user_label, NULL },
-		{ &dialog->remote_user_desc_label, &dialog->remote_user_label, NULL },
-		{ &label, &dialog->protocol_label,       _("Protocol:") },
-		{ &label, &dialog->filename_label,       _("Filename:") },
-		{ &label, &dialog->localfile_label,      _("Local File:") },
-		{ &label, &dialog->status_label,         _("Status:") },
-		{ &label, &dialog->speed_label,          _("Speed:") },
-		{ &label, &dialog->time_elapsed_label,   _("Time Elapsed:") },
-		{ &label, &dialog->time_remaining_label, _("Time Remaining:") }
-	};
-
-	/* Setup the initial table */
-	dialog->table = table = gtk_table_new(G_N_ELEMENTS(labels) + 1, 2, FALSE);
-	gtk_table_set_row_spacings(GTK_TABLE(table), PIDGIN_HIG_BOX_SPACE);
-	gtk_table_set_col_spacings(GTK_TABLE(table), PIDGIN_HIG_BOX_SPACE);
-
-	/* Setup the labels */
-	for (i = 0; i < G_N_ELEMENTS(labels); i++) {
-		GtkWidget *label;
-		char buf[256];
-
-		g_snprintf(buf, sizeof(buf), "<b>%s</b>",
-			   labels[i].desc != NULL ? labels[i].desc : "");
-
-		*labels[i].desc_label = label = gtk_label_new(NULL);
-		gtk_label_set_markup(GTK_LABEL(label), buf);
-		gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
-		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-		gtk_table_attach(GTK_TABLE(table), label, 0, 1, i, i + 1,
-						 GTK_FILL, 0, 0, 0);
-		gtk_widget_show(label);
-
-		*labels[i].val_label = label = gtk_label_new(NULL);
-		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-		gtk_table_attach(GTK_TABLE(table), label, 1, 2, i, i + 1,
-						 GTK_FILL | GTK_EXPAND, 0, 0, 0);
-		gtk_widget_show(label);
-	}
-
-	/* Setup the progress bar */
-	dialog->progress = gtk_progress_bar_new();
-	gtk_table_attach(GTK_TABLE(table), dialog->progress,
-					 0, 2,
-					 G_N_ELEMENTS(labels), G_N_ELEMENTS(labels) + 1,
-					 GTK_FILL, GTK_FILL, 0, 0);
-	gtk_widget_show(dialog->progress);
-
-	return table;
-}
-
-PidginXferDialog *
-pidgin_xfer_dialog_new(void)
-{
-	PidginXferDialog *dialog;
-	GtkWidget *window;
-	GtkWidget *vbox;
-	GtkWidget *expander;
-	GtkWidget *alignment;
-	GtkWidget *table;
-	GtkWidget *checkbox;
-	GtkWidget *bbox;
-
-	dialog = g_new0(PidginXferDialog, 1);
-	dialog->keep_open =
-		purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/filetransfer/keep_open");
-	dialog->auto_clear =
-		purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/filetransfer/clear_finished");
-
-	/* Create the window. */
-#if GTK_CHECK_VERSION(3,0,0)
-	dialog->window = window = pidgin_create_dialog(_("File Transfers"), 0, "file transfer", TRUE);
-#else
-	dialog->window = window = pidgin_create_dialog(_("File Transfers"), PIDGIN_HIG_BORDER, "file transfer", TRUE);
-#endif
-	gtk_window_set_default_size(GTK_WINDOW(window), 450, 250);
-
-	g_signal_connect(G_OBJECT(window), "delete_event",
-					 G_CALLBACK(delete_win_cb), dialog);
-
-	/* Create the main vbox for top half of the window. */
-	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(window), FALSE, PIDGIN_HIG_BORDER);
-
-	/* Setup the listbox */
-	gtk_box_pack_start(GTK_BOX(vbox),
-		pidgin_make_scrollable(setup_tree(dialog), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 140),
-		TRUE, TRUE, 0);
-
-	/* "Close this window when all transfers finish" */
-	checkbox = gtk_check_button_new_with_mnemonic(
-			_("Close this window when all transfers _finish"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
-								 !dialog->keep_open);
-	g_signal_connect(G_OBJECT(checkbox), "toggled",
-					 G_CALLBACK(toggle_keep_open_cb), dialog);
-	gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
-	gtk_widget_show(checkbox);
-
-	/* "Clear finished transfers" */
-	checkbox = gtk_check_button_new_with_mnemonic(
-			_("C_lear finished transfers"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
-								 dialog->auto_clear);
-	g_signal_connect(G_OBJECT(checkbox), "toggled",
-					 G_CALLBACK(toggle_clear_finished_cb), dialog);
-	gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
-	gtk_widget_show(checkbox);
-
-	/* "Download Details" arrow */
-	expander = gtk_expander_new_with_mnemonic(_("File transfer _details"));
-	dialog->expander = expander;
-	gtk_box_pack_start(GTK_BOX(vbox), expander, FALSE, FALSE, 0);
-	gtk_widget_show(expander);
-
-	gtk_widget_set_sensitive(expander, FALSE);
-
-	/* Small indent make table fall under GtkExpander's label */
-	alignment = gtk_alignment_new(1, 0, 1, 1);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 20, 0);
-	gtk_container_add(GTK_CONTAINER(expander), alignment);
-	gtk_widget_show(alignment);
-
-	/* The table of information. */
-	table = make_info_table(dialog);
-	gtk_container_add(GTK_CONTAINER(alignment), table);
-	gtk_widget_show(table);
-
-	bbox = pidgin_dialog_get_action_area(GTK_DIALOG(window));
-
-#define ADD_BUTTON(b, label, callback, callbackdata) do { \
-		GtkWidget *button = gtk_button_new_from_stock(label); \
-		gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); \
-		g_signal_connect(G_OBJECT(button), "clicked", callback, callbackdata); \
-		gtk_widget_show(button); \
-		b = button; \
-	} while (0)
-
-	/* Open button */
-	ADD_BUTTON(dialog->open_button, GTK_STOCK_OPEN, G_CALLBACK(open_button_cb), dialog);
-	gtk_widget_set_sensitive(dialog->open_button, FALSE);
-
-	/* Remove button */
-	ADD_BUTTON(dialog->remove_button, GTK_STOCK_REMOVE, G_CALLBACK(remove_button_cb), dialog);
-	gtk_widget_hide(dialog->remove_button);
-
-	/* Stop button */
-	ADD_BUTTON(dialog->stop_button, GTK_STOCK_STOP, G_CALLBACK(stop_button_cb), dialog);
-	gtk_widget_set_sensitive(dialog->stop_button, FALSE);
-
-	/* Close button */
-	ADD_BUTTON(dialog->close_button, GTK_STOCK_CLOSE, G_CALLBACK(close_button_cb), dialog);
-
-#undef ADD_BUTTON
-
-#ifdef _WIN32
-	g_signal_connect(G_OBJECT(dialog->window), "show",
-		G_CALLBACK(winpidgin_ensure_onscreen), dialog->window);
-#endif
-
-	return dialog;
-}
-
-void
-pidgin_xfer_dialog_destroy(PidginXferDialog *dialog)
-{
-	g_return_if_fail(dialog != NULL);
-
-	purple_notify_close_with_handle(dialog);
-
-	gtk_widget_destroy(dialog->window);
-
-	g_free(dialog);
-}
-
-void
-pidgin_xfer_dialog_show(PidginXferDialog *dialog)
-{
-	PidginXferDialog *tmp;
-
-	if (dialog == NULL) {
-		tmp = pidgin_get_xfer_dialog();
-
-		if (tmp == NULL) {
-			tmp = pidgin_xfer_dialog_new();
-			pidgin_set_xfer_dialog(tmp);
-		}
-
-		gtk_widget_show(tmp->window);
-	} else {
-		gtk_window_present(GTK_WINDOW(dialog->window));
-	}
-}
-
-void
-pidgin_xfer_dialog_hide(PidginXferDialog *dialog)
-{
-	g_return_if_fail(dialog != NULL);
-
-	purple_notify_close_with_handle(dialog);
-
-	gtk_widget_hide(dialog->window);
-}
-
-void
-pidgin_xfer_dialog_add_xfer(PidginXferDialog *dialog, PurpleXfer *xfer)
-{
-	PidginXferUiData *data;
-	PurpleXferType type;
-	GdkPixbuf *pixbuf;
-	char *size_str, *remaining_str;
-	char *lfilename, *utf8;
-
-	g_return_if_fail(dialog != NULL);
-	g_return_if_fail(xfer != NULL);
-
-	g_object_ref(xfer);
-
-	data = purple_xfer_get_ui_data(xfer);
-	data->in_list = TRUE;
-
-	pidgin_xfer_dialog_show(dialog);
-
-	data->last_updated_time = 0;
-
-	type = purple_xfer_get_xfer_type(xfer);
-
-	size_str      = purple_str_size_to_units(purple_xfer_get_size(xfer));
-	remaining_str = purple_str_size_to_units(purple_xfer_get_bytes_remaining(xfer));
-
-	pixbuf = gtk_widget_render_icon(dialog->window,
-									(type == PURPLE_XFER_TYPE_RECEIVE
-									 ? PIDGIN_STOCK_DOWNLOAD
-									 : PIDGIN_STOCK_UPLOAD),
-									GTK_ICON_SIZE_MENU, NULL);
-
-	gtk_list_store_append(dialog->model, &data->iter);
-	lfilename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
-	utf8 = g_filename_to_utf8(lfilename, -1, NULL, NULL, NULL);
-	g_free(lfilename);
-	lfilename = utf8;
-	gtk_list_store_set(dialog->model, &data->iter,
-					   COLUMN_STATUS, pixbuf,
-					   COLUMN_PROGRESS, 0,
-					   COLUMN_FILENAME, (type == PURPLE_XFER_TYPE_RECEIVE)
-					                     ? purple_xfer_get_filename(xfer)
-							     : lfilename,
-					   COLUMN_SIZE, size_str,
-					   COLUMN_REMAINING, _("Waiting for transfer to begin"),
-					   COLUMN_DATA, xfer,
-					   -1);
-	g_free(lfilename);
-
-	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(dialog->tree));
-
-	g_object_unref(pixbuf);
-
-	g_free(size_str);
-	g_free(remaining_str);
-
-	dialog->num_transfers++;
-
-	ensure_row_selected(dialog);
-	update_title_progress(dialog);
-}
-
-void
-pidgin_xfer_dialog_remove_xfer(PidginXferDialog *dialog,
-								PurpleXfer *xfer)
-{
-	PidginXferUiData *data;
-
-	g_return_if_fail(dialog != NULL);
-	g_return_if_fail(xfer != NULL);
-
-	data = purple_xfer_get_ui_data(xfer);
-
-	if (data == NULL)
-		return;
-
-	if (!data->in_list)
-		return;
-
-	data->in_list = FALSE;
-
-	gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &data->iter);
-
-	dialog->num_transfers--;
-
-	ensure_row_selected(dialog);
-
-	update_title_progress(dialog);
-	g_object_unref(xfer);
-}
-
-void
-pidgin_xfer_dialog_cancel_xfer(PidginXferDialog *dialog,
-								PurpleXfer *xfer)
-{
-	PidginXferUiData *data;
-	GdkPixbuf *pixbuf;
-	const gchar *status;
-
-	g_return_if_fail(dialog != NULL);
-	g_return_if_fail(xfer != NULL);
-
-	data = purple_xfer_get_ui_data(xfer);
-
-	if (data == NULL)
-		return;
-
-	if (!data->in_list)
-		return;
-
-	if ((purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) && (dialog->auto_clear)) {
-		pidgin_xfer_dialog_remove_xfer(dialog, xfer);
-		return;
-	}
-
-	data = purple_xfer_get_ui_data(xfer);
-
-	update_detailed_info(dialog, xfer);
-	update_title_progress(dialog);
-
-	pixbuf = gtk_widget_render_icon(dialog->window,
-									PIDGIN_STOCK_FILE_CANCELED,
-									GTK_ICON_SIZE_MENU, NULL);
-
-	if (purple_xfer_is_cancelled(xfer))
-		status = _("Cancelled");
-	else
-		status = _("Failed");
-
-	gtk_list_store_set(dialog->model, &data->iter,
-	                   COLUMN_STATUS, pixbuf,
-	                   COLUMN_REMAINING, status,
-	                   -1);
-
-	g_object_unref(pixbuf);
-
-	update_buttons(dialog, xfer);
-}
-
-void
-pidgin_xfer_dialog_update_xfer(PidginXferDialog *dialog,
-								PurpleXfer *xfer)
-{
-	PidginXferUiData *data;
-	char *size_str, *remaining_str;
-	time_t current_time;
-	GtkTreeIter iter;
-	gboolean valid;
-
-	g_return_if_fail(dialog != NULL);
-	g_return_if_fail(xfer != NULL);
-
-	if ((data = purple_xfer_get_ui_data(xfer)) == NULL)
-		return;
-
-	if (data->in_list == FALSE)
-		return;
-
-	current_time = time(NULL);
-	if (((current_time - data->last_updated_time) == 0) &&
-		(!purple_xfer_is_completed(xfer)))
-	{
-		/* Don't update the window more than once per second */
-		return;
-	}
-	data->last_updated_time = current_time;
-
-	size_str      = purple_str_size_to_units(purple_xfer_get_size(xfer));
-	remaining_str = purple_str_size_to_units(purple_xfer_get_bytes_remaining(xfer));
-
-	gtk_list_store_set(xfer_dialog->model, &data->iter,
-					   COLUMN_PROGRESS, (gint)(purple_xfer_get_progress(xfer) * 100),
-					   COLUMN_SIZE, size_str,
-					   COLUMN_REMAINING, remaining_str,
-					   -1);
-
-	g_free(size_str);
-	g_free(remaining_str);
-
-	if (purple_xfer_is_completed(xfer))
-	{
-		GdkPixbuf *pixbuf;
-
-		pixbuf = gtk_widget_render_icon(dialog->window,
-										PIDGIN_STOCK_FILE_DONE,
-										GTK_ICON_SIZE_MENU, NULL);
-
-		gtk_list_store_set(GTK_LIST_STORE(xfer_dialog->model), &data->iter,
-						   COLUMN_STATUS, pixbuf,
-						   COLUMN_REMAINING, _("Finished"),
-						   -1);
-
-		g_object_unref(pixbuf);
-	}
-
-	update_title_progress(dialog);
-	if (xfer == dialog->selected_xfer)
-		update_detailed_info(xfer_dialog, xfer);
-
-	if (purple_xfer_is_completed(xfer) && dialog->auto_clear)
-		pidgin_xfer_dialog_remove_xfer(dialog, xfer);
-	else
-		update_buttons(dialog, xfer);
-
-	/*
-	 * If all transfers are finished, and the pref is set, then
-	 * close the dialog.  Otherwise just exit this function.
-	 */
-	if (dialog->keep_open)
-		return;
-
-	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->model), &iter);
-	while (valid)
-	{
-		GValue val;
-		PurpleXfer *next;
-
-		val.g_type = 0;
-		gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model),
-				&iter, COLUMN_DATA, &val);
-
-		next = g_value_get_pointer(&val);
-		if (!purple_xfer_is_completed(next))
-			return;
-
-		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(dialog->model), &iter);
-	}
-
-	/* If we got to this point then we know everything is finished */
-	pidgin_xfer_dialog_hide(dialog);
-}
-
-/**************************************************************************
- * File Transfer UI Ops
- **************************************************************************/
-static void
-pidgin_xfer_new_xfer(PurpleXfer *xfer)
-{
-	PidginXferUiData *data;
-
-	/* This is where we're setting xfer's "ui_data" for the first time. */
-	data = g_new0(PidginXferUiData, 1);
-	purple_xfer_set_ui_data(xfer, data);
-}
-
-static void
-pidgin_xfer_destroy(PurpleXfer *xfer)
-{
-	PidginXferUiData *data;
-
-	data = purple_xfer_get_ui_data(xfer);
-	if (data) {
-		g_free(data->name);
-		g_free(data);
-		purple_xfer_set_ui_data(xfer, NULL);
-	}
-}
-
-static void
-pidgin_xfer_add_xfer(PurpleXfer *xfer)
-{
-	if (xfer_dialog == NULL)
-		xfer_dialog = pidgin_xfer_dialog_new();
-
-	pidgin_xfer_dialog_add_xfer(xfer_dialog, xfer);
-}
-
-static void
-pidgin_xfer_update_progress(PurpleXfer *xfer, double percent)
-{
-	pidgin_xfer_dialog_update_xfer(xfer_dialog, xfer);
-}
-
-static void
-pidgin_xfer_cancel_local(PurpleXfer *xfer)
-{
-	if (xfer_dialog)
-		pidgin_xfer_dialog_cancel_xfer(xfer_dialog, xfer);
-}
-
-static void
-pidgin_xfer_cancel_remote(PurpleXfer *xfer)
-{
-	if (xfer_dialog)
-		pidgin_xfer_dialog_cancel_xfer(xfer_dialog, xfer);
-}
-
-static void
-pidgin_xfer_add_thumbnail(PurpleXfer *xfer, const gchar *formats)
-{
-	purple_debug_info("ft", "creating thumbnail for transfer\n");
-
-	if (purple_xfer_get_size(xfer) <= PIDGIN_XFER_MAX_SIZE_IMAGE_THUMBNAIL) {
-		GdkPixbuf *thumbnail =
-			pidgin_pixbuf_new_from_file_at_size(
-					purple_xfer_get_local_filename(xfer), 128, 128);
-
-		if (thumbnail) {
-			gchar **formats_split = g_strsplit(formats, ",", 0);
-			gchar *buffer = NULL;
-			gsize size;
-			char *option_keys[2] = {NULL, NULL};
-			char *option_values[2] = {NULL, NULL};
-			int i;
-			gchar *format = NULL;
-
-			for (i = 0; formats_split[i]; i++) {
-				if (purple_strequal(formats_split[i], "jpeg")) {
-					purple_debug_info("ft", "creating JPEG thumbnail\n");
-					option_keys[0] = "quality";
-					option_values[0] = "90";
-					format = "jpeg";
-					break;
-				} else if (purple_strequal(formats_split[i], "png")) {
-					purple_debug_info("ft", "creating PNG thumbnail\n");
-					option_keys[0] = "compression";
-					option_values[0] = "9";
-					format = "png";
-					break;
-				}
-			}
-
-			/* Try the first format given by the PRPL without options */
-			if (format == NULL) {
-				purple_debug_info("ft",
-				    "creating thumbnail of format %s as demanded by PRPL\n",
-				    formats_split[0]);
-				format = formats_split[0];
-			}
-
-			gdk_pixbuf_save_to_bufferv(thumbnail, &buffer, &size, format,
-				option_keys, option_values, NULL);
-
-			if (buffer) {
-				gchar *mimetype = g_strdup_printf("image/%s", format);
-				purple_debug_info("ft",
-				                  "created thumbnail of %" G_GSIZE_FORMAT " bytes\n",
-					size);
-				purple_xfer_set_thumbnail(xfer, buffer, size, mimetype);
-				g_free(buffer);
-				g_free(mimetype);
-			}
-			g_object_unref(thumbnail);
-			g_strfreev(formats_split);
-		}
-	}
-}
-
-static PurpleXferUiOps ops =
-{
-	pidgin_xfer_new_xfer,
-	pidgin_xfer_destroy,
-	pidgin_xfer_add_xfer,
-	pidgin_xfer_update_progress,
-	pidgin_xfer_cancel_local,
-	pidgin_xfer_cancel_remote,
-	NULL,
-	NULL,
-	NULL,
-	pidgin_xfer_add_thumbnail
-};
-
-/**************************************************************************
- * GTK+ File Transfer API
- **************************************************************************/
-void
-pidgin_xfers_init(void)
-{
-	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/filetransfer");
-	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/filetransfer/clear_finished", TRUE);
-	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/filetransfer/keep_open", FALSE);
-}
-
-void
-pidgin_xfers_uninit(void)
-{
-	if (xfer_dialog != NULL)
-		pidgin_xfer_dialog_destroy(xfer_dialog);
-}
-
-void
-pidgin_set_xfer_dialog(PidginXferDialog *dialog)
-{
-	xfer_dialog = dialog;
-}
-
-PidginXferDialog *
-pidgin_get_xfer_dialog(void)
-{
-	return xfer_dialog;
-}
-
-PurpleXferUiOps *
-pidgin_xfers_get_ui_ops(void)
-{
-	return &ops;
-}
--- a/pidgin/gtkft.h	Fri Sep 06 17:29:25 2013 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/**
- * @file gtkxfer.h GTK+ File Transfer UI
- * @ingroup pidgin
- */
-
-/* pidgin
- *
- * Pidgin 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#ifndef _PIDGINFT_H_
-#define _PIDGINFT_H_
-
-#include "xfer.h"
-
-/**
- * A file transfer dialog.
- *
- * The structure is opaque, as nobody should be touching anything inside of
- * it.
- */
-typedef struct _PidginXferDialog PidginXferDialog;
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/** @name GTK+ File Transfer Dialog API                                   */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Creates a new file transfer dialog.
- *
- * @return The new dialog.
- */
-PidginXferDialog *pidgin_xfer_dialog_new(void);
-
-/**
- * Destroys a file transfer dialog.
- *
- * @param dialog The file transfer dialog.
- */
-void pidgin_xfer_dialog_destroy(PidginXferDialog *dialog);
-
-/**
- * Displays the file transfer dialog given.
- * If dialog is @c NULL, displays the default dialog, creating one if necessary
- *
- * @param dialog The file transfer dialog to show.
- */
-void pidgin_xfer_dialog_show(PidginXferDialog *dialog);
-
-/**
- * Hides the file transfer dialog.
- *
- * @param dialog The file transfer dialog to hide.
- */
-void pidgin_xfer_dialog_hide(PidginXferDialog *dialog);
-
-/**
- * Adds a file transfer to the dialog.
- *
- * @param dialog The file transfer dialog.
- * @param xfer   The file transfer.
- */
-void pidgin_xfer_dialog_add_xfer(PidginXferDialog *dialog, PurpleXfer *xfer);
-
-/**
- * Removes a file transfer from the dialog.
- *
- * @param dialog The file transfer dialog.
- * @param xfer   The file transfer.
- */
-void pidgin_xfer_dialog_remove_xfer(PidginXferDialog *dialog,
-									 PurpleXfer *xfer);
-
-/**
- * Indicate in a file transfer dialog that a transfer was cancelled.
- *
- * @param dialog The file transfer dialog.
- * @param xfer   The file transfer that was cancelled.
- */
-void pidgin_xfer_dialog_cancel_xfer(PidginXferDialog *dialog,
-									 PurpleXfer *xfer);
-
-/**
- * Updates the information for a transfer in the dialog.
- *
- * @param dialog The file transfer dialog.
- * @param xfer   The file transfer.
- */
-void pidgin_xfer_dialog_update_xfer(PidginXferDialog *dialog,
-									 PurpleXfer *xfer);
-
-/*@}*/
-
-/**************************************************************************/
-/** @name GTK+ File Transfer API                                          */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Initializes the GTK+ file transfer system.
- */
-void pidgin_xfers_init(void);
-
-/**
- * Uninitializes the GTK+ file transfer system.
- */
-void pidgin_xfers_uninit(void);
-
-/**
- * Sets pidgin's main file transfer dialog.
- *
- * @param dialog The main dialog.
- */
-void pidgin_set_xfer_dialog(PidginXferDialog *dialog);
-
-/**
- * Returns pirgin's main file transfer dialog.
- *
- * @return The main dialog.
- */
-PidginXferDialog *pidgin_get_xfer_dialog(void);
-
-/**
- * Returns the UI operations structure for the GTK+ file transfer UI.
- *
- * @return The GTK+ file transfer UI operations structure.
- */
-PurpleXferUiOps *pidgin_xfers_get_ui_ops(void);
-
-/*@}*/
-
-G_END_DECLS
-
-#endif /* _PIDGINFT_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkxfer.c	Fri Sep 06 17:32:12 2013 +0530
@@ -0,0 +1,1247 @@
+/**
+ * @file gtkxfer.c GTK+ File Transfer UI
+ * @ingroup pidgin
+ */
+
+/* pidgin
+ *
+ * Pidgin 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+#include "pidgin.h"
+
+#include "debug.h"
+#include "notify.h"
+#include "xfer.h"
+#include "prpl.h"
+#include "util.h"
+
+#include "gtkxfer.h"
+#include "prefs.h"
+#include "pidginstock.h"
+#include "gtkutils.h"
+
+/* the maximum size of files we will try to make a thumbnail for */
+#define PIDGIN_XFER_MAX_SIZE_IMAGE_THUMBNAIL 10 * 1024 * 1024
+
+struct _PidginXferDialog
+{
+	gboolean keep_open;
+	gboolean auto_clear;
+
+	gint num_transfers;
+
+	PurpleXfer *selected_xfer;
+
+	GtkWidget *window;
+	GtkWidget *tree;
+	GtkListStore *model;
+
+	GtkWidget *expander;
+
+	GtkWidget *table;
+
+	GtkWidget *local_user_desc_label;
+	GtkWidget *local_user_label;
+	GtkWidget *remote_user_desc_label;
+	GtkWidget *remote_user_label;
+	GtkWidget *protocol_label;
+	GtkWidget *filename_label;
+	GtkWidget *localfile_label;
+	GtkWidget *status_label;
+	GtkWidget *speed_label;
+	GtkWidget *time_elapsed_label;
+	GtkWidget *time_remaining_label;
+
+	GtkWidget *progress;
+
+	/* Buttons */
+	GtkWidget *open_button;
+	GtkWidget *remove_button;
+	GtkWidget *stop_button;
+	GtkWidget *close_button;
+};
+
+typedef struct
+{
+	GtkTreeIter iter;
+	time_t last_updated_time;
+	gboolean in_list;
+
+	char *name;
+
+} PidginXferUiData;
+
+static PidginXferDialog *xfer_dialog = NULL;
+
+enum
+{
+	COLUMN_STATUS = 0,
+	COLUMN_PROGRESS,
+	COLUMN_FILENAME,
+	COLUMN_SIZE,
+	COLUMN_REMAINING,
+	COLUMN_DATA,
+	NUM_COLUMNS
+};
+
+
+/**************************************************************************
+ * Utility Functions
+ **************************************************************************/
+static void
+get_xfer_info_strings(PurpleXfer *xfer, char **kbsec, char **time_elapsed,
+					  char **time_remaining)
+{
+	double kb_sent, kb_rem;
+	double kbps = 0.0;
+	time_t elapsed, now;
+
+	now = purple_xfer_get_end_time(xfer);
+	if (now == 0)
+		now = time(NULL);
+
+	kb_sent = purple_xfer_get_bytes_sent(xfer) / 1024.0;
+	kb_rem  = purple_xfer_get_bytes_remaining(xfer) / 1024.0;
+	elapsed = purple_xfer_get_start_time(xfer);
+	if (elapsed > 0)
+		elapsed = now - elapsed;
+	else
+		elapsed = 0;
+	kbps    = (elapsed > 0 ? (kb_sent / elapsed) : 0);
+
+	if (kbsec != NULL) {
+		*kbsec = g_strdup_printf(_("%.2f KiB/s"), kbps);
+	}
+
+	if (time_elapsed != NULL)
+	{
+		int h, m, s;
+		int secs_elapsed;
+
+		if (purple_xfer_get_start_time(xfer) > 0)
+		{
+			secs_elapsed = now - purple_xfer_get_start_time(xfer);
+
+			h = secs_elapsed / 3600;
+			m = (secs_elapsed % 3600) / 60;
+			s = secs_elapsed % 60;
+
+			*time_elapsed = g_strdup_printf("%d:%02d:%02d", h, m, s);
+		}
+		else
+		{
+			*time_elapsed = g_strdup(_("Not started"));
+		}
+	}
+
+	if (time_remaining != NULL) {
+		if (purple_xfer_is_completed(xfer)) {
+			*time_remaining = g_strdup(_("Finished"));
+		}
+		else if (purple_xfer_is_cancelled(xfer)) {
+			*time_remaining = g_strdup(_("Cancelled"));
+		}
+		else if (purple_xfer_get_size(xfer) == 0 || (kb_sent > 0 && kbps < 0.001)) {
+			*time_remaining = g_strdup(_("Unknown"));
+		}
+		else if (kb_sent <= 0) {
+			*time_remaining = g_strdup(_("Waiting for transfer to begin"));
+		}
+		else {
+			int h, m, s;
+			int secs_remaining;
+
+			secs_remaining = (int)(kb_rem / kbps);
+
+			h = secs_remaining / 3600;
+			m = (secs_remaining % 3600) / 60;
+			s = secs_remaining % 60;
+
+			*time_remaining = g_strdup_printf("%d:%02d:%02d", h, m, s);
+		}
+	}
+}
+
+static void
+update_title_progress(PidginXferDialog *dialog)
+{
+	gboolean valid;
+	GtkTreeIter iter;
+	int num_active_xfers = 0;
+	guint64 total_bytes_xferred = 0;
+	guint64 total_file_size = 0;
+
+	if (dialog->window == NULL)
+		return;
+
+	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->model), &iter);
+
+	/* Find all active transfers */
+	while (valid) {
+		GValue val;
+		PurpleXfer *xfer = NULL;
+
+		val.g_type = 0;
+		gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model),
+				&iter, COLUMN_DATA, &val);
+
+		xfer = g_value_get_pointer(&val);
+		if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_STARTED) {
+			num_active_xfers++;
+			total_bytes_xferred += purple_xfer_get_bytes_sent(xfer);
+			total_file_size += purple_xfer_get_size(xfer);
+		}
+
+		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(dialog->model), &iter);
+	}
+
+	/* Update the title */
+	if (num_active_xfers > 0)
+	{
+		gchar *title;
+		int total_pct = 0;
+
+		if (total_file_size > 0) {
+			total_pct = 100 * total_bytes_xferred / total_file_size;
+		}
+
+		title = g_strdup_printf(ngettext("File Transfers - %d%% of %d file",
+						 "File Transfers - %d%% of %d files",
+						 num_active_xfers),
+					total_pct, num_active_xfers);
+		gtk_window_set_title(GTK_WINDOW(dialog->window), title);
+		g_free(title);
+	} else {
+		gtk_window_set_title(GTK_WINDOW(dialog->window), _("File Transfers"));
+	}
+}
+
+static void
+update_detailed_info(PidginXferDialog *dialog, PurpleXfer *xfer)
+{
+	PidginXferUiData *data;
+	char *kbsec, *time_elapsed, *time_remaining;
+	char *status, *utf8;
+
+	if (dialog == NULL || xfer == NULL)
+		return;
+
+	data = purple_xfer_get_ui_data(xfer);
+
+	get_xfer_info_strings(xfer, &kbsec, &time_elapsed, &time_remaining);
+
+	status = g_strdup_printf("%d%% (%" G_GOFFSET_FORMAT " of %" G_GOFFSET_FORMAT " bytes)",
+							 (int)(purple_xfer_get_progress(xfer)*100),
+							 purple_xfer_get_bytes_sent(xfer),
+							 purple_xfer_get_size(xfer));
+
+	if (purple_xfer_is_completed(xfer)) {
+
+		GdkPixbuf *pixbuf = NULL;
+
+		pixbuf = gtk_widget_render_icon(xfer_dialog->window,
+										PIDGIN_STOCK_FILE_DONE,
+										GTK_ICON_SIZE_MENU, NULL);
+
+		gtk_list_store_set(GTK_LIST_STORE(xfer_dialog->model), &data->iter,
+						   COLUMN_STATUS, pixbuf,
+						   -1);
+
+		g_object_unref(pixbuf);
+	}
+
+	if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
+		gtk_label_set_markup(GTK_LABEL(dialog->local_user_desc_label),
+							 _("<b>Receiving As:</b>"));
+		gtk_label_set_markup(GTK_LABEL(dialog->remote_user_desc_label),
+							 _("<b>Receiving From:</b>"));
+	}
+	else {
+		gtk_label_set_markup(GTK_LABEL(dialog->remote_user_desc_label),
+							 _("<b>Sending To:</b>"));
+		gtk_label_set_markup(GTK_LABEL(dialog->local_user_desc_label),
+							 _("<b>Sending As:</b>"));
+	}
+
+	gtk_label_set_text(GTK_LABEL(dialog->local_user_label),
+								 purple_account_get_username(purple_xfer_get_account(xfer)));
+	gtk_label_set_text(GTK_LABEL(dialog->remote_user_label), purple_xfer_get_remote_user(xfer));
+	gtk_label_set_text(GTK_LABEL(dialog->protocol_label),
+								 purple_account_get_protocol_name(purple_xfer_get_account(xfer)));
+
+	if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
+		gtk_label_set_text(GTK_LABEL(dialog->filename_label),
+					   purple_xfer_get_filename(xfer));
+	} else {
+		char *tmp;
+
+		tmp = g_path_get_basename(purple_xfer_get_local_filename(xfer));
+		utf8 = g_filename_to_utf8(tmp, -1, NULL, NULL, NULL);
+		g_free(tmp);
+
+		gtk_label_set_text(GTK_LABEL(dialog->filename_label), utf8);
+		g_free(utf8);
+	}
+
+	utf8 = g_filename_to_utf8((purple_xfer_get_local_filename(xfer)), -1, NULL, NULL, NULL);
+	gtk_label_set_text(GTK_LABEL(dialog->localfile_label), utf8);
+	g_free(utf8);
+
+	gtk_label_set_text(GTK_LABEL(dialog->status_label), status);
+
+	gtk_label_set_text(GTK_LABEL(dialog->speed_label), kbsec);
+	gtk_label_set_text(GTK_LABEL(dialog->time_elapsed_label), time_elapsed);
+	gtk_label_set_text(GTK_LABEL(dialog->time_remaining_label),
+					   time_remaining);
+
+	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress),
+								  purple_xfer_get_progress(xfer));
+
+	g_free(kbsec);
+	g_free(time_elapsed);
+	g_free(time_remaining);
+	g_free(status);
+}
+
+static void
+update_buttons(PidginXferDialog *dialog, PurpleXfer *xfer)
+{
+	if (dialog->selected_xfer == NULL) {
+		gtk_widget_set_sensitive(dialog->expander, FALSE);
+		gtk_widget_set_sensitive(dialog->open_button, FALSE);
+		gtk_widget_set_sensitive(dialog->stop_button, FALSE);
+
+		gtk_widget_show(dialog->stop_button);
+		gtk_widget_hide(dialog->remove_button);
+
+		return;
+	}
+
+	if (dialog->selected_xfer != xfer)
+		return;
+
+	if (purple_xfer_is_completed(xfer)) {
+		gtk_widget_hide(dialog->stop_button);
+		gtk_widget_show(dialog->remove_button);
+
+#ifdef _WIN32
+		/* If using Win32... */
+		if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
+			gtk_widget_set_sensitive(dialog->open_button, TRUE);
+		} else {
+			gtk_widget_set_sensitive(dialog->open_button, FALSE);
+		}
+#else
+		if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) {
+			gtk_widget_set_sensitive(dialog->open_button, TRUE);
+		} else {
+			gtk_widget_set_sensitive (dialog->open_button, FALSE);
+		}
+#endif
+
+		gtk_widget_set_sensitive(dialog->remove_button, TRUE);
+	} else if (purple_xfer_is_cancelled(xfer)) {
+		gtk_widget_hide(dialog->stop_button);
+		gtk_widget_show(dialog->remove_button);
+
+		gtk_widget_set_sensitive(dialog->open_button,  FALSE);
+
+		gtk_widget_set_sensitive(dialog->remove_button, TRUE);
+	} else {
+		gtk_widget_show(dialog->stop_button);
+		gtk_widget_hide(dialog->remove_button);
+
+		gtk_widget_set_sensitive(dialog->open_button,  FALSE);
+		gtk_widget_set_sensitive(dialog->stop_button,   TRUE);
+	}
+}
+
+static void
+ensure_row_selected(PidginXferDialog *dialog)
+{
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree));
+
+	if (gtk_tree_selection_get_selected(selection, NULL, &iter))
+		return;
+
+	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->model), &iter))
+		gtk_tree_selection_select_iter(selection, &iter);
+}
+
+/**************************************************************************
+ * Callbacks
+ **************************************************************************/
+static gint
+delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
+{
+	PidginXferDialog *dialog;
+
+	dialog = (PidginXferDialog *)d;
+
+	pidgin_xfer_dialog_hide(dialog);
+
+	return TRUE;
+}
+
+static void
+toggle_keep_open_cb(GtkWidget *w, PidginXferDialog *dialog)
+{
+	dialog->keep_open = !dialog->keep_open;
+	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/filetransfer/keep_open",
+						dialog->keep_open);
+}
+
+static void
+toggle_clear_finished_cb(GtkWidget *w, PidginXferDialog *dialog)
+{
+	dialog->auto_clear = !dialog->auto_clear;
+	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/filetransfer/clear_finished",
+						dialog->auto_clear);
+}
+
+static void
+selection_changed_cb(GtkTreeSelection *selection, PidginXferDialog *dialog)
+{
+	GtkTreeIter iter;
+	PurpleXfer *xfer = NULL;
+
+	if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
+		GValue val;
+
+		gtk_widget_set_sensitive(dialog->expander, TRUE);
+
+		val.g_type = 0;
+		gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model),
+								 &iter, COLUMN_DATA, &val);
+
+		xfer = g_value_get_pointer(&val);
+
+		update_detailed_info(dialog, xfer);
+
+		dialog->selected_xfer = xfer;
+	}
+	else {
+		gtk_expander_set_expanded(GTK_EXPANDER(dialog->expander),
+									 FALSE);
+
+		gtk_widget_set_sensitive(dialog->expander, FALSE);
+
+		dialog->selected_xfer = NULL;
+	}
+
+	update_buttons(dialog, xfer);
+}
+
+static void
+open_button_cb(GtkButton *button, PidginXferDialog *dialog)
+{
+#ifdef _WIN32
+	/* If using Win32... */
+	int code;
+	wchar_t *wc_filename = g_utf8_to_utf16(
+			purple_xfer_get_local_filename(
+				dialog->selected_xfer),
+			-1, NULL, NULL, NULL);
+
+	code = (int) ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL,
+			SW_SHOW);
+
+	g_free(wc_filename);
+
+	if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC)
+	{
+		purple_notify_error(dialog, NULL,
+				_("There is no application configured to open this type of file."), NULL);
+	}
+	else if (code < 32)
+	{
+		purple_notify_error(dialog, NULL,
+				_("An error occurred while opening the file."), NULL);
+		purple_debug_warning("ft", "filename: %s; code: %d\n",
+				purple_xfer_get_local_filename(dialog->selected_xfer), code);
+	}
+#else
+	const char *filename = purple_xfer_get_local_filename(dialog->selected_xfer);
+	char *command = NULL;
+	char *tmp = NULL;
+	GError *error = NULL;
+
+	if (purple_running_gnome())
+	{
+		char *escaped = g_shell_quote(filename);
+		command = g_strdup_printf("gnome-open %s", escaped);
+		g_free(escaped);
+	}
+	else if (purple_running_kde())
+	{
+		char *escaped = g_shell_quote(filename);
+
+		if (purple_str_has_suffix(filename, ".desktop"))
+			command = g_strdup_printf("kfmclient openURL %s 'text/plain'", escaped);
+		else
+			command = g_strdup_printf("kfmclient openURL %s", escaped);
+		g_free(escaped);
+	}
+	else
+	{
+		purple_notify_uri(NULL, filename);
+		return;
+	}
+
+	if (purple_program_is_valid(command))
+	{
+		gint exit_status;
+		if (!g_spawn_command_line_sync(command, NULL, NULL, &exit_status, &error))
+		{
+			tmp = g_strdup_printf(_("Error launching %s: %s"),
+							purple_xfer_get_local_filename(dialog->selected_xfer),
+							error->message);
+			purple_notify_error(dialog, NULL, _("Unable to open file."), tmp);
+			g_free(tmp);
+			g_error_free(error);
+		}
+		if (exit_status != 0)
+		{
+			char *primary = g_strdup_printf(_("Error running %s"), command);
+			char *secondary = g_strdup_printf(_("Process returned error code %d"),
+									exit_status);
+			purple_notify_error(dialog, NULL, primary, secondary);
+			g_free(tmp);
+		}
+	}
+#endif
+}
+
+static void
+remove_button_cb(GtkButton *button, PidginXferDialog *dialog)
+{
+	pidgin_xfer_dialog_remove_xfer(dialog, dialog->selected_xfer);
+}
+
+static void
+stop_button_cb(GtkButton *button, PidginXferDialog *dialog)
+{
+	purple_xfer_cancel_local(dialog->selected_xfer);
+}
+
+static void
+close_button_cb(GtkButton *button, PidginXferDialog *dialog)
+{
+	pidgin_xfer_dialog_hide(dialog);
+}
+
+
+/**************************************************************************
+ * Dialog Building Functions
+ **************************************************************************/
+static GtkWidget *
+setup_tree(PidginXferDialog *dialog)
+{
+	GtkWidget *tree;
+	GtkListStore *model;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection;
+
+	/* Build the tree model */
+	/* Transfer type, Progress Bar, Filename, Size, Remaining */
+	model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_INT,
+							   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+							   G_TYPE_POINTER);
+	dialog->model = model;
+
+	/* Create the treeview */
+	dialog->tree = tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
+	/* gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); */
+
+	gtk_widget_show(tree);
+
+	g_signal_connect(G_OBJECT(selection), "changed",
+					 G_CALLBACK(selection_changed_cb), dialog);
+
+	g_object_unref(G_OBJECT(model));
+
+
+	/* Columns */
+
+	/* Transfer Type column */
+	renderer = gtk_cell_renderer_pixbuf_new();
+	column = gtk_tree_view_column_new_with_attributes(NULL, renderer,
+				"pixbuf", COLUMN_STATUS, NULL);
+	gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
+									GTK_TREE_VIEW_COLUMN_FIXED);
+	gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(column), 25);
+	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
+
+	/* Progress bar column */
+	renderer = gtk_cell_renderer_progress_new();
+	column = gtk_tree_view_column_new_with_attributes(_("Progress"), renderer,
+				"value", COLUMN_PROGRESS, NULL);
+	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
+
+	/* Filename column */
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes(_("Filename"), renderer,
+				"text", COLUMN_FILENAME, NULL);
+	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
+
+	/* File Size column */
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes(_("Size"), renderer,
+				"text", COLUMN_SIZE, NULL);
+	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
+
+	/* Bytes Remaining column */
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes(_("Remaining"),
+				renderer, "text", COLUMN_REMAINING, NULL);
+	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
+
+	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree));
+
+	gtk_widget_show(tree);
+
+	return tree;
+}
+
+static GtkWidget *
+make_info_table(PidginXferDialog *dialog)
+{
+	GtkWidget *table;
+	GtkWidget *label;
+	gsize i;
+
+	struct
+	{
+		GtkWidget **desc_label;
+		GtkWidget **val_label;
+		const char *desc;
+
+	} labels[] =
+	{
+		{ &dialog->local_user_desc_label, &dialog->local_user_label, NULL },
+		{ &dialog->remote_user_desc_label, &dialog->remote_user_label, NULL },
+		{ &label, &dialog->protocol_label,       _("Protocol:") },
+		{ &label, &dialog->filename_label,       _("Filename:") },
+		{ &label, &dialog->localfile_label,      _("Local File:") },
+		{ &label, &dialog->status_label,         _("Status:") },
+		{ &label, &dialog->speed_label,          _("Speed:") },
+		{ &label, &dialog->time_elapsed_label,   _("Time Elapsed:") },
+		{ &label, &dialog->time_remaining_label, _("Time Remaining:") }
+	};
+
+	/* Setup the initial table */
+	dialog->table = table = gtk_table_new(G_N_ELEMENTS(labels) + 1, 2, FALSE);
+	gtk_table_set_row_spacings(GTK_TABLE(table), PIDGIN_HIG_BOX_SPACE);
+	gtk_table_set_col_spacings(GTK_TABLE(table), PIDGIN_HIG_BOX_SPACE);
+
+	/* Setup the labels */
+	for (i = 0; i < G_N_ELEMENTS(labels); i++) {
+		GtkWidget *label;
+		char buf[256];
+
+		g_snprintf(buf, sizeof(buf), "<b>%s</b>",
+			   labels[i].desc != NULL ? labels[i].desc : "");
+
+		*labels[i].desc_label = label = gtk_label_new(NULL);
+		gtk_label_set_markup(GTK_LABEL(label), buf);
+		gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, i, i + 1,
+						 GTK_FILL, 0, 0, 0);
+		gtk_widget_show(label);
+
+		*labels[i].val_label = label = gtk_label_new(NULL);
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+		gtk_table_attach(GTK_TABLE(table), label, 1, 2, i, i + 1,
+						 GTK_FILL | GTK_EXPAND, 0, 0, 0);
+		gtk_widget_show(label);
+	}
+
+	/* Setup the progress bar */
+	dialog->progress = gtk_progress_bar_new();
+	gtk_table_attach(GTK_TABLE(table), dialog->progress,
+					 0, 2,
+					 G_N_ELEMENTS(labels), G_N_ELEMENTS(labels) + 1,
+					 GTK_FILL, GTK_FILL, 0, 0);
+	gtk_widget_show(dialog->progress);
+
+	return table;
+}
+
+PidginXferDialog *
+pidgin_xfer_dialog_new(void)
+{
+	PidginXferDialog *dialog;
+	GtkWidget *window;
+	GtkWidget *vbox;
+	GtkWidget *expander;
+	GtkWidget *alignment;
+	GtkWidget *table;
+	GtkWidget *checkbox;
+	GtkWidget *bbox;
+
+	dialog = g_new0(PidginXferDialog, 1);
+	dialog->keep_open =
+		purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/filetransfer/keep_open");
+	dialog->auto_clear =
+		purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/filetransfer/clear_finished");
+
+	/* Create the window. */
+#if GTK_CHECK_VERSION(3,0,0)
+	dialog->window = window = pidgin_create_dialog(_("File Transfers"), 0, "file transfer", TRUE);
+#else
+	dialog->window = window = pidgin_create_dialog(_("File Transfers"), PIDGIN_HIG_BORDER, "file transfer", TRUE);
+#endif
+	gtk_window_set_default_size(GTK_WINDOW(window), 450, 250);
+
+	g_signal_connect(G_OBJECT(window), "delete_event",
+					 G_CALLBACK(delete_win_cb), dialog);
+
+	/* Create the main vbox for top half of the window. */
+	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(window), FALSE, PIDGIN_HIG_BORDER);
+
+	/* Setup the listbox */
+	gtk_box_pack_start(GTK_BOX(vbox),
+		pidgin_make_scrollable(setup_tree(dialog), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 140),
+		TRUE, TRUE, 0);
+
+	/* "Close this window when all transfers finish" */
+	checkbox = gtk_check_button_new_with_mnemonic(
+			_("Close this window when all transfers _finish"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
+								 !dialog->keep_open);
+	g_signal_connect(G_OBJECT(checkbox), "toggled",
+					 G_CALLBACK(toggle_keep_open_cb), dialog);
+	gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
+	gtk_widget_show(checkbox);
+
+	/* "Clear finished transfers" */
+	checkbox = gtk_check_button_new_with_mnemonic(
+			_("C_lear finished transfers"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
+								 dialog->auto_clear);
+	g_signal_connect(G_OBJECT(checkbox), "toggled",
+					 G_CALLBACK(toggle_clear_finished_cb), dialog);
+	gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
+	gtk_widget_show(checkbox);
+
+	/* "Download Details" arrow */
+	expander = gtk_expander_new_with_mnemonic(_("File transfer _details"));
+	dialog->expander = expander;
+	gtk_box_pack_start(GTK_BOX(vbox), expander, FALSE, FALSE, 0);
+	gtk_widget_show(expander);
+
+	gtk_widget_set_sensitive(expander, FALSE);
+
+	/* Small indent make table fall under GtkExpander's label */
+	alignment = gtk_alignment_new(1, 0, 1, 1);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 20, 0);
+	gtk_container_add(GTK_CONTAINER(expander), alignment);
+	gtk_widget_show(alignment);
+
+	/* The table of information. */
+	table = make_info_table(dialog);
+	gtk_container_add(GTK_CONTAINER(alignment), table);
+	gtk_widget_show(table);
+
+	bbox = pidgin_dialog_get_action_area(GTK_DIALOG(window));
+
+#define ADD_BUTTON(b, label, callback, callbackdata) do { \
+		GtkWidget *button = gtk_button_new_from_stock(label); \
+		gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); \
+		g_signal_connect(G_OBJECT(button), "clicked", callback, callbackdata); \
+		gtk_widget_show(button); \
+		b = button; \
+	} while (0)
+
+	/* Open button */
+	ADD_BUTTON(dialog->open_button, GTK_STOCK_OPEN, G_CALLBACK(open_button_cb), dialog);
+	gtk_widget_set_sensitive(dialog->open_button, FALSE);
+
+	/* Remove button */
+	ADD_BUTTON(dialog->remove_button, GTK_STOCK_REMOVE, G_CALLBACK(remove_button_cb), dialog);
+	gtk_widget_hide(dialog->remove_button);
+
+	/* Stop button */
+	ADD_BUTTON(dialog->stop_button, GTK_STOCK_STOP, G_CALLBACK(stop_button_cb), dialog);
+	gtk_widget_set_sensitive(dialog->stop_button, FALSE);
+
+	/* Close button */
+	ADD_BUTTON(dialog->close_button, GTK_STOCK_CLOSE, G_CALLBACK(close_button_cb), dialog);
+
+#undef ADD_BUTTON
+
+#ifdef _WIN32
+	g_signal_connect(G_OBJECT(dialog->window), "show",
+		G_CALLBACK(winpidgin_ensure_onscreen), dialog->window);
+#endif
+
+	return dialog;
+}
+
+void
+pidgin_xfer_dialog_destroy(PidginXferDialog *dialog)
+{
+	g_return_if_fail(dialog != NULL);
+
+	purple_notify_close_with_handle(dialog);
+
+	gtk_widget_destroy(dialog->window);
+
+	g_free(dialog);
+}
+
+void
+pidgin_xfer_dialog_show(PidginXferDialog *dialog)
+{
+	PidginXferDialog *tmp;
+
+	if (dialog == NULL) {
+		tmp = pidgin_get_xfer_dialog();
+
+		if (tmp == NULL) {
+			tmp = pidgin_xfer_dialog_new();
+			pidgin_set_xfer_dialog(tmp);
+		}
+
+		gtk_widget_show(tmp->window);
+	} else {
+		gtk_window_present(GTK_WINDOW(dialog->window));
+	}
+}
+
+void
+pidgin_xfer_dialog_hide(PidginXferDialog *dialog)
+{
+	g_return_if_fail(dialog != NULL);
+
+	purple_notify_close_with_handle(dialog);
+
+	gtk_widget_hide(dialog->window);
+}
+
+void
+pidgin_xfer_dialog_add_xfer(PidginXferDialog *dialog, PurpleXfer *xfer)
+{
+	PidginXferUiData *data;
+	PurpleXferType type;
+	GdkPixbuf *pixbuf;
+	char *size_str, *remaining_str;
+	char *lfilename, *utf8;
+
+	g_return_if_fail(dialog != NULL);
+	g_return_if_fail(xfer != NULL);
+
+	g_object_ref(xfer);
+
+	data = purple_xfer_get_ui_data(xfer);
+	data->in_list = TRUE;
+
+	pidgin_xfer_dialog_show(dialog);
+
+	data->last_updated_time = 0;
+
+	type = purple_xfer_get_xfer_type(xfer);
+
+	size_str      = purple_str_size_to_units(purple_xfer_get_size(xfer));
+	remaining_str = purple_str_size_to_units(purple_xfer_get_bytes_remaining(xfer));
+
+	pixbuf = gtk_widget_render_icon(dialog->window,
+									(type == PURPLE_XFER_TYPE_RECEIVE
+									 ? PIDGIN_STOCK_DOWNLOAD
+									 : PIDGIN_STOCK_UPLOAD),
+									GTK_ICON_SIZE_MENU, NULL);
+
+	gtk_list_store_append(dialog->model, &data->iter);
+	lfilename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
+	utf8 = g_filename_to_utf8(lfilename, -1, NULL, NULL, NULL);
+	g_free(lfilename);
+	lfilename = utf8;
+	gtk_list_store_set(dialog->model, &data->iter,
+					   COLUMN_STATUS, pixbuf,
+					   COLUMN_PROGRESS, 0,
+					   COLUMN_FILENAME, (type == PURPLE_XFER_TYPE_RECEIVE)
+					                     ? purple_xfer_get_filename(xfer)
+							     : lfilename,
+					   COLUMN_SIZE, size_str,
+					   COLUMN_REMAINING, _("Waiting for transfer to begin"),
+					   COLUMN_DATA, xfer,
+					   -1);
+	g_free(lfilename);
+
+	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(dialog->tree));
+
+	g_object_unref(pixbuf);
+
+	g_free(size_str);
+	g_free(remaining_str);
+
+	dialog->num_transfers++;
+
+	ensure_row_selected(dialog);
+	update_title_progress(dialog);
+}
+
+void
+pidgin_xfer_dialog_remove_xfer(PidginXferDialog *dialog,
+								PurpleXfer *xfer)
+{
+	PidginXferUiData *data;
+
+	g_return_if_fail(dialog != NULL);
+	g_return_if_fail(xfer != NULL);
+
+	data = purple_xfer_get_ui_data(xfer);
+
+	if (data == NULL)
+		return;
+
+	if (!data->in_list)
+		return;
+
+	data->in_list = FALSE;
+
+	gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &data->iter);
+
+	dialog->num_transfers--;
+
+	ensure_row_selected(dialog);
+
+	update_title_progress(dialog);
+	g_object_unref(xfer);
+}
+
+void
+pidgin_xfer_dialog_cancel_xfer(PidginXferDialog *dialog,
+								PurpleXfer *xfer)
+{
+	PidginXferUiData *data;
+	GdkPixbuf *pixbuf;
+	const gchar *status;
+
+	g_return_if_fail(dialog != NULL);
+	g_return_if_fail(xfer != NULL);
+
+	data = purple_xfer_get_ui_data(xfer);
+
+	if (data == NULL)
+		return;
+
+	if (!data->in_list)
+		return;
+
+	if ((purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) && (dialog->auto_clear)) {
+		pidgin_xfer_dialog_remove_xfer(dialog, xfer);
+		return;
+	}
+
+	data = purple_xfer_get_ui_data(xfer);
+
+	update_detailed_info(dialog, xfer);
+	update_title_progress(dialog);
+
+	pixbuf = gtk_widget_render_icon(dialog->window,
+									PIDGIN_STOCK_FILE_CANCELED,
+									GTK_ICON_SIZE_MENU, NULL);
+
+	if (purple_xfer_is_cancelled(xfer))
+		status = _("Cancelled");
+	else
+		status = _("Failed");
+
+	gtk_list_store_set(dialog->model, &data->iter,
+	                   COLUMN_STATUS, pixbuf,
+	                   COLUMN_REMAINING, status,
+	                   -1);
+
+	g_object_unref(pixbuf);
+
+	update_buttons(dialog, xfer);
+}
+
+void
+pidgin_xfer_dialog_update_xfer(PidginXferDialog *dialog,
+								PurpleXfer *xfer)
+{
+	PidginXferUiData *data;
+	char *size_str, *remaining_str;
+	time_t current_time;
+	GtkTreeIter iter;
+	gboolean valid;
+
+	g_return_if_fail(dialog != NULL);
+	g_return_if_fail(xfer != NULL);
+
+	if ((data = purple_xfer_get_ui_data(xfer)) == NULL)
+		return;
+
+	if (data->in_list == FALSE)
+		return;
+
+	current_time = time(NULL);
+	if (((current_time - data->last_updated_time) == 0) &&
+		(!purple_xfer_is_completed(xfer)))
+	{
+		/* Don't update the window more than once per second */
+		return;
+	}
+	data->last_updated_time = current_time;
+
+	size_str      = purple_str_size_to_units(purple_xfer_get_size(xfer));
+	remaining_str = purple_str_size_to_units(purple_xfer_get_bytes_remaining(xfer));
+
+	gtk_list_store_set(xfer_dialog->model, &data->iter,
+					   COLUMN_PROGRESS, (gint)(purple_xfer_get_progress(xfer) * 100),
+					   COLUMN_SIZE, size_str,
+					   COLUMN_REMAINING, remaining_str,
+					   -1);
+
+	g_free(size_str);
+	g_free(remaining_str);
+
+	if (purple_xfer_is_completed(xfer))
+	{
+		GdkPixbuf *pixbuf;
+
+		pixbuf = gtk_widget_render_icon(dialog->window,
+										PIDGIN_STOCK_FILE_DONE,
+										GTK_ICON_SIZE_MENU, NULL);
+
+		gtk_list_store_set(GTK_LIST_STORE(xfer_dialog->model), &data->iter,
+						   COLUMN_STATUS, pixbuf,
+						   COLUMN_REMAINING, _("Finished"),
+						   -1);
+
+		g_object_unref(pixbuf);
+	}
+
+	update_title_progress(dialog);
+	if (xfer == dialog->selected_xfer)
+		update_detailed_info(xfer_dialog, xfer);
+
+	if (purple_xfer_is_completed(xfer) && dialog->auto_clear)
+		pidgin_xfer_dialog_remove_xfer(dialog, xfer);
+	else
+		update_buttons(dialog, xfer);
+
+	/*
+	 * If all transfers are finished, and the pref is set, then
+	 * close the dialog.  Otherwise just exit this function.
+	 */
+	if (dialog->keep_open)
+		return;
+
+	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->model), &iter);
+	while (valid)
+	{
+		GValue val;
+		PurpleXfer *next;
+
+		val.g_type = 0;
+		gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model),
+				&iter, COLUMN_DATA, &val);
+
+		next = g_value_get_pointer(&val);
+		if (!purple_xfer_is_completed(next))
+			return;
+
+		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(dialog->model), &iter);
+	}
+
+	/* If we got to this point then we know everything is finished */
+	pidgin_xfer_dialog_hide(dialog);
+}
+
+/**************************************************************************
+ * File Transfer UI Ops
+ **************************************************************************/
+static void
+pidgin_xfer_new_xfer(PurpleXfer *xfer)
+{
+	PidginXferUiData *data;
+
+	/* This is where we're setting xfer's "ui_data" for the first time. */
+	data = g_new0(PidginXferUiData, 1);
+	purple_xfer_set_ui_data(xfer, data);
+}
+
+static void
+pidgin_xfer_destroy(PurpleXfer *xfer)
+{
+	PidginXferUiData *data;
+
+	data = purple_xfer_get_ui_data(xfer);
+	if (data) {
+		g_free(data->name);
+		g_free(data);
+		purple_xfer_set_ui_data(xfer, NULL);
+	}
+}
+
+static void
+pidgin_xfer_add_xfer(PurpleXfer *xfer)
+{
+	if (xfer_dialog == NULL)
+		xfer_dialog = pidgin_xfer_dialog_new();
+
+	pidgin_xfer_dialog_add_xfer(xfer_dialog, xfer);
+}
+
+static void
+pidgin_xfer_update_progress(PurpleXfer *xfer, double percent)
+{
+	pidgin_xfer_dialog_update_xfer(xfer_dialog, xfer);
+}
+
+static void
+pidgin_xfer_cancel_local(PurpleXfer *xfer)
+{
+	if (xfer_dialog)
+		pidgin_xfer_dialog_cancel_xfer(xfer_dialog, xfer);
+}
+
+static void
+pidgin_xfer_cancel_remote(PurpleXfer *xfer)
+{
+	if (xfer_dialog)
+		pidgin_xfer_dialog_cancel_xfer(xfer_dialog, xfer);
+}
+
+static void
+pidgin_xfer_add_thumbnail(PurpleXfer *xfer, const gchar *formats)
+{
+	purple_debug_info("ft", "creating thumbnail for transfer\n");
+
+	if (purple_xfer_get_size(xfer) <= PIDGIN_XFER_MAX_SIZE_IMAGE_THUMBNAIL) {
+		GdkPixbuf *thumbnail =
+			pidgin_pixbuf_new_from_file_at_size(
+					purple_xfer_get_local_filename(xfer), 128, 128);
+
+		if (thumbnail) {
+			gchar **formats_split = g_strsplit(formats, ",", 0);
+			gchar *buffer = NULL;
+			gsize size;
+			char *option_keys[2] = {NULL, NULL};
+			char *option_values[2] = {NULL, NULL};
+			int i;
+			gchar *format = NULL;
+
+			for (i = 0; formats_split[i]; i++) {
+				if (purple_strequal(formats_split[i], "jpeg")) {
+					purple_debug_info("ft", "creating JPEG thumbnail\n");
+					option_keys[0] = "quality";
+					option_values[0] = "90";
+					format = "jpeg";
+					break;
+				} else if (purple_strequal(formats_split[i], "png")) {
+					purple_debug_info("ft", "creating PNG thumbnail\n");
+					option_keys[0] = "compression";
+					option_values[0] = "9";
+					format = "png";
+					break;
+				}
+			}
+
+			/* Try the first format given by the PRPL without options */
+			if (format == NULL) {
+				purple_debug_info("ft",
+				    "creating thumbnail of format %s as demanded by PRPL\n",
+				    formats_split[0]);
+				format = formats_split[0];
+			}
+
+			gdk_pixbuf_save_to_bufferv(thumbnail, &buffer, &size, format,
+				option_keys, option_values, NULL);
+
+			if (buffer) {
+				gchar *mimetype = g_strdup_printf("image/%s", format);
+				purple_debug_info("ft",
+				                  "created thumbnail of %" G_GSIZE_FORMAT " bytes\n",
+					size);
+				purple_xfer_set_thumbnail(xfer, buffer, size, mimetype);
+				g_free(buffer);
+				g_free(mimetype);
+			}
+			g_object_unref(thumbnail);
+			g_strfreev(formats_split);
+		}
+	}
+}
+
+static PurpleXferUiOps ops =
+{
+	pidgin_xfer_new_xfer,
+	pidgin_xfer_destroy,
+	pidgin_xfer_add_xfer,
+	pidgin_xfer_update_progress,
+	pidgin_xfer_cancel_local,
+	pidgin_xfer_cancel_remote,
+	NULL,
+	NULL,
+	NULL,
+	pidgin_xfer_add_thumbnail
+};
+
+/**************************************************************************
+ * GTK+ File Transfer API
+ **************************************************************************/
+void
+pidgin_xfers_init(void)
+{
+	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/filetransfer");
+	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/filetransfer/clear_finished", TRUE);
+	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/filetransfer/keep_open", FALSE);
+}
+
+void
+pidgin_xfers_uninit(void)
+{
+	if (xfer_dialog != NULL)
+		pidgin_xfer_dialog_destroy(xfer_dialog);
+}
+
+void
+pidgin_set_xfer_dialog(PidginXferDialog *dialog)
+{
+	xfer_dialog = dialog;
+}
+
+PidginXferDialog *
+pidgin_get_xfer_dialog(void)
+{
+	return xfer_dialog;
+}
+
+PurpleXferUiOps *
+pidgin_xfers_get_ui_ops(void)
+{
+	return &ops;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkxfer.h	Fri Sep 06 17:32:12 2013 +0530
@@ -0,0 +1,152 @@
+/**
+ * @file gtkxfer.h GTK+ File Transfer UI
+ * @ingroup pidgin
+ */
+
+/* pidgin
+ *
+ * Pidgin 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef _PIDGINFT_H_
+#define _PIDGINFT_H_
+
+#include "xfer.h"
+
+/**
+ * A file transfer dialog.
+ *
+ * The structure is opaque, as nobody should be touching anything inside of
+ * it.
+ */
+typedef struct _PidginXferDialog PidginXferDialog;
+
+G_BEGIN_DECLS
+
+/**************************************************************************/
+/** @name GTK+ File Transfer Dialog API                                   */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates a new file transfer dialog.
+ *
+ * @return The new dialog.
+ */
+PidginXferDialog *pidgin_xfer_dialog_new(void);
+
+/**
+ * Destroys a file transfer dialog.
+ *
+ * @param dialog The file transfer dialog.
+ */
+void pidgin_xfer_dialog_destroy(PidginXferDialog *dialog);
+
+/**
+ * Displays the file transfer dialog given.
+ * If dialog is @c NULL, displays the default dialog, creating one if necessary
+ *
+ * @param dialog The file transfer dialog to show.
+ */
+void pidgin_xfer_dialog_show(PidginXferDialog *dialog);
+
+/**
+ * Hides the file transfer dialog.
+ *
+ * @param dialog The file transfer dialog to hide.
+ */
+void pidgin_xfer_dialog_hide(PidginXferDialog *dialog);
+
+/**
+ * Adds a file transfer to the dialog.
+ *
+ * @param dialog The file transfer dialog.
+ * @param xfer   The file transfer.
+ */
+void pidgin_xfer_dialog_add_xfer(PidginXferDialog *dialog, PurpleXfer *xfer);
+
+/**
+ * Removes a file transfer from the dialog.
+ *
+ * @param dialog The file transfer dialog.
+ * @param xfer   The file transfer.
+ */
+void pidgin_xfer_dialog_remove_xfer(PidginXferDialog *dialog,
+									 PurpleXfer *xfer);
+
+/**
+ * Indicate in a file transfer dialog that a transfer was cancelled.
+ *
+ * @param dialog The file transfer dialog.
+ * @param xfer   The file transfer that was cancelled.
+ */
+void pidgin_xfer_dialog_cancel_xfer(PidginXferDialog *dialog,
+									 PurpleXfer *xfer);
+
+/**
+ * Updates the information for a transfer in the dialog.
+ *
+ * @param dialog The file transfer dialog.
+ * @param xfer   The file transfer.
+ */
+void pidgin_xfer_dialog_update_xfer(PidginXferDialog *dialog,
+									 PurpleXfer *xfer);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name GTK+ File Transfer API                                          */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Initializes the GTK+ file transfer system.
+ */
+void pidgin_xfers_init(void);
+
+/**
+ * Uninitializes the GTK+ file transfer system.
+ */
+void pidgin_xfers_uninit(void);
+
+/**
+ * Sets pidgin's main file transfer dialog.
+ *
+ * @param dialog The main dialog.
+ */
+void pidgin_set_xfer_dialog(PidginXferDialog *dialog);
+
+/**
+ * Returns pirgin's main file transfer dialog.
+ *
+ * @return The main dialog.
+ */
+PidginXferDialog *pidgin_get_xfer_dialog(void);
+
+/**
+ * Returns the UI operations structure for the GTK+ file transfer UI.
+ *
+ * @return The GTK+ file transfer UI operations structure.
+ */
+PurpleXferUiOps *pidgin_xfers_get_ui_ops(void);
+
+/*@}*/
+
+G_END_DECLS
+
+#endif /* _PIDGINFT_H_ */

mercurial