src: convert accelerator handling over to actions

This better decouples the accelerator handling from the current user
interface design.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2021-02-12 12:21:05 +00:00
parent 407836ecee
commit 2f11e0a407
5 changed files with 186 additions and 228 deletions

View File

@ -162,12 +162,9 @@ struct _VirtViewerAppPrivate {
GKeyFile *config;
gchar *config_file;
guint insert_smartcard_accel_key;
GdkModifierType insert_smartcard_accel_mods;
guint remove_smartcard_accel_key;
GdkModifierType remove_smartcard_accel_mods;
guint usb_device_reset_accel_key;
GdkModifierType usb_device_reset_accel_mods;
gchar **insert_smartcard_accel;
gchar **remove_smartcard_accel;
gchar **usb_device_reset_accel;
gboolean quit_on_disconnect;
gboolean supports_share_clipboard;
VirtViewerKeyMapping *keyMappings;
@ -2130,28 +2127,6 @@ virt_viewer_app_init(VirtViewerApp *self)
g_signal_connect(self, "notify::guri", G_CALLBACK(title_maybe_changed), NULL);
}
static void
virt_viewer_set_insert_smartcard_accel(VirtViewerApp *self,
guint accel_key,
GdkModifierType accel_mods)
{
VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self);
priv->insert_smartcard_accel_key = accel_key;
priv->insert_smartcard_accel_mods = accel_mods;
}
static void
virt_viewer_set_remove_smartcard_accel(VirtViewerApp *self,
guint accel_key,
GdkModifierType accel_mods)
{
VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self);
priv->remove_smartcard_accel_key = accel_key;
priv->remove_smartcard_accel_mods = accel_mods;
}
static void
virt_viewer_update_smartcard_accels(VirtViewerApp *self)
{
@ -2166,38 +2141,30 @@ virt_viewer_update_smartcard_accels(VirtViewerApp *self)
sw_smartcard = FALSE;
}
if (sw_smartcard) {
gboolean r;
g_debug("enabling smartcard shortcuts");
r = gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-insert",
priv->insert_smartcard_accel_key,
priv->insert_smartcard_accel_mods,
TRUE);
if (!r)
g_warning("Unable to set hotkey for 'smartcard-insert' due to a conflict in GTK");
r = gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-remove",
priv->remove_smartcard_accel_key,
priv->remove_smartcard_accel_mods,
TRUE);
if (!r)
g_warning("Unable to set hotkey for 'smartcard-remove' due to a conflict in GTK");
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "app.smartcard-insert",
(const gchar * const *)priv->insert_smartcard_accel);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "app.smartcard-remove",
(const gchar * const *)priv->remove_smartcard_accel);
} else {
g_debug("disabling smartcard shortcuts");
gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-insert", 0, 0, TRUE);
gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-remove", 0, 0, TRUE);
const gchar *no_accels[] = { NULL };
char **old_insert_accels = gtk_application_get_accels_for_action(GTK_APPLICATION(self), "win.smartcard-insert");
char **old_remove_accels = gtk_application_get_accels_for_action(GTK_APPLICATION(self), "win.smartcard-remove");
if (old_insert_accels) {
g_strfreev(priv->insert_smartcard_accel);
priv->insert_smartcard_accel = old_insert_accels;
}
if (old_remove_accels) {
g_strfreev(priv->remove_smartcard_accel);
priv->remove_smartcard_accel = old_remove_accels;
}
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.smartcard-insert", no_accels);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.smartcard-remove", no_accels);
}
}
static void
virt_viewer_set_usb_device_reset_accel(VirtViewerApp *self,
guint accel_key,
GdkModifierType accel_mods)
{
VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self);
priv->usb_device_reset_accel_key = accel_key;
priv->usb_device_reset_accel_mods = accel_mods;
}
static void
virt_viewer_update_usbredir_accels(VirtViewerApp *self)
{
@ -2212,12 +2179,17 @@ virt_viewer_update_usbredir_accels(VirtViewerApp *self)
}
if (has_usbredir) {
gtk_accel_map_change_entry("<virt-viewer>/file/usb-device-reset",
priv->usb_device_reset_accel_key,
priv->usb_device_reset_accel_mods,
TRUE);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.usb-device-reset",
(const gchar * const *)priv->usb_device_reset_accel);
} else {
gtk_accel_map_change_entry("<virt-viewer>/file/usb-device-reset", 0, 0, TRUE);
const gchar *no_accels[] = { NULL };
char **old_accels = gtk_application_get_accels_for_action(GTK_APPLICATION(self), "win.usb-device-reset");
if (old_accels) {
g_strfreev(priv->usb_device_reset_accel);
priv->usb_device_reset_accel = old_accels;
}
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.usb-device-reset", no_accels);
}
}
@ -2388,12 +2360,30 @@ static GActionEntry actions[] = {
.activate = virt_viewer_app_action_smartcard_remove },
};
struct VirtViewerActionAccels {
const char *action;
const char *accels[3];
};
static const struct VirtViewerActionAccels action_accels[] = {
{ "win.fullscreen", {"F11", NULL, NULL} },
{ "win.zoom-in", { "<Ctrl>plus", "<Ctrl>KP_Add", NULL } },
{ "win.zoom-out", { "<Ctrl>minus", "<Ctrl>KP_Subtract", NULL } },
{ "win.zoom-reset", { "<Ctrl>0", "<Ctrl>KP_0", NULL } },
{ "win.release-cursor", {"<Shift>F12", NULL, NULL} },
{ "app.smartcard-insert", {"<Shift>F8", NULL, NULL} },
{ "app.smartcard-remove", {"<Shift>F9", NULL, NULL} },
{ "win.secure-attention", {"<Ctrl><Alt>End", NULL, NULL} },
{ "win.usb-device-reset", {"<Ctrl><Shift>r", NULL, NULL} },
};
static void
virt_viewer_app_on_application_startup(GApplication *app)
{
VirtViewerApp *self = VIRT_VIEWER_APP(app);
VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self);
GError *error = NULL;
gint i;
G_APPLICATION_CLASS(virt_viewer_app_parent_class)->startup(app);
@ -2404,6 +2394,12 @@ virt_viewer_app_on_application_startup(GApplication *app)
priv->resource = virt_viewer_get_resource();
for (i = 0 ; i < G_N_ELEMENTS(action_accels); i++) {
gtk_application_set_accels_for_action(GTK_APPLICATION(app),
action_accels[i].action,
action_accels[i].accels);
}
virt_viewer_app_set_debug(opt_debug);
virt_viewer_app_set_fullscreen(self, opt_fullscreen);
@ -2427,17 +2423,6 @@ virt_viewer_app_on_application_startup(GApplication *app)
virt_viewer_window_set_zoom_level(priv->main_window, opt_zoom);
virt_viewer_set_insert_smartcard_accel(self, GDK_KEY_F8, GDK_SHIFT_MASK);
virt_viewer_set_remove_smartcard_accel(self, GDK_KEY_F9, GDK_SHIFT_MASK);
virt_viewer_set_usb_device_reset_accel(self, GDK_KEY_r, GDK_SHIFT_MASK | GDK_CONTROL_MASK);
gtk_accel_map_add_entry("<virt-viewer>/view/toggle-fullscreen", GDK_KEY_F11, 0);
gtk_accel_map_add_entry("<virt-viewer>/view/release-cursor", GDK_KEY_F12, GDK_SHIFT_MASK);
gtk_accel_map_add_entry("<virt-viewer>/view/zoom-reset", GDK_KEY_0, GDK_CONTROL_MASK);
gtk_accel_map_add_entry("<virt-viewer>/view/zoom-out", GDK_KEY_minus, GDK_CONTROL_MASK);
gtk_accel_map_add_entry("<virt-viewer>/view/zoom-in", GDK_KEY_plus, GDK_CONTROL_MASK);
gtk_accel_map_add_entry("<virt-viewer>/send/secure-attention", GDK_KEY_End, GDK_CONTROL_MASK | GDK_MOD1_MASK);
// Restore initial state of config-share-clipboard property from config and notify about it
virt_viewer_app_set_config_share_clipboard(self, virt_viewer_app_get_config_share_clipboard(self));
@ -2675,16 +2660,14 @@ gboolean virt_viewer_app_get_direct(VirtViewerApp *self)
void
virt_viewer_app_clear_hotkeys(VirtViewerApp *self)
{
/* Disable default bindings and replace them with our own */
gtk_accel_map_change_entry("<virt-viewer>/view/toggle-fullscreen", 0, 0, TRUE);
gtk_accel_map_change_entry("<virt-viewer>/view/release-cursor", 0, 0, TRUE);
gtk_accel_map_change_entry("<virt-viewer>/view/zoom-reset", 0, 0, TRUE);
gtk_accel_map_change_entry("<virt-viewer>/view/zoom-in", 0, 0, TRUE);
gtk_accel_map_change_entry("<virt-viewer>/view/zoom-out", 0, 0, TRUE);
gtk_accel_map_change_entry("<virt-viewer>/send/secure-attention", 0, 0, TRUE);
virt_viewer_set_insert_smartcard_accel(self, 0, 0);
virt_viewer_set_remove_smartcard_accel(self, 0, 0);
virt_viewer_set_usb_device_reset_accel(self, 0, 0);
gint i;
const gchar *no_accels[] = { NULL };
for (i = 0 ; i < G_N_ELEMENTS(action_accels); i++) {
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
action_accels[i].action,
no_accels);
}
}
void
@ -2708,6 +2691,8 @@ 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);
virt_viewer_update_smartcard_accels(self);
virt_viewer_update_usbredir_accels(self);
return;
}
@ -2724,38 +2709,37 @@ virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys_str)
gchar *accel = spice_hotkey_to_gtk_accelerator(value);
guint accel_key;
GdkModifierType accel_mods;
const gchar *accels[] = { accel, NULL };
gtk_accelerator_parse(accel, &accel_key, &accel_mods);
g_free(accel);
if (accel_key == 0 && accel_mods == 0) {
g_warning("Invalid value '%s' for key '%s'", value, *hotkey);
g_free(accel);
continue;
}
gboolean status = TRUE;
if (g_str_equal(*hotkey, "toggle-fullscreen")) {
status = gtk_accel_map_change_entry("<virt-viewer>/view/toggle-fullscreen", accel_key, accel_mods, TRUE);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.fullscreen", accels);
} else if (g_str_equal(*hotkey, "release-cursor")) {
status = gtk_accel_map_change_entry("<virt-viewer>/view/release-cursor", accel_key, accel_mods, TRUE);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.release-cursor", accels);
} else if (g_str_equal(*hotkey, "zoom-reset")) {
status = gtk_accel_map_change_entry("<virt-viewer>/view/zoom-reset", accel_key, accel_mods, TRUE);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.zoom-reset", accels);
} else if (g_str_equal(*hotkey, "zoom-out")) {
status = gtk_accel_map_change_entry("<virt-viewer>/view/zoom-out", accel_key, accel_mods, TRUE);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.zoom-out", accels);
} else if (g_str_equal(*hotkey, "zoom-in")) {
status = gtk_accel_map_change_entry("<virt-viewer>/view/zoom-in", accel_key, accel_mods, TRUE);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.zoom-in", accels);
} else if (g_str_equal(*hotkey, "secure-attention")) {
status = gtk_accel_map_change_entry("<virt-viewer>/send/secure-attention", accel_key, accel_mods, TRUE);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.secure-attention", accels);
} else if (g_str_equal(*hotkey, "smartcard-insert")) {
virt_viewer_set_insert_smartcard_accel(self, accel_key, accel_mods);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "app.smartcard-insert", accels);
} else if (g_str_equal(*hotkey, "smartcard-remove")) {
virt_viewer_set_remove_smartcard_accel(self, accel_key, accel_mods);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "app.smartcard-remove", accels);
} else if (g_str_equal(*hotkey, "usb-device-reset")) {
virt_viewer_set_usb_device_reset_accel(self, accel_key, accel_mods);
gtk_application_set_accels_for_action(GTK_APPLICATION(self), "app.usb-device-reset", accels);
} else {
g_warning("Unknown hotkey command %s", *hotkey);
}
if (!status)
g_warning("Unable to set hotkey for '%s' due to a conflict in GTK", *hotkey);
g_free(accel);
}
g_strfreev(hotkeys);

View File

@ -237,15 +237,21 @@ enable_accel_changed(VirtViewerApp *app,
GParamSpec *pspec G_GNUC_UNUSED,
VirtViewerDisplaySpice *self)
{
GtkAccelKey key = {0, 0, 0};
gboolean kiosk;
guint accel_key = 0;
GdkModifierType accel_mods = 0;
gchar **accels;
if (virt_viewer_app_get_enable_accel(app))
gtk_accel_map_lookup_entry("<virt-viewer>/view/release-cursor", &key);
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);
}
g_object_get(app, "kiosk", &kiosk, NULL);
if (key.accel_key || key.accel_mods || kiosk) {
if (accel_key || accel_mods || kiosk) {
SpiceGrabSequence *seq = spice_grab_sequence_new(0, NULL);
/* disable default grab sequence */
spice_display_set_grab_keys(self->display, seq);

View File

@ -187,15 +187,21 @@ enable_accel_changed(VirtViewerApp *app,
GParamSpec *pspec G_GNUC_UNUSED,
VncDisplay *vnc)
{
GtkAccelKey key = {0, 0, 0};
gboolean kiosk;
guint accel_key = 0;
GdkModifierType accel_mods = 0;
gchar **accels;
if (virt_viewer_app_get_enable_accel(app))
gtk_accel_map_lookup_entry("<virt-viewer>/view/release-cursor", &key);
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);
}
g_object_get(app, "kiosk", &kiosk, NULL);
if (key.accel_key || key.accel_mods || kiosk) {
if (accel_key || accel_mods || kiosk) {
VncGrabSequence *seq = vnc_grab_sequence_new(0, NULL);
/* disable default grab sequence */
vnc_display_set_grab_keys(vnc, seq);

View File

@ -869,17 +869,14 @@ virt_viewer_file_set_ovirt_admin(VirtViewerFile* self, gint value)
}
static void
spice_hotkey_set_accel(const gchar *accel_path, const gchar *key)
spice_hotkey_set_accel(VirtViewerApp *app, const gchar *action_name, const gchar *key)
{
gchar *accel;
guint accel_key;
GdkModifierType accel_mods;
gchar *accel = spice_hotkey_to_gtk_accelerator(key);
const gchar *accels[] = { accel, NULL };
gtk_application_set_accels_for_action(GTK_APPLICATION(app), action_name, accels);
accel = spice_hotkey_to_gtk_accelerator(key);
gtk_accelerator_parse(accel, &accel_key, &accel_mods);
g_free(accel);
gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
}
static gboolean
@ -960,16 +957,16 @@ virt_viewer_file_fill_app(VirtViewerFile* self, VirtViewerApp *app, GError **err
gchar *val;
static const struct {
const char *prop;
const char *accel;
const char *action_name;
} accels[] = {
{ "release-cursor", "<virt-viewer>/view/release-cursor" },
{ "toggle-fullscreen", "<virt-viewer>/view/toggle-fullscreen" },
{ "zoom-in", "<virt-viewer>/view/zoom-in" },
{ "zoom-out", "<virt-viewer>/view/zoom-out" },
{ "zoom-reset", "<virt-viewer>/view/zoom-reset" },
{ "smartcard-insert", "<virt-viewer>/file/smartcard-insert" },
{ "smartcard-remove", "<virt-viewer>/file/smartcard-remove" },
{ "secure-attention", "<virt-viewer>/send/secure-attention" }
{ "release-cursor", "win.release-cursor" },
{ "toggle-fullscreen", "win.fullscreen" },
{ "zoom-in", "win.zoom-in" },
{ "zoom-out", "win.zoom-out" },
{ "zoom-reset", "win.zoom-reset" },
{ "smartcard-insert", "app.smartcard-insert" },
{ "smartcard-remove", "app.smartcard-remove" },
{ "secure-attention", "win.secure-attention" },
};
int i;
@ -977,7 +974,7 @@ virt_viewer_file_fill_app(VirtViewerFile* self, VirtViewerApp *app, GError **err
if (!virt_viewer_file_is_set(self, accels[i].prop))
continue;
g_object_get(self, accels[i].prop, &val, NULL);
spice_hotkey_set_accel(accels[i].accel, val);
spice_hotkey_set_accel(app, accels[i].action_name, val);
g_free(val);
}
}

View File

@ -501,6 +501,20 @@ virt_viewer_window_action_change_cd(GSimpleAction *act G_GNUC_UNUSED,
virt_viewer_window_change_cd(VIRT_VIEWER_WINDOW(opaque));
}
static void
virt_viewer_window_action_secure_attention(GSimpleAction *action G_GNUC_UNUSED,
GVariant *param G_GNUC_UNUSED,
gpointer opaque)
{
g_return_if_fail(VIRT_VIEWER_IS_WINDOW(opaque));
VirtViewerWindow *self = VIRT_VIEWER_WINDOW(opaque);
guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete };
virt_viewer_display_send_keys(VIRT_VIEWER_DISPLAY(self->display),
keys, G_N_ELEMENTS(keys));
}
static GActionEntry actions[] = {
{ .name = "zoom-out",
.activate = virt_viewer_window_action_zoom_out },
@ -534,6 +548,8 @@ static GActionEntry actions[] = {
.activate = virt_viewer_window_action_preferences },
{ .name = "change-cd",
.activate = virt_viewer_window_action_change_cd },
{ .name = "secure-attention",
.activate = virt_viewer_window_action_secure_attention },
};
static void
@ -789,27 +805,26 @@ virt_viewer_window_enter_fullscreen(VirtViewerWindow *self, gint monitor)
struct keyComboDef {
guint32 keys[MAX_KEY_COMBO];
const char *accel_label;
const gchar* accel_path;
};
static const struct keyComboDef keyCombos[] = {
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete, GDK_KEY_VoidSymbol }, "<Control><Alt>Delete", "<virt-viewer>/send/secure-attention"},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_BackSpace, GDK_KEY_VoidSymbol }, "<Control><Alt>BackSpace", NULL},
{ { GDK_KEY_VoidSymbol }, "" , NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F1, GDK_KEY_VoidSymbol }, "<Control><Alt>F1", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F2, GDK_KEY_VoidSymbol }, "<Control><Alt>F2", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F3, GDK_KEY_VoidSymbol }, "<Control><Alt>F3", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F4, GDK_KEY_VoidSymbol }, "<Control><Alt>F4", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F5, GDK_KEY_VoidSymbol }, "<Control><Alt>F5", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F6, GDK_KEY_VoidSymbol }, "<Control><Alt>F6", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F7, GDK_KEY_VoidSymbol }, "<Control><Alt>F7", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F8, GDK_KEY_VoidSymbol }, "<Control><Alt>F8", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F9, GDK_KEY_VoidSymbol }, "<Control><Alt>F9", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F10, GDK_KEY_VoidSymbol }, "<Control><Alt>F10", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F11, GDK_KEY_VoidSymbol }, "<Control><Alt>F11", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F12, GDK_KEY_VoidSymbol }, "<Control><Alt>F12", NULL},
{ { GDK_KEY_VoidSymbol }, "" , NULL},
{ { GDK_KEY_Print, GDK_KEY_VoidSymbol }, "Print", NULL},
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete, GDK_KEY_VoidSymbol }, "<Control><Alt>Delete" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_BackSpace, GDK_KEY_VoidSymbol }, "<Control><Alt>BackSpace" },
{ { GDK_KEY_VoidSymbol }, "" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F1, GDK_KEY_VoidSymbol }, "<Control><Alt>F1" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F2, GDK_KEY_VoidSymbol }, "<Control><Alt>F2" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F3, GDK_KEY_VoidSymbol }, "<Control><Alt>F3" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F4, GDK_KEY_VoidSymbol }, "<Control><Alt>F4" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F5, GDK_KEY_VoidSymbol }, "<Control><Alt>F5" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F6, GDK_KEY_VoidSymbol }, "<Control><Alt>F6" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F7, GDK_KEY_VoidSymbol }, "<Control><Alt>F7" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F8, GDK_KEY_VoidSymbol }, "<Control><Alt>F8" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F9, GDK_KEY_VoidSymbol }, "<Control><Alt>F9" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F10, GDK_KEY_VoidSymbol }, "<Control><Alt>F10" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F11, GDK_KEY_VoidSymbol }, "<Control><Alt>F11" },
{ { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_F12, GDK_KEY_VoidSymbol }, "<Control><Alt>F12" },
{ { GDK_KEY_VoidSymbol }, "" },
{ { GDK_KEY_Print, GDK_KEY_VoidSymbol }, "Print" },
};
static guint
@ -824,8 +839,8 @@ get_nkeys(const guint32 *keys)
}
static void
virt_viewer_menu_add_combo(VirtViewerWindow *self, GtkMenu *menu,
const guint *keys, const gchar *label, const gchar* accel_path)
virt_viewer_menu_add_combo(VirtViewerWindow *self G_GNUC_UNUSED, GtkMenu *menu,
const guint *keys, const gchar *label)
{
GtkWidget *item;
@ -833,11 +848,6 @@ virt_viewer_menu_add_combo(VirtViewerWindow *self, GtkMenu *menu,
item = gtk_separator_menu_item_new();
} else {
item = gtk_menu_item_new_with_label(label);
if (accel_path) {
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path);
/* make accel work in fullscreen */
g_signal_connect(item, "can-activate-accel", G_CALLBACK(can_activate_cb), self);
}
gtk_actionable_set_action_name(GTK_ACTIONABLE(item), "win.send-key");
gtk_actionable_set_action_target_value(GTK_ACTIONABLE(item),
g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
@ -850,7 +860,8 @@ virt_viewer_menu_add_combo(VirtViewerWindow *self, GtkMenu *menu,
}
static guint*
accel_key_to_keys(const GtkAccelKey *key)
accel_key_to_keys(guint accel_key,
GdkModifierType accel_mods)
{
guint i;
guint *val, *keys;
@ -863,59 +874,28 @@ accel_key_to_keys(const GtkAccelKey *key)
{GDK_MOD1_MASK, GDK_KEY_Alt_L},
};
g_warn_if_fail((key->accel_mods &
g_warn_if_fail((accel_mods &
~(GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) == 0);
keys = val = g_new(guint, G_N_ELEMENTS(modifiers) + 2); /* up to 3 modifiers, key and the stop symbol */
/* first, send the modifiers */
for (i = 0; i < G_N_ELEMENTS(modifiers); i++) {
if (key->accel_mods & modifiers[i].mask)
if (accel_mods & modifiers[i].mask)
*val++ = modifiers[i].key;
}
/* only after, the non-modifier key (ctrl-t, not t-ctrl) */
*val++ = key->accel_key;
*val++ = accel_key;
/* stop symbol */
*val = GDK_KEY_VoidSymbol;
return keys;
}
struct accelCbData
{
VirtViewerWindow *self;
GtkMenu *menu;
};
static void
accel_map_item_cb(gpointer data,
const gchar *accel_path,
guint accel_key,
GdkModifierType accel_mods,
gboolean changed G_GNUC_UNUSED)
{
struct accelCbData *d = data;
GtkAccelKey key = {
.accel_key = accel_key,
.accel_mods = accel_mods
};
if (!g_str_has_prefix(accel_path, "<virt-viewer>"))
return;
if (accel_key == GDK_KEY_VoidSymbol || accel_key == 0)
return;
guint *keys = accel_key_to_keys(&key);
gchar *label = gtk_accelerator_get_label(accel_key, accel_mods);
virt_viewer_menu_add_combo(d->self, d->menu, keys, label, NULL);
g_free(label);
g_free(keys);
}
static GtkMenu*
virt_viewer_window_get_keycombo_menu(VirtViewerWindow *self)
{
gint i;
gint i, j;
GtkMenu *menu = GTK_MENU(gtk_menu_new());
gtk_menu_set_accel_group(menu, self->accel_group);
@ -927,43 +907,44 @@ virt_viewer_window_get_keycombo_menu(VirtViewerWindow *self)
gtk_accelerator_parse(keyCombos[i].accel_label, &key, &mods);
label = gtk_accelerator_get_label(key, mods);
}
virt_viewer_menu_add_combo(self, menu, keyCombos[i].keys, label, keyCombos[i].accel_path);
virt_viewer_menu_add_combo(self, menu, keyCombos[i].keys, label);
g_free(label);
}
if (virt_viewer_app_get_enable_accel(self->app)) {
struct accelCbData d = {
.self = self,
.menu = menu
};
gchar **accelactions = gtk_application_list_action_descriptions(GTK_APPLICATION(self->app));
gtk_accel_map_foreach(&d, accel_map_item_cb);
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++) {
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, menu, keys, label);
g_free(label);
g_free(keys);
}
g_strfreev(accels);
}
g_strfreev(accelactions);
}
gtk_widget_show_all(GTK_WIDGET(menu));
return menu;
}
struct VirtViewerActionAccels {
const char *accels[2];
const char *action;
};
static const struct VirtViewerActionAccels action_accels[] = {
/* numpad keys are not handled automatically by gtk, see bgo#699823 */
{ {"<control>KP_Add", NULL}, "win.zoom-in" },
{ {"<control>KP_Subtract", NULL}, "win.zoom-out" },
{ {"<control>KP_0", NULL}, "win.zoom-reset" },
};
void
virt_viewer_window_disable_modifiers(VirtViewerWindow *self)
{
GtkSettings *settings = gtk_settings_get_default();
GValue empty;
GSList *accels;
guint i;
if (!self->accel_enabled)
return;
@ -991,13 +972,6 @@ virt_viewer_window_disable_modifiers(VirtViewerWindow *self)
"gtk-enable-mnemonics", FALSE,
NULL);
for (i = 0; i < G_N_ELEMENTS(action_accels); i++) {
const char *noaccels[1] = { NULL };
gtk_application_set_accels_for_action(GTK_APPLICATION(self->app),
action_accels[i].action,
noaccels);
}
self->accel_enabled = FALSE;
}
@ -1006,8 +980,6 @@ virt_viewer_window_enable_modifiers(VirtViewerWindow *self)
{
GtkSettings *settings = gtk_settings_get_default();
GSList *accels;
guint i;
GtkAccelKey key;
GSList *attached_accels;
if (self->accel_enabled)
@ -1031,19 +1003,6 @@ virt_viewer_window_enable_modifiers(VirtViewerWindow *self)
"gtk-enable-mnemonics", self->enable_mnemonics_save,
NULL);
/* 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 (!virt_viewer_app_get_enable_accel(self->app)
&& gtk_accel_map_lookup_entry("<virt-viewer>/view/zoom-out", &key)
&& key.accel_key != 0) {
for (i = 0; i < G_N_ELEMENTS(action_accels); i++) {
gtk_application_set_accels_for_action(GTK_APPLICATION(self->app),
action_accels[i].action,
action_accels[i].accels);
}
}
self->accel_enabled = TRUE;
}
@ -1453,14 +1412,20 @@ virt_viewer_window_update_title(VirtViewerWindow *self)
if (self->grabbed) {
gchar *label;
GtkAccelKey key = {0, 0, 0};
guint accel_key = 0;
GdkModifierType accel_mods = 0;
gchar **accels;
if (virt_viewer_app_get_enable_accel(self->app))
gtk_accel_map_lookup_entry("<virt-viewer>/view/release-cursor", &key);
if (virt_viewer_app_get_enable_accel(self->app)) {
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 (key.accel_key || key.accel_mods) {
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);
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"));
}