[mutter/wip/is-switch-fixes: 3/4] Grab and emit a signal when XK_ISO_Next_Group is pressed
- From: Rui Matos <rtcm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/is-switch-fixes: 3/4] Grab and emit a signal when XK_ISO_Next_Group is pressed
- Date: Fri, 5 Apr 2013 15:59:08 +0000 (UTC)
commit 0e83b748d5f60a61d352505b657bfa05b0aea8f0
Author: Rui Matos <tiagomatos gmail com>
Date: Thu Mar 28 17:57:12 2013 +0100
Grab and emit a signal when XK_ISO_Next_Group is pressed
This will make it possible to implement input source switching in
gnome-shell using the popular modifiers-only keybinding that's
implemented on the X server through an XKB option.
https://bugzilla.gnome.org/show_bug.cgi?id=697002
src/core/display-private.h | 1 +
src/core/display.c | 15 +++
src/core/keybindings.c | 229 ++++++++++++++++++++++++++++++++++++++++++++
src/core/prefs.c | 64 ++++++++++++-
src/meta/prefs.h | 2 +
5 files changed, 310 insertions(+), 1 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 1f73fc3..52550bc 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -458,6 +458,7 @@ void meta_display_overlay_key_activate (MetaDisplay *display);
void meta_display_accelerator_activate (MetaDisplay *display,
guint action,
guint deviceid);
+void meta_display_modifiers_accelerator_activate (MetaDisplay *display);
/* In above-tab-keycode.c */
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
diff --git a/src/core/display.c b/src/core/display.c
index f4f7e63..95b7274 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -139,6 +139,7 @@ enum
{
OVERLAY_KEY,
ACCELERATOR_ACTIVATED,
+ MODIFIERS_ACCELERATOR_ACTIVATED,
FOCUS_WINDOW,
WINDOW_CREATED,
WINDOW_DEMANDS_ATTENTION,
@@ -255,6 +256,14 @@ meta_display_class_init (MetaDisplayClass *klass)
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+ display_signals[MODIFIERS_ACCELERATOR_ACTIVATED] =
+ g_signal_new ("modifiers-accelerator-activated",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
display_signals[WINDOW_CREATED] =
g_signal_new ("window-created",
G_TYPE_FROM_CLASS (klass),
@@ -5682,6 +5691,12 @@ meta_display_accelerator_activate (MetaDisplay *display,
}
void
+meta_display_modifiers_accelerator_activate (MetaDisplay *display)
+{
+ g_signal_emit (display, display_signals[MODIFIERS_ACCELERATOR_ACTIVATED], 0);
+}
+
+void
meta_display_get_compositor_version (MetaDisplay *display,
int *major,
int *minor)
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 78b22a7..b9321f6 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -153,6 +153,10 @@ static void regrab_key_bindings (MetaDisplay *display);
static GHashTable *key_handlers;
static GHashTable *external_grabs;
+static char *iso_next_group_option;
+static MetaKeyCombo *iso_next_group_combos;
+static int n_iso_next_group_combos;
+
#define HANDLER(name) g_hash_table_lookup (key_handlers, (name))
static void
@@ -301,6 +305,168 @@ reload_modmap (MetaDisplay *display)
display->meta_mask);
}
+static int
+get_keycodes_for_keysym (MetaDisplay *display,
+ int keysym,
+ int **keycodes)
+{
+ GArray *retval;
+ int n_keycodes;
+ int keycode;
+
+ retval = g_array_new (FALSE, FALSE, sizeof (int));
+
+ keycode = display->min_keycode;
+ while (keycode <= display->max_keycode)
+ {
+ const KeySym *syms = display->keymap + (keycode - display->min_keycode) * display->keysyms_per_keycode;
+ int i = 0;
+
+ while (i < display->keysyms_per_keycode)
+ {
+ if (syms[i] == (unsigned int)keysym)
+ g_array_append_val (retval, keycode);
+
+ ++i;
+ }
+
+ ++keycode;
+ }
+
+ n_keycodes = retval->len;
+ *keycodes = (int*) g_array_free (retval, n_keycodes == 0 ? TRUE : FALSE);
+
+ return n_keycodes;
+}
+
+static void
+reload_iso_next_group_combos (MetaDisplay *display)
+{
+ MetaKeyCombo *combos;
+ int *keycodes;
+ int n_keycodes;
+ int n_combos;
+ int i;
+
+ g_clear_pointer (&iso_next_group_combos, g_free);
+ n_iso_next_group_combos = 0;
+
+ if (iso_next_group_option == NULL)
+ return;
+
+ n_keycodes = get_keycodes_for_keysym (display, XK_ISO_Next_Group, &keycodes);
+
+ if (g_str_equal (iso_next_group_option, "toggle") ||
+ g_str_equal (iso_next_group_option, "lalt_toggle") ||
+ g_str_equal (iso_next_group_option, "lwin_toggle") ||
+ g_str_equal (iso_next_group_option, "rwin_toggle") ||
+ g_str_equal (iso_next_group_option, "lshift_toggle") ||
+ g_str_equal (iso_next_group_option, "rshift_toggle") ||
+ g_str_equal (iso_next_group_option, "lctrl_toggle") ||
+ g_str_equal (iso_next_group_option, "rctrl_toggle") ||
+ g_str_equal (iso_next_group_option, "sclk_toggle") ||
+ g_str_equal (iso_next_group_option, "menu_toggle") ||
+ g_str_equal (iso_next_group_option, "caps_toggle"))
+ {
+ n_combos = n_keycodes;
+ combos = g_new (MetaKeyCombo, n_combos);
+
+ for (i = 0; i < n_keycodes; ++i)
+ {
+ combos[i].keysym = XK_ISO_Next_Group;
+ combos[i].keycode = keycodes[i];
+ combos[i].modifiers = 0;
+ }
+ }
+ else if (g_str_equal (iso_next_group_option, "shift_caps_toggle") ||
+ g_str_equal (iso_next_group_option, "shifts_toggle"))
+ {
+ n_combos = n_keycodes;
+ combos = g_new (MetaKeyCombo, n_combos);
+
+ for (i = 0; i < n_keycodes; ++i)
+ {
+ combos[i].keysym = XK_ISO_Next_Group;
+ combos[i].keycode = keycodes[i];
+ combos[i].modifiers = ShiftMask;
+ }
+ }
+ else if (g_str_equal (iso_next_group_option, "alt_caps_toggle") ||
+ g_str_equal (iso_next_group_option, "alt_space_toggle"))
+ {
+ n_combos = n_keycodes;
+ combos = g_new (MetaKeyCombo, n_combos);
+
+ for (i = 0; i < n_keycodes; ++i)
+ {
+ combos[i].keysym = XK_ISO_Next_Group;
+ combos[i].keycode = keycodes[i];
+ combos[i].modifiers = Mod1Mask;
+ }
+ }
+ else if (g_str_equal (iso_next_group_option, "ctrl_shift_toggle") ||
+ g_str_equal (iso_next_group_option, "lctrl_lshift_toggle") ||
+ g_str_equal (iso_next_group_option, "rctrl_rshift_toggle"))
+ {
+ n_combos = n_keycodes * 2;
+ combos = g_new (MetaKeyCombo, n_combos);
+
+ for (i = 0; i < n_keycodes; ++i)
+ {
+ combos[i].keysym = XK_ISO_Next_Group;
+ combos[i].keycode = keycodes[i];
+ combos[i].modifiers = ShiftMask;
+
+ combos[i + n_keycodes].keysym = XK_ISO_Next_Group;
+ combos[i + n_keycodes].keycode = keycodes[i];
+ combos[i + n_keycodes].modifiers = ControlMask;
+ }
+ }
+ else if (g_str_equal (iso_next_group_option, "ctrl_alt_toggle"))
+ {
+ n_combos = n_keycodes * 2;
+ combos = g_new (MetaKeyCombo, n_combos);
+
+ for (i = 0; i < n_keycodes; ++i)
+ {
+ combos[i].keysym = XK_ISO_Next_Group;
+ combos[i].keycode = keycodes[i];
+ combos[i].modifiers = Mod1Mask;
+
+ combos[i + n_keycodes].keysym = XK_ISO_Next_Group;
+ combos[i + n_keycodes].keycode = keycodes[i];
+ combos[i + n_keycodes].modifiers = ControlMask;
+ }
+ }
+ else if (g_str_equal (iso_next_group_option, "alt_shift_toggle") ||
+ g_str_equal (iso_next_group_option, "lalt_lshift_toggle"))
+ {
+ n_combos = n_keycodes * 2;
+ combos = g_new (MetaKeyCombo, n_combos);
+
+ for (i = 0; i < n_keycodes; ++i)
+ {
+ combos[i].keysym = XK_ISO_Next_Group;
+ combos[i].keycode = keycodes[i];
+ combos[i].modifiers = Mod1Mask;
+
+ combos[i + n_keycodes].keysym = XK_ISO_Next_Group;
+ combos[i + n_keycodes].keycode = keycodes[i];
+ combos[i + n_keycodes].modifiers = ShiftMask;
+ }
+ }
+ else
+ {
+ n_combos = 0;
+ combos = NULL;
+ }
+
+ g_free (keycodes);
+
+ n_iso_next_group_combos = n_combos;
+ iso_next_group_combos = combos;
+}
+
static guint
keysym_to_keycode (MetaDisplay *display,
guint keysym)
@@ -327,6 +493,8 @@ reload_keycodes (MetaDisplay *display)
display->overlay_key_combo.keycode = 0;
}
+ reload_iso_next_group_combos (display);
+
if (display->key_bindings)
{
int i;
@@ -528,6 +696,9 @@ rebuild_special_bindings (MetaDisplay *display)
meta_prefs_get_overlay_binding (&combo);
display->overlay_key_combo = combo;
+
+ g_free (iso_next_group_option);
+ iso_next_group_option = meta_prefs_get_iso_next_group_option ();
}
static void
@@ -1030,6 +1201,22 @@ meta_screen_grab_keys (MetaScreen *screen)
display->overlay_key_combo.keycode,
display->overlay_key_combo.modifiers);
+ if (iso_next_group_combos)
+ {
+ int i = 0;
+ while (i < n_iso_next_group_combos)
+ {
+ if (iso_next_group_combos[i].keycode != 0)
+ {
+ meta_grab_key (display, screen->xroot,
+ iso_next_group_combos[i].keysym,
+ iso_next_group_combos[i].keycode,
+ iso_next_group_combos[i].modifiers);
+ }
+ ++i;
+ }
+ }
+
grab_keys (screen->display->key_bindings,
screen->display->n_key_bindings,
screen->display, screen->xroot,
@@ -1788,6 +1975,38 @@ process_overlay_key (MetaDisplay *display,
return FALSE;
}
+static gboolean
+process_iso_next_group (MetaDisplay *display,
+ MetaScreen *screen,
+ XIDeviceEvent *event,
+ KeySym keysym)
+{
+ gboolean activate;
+ unsigned int mods;
+ int i;
+
+ if (event->evtype != XI_KeyPress)
+ return FALSE;
+
+ activate = FALSE;
+ mods = (event->mods.effective & 0xff & ~(display->ignored_modifier_mask));
+
+ for (i = 0; i < n_iso_next_group_combos; ++i)
+ {
+ if (event->detail == (int)iso_next_group_combos[i].keycode &&
+ mods == iso_next_group_combos[i].modifiers)
+ {
+ activate = TRUE;
+ break;
+ }
+ }
+
+ if (activate)
+ meta_display_modifiers_accelerator_activate (display);
+
+ return activate;
+}
+
/* Handle a key event. May be called recursively: some key events cause
* grabs to be ended and then need to be processed again in their own
* right. This cannot cause infinite recursion because we never call
@@ -1862,6 +2081,10 @@ meta_display_process_key_event (MetaDisplay *display,
handled = process_overlay_key (display, screen, event, keysym);
if (handled)
return TRUE;
+
+ handled = process_iso_next_group (display, screen, event, keysym);
+ if (handled)
+ return TRUE;
}
XIAllowEvents (display->xdisplay, event->deviceid,
@@ -4556,6 +4779,12 @@ meta_display_init_keys (MetaDisplay *display)
g_hash_table_insert (key_handlers, g_strdup ("overlay-key"), handler);
handler = g_new0 (MetaKeyHandler, 1);
+ handler->name = g_strdup ("iso-next-group");
+ handler->flags = META_KEY_BINDING_BUILTIN;
+
+ g_hash_table_insert (key_handlers, g_strdup ("iso-next-group"), handler);
+
+ handler = g_new0 (MetaKeyHandler, 1);
handler->name = g_strdup ("external-grab");
handler->func = handle_external_grab;
handler->default_func = handle_external_grab;
diff --git a/src/core/prefs.c b/src/core/prefs.c
index 288a312..a780f86 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -55,6 +55,7 @@
#define KEY_GNOME_ANIMATIONS "enable-animations"
#define KEY_GNOME_CURSOR_THEME "cursor-theme"
#define KEY_GNOME_CURSOR_SIZE "cursor-size"
+#define KEY_XKB_OPTIONS "xkb-options"
#define KEY_OVERLAY_KEY "overlay-key"
#define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary"
@@ -65,6 +66,7 @@
#define SCHEMA_GENERAL "org.gnome.desktop.wm.preferences"
#define SCHEMA_MUTTER "org.gnome.mutter"
#define SCHEMA_INTERFACE "org.gnome.desktop.interface"
+#define SCHEMA_INPUT_SOURCES "org.gnome.desktop.input-sources"
#define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
@@ -115,6 +117,7 @@ static gboolean workspaces_only_on_primary = FALSE;
static gboolean no_tab_popup = FALSE;
+static char *iso_next_group_option = NULL;
static void handle_preference_update_enum (GSettings *settings,
gchar *key);
@@ -140,6 +143,7 @@ static gboolean theme_name_handler (GVariant*, gpointer*, gpointer);
static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
static gboolean overlay_key_handler (GVariant*, gpointer*, gpointer);
+static gboolean iso_next_group_handler (GVariant*, gpointer*, gpointer);
static void do_override (char *key, char *schema);
@@ -433,6 +437,14 @@ static MetaStringPreference preferences_string[] =
overlay_key_handler,
NULL,
},
+ {
+ { "xkb-options",
+ SCHEMA_INPUT_SOURCES,
+ META_PREF_KEYBINDINGS,
+ },
+ iso_next_group_handler,
+ NULL,
+ },
{ { NULL, 0, 0 }, NULL },
};
@@ -857,6 +869,11 @@ meta_prefs_init (void)
G_CALLBACK (settings_changed), NULL);
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings);
+ settings = g_settings_new (SCHEMA_INPUT_SOURCES);
+ g_signal_connect (settings, "changed::" KEY_XKB_OPTIONS,
+ G_CALLBACK (settings_changed), NULL);
+ g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INPUT_SOURCES), settings);
+
for (tmp = overridden_keys; tmp; tmp = tmp->next)
{
@@ -1035,7 +1052,8 @@ settings_changed (GSettings *settings,
handle_preference_update_bool (settings, key);
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
handle_preference_update_int (settings, key);
- else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
+ else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING) ||
+ g_variant_type_equal (type, G_VARIANT_TYPE_STRING_ARRAY))
{
cursor = preferences_enum;
found_enum = FALSE;
@@ -1554,6 +1572,44 @@ overlay_key_handler (GVariant *value,
return TRUE;
}
+static void
+set_iso_next_group_option (const char *option)
+{
+ if (g_strcmp0 (option, iso_next_group_option) == 0)
+ return;
+
+ g_free (iso_next_group_option);
+ iso_next_group_option = g_strdup (option);
+
+ queue_changed (META_PREF_KEYBINDINGS);
+}
+
+static gboolean
+iso_next_group_handler (GVariant *value,
+ gpointer *result,
+ gpointer data)
+{
+ const char **xkb_options, **p;
+
+ *result = NULL; /* ignored */
+ xkb_options = g_variant_get_strv (value, NULL);
+
+ for (p = xkb_options; p && *p; ++p)
+ if (g_str_has_prefix (*p, "grp:"))
+ {
+ set_iso_next_group_option (*p + 4);
+ break;
+ }
+
+ /* If we didn't find it, it still needs to be disabled. */
+ if (p && *p == NULL)
+ set_iso_next_group_option (NULL);
+
+ g_free (xkb_options);
+
+ return TRUE;
+}
+
const PangoFontDescription*
meta_prefs_get_titlebar_font (void)
{
@@ -2097,6 +2153,12 @@ meta_prefs_get_overlay_binding (MetaKeyCombo *combo)
*combo = overlay_key_combo;
}
+char *
+meta_prefs_get_iso_next_group_option (void)
+{
+ return g_strdup (iso_next_group_option);
+}
+
GDesktopTitlebarAction
meta_prefs_get_action_double_click_titlebar (void)
{
diff --git a/src/meta/prefs.h b/src/meta/prefs.h
index effb252..4429707 100644
--- a/src/meta/prefs.h
+++ b/src/meta/prefs.h
@@ -353,6 +353,7 @@ typedef enum _MetaKeyBindingAction
META_KEYBINDING_ACTION_MOVE_TO_SIDE_W,
META_KEYBINDING_ACTION_MOVE_TO_CENTER,
META_KEYBINDING_ACTION_OVERLAY_KEY,
+ META_KEYBINDING_ACTION_ISO_NEXT_GROUP,
META_KEYBINDING_ACTION_LAST
} MetaKeyBindingAction;
@@ -442,6 +443,7 @@ void meta_prefs_get_window_binding (const char *name,
MetaVirtualModifier *modifiers);
void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
+char *meta_prefs_get_iso_next_group_option (void);
gboolean meta_prefs_get_visual_bell (void);
gboolean meta_prefs_bell_is_audible (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]