From f0cc7103becccbce95bdf0c80151178af2bace5a Mon Sep 17 00:00:00 2001 From: Paul Donohue Date: Sun, 25 Apr 2021 11:58:44 -0400 Subject: [PATCH] src: Support modifier-only hotkey for release-cursor This is implemented by switching from GTK accelerators to using the display's grab sequence handling when a modifier-only hotkey is configured. Signed-off-by: Paul Donohue --- src/virt-viewer-app.c | 64 +++++++++------- src/virt-viewer-app.h | 4 +- src/virt-viewer-display-spice.c | 35 ++++----- src/virt-viewer-display-vnc.c | 35 ++++----- src/virt-viewer-file.c | 2 - src/virt-viewer-util.c | 127 ++++++++++++++++++++++++++++++++ src/virt-viewer-util.h | 1 + src/virt-viewer-window.c | 62 +++++++++------- 8 files changed, 235 insertions(+), 95 deletions(-) diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c index adcec5a..e834a3e 100644 --- a/src/virt-viewer-app.c +++ b/src/virt-viewer-app.c @@ -131,7 +131,6 @@ struct _VirtViewerAppPrivate { GResource *resource; gboolean direct; gboolean verbose; - gboolean enable_accel; gboolean authretry; gboolean started; gboolean fullscreen; @@ -166,6 +165,7 @@ struct _VirtViewerAppPrivate { GKeyFile *config; gchar *config_file; + gchar *release_cursor_display_hotkey; gchar **insert_smartcard_accel; gchar **remove_smartcard_accel; gchar **usb_device_reset_accel; @@ -185,7 +185,7 @@ enum { PROP_GURI, PROP_FULLSCREEN, PROP_TITLE, - PROP_ENABLE_ACCEL, + PROP_RELEASE_CURSOR_DISPLAY_HOTKEY, PROP_KIOSK, PROP_QUIT_ON_DISCONNECT, PROP_UUID, @@ -1930,8 +1930,8 @@ virt_viewer_app_get_property (GObject *object, guint property_id, g_value_set_string(value, virt_viewer_app_get_title(self)); break; - case PROP_ENABLE_ACCEL: - g_value_set_boolean(value, virt_viewer_app_get_enable_accel(self)); + case PROP_RELEASE_CURSOR_DISPLAY_HOTKEY: + g_value_set_string(value, virt_viewer_app_get_release_cursor_display_hotkey(self)); break; case PROP_KIOSK: @@ -2001,8 +2001,8 @@ virt_viewer_app_set_property (GObject *object, guint property_id, priv->title = g_value_dup_string(value); break; - case PROP_ENABLE_ACCEL: - virt_viewer_app_set_enable_accel(self, g_value_get_boolean(value)); + case PROP_RELEASE_CURSOR_DISPLAY_HOTKEY: + virt_viewer_app_set_release_cursor_display_hotkey(self, g_value_dup_string(value)); break; case PROP_KIOSK: @@ -2089,6 +2089,8 @@ virt_viewer_app_dispose (GObject *object) priv->uuid = NULL; g_free(priv->config_file); priv->config_file = NULL; + g_free(priv->release_cursor_display_hotkey); + priv->release_cursor_display_hotkey = NULL; g_strfreev(priv->insert_smartcard_accel); priv->insert_smartcard_accel = NULL; g_strfreev(priv->remove_smartcard_accel); @@ -2496,6 +2498,7 @@ virt_viewer_app_on_application_startup(GApplication *app) virt_viewer_app_set_kiosk(self, opt_kiosk); + priv->release_cursor_display_hotkey = NULL; hotkey_names = g_new(gchar*, G_N_ELEMENTS(hotkey_defaults) + 1); for (i = 0 ; i < G_N_ELEMENTS(hotkey_defaults); i++) { hotkey_names[i] = g_strdup(hotkey_defaults[i].name); @@ -2699,14 +2702,13 @@ virt_viewer_app_class_init (VirtViewerAppClass *klass) G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, - PROP_ENABLE_ACCEL, - g_param_spec_boolean("enable-accel", - "Enable Accel", - "Enable accelerators", - FALSE, - G_PARAM_CONSTRUCT | - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); + PROP_RELEASE_CURSOR_DISPLAY_HOTKEY, + g_param_spec_string("release-cursor-display-hotkey", + "Release Cursor Display Hotkey", + "Display-managed hotkey to ungrab keyboard and mouse", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_KIOSK, @@ -2828,21 +2830,24 @@ gboolean virt_viewer_app_get_direct(VirtViewerApp *self) return priv->direct; } -gboolean -virt_viewer_app_get_enable_accel(VirtViewerApp *self) +gchar* +virt_viewer_app_get_release_cursor_display_hotkey(VirtViewerApp *self) { - g_return_val_if_fail(VIRT_VIEWER_IS_APP(self), FALSE); + g_return_val_if_fail(VIRT_VIEWER_IS_APP(self), NULL); VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self); - return priv->enable_accel; + return priv->release_cursor_display_hotkey; } void -virt_viewer_app_set_enable_accel(VirtViewerApp *self, gboolean enable) +virt_viewer_app_set_release_cursor_display_hotkey(VirtViewerApp *self, const gchar *hotkey) { + g_return_if_fail(VIRT_VIEWER_IS_APP(self)); + VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self); - priv->enable_accel = enable; - g_object_notify(G_OBJECT(self), "enable-accel"); + g_free(priv->release_cursor_display_hotkey); + priv->release_cursor_display_hotkey = g_strdup(hotkey); + g_object_notify(G_OBJECT(self), "release-cursor-display-hotkey"); } gchar** @@ -2863,6 +2868,7 @@ virt_viewer_app_clear_hotkeys(VirtViewerApp *self) } g_return_if_fail(VIRT_VIEWER_IS_APP(self)); + virt_viewer_app_set_release_cursor_display_hotkey(self, "Control_L+Alt_L"); VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self); g_strfreev(priv->insert_smartcard_accel); priv->insert_smartcard_accel = NULL; @@ -2909,7 +2915,18 @@ virt_viewer_app_set_hotkey(VirtViewerApp *self, const gchar *hotkey_name, accels[0] = hotkey; gtk_accelerator_parse(accels[0], &accel_key, &accel_mods); } - if (accel_key == 0 && accel_mods == 0) { + if (g_str_equal(hotkey_name, "release-cursor")) { + if (accel_key == 0) { + /* GTK does not support using modifiers as hotkeys without any non-modifiers + * (eg. CTRL+ALT), however the displays do support this for the grab sequence. + */ + virt_viewer_app_set_release_cursor_display_hotkey(self, hotkey); + g_free(accel); + return; + } + virt_viewer_app_set_release_cursor_display_hotkey(self, NULL); + } + if (accel_key == 0) { g_warning("Invalid hotkey '%s' for '%s'", hotkey, hotkey_name); g_free(accel); return; @@ -2953,7 +2970,6 @@ virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys_str) if (!hotkeys || g_strv_length(hotkeys) == 0) { g_strfreev(hotkeys); - virt_viewer_app_set_enable_accel(self, FALSE); return; } @@ -2970,8 +2986,6 @@ virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys_str) virt_viewer_app_set_hotkey(self, *hotkey, value); } g_strfreev(hotkeys); - - virt_viewer_app_set_enable_accel(self, TRUE); } void diff --git a/src/virt-viewer-app.h b/src/virt-viewer-app.h index 5281ab6..f0062b5 100644 --- a/src/virt-viewer-app.h +++ b/src/virt-viewer-app.h @@ -73,6 +73,8 @@ gboolean virt_viewer_app_initial_connect(VirtViewerApp *self, GError **error); gboolean virt_viewer_app_get_direct(VirtViewerApp *self); void virt_viewer_app_set_direct(VirtViewerApp *self, gboolean direct); char** virt_viewer_app_get_hotkey_names(void); +gchar* virt_viewer_app_get_release_cursor_display_hotkey(VirtViewerApp *self); +void virt_viewer_app_set_release_cursor_display_hotkey(VirtViewerApp *self, const gchar *hotkey); void virt_viewer_app_set_hotkey(VirtViewerApp *self, const gchar *hotkey_name, const gchar *hotkey); void virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys); void virt_viewer_app_set_attach(VirtViewerApp *self, gboolean attach); @@ -96,13 +98,11 @@ void virt_viewer_app_set_connect_info(VirtViewerApp *self, void virt_viewer_app_show_status(VirtViewerApp *self, const gchar *fmt, ...) G_GNUC_PRINTF(2, 3); void virt_viewer_app_show_display(VirtViewerApp *self); GList* virt_viewer_app_get_windows(VirtViewerApp *self); -gboolean virt_viewer_app_get_enable_accel(VirtViewerApp *self); VirtViewerSession* virt_viewer_app_get_session(VirtViewerApp *self); gboolean virt_viewer_app_get_fullscreen(VirtViewerApp *app); void virt_viewer_app_clear_hotkeys(VirtViewerApp *app); GList* virt_viewer_app_get_initial_displays(VirtViewerApp* self); gint virt_viewer_app_get_initial_monitor_for_display(VirtViewerApp* self, gint display); -void virt_viewer_app_set_enable_accel(VirtViewerApp *app, gboolean enable); void virt_viewer_app_show_preferences(VirtViewerApp *app, GtkWidget *parent); gboolean virt_viewer_app_get_session_cancelled(VirtViewerApp *self); diff --git a/src/virt-viewer-display-spice.c b/src/virt-viewer-display-spice.c index fba2fdb..2265f02 100644 --- a/src/virt-viewer-display-spice.c +++ b/src/virt-viewer-display-spice.c @@ -233,31 +233,26 @@ zoom_level_changed(VirtViewerDisplaySpice *self, } static void -enable_accel_changed(VirtViewerApp *app, - GParamSpec *pspec G_GNUC_UNUSED, - VirtViewerDisplaySpice *self) +release_cursor_display_hotkey_changed(VirtViewerApp *app, + GParamSpec *pspec G_GNUC_UNUSED, + VirtViewerDisplaySpice *self) { gboolean kiosk; - guint accel_key = 0; - GdkModifierType accel_mods = 0; - gchar **accels; - - if (virt_viewer_app_get_enable_accel(app)){ - accels = gtk_application_get_accels_for_action(GTK_APPLICATION(app), "win.release-cursor"); - if (accels[0]) - gtk_accelerator_parse(accels[0], &accel_key, &accel_mods); - g_strfreev(accels); - } - + gchar *hotkey; g_object_get(app, "kiosk", &kiosk, NULL); + hotkey = virt_viewer_app_get_release_cursor_display_hotkey(app); - if (accel_key || accel_mods || kiosk) { - SpiceGrabSequence *seq = spice_grab_sequence_new(0, NULL); + if (kiosk || hotkey == NULL) { /* disable default grab sequence */ + SpiceGrabSequence *seq = spice_grab_sequence_new(0, NULL); spice_display_set_grab_keys(self->display, seq); spice_grab_sequence_free(seq); } else { - spice_display_set_grab_keys(self->display, NULL); + hotkey = spice_hotkey_to_display_hotkey(hotkey); + SpiceGrabSequence *seq = spice_grab_sequence_new_from_string(hotkey); + g_free(hotkey); + spice_display_set_grab_keys(self->display, seq); + spice_grab_sequence_free(seq); } } @@ -337,8 +332,8 @@ virt_viewer_display_spice_new(VirtViewerSessionSpice *session, app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(session)); - virt_viewer_signal_connect_object(app, "notify::enable-accel", - G_CALLBACK(enable_accel_changed), self, 0); + virt_viewer_signal_connect_object(app, "notify::release-cursor-display-hotkey", + G_CALLBACK(release_cursor_display_hotkey_changed), self, 0); virt_viewer_signal_connect_object(self, "notify::fullscreen", G_CALLBACK(resize_policy_changed), app, 0); virt_viewer_signal_connect_object(self, "notify::auto-resize", @@ -346,7 +341,7 @@ virt_viewer_display_spice_new(VirtViewerSessionSpice *session, virt_viewer_signal_connect_object(self, "notify::zoom-level", G_CALLBACK(zoom_level_changed), app, 0); resize_policy_changed(self, NULL, app); - enable_accel_changed(app, NULL, self); + release_cursor_display_hotkey_changed(app, NULL, self); return GTK_WIDGET(self); } diff --git a/src/virt-viewer-display-vnc.c b/src/virt-viewer-display-vnc.c index 5ee253b..5b28cd2 100644 --- a/src/virt-viewer-display-vnc.c +++ b/src/virt-viewer-display-vnc.c @@ -192,31 +192,26 @@ virt_viewer_display_vnc_resize_desktop(VncDisplay *vnc G_GNUC_UNUSED, static void -enable_accel_changed(VirtViewerApp *app, - GParamSpec *pspec G_GNUC_UNUSED, - VncDisplay *vnc) +release_cursor_display_hotkey_changed(VirtViewerApp *app, + GParamSpec *pspec G_GNUC_UNUSED, + VncDisplay *vnc) { gboolean kiosk; - guint accel_key = 0; - GdkModifierType accel_mods = 0; - gchar **accels; - - if (virt_viewer_app_get_enable_accel(app)){ - accels = gtk_application_get_accels_for_action(GTK_APPLICATION(app), "win.release-cursor"); - if (accels[0]) - gtk_accelerator_parse(accels[0], &accel_key, &accel_mods); - g_strfreev(accels); - } - + gchar *hotkey; g_object_get(app, "kiosk", &kiosk, NULL); + hotkey = virt_viewer_app_get_release_cursor_display_hotkey(app); - if (accel_key || accel_mods || kiosk) { - VncGrabSequence *seq = vnc_grab_sequence_new(0, NULL); + if(kiosk || hotkey == NULL) { /* disable default grab sequence */ + VncGrabSequence *seq = vnc_grab_sequence_new(0, NULL); vnc_display_set_grab_keys(vnc, seq); vnc_grab_sequence_free(seq); } else { - vnc_display_set_grab_keys(vnc, NULL); + hotkey = spice_hotkey_to_display_hotkey(hotkey); + VncGrabSequence *seq = vnc_grab_sequence_new_from_string(hotkey); + g_free(hotkey); + vnc_display_set_grab_keys(vnc, seq); + vnc_grab_sequence_free(seq); } } @@ -293,9 +288,9 @@ virt_viewer_display_vnc_new(VirtViewerSessionVnc *session, G_CALLBACK(virt_viewer_display_vnc_initialized), self); app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(session)); - virt_viewer_signal_connect_object(app, "notify::enable-accel", - G_CALLBACK(enable_accel_changed), self->vnc, 0); - enable_accel_changed(app, NULL, self->vnc); + virt_viewer_signal_connect_object(app, "notify::release-cursor-display-hotkey", + G_CALLBACK(release_cursor_display_hotkey_changed), self->vnc, 0); + release_cursor_display_hotkey_changed(app, NULL, self->vnc); #ifdef HAVE_VNC_REMOTE_RESIZE virt_viewer_signal_connect_object(self, "notify::auto-resize", diff --git a/src/virt-viewer-file.c b/src/virt-viewer-file.c index c1312e6..71029bc 100644 --- a/src/virt-viewer-file.c +++ b/src/virt-viewer-file.c @@ -970,8 +970,6 @@ virt_viewer_file_fill_app(VirtViewerFile* self, VirtViewerApp *app, GError **err } } - virt_viewer_app_set_enable_accel(app, TRUE); - if (virt_viewer_file_is_set(self, "fullscreen")) g_object_set(G_OBJECT(app), "fullscreen", virt_viewer_file_get_fullscreen(self), NULL); diff --git a/src/virt-viewer-util.c b/src/virt-viewer-util.c index 492cd24..1c13236 100644 --- a/src/virt-viewer-util.c +++ b/src/virt-viewer-util.c @@ -434,6 +434,133 @@ spice_hotkey_to_gtk_accelerator(const gchar *key) return accel; } +static gchar * +spice_key_to_gdk_key(const gchar *spice_key) +{ + guint i; + gchar *key = g_strdup(spice_key); + + static const struct { + const char *spice; + const char *gdk; + } keys[] = { + + { "alt", "Alt_L" }, + { "lalt", "Alt_L" }, + { "leftalt", "Alt_L" }, + { "left-alt", "Alt_L" }, + { "ralt", "Alt_R" }, + { "rightalt", "Alt_R" }, + { "right-alt", "Alt_R" }, + + { "ctrl", "Control_L" }, + { "ctl", "Control_L" }, + { "control", "Control_L" }, + { "lctrl", "Control_L" }, + { "leftctrl", "Control_L" }, + { "left-ctrl", "Control_L" }, + { "rctrl", "Control_R" }, + { "rightctrl", "Control_R" }, + { "right-ctrl", "Control_R" }, + + { "cmd", "Control_L" }, + { "lcmd", "Control_L" }, + { "leftcmd", "Control_L" }, + { "left-cmd", "Control_L" }, + { "rcmd", "Control_R" }, + { "rightcmd", "Control_R" }, + { "right-cmd", "Control_R" }, + + { "shift", "Shift_L" }, + { "shft", "Shift_L" }, + { "lshift", "Shift_L" }, + { "leftshift", "Shift_L" }, + { "left-shift", "Shift_L" }, + { "rshift", "Shift_R" }, + { "rightshift", "Shift_R" }, + { "right-shift", "Shift_R" }, + + { "win", "Super_L" }, + { "lwin", "Super_L" }, + { "leftwin", "Super_L" }, + { "left-win", "Super_L" }, + { "rwin", "Super_R" }, + { "rightwin", "Super_R" }, + { "right-win", "Super_R" }, + + { "super", "Super_L" }, + { "hyper", "Hyper_L" }, + { "meta", "Meta_L" }, + + { "esc", "Escape" }, + { "escape", "Escape" }, + { "ins", "Insert" }, + { "insert", "Insert" }, + { "del", "Delete" }, + { "delete", "Delete" }, + + { "pgup", "Page_Up" }, + { "pageup", "Page_Up" }, + { "pgdn", "Page_Down" }, + { "pagedown", "Page_Down" }, + + { "home", "Home" }, + { "end", "End" }, + { "space", "space" }, + + { "enter", "Return" }, + + { "tab", "Tab" }, + { "f1", "F1" }, + { "f2", "F2" }, + { "f3", "F3" }, + { "f4", "F4" }, + { "f5", "F5" }, + { "f6", "F6" }, + { "f7", "F7" }, + { "f8", "F8" }, + { "f9", "F9" }, + { "f10", "F10" }, + { "f11", "F11" }, + { "f12", "F12" }, + }; + + if (key[0] == '<' && key[strlen(key)-1] == '>') { + gchar *tmp = key; + key = g_strndup(key+1, strlen(key)-2); + g_free(tmp); + } + + for (i = 0; i < G_N_ELEMENTS(keys); ++i) { + if (g_ascii_strcasecmp(keys[i].spice, key) == 0) { + g_free(key); + return g_strdup(keys[i].gdk); + } + } + + return key; +} + +gchar* +spice_hotkey_to_display_hotkey(const gchar *key) +{ + gchar *new_key, **k, **keyv; + + keyv = g_strsplit(key, "+", -1); + g_return_val_if_fail(keyv != NULL, NULL); + + for (k = keyv; *k != NULL; k++) { + gchar *tmp = *k; + *k = spice_key_to_gdk_key(tmp); + g_free(tmp); + } + + new_key = g_strjoinv("+", keyv); + g_strfreev(keyv); + + return new_key; +} + static gboolean str_is_empty(const gchar *str) { return ((str == NULL) || (str[0] == '\0')); diff --git a/src/virt-viewer-util.h b/src/virt-viewer-util.h index 57e5725..5420a63 100644 --- a/src/virt-viewer-util.h +++ b/src/virt-viewer-util.h @@ -54,6 +54,7 @@ gulong virt_viewer_signal_connect_object(gpointer instance, GConnectFlags connect_flags); gchar* spice_hotkey_to_gtk_accelerator(const gchar *key); +gchar* spice_hotkey_to_display_hotkey(const gchar *key); gint virt_viewer_compare_buildid(const gchar *s1, const gchar *s2); /* monitor alignment */ diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c index b65fdf6..fe740ce 100644 --- a/src/virt-viewer-window.c +++ b/src/virt-viewer-window.c @@ -224,7 +224,7 @@ virt_viewer_window_constructed(GObject *object) if (G_OBJECT_CLASS(virt_viewer_window_parent_class)->constructed) G_OBJECT_CLASS(virt_viewer_window_parent_class)->constructed(object); - g_signal_connect(self->app, "notify::enable-accel", + g_signal_connect(self->app, "notify::release-cursor-display-hotkey", G_CALLBACK(rebuild_combo_menu), object); rebuild_combo_menu(NULL, NULL, object); } @@ -872,34 +872,48 @@ virt_viewer_window_get_keycombo_menu(VirtViewerWindow *self) } } - if (virt_viewer_app_get_enable_accel(self->app)) { - gchar **accelactions = gtk_application_list_action_descriptions(GTK_APPLICATION(self->app)); + gchar **accelactions = gtk_application_list_action_descriptions(GTK_APPLICATION(self->app)); - sectionitems = g_menu_new(); - section = g_menu_item_new_section(NULL, G_MENU_MODEL(sectionitems)); - g_menu_append_item(menu, section); + sectionitems = g_menu_new(); + section = g_menu_item_new_section(NULL, G_MENU_MODEL(sectionitems)); + g_menu_append_item(menu, section); - for (i = 0; accelactions[i] != NULL; i++) { - gchar **accels = gtk_application_get_accels_for_action(GTK_APPLICATION(self->app), - accelactions[i]); - - for (j = 0; accels[j] != NULL; j++) { + for (i = 0; accelactions[i] != NULL; i++) { + if (g_str_equal(accelactions[i], "win.release-cursor")) { + gchar *display_hotkey = virt_viewer_app_get_release_cursor_display_hotkey(self->app); + if (display_hotkey) { + gchar *accel = spice_hotkey_to_gtk_accelerator(display_hotkey); guint accel_key; GdkModifierType accel_mods; - gtk_accelerator_parse(accels[j], &accel_key, &accel_mods); + gtk_accelerator_parse(accel, &accel_key, &accel_mods); guint *keys = accel_key_to_keys(accel_key, accel_mods); - gchar *label = gtk_accelerator_get_label(accel_key, accel_mods); + gchar *label = spice_hotkey_to_display_hotkey(display_hotkey); virt_viewer_menu_add_combo(self, sectionitems, keys, label); g_free(label); g_free(keys); } - g_strfreev(accels); } - g_strfreev(accelactions); + gchar **accels = gtk_application_get_accels_for_action(GTK_APPLICATION(self->app), + accelactions[i]); + + for (j = 0; accels[j] != NULL; j++) { + guint accel_key; + GdkModifierType accel_mods; + gtk_accelerator_parse(accels[j], &accel_key, &accel_mods); + + guint *keys = accel_key_to_keys(accel_key, accel_mods); + gchar *label = gtk_accelerator_get_label(accel_key, accel_mods); + virt_viewer_menu_add_combo(self, sectionitems, keys, label); + g_free(label); + g_free(keys); + } + g_strfreev(accels); } + g_strfreev(accelactions); + return menu; } @@ -921,9 +935,7 @@ virt_viewer_window_disable_modifiers(VirtViewerWindow *self) /* This stops global accelerators like Ctrl+Q == Quit */ for (accels = self->accel_list ; accels ; accels = accels->next) { - if (virt_viewer_app_get_enable_accel(self->app) && - self->accel_group == accels->data && - !self->kiosk) + if (self->accel_group == accels->data && !self->kiosk) continue; gtk_window_remove_accel_group(GTK_WINDOW(self->window), accels->data); } @@ -1292,25 +1304,25 @@ virt_viewer_window_update_title(VirtViewerWindow *self) if (self->grabbed) { gchar *label; + gchar *display_hotkey; guint accel_key = 0; GdkModifierType accel_mods = 0; gchar **accels; - if (virt_viewer_app_get_enable_accel(self->app)) { + display_hotkey = virt_viewer_app_get_release_cursor_display_hotkey(self->app); + if (display_hotkey) { + label = spice_hotkey_to_display_hotkey(display_hotkey); + } else { accels = gtk_application_get_accels_for_action(GTK_APPLICATION(self->app), "win.release-cursor"); if (accels[0]) gtk_accelerator_parse(accels[0], &accel_key, &accel_mods); g_strfreev(accels); - } - - if (accel_key || accel_mods) { g_debug("release-cursor accel key: key=%u, mods=%x", accel_key, accel_mods); label = gtk_accelerator_get_label(accel_key, accel_mods); - } else { - label = g_strdup(_("Ctrl_L+Alt_L")); } grabhint = g_strdup_printf(_("(Press %s to release pointer)"), label); + g_free(label); if (self->subtitle) { /* translators: @@ -1330,8 +1342,6 @@ virt_viewer_window_update_title(VirtViewerWindow *self) grabhint, g_get_application_name()); } - - g_free(label); } else if (self->subtitle) { /* translators: * This is " - "