On Mon, May 2, 2016 at 12:13 PM, Fabiano Fidêncio <fabiano@xxxxxxxxxxxx> wrote: > On Mon, May 2, 2016 at 12:10 PM, Fabiano Fidêncio <fabiano@xxxxxxxxxxxx> wrote: >> On Fri, Apr 8, 2016 at 5:26 PM, Jonathon Jongsma <jjongsma@xxxxxxxxxx> wrote: >>> This dialog will show the progress of files being transferred from the >>> client to the guest and allows the user to cancel ongoing file transfer >>> tasks. The user can cancel each transfer individually, or cancel all >>> ongoing transfers at once. >>> --- >>> src/Makefile.am | 2 + >>> src/virt-viewer-file-transfer-dialog.c | 213 +++++++++++++++++++++++++++++++++ >> >> This file must be included in po/POTFILES.in >> >>> src/virt-viewer-file-transfer-dialog.h | 61 ++++++++++ >>> src/virt-viewer-session-spice.c | 23 +++- >>> 4 files changed, 298 insertions(+), 1 deletion(-) >>> create mode 100644 src/virt-viewer-file-transfer-dialog.c >>> create mode 100644 src/virt-viewer-file-transfer-dialog.h >>> >>> diff --git a/src/Makefile.am b/src/Makefile.am >>> index ff487ba..115d73d 100644 >>> --- a/src/Makefile.am >>> +++ b/src/Makefile.am >>> @@ -91,6 +91,8 @@ libvirt_viewer_la_SOURCES += \ >>> virt-viewer-session-spice.c \ >>> virt-viewer-display-spice.h \ >>> virt-viewer-display-spice.c \ >>> + virt-viewer-file-transfer-dialog.h \ >>> + virt-viewer-file-transfer-dialog.c \ >>> $(NULL) >>> endif >>> >>> diff --git a/src/virt-viewer-file-transfer-dialog.c b/src/virt-viewer-file-transfer-dialog.c >>> new file mode 100644 >>> index 0000000..bd85d82 >>> --- /dev/null >>> +++ b/src/virt-viewer-file-transfer-dialog.c >>> @@ -0,0 +1,213 @@ >>> +/* >>> + * Virt Viewer: A virtual machine console viewer >>> + * >>> + * Copyright (C) 2016 Red Hat, Inc. >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License as published by >>> + * the Free Software Foundation; either version 2 of the License, or >>> + * (at your option) any later version. >>> + * >>> + * This program is distributed in the hope that it will be useful, >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>> + * GNU General Public License for more details. >>> + * >>> + * You should have received a copy of the GNU General Public License >>> + * along with this program; if not, write to the Free Software >>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >>> + */ >>> + >>> +#include "virt-viewer-file-transfer-dialog.h" >>> +#include <glib/gi18n.h> > > And is also missing #include <config.h> > >>> + >>> +G_DEFINE_TYPE(VirtViewerFileTransferDialog, virt_viewer_file_transfer_dialog, GTK_TYPE_DIALOG) >>> + >>> +#define FILE_TRANSFER_DIALOG_PRIVATE(o) \ >>> + (G_TYPE_INSTANCE_GET_PRIVATE((o), VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG, VirtViewerFileTransferDialogPrivate)) >>> + >>> +struct _VirtViewerFileTransferDialogPrivate >>> +{ >>> + /* GHashTable<SpiceFileTransferTask, widgets> */ >>> + GHashTable *file_transfers; >>> +}; >>> + >>> + >>> +static void >>> +virt_viewer_file_transfer_dialog_dispose(GObject *object) >>> +{ >>> + VirtViewerFileTransferDialog *self = VIRT_VIEWER_FILE_TRANSFER_DIALOG(object); >>> + >>> + g_clear_pointer(&self->priv->file_transfers, g_hash_table_unref); >>> + >>> + G_OBJECT_CLASS(virt_viewer_file_transfer_dialog_parent_class)->dispose(object); >>> +} >>> + >>> +static void >>> +virt_viewer_file_transfer_dialog_class_init(VirtViewerFileTransferDialogClass *klass) >>> +{ >>> + GObjectClass *object_class = G_OBJECT_CLASS(klass); >>> + >>> + g_type_class_add_private(klass, sizeof(VirtViewerFileTransferDialogPrivate)); >>> + >>> + object_class->dispose = virt_viewer_file_transfer_dialog_dispose; >>> +} >>> + >>> +static void >>> +dialog_response(GtkDialog *dialog, >>> + gint response_id, >>> + gpointer user_data G_GNUC_UNUSED) >>> +{ >>> + VirtViewerFileTransferDialog *self = VIRT_VIEWER_FILE_TRANSFER_DIALOG(dialog); >>> + GHashTableIter iter; >>> + gpointer key, value; >>> + >>> + switch (response_id) { >>> + case GTK_RESPONSE_CANCEL: >>> + /* cancel all current tasks */ >>> + g_hash_table_iter_init(&iter, self->priv->file_transfers); >>> + >>> + while (g_hash_table_iter_next(&iter, &key, &value)) { >>> + spice_file_transfer_task_cancel(SPICE_FILE_TRANSFER_TASK(key)); >>> + } >>> + break; >>> + case GTK_RESPONSE_DELETE_EVENT: >>> + /* silently ignore */ >>> + break; >>> + default: >>> + g_warn_if_reached(); >>> + } >>> +} >>> + >>> +static void task_cancel_clicked(GtkButton *button G_GNUC_UNUSED, >>> + gpointer user_data) >>> +{ >>> + SpiceFileTransferTask *task = user_data; >>> + spice_file_transfer_task_cancel(task); >>> +} >>> + >>> +typedef struct { >>> + GtkWidget *vbox; >>> + GtkWidget *hbox; >>> + GtkWidget *progress; >>> + GtkWidget *label; >>> + GtkWidget *cancel; >>> +} TaskWidgets; >>> + >>> +static TaskWidgets *task_widgets_new(SpiceFileTransferTask *task) >>> +{ >>> + TaskWidgets *w = g_new0(TaskWidgets, 1); >>> + >>> + w->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); >>> + w->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); >>> + w->progress = gtk_progress_bar_new(); >>> + w->label = gtk_label_new(spice_file_transfer_task_get_filename(task)); >>> + w->cancel = gtk_button_new_from_icon_name("gtk-cancel", GTK_ICON_SIZE_SMALL_TOOLBAR); >>> + gtk_widget_set_hexpand(w->progress, TRUE); >>> + gtk_widget_set_valign(w->progress, GTK_ALIGN_CENTER); >>> + gtk_widget_set_hexpand(w->label, TRUE); >>> + gtk_widget_set_valign(w->label, GTK_ALIGN_END); >>> + gtk_widget_set_halign(w->label, GTK_ALIGN_START); >>> + gtk_widget_set_hexpand(w->cancel, FALSE); >>> + gtk_widget_set_valign(w->cancel, GTK_ALIGN_CENTER); >>> + >>> + g_signal_connect(w->cancel, "clicked", >>> + G_CALLBACK(task_cancel_clicked), task); >>> + >>> + gtk_box_pack_start(GTK_BOX(w->hbox), w->progress, TRUE, TRUE, 0); >>> + gtk_box_pack_start(GTK_BOX(w->hbox), w->cancel, FALSE, TRUE, 0); >>> + gtk_box_pack_start(GTK_BOX(w->vbox), w->label, TRUE, TRUE, 0); >>> + gtk_box_pack_start(GTK_BOX(w->vbox), w->hbox, TRUE, TRUE, 0); >>> + >>> + gtk_widget_show_all(w->vbox); >>> + return w; >>> +} >>> + >>> +static gboolean delete_event(GtkWidget *widget, >>> + GdkEvent *event G_GNUC_UNUSED, >>> + gpointer user_data G_GNUC_UNUSED) >>> +{ >>> + /* don't allow window to be deleted, just process the response signal, >>> + * which may result in the window being hidden */ >>> + gtk_dialog_response(GTK_DIALOG(widget), GTK_RESPONSE_CANCEL); >>> + return TRUE; >>> +} >>> + >>> +static void >>> +virt_viewer_file_transfer_dialog_init(VirtViewerFileTransferDialog *self) >>> +{ >>> + GtkBox *content = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(self))); >>> + >>> + self->priv = FILE_TRANSFER_DIALOG_PRIVATE(self); >>> + >>> + gtk_widget_set_size_request(GTK_WIDGET(content), 400, -1); >>> + gtk_container_set_border_width(GTK_CONTAINER(content), 12); >>> + self->priv->file_transfers = g_hash_table_new_full(g_direct_hash, g_direct_equal, >>> + g_object_unref, >>> + (GDestroyNotify)g_free); >>> + gtk_dialog_add_button(GTK_DIALOG(self), _("Cancel"), GTK_RESPONSE_CANCEL); >>> + gtk_dialog_set_default_response(GTK_DIALOG(self), >>> + GTK_RESPONSE_CANCEL); >>> + g_signal_connect(self, "response", G_CALLBACK(dialog_response), NULL); >>> + g_signal_connect(self, "delete-event", G_CALLBACK(delete_event), NULL); >>> +} >>> + >>> +VirtViewerFileTransferDialog * >>> +virt_viewer_file_transfer_dialog_new(GtkWindow *parent) >>> +{ >>> + return g_object_new(VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG, >>> + "title", _("File Transfers"), >>> + "transient-for", parent, >>> + "resizable", FALSE, >>> + NULL); >>> +} >>> + >>> +static void task_progress_notify(GObject *object, >>> + GParamSpec *pspec G_GNUC_UNUSED, >>> + gpointer user_data) >>> +{ >>> + VirtViewerFileTransferDialog *self = VIRT_VIEWER_FILE_TRANSFER_DIALOG(user_data); >>> + SpiceFileTransferTask *task = SPICE_FILE_TRANSFER_TASK(object); >>> + TaskWidgets *w = g_hash_table_lookup(self->priv->file_transfers, task); >>> + g_return_if_fail(w); >>> + >>> + double pct = spice_file_transfer_task_get_progress(task); >>> + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(w->progress), pct); >>> +} >>> + >>> +static void task_finished(SpiceFileTransferTask *task, >>> + GError *error, >>> + gpointer user_data) >>> +{ >>> + VirtViewerFileTransferDialog *self = VIRT_VIEWER_FILE_TRANSFER_DIALOG(user_data); >>> + TaskWidgets *w = g_hash_table_lookup(self->priv->file_transfers, task); >>> + >>> + if (error && !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) >>> + g_warning("File transfer task %p failed: %s", task, error->message); >>> + >>> + g_return_if_fail(w); >>> + >>> + gtk_widget_destroy(w->vbox); >>> + >>> + g_hash_table_remove(self->priv->file_transfers, task); >>> + >>> + /* if this is the last transfer, close the dialog */ >>> + if (!g_hash_table_size(self->priv->file_transfers)) >>> + gtk_widget_hide(GTK_WIDGET(self)); >>> +} >>> + >>> +void virt_viewer_file_transfer_dialog_add_task(VirtViewerFileTransferDialog *self, >>> + SpiceFileTransferTask *task) >>> +{ >>> + GtkBox *content = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(self))); >>> + TaskWidgets *w = task_widgets_new(task); >>> + >>> + gtk_box_pack_start(content, >>> + w->vbox, >>> + TRUE, TRUE, 12); >>> + g_hash_table_insert(self->priv->file_transfers, g_object_ref(task), w); >>> + g_signal_connect(task, "notify::progress", G_CALLBACK(task_progress_notify), self); >>> + g_signal_connect(task, "finished", G_CALLBACK(task_finished), self); >>> + >>> + gtk_widget_show(GTK_WIDGET(self)); >>> +} >>> diff --git a/src/virt-viewer-file-transfer-dialog.h b/src/virt-viewer-file-transfer-dialog.h >>> new file mode 100644 >>> index 0000000..8805b14 >>> --- /dev/null >>> +++ b/src/virt-viewer-file-transfer-dialog.h >>> @@ -0,0 +1,61 @@ >>> +/* >>> + * Virt Viewer: A virtual machine console viewer >>> + * >>> + * Copyright (C) 2016 Red Hat, Inc. >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License as published by >>> + * the Free Software Foundation; either version 2 of the License, or >>> + * (at your option) any later version. >>> + * >>> + * This program is distributed in the hope that it will be useful, >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>> + * GNU General Public License for more details. >>> + * >>> + * You should have received a copy of the GNU General Public License >>> + * along with this program; if not, write to the Free Software >>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >>> + */ >>> + >>> +#ifndef __VIRT_VIEWER_FILE_TRANSFER_DIALOG_H__ >>> +#define __VIRT_VIEWER_FILE_TRANSFER_DIALOG_H__ >>> + >>> +#include <gtk/gtk.h> >>> +#include <spice-client.h> >>> + >>> +G_BEGIN_DECLS >>> + >>> +#define VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG virt_viewer_file_transfer_dialog_get_type() >>> + >>> +#define VIRT_VIEWER_FILE_TRANSFER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG, VirtViewerFileTransferDialog)) >>> +#define VIRT_VIEWER_FILE_TRANSFER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG, VirtViewerFileTransferDialogClass)) >>> +#define VIRT_VIEWER_IS_FILE_TRANSFER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG)) >>> +#define VIRT_VIEWER_IS_FILE_TRANSFER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG)) >>> +#define VIRT_VIEWER_FILE_TRANSFER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VIRT_VIEWER_TYPE_FILE_TRANSFER_DIALOG, VirtViewerFileTransferDialogClass)) >>> + >>> +typedef struct _VirtViewerFileTransferDialog VirtViewerFileTransferDialog; >>> +typedef struct _VirtViewerFileTransferDialogClass VirtViewerFileTransferDialogClass; >>> +typedef struct _VirtViewerFileTransferDialogPrivate VirtViewerFileTransferDialogPrivate; >>> + >>> +struct _VirtViewerFileTransferDialog >>> +{ >>> + GtkDialog parent; >>> + >>> + VirtViewerFileTransferDialogPrivate *priv; >>> +}; >>> + >>> +struct _VirtViewerFileTransferDialogClass >>> +{ >>> + GtkDialogClass parent_class; >>> +}; >>> + >>> +GType virt_viewer_file_transfer_dialog_get_type(void) G_GNUC_CONST; >>> + >>> +VirtViewerFileTransferDialog *virt_viewer_file_transfer_dialog_new(GtkWindow *parent); >>> +void virt_viewer_file_transfer_dialog_add_task(VirtViewerFileTransferDialog *self, >>> + SpiceFileTransferTask *task); >>> + >>> +G_END_DECLS >>> + >>> +#endif /* __VIRT_VIEWER_FILE_TRANSFER_DIALOG_H__ */ >>> diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c >>> index f7f2dc9..5f05df7 100644 >>> --- a/src/virt-viewer-session-spice.c >>> +++ b/src/virt-viewer-session-spice.c >>> @@ -30,12 +30,12 @@ >>> >>> #include <usb-device-widget.h> >>> #include "virt-viewer-file.h" >>> +#include "virt-viewer-file-transfer-dialog.h" >>> #include "virt-viewer-util.h" >>> #include "virt-viewer-session-spice.h" >>> #include "virt-viewer-display-spice.h" >>> #include "virt-viewer-auth.h" >>> >>> - >>> G_DEFINE_TYPE (VirtViewerSessionSpice, virt_viewer_session_spice, VIRT_VIEWER_TYPE_SESSION) >>> >>> >>> @@ -50,6 +50,8 @@ struct _VirtViewerSessionSpicePrivate { >>> gboolean has_sw_smartcard_reader; >>> guint pass_try; >>> gboolean did_auto_conf; >>> + VirtViewerFileTransferDialog *file_transfer_dialog; >>> + >>> }; >>> >>> #define VIRT_VIEWER_SESSION_SPICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), VIRT_VIEWER_TYPE_SESSION_SPICE, VirtViewerSessionSpicePrivate)) >>> @@ -147,6 +149,10 @@ virt_viewer_session_spice_dispose(GObject *obj) >>> spice->priv->audio = NULL; >>> >>> g_clear_object(&spice->priv->main_window); >>> + if (spice->priv->file_transfer_dialog) { >>> + gtk_widget_destroy(GTK_WIDGET(spice->priv->file_transfer_dialog)); >>> + spice->priv->file_transfer_dialog = NULL; >>> + } >>> >>> G_OBJECT_CLASS(virt_viewer_session_spice_parent_class)->dispose(obj); >>> } >>> @@ -224,6 +230,9 @@ virt_viewer_session_spice_constructed(GObject *obj) >>> G_CALLBACK(update_share_folder), self, >>> G_CONNECT_SWAPPED); >>> >>> + self->priv->file_transfer_dialog = >>> + virt_viewer_file_transfer_dialog_new(self->priv->main_window); >>> + >>> G_OBJECT_CLASS(virt_viewer_session_spice_parent_class)->constructed(obj); >>> } >>> >>> @@ -922,6 +931,16 @@ virt_viewer_session_spice_display_monitors(SpiceChannel *channel, >>> } >>> >>> static void >>> +on_new_file_transfer(SpiceMainChannel *channel G_GNUC_UNUSED, >>> + SpiceFileTransferTask *task, >>> + gpointer user_data) >>> +{ >>> + VirtViewerSessionSpice *self = VIRT_VIEWER_SESSION_SPICE(user_data); >>> + virt_viewer_file_transfer_dialog_add_task(self->priv->file_transfer_dialog, >>> + task); >>> +} >>> + >>> +static void >>> virt_viewer_session_spice_channel_new(SpiceSession *s, >>> SpiceChannel *channel, >>> VirtViewerSession *session) >>> @@ -953,6 +972,8 @@ virt_viewer_session_spice_channel_new(SpiceSession *s, >>> >>> virt_viewer_signal_connect_object(channel, "notify::agent-connected", >>> G_CALLBACK(agent_connected_changed), self, 0); >>> + virt_viewer_signal_connect_object(channel, "new-file-transfer", >>> + G_CALLBACK(on_new_file_transfer), self, 0); >>> } >>> >>> if (SPICE_IS_DISPLAY_CHANNEL(channel)) { >>> -- >>> 2.4.11 >>> >>> _______________________________________________ >>> virt-tools-list mailing list >>> virt-tools-list@xxxxxxxxxx >>> https://www.redhat.com/mailman/listinfo/virt-tools-list >> >> >> ACK! >> -- >> Fabiano Fidêncio > > > > -- > Fabiano Fidêncio > > _______________________________________________ > virt-tools-list mailing list > virt-tools-list@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/virt-tools-list I've done the necessary changes and pushed both patches. Thanks! _______________________________________________ virt-tools-list mailing list virt-tools-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/virt-tools-list