diff --git a/SOURCES/0023-vnc-session-save-message-from-vnc-error-for-vnc-disc.patch b/SOURCES/0023-vnc-session-save-message-from-vnc-error-for-vnc-disc.patch new file mode 100644 index 0000000..fc0ccd4 --- /dev/null +++ b/SOURCES/0023-vnc-session-save-message-from-vnc-error-for-vnc-disc.patch @@ -0,0 +1,88 @@ +From 11ec065ce2aea7d0529539e4af1a95d8e210ed27 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jakub=20Jank=C5=AF?= +Date: Wed, 3 Feb 2021 23:27:50 +0100 +Subject: [PATCH] vnc-session: save message from "vnc-error" for "vnc-disconnected" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +"vnc-error" is always followed by "vnc-disconnected". +So save the error message and use it in "vnc-disconnected" callback. + +"session-disconnected" already allows us to set a string +with details on why the disconnection happened. + +This approach is also similar to the one in spice session +(GError is saved in virt_viewer_session_spice_channel_destroyed). + +Signed-off-by: Jakub Janků +--- + src/virt-viewer-session-vnc.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/src/virt-viewer-session-vnc.c b/src/virt-viewer-session-vnc.c +index 3d11112..7d6dfb2 100644 +--- a/src/virt-viewer-session-vnc.c ++++ b/src/virt-viewer-session-vnc.c +@@ -40,6 +40,7 @@ struct _VirtViewerSessionVncPrivate { + /* XXX we should really just have a VncConnection */ + VncDisplay *vnc; + gboolean auth_dialog_cancelled; ++ gchar *error_msg; + }; + + G_DEFINE_TYPE_WITH_PRIVATE(VirtViewerSessionVnc, virt_viewer_session_vnc, VIRT_VIEWER_TYPE_SESSION) +@@ -63,6 +64,7 @@ virt_viewer_session_vnc_finalize(GObject *obj) + } + if (vnc->priv->main_window) + g_object_unref(vnc->priv->main_window); ++ g_free(vnc->priv->error_msg); + + G_OBJECT_CLASS(virt_viewer_session_vnc_parent_class)->finalize(obj); + } +@@ -122,7 +124,7 @@ virt_viewer_session_vnc_disconnected(VncDisplay *vnc G_GNUC_UNUSED, + virt_viewer_session_clear_displays(VIRT_VIEWER_SESSION(session)); + display = virt_viewer_display_vnc_new(session, session->priv->vnc); + g_debug("Disconnected"); +- g_signal_emit_by_name(session, "session-disconnected", NULL); ++ g_signal_emit_by_name(session, "session-disconnected", session->priv->error_msg); + virt_viewer_display_set_enabled(VIRT_VIEWER_DISPLAY(display), FALSE); + virt_viewer_display_set_show_hint(VIRT_VIEWER_DISPLAY(display), + VIRT_VIEWER_DISPLAY_SHOW_HINT_READY, FALSE); +@@ -135,6 +137,10 @@ virt_viewer_session_vnc_error(VncDisplay *vnc G_GNUC_UNUSED, + { + g_warning("vnc-session: got vnc error %s", msg); + g_signal_emit_by_name(session, "session-error", msg); ++ /* "vnc-error" is always followed by "vnc-disconnected", ++ * so save the error for that signal */ ++ g_free(session->priv->error_msg); ++ session->priv->error_msg = g_strdup(msg); + } + + static void +@@ -162,8 +168,9 @@ virt_viewer_session_vnc_bell(VncDisplay *vnc G_GNUC_UNUSED, + static void + virt_viewer_session_vnc_auth_unsupported(VncDisplay *vnc G_GNUC_UNUSED, + unsigned int authType, +- VirtViewerSession *session) ++ VirtViewerSessionVnc *session) + { ++ g_clear_pointer(&session->priv->error_msg, g_free); + gchar *msg = g_strdup_printf(_("Unsupported authentication type %u"), + authType); + g_signal_emit_by_name(session, "session-auth-unsupported", msg); +@@ -173,9 +180,9 @@ virt_viewer_session_vnc_auth_unsupported(VncDisplay *vnc G_GNUC_UNUSED, + static void + virt_viewer_session_vnc_auth_failure(VncDisplay *vnc G_GNUC_UNUSED, + const gchar *reason, +- VirtViewerSession *session) ++ VirtViewerSessionVnc *session) + { +- ++ g_clear_pointer(&session->priv->error_msg, g_free); + g_signal_emit_by_name(session, "session-auth-refused", reason); + } + +-- +2.29.2 + diff --git a/SOURCES/0024-session-remove-session-error-signal.patch b/SOURCES/0024-session-remove-session-error-signal.patch new file mode 100644 index 0000000..33aa9c0 --- /dev/null +++ b/SOURCES/0024-session-remove-session-error-signal.patch @@ -0,0 +1,163 @@ +From 8bc91ac80f9c5c7df30f25e35946be0869be3db5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jakub=20Jank=C5=AF?= +Date: Wed, 10 Feb 2021 10:58:57 +0100 +Subject: [PATCH] session: remove "session-error" signal +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This partially reverts commit de5cd71. + +Problem with that commit is, that it practically renders +the "session-auth-*" signals from vnc session useless. +That's because gtk-vnc currently emits "vnc-error" before each +"vnc-auth-*" signal and the error callback in virt-viewer-app.c +calls virt_viewer_app_disconnected(), which in turn closes +the session. +As a consequence, virt-viewer never retries authentication +with vnc, it simply exits. + +Since the last commit, vnc, similarly to spice, emits +"session-disconnected" with the appropriate error message. Thus +there's no need to maintain separate "session-error" signal +for now. + +With vnc, this error message is shown to the user in a dialog, +if the disconnect happened during the init phase. +"session-auth-*" callbacks create their own dialogs, so +initialized must be set to TRUE to avoid having a dialog +displayed twice. + +Related: +https://bugzilla.redhat.com/show_bug.cgi?id=1911224 + +Signed-off-by: Jakub Janků +--- + src/virt-viewer-app.c | 33 +++++++++++---------------------- + src/virt-viewer-session-vnc.c | 1 - + src/virt-viewer-session.c | 9 --------- + 3 files changed, 11 insertions(+), 32 deletions(-) + +diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c +index e42535b..2bb780f 100644 +--- a/src/virt-viewer-app.c ++++ b/src/virt-viewer-app.c +@@ -70,9 +70,6 @@ void virt_viewer_app_about_delete(GtkWidget *dialog, void *dummy, VirtViewerApp + /* Internal methods */ + static void virt_viewer_app_connected(VirtViewerSession *session, + VirtViewerApp *self); +-static void virt_viewer_app_error(VirtViewerSession *session G_GNUC_UNUSED, +- const gchar *msg, +- VirtViewerApp *self); + static void virt_viewer_app_initialized(VirtViewerSession *session, + VirtViewerApp *self); + static void virt_viewer_app_disconnected(VirtViewerSession *session, +@@ -745,7 +742,8 @@ static void hide_one_window(gpointer value, + { + VirtViewerApp* self = VIRT_VIEWER_APP(user_data); + VirtViewerAppPrivate *priv = self->priv; +- gboolean connect_error = !priv->connected && !priv->cancelled; ++ gboolean connect_error = !priv->cancelled && ++ !(VIRT_VIEWER_IS_SESSION_VNC(priv->session) ? priv->initialized : priv->connected); + + if (connect_error || self->priv->main_window != value) + virt_viewer_window_hide(VIRT_VIEWER_WINDOW(value)); +@@ -1342,8 +1340,6 @@ virt_viewer_app_create_session(VirtViewerApp *self, const gchar *type, GError ** + + g_signal_connect(priv->session, "session-initialized", + G_CALLBACK(virt_viewer_app_initialized), self); +- g_signal_connect(priv->session, "session-error", +- G_CALLBACK(virt_viewer_app_error), self); + g_signal_connect(priv->session, "session-connected", + G_CALLBACK(virt_viewer_app_connected), self); + g_signal_connect(priv->session, "session-disconnected", +@@ -1721,7 +1717,8 @@ virt_viewer_app_disconnected(VirtViewerSession *session G_GNUC_UNUSED, const gch + VirtViewerApp *self) + { + VirtViewerAppPrivate *priv = self->priv; +- gboolean connect_error = !priv->connected && !priv->cancelled; ++ gboolean connect_error = !priv->cancelled && ++ !(VIRT_VIEWER_IS_SESSION_VNC(session) ? priv->initialized : priv->connected); + + if (!priv->kiosk) + virt_viewer_app_hide_all_windows(self); +@@ -1744,21 +1741,6 @@ virt_viewer_app_disconnected(VirtViewerSession *session G_GNUC_UNUSED, const gch + virt_viewer_app_deactivate(self, connect_error); + } + +-static void +-virt_viewer_app_error(VirtViewerSession *session G_GNUC_UNUSED, +- const gchar *msg, +- VirtViewerApp *self) +-{ +- VirtViewerAppPrivate *priv = self->priv; +- +- /* Do not open a dialog if the connection was initialized +- * This happens when the VNC server closes the connection */ +- if (!priv->initialized) +- priv->connected = FALSE; /* display error dialog */ +- +- virt_viewer_app_disconnected(session, msg, self); +-} +- + static void virt_viewer_app_cancelled(VirtViewerSession *session, + VirtViewerApp *self) + { +@@ -1781,15 +1763,22 @@ static void virt_viewer_app_auth_refused(VirtViewerSession *session, + * VirtViewerApp needs to schedule a new connection to retry */ + priv->authretry = (!virt_viewer_session_can_retry_auth(session) && + !virt_viewer_session_get_file(session)); ++ ++ /* don't display another dialog in virt_viewer_app_disconnected when using VNC */ ++ priv->initialized = TRUE; + } + + static void virt_viewer_app_auth_unsupported(VirtViewerSession *session G_GNUC_UNUSED, + const char *msg, + VirtViewerApp *self) + { ++ VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self); + virt_viewer_app_simple_message_dialog(self, + _("Unable to authenticate with remote desktop server: %s"), + msg); ++ ++ /* don't display another dialog in virt_viewer_app_disconnected when using VNC */ ++ priv->initialized = TRUE; + } + + static void virt_viewer_app_usb_failed(VirtViewerSession *session G_GNUC_UNUSED, +diff --git a/src/virt-viewer-session-vnc.c b/src/virt-viewer-session-vnc.c +index 7d6dfb2..aa29d00 100644 +--- a/src/virt-viewer-session-vnc.c ++++ b/src/virt-viewer-session-vnc.c +@@ -136,7 +136,6 @@ virt_viewer_session_vnc_error(VncDisplay *vnc G_GNUC_UNUSED, + VirtViewerSessionVnc *session) + { + g_warning("vnc-session: got vnc error %s", msg); +- g_signal_emit_by_name(session, "session-error", msg); + /* "vnc-error" is always followed by "vnc-disconnected", + * so save the error for that signal */ + g_free(session->priv->error_msg); +diff --git a/src/virt-viewer-session.c b/src/virt-viewer-session.c +index 639d7a4..4171f3d 100644 +--- a/src/virt-viewer-session.c ++++ b/src/virt-viewer-session.c +@@ -276,15 +276,6 @@ virt_viewer_session_class_init(VirtViewerSessionClass *class) + G_TYPE_NONE, + 0); + +- g_signal_new("session-error", +- G_OBJECT_CLASS_TYPE(object_class), +- G_SIGNAL_RUN_FIRST, +- 0, +- NULL, NULL, +- g_cclosure_marshal_VOID__STRING, +- G_TYPE_NONE, +- 1, +- G_TYPE_STRING); + g_signal_new("session-disconnected", + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, +-- +2.29.2 + diff --git a/SOURCES/0025-vnc-session-use-g_signal_connect_object.patch b/SOURCES/0025-vnc-session-use-g_signal_connect_object.patch new file mode 100644 index 0000000..7043453 --- /dev/null +++ b/SOURCES/0025-vnc-session-use-g_signal_connect_object.patch @@ -0,0 +1,118 @@ +From 5a55d43796385c9d919ce4c8eb92c2e5e614937c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jakub=20Jank=C5=AF?= +Date: Wed, 3 Feb 2021 21:10:09 +0100 +Subject: [PATCH] vnc-session: use g_signal_connect_object +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the VncDisplay emits a signal and the VirtViewerSessionVnc +instance is no longer valid, using the pointer inside one of the +callbacks can lead to segfault. + +To prevent that, use g_signal_connect_object instead of +g_signal_connect. + +Related: +https://bugzilla.redhat.com/show_bug.cgi?id=1911224 + +Signed-off-by: Jakub Janků +--- + src/virt-viewer-session-vnc.c | 72 +++++++++++++++++------------------ + 1 file changed, 36 insertions(+), 36 deletions(-) + +diff --git a/src/virt-viewer-session-vnc.c b/src/virt-viewer-session-vnc.c +index aa29d00..5730e9d 100644 +--- a/src/virt-viewer-session-vnc.c ++++ b/src/virt-viewer-session-vnc.c +@@ -395,26 +395,26 @@ virt_viewer_session_vnc_close(VirtViewerSession* session) + self->priv->vnc = VNC_DISPLAY(vnc_display_new()); + g_object_ref_sink(self->priv->vnc); + +- g_signal_connect(self->priv->vnc, "vnc-connected", +- G_CALLBACK(virt_viewer_session_vnc_connected), session); +- g_signal_connect(self->priv->vnc, "vnc-initialized", +- G_CALLBACK(virt_viewer_session_vnc_initialized), session); +- g_signal_connect(self->priv->vnc, "vnc-disconnected", +- G_CALLBACK(virt_viewer_session_vnc_disconnected), session); +- g_signal_connect(self->priv->vnc, "vnc-error", +- G_CALLBACK(virt_viewer_session_vnc_error), session); ++ g_signal_connect_object(self->priv->vnc, "vnc-connected", ++ G_CALLBACK(virt_viewer_session_vnc_connected), session, 0); ++ g_signal_connect_object(self->priv->vnc, "vnc-initialized", ++ G_CALLBACK(virt_viewer_session_vnc_initialized), session, 0); ++ g_signal_connect_object(self->priv->vnc, "vnc-disconnected", ++ G_CALLBACK(virt_viewer_session_vnc_disconnected), session, 0); ++ g_signal_connect_object(self->priv->vnc, "vnc-error", ++ G_CALLBACK(virt_viewer_session_vnc_error), session, 0); + +- g_signal_connect(self->priv->vnc, "vnc-bell", +- G_CALLBACK(virt_viewer_session_vnc_bell), session); +- g_signal_connect(self->priv->vnc, "vnc-auth-failure", +- G_CALLBACK(virt_viewer_session_vnc_auth_failure), session); +- g_signal_connect(self->priv->vnc, "vnc-auth-unsupported", +- G_CALLBACK(virt_viewer_session_vnc_auth_unsupported), session); +- g_signal_connect(self->priv->vnc, "vnc-server-cut-text", +- G_CALLBACK(virt_viewer_session_vnc_cut_text), session); ++ g_signal_connect_object(self->priv->vnc, "vnc-bell", ++ G_CALLBACK(virt_viewer_session_vnc_bell), session, 0); ++ g_signal_connect_object(self->priv->vnc, "vnc-auth-failure", ++ G_CALLBACK(virt_viewer_session_vnc_auth_failure), session, 0); ++ g_signal_connect_object(self->priv->vnc, "vnc-auth-unsupported", ++ G_CALLBACK(virt_viewer_session_vnc_auth_unsupported), session, 0); ++ g_signal_connect_object(self->priv->vnc, "vnc-server-cut-text", ++ G_CALLBACK(virt_viewer_session_vnc_cut_text), session, 0); + +- g_signal_connect(self->priv->vnc, "vnc-auth-credential", +- G_CALLBACK(virt_viewer_session_vnc_auth_credential), session); ++ g_signal_connect_object(self->priv->vnc, "vnc-auth-credential", ++ G_CALLBACK(virt_viewer_session_vnc_auth_credential), session, 0); + + } + +@@ -432,24 +432,24 @@ virt_viewer_session_vnc_new(VirtViewerApp *app, GtkWindow *main_window) + +- g_signal_connect(session->priv->vnc, "vnc-connected", +- G_CALLBACK(virt_viewer_session_vnc_connected), session); +- g_signal_connect(session->priv->vnc, "vnc-initialized", +- G_CALLBACK(virt_viewer_session_vnc_initialized), session); +- g_signal_connect(session->priv->vnc, "vnc-disconnected", +- G_CALLBACK(virt_viewer_session_vnc_disconnected), session); +- g_signal_connect(session->priv->vnc, "vnc-error", +- G_CALLBACK(virt_viewer_session_vnc_error), session); ++ g_signal_connect_object(session->priv->vnc, "vnc-connected", ++ G_CALLBACK(virt_viewer_session_vnc_connected), session, 0); ++ g_signal_connect_object(session->priv->vnc, "vnc-initialized", ++ G_CALLBACK(virt_viewer_session_vnc_initialized), session, 0); ++ g_signal_connect_object(session->priv->vnc, "vnc-disconnected", ++ G_CALLBACK(virt_viewer_session_vnc_disconnected), session, 0); ++ g_signal_connect_object(session->priv->vnc, "vnc-error", ++ G_CALLBACK(virt_viewer_session_vnc_error), session, 0); + +- g_signal_connect(session->priv->vnc, "vnc-bell", +- G_CALLBACK(virt_viewer_session_vnc_bell), session); +- g_signal_connect(session->priv->vnc, "vnc-auth-failure", +- G_CALLBACK(virt_viewer_session_vnc_auth_failure), session); +- g_signal_connect(session->priv->vnc, "vnc-auth-unsupported", +- G_CALLBACK(virt_viewer_session_vnc_auth_unsupported), session); +- g_signal_connect(session->priv->vnc, "vnc-server-cut-text", +- G_CALLBACK(virt_viewer_session_vnc_cut_text), session); ++ g_signal_connect_object(session->priv->vnc, "vnc-bell", ++ G_CALLBACK(virt_viewer_session_vnc_bell), session, 0); ++ g_signal_connect_object(session->priv->vnc, "vnc-auth-failure", ++ G_CALLBACK(virt_viewer_session_vnc_auth_failure), session, 0); ++ g_signal_connect_object(session->priv->vnc, "vnc-auth-unsupported", ++ G_CALLBACK(virt_viewer_session_vnc_auth_unsupported), session, 0); ++ g_signal_connect_object(session->priv->vnc, "vnc-server-cut-text", ++ G_CALLBACK(virt_viewer_session_vnc_cut_text), session, 0); + +- g_signal_connect(session->priv->vnc, "vnc-auth-credential", +- G_CALLBACK(virt_viewer_session_vnc_auth_credential), session); ++ g_signal_connect_object(session->priv->vnc, "vnc-auth-credential", ++ G_CALLBACK(virt_viewer_session_vnc_auth_credential), session, 0); + + return VIRT_VIEWER_SESSION(session); + } +-- +2.29.2 + diff --git a/SOURCES/0026-build-fix-build-without-gtk-vnc.patch b/SOURCES/0026-build-fix-build-without-gtk-vnc.patch new file mode 100644 index 0000000..40cacc2 --- /dev/null +++ b/SOURCES/0026-build-fix-build-without-gtk-vnc.patch @@ -0,0 +1,54 @@ +From 81129f8eb11e86ccc9329b5a7cb4e319a4db7e04 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Mon, 8 Mar 2021 16:52:06 +0100 +Subject: [PATCH] build: fix build without gtk-vnc + +Without gtk-vnc we get implicit function declaration for +VIRT_VIEWER_IS_SESSION_VNC. Introduced at 8bc91ac "session: remove +"session-error" signal" in 2021-02-18 + +As we are already using #ifdef here, I've also changed the ternary to +an if for clarity. + +Signed-off-by: Victor Toso +--- + src/virt-viewer-app.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c +index 5d3b395..b20d11a 100644 +--- a/src/virt-viewer-app.c ++++ b/src/virt-viewer-app.c +@@ -748,8 +748,12 @@ static void hide_one_window(gpointer value, + { + VirtViewerApp* self = VIRT_VIEWER_APP(user_data); + VirtViewerAppPrivate *priv = self->priv; +- gboolean connect_error = !priv->cancelled && +- !(VIRT_VIEWER_IS_SESSION_VNC(priv->session) ? priv->initialized : priv->connected); ++ gboolean connect_error = !priv->cancelled && !priv->connected; ++#ifdef HAVE_GTK_VNC ++ if (VIRT_VIEWER_IS_SESSION_VNC(priv->session)) { ++ connect_error = !priv->cancelled && !priv->initialized; ++ } ++#endif + + if (connect_error || self->priv->main_window != value) + virt_viewer_window_hide(VIRT_VIEWER_WINDOW(value)); +@@ -1773,8 +1777,12 @@ virt_viewer_app_disconnected(VirtViewerSession *session G_GNUC_UNUSED, const gch + VirtViewerApp *self) + { + VirtViewerAppPrivate *priv = self->priv; +- gboolean connect_error = !priv->cancelled && +- !(VIRT_VIEWER_IS_SESSION_VNC(session) ? priv->initialized : priv->connected); ++ gboolean connect_error = !priv->cancelled && !priv->connected; ++#ifdef HAVE_GTK_VNC ++ if (VIRT_VIEWER_IS_SESSION_VNC(priv->session)) { ++ connect_error = !priv->cancelled && !priv->initialized; ++ } ++#endif + + if (!priv->kiosk) + virt_viewer_app_hide_all_windows(self); +-- +2.29.2 + diff --git a/SOURCES/0027-ovirt-foreign-menu-Support-changing-ISO-from-Data-St.patch b/SOURCES/0027-ovirt-foreign-menu-Support-changing-ISO-from-Data-St.patch new file mode 100644 index 0000000..3ccdb80 --- /dev/null +++ b/SOURCES/0027-ovirt-foreign-menu-Support-changing-ISO-from-Data-St.patch @@ -0,0 +1,440 @@ +From 0522f86a3e8420b1a2e32dbdf798d4667c91f036 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Wed, 1 Jul 2020 11:16:09 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Support changing ISO from + Data StorageDomain + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1835640 + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/glib-compat.c | 21 +++++ + src/glib-compat.h | 5 + + src/ovirt-foreign-menu.c | 104 +++++++++++++++------ + src/ovirt-foreign-menu.h | 3 + + src/remote-viewer-iso-list-dialog.c | 46 +++++---- + src/resources/ui/remote-viewer-iso-list.ui | 2 + + 6 files changed, 135 insertions(+), 46 deletions(-) + +diff --git a/src/glib-compat.c b/src/glib-compat.c +index 62ac87e..17122f6 100644 +--- a/src/glib-compat.c ++++ b/src/glib-compat.c +@@ -33,3 +33,24 @@ g_strv_contains (const gchar * const *strv, + return FALSE; + } + #endif ++ ++#if !GLIB_CHECK_VERSION(2,60,0) ++gboolean ++g_strv_equal (const gchar * const *strv1, ++ const gchar * const *strv2) ++{ ++ g_return_val_if_fail (strv1 != NULL, FALSE); ++ g_return_val_if_fail (strv2 != NULL, FALSE); ++ ++ if (strv1 == strv2) ++ return TRUE; ++ ++ for (; *strv1 != NULL && *strv2 != NULL; strv1++, strv2++) ++ { ++ if (!g_str_equal (*strv1, *strv2)) ++ return FALSE; ++ } ++ ++ return (*strv1 == NULL && *strv2 == NULL); ++} ++#endif +diff --git a/src/glib-compat.h b/src/glib-compat.h +index f1b43ae..a89ae04 100644 +--- a/src/glib-compat.h ++++ b/src/glib-compat.h +@@ -34,6 +34,11 @@ gboolean g_strv_contains (const gchar * const *strv, + const gchar *str); + #endif + ++#if !GLIB_CHECK_VERSION(2,60,0) ++gboolean g_strv_equal (const gchar * const *strv1, ++ const gchar * const *strv2); ++#endif ++ + G_END_DECLS + + #endif // GLIB_COMPAT_H +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index 8d02a79..a6745d3 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -77,9 +77,9 @@ struct _OvirtForeignMenuPrivate { + /* The next 2 members are used when changing the ISO image shown in + * a VM */ + /* Name of the ISO which is currently used by the VM OvirtCdrom */ +- char *current_iso_name; ++ GStrv current_iso_info; + /* Name of the ISO we are trying to insert in the VM OvirtCdrom */ +- char *next_iso_name; ++ GStrv next_iso_info; + + GList *iso_names; + }; +@@ -112,6 +112,40 @@ ovirt_foreign_menu_get_current_iso_name(OvirtForeignMenu *foreign_menu) + return name; + } + ++static GStrv ++iso_info_new(const gchar *name, const gchar *id) ++{ ++ GStrv info = g_new0(gchar *, 3); ++ info[0] = g_strdup(name); ++ info[1] = id != NULL ? g_strdup(id) : g_strdup(name); ++ return info; ++} ++ ++ ++GStrv ++ovirt_foreign_menu_get_current_iso_info(OvirtForeignMenu *menu) ++{ ++ if (menu->priv->cdrom == NULL) ++ return NULL; ++ ++ return menu->priv->current_iso_info; ++} ++ ++static void ++ovirt_foreign_menu_set_current_iso_info(OvirtForeignMenu *menu, const gchar *name, const gchar *id) ++{ ++ GStrv info = NULL; ++ ++ g_debug("Setting current ISO to: name '%s', id '%s'", name, id); ++ if (menu->priv->cdrom == NULL) ++ return; ++ ++ if (name != NULL) ++ info = iso_info_new(name, id); ++ ++ g_strfreev(menu->priv->current_iso_info); ++ menu->priv->current_iso_info = info; ++} + + GList* + ovirt_foreign_menu_get_iso_names(OvirtForeignMenu *foreign_menu) +@@ -211,8 +245,8 @@ ovirt_foreign_menu_dispose(GObject *obj) + self->priv->iso_names = NULL; + } + +- g_clear_pointer(&self->priv->current_iso_name, g_free); +- g_clear_pointer(&self->priv->next_iso_name, g_free); ++ g_clear_pointer(&self->priv->current_iso_info, g_strfreev); ++ g_clear_pointer(&self->priv->next_iso_info, g_strfreev); + + G_OBJECT_CLASS(ovirt_foreign_menu_parent_class)->dispose(obj); + } +@@ -402,21 +436,21 @@ static void iso_name_set_cb(GObject *source_object, + updated = ovirt_cdrom_update_finish(OVIRT_CDROM(source_object), + result, &error); + if (updated) { +- g_debug("Finished updating cdrom content: %s", foreign_menu->priv->next_iso_name); +- g_free(foreign_menu->priv->current_iso_name); +- foreign_menu->priv->current_iso_name = foreign_menu->priv->next_iso_name; +- foreign_menu->priv->next_iso_name = NULL; ++ g_debug("Finished updating cdrom content"); ++ g_strfreev(foreign_menu->priv->current_iso_info); ++ foreign_menu->priv->current_iso_info = foreign_menu->priv->next_iso_info; ++ foreign_menu->priv->next_iso_info = NULL; + g_task_return_boolean(task, TRUE); + goto end; + } + + /* Reset old state back as we were not successful in switching to + * the new ISO */ +- g_debug("setting OvirtCdrom:file back to '%s'", +- foreign_menu->priv->current_iso_name); ++ g_debug("setting OvirtCdrom:file back"); + g_object_set(foreign_menu->priv->cdrom, "file", +- foreign_menu->priv->current_iso_name, NULL); +- g_clear_pointer(&foreign_menu->priv->next_iso_name, g_free); ++ foreign_menu->priv->current_iso_info ? foreign_menu->priv->current_iso_info[1] : NULL, ++ NULL); ++ g_clear_pointer(&foreign_menu->priv->next_iso_info, g_strfreev); + + if (error != NULL) { + g_warning("failed to update cdrom resource: %s", error->message); +@@ -434,6 +468,7 @@ end: + + void ovirt_foreign_menu_set_current_iso_name_async(OvirtForeignMenu *foreign_menu, + const char *name, ++ const char *id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +@@ -441,18 +476,18 @@ void ovirt_foreign_menu_set_current_iso_name_async(OvirtForeignMenu *foreign_men + GTask *task; + + g_return_if_fail(foreign_menu->priv->cdrom != NULL); +- g_return_if_fail(foreign_menu->priv->next_iso_name == NULL); ++ g_return_if_fail(foreign_menu->priv->next_iso_info == NULL); + + if (name) { + g_debug("Updating VM cdrom image to '%s'", name); +- foreign_menu->priv->next_iso_name = g_strdup(name); ++ foreign_menu->priv->next_iso_info = iso_info_new(name, id); + } else { + g_debug("Removing current cdrom image"); +- foreign_menu->priv->next_iso_name = NULL; ++ foreign_menu->priv->next_iso_info = NULL; + } + + g_object_set(foreign_menu->priv->cdrom, +- "file", name, ++ "file", id, + NULL); + + task = g_task_new(foreign_menu, cancellable, callback, user_data); +@@ -477,10 +512,11 @@ static void ovirt_foreign_menu_set_files(OvirtForeignMenu *menu, + GList *sorted_files = NULL; + const GList *it; + GList *it2; ++ gchar *current_iso_name = ovirt_foreign_menu_get_current_iso_name(menu); + + for (it = files; it != NULL; it = it->next) { +- char *name; +- g_object_get(it->data, "name", &name, NULL); ++ char *name = NULL, *id = NULL; ++ g_object_get(it->data, "name", &name, "guid", &id, NULL); + + #ifdef HAVE_OVIRT_STORAGE_DOMAIN_GET_DISKS + if (OVIRT_IS_DISK(it->data)) { +@@ -488,7 +524,7 @@ static void ovirt_foreign_menu_set_files(OvirtForeignMenu *menu, + g_object_get(it->data, "content-type", &content_type, NULL); + if (content_type != OVIRT_DISK_CONTENT_TYPE_ISO) { + g_debug("Ignoring %s disk which content-type is not ISO", name); +- continue; ++ goto loop_end; + } + } + #endif +@@ -499,13 +535,27 @@ static void ovirt_foreign_menu_set_files(OvirtForeignMenu *menu, + * to differentiate between ISOs and floppy images */ + if (!g_str_has_suffix(name, ".iso")) { + g_debug("Ignoring %s which does not have a .iso extension", name); +- g_free(name); +- continue; ++ goto loop_end; + } +- sorted_files = g_list_insert_sorted(sorted_files, name, ++ ++ g_debug("Adding ISO to the list: name '%s', id '%s'", name, id); ++ sorted_files = g_list_insert_sorted(sorted_files, iso_info_new(name, id), + (GCompareFunc)g_strcmp0); ++ ++ /* Check if info matches with current cdrom file */ ++ if (current_iso_name != NULL && ++ (g_strcmp0(current_iso_name, name) == 0 || ++ g_strcmp0(current_iso_name, id) == 0)) { ++ ovirt_foreign_menu_set_current_iso_info(menu, name, id); ++ } ++ ++loop_end: ++ g_free(name); ++ g_free(id); + } + ++ g_free(current_iso_name); ++ + for (it = sorted_files, it2 = menu->priv->iso_names; + (it != NULL) && (it2 != NULL); + it = it->next, it2 = it2->next) { +@@ -516,11 +566,11 @@ static void ovirt_foreign_menu_set_files(OvirtForeignMenu *menu, + + if ((it == NULL) && (it2 == NULL)) { + /* sorted_files and menu->priv->files content was the same */ +- g_list_free_full(sorted_files, (GDestroyNotify)g_free); ++ g_list_free_full(sorted_files, (GDestroyNotify)g_strfreev); + return; + } + +- g_list_free_full(menu->priv->iso_names, (GDestroyNotify)g_free); ++ g_list_free_full(menu->priv->iso_names, (GDestroyNotify)g_strfreev); + menu->priv->iso_names = sorted_files; + } + +@@ -543,12 +593,6 @@ static void cdrom_file_refreshed_cb(GObject *source_object, + } + + /* Content of OvirtCdrom is now current */ +- g_clear_pointer(&menu->priv->current_iso_name, g_free); +- if (menu->priv->cdrom != NULL) { +- g_object_get(G_OBJECT(menu->priv->cdrom), +- "file", &menu->priv->current_iso_name, +- NULL); +- } + if (menu->priv->cdrom != NULL) { + ovirt_foreign_menu_next_async_step(menu, task, STATE_CDROM_FILE); + } else { +diff --git a/src/ovirt-foreign-menu.h b/src/ovirt-foreign-menu.h +index 340201f..6d2da77 100644 +--- a/src/ovirt-foreign-menu.h ++++ b/src/ovirt-foreign-menu.h +@@ -79,6 +79,7 @@ GList *ovirt_foreign_menu_fetch_iso_names_finish(OvirtForeignMenu *foreign_menu, + + void ovirt_foreign_menu_set_current_iso_name_async(OvirtForeignMenu *foreign_menu, + const char *name, ++ const char *id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +@@ -91,6 +92,8 @@ GtkWidget *ovirt_foreign_menu_get_gtk_menu(OvirtForeignMenu *foreign_menu); + gchar *ovirt_foreign_menu_get_current_iso_name(OvirtForeignMenu *menu); + GList *ovirt_foreign_menu_get_iso_names(OvirtForeignMenu *menu); + ++GStrv ovirt_foreign_menu_get_current_iso_info(OvirtForeignMenu *menu); ++ + G_END_DECLS + + #endif /* _OVIRT_FOREIGN_MENU_H */ +diff --git a/src/remote-viewer-iso-list-dialog.c b/src/remote-viewer-iso-list-dialog.c +index c6fbe50..fa10711 100644 +--- a/src/remote-viewer-iso-list-dialog.c ++++ b/src/remote-viewer-iso-list-dialog.c +@@ -53,6 +53,7 @@ enum RemoteViewerISOListDialogModel + ISO_IS_ACTIVE = 0, + ISO_NAME, + FONT_WEIGHT, ++ ISO_ID, + }; + + enum RemoteViewerISOListDialogProperties { +@@ -119,18 +120,23 @@ remote_viewer_iso_list_dialog_show_files(RemoteViewerISOListDialog *self) + } + + static void +-remote_viewer_iso_list_dialog_foreach(char *name, RemoteViewerISOListDialog *self) ++remote_viewer_iso_list_dialog_foreach(GStrv info, RemoteViewerISOListDialog *self) + { +- gchar *current_iso = ovirt_foreign_menu_get_current_iso_name(self->foreign_menu); +- gboolean active = (g_strcmp0(current_iso, name) == 0); ++ GStrv current_iso = ovirt_foreign_menu_get_current_iso_info(self->foreign_menu); ++G_GNUC_BEGIN_IGNORE_DEPRECATIONS ++ gboolean active = (g_strv_equal((const gchar * const *) current_iso, ++ (const gchar * const *) info) == TRUE); ++G_GNUC_END_IGNORE_DEPRECATIONS + gint weight = active ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL; + GtkTreeIter iter; + + gtk_list_store_append(self->list_store, &iter); + gtk_list_store_set(self->list_store, &iter, + ISO_IS_ACTIVE, active, +- ISO_NAME, name, +- FONT_WEIGHT, weight, -1); ++ ISO_NAME, info[0], ++ FONT_WEIGHT, weight, ++ ISO_ID, info[1], ++ -1); + + if (active) { + GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(self->list_store), &iter); +@@ -138,8 +144,6 @@ remote_viewer_iso_list_dialog_foreach(char *name, RemoteViewerISOListDialog *sel + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(self->tree_view), path, NULL, TRUE, 0.5, 0.5); + gtk_tree_path_free(path); + } +- +- g_free(current_iso); + } + + static void +@@ -219,24 +223,29 @@ remote_viewer_iso_list_dialog_toggled(GtkCellRendererToggle *cell_renderer G_GNU + GtkTreePath *tree_path = gtk_tree_path_new_from_string(path); + GtkTreeIter iter; + gboolean active; +- gchar *name; ++ gchar *name, *id; + + gtk_tree_view_set_cursor(GTK_TREE_VIEW(self->tree_view), tree_path, NULL, FALSE); + gtk_tree_model_get_iter(model, &iter, tree_path); + gtk_tree_model_get(model, &iter, + ISO_IS_ACTIVE, &active, +- ISO_NAME, &name, -1); ++ ISO_NAME, &name, ++ ISO_ID, &id, ++ -1); + + gtk_dialog_set_response_sensitive(GTK_DIALOG(self), GTK_RESPONSE_NONE, FALSE); + gtk_widget_set_sensitive(self->tree_view, FALSE); + + self->cancellable = g_cancellable_new(); +- ovirt_foreign_menu_set_current_iso_name_async(self->foreign_menu, active ? NULL : name, ++ ovirt_foreign_menu_set_current_iso_name_async(self->foreign_menu, ++ active ? NULL : name, ++ active ? NULL : id, + self->cancellable, + (GAsyncReadyCallback)ovirt_foreign_menu_iso_name_changed, + self); + gtk_tree_path_free(tree_path); + g_free(name); ++ g_free(id); + } + + G_MODULE_EXPORT void +@@ -305,9 +314,9 @@ ovirt_foreign_menu_iso_name_changed(OvirtForeignMenu *foreign_menu, + RemoteViewerISOListDialog *self) + { + GtkTreeModel *model = GTK_TREE_MODEL(self->list_store); +- gchar *current_iso; ++ GStrv current_iso; + GtkTreeIter iter; +- gchar *name; ++ gchar *name, *id; + gboolean active, match = FALSE; + GError *error = NULL; + +@@ -328,13 +337,18 @@ ovirt_foreign_menu_iso_name_changed(OvirtForeignMenu *foreign_menu, + if (!gtk_tree_model_get_iter_first(model, &iter)) + goto end; + +- current_iso = ovirt_foreign_menu_get_current_iso_name(foreign_menu); ++ current_iso = ovirt_foreign_menu_get_current_iso_info(foreign_menu); + + do { + gtk_tree_model_get(model, &iter, + ISO_IS_ACTIVE, &active, +- ISO_NAME, &name, -1); +- match = (g_strcmp0(current_iso, name) == 0); ++ ISO_NAME, &name, ++ ISO_ID, &id, ++ -1); ++ ++ if (current_iso) ++ match = (g_strcmp0(current_iso[0], name) == 0 && ++ g_strcmp0(current_iso[1], id) == 0); + + /* iso is not active anymore */ + if (active && !match) { +@@ -348,11 +362,11 @@ ovirt_foreign_menu_iso_name_changed(OvirtForeignMenu *foreign_menu, + } + + g_free(name); ++ g_free(id); + } while (gtk_tree_model_iter_next(model, &iter)); + + gtk_dialog_set_response_sensitive(GTK_DIALOG(self), GTK_RESPONSE_NONE, TRUE); + gtk_widget_set_sensitive(self->tree_view, TRUE); +- g_free(current_iso); + + end: + g_clear_error(&error); +diff --git a/src/resources/ui/remote-viewer-iso-list.ui b/src/resources/ui/remote-viewer-iso-list.ui +index ab1bdc4..96fabef 100644 +--- a/src/resources/ui/remote-viewer-iso-list.ui ++++ b/src/resources/ui/remote-viewer-iso-list.ui +@@ -10,6 +10,8 @@ + + + ++ ++ + + + +-- +2.31.1 + diff --git a/SPECS/virt-viewer.spec b/SPECS/virt-viewer.spec index 745749e..f38a67b 100644 --- a/SPECS/virt-viewer.spec +++ b/SPECS/virt-viewer.spec @@ -19,7 +19,7 @@ Name: virt-viewer Version: 9.0 -Release: 9%{?dist}%{?extra_release} +Release: 11%{?dist}%{?extra_release} Summary: Virtual Machine Viewer Group: Applications/System License: GPLv2+ @@ -65,6 +65,16 @@ Patch020: 0020-zoom-hotkeys-disable-numpad-when-users-set-new-hotke.patch # rhbz#1893584 Patch021: 0021-disable-default-grab-sequence-in-kiosk-mode.patch +# Patch022 is defined earlier + +# rhbz#1911224 and rhbz#1926691 +# Patches slightly modified so they apply +Patch023: 0023-vnc-session-save-message-from-vnc-error-for-vnc-disc.patch +Patch024: 0024-session-remove-session-error-signal.patch +Patch025: 0025-vnc-session-use-g_signal_connect_object.patch +Patch026: 0026-build-fix-build-without-gtk-vnc.patch +Patch027: 0027-ovirt-foreign-menu-Support-changing-ISO-from-Data-St.patch + Requires: openssh-clients Requires(post): %{_sbindir}/update-alternatives Requires(postun): %{_sbindir}/update-alternatives @@ -136,6 +146,12 @@ the display, and libvirt for looking up VNC/SPICE server details. %patch021 -p1 %patch022 -p1 +%patch023 -p1 +%patch024 -p1 +%patch025 -p1 +%patch026 -p1 +%patch027 -p1 + %build %if 0%{?enable_autotools} @@ -174,6 +190,15 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man1/remote-viewer.1* %changelog +* Thu Aug 26 2021 Eduardo Lima (Etrunko) - 9.0.11 +- Add support for changing ISO fom Data StorageDomain + Resolves: rhbz#1835640 + +* Wed Mar 10 2021 Uri Lublin - 9.0-10 +- VNC: errors handling improvements + Resolves: rhbz#1911224 + Resolves: rhbz#1926691 + * Thu Jan 21 2021 Uri Lublin - 9.0-9 - Show an error dialog upon vnc-error only if session was initialized Resolves: rhbz#1448151