diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e9fc099 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/virt-viewer-9.0.tar.gz diff --git a/0001-DOWNSTREAM-Workaround-inconsistency-with-REST-API.patch b/0001-DOWNSTREAM-Workaround-inconsistency-with-REST-API.patch new file mode 100644 index 0000000..a564b72 --- /dev/null +++ b/0001-DOWNSTREAM-Workaround-inconsistency-with-REST-API.patch @@ -0,0 +1,80 @@ +From 182fb30ff7cd85873d479b214bebf291aed2eaf1 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 23 Aug 2019 11:30:32 -0300 +Subject: [PATCH virt-viewer] [DOWNSTREAM] Workaround inconsistency with REST + API + +The storage domain object returned in this stage does not provide a link +to the files subcollection. To workaround this problem, we use the id of +the given storage domain to create a new object but referencing the +toplevel api, which in turn provides the file collection. + +This is meant to be a donwnstream patch only, while this issue is not +addressed by RHV. + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1717900 + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 38 ++++++++++++++++++++++++++++++++++++-- + 1 file changed, 36 insertions(+), 2 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index 98ab7b9..a849991 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -686,6 +686,37 @@ static gboolean ovirt_foreign_menu_set_file_collection(OvirtForeignMenu *menu, O + return TRUE; + } + ++static gboolean set_file_collection_from_toplevel_storage_domain(OvirtForeignMenu *menu, OvirtStorageDomain *domain) ++{ ++ gboolean ret = FALSE; ++ GError *error = NULL; ++ OvirtResource *resource = NULL; ++ gchar *href = NULL, *id = NULL; ++ ++ g_object_get(domain, "guid", &id, NULL); ++ href = g_strdup_printf("/ovirt-engine/api/storagedomains/%s", id); ++ resource = g_initable_new(OVIRT_TYPE_STORAGE_DOMAIN, NULL, &error, "guid", id, "href", href, NULL); ++ if (error != NULL) { ++ g_warning("Failed to create storage domain with href %s: %s", href, error->message); ++ goto end; ++ } ++ ++ ovirt_resource_refresh(resource, menu->priv->proxy, &error); ++ if (error != NULL) { ++ g_warning("Failed to refresh storage domain: %s", error->message); ++ goto end; ++ } ++ ++ ret = ovirt_foreign_menu_set_file_collection(menu, ovirt_storage_domain_get_files(OVIRT_STORAGE_DOMAIN(resource))); ++ ++end: ++ g_clear_error(&error); ++ g_clear_object(&resource); ++ g_free(id); ++ g_free(href); ++ return ret; ++} ++ + static void storage_domains_fetched_cb(GObject *source_object, + GAsyncResult *result, + gpointer user_data) +@@ -717,8 +748,11 @@ static void storage_domains_fetched_cb(GObject *source_object, + domain_valid = TRUE; + + file_collection = ovirt_storage_domain_get_files(domain); +- if (!ovirt_foreign_menu_set_file_collection(menu, file_collection)) +- continue; ++ if (!ovirt_foreign_menu_set_file_collection(menu, file_collection)) { ++ /* Retry with toplevel storage domain */ ++ if (!set_file_collection_from_toplevel_storage_domain(menu, domain)) ++ continue; ++ } + + break; /* There can only be one valid storage domain at a time, + no need to iterate more on the list */ +-- +2.26.2 + diff --git a/0002-DOWNSTREAM-ovirt-foreign-menu-Bypass-errors-from-Hos.patch b/0002-DOWNSTREAM-ovirt-foreign-menu-Bypass-errors-from-Hos.patch new file mode 100644 index 0000000..afc0104 --- /dev/null +++ b/0002-DOWNSTREAM-ovirt-foreign-menu-Bypass-errors-from-Hos.patch @@ -0,0 +1,146 @@ +From d8dc636c63a3616a938c600487e473a71c67cf96 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 6 Jul 2018 09:12:18 -0300 +Subject: [PATCH virt-viewer] [DOWNSTREAM] ovirt-foreign-menu: Bypass errors + from Host/Cluster/Data Center + +When accessing ovirt as a regular user, it may happen that queries to +Hosts, Clusters and Data Centers return errors due to insufficient +permissions, while they will work fine if access is done by admin user. +In this case, we skip the errors and fallback to the old method. + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 60 ++++++++++++++++++++++++++++++---------- + 1 file changed, 46 insertions(+), 14 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index a849991..dc6ecf4 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -627,12 +627,21 @@ G_GNUC_END_IGNORE_DEPRECATIONS + } + + static gboolean storage_domain_attached_to_data_center(OvirtStorageDomain *domain, +- OvirtDataCenter *data_center) ++ OvirtDataCenter *data_center) + { + GStrv data_center_ids; + char *data_center_guid; + gboolean match; + ++ /* For some reason we did not get data center information, so just return ++ * TRUE as it will work like a fallback to old method, where we did not ++ * check relationship between data center and storage domain. ++ */ ++ if (data_center == NULL) { ++ g_debug("Could not get data center info, considering storage domain is attached to it"); ++ return TRUE; ++ } ++ + g_object_get(domain, "data-center-ids", &data_center_ids, NULL); + g_object_get(data_center, "guid", &data_center_guid, NULL); + match = strv_contains((const gchar * const *) data_center_ids, data_center_guid); +@@ -779,9 +788,11 @@ static void ovirt_foreign_menu_fetch_storage_domain_async(OvirtForeignMenu *menu + #ifdef HAVE_OVIRT_DATA_CENTER + g_return_if_fail(OVIRT_IS_FOREIGN_MENU(menu)); + g_return_if_fail(OVIRT_IS_PROXY(menu->priv->proxy)); +- g_return_if_fail(OVIRT_IS_DATA_CENTER(menu->priv->data_center)); + +- collection = ovirt_data_center_get_storage_domains(menu->priv->data_center); ++ if (menu->priv->data_center != NULL) ++ collection = ovirt_data_center_get_storage_domains(menu->priv->data_center); ++ else ++ collection = ovirt_api_get_storage_domains(menu->priv->api); + #else + collection = ovirt_api_get_storage_domains(menu->priv->api); + #endif +@@ -806,9 +817,7 @@ static void data_center_fetched_cb(GObject *source_object, + ovirt_resource_refresh_finish(resource, result, &error); + if (error != NULL) { + g_debug("failed to fetch Data Center: %s", error->message); +- g_task_return_error(task, error); +- g_object_unref(task); +- return; ++ g_clear_error(&error); + } + + ovirt_foreign_menu_next_async_step(menu, task, STATE_DATA_CENTER); +@@ -823,6 +832,12 @@ static void ovirt_foreign_menu_fetch_data_center_async(OvirtForeignMenu *menu, + g_return_if_fail(OVIRT_IS_CLUSTER(menu->priv->cluster)); + + menu->priv->data_center = ovirt_cluster_get_data_center(menu->priv->cluster); ++ ++ if (menu->priv->data_center == NULL) { ++ ovirt_foreign_menu_next_async_step(menu, task, STATE_DATA_CENTER); ++ return; ++ } ++ + ovirt_resource_refresh_async(OVIRT_RESOURCE(menu->priv->data_center), + menu->priv->proxy, + g_task_get_cancellable(task), +@@ -843,9 +858,7 @@ static void cluster_fetched_cb(GObject *source_object, + ovirt_resource_refresh_finish(resource, result, &error); + if (error != NULL) { + g_debug("failed to fetch Cluster: %s", error->message); +- g_task_return_error(task, error); +- g_object_unref(task); +- return; ++ g_clear_error(&error); + } + + ovirt_foreign_menu_next_async_step(menu, task, STATE_CLUSTER); +@@ -857,9 +870,21 @@ static void ovirt_foreign_menu_fetch_cluster_async(OvirtForeignMenu *menu, + { + g_return_if_fail(OVIRT_IS_FOREIGN_MENU(menu)); + g_return_if_fail(OVIRT_IS_PROXY(menu->priv->proxy)); +- g_return_if_fail(OVIRT_IS_HOST(menu->priv->host)); + +- menu->priv->cluster = ovirt_host_get_cluster(menu->priv->host); ++ /* If there is no host information, we get cluster from the VM */ ++ if (menu->priv->host == NULL) { ++ g_return_if_fail(OVIRT_IS_VM(menu->priv->vm)); ++ menu->priv->cluster = ovirt_vm_get_cluster(menu->priv->vm); ++ } else { ++ g_return_if_fail(OVIRT_IS_HOST(menu->priv->host)); ++ menu->priv->cluster = ovirt_host_get_cluster(menu->priv->host); ++ } ++ ++ if (menu->priv->cluster == NULL) { ++ ovirt_foreign_menu_next_async_step(menu, task, STATE_CLUSTER); ++ return; ++ } ++ + ovirt_resource_refresh_async(OVIRT_RESOURCE(menu->priv->cluster), + menu->priv->proxy, + g_task_get_cancellable(task), +@@ -880,9 +905,7 @@ static void host_fetched_cb(GObject *source_object, + ovirt_resource_refresh_finish(resource, result, &error); + if (error != NULL) { + g_debug("failed to fetch Host: %s", error->message); +- g_task_return_error(task, error); +- g_object_unref(task); +- return; ++ g_clear_error(&error); + } + + ovirt_foreign_menu_next_async_step(menu, task, STATE_HOST); +@@ -897,6 +920,15 @@ static void ovirt_foreign_menu_fetch_host_async(OvirtForeignMenu *menu, + g_return_if_fail(OVIRT_IS_VM(menu->priv->vm)); + + menu->priv->host = ovirt_vm_get_host(menu->priv->vm); ++ ++ /* In some cases the VM XML does not include host information, so we just ++ * skip to the next step ++ */ ++ if (menu->priv->host == NULL) { ++ ovirt_foreign_menu_next_async_step(menu, task, STATE_HOST); ++ return; ++ } ++ + ovirt_resource_refresh_async(OVIRT_RESOURCE(menu->priv->host), + menu->priv->proxy, + g_task_get_cancellable(task), +-- +2.26.2 + diff --git a/0003-DOWNSTREAM-remote-viewer-Set-admin-privileges-when-c.patch b/0003-DOWNSTREAM-remote-viewer-Set-admin-privileges-when-c.patch new file mode 100644 index 0000000..9d07748 --- /dev/null +++ b/0003-DOWNSTREAM-remote-viewer-Set-admin-privileges-when-c.patch @@ -0,0 +1,34 @@ +From f06747e69cdade6c2774462a208535de890978c1 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Mon, 26 Aug 2019 10:18:20 -0300 +Subject: [PATCH virt-viewer] [DOWNSTREAM] remote-viewer: Set admin privileges + when connecting to ovirt + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/remote-viewer.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/remote-viewer.c b/src/remote-viewer.c +index 2450096..9e63bfb 100644 +--- a/src/remote-viewer.c ++++ b/src/remote-viewer.c +@@ -340,6 +340,7 @@ authenticate_cb(RestProxy *proxy, G_GNUC_UNUSED RestProxyAuth *auth, + g_object_set(G_OBJECT(proxy), + "username", username, + "password", password, ++ "admin", g_str_has_prefix(username, "admin"), + NULL); + } else { + rest_proxy_auth_cancel(auth); +@@ -433,6 +434,7 @@ create_ovirt_session(VirtViewerApp *app, const char *uri, GError **err) + proxy = ovirt_proxy_new(rest_uri); + g_object_set(proxy, + "username", username, ++ "admin", g_str_has_prefix(username, "admin"), + NULL); + ovirt_set_proxy_options(proxy); + g_signal_connect(G_OBJECT(proxy), "authenticate", +-- +2.26.2 + diff --git a/0004-ovirt-Do-not-filter-out-DATA-storage-domains.patch b/0004-ovirt-Do-not-filter-out-DATA-storage-domains.patch new file mode 100644 index 0000000..285715a --- /dev/null +++ b/0004-ovirt-Do-not-filter-out-DATA-storage-domains.patch @@ -0,0 +1,38 @@ +From 21b482e6b85df7dca46e1dc8501b0f28ce4570a1 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 15 May 2020 10:24:08 -0300 +Subject: [PATCH virt-viewer] ovirt: Do not filter out DATA storage domains + +Since ovirt 4.2 it is acceptable to have ISO images in storage domains +of DATA type, while the usage of ISO type is about to be deprecated. The +code now allow both types of storage domains when looking up for ISO +images. + +https://access.redhat.com/documentation/en-us/red_hat_virtualization/4.2/html/release_notes/deprecated_features_rhv +https://access.redhat.com/documentation/en-us/red_hat_virtualization/4.4-beta/html/release_notes/deprecated_features_rhv + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1835640 + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index dc6ecf4..c31c93f 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -661,8 +661,8 @@ static gboolean storage_domain_validate(OvirtForeignMenu *menu G_GNUC_UNUSED, + + g_object_get(domain, "name", &name, "type", &type, "state", &state, NULL); + +- if (type != OVIRT_STORAGE_DOMAIN_TYPE_ISO) { +- g_debug("Storage domain '%s' type is not ISO", name); ++ if (type != OVIRT_STORAGE_DOMAIN_TYPE_ISO && type != OVIRT_STORAGE_DOMAIN_TYPE_DATA) { ++ g_debug("Storage domain '%s' type is not ISO or DATA", name); + ret = FALSE; + } + +-- +2.26.2 + diff --git a/0005-display-error-message-on-no-extension-for-screenshot.patch b/0005-display-error-message-on-no-extension-for-screenshot.patch new file mode 100644 index 0000000..a7d36e7 --- /dev/null +++ b/0005-display-error-message-on-no-extension-for-screenshot.patch @@ -0,0 +1,53 @@ +From c6afc28cc9761af3e992eab0ca105a978b83a346 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Julien=20Rop=C3=A9?= +Date: Tue, 9 Jun 2020 14:44:39 +0200 +Subject: [PATCH remote-viewer] Rather than adding a default extension to + screenshots, display an error message to make the user add it. This prevents + the silent overwriting of the file, and still makes sure the user knows why + we don't proceed. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix BZ#1752514 + +Signed-off-by: Julien Ropé +--- + src/virt-viewer-window.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c +index 928658f..7ecee21 100644 +--- a/src/virt-viewer-window.c ++++ b/src/virt-viewer-window.c +@@ -1085,17 +1085,22 @@ virt_viewer_window_menu_file_screenshot(GtkWidget *menu G_GNUC_UNUSED, + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (dialog), image_dir); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER (dialog), _("Screenshot.png")); + ++retry_dialog: + if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { + char *filename; + GError *error = NULL; + + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog)); + if (g_strrstr(filename, ".") == NULL) { +- // no extension provided: add the .png default +- char *tmp_filename ; +- tmp_filename = g_strdup_printf("%s.png", filename) ; +- g_free(filename) ; +- filename = tmp_filename ; ++ // no extension provided ++ GtkWidget *msg_dialog ; ++ g_free(filename); ++ msg_dialog = gtk_message_dialog_new (GTK_WINDOW(dialog), GTK_DIALOG_MODAL, ++ GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, ++ _("Please add an extension to the file name")); ++ gtk_dialog_run(GTK_DIALOG(msg_dialog)); ++ gtk_widget_destroy(msg_dialog); ++ goto retry_dialog; + } + + if (!virt_viewer_window_save_screenshot(self, filename, &error)) { +-- +2.26.2 + diff --git a/0006-ovirt-foreign-menu-Use-proper-function-in-the-case-o.patch b/0006-ovirt-foreign-menu-Use-proper-function-in-the-case-o.patch new file mode 100644 index 0000000..4fce592 --- /dev/null +++ b/0006-ovirt-foreign-menu-Use-proper-function-in-the-case-o.patch @@ -0,0 +1,103 @@ +From 0a16fd513034c2a1475ed84b38461faea7a12250 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Thu, 25 Jun 2020 21:19:32 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Use proper function in the + case of DATA StorageDomains + +Unlike the StorageDomain objects of ISO type, the DATA ones require a +specific API recently added to libgovirt to support them. This commit +makes use of those new functions under #ifdef guards and adds proper a +check to configure.ac. + +Related: https://bugzilla.redhat.com/show_bug.cgi?id=1847223 + +Signed-off-by: Eduardo Lima (Etrunko) +--- + configure.ac | 2 +- + src/ovirt-foreign-menu.c | 36 ++++++++++++++++++++++++++++++++++-- + 2 files changed, 35 insertions(+), 3 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 9da056f..a313ce1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -203,7 +203,7 @@ AS_IF([test "x$with_ovirt" = "xyes"], + SAVED_LIBS="$LIBS" + CFLAGS="$SAVED_CFLAGS $OVIRT_CFLAGS" + LIBS="$SAVED_LIBS $OVIRT_LIBS" +- AC_CHECK_FUNCS([ovirt_api_search_vms ovirt_vm_get_host ovirt_host_get_cluster ovirt_cluster_get_data_center], ++ AC_CHECK_FUNCS([ovirt_api_search_vms ovirt_vm_get_host ovirt_host_get_cluster ovirt_cluster_get_data_center ovirt_storage_domain_get_disks], + [AC_DEFINE([HAVE_OVIRT_DATA_CENTER], 1, [Have support for data center])], + [] + ) +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index c31c93f..3c67f1a 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -481,6 +481,18 @@ static void ovirt_foreign_menu_set_files(OvirtForeignMenu *menu, + for (it = files; it != NULL; it = it->next) { + char *name; + g_object_get(it->data, "name", &name, NULL); ++ ++#ifdef HAVE_OVIRT_STORAGE_DOMAIN_GET_DISKS ++ if (OVIRT_IS_DISK(it->data)) { ++ OvirtDiskContentType content_type; ++ 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; ++ } ++ } ++#endif ++ + /* The oVirt REST API is supposed to have a 'type' node + * associated with file resources , but as of 3.2, this node + * is not present, so we do an extension check instead +@@ -695,6 +707,26 @@ static gboolean ovirt_foreign_menu_set_file_collection(OvirtForeignMenu *menu, O + return TRUE; + } + ++static OvirtCollection *storage_domain_get_files(OvirtStorageDomain *domain) ++{ ++ OvirtCollection *files = NULL; ++ OvirtStorageDomainType type; ++ ++ if (domain == NULL) ++ return NULL; ++ ++ g_object_get(domain, "type", &type, NULL); ++ ++ if (type == OVIRT_STORAGE_DOMAIN_TYPE_ISO) ++ files = ovirt_storage_domain_get_files(domain); ++#ifdef HAVE_OVIRT_STORAGE_DOMAIN_GET_DISKS ++ else if (type == OVIRT_STORAGE_DOMAIN_TYPE_DATA) ++ files = ovirt_storage_domain_get_disks(domain); ++#endif ++ ++ return files; ++} ++ + static gboolean set_file_collection_from_toplevel_storage_domain(OvirtForeignMenu *menu, OvirtStorageDomain *domain) + { + gboolean ret = FALSE; +@@ -716,7 +748,7 @@ static gboolean set_file_collection_from_toplevel_storage_domain(OvirtForeignMen + goto end; + } + +- ret = ovirt_foreign_menu_set_file_collection(menu, ovirt_storage_domain_get_files(OVIRT_STORAGE_DOMAIN(resource))); ++ ret = ovirt_foreign_menu_set_file_collection(menu, storage_domain_get_files(OVIRT_STORAGE_DOMAIN(resource))); + + end: + g_clear_error(&error); +@@ -756,7 +788,7 @@ static void storage_domains_fetched_cb(GObject *source_object, + if (!domain_valid) + domain_valid = TRUE; + +- file_collection = ovirt_storage_domain_get_files(domain); ++ file_collection = storage_domain_get_files(domain); + if (!ovirt_foreign_menu_set_file_collection(menu, file_collection)) { + /* Retry with toplevel storage domain */ + if (!set_file_collection_from_toplevel_storage_domain(menu, domain)) +-- +2.26.2 + diff --git a/0007-ovirt-foreign-menu-Take-into-account-StorageDomains-.patch b/0007-ovirt-foreign-menu-Take-into-account-StorageDomains-.patch new file mode 100644 index 0000000..402744f --- /dev/null +++ b/0007-ovirt-foreign-menu-Take-into-account-StorageDomains-.patch @@ -0,0 +1,99 @@ +From f5936a87795dfdefee10f87672abcf8f9175a7c9 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Mon, 15 Jun 2020 20:53:18 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Take into account + StorageDomains of type DATA + +Now that we support both ISO and DATA storage domain types, we need to +make sure that the files are listed correctly. In this case we give the +domains of ISO type the precedence over DATA ones. + +This change extends previous commit bbda3aa which made it possible for +storage domains of type DATA to be considered valid. + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 39 ++++++++++++++++++++++----------------- + 1 file changed, 22 insertions(+), 17 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index 3c67f1a..8d02a79 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -734,6 +734,9 @@ static gboolean set_file_collection_from_toplevel_storage_domain(OvirtForeignMen + OvirtResource *resource = NULL; + gchar *href = NULL, *id = NULL; + ++ if (domain == NULL) ++ return FALSE; ++ + g_object_get(domain, "guid", &id, NULL); + href = g_strdup_printf("/ovirt-engine/api/storagedomains/%s", id); + resource = g_initable_new(OVIRT_TYPE_STORAGE_DOMAIN, NULL, &error, "guid", id, "href", href, NULL); +@@ -767,8 +770,8 @@ static void storage_domains_fetched_cb(GObject *source_object, + OvirtForeignMenu *menu = OVIRT_FOREIGN_MENU(g_task_get_source_object(task)); + OvirtCollection *collection = OVIRT_COLLECTION(source_object); + GHashTableIter iter; +- OvirtStorageDomain *domain; +- gboolean domain_valid = FALSE; ++ OvirtStorageDomain *domain, *valid_domain = NULL; ++ OvirtCollection *file_collection; + + ovirt_collection_fetch_finish(collection, result, &error); + if (error != NULL) { +@@ -780,35 +783,37 @@ static void storage_domains_fetched_cb(GObject *source_object, + + g_hash_table_iter_init(&iter, ovirt_collection_get_resources(collection)); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&domain)) { +- OvirtCollection *file_collection; +- + if (!storage_domain_validate(menu, domain)) + continue; + +- if (!domain_valid) +- domain_valid = TRUE; ++ /* Storage domain of type ISO has precedence over type DATA */ ++ if (valid_domain != NULL) { ++ OvirtStorageDomainType domain_type, valid_type; ++ g_object_get(domain, "type", &domain_type, NULL); ++ g_object_get(valid_domain, "type", &valid_type, NULL); + +- file_collection = storage_domain_get_files(domain); +- if (!ovirt_foreign_menu_set_file_collection(menu, file_collection)) { +- /* Retry with toplevel storage domain */ +- if (!set_file_collection_from_toplevel_storage_domain(menu, domain)) +- continue; ++ if (domain_type > valid_type) ++ valid_domain = domain; ++ ++ continue; + } + +- break; /* There can only be one valid storage domain at a time, +- no need to iterate more on the list */ ++ valid_domain = domain; + } + +- if (menu->priv->files != NULL) { +- ovirt_foreign_menu_next_async_step(menu, task, STATE_STORAGE_DOMAIN); +- } else { +- const char *msg = domain_valid ? "Could not find ISO file collection" ++ file_collection = storage_domain_get_files(valid_domain); ++ if (!ovirt_foreign_menu_set_file_collection(menu, file_collection) && ++ !set_file_collection_from_toplevel_storage_domain(menu, valid_domain)) { /* Retry with toplevel storage domain */ ++ const char *msg = valid_domain ? "Could not find ISO file collection" + : "Could not find valid ISO storage domain"; + + g_debug("%s", msg); + g_task_return_new_error(task, OVIRT_ERROR, OVIRT_ERROR_FAILED, "%s", msg); + g_object_unref(task); ++ return; + } ++ ++ ovirt_foreign_menu_next_async_step(menu, task, STATE_STORAGE_DOMAIN); + } + + +-- +2.26.2 + diff --git a/0008-More-specific-key-accelerator-description.patch b/0008-More-specific-key-accelerator-description.patch new file mode 100644 index 0000000..1189e8d --- /dev/null +++ b/0008-More-specific-key-accelerator-description.patch @@ -0,0 +1,32 @@ +From ae25f6ca6b46e95281186492de5bc0a0fe4974a6 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 10 Jul 2020 10:58:35 +0100 +Subject: [PATCH] More specific key accelerator description + +The default key accelerator to release mouse if left control and +left alt but the current description is "Ctrl+Alt", change to +"Ctrl_L+Alt_L" to avoid misunderstanding. + +This solves https://bugzilla.redhat.com/show_bug.cgi?id=1548371 + +Signed-off-by: Frediano Ziglio +--- + src/virt-viewer-window.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c +index 6c9bc41..614120f 100644 +--- a/src/virt-viewer-window.c ++++ b/src/virt-viewer-window.c +@@ -1395,7 +1395,7 @@ virt_viewer_window_update_title(VirtViewerWindow *self) + g_debug("release-cursor accel key: key=%u, mods=%x, flags=%u", key.accel_key, key.accel_mods, key.accel_flags); + label = gtk_accelerator_get_label(key.accel_key, key.accel_mods); + } else { +- label = g_strdup(_("Ctrl+Alt")); ++ label = g_strdup(_("Ctrl_L+Alt_L")); + } + + ungrab = g_strdup_printf(_("(Press %s to release pointer)"), label); +-- +2.28.0 + diff --git a/0009-virt-viewer-file-transfer-dialog-Reports-detailed-er.patch b/0009-virt-viewer-file-transfer-dialog-Reports-detailed-er.patch new file mode 100644 index 0000000..70f334f --- /dev/null +++ b/0009-virt-viewer-file-transfer-dialog-Reports-detailed-er.patch @@ -0,0 +1,122 @@ +From 522cca5ac1473405d325fce4fef0d6e0343f6257 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 10 Jun 2020 13:27:36 +0100 +Subject: [PATCH] virt-viewer-file-transfer-dialog: Reports detailed errors + +Instead of showing just a generic error with a list of files group +files by error and show them. + +This solves https://bugzilla.redhat.com/show_bug.cgi?id=1753563 + +Signed-off-by: Frediano Ziglio +--- + src/virt-viewer-file-transfer-dialog.c | 47 +++++++++++++++++++++++--- + 1 file changed, 43 insertions(+), 4 deletions(-) + +diff --git a/src/virt-viewer-file-transfer-dialog.c b/src/virt-viewer-file-transfer-dialog.c +index b510d8e..975346f 100644 +--- a/src/virt-viewer-file-transfer-dialog.c ++++ b/src/virt-viewer-file-transfer-dialog.c +@@ -188,6 +188,23 @@ error_dialog_response(GtkDialog *dialog, + gtk_widget_destroy(GTK_WIDGET(dialog)); + } + ++static const gchar* ++file_error_message(GError *err) ++{ ++ if (err && err->message) { ++ return err->message; ++ } ++ return _("Unspecified error"); ++} ++ ++static gint ++compare_file_error(gconstpointer a, gconstpointer b) ++{ ++ GError *error_a = g_object_get_data(G_OBJECT(a), "virt-viewer-error"); ++ GError *error_b = g_object_get_data(G_OBJECT(b), "virt-viewer-error"); ++ return g_strcmp0(file_error_message(error_a), file_error_message(error_b)); ++} ++ + static gboolean hide_transfer_dialog(gpointer data) + { + VirtViewerFileTransferDialog *self = data; +@@ -202,10 +219,26 @@ static gboolean hide_transfer_dialog(gpointer data) + GString *msg = g_string_new(""); + GtkWidget *dialog, *files_label, *scrolled_window, *area; + GtkRequisition files_label_sz; ++ const gchar *last_error = NULL; ++ const gchar *group_separator = ""; ++ ++ self->priv->failed = g_slist_sort(self->priv->failed, compare_file_error); + + for (sl = self->priv->failed; sl != NULL; sl = g_slist_next(sl)) { + SpiceFileTransferTask *failed_task = sl->data; + gchar *filename = spice_file_transfer_task_get_filename(failed_task); ++ ++ const gchar *error_message = ++ file_error_message(g_object_get_data(G_OBJECT(failed_task), "virt-viewer-error")); ++ if (g_strcmp0(error_message, last_error) != 0) { ++ // add error message ++ gchar *header = g_markup_printf_escaped("%s%s:", group_separator, error_message); ++ g_string_append(msg, header); ++ g_free(header); ++ last_error = error_message; ++ group_separator = "\n\n"; ++ } ++ + if (filename == NULL) { + guint id; + +@@ -214,15 +247,16 @@ static gboolean hide_transfer_dialog(gpointer data) + filename = g_strdup_printf("(task #%u)", id); + } + +- g_string_append_printf(msg, "\n%s", filename); ++ gchar *escaped_filename = g_markup_printf_escaped("\n%s", filename); ++ g_string_append(msg, escaped_filename); ++ g_free(escaped_filename); + g_free(filename); + } + g_slist_free_full(self->priv->failed, g_object_unref); + self->priv->failed = NULL; + + dialog = gtk_message_dialog_new(GTK_WINDOW(self), 0, GTK_MESSAGE_ERROR, +- GTK_BUTTONS_OK, +- _("An error caused the following file transfers to fail:")); ++ GTK_BUTTONS_OK, NULL); + gtk_window_set_title(GTK_WINDOW(dialog), "Transfer error"); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); +@@ -232,8 +266,9 @@ static gboolean hide_transfer_dialog(gpointer data) + area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); + gtk_container_add(GTK_CONTAINER(area), scrolled_window); + +- files_label = gtk_label_new(msg->str + 1); /* skip the initial '\n' */ ++ files_label = gtk_label_new(NULL); + gtk_label_set_selectable(GTK_LABEL(files_label), TRUE); ++ gtk_label_set_markup(GTK_LABEL(files_label), msg->str); + gtk_container_add(GTK_CONTAINER(scrolled_window), files_label); + + g_string_free(msg, TRUE); +@@ -242,6 +277,8 @@ static gboolean hide_transfer_dialog(gpointer data) + + /* adjust panel to file_label height */ + gtk_widget_get_preferred_size(files_label, NULL, &files_label_sz); ++ gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(scrolled_window), ++ MIN(files_label_sz.width, 500)); + gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled_window), + MIN(files_label_sz.height, 170)); + } +@@ -256,6 +293,8 @@ static void task_finished(SpiceFileTransferTask *task, + VirtViewerFileTransferDialog *self = VIRT_VIEWER_FILE_TRANSFER_DIALOG(user_data); + + if (error && !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { ++ g_object_set_data_full(G_OBJECT(task), "virt-viewer-error", ++ g_error_copy(error), (GDestroyNotify) g_error_free); + self->priv->failed = g_slist_prepend(self->priv->failed, g_object_ref(task)); + g_warning("File transfer task %p failed: %s", task, error->message); + } +-- +2.28.0 + diff --git a/0010-ui-improve-homepage-in-about-dialog.patch b/0010-ui-improve-homepage-in-about-dialog.patch new file mode 100644 index 0000000..466c1f0 --- /dev/null +++ b/0010-ui-improve-homepage-in-about-dialog.patch @@ -0,0 +1,32 @@ +From 671f79bd7d0668fb0c70cd17d09a77482b9f5fbe Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 22 Jul 2020 12:08:25 +0200 +Subject: [PATCH] ui: improve homepage in about dialog + +Switch the homepage URL to https, and synchronize the label with the +URL. Also, do not make the label translatable, as it is pointless (it is +only a URL). + +Signed-off-by: Pino Toscano +--- + src/resources/ui/virt-viewer-about.ui | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/resources/ui/virt-viewer-about.ui b/src/resources/ui/virt-viewer-about.ui +index 5f6ce70..681590f 100644 +--- a/src/resources/ui/virt-viewer-about.ui ++++ b/src/resources/ui/virt-viewer-about.ui +@@ -16,8 +16,8 @@ + Copyright (C) 2007-2012 Daniel P. Berrange + Copyright (C) 2007-2014 Red Hat, Inc. + A remote desktop client built with GTK-VNC, SPICE-GTK and libvirt +- http://gitlab.com/virt-viewer/virt-viewer/ +- gitlab.com/virt-viewer/virt-viewer ++ https://gitlab.com/virt-viewer/virt-viewer ++ https://gitlab.com/virt-viewer/virt-viewer + 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 +-- +2.28.0 + diff --git a/0011-about-ui-year-2020-in-Copyright.patch b/0011-about-ui-year-2020-in-Copyright.patch new file mode 100644 index 0000000..9e02571 --- /dev/null +++ b/0011-about-ui-year-2020-in-Copyright.patch @@ -0,0 +1,28 @@ +From d880ce4a4097d4e7efa1ba1a7fe28147b2e439bc Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 25 Aug 2020 20:10:59 +0300 +Subject: [PATCH] about ui: year 2020 in Copyright + +rhbz#1848267 + +Signed-off-by: Uri Lublin +--- + src/resources/ui/virt-viewer-about.ui | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/resources/ui/virt-viewer-about.ui b/src/resources/ui/virt-viewer-about.ui +index 681590f..25b2165 100644 +--- a/src/resources/ui/virt-viewer-about.ui ++++ b/src/resources/ui/virt-viewer-about.ui +@@ -15,7 +15,7 @@ + True + Virtual Machine Viewer + Copyright (C) 2007-2012 Daniel P. Berrange +-Copyright (C) 2007-2014 Red Hat, Inc. ++Copyright (C) 2007-2020 Red Hat, Inc. + A remote desktop client built with GTK-VNC, SPICE-GTK and libvirt + https://gitlab.com/virt-viewer/virt-viewer + https://gitlab.com/virt-viewer/virt-viewer +-- +2.28.0 + diff --git a/0012-ui-about-po-update-pot-file.patch b/0012-ui-about-po-update-pot-file.patch new file mode 100644 index 0000000..9fcd14a --- /dev/null +++ b/0012-ui-about-po-update-pot-file.patch @@ -0,0 +1,35 @@ +From b7a2f05266e82fbdf0642b27276099a55844dbae Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 11 Sep 2020 11:35:00 +0200 +Subject: [PATCH] po: update pot file + +Signed-off-by: Pino Toscano +--- + po/virt-viewer.pot | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/po/virt-viewer.pot b/po/virt-viewer.pot +index a3e49ad..1853fcd 100644 +--- a/po/virt-viewer.pot ++++ b/po/virt-viewer.pot +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: virt-viewer 9.0\n" + "Report-Msgid-Bugs-To: https://gitlab.com/virt-viewer/virt-viewer/-/issues\n" +-"POT-Creation-Date: 2020-05-01 17:38+0100\n" ++"POT-Creation-Date: 2020-09-11 11:34+0200\n" + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" + "Last-Translator: FULL NAME \n" + "Language-Team: LANGUAGE \n" +@@ -199,7 +199,7 @@ msgstr "" + #: src/resources/ui/virt-viewer-about.ui:16 + msgid "" + "Copyright (C) 2007-2012 Daniel P. Berrange\n" +-"Copyright (C) 2007-2014 Red Hat, Inc." ++"Copyright (C) 2007-2020 Red Hat, Inc." + msgstr "" + + #: src/resources/ui/virt-viewer-about.ui:18 +-- +2.28.0 + diff --git a/0013-vnc-show-an-error-dialog-upon-vnc-error.patch b/0013-vnc-show-an-error-dialog-upon-vnc-error.patch new file mode 100644 index 0000000..88850d5 --- /dev/null +++ b/0013-vnc-show-an-error-dialog-upon-vnc-error.patch @@ -0,0 +1,134 @@ +From de5cd71013532d1a1240315c92fd0b5ca708fe01 Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 27 Oct 2020 19:53:36 +0200 +Subject: [PATCH] vnc: show an error dialog upon vnc-error + +For example when connecting by accident to a spice server + +Signed-off-by: Uri Lublin +--- + src/virt-viewer-app.c | 20 +++++++++++++++++--- + src/virt-viewer-session-vnc.c | 13 +++++++++++++ + src/virt-viewer-session.c | 9 +++++++++ + 3 files changed, 39 insertions(+), 3 deletions(-) + +diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c +index c0e0c9c..8cfdc2d 100644 +--- a/src/virt-viewer-app.c ++++ b/src/virt-viewer-app.c +@@ -78,6 +78,9 @@ 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, +@@ -1292,6 +1295,8 @@ 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", +@@ -1654,8 +1659,6 @@ virt_viewer_app_connected(VirtViewerSession *session G_GNUC_UNUSED, + virt_viewer_app_show_status(self, _("Connected to graphic server")); + } + +- +- + static void + virt_viewer_app_initialized(VirtViewerSession *session G_GNUC_UNUSED, + VirtViewerApp *self) +@@ -1690,6 +1693,18 @@ 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; ++ ++ priv->connected = FALSE; /* display error dialog */ ++ ++ virt_viewer_app_disconnected(session, msg, self); ++} ++ + static void virt_viewer_app_cancelled(VirtViewerSession *session, + VirtViewerApp *self) + { +@@ -1698,7 +1713,6 @@ static void virt_viewer_app_cancelled(VirtViewerSession *session, + virt_viewer_app_disconnected(session, NULL, self); + } + +- + static void virt_viewer_app_auth_refused(VirtViewerSession *session, + const char *msg, + VirtViewerApp *self) +diff --git a/src/virt-viewer-session-vnc.c b/src/virt-viewer-session-vnc.c +index 261d984..2598c70 100644 +--- a/src/virt-viewer-session-vnc.c ++++ b/src/virt-viewer-session-vnc.c +@@ -128,6 +128,15 @@ virt_viewer_session_vnc_disconnected(VncDisplay *vnc G_GNUC_UNUSED, + VIRT_VIEWER_DISPLAY_SHOW_HINT_READY, FALSE); + } + ++static void ++virt_viewer_session_vnc_error(VncDisplay *vnc G_GNUC_UNUSED, ++ const gchar* msg, ++ VirtViewerSessionVnc *session) ++{ ++ g_warning("vnc-session: got vnc error %s", msg); ++ g_signal_emit_by_name(session, "session-error", msg); ++} ++ + static void + virt_viewer_session_vnc_initialized(VncDisplay *vnc G_GNUC_UNUSED, + VirtViewerSessionVnc *session) +@@ -386,6 +395,8 @@ virt_viewer_session_vnc_close(VirtViewerSession* session) + 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(self->priv->vnc, "vnc-bell", + G_CALLBACK(virt_viewer_session_vnc_bell), session); +@@ -418,6 +429,8 @@ virt_viewer_session_vnc_new(VirtViewerApp *app, GtkWindow *main_window) + 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(session->priv->vnc, "vnc-bell", + G_CALLBACK(virt_viewer_session_vnc_bell), session); +diff --git a/src/virt-viewer-session.c b/src/virt-viewer-session.c +index a809814..d58fc37 100644 +--- a/src/virt-viewer-session.c ++++ b/src/virt-viewer-session.c +@@ -272,6 +272,15 @@ 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.28.0 + diff --git a/0014-Fix-warning-by-Coverity.patch b/0014-Fix-warning-by-Coverity.patch new file mode 100644 index 0000000..8cb6d76 --- /dev/null +++ b/0014-Fix-warning-by-Coverity.patch @@ -0,0 +1,69 @@ +From 1573a790da7370f547d542191d530ba8580e5a03 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Mon, 14 Sep 2020 13:51:15 +0100 +Subject: [PATCH] Fix warning by Coverity + +Error: DEADCODE (CWE-561): [#def1] +virt-viewer-9.0/src/virt-viewer-display-vte.c:164: assignment: Assigning: "scroll" = "NULL". +virt-viewer-9.0/src/virt-viewer-display-vte.c:188: null: At condition "scroll", the value of "scroll" must be "NULL". +virt-viewer-9.0/src/virt-viewer-display-vte.c:188: dead_error_condition: The condition "scroll" cannot be true. +virt-viewer-9.0/src/virt-viewer-display-vte.c:189: dead_error_begin: Execution cannot reach this statement: "gtk_container_add((GtkConta...". +virt-viewer-9.0/src/virt-viewer-display-vte.c:189: effectively_constant: Local variable "scroll" is assigned only once, to a constant value, making it effectively constant throughout its scope. If this is not the intent, examine the logic to see if there is a missing assignment that would make "scroll" not remain constant. + +Reported in https://gitlab.com/virt-viewer/virt-viewer/-/issues/7. + +Signed-off-by: Frediano Ziglio +--- + src/virt-viewer-display-vte.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/virt-viewer-display-vte.c b/src/virt-viewer-display-vte.c +index ef0d5ac..9e4f734 100644 +--- a/src/virt-viewer-display-vte.c ++++ b/src/virt-viewer-display-vte.c +@@ -147,7 +147,6 @@ virt_viewer_display_vte_commit(VirtViewerDisplayVte *self, + { + g_signal_emit_by_name(self, "commit", text, size); + } +-#endif + + static void + virt_viewer_display_vte_adj_changed(VirtViewerDisplayVte *self, +@@ -156,12 +155,16 @@ virt_viewer_display_vte_adj_changed(VirtViewerDisplayVte *self, + gtk_widget_set_visible(self->priv->scroll, + gtk_adjustment_get_upper(adjustment) > gtk_adjustment_get_page_size(adjustment)); + } ++#endif + + GtkWidget * + virt_viewer_display_vte_new(VirtViewerSession *session, const char *name) + { + VirtViewerDisplayVte *self; +- GtkWidget *grid, *scroll = NULL, *vte; ++ GtkWidget *grid, *vte; ++#ifdef HAVE_VTE ++ GtkWidget *scroll = NULL; ++#endif + + self = g_object_new(VIRT_VIEWER_TYPE_DISPLAY_VTE, + "session", session, +@@ -185,6 +188,8 @@ virt_viewer_display_vte_new(VirtViewerSession *session, const char *name) + grid = gtk_grid_new(); + + gtk_container_add(GTK_CONTAINER(grid), vte); ++ ++#ifdef HAVE_VTE + if (scroll) { + gtk_container_add(GTK_CONTAINER(grid), scroll); + gtk_widget_hide(scroll); +@@ -192,6 +197,7 @@ virt_viewer_display_vte_new(VirtViewerSession *session, const char *name) + "changed", G_CALLBACK(virt_viewer_display_vte_adj_changed), + self, G_CONNECT_SWAPPED); + } ++#endif + + gtk_container_add(GTK_CONTAINER(self), grid); + +-- +2.28.0 + diff --git a/0015-windows-fix-nonuniform-behavior-of-zoom-hotkeys.patch b/0015-windows-fix-nonuniform-behavior-of-zoom-hotkeys.patch new file mode 100644 index 0000000..fe7738e --- /dev/null +++ b/0015-windows-fix-nonuniform-behavior-of-zoom-hotkeys.patch @@ -0,0 +1,71 @@ +From a40c8f4508e96c29ea5a24042906d5ded90241fb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jakub=20Jank=C5=AF?= +Date: Thu, 3 Dec 2020 13:40:33 +0100 +Subject: [PATCH] windows: fix nonuniform behavior of zoom hotkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a vv file is used or the hotkeys are customized using the +--hotkeys cmd option, all hotkeys that are not explicitly +requested get disabled, this includes the zomm hotkeys. + +As a consequence, the labels for zoom actions in the menu +disappear. However, the user can still perform these actions +using the keys on the numpad which are handled separately. + +To fix it, check that the normal zoom hotkeys are enabled +before enabling the keypad ones. + +Related to: https://bugzilla.redhat.com/show_bug.cgi?id=1791261 + +Signed-off-by: Jakub Janků +--- + src/virt-viewer-window.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c +index eed3086..5647023 100644 +--- a/src/virt-viewer-window.c ++++ b/src/virt-viewer-window.c +@@ -887,6 +887,7 @@ virt_viewer_window_enable_modifiers(VirtViewerWindow *self) + VirtViewerWindowPrivate *priv = self->priv; + GSList *accels; + guint i; ++ GtkAccelKey key; + + if (priv->accel_enabled) + return; +@@ -904,15 +905,20 @@ virt_viewer_window_enable_modifiers(VirtViewerWindow *self) + "gtk-enable-mnemonics", priv->enable_mnemonics_save, + NULL); + +- g_action_map_add_action_entries(G_ACTION_MAP(priv->window), +- keypad_action_entries, G_N_ELEMENTS(keypad_action_entries), +- self); +- for (i = 0; i < G_N_ELEMENTS(keypad_action_entries); i++) { +- gchar *detailed_name = g_strdup_printf("win.%s", keypad_action_entries[i].name); +- gtk_application_set_accels_for_action(GTK_APPLICATION(priv->app), +- detailed_name, +- keypad_action_accels[i]); +- g_free(detailed_name); ++ /* if zoom actions using "normal" +/-/0 keys are enabled, ++ * allow the user to use the numpad +/-/0 keys as well */ ++ if (gtk_accel_map_lookup_entry("/view/zoom-out", &key) ++ && key.accel_key != 0) { ++ g_action_map_add_action_entries(G_ACTION_MAP(priv->window), ++ keypad_action_entries, G_N_ELEMENTS(keypad_action_entries), ++ self); ++ for (i = 0; i < G_N_ELEMENTS(keypad_action_entries); i++) { ++ gchar *detailed_name = g_strdup_printf("win.%s", keypad_action_entries[i].name); ++ gtk_application_set_accels_for_action(GTK_APPLICATION(priv->app), ++ detailed_name, ++ keypad_action_accels[i]); ++ g_free(detailed_name); ++ } + } + + priv->accel_enabled = TRUE; +-- +2.29.2 + diff --git a/0016-hotkeys-enable-setting-zoom-hotkeys-from-command-lin.patch b/0016-hotkeys-enable-setting-zoom-hotkeys-from-command-lin.patch new file mode 100644 index 0000000..80ccb1b --- /dev/null +++ b/0016-hotkeys-enable-setting-zoom-hotkeys-from-command-lin.patch @@ -0,0 +1,30 @@ +From e89e82eeb9a917f077720d4821c0e306a6d130d1 Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 8 Dec 2020 19:50:01 +0200 +Subject: [PATCH 16/19] hotkeys: enable setting zoom hotkeys from command line + +Signed-off-by: Uri Lublin +--- + src/virt-viewer-app.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c +index 3ee5990..8d795ca 100644 +--- a/src/virt-viewer-app.c ++++ b/src/virt-viewer-app.c +@@ -2511,6 +2511,12 @@ virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys_str) + status = gtk_accel_map_change_entry("/view/toggle-fullscreen", accel_key, accel_mods, TRUE); + } else if (g_str_equal(*hotkey, "release-cursor")) { + status = gtk_accel_map_change_entry("/view/release-cursor", accel_key, accel_mods, TRUE); ++ } else if (g_str_equal(*hotkey, "zoom-reset")) { ++ status = gtk_accel_map_change_entry("/view/zoom-reset", accel_key, accel_mods, TRUE); ++ } else if (g_str_equal(*hotkey, "zoom-out")) { ++ status = gtk_accel_map_change_entry("/view/zoom-out", accel_key, accel_mods, TRUE); ++ } else if (g_str_equal(*hotkey, "zoom-in")) { ++ status = gtk_accel_map_change_entry("/view/zoom-in", accel_key, accel_mods, TRUE); + } else if (g_str_equal(*hotkey, "secure-attention")) { + status = gtk_accel_map_change_entry("/send/secure-attention", accel_key, accel_mods, TRUE); + } else if (g_str_equal(*hotkey, "smartcard-insert")) { +-- +2.29.2 + diff --git a/0017-hotkeys-enable-setting-zoom-hotkeys-from-a-vv-file.patch b/0017-hotkeys-enable-setting-zoom-hotkeys-from-a-vv-file.patch new file mode 100644 index 0000000..9757f41 --- /dev/null +++ b/0017-hotkeys-enable-setting-zoom-hotkeys-from-a-vv-file.patch @@ -0,0 +1,164 @@ +From 8cc06670239ae382a3b2e17fe39f5ecfb7bfe2f9 Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 8 Dec 2020 19:50:57 +0200 +Subject: [PATCH 17/19] hotkeys: enable setting zoom hotkeys from a vv file + +Signed-off-by: Uri Lublin +--- + src/virt-viewer-file.c | 79 ++++++++++++++++++++++++++++++++++++++++++ + src/virt-viewer-file.h | 7 ++++ + 2 files changed, 86 insertions(+) + +diff --git a/src/virt-viewer-file.c b/src/virt-viewer-file.c +index 7d2b2cb..143074f 100644 +--- a/src/virt-viewer-file.c ++++ b/src/virt-viewer-file.c +@@ -57,6 +57,9 @@ + * - title: string + * - toggle-fullscreen: string in spice hotkey format + * - release-cursor: string in spice hotkey format ++ * - zoom-in: zoom in and make the client window larger ++ * - zoom-out: zoom out and make the client window smaller ++ * - zoom-reset: reset zoom and client window size + * - smartcard-insert: string in spice hotkey format + * - smartcard-remove: string in spice hotkey format + * - secure-attention: string in spice hotkey format +@@ -117,6 +120,9 @@ enum { + PROP_TITLE, + PROP_TOGGLE_FULLSCREEN, + PROP_RELEASE_CURSOR, ++ PROP_ZOOM_IN, ++ PROP_ZOOM_OUT, ++ PROP_ZOOM_RESET, + PROP_ENABLE_SMARTCARD, + PROP_ENABLE_USBREDIR, + PROP_COLOR_DEPTH, +@@ -514,6 +520,46 @@ virt_viewer_file_set_release_cursor(VirtViewerFile* self, const gchar* value) + g_object_notify(G_OBJECT(self), "release-cursor"); + } + ++gchar* ++virt_viewer_file_get_zoom_in(VirtViewerFile* self) ++{ ++ return virt_viewer_file_get_string(self, MAIN_GROUP, "zoom-in"); ++} ++ ++void ++virt_viewer_file_set_zoom_in(VirtViewerFile* self, const gchar* value) ++{ ++ virt_viewer_file_set_string(self, MAIN_GROUP, "zoom-in", value); ++ g_object_notify(G_OBJECT(self), "zoom-in"); ++} ++ ++gchar* ++virt_viewer_file_get_zoom_out(VirtViewerFile* self) ++{ ++ return virt_viewer_file_get_string(self, MAIN_GROUP, "zoom-out"); ++} ++ ++void ++virt_viewer_file_set_zoom_out(VirtViewerFile* self, const gchar* value) ++{ ++ virt_viewer_file_set_string(self, MAIN_GROUP, "zoom-out", value); ++ g_object_notify(G_OBJECT(self), "zoom-out"); ++} ++ ++gchar* ++virt_viewer_file_get_zoom_reset(VirtViewerFile* self) ++{ ++ return virt_viewer_file_get_string(self, MAIN_GROUP, "zoom-reset"); ++} ++ ++void ++virt_viewer_file_set_zoom_reset(VirtViewerFile* self, const gchar* value) ++{ ++ virt_viewer_file_set_string(self, MAIN_GROUP, "zoom-reset", value); ++ g_object_notify(G_OBJECT(self), "zoom-reset"); ++} ++ ++ + gchar* + virt_viewer_file_get_secure_attention(VirtViewerFile* self) + { +@@ -917,6 +963,9 @@ virt_viewer_file_fill_app(VirtViewerFile* self, VirtViewerApp *app, GError **err + } accels[] = { + { "release-cursor", "/view/release-cursor" }, + { "toggle-fullscreen", "/view/toggle-fullscreen" }, ++ { "zoom-in", "/view/zoom-in" }, ++ { "zoom-out", "/view/zoom-out" }, ++ { "zoom-reset", "/view/zoom-reset" }, + { "smartcard-insert", "/file/smartcard-insert" }, + { "smartcard-remove", "/file/smartcard-remove" }, + { "secure-attention", "/send/secure-attention" } +@@ -995,6 +1044,15 @@ virt_viewer_file_set_property(GObject* object, guint property_id, + case PROP_RELEASE_CURSOR: + virt_viewer_file_set_release_cursor(self, g_value_get_string(value)); + break; ++ case PROP_ZOOM_IN: ++ virt_viewer_file_set_zoom_in(self, g_value_get_string(value)); ++ break; ++ case PROP_ZOOM_OUT: ++ virt_viewer_file_set_zoom_out(self, g_value_get_string(value)); ++ break; ++ case PROP_ZOOM_RESET: ++ virt_viewer_file_set_zoom_reset(self, g_value_get_string(value)); ++ break; + case PROP_SECURE_ATTENTION: + virt_viewer_file_set_secure_attention(self, g_value_get_string(value)); + break; +@@ -1112,6 +1170,15 @@ virt_viewer_file_get_property(GObject* object, guint property_id, + case PROP_RELEASE_CURSOR: + g_value_take_string(value, virt_viewer_file_get_release_cursor(self)); + break; ++ case PROP_ZOOM_IN: ++ g_value_take_string(value, virt_viewer_file_get_zoom_in(self)); ++ break; ++ case PROP_ZOOM_OUT: ++ g_value_take_string(value, virt_viewer_file_get_zoom_out(self)); ++ break; ++ case PROP_ZOOM_RESET: ++ g_value_take_string(value, virt_viewer_file_get_zoom_reset(self)); ++ break; + case PROP_SECURE_ATTENTION: + g_value_take_string(value, virt_viewer_file_get_secure_attention(self)); + break; +@@ -1255,6 +1322,18 @@ virt_viewer_file_class_init(VirtViewerFileClass* klass) + g_param_spec_string("release-cursor", "release-cursor", "release-cursor", NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); + ++ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_ZOOM_IN, ++ g_param_spec_string("zoom-in", "zoom-in", "zoom-in", NULL, ++ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); ++ ++ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_ZOOM_OUT, ++ g_param_spec_string("zoom-out", "zoom-out", "zoom-out", NULL, ++ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); ++ ++ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_ZOOM_RESET, ++ g_param_spec_string("zoom-reset", "zoom-reset", "zoom-reset", NULL, ++ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); ++ + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_SECURE_ATTENTION, + g_param_spec_string("secure-attention", "secure-attention", "secure-attention", NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); +diff --git a/src/virt-viewer-file.h b/src/virt-viewer-file.h +index 108bcbf..b0aef6d 100644 +--- a/src/virt-viewer-file.h ++++ b/src/virt-viewer-file.h +@@ -86,6 +86,13 @@ gchar* virt_viewer_file_get_toggle_fullscreen(VirtViewerFile* self); + void virt_viewer_file_set_toggle_fullscreen(VirtViewerFile* self, const gchar* value); + gchar* virt_viewer_file_get_release_cursor(VirtViewerFile* self); + void virt_viewer_file_set_release_cursor(VirtViewerFile* self, const gchar* value); ++gchar* virt_viewer_file_get_zoom_in(VirtViewerFile* self); ++void virt_viewer_file_set_zoom_in(VirtViewerFile* self, const gchar* value); ++gchar* virt_viewer_file_get_zoom_out(VirtViewerFile* self); ++void virt_viewer_file_set_zoom_out(VirtViewerFile* self, const gchar* value); ++gchar* virt_viewer_file_get_zoom_reset(VirtViewerFile* self); ++void virt_viewer_file_set_zoom_reset(VirtViewerFile* self, const gchar* value); ++ + gint virt_viewer_file_get_enable_smartcard(VirtViewerFile* self); + void virt_viewer_file_set_enable_smartcard(VirtViewerFile* self, gint value); + gint virt_viewer_file_get_enable_usbredir(VirtViewerFile* self); +-- +2.29.2 + diff --git a/0018-tests-hotkeys-add-zoom-hotkeys.patch b/0018-tests-hotkeys-add-zoom-hotkeys.patch new file mode 100644 index 0000000..fa25991 --- /dev/null +++ b/0018-tests-hotkeys-add-zoom-hotkeys.patch @@ -0,0 +1,25 @@ +From 8de1e49136599842d52823295c0d3f4b941601de Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 8 Dec 2020 20:11:23 +0200 +Subject: [PATCH 18/19] tests: hotkeys: add zoom hotkeys + +Signed-off-by: Uri Lublin +--- + tests/test-hotkeys.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/test-hotkeys.c b/tests/test-hotkeys.c +index cd2bd88..8275647 100644 +--- a/tests/test-hotkeys.c ++++ b/tests/test-hotkeys.c +@@ -67,6 +67,7 @@ test_hotkeys_good(void) + const gchar *hotkeys[] = { + "toggle-fullscreen=shift+f11", + "release-cursor=shift+f12,secure-attention=ctrl+shift+b", ++ "zoom-in=shift+f2,zoom-out=shift+f3,zoom-reset=shift+f4", + "smartcard-insert=shift+I,smartcard-remove=shift+R", + }; + +-- +2.29.2 + diff --git a/0019-man-add-zoom-hotkeys.patch b/0019-man-add-zoom-hotkeys.patch new file mode 100644 index 0000000..dfb6aea --- /dev/null +++ b/0019-man-add-zoom-hotkeys.patch @@ -0,0 +1,61 @@ +From ae3e15f851605e5551406412fed00a034fc66f58 Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 8 Dec 2020 20:12:19 +0200 +Subject: [PATCH 19/19] man: add zoom hotkeys + +Signed-off-by: Uri Lublin +--- + man/remote-viewer.pod | 15 ++++++++++++++- + man/virt-viewer.pod | 3 ++- + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/man/remote-viewer.pod b/man/remote-viewer.pod +index 73c829f..e820f4b 100644 +--- a/man/remote-viewer.pod ++++ b/man/remote-viewer.pod +@@ -69,7 +69,8 @@ guest display widget does not have focus. Any actions specified in B + will be effective even when the guest display widget has input focus. The format + for B is =[+][,=[+]]. + Key-names are case-insensitive. Valid actions are: toggle-fullscreen, +-release-cursor, secure-attention, smartcard-insert and smartcard-remove. The ++release-cursor, zoom-in, zoom-out, zoom-reset, ++secure-attention, smartcard-insert and smartcard-remove. The + C action sends a secure attention sequence (Ctrl+Alt+Del) to + the guest. Examples: + +@@ -224,6 +225,18 @@ Key binding for entering and leaving fullscreen mode. (see L for descrip + + Key binding for releasing cursor grab. (see L for description of expected string) + ++=item C (hotkey string) ++ ++Key binding for zooming in and enlarging client window size. (see L for description of expected string) ++ ++=item C (hotkey string) ++ ++Key binding for zooming out and reducing client window size. (see L for description of expected string) ++ ++=item C (hotkey string) ++ ++Key binding for reseting zoom and client window size. (see L for description of expected string) ++ + =item C (hotkey string) + + Key binding for inserting emulated smartcard. (see L for description of expected string) +diff --git a/man/virt-viewer.pod b/man/virt-viewer.pod +index d55c5be..a42134b 100644 +--- a/man/virt-viewer.pod ++++ b/man/virt-viewer.pod +@@ -89,7 +89,8 @@ guest display widget does not have focus. Any actions specified in B + will be effective even when the guest display widget has input focus. The format + for B is =[+][,=[+]]. + Key-names are case-insensitive. Valid actions are: toggle-fullscreen, +-release-cursor, secure-attention, smartcard-insert and smartcard-remove. The ++release-cursor, zoom-in, zoom-out, zoom-reset, ++secure-attention, smartcard-insert and smartcard-remove. The + C action sends a secure attention sequence (Ctrl+Alt+Del) to + the guest. Examples: + +-- +2.29.2 + diff --git a/0020-zoom-hotkeys-disable-numpad-when-users-set-new-hotke.patch b/0020-zoom-hotkeys-disable-numpad-when-users-set-new-hotke.patch new file mode 100644 index 0000000..9f738fa --- /dev/null +++ b/0020-zoom-hotkeys-disable-numpad-when-users-set-new-hotke.patch @@ -0,0 +1,45 @@ +From a0f227c723d424c6f1cf63efa213668e69800e98 Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Sun, 10 Jan 2021 17:05:09 +0200 +Subject: [PATCH] zoom hotkeys: disable numpad when users set new hotkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a user sets any hotkey, disable numpad hotkeys. +If a user does not set any hotkey and the default hotkeys +are enabled, then numpad hotkeys are enabled too. + +This is a folloup for commits a40c8f4 and e89e82e + 8cc0667. +Currently setting (e.g. ctrl [123]) hotkeys for zoom (in/out/reset), +re-enable the default numpad hotkeys (ctrl [+-0]). + +Related to: https://bugzilla.redhat.com/show_bug.cgi?id=1791261 + +Suggested-by: Jakub Janků +Signed-off-by: Uri Lublin +--- + src/virt-viewer-window.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c +index 5647023..448ef74 100644 +--- a/src/virt-viewer-window.c ++++ b/src/virt-viewer-window.c +@@ -905,9 +905,11 @@ virt_viewer_window_enable_modifiers(VirtViewerWindow *self) + "gtk-enable-mnemonics", priv->enable_mnemonics_save, + NULL); + +- /* if zoom actions using "normal" +/-/0 keys are enabled, ++ /* if the user did not set hotkeys and ++ * zoom actions using "normal" +/-/0 keys are enabled, + * allow the user to use the numpad +/-/0 keys as well */ +- if (gtk_accel_map_lookup_entry("/view/zoom-out", &key) ++ if (!virt_viewer_app_get_enable_accel(priv->app) ++ && gtk_accel_map_lookup_entry("/view/zoom-out", &key) + && key.accel_key != 0) { + g_action_map_add_action_entries(G_ACTION_MAP(priv->window), + keypad_action_entries, G_N_ELEMENTS(keypad_action_entries), +-- +2.29.2 + diff --git a/0021-disable-default-grab-sequence-in-kiosk-mode.patch b/0021-disable-default-grab-sequence-in-kiosk-mode.patch new file mode 100644 index 0000000..91450f4 --- /dev/null +++ b/0021-disable-default-grab-sequence-in-kiosk-mode.patch @@ -0,0 +1,70 @@ +From c3a3f23968edceaf097f20450c795c762ec36fc0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jakub=20Jank=C5=AF?= +Date: Sun, 20 Dec 2020 12:29:27 +0100 +Subject: [PATCH] disable default grab sequence in kiosk mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Hotkeys should be disabled in kiosk mode. However, if no +"release-cursor" hotkey is specified, the default Ctrl+Alt +grab sequence keeps functioning even in kiosk mode. +That's because it's based on the spice/vnc functionality instead +of on the accelerators in virt-viewer. + +That's especially problematic with spice, because the grab +sequence releases both the cursor and the keyboard. Thus the user +can escape from kiosk mode by pressing Ctrl+Alt followed by +Alt+Tab, for example. + +Related: https://bugzilla.redhat.com/show_bug.cgi?id=1893584 + +Signed-off-by: Jakub Janků +--- + src/virt-viewer-display-spice.c | 6 +++++- + src/virt-viewer-display-vnc.c | 6 +++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/virt-viewer-display-spice.c b/src/virt-viewer-display-spice.c +index a82422c..799403c 100644 +--- a/src/virt-viewer-display-spice.c ++++ b/src/virt-viewer-display-spice.c +@@ -238,10 +238,14 @@ enable_accel_changed(VirtViewerApp *app, + VirtViewerDisplaySpice *self) + { + GtkAccelKey key = {0, 0, 0}; ++ gboolean kiosk; ++ + if (virt_viewer_app_get_enable_accel(app)) + gtk_accel_map_lookup_entry("/view/release-cursor", &key); + +- if (key.accel_key || key.accel_mods) { ++ g_object_get(app, "kiosk", &kiosk, NULL); ++ ++ if (key.accel_key || key.accel_mods || kiosk) { + SpiceGrabSequence *seq = spice_grab_sequence_new(0, NULL); + /* disable default grab sequence */ + spice_display_set_grab_keys(self->priv->display, seq); +diff --git a/src/virt-viewer-display-vnc.c b/src/virt-viewer-display-vnc.c +index d38dcac..537173c 100644 +--- a/src/virt-viewer-display-vnc.c ++++ b/src/virt-viewer-display-vnc.c +@@ -188,10 +188,14 @@ enable_accel_changed(VirtViewerApp *app, + VncDisplay *vnc) + { + GtkAccelKey key = {0, 0, 0}; ++ gboolean kiosk; ++ + if (virt_viewer_app_get_enable_accel(app)) + gtk_accel_map_lookup_entry("/view/release-cursor", &key); + +- if (key.accel_key || key.accel_mods) { ++ g_object_get(app, "kiosk", &kiosk, NULL); ++ ++ if (key.accel_key || key.accel_mods || kiosk) { + VncGrabSequence *seq = vnc_grab_sequence_new(0, NULL); + /* disable default grab sequence */ + vnc_display_set_grab_keys(vnc, seq); +-- +2.29.2 + diff --git a/0022-vnc-no-dialog-for-server-closed-connection-error.patch b/0022-vnc-no-dialog-for-server-closed-connection-error.patch new file mode 100644 index 0000000..b6e02c1 --- /dev/null +++ b/0022-vnc-no-dialog-for-server-closed-connection-error.patch @@ -0,0 +1,62 @@ +From 74fdd26c949847bca41c7ca71bc88d30d92d92aa Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Sun, 17 Jan 2021 19:25:57 +0200 +Subject: [PATCH] vnc: no dialog for server-closed-connection error + +Following commit de5cd71, when the server closes the connection +(likely when qemu-kvm exits), a dialog is shown to the user. + +This behavior change is not good for automatic tests that expect +virt-viewer to exit without any dialog. + +This patch makes sure no dialog is shown for this error, by +checking if the VNC connection was already initialized. + +Signed-off-by: Uri Lublin +--- + src/virt-viewer-app.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c +index 8d795ca..4a579f8 100644 +--- a/src/virt-viewer-app.c ++++ b/src/virt-viewer-app.c +@@ -139,6 +139,7 @@ struct _VirtViewerAppPrivate { + gboolean kiosk; + gboolean vm_ui; + gboolean vm_running; ++ gboolean initialized; + + VirtViewerSession *session; + gboolean active; +@@ -1651,6 +1652,7 @@ virt_viewer_app_deactivate(VirtViewerApp *self, gboolean connect_error) + virt_viewer_session_close(VIRT_VIEWER_SESSION(priv->session)); + } + ++ priv->initialized = FALSE; + priv->connected = FALSE; + priv->active = FALSE; + priv->started = FALSE; +@@ -1689,6 +1691,7 @@ static void + virt_viewer_app_initialized(VirtViewerSession *session G_GNUC_UNUSED, + VirtViewerApp *self) + { ++ self->priv->initialized = TRUE; + virt_viewer_app_update_title(self); + } + +@@ -1727,7 +1730,10 @@ virt_viewer_app_error(VirtViewerSession *session G_GNUC_UNUSED, + { + VirtViewerAppPrivate *priv = self->priv; + +- priv->connected = FALSE; /* display error dialog */ ++ /* 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); + } +-- +2.29.2 + diff --git a/0023-vnc-session-save-message-from-vnc-error-for-vnc-disc.patch b/0023-vnc-session-save-message-from-vnc-error-for-vnc-disc.patch new file mode 100644 index 0000000..fc0ccd4 --- /dev/null +++ b/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/0024-session-remove-session-error-signal.patch b/0024-session-remove-session-error-signal.patch new file mode 100644 index 0000000..33aa9c0 --- /dev/null +++ b/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/0025-vnc-session-use-g_signal_connect_object.patch b/0025-vnc-session-use-g_signal_connect_object.patch new file mode 100644 index 0000000..7043453 --- /dev/null +++ b/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/0026-build-fix-build-without-gtk-vnc.patch b/0026-build-fix-build-without-gtk-vnc.patch new file mode 100644 index 0000000..40cacc2 --- /dev/null +++ b/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/0027-ovirt-foreign-menu-Support-changing-ISO-from-Data-St.patch b/0027-ovirt-foreign-menu-Support-changing-ISO-from-Data-St.patch new file mode 100644 index 0000000..3ccdb80 --- /dev/null +++ b/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/EMPTY b/EMPTY deleted file mode 100644 index 0519ecb..0000000 --- a/EMPTY +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/sources b/sources new file mode 100644 index 0000000..18ea4ba --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (virt-viewer-9.0.tar.gz) = a5901d76c3e144fa3d6e640de93ed7f1e7cbeb075c04cdbe4a8c9c09bce96104ea552484df5e84c7a69af8dddd1177123ddb81b2dac775a98ac312f3102daae2 diff --git a/virt-viewer.spec b/virt-viewer.spec new file mode 100644 index 0000000..f38a67b --- /dev/null +++ b/virt-viewer.spec @@ -0,0 +1,482 @@ +# -*- rpm-spec -*- + +%global _hardened_build 1 + +# Default to skipping autoreconf. Distros can change just this one line +# (or provide a command-line override) if they backport any patches that +# touch configure.ac or Makefile.am. +%{!?enable_autotools:%global enable_autotools 1} + +%define with_spice 0 +%if 0%{?fedora} >= 17 || 0%{?rhel} >= 6 +%define with_spice 1 +%endif + +%define with_govirt 0 +%if 0%{?fedora} > 19 || 0%{?rhel} >= 7 +%define with_govirt 1 +%endif + +Name: virt-viewer +Version: 9.0 +Release: 11%{?dist}%{?extra_release} +Summary: Virtual Machine Viewer +Group: Applications/System +License: GPLv2+ +URL: https://virt-manager.org/ +Source0: http://virt-manager.org/download/sources/%{name}/%{name}-%{version}.tar.gz + +Patch001: 0001-DOWNSTREAM-Workaround-inconsistency-with-REST-API.patch +Patch002: 0002-DOWNSTREAM-ovirt-foreign-menu-Bypass-errors-from-Hos.patch +Patch003: 0003-DOWNSTREAM-remote-viewer-Set-admin-privileges-when-c.patch +Patch004: 0004-ovirt-Do-not-filter-out-DATA-storage-domains.patch +Patch005: 0005-display-error-message-on-no-extension-for-screenshot.patch +Patch006: 0006-ovirt-foreign-menu-Use-proper-function-in-the-case-o.patch +Patch007: 0007-ovirt-foreign-menu-Take-into-account-StorageDomains-.patch + +#rhbz#1548371 +Patch008: 0008-More-specific-key-accelerator-description.patch + +#rhbz#1753563 +Patch009: 0009-virt-viewer-file-transfer-dialog-Reports-detailed-er.patch + +# rhbz#1848267 +# Patches 10 and 12 slightly modified to match downstream +Patch010: 0010-ui-improve-homepage-in-about-dialog.patch +Patch011: 0011-about-ui-year-2020-in-Copyright.patch +Patch012: 0012-ui-about-po-update-pot-file.patch + +# rhbz#1448151 +Patch013: 0013-vnc-show-an-error-dialog-upon-vnc-error.patch +Patch022: 0022-vnc-no-dialog-for-server-closed-connection-error.patch + +# rhbz#1876719 +Patch014: 0014-Fix-warning-by-Coverity.patch + +# rhbz#1791261 +Patch015: 0015-windows-fix-nonuniform-behavior-of-zoom-hotkeys.patch +Patch016: 0016-hotkeys-enable-setting-zoom-hotkeys-from-command-lin.patch +Patch017: 0017-hotkeys-enable-setting-zoom-hotkeys-from-a-vv-file.patch +Patch018: 0018-tests-hotkeys-add-zoom-hotkeys.patch +# patch19 slightly modified, no usb-device-reset accel +Patch019: 0019-man-add-zoom-hotkeys.patch +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 +Requires(post): desktop-file-utils +Requires(postun): desktop-file-utils + +%if 0%{?enable_autotools} +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: gettext-devel +BuildRequires: libtool +%endif + +BuildRequires: gcc +BuildRequires: pkgconfig(glib-2.0) >= 2.38 +BuildRequires: pkgconfig(gtk+-3.0) >= 3.18 +BuildRequires: pkgconfig(libvirt) >= 0.10.0 +BuildRequires: pkgconfig(libvirt-glib-1.0) >= 0.1.8 +BuildRequires: pkgconfig(libxml-2.0) >= 2.6.0 +BuildRequires: pkgconfig(gtk-vnc-2.0) >= 0.4.0 +%if %{with_spice} +BuildRequires: pkgconfig(spice-client-gtk-3.0) >= 0.35 +BuildRequires: pkgconfig(spice-protocol) >= 0.12.7 +%endif +BuildRequires: /usr/bin/pod2man +BuildRequires: intltool +%if %{with_govirt} +BuildRequires: pkgconfig(govirt-1.0) >= 0.3.2 +%endif + +%if 0%{?fedora} >= 20 +Obsoletes: spice-client < 0.12.3-2 +%endif + + +%description +Virtual Machine Viewer provides a graphical console client for connecting +to virtual machines. It uses the GTK-VNC or SPICE-GTK widgets to provide +the display, and libvirt for looking up VNC/SPICE server details. + +%prep +%setup -q + +%patch001 -p1 +%patch002 -p1 +%patch003 -p1 +%patch004 -p1 +%patch005 -p1 +%patch006 -p1 +%patch007 -p1 + +%patch008 -p1 +%patch009 -p1 + +%patch010 -p1 +%patch011 -p1 +%patch012 -p1 + +%patch013 -p1 +%patch014 -p1 + +%patch015 -p1 +%patch016 -p1 +%patch017 -p1 +%patch018 -p1 +%patch019 -p1 +%patch020 -p1 + +%patch021 -p1 +%patch022 -p1 + +%patch023 -p1 +%patch024 -p1 +%patch025 -p1 +%patch026 -p1 +%patch027 -p1 + +%build + +%if 0%{?enable_autotools} +autoreconf -if +%endif + +%if %{with_spice} +%define spice_arg --with-spice-gtk +%else +%define spice_arg --without-spice-gtk +%endif + +%if %{with_govirt} +%define govirt_arg --with-ovirt +%endif + +%configure %{spice_arg} %{govirt_arg} --with-buildid=%{release} --disable-update-mimedb --with-osid=rhel%{?rhel} +%__make %{?_smp_mflags} V=1 + + +%install +rm -rf $RPM_BUILD_ROOT +%__make install DESTDIR=$RPM_BUILD_ROOT +%find_lang %{name} + +%files -f %{name}.lang +%doc README.md COPYING AUTHORS ChangeLog NEWS +%{_bindir}/%{name} +%{_bindir}/remote-viewer +%{_datadir}/icons/hicolor/*/apps/* +%{_datadir}/icons/hicolor/*/devices/* +%{_datadir}/applications/remote-viewer.desktop +%{_datadir}/appdata/remote-viewer.appdata.xml +%{_datadir}/mime/packages/virt-viewer-mime.xml +%{_mandir}/man1/virt-viewer.1* +%{_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 + +* Mon Jan 18 2021 Uri Lublin - 9.0-8 +- Disable default grab sequence in kiosk mode + Resolves: rhbz#1893584 + +* Mon Jan 11 2021 Uri Lublin - 9.0-7 +- Fix some zoom hotkeys issues + Resolves: rhbz#1791261 + +* Tue Dec 22 2020 Eduardo Lima (Etrunko) - 9.0-6 +- Add back support for DATA storage domains. + Resolves: rhbz#1835640 + +* Thu Dec 03 2020 Uri Lublin - 9.0-5 +- More specific key accelerator description for cursor release + Resolves: rhbz#1548371 +- Report detailed error when file transfer fails + Resolves: rhbz#1753563 +- Update copyright year in "about ui" + Resolves: rhbz#1848267 +- Show an error dialog upon vnc-error + Resolves: rhbz#1448151 +- Fix warning by Coverity + Resolves: rhbz#1876719 + +* Fri Aug 28 2020 Eduardo Lima (Etrunko) - 9.0-4 +- Revert support for DATA storage domains temporarily. + Resolves: rhbz#1873549 + +* Thu Jun 25 2020 Eduardo Lima (Etrunko) - 9.0-3 +- Handle DATA storage domains properly + Resolves: rhbz#1835640 + +* Tue Jun 9 2020 Julien Rope - 9.0-2 +- Display an error when no extension is given to a screenshot. + Resolves: rhbz#1752514 + +* Tue May 19 2020 Eduardo Lima (Etrunko) - 9.0-1 +- Rebase to latest upstream + Resolves: rhbz#1837489 +- Do not filter out DATA storage domains + Resolves: rhbz#1835640 + +* Tue Dec 17 2019 Victor Toso - 7.0-9 +- Always add vm's name to settings file + Related: rhbz#1750706 + +* Tue Aug 27 2019 Eduardo Lima (Etrunko) - 7.0-8 +- Request tolplevel storage domain API object + Related: rhbz#1717900 + +* Mon Aug 19 2019 Kevin Pouget - 7.0-7 +- Improve the error shown to the user when a file transfer fails. + Resolves: rhbz#1496356 + +* Fri Aug 16 2019 Eduardo Lima (Etrunko) - 7.0-6 +- Bypass errors from oVirt foreign menu queries + Resolves: rhbz#1717900 + +* Mon Jul 22 2019 Victor Toso - 7.0-5 +- Listen to SpiceSession::disconnected + Resolves: rhbz#1655957 + +* Wed Mar 20 2019 Victor Toso - 7.0-4 +- Some .spec file changes missed by rebase from F28 on RHEL-8.0 + Resolves: rhbz#1660060 + +* Tue Dec 18 2018 Victor Toso - 7.0-3 +- Fix connection with ovirt + Resolves: rhbz#1584561 + +* Tue Oct 16 2018 Jonathon Jongsma - 7.0-2 +- Fix fullscreen displays on wrong monitors in wayland + Resolves: rhbz#1584561 + +* Fri Jul 27 2018 Daniel P. Berrangé - 7.0-1 +- Update to 7.0 release + +* Sat Jul 14 2018 Fedora Release Engineering - 6.0-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu Jun 28 2018 Fabiano Fidêncio - 6.0-5 +- Add missing patch for spice-controller so being removed + +* Thu Jun 28 2018 Daniel P. Berrangé - 6.0-4 +- Rebuild for spice-controller so being removed + +* Fri Feb 09 2018 Fedora Release Engineering - 6.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Thu Jan 18 2018 Igor Gnatenko - 6.0-2 +- Remove obsolete scriptlets + +* Tue Aug 15 2017 Daniel P. Berrange - 6.0-1 +- Update to 6.0 release + +* Thu Aug 03 2017 Fedora Release Engineering - 5.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 5.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Sat Feb 11 2017 Fedora Release Engineering - 5.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Nov 24 2016 Daniel P. Berrange - 5.0-1 +- Update to 5.0 release + +* Wed Oct 05 2016 Christophe Fergeau 4.0-2 +- Add upstream patch fixing virt-viewer window gradually getting bigger and + bigger + +* Thu Jun 30 2016 Daniel P. Berrange - 4.0-1 +- Update to 4.0 release + +* Wed Jun 22 2016 Christophe Fergeau - 3.0-3 +- Rebuild for spice-gtk ABI break + +* Fri Feb 05 2016 Fedora Release Engineering - 3.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Fri Dec 4 2015 Fabiano Fidêncio - 3.0-1 +- Update to 3.0 release + +* Fri Jun 19 2015 Fedora Release Engineering - 2.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Mon Jan 12 2015 Daniel P. Berrange - 2.0-1 +- Update to 2.0 release + +* Sat Sep 27 2014 Rex Dieter - 1.0-3 +- update/optimize mime scriptlets + +* Mon Aug 18 2014 Fedora Release Engineering - 1.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Mon Jul 21 2014 Daniel P. Berrange - 1.0-1 +- Update to 1.0 release + +* Sun Jun 08 2014 Fedora Release Engineering - 0.6.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed Feb 26 2014 Christophe Fergeau 0.6.0-1 +- Update to 0.6.0 release + +* Tue Nov 26 2013 Christophe Fergeau 0.5.7-2 +- Rebuild for new libgovirt + +* Wed Jul 31 2013 Daniel P. Berrange - 0.5.7-1 +- Update to 0.5.7 release + +* Thu May 23 2013 Christophe Fergeau - 0.5.6-2 +- Mark remote-viewer as replacing spice-client + +* Wed May 1 2013 Daniel P. Berrange - 0.5.6-1 +- Update to 0.5.6 release + +* Wed Feb 13 2013 Daniel P. Berrange - 0.5.5-1 +- Update to 0.5.5 release + +* Fri Dec 14 2012 Cole Robinson - 0.5.4-3 +- Fix crash after entering spice password (bz #880381) + +* Sat Oct 13 2012 Chris Tyler - 0.5.4-2 +- Enabled spice support for ARM archs + +* Mon Sep 17 2012 Daniel P. Berrange - 0.5.4-1 +- Update to 0.5.4 release + +* Fri Sep 14 2012 Hans de Goede - 0.5.3-6 +- Rebuild for spice-gtk ABI breakage (previous spice-gtk build was borked) + +* Tue Sep 11 2012 Hans de Goede - 0.5.3-5 +- Rebuild for spice-gtk ABI breakage + +* Fri Sep 7 2012 Hans de Goede - 0.5.3-4 +- Rebuild for spice-gtk soname change + +* Mon Aug 13 2012 Daniel P. Berrange - 0.5.3-3 +- Rebuild for spice-gtk soname change + +* Sun Jul 22 2012 Fedora Release Engineering - 0.5.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Wed May 16 2012 Daniel P. Berrange - 0.5.3-1 +- Update to 0.5.3 release + +* Fri Mar 9 2012 Daniel P. Berrange - 0.5.2-1 +- Update to 0.5.2 release + +* Fri Feb 17 2012 Daniel P. Berrange - 0.5.1-1 +- Update to 0.5.1 release + +* Tue Feb 14 2012 Daniel P. Berrange - 0.5.0-1 +- Update to 0.5.0 release + +* Sat Jan 14 2012 Fedora Release Engineering - 0.4.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Nov 9 2011 Daniel P. Berrange - 0.4.2-1 +- Update to 0.4.2 release + +* Sun Aug 14 2011 Daniel P. Berrange - 0.4.1-3 +- More ssh tunnelling port fixes + +* Fri Aug 12 2011 Daniel P. Berrange - 0.4.1-2 +- Fix ssh tunnelling + +* Thu Aug 4 2011 Daniel P. Berrange - 0.4.1-1 +- Update to 0.4.1 release + +* Tue Aug 2 2011 Daniel P. Berrange - 0.4.0-2 +- Rebuild for accidental spice-glib soname change + +* Tue Jul 12 2011 Daniel P. Berrange - 0.4.0-1 +- Update to 0.4.0 release +- Switch build to GTK3 instead of GTK2 + +* Tue May 31 2011 Daniel P. Berrange - 0.3.1-2 +- Rebuild for spice-glib ABI breakage + +* Wed May 11 2011 Karsten Hopp 0.3.1-1.1 +- spice-gtk is x86 x86_64 only, don't require it on other archs + +* Mon Feb 21 2011 Daniel P. Berrange - 0.3.1-1 +- Update to 0.3.1 release + +* Mon Feb 21 2011 Daniel P. Berrange - 0.3.0-1 +- Update to 0.3.0 and enable SPICE + +* Mon Feb 07 2011 Fedora Release Engineering - 0.2.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Fri Jan 15 2010 Daniel P. Berrange - 0.2.1-1 +- Update to 0.2.1 release + +* Wed Jul 29 2009 Daniel P. Berrange - 0.2.0-1.fc12 +- Update to 0.2.0 release + +* Sun Jul 26 2009 Fedora Release Engineering - 0.0.3-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu May 7 2009 Daniel P. Berrange - 0.0.3-5.fc12 +- Fix auth against libvirt (rhbz #499594) +- Fix confusion of VNC credentials (rhbz #499595) +- Correct keyboard grab handling (rhbz #499362) + +* Wed Feb 25 2009 Fedora Release Engineering - 0.0.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Mon Jul 7 2008 Tom "spot" Callaway - 0.0.3-3.fc10 +- fix conditional comparison +- remove file dep + +* Wed Jun 25 2008 Daniel P. Berrange - 0.0.3-2.fc10 +- Rebuild for GNU TLS ABI bump + +* Mon Mar 10 2008 Daniel P. Berrange - 0.0.3-1.fc9 +- Updated to 0.0.3 release + +* Mon Feb 18 2008 Fedora Release Engineering - 0.0.2-4 +- Autorebuild for GCC 4.3 + +* Fri Jan 11 2008 Daniel P. Berrange - 0.0.2-3.fc9 +- Set domain name as window title +- Hide input for passwd fields during auth + +* Mon Oct 15 2007 Daniel P. Berrange - 0.0.2-2.fc8 +- Change TLS x509 credential name to sync with libvirt + +* Tue Aug 28 2007 Daniel P. Berrange - 0.0.2-1.fc8 +- Added support for remote console access + +* Fri Aug 17 2007 Daniel P. Berrange - 0.0.1-2.fc8 +- Restrict built to x86 & ia64 because libvirt is only on those arches + +* Wed Aug 15 2007 Daniel P. Berrange - 0.0.1-1.fc8 +- First release