pidgin/pidgin

Merged in default (pull request #665)

2019-12-30, Gary Kramlich
8066acc5ed93
Merged in default (pull request #665)

Convert most Xfer UI ops to signals

Approved-by: Gary Kramlich
--- a/ChangeLog.API Fri Dec 27 01:06:53 2019 -0500
+++ b/ChangeLog.API Mon Dec 30 07:08:44 2019 +0000
@@ -325,6 +325,10 @@
* _PurpleSoundEventID
* _XMLNodeType
* account-authorization-requested-with-message signal
+ * file-recv-accept, file-recv-cancel, file-recv-complete,
+ file-recv-start, file-send-accept, file-send-cancel,
+ file-send-complete, file-send-start signals. Use
+ notify::status on #PurpleXfer objects instead.
* network-configuration-changed signal
* PurpleAccount->ui_data
* PurpleAccountPrefsUiOps
@@ -469,12 +473,30 @@
* purple_util_get_image_checksum. Use
g_compute_checksum_for_data(G_CHECKSUM_SHA1, ...), instead.
* purple_uts35_to_str
+ * purple_xfer_add
+ * purple_xfer_get_ui_data and purple_xfer_set_ui_data. Use
+ GObject data functions instead.
+ * purple_xfer_update_progress
* PurpleCertificateVerificationStatus.PURPLE_CERTIFICATE_INVALID
* PurpleConnectionUiOps.report_disconnect_reason
* PurplePluginProtocolInfo.add_buddy_with_invite
* PurplePluginProtocolInfo.add_buddies_with_invite
* PurplePluginProtocolInfo.get_cb_away
* PurpleValue, use GValue instead.
+ * PurpleXferUiOps.add_thumbnail. Use PurpleXfer::add-thumbnail
+ instead.
+ * PurpleXferUiOps.add_xfer. Use notify::visible on #PurpleXfer
+ objects instead.
+ * PurpleXferUiOps.cancel_local and
+ PurpleXferUiOps.cancel_remote. Use notify::status on
+ #PurpleXfer objects instead.
+ * PurpleXferUiOps.data_not_sent. Use PurpleXfer::data-not-sent
+ instead.
+ * PurpleXferUiOps.destroy
+ * PurpleXferUiOps.ui_read. Use PurpleXfer::read-local instead.
+ * PurpleXferUiOps.ui_write. Use PurpleXfer::write-local instead.
+ * PurpleXferUiOps.update_progress. Use notify::progress on
+ #PurpleXfer objects instead.
* serv_got_attention
* serv_send_attention
* struct _PurpleAttentionType
--- a/doc/reference/libpurple/signals_xfer.xml Fri Dec 27 01:06:53 2019 -0500
+++ b/doc/reference/libpurple/signals_xfer.xml Mon Dec 30 07:08:44 2019 +0000
@@ -8,105 +8,13 @@
<refsect1 id="xfers.signals" role="signal_proto">
<title role="signal_proto.title">List of signals</title>
<synopsis>
- &quot;<link linkend="xfers-file-recv-accept">file-recv-accept</link>&quot;
- &quot;<link linkend="xfers-file-recv-start">file-recv-start</link>&quot;
- &quot;<link linkend="xfers-file-recv-cancel">file-recv-cancel</link>&quot;
- &quot;<link linkend="xfers-file-recv-complete">file-recv-complete</link>&quot;
&quot;<link linkend="xfers-file-recv-request">file-recv-request</link>&quot;
- &quot;<link linkend="xfers-file-send-accept">file-send-accept</link>&quot;
- &quot;<link linkend="xfers-file-send-start">file-send-start</link>&quot;
- &quot;<link linkend="xfers-file-send-cancel">file-send-cancel</link>&quot;
- &quot;<link linkend="xfers-file-send-complete">file-send-complete</link>&quot;
</synopsis>
</refsect1>
<refsect1 id="xfers.signal-details" role="signals">
<title role="signals.title">Signal details</title>
-<refsect2 id="xfers-file-recv-accept" role="signal">
- <title>The <literal>&quot;file-recv-accept&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an incoming file transfer has been accepted.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
-<refsect2 id="xfers-file-recv-start" role="signal">
- <title>The <literal>&quot;file-recv-start&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an incoming file transfer has been started.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
-<refsect2 id="xfers-file-recv-cancel" role="signal">
- <title>The <literal>&quot;file-recv-cancel&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an incoming file transfer has been canceled.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
-<refsect2 id="xfers-file-recv-complete" role="signal">
- <title>The <literal>&quot;file-recv-complete&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an incoming file transfer has been completed.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
<refsect2 id="xfers-file-recv-request" role="signal">
<title>The <literal>&quot;file-recv-request&quot;</literal> signal</title>
<programlisting>
@@ -128,90 +36,6 @@
</variablelist>
</refsect2>
-<refsect2 id="xfers-file-send-accept" role="signal">
- <title>The <literal>&quot;file-send-accept&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an outgoing file transfer has been accepted.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
-<refsect2 id="xfers-file-send-start" role="signal">
- <title>The <literal>&quot;file-send-start&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an outgoing file transfer has started.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
-<refsect2 id="xfers-file-send-cancel" role="signal">
- <title>The <literal>&quot;file-send-cancel&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an outgoing file transfer has been canceled.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
-<refsect2 id="xfers-file-send-complete" role="signal">
- <title>The <literal>&quot;file-send-complete&quot;</literal> signal</title>
-<programlisting>
-void user_function (PurpleXfer *xfer,
- gpointer data)
-</programlisting>
- <para>
-Emitted when an outgoing file transfer has been completed.
- </para>
- <variablelist role="params">
- <varlistentry>
- <term><parameter>xfer</parameter>&#160;:</term>
- <listitem><simpara>The file transfer.</simpara></listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter>&#160;:</term>
- <listitem><simpara>User data.</simpara></listitem>
- </varlistentry>
- </variablelist>
-</refsect2>
-
</refsect1>
</chapter>
--- a/finch/gntxfer.c Fri Dec 27 01:06:53 2019 -0500
+++ b/finch/gntxfer.c Mon Dec 30 07:08:44 2019 +0000
@@ -55,12 +55,11 @@
static PurpleGntXferDialog *xfer_dialog = NULL;
+#define UI_DATA "finch-ui-data"
typedef struct
{
gint64 last_updated_time;
- gboolean in_list;
- char *name;
gboolean notified; /* Has the completion of the transfer been notified? */
} PurpleGntXferUiData;
@@ -256,8 +255,7 @@
for (iter = purple_xfers_get_all(); iter; iter = iter->next) {
PurpleXfer *xfer = (PurpleXfer *)iter->data;
- PurpleGntXferUiData *data = purple_xfer_get_ui_data(xfer);
- if (data->in_list) {
+ if (purple_xfer_get_visible(xfer)) {
finch_xfer_dialog_add_xfer(xfer);
finch_xfer_dialog_update_xfer(xfer);
gnt_tree_set_selected(GNT_TREE(tree), xfer);
@@ -296,8 +294,7 @@
g_object_ref(xfer);
- data = purple_xfer_get_ui_data(xfer);
- data->in_list = TRUE;
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
finch_xfer_dialog_show();
@@ -329,20 +326,14 @@
void
finch_xfer_dialog_remove_xfer(PurpleXfer *xfer)
{
- PurpleGntXferUiData *data;
-
g_return_if_fail(xfer_dialog != NULL);
g_return_if_fail(xfer != NULL);
- data = purple_xfer_get_ui_data(xfer);
-
- if (data == NULL)
+ if (!purple_xfer_get_visible(xfer)) {
return;
+ }
- if (!data->in_list)
- return;
-
- data->in_list = FALSE;
+ purple_xfer_set_visible(xfer, FALSE);
gnt_tree_remove(GNT_TREE(xfer_dialog->tree), xfer);
@@ -364,13 +355,14 @@
g_return_if_fail(xfer_dialog != NULL);
g_return_if_fail(xfer != NULL);
- data = purple_xfer_get_ui_data(xfer);
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
if (data == NULL)
return;
- if (!data->in_list)
+ if (!purple_xfer_get_visible(xfer)) {
return;
+ }
if ((purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) && (xfer_dialog->auto_clear)) {
finch_xfer_dialog_remove_xfer(xfer);
@@ -414,11 +406,10 @@
g_return_if_fail(xfer_dialog != NULL);
g_return_if_fail(xfer != NULL);
- if ((data = purple_xfer_get_ui_data(xfer)) == NULL)
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
+ if (data == NULL || !purple_xfer_get_visible(xfer) || data->notified) {
return;
-
- if (data->in_list == FALSE || data->notified)
- return;
+ }
current_time = g_get_monotonic_time();
if (((current_time - data->last_updated_time) < G_USEC_PER_SEC) &&
@@ -465,31 +456,33 @@
* File Transfer UI Ops
**************************************************************************/
static void
-finch_xfer_new_xfer(PurpleXfer *xfer)
+finch_xfer_progress_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
{
- PurpleGntXferUiData *data;
-
- /* This is where we're setting xfer's "ui_data" for the first time. */
- data = g_new0(PurpleGntXferUiData, 1);
- purple_xfer_set_ui_data(xfer, data);
-}
-
-static void
-finch_xfer_destroy(PurpleXfer *xfer)
-{
- PurpleGntXferUiData *data;
-
- data = purple_xfer_get_ui_data(xfer);
- if (data) {
- g_free(data->name);
- g_free(data);
- purple_xfer_set_ui_data(xfer, NULL);
+ if (xfer_dialog) {
+ finch_xfer_dialog_update_xfer(xfer);
}
}
static void
-finch_xfer_add_xfer(PurpleXfer *xfer)
+finch_xfer_status_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
{
+ if (xfer_dialog) {
+ if (purple_xfer_is_cancelled(xfer)) {
+ finch_xfer_dialog_cancel_xfer(xfer);
+ }
+ }
+}
+
+static void
+finch_xfer_visible_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
+{
+ if (!purple_xfer_get_visible(xfer)) {
+ return;
+ }
+
if (!xfer_dialog)
finch_xfer_dialog_new();
@@ -498,38 +491,25 @@
}
static void
-finch_xfer_update_progress(PurpleXfer *xfer, double percent)
-{
- if (xfer_dialog)
- finch_xfer_dialog_update_xfer(xfer);
-}
-
-static void
-finch_xfer_cancel_local(PurpleXfer *xfer)
+finch_xfer_new_xfer(PurpleXfer *xfer)
{
- if (xfer_dialog)
- finch_xfer_dialog_cancel_xfer(xfer);
-}
+ PurpleGntXferUiData *data;
+
+ /* This is where we're setting xfer's "ui_data" for the first time. */
+ data = g_new0(PurpleGntXferUiData, 1);
+ g_object_set_data_full(G_OBJECT(xfer), UI_DATA, data, g_free);
-static void
-finch_xfer_cancel_remote(PurpleXfer *xfer)
-{
- if (xfer_dialog)
- finch_xfer_dialog_cancel_xfer(xfer);
+ g_signal_connect(xfer, "notify::progress",
+ G_CALLBACK(finch_xfer_progress_notify), NULL);
+ g_signal_connect(xfer, "notify::status",
+ G_CALLBACK(finch_xfer_status_notify), NULL);
+ g_signal_connect(xfer, "notify::visible",
+ G_CALLBACK(finch_xfer_visible_notify), NULL);
}
static PurpleXferUiOps ops =
{
- finch_xfer_new_xfer,
- finch_xfer_destroy,
- finch_xfer_add_xfer,
- finch_xfer_update_progress,
- finch_xfer_cancel_local,
- finch_xfer_cancel_remote,
- NULL, /* ui_write */
- NULL, /* ui_read */
- NULL, /* data_not_sent */
- NULL /* add_thumbnail */
+ finch_xfer_new_xfer
};
/**************************************************************************
--- a/libpurple/plugins/autoaccept.c Fri Dec 27 01:06:53 2019 -0500
+++ b/libpurple/plugins/autoaccept.c Mon Dec 30 07:08:44 2019 +0000
@@ -63,11 +63,17 @@
}
static void
-auto_accept_complete_cb(PurpleXfer *xfer, PurpleXfer *my)
+auto_accept_complete_cb(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
{
- if (xfer == my && purple_prefs_get_bool(PREF_NOTIFY) &&
- !purple_conversations_find_im_with_account(purple_xfer_get_remote_user(xfer), purple_xfer_get_account(xfer)))
- {
+ if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_DONE) {
+ return;
+ }
+
+ if (purple_prefs_get_bool(PREF_NOTIFY) &&
+ !purple_conversations_find_im_with_account(
+ purple_xfer_get_remote_user(xfer),
+ purple_xfer_get_account(xfer))) {
char *message = g_strdup_printf(_("Autoaccepted file transfer of \"%s\" from \"%s\" completed."),
purple_xfer_get_filename(xfer), purple_xfer_get_remote_user(xfer));
purple_notify_info(NULL, _("Autoaccept complete"), message,
@@ -168,8 +174,8 @@
g_free(filename);
}
- purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", handle,
- PURPLE_CALLBACK(auto_accept_complete_cb), xfer);
+ g_signal_connect(xfer, "notify::status",
+ G_CALLBACK(auto_accept_complete_cb), NULL);
break;
case FT_REJECT:
purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
--- a/libpurple/plugins/signals-test.c Fri Dec 27 01:06:53 2019 -0500
+++ b/libpurple/plugins/signals-test.c Mon Dec 30 07:08:44 2019 +0000
@@ -543,49 +543,6 @@
}
/**************************************************************************
- * File transfer signal callbacks
- **************************************************************************/
-static void
-ft_recv_accept_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file receive accepted\n");
-}
-
-static void
-ft_send_accept_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file send accepted\n");
-}
-
-static void
-ft_recv_start_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file receive started\n");
-}
-
-static void
-ft_send_start_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file send started\n");
-}
-
-static void
-ft_recv_cancel_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file receive cancelled\n");
-}
-
-static void
-ft_send_cancel_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file send cancelled\n");
-}
-
-static void
-ft_recv_complete_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file receive completed\n");
-}
-
-static void
-ft_send_complete_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file send completed\n");
-}
-
-/**************************************************************************
* Sound signal callbacks
**************************************************************************/
static int
@@ -716,7 +673,6 @@
void *conn_handle = purple_connections_get_handle();
void *conv_handle = purple_conversations_get_handle();
void *accounts_handle = purple_accounts_get_handle();
- void *ft_handle = purple_xfers_get_handle();
void *sound_handle = purple_sounds_get_handle();
void *notify_handle = purple_notify_get_handle();
void *jabber_handle = purple_protocols_find("prpl-jabber");
@@ -833,24 +789,6 @@
purple_signal_connect(core_handle, "uri-handler",
plugin, PURPLE_CALLBACK(uri_handler), NULL);
- /* File transfer signals */
- purple_signal_connect(ft_handle, "file-recv-accept",
- plugin, PURPLE_CALLBACK(ft_recv_accept_cb), NULL);
- purple_signal_connect(ft_handle, "file-recv-start",
- plugin, PURPLE_CALLBACK(ft_recv_start_cb), NULL);
- purple_signal_connect(ft_handle, "file-recv-cancel",
- plugin, PURPLE_CALLBACK(ft_recv_cancel_cb), NULL);
- purple_signal_connect(ft_handle, "file-recv-complete",
- plugin, PURPLE_CALLBACK(ft_recv_complete_cb), NULL);
- purple_signal_connect(ft_handle, "file-send-accept",
- plugin, PURPLE_CALLBACK(ft_send_accept_cb), NULL);
- purple_signal_connect(ft_handle, "file-send-start",
- plugin, PURPLE_CALLBACK(ft_send_start_cb), NULL);
- purple_signal_connect(ft_handle, "file-send-cancel",
- plugin, PURPLE_CALLBACK(ft_send_cancel_cb), NULL);
- purple_signal_connect(ft_handle, "file-send-complete",
- plugin, PURPLE_CALLBACK(ft_send_complete_cb), NULL);
-
/* Sound signals */
purple_signal_connect(sound_handle, "playing-sound-event", plugin,
PURPLE_CALLBACK(sound_playing_event_cb), NULL);
--- a/libpurple/protocols/jabber/oob.c Fri Dec 27 01:06:53 2019 -0500
+++ b/libpurple/protocols/jabber/oob.c Mon Dec 30 07:08:44 2019 +0000
@@ -87,7 +87,6 @@
total = soup_message_headers_get_content_length(msg->response_headers);
purple_xfer_set_size(xfer, total);
- purple_xfer_update_progress(xfer);
}
static void
--- a/libpurple/protocols/sametime/sametime.c Fri Dec 27 01:06:53 2019 -0500
+++ b/libpurple/protocols/sametime/sametime.c Mon Dec 30 07:08:44 2019 +0000
@@ -2174,8 +2174,6 @@
filesize = purple_xfer_get_size(xfer);
idb.user = remote_user;
- purple_xfer_update_progress(xfer);
-
/* test that we can actually send the file */
fp = g_fopen(filename, "rb");
if(! fp) {
@@ -2277,7 +2275,6 @@
/* calculate progress and display it */
purple_xfer_set_bytes_sent(xfer, purple_xfer_get_bytes_sent(xfer) + o.len);
- purple_xfer_update_progress(xfer);
mwFileTransfer_send(ft, &o);
@@ -2371,7 +2368,6 @@
/* update the progress */
purple_xfer_set_bytes_sent(xfer, purple_xfer_get_bytes_sent(xfer) + data->len);
- purple_xfer_update_progress(xfer);
/* let the other side know we got it, and to send some more */
mwFileTransfer_ack(ft);
--- a/libpurple/protocols/silc/ft.c Fri Dec 27 01:06:53 2019 -0500
+++ b/libpurple/protocols/silc/ft.c Mon Dec 30 07:08:44 2019 +0000
@@ -89,7 +89,6 @@
"during file transfer"), _("Remote disconnected"),
purple_request_cpar_from_connection(gc));
purple_xfer_set_status(xfer->xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
- purple_xfer_update_progress(xfer->xfer);
silc_client_file_close(client, conn, session_id);
return;
}
@@ -131,7 +130,6 @@
purple_request_cpar_from_connection(gc));
}
purple_xfer_set_status(xfer->xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
- purple_xfer_update_progress(xfer->xfer);
silc_client_file_close(client, conn, session_id);
return;
}
@@ -142,7 +140,6 @@
if (offset && filesize) {
purple_xfer_set_bytes_sent(xfer->xfer, offset);
}
- purple_xfer_update_progress(xfer->xfer);
if (status == SILC_CLIENT_FILE_MONITOR_SEND ||
status == SILC_CLIENT_FILE_MONITOR_RECEIVE) {
--- a/libpurple/xfer.c Fri Dec 27 01:06:53 2019 -0500
+++ b/libpurple/xfer.c Mon Dec 30 07:08:44 2019 +0000
@@ -73,7 +73,8 @@
PurpleXferStatus status; /* File Transfer's status. */
- gpointer ui_data; /* UI-specific data */
+ gboolean visible; /* Hint the UI that the transfer should
+ be visible or not. */
PurpleXferUiOps *ui_ops; /* UI-specific operations. */
/*
@@ -115,12 +116,26 @@
PROP_START_TIME,
PROP_END_TIME,
PROP_STATUS,
- PROP_UI_DATA,
+ PROP_PROGRESS,
+ PROP_VISIBLE,
PROP_LAST
};
static GParamSpec *properties[PROP_LAST];
+/* GObject signal enums */
+enum
+{
+ SIG_OPEN_LOCAL,
+ SIG_QUERY_LOCAL,
+ SIG_READ_LOCAL,
+ SIG_WRITE_LOCAL,
+ SIG_DATA_NOT_SENT,
+ SIG_ADD_THUMBNAIL,
+ SIG_LAST
+};
+static guint signals[SIG_LAST] = {0};
+
G_DEFINE_TYPE_WITH_PRIVATE(PurpleXfer, purple_xfer, G_TYPE_OBJECT);
static int purple_xfer_choose_file(PurpleXfer *xfer);
@@ -169,44 +184,19 @@
priv->status = status;
g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_STATUS]);
-
- if(priv->type == PURPLE_XFER_TYPE_SEND) {
- switch(status) {
- case PURPLE_XFER_STATUS_ACCEPTED:
- purple_signal_emit(purple_xfers_get_handle(), "file-send-accept", xfer);
- break;
- case PURPLE_XFER_STATUS_STARTED:
- purple_signal_emit(purple_xfers_get_handle(), "file-send-start", xfer);
- break;
- case PURPLE_XFER_STATUS_DONE:
- purple_signal_emit(purple_xfers_get_handle(), "file-send-complete", xfer);
- break;
- case PURPLE_XFER_STATUS_CANCEL_LOCAL:
- case PURPLE_XFER_STATUS_CANCEL_REMOTE:
- purple_signal_emit(purple_xfers_get_handle(), "file-send-cancel", xfer);
- break;
- default:
- break;
- }
- } else if(priv->type == PURPLE_XFER_TYPE_RECEIVE) {
- switch(status) {
- case PURPLE_XFER_STATUS_ACCEPTED:
- purple_signal_emit(purple_xfers_get_handle(), "file-recv-accept", xfer);
- break;
- case PURPLE_XFER_STATUS_STARTED:
- purple_signal_emit(purple_xfers_get_handle(), "file-recv-start", xfer);
- break;
- case PURPLE_XFER_STATUS_DONE:
- purple_signal_emit(purple_xfers_get_handle(), "file-recv-complete", xfer);
- break;
- case PURPLE_XFER_STATUS_CANCEL_LOCAL:
- case PURPLE_XFER_STATUS_CANCEL_REMOTE:
- purple_signal_emit(purple_xfers_get_handle(), "file-recv-cancel", xfer);
- break;
- default:
- break;
- }
- }
+}
+
+void
+purple_xfer_set_visible(PurpleXfer *xfer, gboolean visible)
+{
+ PurpleXferPrivate *priv = NULL;
+
+ g_return_if_fail(PURPLE_IS_XFER(xfer));
+
+ priv = purple_xfer_get_instance_private(xfer);
+ priv->visible = visible;
+
+ g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_VISIBLE]);
}
static void
@@ -571,12 +561,25 @@
}
}
+static gboolean
+do_query_local(PurpleXfer *xfer, const gchar *filename)
+{
+ GStatBuf st;
+
+ if (g_stat(filename, &st) == -1) {
+ purple_xfer_show_file_error(xfer, filename);
+ return FALSE;
+ }
+
+ purple_xfer_set_size(xfer, st.st_size);
+ return TRUE;
+}
+
void
purple_xfer_request_accepted(PurpleXfer *xfer, const gchar *filename)
{
PurpleXferClass *klass = NULL;
PurpleXferPrivate *priv = NULL;
- GStatBuf st;
gchar *msg, *utf8, *base;
PurpleBuddy *buddy;
@@ -606,8 +609,7 @@
if (priv->type == PURPLE_XFER_TYPE_SEND) {
/* Sending a file */
/* Check the filename. */
- PurpleXferUiOps *ui_ops;
- ui_ops = purple_xfer_get_ui_ops(xfer);
+ gboolean query_status;
#ifdef _WIN32
if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\"))
@@ -626,18 +628,13 @@
return;
}
- if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
- if (g_stat(filename, &st) == -1) {
- purple_xfer_show_file_error(xfer, filename);
- g_object_unref(xfer);
- return;
- }
-
- purple_xfer_set_local_filename(xfer, filename);
- purple_xfer_set_size(xfer, st.st_size);
- } else {
- purple_xfer_set_local_filename(xfer, filename);
+ g_signal_emit(xfer, signals[SIG_QUERY_LOCAL], 0, filename,
+ &query_status);
+ if (!query_status) {
+ g_object_unref(xfer);
+ return;
}
+ purple_xfer_set_local_filename(xfer, filename);
base = g_path_get_basename(filename);
utf8 = g_filename_to_utf8(base, -1, NULL, NULL, NULL);
@@ -661,7 +658,7 @@
g_free(msg);
}
- purple_xfer_add(xfer);
+ purple_xfer_set_visible(xfer, TRUE);
klass->init(xfer);
}
@@ -763,6 +760,17 @@
}
gboolean
+purple_xfer_get_visible(PurpleXfer *xfer)
+{
+ PurpleXferPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_XFER(xfer), FALSE);
+
+ priv = purple_xfer_get_instance_private(xfer);
+ return priv->visible;
+}
+
+gboolean
purple_xfer_is_cancelled(PurpleXfer *xfer)
{
g_return_val_if_fail(PURPLE_IS_XFER(xfer), TRUE);
@@ -932,7 +940,6 @@
purple_xfer_set_completed(PurpleXfer *xfer, gboolean completed)
{
PurpleXferPrivate *priv = NULL;
- PurpleXferUiOps *ui_ops;
g_return_if_fail(PURPLE_IS_XFER(xfer));
@@ -973,10 +980,7 @@
g_free(msg);
}
- ui_ops = purple_xfer_get_ui_ops(xfer);
-
- if (ui_ops != NULL && ui_ops->update_progress != NULL)
- ui_ops->update_progress(xfer, purple_xfer_get_progress(xfer));
+ g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_PROGRESS]);
}
void
@@ -1045,13 +1049,18 @@
purple_xfer_set_size(PurpleXfer *xfer, goffset size)
{
PurpleXferPrivate *priv = NULL;
+ GObject *obj;
g_return_if_fail(PURPLE_IS_XFER(xfer));
priv = purple_xfer_get_instance_private(xfer);
priv->size = size;
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_FILE_SIZE]);
+ obj = G_OBJECT(xfer);
+ g_object_freeze_notify(obj);
+ g_object_notify_by_pspec(obj, properties[PROP_FILE_SIZE]);
+ g_object_notify_by_pspec(obj, properties[PROP_PROGRESS]);
+ g_object_thaw_notify(obj);
}
void
@@ -1071,13 +1080,18 @@
purple_xfer_set_bytes_sent(PurpleXfer *xfer, goffset bytes_sent)
{
PurpleXferPrivate *priv = NULL;
+ GObject *obj;
g_return_if_fail(PURPLE_IS_XFER(xfer));
priv = purple_xfer_get_instance_private(xfer);
priv->bytes_sent = bytes_sent;
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_BYTES_SENT]);
+ obj = G_OBJECT(xfer);
+ g_object_freeze_notify(obj);
+ g_object_notify_by_pspec(obj, properties[PROP_BYTES_SENT]);
+ g_object_notify_by_pspec(obj, properties[PROP_PROGRESS]);
+ g_object_thaw_notify(obj);
}
PurpleXferUiOps *
@@ -1206,11 +1220,23 @@
return do_write(xfer, buffer, s);
}
+static gssize
+do_write_local(PurpleXfer *xfer, const guchar *buffer, gssize size)
+{
+ PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
+
+ if (priv->dest_fp == NULL) {
+ purple_debug_error("xfer", "File is not opened for writing");
+ return -1;
+ }
+
+ return fwrite(buffer, 1, size, priv->dest_fp);
+}
+
gboolean
purple_xfer_write_file(PurpleXfer *xfer, const guchar *buffer, gsize size)
{
PurpleXferPrivate *priv = NULL;
- PurpleXferUiOps *ui_ops;
gsize wc;
goffset remaining;
gboolean fs_known;
@@ -1220,7 +1246,6 @@
priv = purple_xfer_get_instance_private(xfer);
- ui_ops = purple_xfer_get_ui_ops(xfer);
fs_known = (priv->size > 0);
remaining = purple_xfer_get_bytes_remaining(xfer);
@@ -1231,17 +1256,7 @@
size = remaining;
}
- if (ui_ops && ui_ops->ui_write) {
- wc = ui_ops->ui_write(xfer, buffer, size);
- } else {
- if (priv->dest_fp == NULL) {
- purple_debug_error("xfer",
- "File is not opened for writing\n");
- purple_xfer_cancel_local(xfer);
- return FALSE;
- }
- wc = fwrite(buffer, 1, size, priv->dest_fp);
- }
+ g_signal_emit(xfer, signals[SIG_WRITE_LOCAL], 0, buffer, size, &wc);
if (wc != size) {
purple_debug_error("xfer",
@@ -1258,51 +1273,39 @@
return TRUE;
}
+static gssize
+do_read_local(PurpleXfer *xfer, guchar *buffer, gssize size)
+{
+ PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
+ gssize got_len;
+
+ if (priv->dest_fp == NULL) {
+ purple_debug_error("xfer", "File is not opened for reading");
+ return -1;
+ }
+
+ got_len = fread(buffer, 1, size, priv->dest_fp);
+ if ((got_len < 0 || got_len != size) && ferror(priv->dest_fp)) {
+ purple_debug_error("xfer", "Unable to read file.");
+ return -1;
+ }
+
+ return got_len;
+}
+
gssize
purple_xfer_read_file(PurpleXfer *xfer, guchar *buffer, gsize size)
{
- PurpleXferPrivate *priv = NULL;
- PurpleXferUiOps *ui_ops;
gssize got_len;
g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
g_return_val_if_fail(buffer != NULL, 0);
- priv = purple_xfer_get_instance_private(xfer);
- ui_ops = purple_xfer_get_ui_ops(xfer);
-
- if (ui_ops && ui_ops->ui_read) {
- guchar *buffer_got = NULL;
-
- got_len = ui_ops->ui_read(xfer, &buffer_got, size);
-
- if (got_len >= 0 && (gsize)got_len > size) {
- g_free(buffer_got);
- purple_debug_error("xfer",
- "Got too much data from UI.\n");
- purple_xfer_cancel_local(xfer);
- return -1;
- }
-
- if (got_len > 0)
- memcpy(buffer, buffer_got, got_len);
- g_free(buffer_got);
- } else {
- if (priv->dest_fp == NULL) {
- purple_debug_error("xfer",
- "File is not opened for reading\n");
- purple_xfer_cancel_local(xfer);
- return -1;
- }
- got_len = fread(buffer, 1, size, priv->dest_fp);
- if ((got_len < 0 || (gsize)got_len != size) &&
- ferror(priv->dest_fp))
- {
- purple_debug_error("xfer",
- "Unable to read file.\n");
- purple_xfer_cancel_local(xfer);
- return -1;
- }
+ g_signal_emit(xfer, signals[SIG_READ_LOCAL], 0, buffer, size, &got_len);
+ if (got_len < 0 || got_len > size) {
+ purple_debug_error("xfer", "Unable to read file.");
+ purple_xfer_cancel_local(xfer);
+ return -1;
}
if (got_len > 0) {
@@ -1313,16 +1316,26 @@
return got_len;
}
+static gboolean
+do_data_not_sent(PurpleXfer *xfer, const guchar *buffer, gsize size)
+{
+ PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
+
+ if (priv->buffer == NULL) {
+ priv->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE);
+ g_byte_array_append(priv->buffer, buffer, size);
+ }
+
+ return TRUE;
+}
+
static void
do_transfer(PurpleXfer *xfer)
{
PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- PurpleXferUiOps *ui_ops;
guchar *buffer = NULL;
gssize r = 0;
- ui_ops = purple_xfer_get_ui_ops(xfer);
-
if (priv->type == PURPLE_XFER_TYPE_RECEIVE) {
r = purple_xfer_read(xfer, &buffer);
if (r > 0) {
@@ -1342,7 +1355,8 @@
(gsize)purple_xfer_get_bytes_remaining(xfer),
(gsize)priv->current_buffer_size
);
- gboolean read = TRUE;
+ gboolean read_more = TRUE;
+ gboolean existing_buffer = FALSE;
/* this is so the protocol can keep the connection open
if it needs to for some odd reason. */
@@ -1355,15 +1369,16 @@
}
if (priv->buffer) {
+ existing_buffer = TRUE;
if (priv->buffer->len < s) {
s -= priv->buffer->len;
- read = TRUE;
+ read_more = TRUE;
} else {
- read = FALSE;
+ read_more = FALSE;
}
}
- if (read) {
+ if (read_more) {
buffer = g_new(guchar, s);
result = purple_xfer_read_file(xfer, buffer, s);
if (result == 0) {
@@ -1414,11 +1429,15 @@
*/
purple_xfer_increase_buffer_size(xfer);
} else {
- if (ui_ops && ui_ops->data_not_sent)
- ui_ops->data_not_sent(xfer, buffer + r, result - r);
+ gboolean result;
+ g_signal_emit(xfer, signals[SIG_DATA_NOT_SENT], 0, buffer + r,
+ result - r, &result);
+ if (!result) {
+ purple_xfer_cancel_local(xfer);
+ }
}
- if (priv->buffer) {
+ if (existing_buffer && priv->buffer) {
/*
* Remove what we wrote
* If we wrote the whole buffer the byte array will be empty
@@ -1434,10 +1453,6 @@
if (klass && klass->ack)
klass->ack(xfer, buffer, r);
-
- if (ui_ops != NULL && ui_ops->update_progress != NULL)
- ui_ops->update_progress(xfer,
- purple_xfer_get_progress(xfer));
}
g_free(buffer);
@@ -1479,34 +1494,44 @@
do_transfer(xfer);
}
+static gboolean
+do_open_local(PurpleXfer *xfer)
+{
+ PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
+
+ priv->dest_fp =
+ g_fopen(purple_xfer_get_local_filename(xfer),
+ priv->type == PURPLE_XFER_TYPE_RECEIVE ? "wb" : "rb");
+
+ if (priv->dest_fp == NULL) {
+ purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
+ return FALSE;
+ }
+
+ if (fseek(priv->dest_fp, priv->bytes_sent, SEEK_SET) != 0) {
+ purple_debug_error("xfer", "couldn't seek");
+ purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void
begin_transfer(PurpleXfer *xfer, PurpleInputCondition cond)
{
PurpleXferClass *klass = PURPLE_XFER_GET_CLASS(xfer);
PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- PurpleXferUiOps *ui_ops = purple_xfer_get_ui_ops(xfer);
+ gboolean open_status = FALSE;
if (priv->start_time != 0) {
purple_debug_error("xfer", "Transfer is being started multiple times\n");
g_return_if_reached();
}
- if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
- priv->dest_fp = g_fopen(purple_xfer_get_local_filename(xfer),
- priv->type == PURPLE_XFER_TYPE_RECEIVE ? "wb" : "rb");
-
- if (priv->dest_fp == NULL) {
- purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
- purple_xfer_cancel_local(xfer);
- return;
- }
-
- if (fseek(priv->dest_fp, priv->bytes_sent, SEEK_SET) != 0) {
- purple_debug_error("xfer", "couldn't seek\n");
- purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
- purple_xfer_cancel_local(xfer);
- return;
- }
+ g_signal_emit(xfer, signals[SIG_OPEN_LOCAL], 0, &open_status);
+ if (!open_status) {
+ purple_xfer_cancel_local(xfer);
}
if (priv->fd != -1) {
@@ -1698,24 +1723,10 @@
}
void
-purple_xfer_add(PurpleXfer *xfer)
-{
- PurpleXferUiOps *ui_ops;
-
- g_return_if_fail(PURPLE_IS_XFER(xfer));
-
- ui_ops = purple_xfer_get_ui_ops(xfer);
-
- if (ui_ops != NULL && ui_ops->add_xfer != NULL)
- ui_ops->add_xfer(xfer);
-}
-
-void
purple_xfer_cancel_local(PurpleXfer *xfer)
{
PurpleXferClass *klass = NULL;
PurpleXferPrivate *priv = NULL;
- PurpleXferUiOps *ui_ops;
char *msg = NULL;
g_return_if_fail(PURPLE_IS_XFER(xfer));
@@ -1779,12 +1790,6 @@
priv->dest_fp = NULL;
}
- ui_ops = purple_xfer_get_ui_ops(xfer);
-
- if (ui_ops != NULL && ui_ops->cancel_local != NULL) {
- ui_ops->cancel_local(xfer);
- }
-
g_object_unref(xfer);
}
@@ -1793,7 +1798,6 @@
{
PurpleXferClass *klass = NULL;
PurpleXferPrivate *priv = NULL;
- PurpleXferUiOps *ui_ops;
gchar *msg;
PurpleAccount *account;
PurpleBuddy *buddy;
@@ -1849,11 +1853,6 @@
priv->dest_fp = NULL;
}
- ui_ops = purple_xfer_get_ui_ops(xfer);
-
- if (ui_ops != NULL && ui_ops->cancel_remote != NULL)
- ui_ops->cancel_remote(xfer);
-
g_object_unref(xfer);
}
@@ -1883,19 +1882,6 @@
g_free(title);
}
-void
-purple_xfer_update_progress(PurpleXfer *xfer)
-{
- PurpleXferUiOps *ui_ops;
-
- g_return_if_fail(PURPLE_IS_XFER(xfer));
-
- ui_ops = purple_xfer_get_ui_ops(xfer);
- if (ui_ops != NULL && ui_ops->update_progress != NULL) {
- ui_ops->update_progress(xfer, purple_xfer_get_progress(xfer));
- }
-}
-
gconstpointer
purple_xfer_get_thumbnail(PurpleXfer *xfer, gsize *len)
{
@@ -1958,38 +1944,9 @@
void
purple_xfer_prepare_thumbnail(PurpleXfer *xfer, const gchar *formats)
{
- PurpleXferUiOps *ui_ops;
-
g_return_if_fail(PURPLE_IS_XFER(xfer));
- ui_ops = purple_xfer_get_ui_ops(xfer);
- if (ui_ops && ui_ops->add_thumbnail) {
- ui_ops->add_thumbnail(xfer, formats);
- }
-}
-
-void purple_xfer_set_ui_data(PurpleXfer *xfer, gpointer ui_data)
-{
- PurpleXferPrivate *priv = NULL;
-
- g_return_if_fail(PURPLE_IS_XFER(xfer));
-
- priv = purple_xfer_get_instance_private(xfer);
-
- priv->ui_data = ui_data;
-
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_UI_DATA]);
-}
-
-gpointer purple_xfer_get_ui_data(PurpleXfer *xfer)
-{
- PurpleXferPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
- priv = purple_xfer_get_instance_private(xfer);
-
- return priv->ui_data;
+ g_signal_emit(xfer, signals[SIG_ADD_THUMBNAIL], 0, formats, NULL);
}
/**************************************************************************
@@ -2039,8 +1996,8 @@
case PROP_STATUS:
purple_xfer_set_status(xfer, g_value_get_enum(value));
break;
- case PROP_UI_DATA:
- purple_xfer_set_ui_data(xfer, g_value_get_pointer(value));
+ case PROP_VISIBLE:
+ purple_xfer_set_visible(xfer, g_value_get_boolean(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -2103,8 +2060,11 @@
case PROP_STATUS:
g_value_set_enum(value, purple_xfer_get_status(xfer));
break;
- case PROP_UI_DATA:
- g_value_set_pointer(value, purple_xfer_get_ui_data(xfer));
+ case PROP_PROGRESS:
+ g_value_set_double(value, purple_xfer_get_progress(xfer));
+ break;
+ case PROP_VISIBLE:
+ g_value_set_boolean(value, purple_xfer_get_visible(xfer));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -2127,20 +2087,12 @@
purple_xfer_constructed(GObject *object)
{
PurpleXfer *xfer = PURPLE_XFER(object);
- PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
PurpleXferUiOps *ui_ops;
G_OBJECT_CLASS(purple_xfer_parent_class)->constructed(object);
ui_ops = purple_xfers_get_ui_ops();
- if (ui_ops && ui_ops->data_not_sent) {
- /* If the ui will handle unsent data no need for buffer */
- priv->buffer = NULL;
- } else {
- priv->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE);
- }
-
if (ui_ops != NULL && ui_ops->new_xfer != NULL) {
ui_ops->new_xfer(xfer);
}
@@ -2153,7 +2105,6 @@
{
PurpleXfer *xfer = PURPLE_XFER(object);
PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- PurpleXferUiOps *ui_ops;
/* Close the file browser, if it's open */
purple_request_close_with_handle(xfer);
@@ -2162,12 +2113,6 @@
purple_xfer_cancel_local(xfer);
}
- ui_ops = purple_xfer_get_ui_ops(xfer);
-
- if (ui_ops != NULL && ui_ops->destroy != NULL) {
- ui_ops->destroy(xfer);
- }
-
xfers = g_list_remove(xfers, xfer);
g_free(priv->who);
@@ -2199,6 +2144,14 @@
klass->write = do_write;
klass->read = do_read;
+ klass->open_local = do_open_local;
+ klass->query_local = do_query_local;
+ klass->read_local = do_read_local;
+ klass->write_local = do_write_local;
+ klass->data_not_sent = do_data_not_sent;
+
+ /* Properties */
+
properties[PROP_TYPE] = g_param_spec_enum("type", "Transfer type",
"The type of file transfer.", PURPLE_TYPE_XFER_TYPE,
PURPLE_XFER_TYPE_UNKNOWN,
@@ -2280,11 +2233,149 @@
PURPLE_TYPE_XFER_STATUS, PURPLE_XFER_STATUS_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- properties[PROP_UI_DATA] = g_param_spec_pointer("ui-data", "UI Data",
- "The UI specific data for this xfer",
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ properties[PROP_PROGRESS] = g_param_spec_double(
+ "progress", "Progress",
+ "The current progress of the file transfer.", -1.0, 1.0, -1.0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_VISIBLE] = g_param_spec_boolean(
+ "visible", "Visible",
+ "Hint for UIs whether this transfer should be visible.", FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, PROP_LAST, properties);
+
+ /* Signals */
+
+ /**
+ * PurpleXfer::open-local:
+ *
+ * Open a file locally for a file transfer.
+ *
+ * The default class handler will open a file using standard library
+ * functions. If you connect to this signal, you should connect to
+ * PurpleXfer::query-local, PurpleXfer::read-local, PurpleXfer::write-local
+ * and PurpleXfer::data-not-sent as well.
+ *
+ * Returns: %TRUE if the file was opened successfully, or %FALSE otherwise,
+ * and the transfer should be cancelled (libpurple will cancel).
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_OPEN_LOCAL] = g_signal_new(
+ "open-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleXferClass, open_local),
+ g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_BOOLEAN, 0);
+
+ /**
+ * PurpleXfer::query-local:
+ * @filename: The filename of the transfer.
+ *
+ * Query a file's properties locally.
+ *
+ * The default class handler will query a file using standard library
+ * functions, and set the transfer's size. If you connect to this signal,
+ * you should try to do the same, but it is not necessarily an error if you
+ * cannot. If you connect to this signal, you must connect to
+ * PurpleXfer::open-local, PurpleXfer::read-local, PurpleXfer::write-local
+ * and PurpleXfer::data-not-sent as well.
+ *
+ * Returns: %TRUE if the properties were queried successfully, or %FALSE
+ * otherwise, and the transfer should be cancelled (libpurple will
+ * cancel).
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_QUERY_LOCAL] = g_signal_new(
+ "query-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleXferClass, query_local),
+ g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_BOOLEAN, 1,
+ G_TYPE_STRING);
+
+ /**
+ * PurpleXfer::read-local:
+ * @buffer: (out): A pointer to a buffer to fill.
+ * @size: The maximum amount of data to put in the buffer.
+ *
+ * Read data locally to send to the protocol for a file transfer.
+ *
+ * The default class handler will read from a file using standard library
+ * functions. If you connect to this signal, you must connect to
+ * PurpleXfer::open-local, PurpleXfer::query-local, PurpleXfer::write-local
+ * and PurpleXfer::data-not-sent as well.
+ *
+ * Returns: The amount of data in the buffer, 0 if nothing is available,
+ * and a negative value if an error occurred and the transfer
+ * should be cancelled (libpurple will cancel).
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_READ_LOCAL] = g_signal_new(
+ "read-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleXferClass, read_local),
+ g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_LONG, 2,
+ G_TYPE_POINTER, G_TYPE_LONG);
+
+ /**
+ * PurpleXfer::write-local:
+ * @buffer: The buffer to write.
+ * @size: The size of the buffer.
+ *
+ * Write data received from the protocol locally. The signal handler must
+ * deal with the entire buffer and return size, or it is treated as an
+ * error.
+ *
+ * The default class handler will write to a file using standard library
+ * functions. If you connect to this signal, you must connect to
+ * PurpleXfer::open-local, PurpleXfer::query-local, PurpleXfer::read-local
+ * and PurpleXfer::data-not-sent as well.
+ *
+ * Returns: @size if the write was successful, or a value between 0 and
+ * @size on error.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_WRITE_LOCAL] = g_signal_new(
+ "write-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleXferClass, write_local),
+ g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_LONG, 2,
+ G_TYPE_POINTER, G_TYPE_LONG);
+
+ /**
+ * PurpleXfer::data-not-sent:
+ * @buffer: A pointer to the beginning of the unwritten data.
+ * @size: The amount of unwritten data.
+ *
+ * Notify the UI that not all the data read in was written. The UI should
+ * re-enqueue this data and return it the next time read is called.
+ *
+ * If you connect to this signal, you must connect to
+ * PurpleXfer::open-local, PurpleXfer::query-local, PurpleXfer::read-local
+ * and PurpleXfer::write-local as well.
+ *
+ * Returns: %TRUE if the data was re-enqueued successfully, or %FALSE
+ * otherwise, and the transfer should be cancelled (libpurple
+ * will cancel).
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_DATA_NOT_SENT] = g_signal_new(
+ "data-not-sent", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleXferClass, data_not_sent),
+ g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_BOOLEAN, 2,
+ G_TYPE_POINTER, G_TYPE_ULONG);
+
+ /**
+ * PurpleXfer::add-thumbnail:
+ * @formats: A comma-separated string of allowed image formats.
+ *
+ * Request that a thumbnail be added to a file transfer.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_ADD_THUMBNAIL] = g_signal_new(
+ "add-thumbnail", G_TYPE_FROM_CLASS(klass), G_SIGNAL_ACTION, 0, NULL,
+ NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
}
PurpleXfer *
@@ -2340,30 +2431,6 @@
void *handle = purple_xfers_get_handle();
/* register signals */
- purple_signal_register(handle, "file-recv-accept",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
- purple_signal_register(handle, "file-send-accept",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
- purple_signal_register(handle, "file-recv-start",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
- purple_signal_register(handle, "file-send-start",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
- purple_signal_register(handle, "file-send-cancel",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
- purple_signal_register(handle, "file-recv-cancel",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
- purple_signal_register(handle, "file-send-complete",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
- purple_signal_register(handle, "file-recv-complete",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
- PURPLE_TYPE_XFER);
purple_signal_register(handle, "file-recv-request",
purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
PURPLE_TYPE_XFER);
--- a/libpurple/xfer.h Fri Dec 27 01:06:53 2019 -0500
+++ b/libpurple/xfer.h Mon Dec 30 07:08:44 2019 +0000
@@ -31,19 +31,11 @@
#define PURPLE_TYPE_XFER_UI_OPS (purple_xfer_ui_ops_get_type())
-#define PURPLE_TYPE_PROTOCOL_XFER (purple_protocol_xfer_get_type())
-#define PURPLE_PROTOCOL_XFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_PROTOCOL_XFER, PurpleProtocolXfer))
-#define PURPLE_IS_PROTOCOL_XFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_PROTOCOL_XFER))
-#define PURPLE_PROTOCOL_XFER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE((obj), PURPLE_TYPE_PROTOCOL_XFER, PurpleProtocolXferInterface))
-
/**************************************************************************/
/* Data Structures */
/**************************************************************************/
typedef struct _PurpleXferUiOps PurpleXferUiOps;
-typedef struct _PurpleProtocolXfer PurpleProtocolXfer;
-typedef struct _PurpleProtocolXferInterface PurpleProtocolXferInterface;
-
#include <glib.h>
#include <stdio.h>
@@ -99,41 +91,6 @@
/**
* PurpleXferUiOps:
* @new_xfer: UI op that's called after a new transfer is created.
- * @destroy: UI op that's called when a transfer is being destroyed.
- * @add_xfer: UI op that's called when a transfer should be added to the UI.
- * @update_progress: UI op that's called when a transfer's progress has been
- * updated.
- * @cancel_local: UI op that's called when a transfer has been cancelled on the
- * local end.
- * @cancel_remote: UI op that's called when a transfer has been cancelled on
- * the remote end.
- * @ui_write: UI op to write data received from the protocol. The UI must deal
- * with the entire buffer and return size, or it is treated as an
- * error.
- * <sbr/>@xfer: The file transfer structure
- * <sbr/>@buffer: The buffer to write
- * <sbr/>@size: The size of the buffer
- * <sbr/>Returns: size if the write was successful, or a value
- * between 0 and size on error.
- * @ui_read: UI op to read data to send to the protocol for a file transfer.
- * <sbr/>@xfer: The file transfer structure
- * <sbr/>@buffer: A pointer to a buffer. The UI must allocate this
- * buffer. libpurple will free the data.
- * <sbr/>@size: The maximum amount of data to put in the buffer.
- * <sbr/>Returns: The amount of data in the buffer, 0 if nothing is
- * available, and a negative value if an error occurred
- * and the transfer should be cancelled (libpurple will
- * cancel).
- * @data_not_sent: Op to notify the UI that not all the data read in was
- * written. The UI should re-enqueue this data and return it the
- * next time read is called.
- * <sbr/>This <emphasis>MUST</emphasis> be implemented if read
- * and write are implemented.
- * <sbr/>@xfer: The file transfer structure
- * <sbr/>@buffer: A pointer to the beginning of the unwritten
- * data.
- * <sbr/>@size: The amount of unwritten data.
- * @add_thumbnail: Op to create a thumbnail image for a file transfer
*
* File transfer UI operations.
*
@@ -143,15 +100,6 @@
struct _PurpleXferUiOps
{
void (*new_xfer)(PurpleXfer *xfer);
- void (*destroy)(PurpleXfer *xfer);
- void (*add_xfer)(PurpleXfer *xfer);
- void (*update_progress)(PurpleXfer *xfer, double percent);
- void (*cancel_local)(PurpleXfer *xfer);
- void (*cancel_remote)(PurpleXfer *xfer);
- gssize (*ui_write)(PurpleXfer *xfer, const guchar *buffer, gssize size);
- gssize (*ui_read)(PurpleXfer *xfer, guchar **buffer, gssize size);
- void (*data_not_sent)(PurpleXfer *xfer, const guchar *buffer, gsize size);
- void (*add_thumbnail)(PurpleXfer *xfer, const gchar *formats);
};
/**
@@ -166,6 +114,11 @@
* @read: Called when reading data from the file transfer.
* @write: Called when writing data to the file transfer.
* @ack: Called when a file transfer is acknowledged.
+ * @open_local: The vfunc for PurpleXfer::open-local. Since: 3.0.0
+ * @query_local: The vfunc for PurpleXfer::query-local. Since: 3.0.0
+ * @read_local: The vfunc for PurpleXfer::read-local. Since: 3.0.0
+ * @write_local: The vfunc for PurpleXfer::write-local. Since: 3.0.0
+ * @data_not_sent: The vfunc for PurpleXfer::data-not-sent. Since: 3.0.0
*
* Base class for all #PurpleXfer's
*/
@@ -183,37 +136,17 @@
gssize (*write)(PurpleXfer *xfer, const guchar *buffer, gsize size);
void (*ack)(PurpleXfer *xfer, const guchar *buffer, gsize size);
+ gboolean (*open_local)(PurpleXfer *xfer);
+ gboolean (*query_local)(PurpleXfer *xfer, const gchar *filename);
+ gssize (*read_local)(PurpleXfer *xfer, guchar *buffer, gssize size);
+ gssize (*write_local)(PurpleXfer *xfer, const guchar *buffer, gssize size);
+ gboolean (*data_not_sent)(PurpleXfer *xfer, const guchar *buffer,
+ gsize size);
+
/*< private >*/
gpointer reserved[4];
};
-/**
- * PurpleProtocolXferInterface:
- * @can_receive: A method to determine if we can receive a file.
- * @send_file: A method to determine if we can send a file.
- * @new_xfer: A method to create a new file transfer.
- *
- * The protocol file transfer interface.
- *
- * This interface provides file transfer callbacks for the protocol.
- */
-struct _PurpleProtocolXferInterface
-{
- /*< private >*/
- GTypeInterface parent_iface;
-
- /*< public >*/
- gboolean (*can_receive)(PurpleProtocolXfer *prplxfer,
- PurpleConnection *connection, const gchar *who);
-
- void (*send_file)(PurpleProtocolXfer *prplxfer,
- PurpleConnection *connection, const gchar *who,
- const gchar *filename);
-
- PurpleXfer *(*new_xfer)(PurpleProtocolXfer *prplxfer,
- PurpleConnection *connection, const gchar *who);
-};
-
/**************************************************************************/
/* File Transfer API */
/**************************************************************************/
@@ -331,6 +264,20 @@
PurpleXferStatus purple_xfer_get_status(PurpleXfer *xfer);
/**
+ * purple_xfer_get_visible:
+ * @xfer: The file transfer.
+ *
+ * Returns whether the UI should show the file transfer in its listing.
+ *
+ * Note, this is just a hint for UIs and has no effect internally.
+ *
+ * Returns: The visibility.
+ *
+ * Since: 3.0.0
+ */
+gboolean purple_xfer_get_visible(PurpleXfer *xfer);
+
+/**
* purple_xfer_is_cancelled:
* @xfer: The file transfer.
*
@@ -499,6 +446,19 @@
void purple_xfer_set_status(PurpleXfer *xfer, PurpleXferStatus status);
/**
+ * purple_xfer_set_visible:
+ * @xfer: The file transfer.
+ * @visible: The visibility.
+ *
+ * Sets whether the UI should show the file transfer in its listing.
+ *
+ * Note, this is just a hint for UIs and has no effect internally.
+ *
+ * Since: 3.0.0
+ */
+void purple_xfer_set_visible(PurpleXfer *xfer, gboolean visible);
+
+/**
* purple_xfer_set_message:
* @xfer: The file transfer.
* @message: The message.
@@ -660,15 +620,6 @@
void purple_xfer_end(PurpleXfer *xfer);
/**
- * purple_xfer_add:
- * @xfer: The file transfer.
- *
- * Adds a new file transfer to the list of file transfers. Call this only
- * if you are not using purple_xfer_start.
- */
-void purple_xfer_add(PurpleXfer *xfer);
-
-/**
* purple_xfer_cancel_local:
* @xfer: The file transfer.
*
@@ -700,14 +651,6 @@
void purple_xfer_error(PurpleXferType type, PurpleAccount *account, const char *who, const char *msg);
/**
- * purple_xfer_update_progress:
- * @xfer: The file transfer.
- *
- * Updates file transfer progress.
- */
-void purple_xfer_update_progress(PurpleXfer *xfer);
-
-/**
* purple_xfer_conversation_write:
* @xfer: The file transfer to which this message relates.
* @message: The message to display.
@@ -785,27 +728,6 @@
*/
void purple_xfer_prepare_thumbnail(PurpleXfer *xfer, const gchar *formats);
-/**
- * purple_xfer_set_ui_data:
- * @xfer: The file transfer.
- * @ui_data: A pointer to associate with this file transfer.
- *
- * Set the UI data associated with this file transfer.
- */
-void purple_xfer_set_ui_data(PurpleXfer *xfer, gpointer ui_data);
-
-/**
- * purple_xfer_get_ui_data:
- * @xfer: The file transfer.
- *
- * Get the UI data associated with this file transfer.
- *
- * Returns: The UI data associated with this file transfer. This is a
- * convenience field provided to the UIs--it is not
- * used by the libpurple core.
- */
-gpointer purple_xfer_get_ui_data(PurpleXfer *xfer);
-
/**************************************************************************/
/* File Transfer Subsystem API */
/**************************************************************************/
@@ -870,13 +792,41 @@
/******************************************************************************
* Protocol Interface
*****************************************************************************/
+#define PURPLE_TYPE_PROTOCOL_XFER (purple_protocol_xfer_get_type())
/**
* purple_protocol_xfer_get_type:
*
* Returns: The #GType for the protocol xfer interface.
*/
-GType purple_protocol_xfer_get_type(void);
+G_DECLARE_INTERFACE(PurpleProtocolXfer, purple_protocol_xfer, PURPLE,
+ PROTOCOL_XFER, GObject)
+
+/**
+ * PurpleProtocolXferInterface:
+ * @can_receive: A method to determine if we can receive a file.
+ * @send_file: A method to determine if we can send a file.
+ * @new_xfer: A method to create a new file transfer.
+ *
+ * The protocol file transfer interface.
+ *
+ * This interface provides file transfer callbacks for the protocol.
+ */
+struct _PurpleProtocolXferInterface {
+ /*< private >*/
+ GTypeInterface parent_iface;
+
+ /*< public >*/
+ gboolean (*can_receive)(PurpleProtocolXfer *prplxfer,
+ PurpleConnection *connection, const gchar *who);
+
+ void (*send_file)(PurpleProtocolXfer *prplxfer,
+ PurpleConnection *connection, const gchar *who,
+ const gchar *filename);
+
+ PurpleXfer *(*new_xfer)(PurpleProtocolXfer *prplxfer,
+ PurpleConnection *connection, const gchar *who);
+};
/**
* purple_protocol_xfer_can_receive:
--- a/pidgin/gtkxfer.c Fri Dec 27 01:06:53 2019 -0500
+++ b/pidgin/gtkxfer.c Mon Dec 30 07:08:44 2019 +0000
@@ -46,8 +46,6 @@
GtkWidget *keep_open;
GtkWidget *auto_clear;
- gint num_transfers;
-
PurpleXfer *selected_xfer;
GtkWidget *tree;
@@ -78,14 +76,11 @@
G_DEFINE_TYPE(PidginXferDialog, pidgin_xfer_dialog, GTK_TYPE_DIALOG);
+#define UI_DATA "pidgin-ui-data"
typedef struct
{
GtkTreeIter iter;
gint64 last_updated_time;
- gboolean in_list;
-
- char *name;
-
} PidginXferUiData;
static PidginXferDialog *xfer_dialog = NULL;
@@ -237,7 +232,7 @@
if (dialog == NULL || xfer == NULL)
return;
- data = purple_xfer_get_ui_data(xfer);
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
get_xfer_info_strings(xfer, &kbsec, &time_elapsed, &time_remaining);
@@ -695,8 +690,7 @@
g_object_ref(xfer);
- data = purple_xfer_get_ui_data(xfer);
- data->in_list = TRUE;
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
pidgin_xfer_dialog_show(dialog);
@@ -729,8 +723,6 @@
g_free(size_str);
g_free(remaining_str);
- dialog->num_transfers++;
-
ensure_row_selected(dialog);
update_title_progress(dialog);
}
@@ -744,20 +736,19 @@
g_return_if_fail(dialog != NULL);
g_return_if_fail(xfer != NULL);
- data = purple_xfer_get_ui_data(xfer);
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
if (data == NULL)
return;
- if (!data->in_list)
+ if (!purple_xfer_get_visible(xfer)) {
return;
+ }
- data->in_list = FALSE;
+ purple_xfer_set_visible(xfer, FALSE);
gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &data->iter);
- dialog->num_transfers--;
-
ensure_row_selected(dialog);
update_title_progress(dialog);
@@ -774,13 +765,14 @@
g_return_if_fail(dialog != NULL);
g_return_if_fail(xfer != NULL);
- data = purple_xfer_get_ui_data(xfer);
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
if (data == NULL)
return;
- if (!data->in_list)
+ if (!purple_xfer_get_visible(xfer)) {
return;
+ }
if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL &&
gtk_toggle_button_get_active(
@@ -789,7 +781,7 @@
return;
}
- data = purple_xfer_get_ui_data(xfer);
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
update_detailed_info(dialog, xfer);
update_title_progress(dialog);
@@ -820,11 +812,10 @@
g_return_if_fail(dialog != NULL);
g_return_if_fail(xfer != NULL);
- if ((data = purple_xfer_get_ui_data(xfer)) == NULL)
+ data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
+ if (data == NULL || !purple_xfer_get_visible(xfer)) {
return;
-
- if (data->in_list == FALSE)
- return;
+ }
current_time = g_get_monotonic_time();
if (((current_time - data->last_updated_time) < G_USEC_PER_SEC) &&
@@ -901,59 +892,8 @@
* 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)
+pidgin_xfer_add_thumbnail(PurpleXfer *xfer, const gchar *formats,
+ G_GNUC_UNUSED gpointer data)
{
purple_debug_info("xfer", "creating thumbnail for transfer\n");
@@ -1013,18 +953,61 @@
}
}
+static void
+pidgin_xfer_progress_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
+{
+ pidgin_xfer_dialog_update_xfer(xfer_dialog, xfer);
+}
+
+static void
+pidgin_xfer_status_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
+{
+ if (xfer_dialog) {
+ if (purple_xfer_is_cancelled(xfer)) {
+ pidgin_xfer_dialog_cancel_xfer(xfer_dialog, xfer);
+ }
+ }
+}
+
+static void
+pidgin_xfer_visible_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
+{
+ if (!purple_xfer_get_visible(xfer)) {
+ return;
+ }
+
+ if (xfer_dialog == NULL) {
+ xfer_dialog = pidgin_xfer_dialog_new();
+ }
+
+ pidgin_xfer_dialog_add_xfer(xfer_dialog, xfer);
+}
+
+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);
+ g_object_set_data_full(G_OBJECT(xfer), UI_DATA, data, g_free);
+
+ g_signal_connect(xfer, "add-thumbnail",
+ G_CALLBACK(pidgin_xfer_add_thumbnail), NULL);
+ g_signal_connect(xfer, "notify::progress",
+ G_CALLBACK(pidgin_xfer_progress_notify), NULL);
+ g_signal_connect(xfer, "notify::status",
+ G_CALLBACK(pidgin_xfer_status_notify), NULL);
+ g_signal_connect(xfer, "notify::visible",
+ G_CALLBACK(pidgin_xfer_visible_notify), NULL);
+}
+
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
+ pidgin_xfer_new_xfer
};
/**************************************************************************