mirror of
https://github.com/brl/mutter.git
synced 2024-11-24 17:10:40 -05:00
keybindings: 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
This commit is contained in:
parent
d664cfcc90
commit
7186ddff49
@ -239,6 +239,8 @@ struct _MetaDisplay
|
|||||||
unsigned int meta_mask;
|
unsigned int meta_mask;
|
||||||
MetaKeyCombo overlay_key_combo;
|
MetaKeyCombo overlay_key_combo;
|
||||||
gboolean overlay_key_only_pressed;
|
gboolean overlay_key_only_pressed;
|
||||||
|
MetaKeyCombo *iso_next_group_combos;
|
||||||
|
int n_iso_next_group_combos;
|
||||||
|
|
||||||
/* Monitor cache */
|
/* Monitor cache */
|
||||||
unsigned int monitor_cache_invalidated : 1;
|
unsigned int monitor_cache_invalidated : 1;
|
||||||
@ -458,6 +460,7 @@ void meta_display_overlay_key_activate (MetaDisplay *display);
|
|||||||
void meta_display_accelerator_activate (MetaDisplay *display,
|
void meta_display_accelerator_activate (MetaDisplay *display,
|
||||||
guint action,
|
guint action,
|
||||||
guint deviceid);
|
guint deviceid);
|
||||||
|
gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
|
||||||
|
|
||||||
/* In above-tab-keycode.c */
|
/* In above-tab-keycode.c */
|
||||||
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
|
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
|
||||||
|
@ -139,6 +139,7 @@ enum
|
|||||||
{
|
{
|
||||||
OVERLAY_KEY,
|
OVERLAY_KEY,
|
||||||
ACCELERATOR_ACTIVATED,
|
ACCELERATOR_ACTIVATED,
|
||||||
|
MODIFIERS_ACCELERATOR_ACTIVATED,
|
||||||
FOCUS_WINDOW,
|
FOCUS_WINDOW,
|
||||||
WINDOW_CREATED,
|
WINDOW_CREATED,
|
||||||
WINDOW_DEMANDS_ATTENTION,
|
WINDOW_DEMANDS_ATTENTION,
|
||||||
@ -255,6 +256,25 @@ meta_display_class_init (MetaDisplayClass *klass)
|
|||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
|
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MetaDisplay::modifiers-accelerator-activated:
|
||||||
|
* @display: the #MetaDisplay instance
|
||||||
|
*
|
||||||
|
* The ::modifiers-accelerator-activated signal will be emitted when
|
||||||
|
* a special modifiers-only keybinding is activated.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE means that the keyboard device should remain
|
||||||
|
* frozen and %FALSE for the default behavior of unfreezing the
|
||||||
|
* keyboard.
|
||||||
|
*/
|
||||||
|
display_signals[MODIFIERS_ACCELERATOR_ACTIVATED] =
|
||||||
|
g_signal_new ("modifiers-accelerator-activated",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
g_signal_accumulator_first_wins, NULL, NULL,
|
||||||
|
G_TYPE_BOOLEAN, 0);
|
||||||
|
|
||||||
display_signals[WINDOW_CREATED] =
|
display_signals[WINDOW_CREATED] =
|
||||||
g_signal_new ("window-created",
|
g_signal_new ("window-created",
|
||||||
G_TYPE_FROM_CLASS (klass),
|
G_TYPE_FROM_CLASS (klass),
|
||||||
@ -5681,6 +5701,16 @@ meta_display_accelerator_activate (MetaDisplay *display,
|
|||||||
0, action, deviceid);
|
0, action, deviceid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_display_modifiers_accelerator_activate (MetaDisplay *display)
|
||||||
|
{
|
||||||
|
gboolean freeze;
|
||||||
|
|
||||||
|
g_signal_emit (display, display_signals[MODIFIERS_ACCELERATOR_ACTIVATED], 0, &freeze);
|
||||||
|
|
||||||
|
return freeze;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_display_get_compositor_version (MetaDisplay *display,
|
meta_display_get_compositor_version (MetaDisplay *display,
|
||||||
int *major,
|
int *major,
|
||||||
|
@ -302,6 +302,172 @@ reload_modmap (MetaDisplay *display)
|
|||||||
display->meta_mask);
|
display->meta_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Original code from gdk_x11_keymap_get_entries_for_keyval() in
|
||||||
|
* gdkkeys-x11.c */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const char *iso_next_group_option;
|
||||||
|
MetaKeyCombo *combos;
|
||||||
|
int *keycodes;
|
||||||
|
int n_keycodes;
|
||||||
|
int n_combos;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_clear_pointer (&display->iso_next_group_combos, g_free);
|
||||||
|
display->n_iso_next_group_combos = 0;
|
||||||
|
|
||||||
|
iso_next_group_option = meta_prefs_get_iso_next_group_option ();
|
||||||
|
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);
|
||||||
|
|
||||||
|
display->n_iso_next_group_combos = n_combos;
|
||||||
|
display->iso_next_group_combos = combos;
|
||||||
|
}
|
||||||
|
|
||||||
static guint
|
static guint
|
||||||
keysym_to_keycode (MetaDisplay *display,
|
keysym_to_keycode (MetaDisplay *display,
|
||||||
guint keysym)
|
guint keysym)
|
||||||
@ -328,6 +494,8 @@ reload_keycodes (MetaDisplay *display)
|
|||||||
display->overlay_key_combo.keycode = 0;
|
display->overlay_key_combo.keycode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reload_iso_next_group_combos (display);
|
||||||
|
|
||||||
if (display->key_bindings)
|
if (display->key_bindings)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1026,6 +1194,22 @@ meta_screen_change_keygrabs (MetaScreen *screen,
|
|||||||
display->overlay_key_combo.keycode,
|
display->overlay_key_combo.keycode,
|
||||||
display->overlay_key_combo.modifiers);
|
display->overlay_key_combo.modifiers);
|
||||||
|
|
||||||
|
if (display->iso_next_group_combos)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (i < display->n_iso_next_group_combos)
|
||||||
|
{
|
||||||
|
if (display->iso_next_group_combos[i].keycode != 0)
|
||||||
|
{
|
||||||
|
meta_change_keygrab (display, screen->xroot, grab,
|
||||||
|
display->iso_next_group_combos[i].keysym,
|
||||||
|
display->iso_next_group_combos[i].keycode,
|
||||||
|
display->iso_next_group_combos[i].modifiers);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
change_binding_keygrabs (screen->display->key_bindings,
|
change_binding_keygrabs (screen->display->key_bindings,
|
||||||
screen->display->n_key_bindings,
|
screen->display->n_key_bindings,
|
||||||
screen->display, screen->xroot,
|
screen->display, screen->xroot,
|
||||||
@ -1801,6 +1985,41 @@ process_overlay_key (MetaDisplay *display,
|
|||||||
return FALSE;
|
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 < display->n_iso_next_group_combos; ++i)
|
||||||
|
{
|
||||||
|
if (event->detail == (int)display->iso_next_group_combos[i].keycode &&
|
||||||
|
mods == display->iso_next_group_combos[i].modifiers)
|
||||||
|
{
|
||||||
|
/* If the signal handler returns TRUE the keyboard will
|
||||||
|
remain frozen. It's the signal handler's responsibility
|
||||||
|
to unfreeze it. */
|
||||||
|
if (!meta_display_modifiers_accelerator_activate (display))
|
||||||
|
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||||
|
XIAsyncDevice, event->time);
|
||||||
|
activate = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return activate;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle a key event. May be called recursively: some key events cause
|
/* 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
|
* grabs to be ended and then need to be processed again in their own
|
||||||
* right. This cannot cause infinite recursion because we never call
|
* right. This cannot cause infinite recursion because we never call
|
||||||
@ -1875,6 +2094,10 @@ meta_display_process_key_event (MetaDisplay *display,
|
|||||||
handled = process_overlay_key (display, screen, event, keysym);
|
handled = process_overlay_key (display, screen, event, keysym);
|
||||||
if (handled)
|
if (handled)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
handled = process_iso_next_group (display, screen, event, keysym);
|
||||||
|
if (handled)
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
XIAllowEvents (display->xdisplay, event->deviceid,
|
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||||
@ -4568,6 +4791,12 @@ meta_display_init_keys (MetaDisplay *display)
|
|||||||
|
|
||||||
g_hash_table_insert (key_handlers, g_strdup ("overlay-key"), handler);
|
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 = g_new0 (MetaKeyHandler, 1);
|
||||||
handler->name = g_strdup ("external-grab");
|
handler->name = g_strdup ("external-grab");
|
||||||
handler->func = handle_external_grab;
|
handler->func = handle_external_grab;
|
||||||
|
Loading…
Reference in New Issue
Block a user