Skip to content

Commit

Permalink
Merge pull request #993 from larchunix/spice-file-xfer-progress
Browse files Browse the repository at this point in the history
spice: show progress of drag & drop file transfers
  • Loading branch information
antenore authored Sep 13, 2016
2 parents 0967c05 + 7ba2110 commit 42f5a87
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 0 deletions.
1 change: 1 addition & 0 deletions remmina-plugins/spice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

set(REMMINA_PLUGIN_SPICE_SRCS
spice_plugin.c
spice_plugin_file_transfer.c
spice_plugin_usb.c
)

Expand Down
22 changes: 22 additions & 0 deletions remmina-plugins/spice/spice_plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ static void remmina_plugin_spice_display_ready_cb(GObject *, GParamSpec *, Remmi
static void remmina_plugin_spice_update_scale(RemminaProtocolWidget *);

void remmina_plugin_spice_select_usb_devices(RemminaProtocolWidget *);
#ifdef SPICE_GTK_CHECK_VERSION
# if SPICE_GTK_CHECK_VERSION(0, 31, 0)
void remmina_plugin_spice_file_transfer_new_cb(SpiceMainChannel *, SpiceFileTransferTask *, RemminaProtocolWidget *);
# endif /* SPICE_GTK_CHECK_VERSION(0, 31, 0) */
#endif /* SPICE_GTK_CHECK_VERSION */

static void remmina_plugin_spice_init(RemminaProtocolWidget *gp)
{
Expand Down Expand Up @@ -152,6 +157,15 @@ static gboolean remmina_plugin_spice_close_connection(RemminaProtocolWidget *gp)
remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect");
}

#ifdef SPICE_GTK_CHECK_VERSION
# if SPICE_GTK_CHECK_VERSION(0, 31, 0)
if (gpdata->file_transfers)
{
g_hash_table_unref(gpdata->file_transfers);
}
# endif /* SPICE_GTK_CHECK_VERSION(0, 31, 0) */
#endif /* SPICE_GTK_CHECK_VERSION */

return FALSE;
}

Expand All @@ -172,6 +186,14 @@ static void remmina_plugin_spice_channel_new_cb(SpiceSession *session, SpiceChan
"channel-event",
G_CALLBACK(remmina_plugin_spice_main_channel_event_cb),
gp);
#ifdef SPICE_GTK_CHECK_VERSION
# if SPICE_GTK_CHECK_VERSION(0, 31, 0)
g_signal_connect(channel,
"new-file-transfer",
G_CALLBACK(remmina_plugin_spice_file_transfer_new_cb),
gp);
# endif /* SPICE_GTK_CHECK_VERSION(0, 31, 0) */
#endif /* SPICE_GTK_CHECK_VERSION */
}

if (SPICE_IS_DISPLAY_CHANNEL(channel))
Expand Down
8 changes: 8 additions & 0 deletions remmina-plugins/spice/spice_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ typedef struct _RemminaPluginSpiceData
SpiceGtkSession *gtk_session;
SpiceMainChannel *main_channel;
SpiceSession *session;

#ifdef SPICE_GTK_CHECK_VERSION
# if SPICE_GTK_CHECK_VERSION(0, 31, 0)
/* key: SpiceFileTransferTask, value: RemminaPluginSpiceXferWidgets */
GHashTable *file_transfers;
GtkWidget *file_transfer_dialog;
# endif /* SPICE_GTK_CHECK_VERSION(0, 31, 0) */
#endif /* SPICE_GTK_CHECK_VERSION */
} RemminaPluginSpiceData;


Expand Down
223 changes: 223 additions & 0 deletions remmina-plugins/spice/spice_plugin_file_transfer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
* Remmina - The GTK+ Remote Desktop Client
* Copyright (C) 2016 Denis Ollier
*
* 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 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. * If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. * If you
* do not wish to do so, delete this exception statement from your
* version. * If you delete this exception statement from all source
* files in the program, then also delete it here.
*
*/

#include "spice_plugin.h"

#ifdef SPICE_GTK_CHECK_VERSION
# if SPICE_GTK_CHECK_VERSION(0, 31, 0)

static void remmina_plugin_spice_file_transfer_cancel_cb(GtkButton *, SpiceFileTransferTask *);
static void remmina_plugin_spice_file_transfer_dialog_response_cb(GtkDialog *, gint, RemminaProtocolWidget *);
static void remmina_plugin_spice_file_transfer_finished_cb(SpiceFileTransferTask *, GError *, RemminaProtocolWidget *);
static void remmina_plugin_spice_file_transfer_progress_cb(GObject *, GParamSpec *, RemminaProtocolWidget *);

typedef struct _RemminaPluginSpiceXferWidgets {
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *progress;
GtkWidget *label;
GtkWidget *cancel;
} RemminaPluginSpiceXferWidgets;

static RemminaPluginSpiceXferWidgets * remmina_plugin_spice_xfer_widgets_new(SpiceFileTransferTask *);
static void remmina_plugin_spice_xfer_widgets_free(RemminaPluginSpiceXferWidgets *widgets);

void remmina_plugin_spice_file_transfer_new_cb(SpiceMainChannel *main_channel, SpiceFileTransferTask *task, RemminaProtocolWidget *gp)
{
TRACE_CALL(__func__);

GtkWidget *dialog_content;
RemminaPluginSpiceXferWidgets *widgets;
RemminaPluginSpiceData *gpdata = GET_PLUGIN_DATA(gp);

g_signal_connect(task,
"finished",
G_CALLBACK(remmina_plugin_spice_file_transfer_finished_cb),
gp);

if (!gpdata->file_transfers)
{
gpdata->file_transfers = g_hash_table_new_full(g_direct_hash,
g_direct_equal,
g_object_unref,
(GDestroyNotify)remmina_plugin_spice_xfer_widgets_free);
}

if (!gpdata->file_transfer_dialog)
{
/*
* FIXME: Use the RemminaConnectionWindow as transient parent widget
* (and add the GTK_DIALOG_DESTROY_WITH_PARENT flag) if it becomes
* accessible from the Remmina plugin API.
*/
gpdata->file_transfer_dialog = gtk_dialog_new_with_buttons(_("File Transfers"),
NULL, 0,
_("_Cancel"),
GTK_RESPONSE_CANCEL,
NULL);
dialog_content = gtk_dialog_get_content_area(GTK_DIALOG(gpdata->file_transfer_dialog));
gtk_widget_set_size_request(dialog_content, 400, -1);
gtk_window_set_resizable(GTK_WINDOW(gpdata->file_transfer_dialog), FALSE);
g_signal_connect(gpdata->file_transfer_dialog,
"response",
G_CALLBACK(remmina_plugin_spice_file_transfer_dialog_response_cb),
gp);
}

widgets = remmina_plugin_spice_xfer_widgets_new(task);
g_hash_table_insert(gpdata->file_transfers, g_object_ref(task), widgets);

gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(gpdata->file_transfer_dialog))),
widgets->vbox,
TRUE, TRUE, 6);

g_signal_connect(task,
"notify::progress",
G_CALLBACK(remmina_plugin_spice_file_transfer_progress_cb),
gp);

gtk_widget_show(gpdata->file_transfer_dialog);
}

static RemminaPluginSpiceXferWidgets * remmina_plugin_spice_xfer_widgets_new(SpiceFileTransferTask *task)
{
TRACE_CALL(__func__);

gchar *filename;
RemminaPluginSpiceXferWidgets *widgets = g_new0(RemminaPluginSpiceXferWidgets, 1);

widgets->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
widgets->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);

filename = spice_file_transfer_task_get_filename(task);
widgets->label = gtk_label_new(filename);
gtk_widget_set_halign(widgets->label, GTK_ALIGN_START);
gtk_widget_set_valign(widgets->label, GTK_ALIGN_BASELINE);

widgets->progress = gtk_progress_bar_new();
gtk_widget_set_hexpand(widgets->progress, TRUE);
gtk_widget_set_valign(widgets->progress, GTK_ALIGN_CENTER);

widgets->cancel = gtk_button_new_from_icon_name("gtk-cancel", GTK_ICON_SIZE_SMALL_TOOLBAR);
g_signal_connect(widgets->cancel,
"clicked",
G_CALLBACK(remmina_plugin_spice_file_transfer_cancel_cb),
task);
gtk_widget_set_hexpand(widgets->cancel, FALSE);
gtk_widget_set_valign(widgets->cancel, GTK_ALIGN_CENTER);

gtk_box_pack_start(GTK_BOX(widgets->hbox), widgets->progress,
TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(widgets->hbox), widgets->cancel,
FALSE, TRUE, 0);

gtk_box_pack_start(GTK_BOX(widgets->vbox), widgets->label,
TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(widgets->vbox), widgets->hbox,
TRUE, TRUE, 0);

gtk_widget_show_all(widgets->vbox);

g_free(filename);

return widgets;
}

static void remmina_plugin_spice_xfer_widgets_free(RemminaPluginSpiceXferWidgets *widgets)
{
TRACE_CALL(__func__);

/* Child widgets will be destroyed automatically */
gtk_widget_destroy(widgets->vbox);
g_free(widgets);
}

static void remmina_plugin_spice_file_transfer_cancel_cb(GtkButton *button, SpiceFileTransferTask *task)
{
TRACE_CALL(__func__);

spice_file_transfer_task_cancel(task);
}


static void remmina_plugin_spice_file_transfer_dialog_response_cb(GtkDialog *dialog, gint response, RemminaProtocolWidget *gp)
{
TRACE_CALL(__func__);

GHashTableIter iter;
gpointer key, value;
SpiceFileTransferTask *task;
RemminaPluginSpiceData *gpdata = GET_PLUGIN_DATA(gp);

if (response == GTK_RESPONSE_CANCEL)
{
g_hash_table_iter_init(&iter, gpdata->file_transfers);
while (g_hash_table_iter_next(&iter, &key, &value))
{
task = key;
spice_file_transfer_task_cancel(task);
}
}
}

static void remmina_plugin_spice_file_transfer_progress_cb(GObject *task, GParamSpec *param_spec, RemminaProtocolWidget *gp)
{
TRACE_CALL(__func__);

RemminaPluginSpiceXferWidgets *widgets;
RemminaPluginSpiceData *gpdata = GET_PLUGIN_DATA(gp);

widgets = g_hash_table_lookup(gpdata->file_transfers, task);
if (widgets)
{
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(widgets->progress),
spice_file_transfer_task_get_progress(SPICE_FILE_TRANSFER_TASK(task)));
}
}

static void remmina_plugin_spice_file_transfer_finished_cb(SpiceFileTransferTask *task, GError *error, RemminaProtocolWidget *gp)
{
TRACE_CALL(__func__);

RemminaPluginSpiceData *gpdata = GET_PLUGIN_DATA(gp);

g_hash_table_remove(gpdata->file_transfers, task);

if (!g_hash_table_size(gpdata->file_transfers))
{
gtk_widget_hide(gpdata->file_transfer_dialog);
}
}
# endif /* SPICE_GTK_CHECK_VERSION(0, 31, 0) */
#endif /* SPICE_GTK_CHECK_VERSION */

0 comments on commit 42f5a87

Please sign in to comment.