From 3645c63c0842f4c416d20c36601c0b4fb91e08a4 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Fri, 15 Aug 2014 16:23:15 -0400 Subject: [PATCH] keybindings: Rewrite the modmap code so that it uses libxkbcommon This removes our Xwayland dependency in the native path. The direct grabs are still there for the X11 backend and are a bit disgusting, but that's OK. We can refactor it out later. This introduces some pretty lousy hackery because it depends on https://github.com/xkbcommon/libxkbcommon/pull/10 , and I really don't want to wait on that to squash this dep. --- src/Makefile.am | 2 + src/core/keybindings-private.h | 9 +-- src/core/keybindings.c | 89 +++++++------------------- src/core/xkbcommon-hacks.c | 112 +++++++++++++++++++++++++++++++++ src/core/xkbcommon-hacks.h | 34 ++++++++++ 5 files changed, 175 insertions(+), 71 deletions(-) create mode 100644 src/core/xkbcommon-hacks.c create mode 100644 src/core/xkbcommon-hacks.h diff --git a/src/Makefile.am b/src/Makefile.am index a6606eeb4..a333113c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -153,6 +153,8 @@ libmutter_la_SOURCES = \ meta/gradient.h \ core/meta-gesture-tracker.c \ core/meta-gesture-tracker-private.h \ + core/xkbcommon-hacks.c \ + core/xkbcommon-hacks.h \ core/keybindings.c \ core/keybindings-private.h \ core/main.c \ diff --git a/src/core/keybindings-private.h b/src/core/keybindings-private.h index 5cd8c0e57..9dfa4e836 100644 --- a/src/core/keybindings-private.h +++ b/src/core/keybindings-private.h @@ -29,6 +29,7 @@ #include #include +#include typedef struct _MetaKeyHandler MetaKeyHandler; struct _MetaKeyHandler @@ -97,10 +98,10 @@ typedef struct int max_keycode; KeySym *keymap; int keysyms_per_keycode; - unsigned int ignored_modifier_mask; - unsigned int hyper_mask; - unsigned int super_mask; - unsigned int meta_mask; + xkb_mod_mask_t ignored_modifier_mask; + xkb_mod_mask_t hyper_mask; + xkb_mod_mask_t super_mask; + xkb_mod_mask_t meta_mask; MetaKeyCombo overlay_key_combo; gboolean overlay_key_only_pressed; MetaKeyCombo *iso_next_group_combos; diff --git a/src/core/keybindings.c b/src/core/keybindings.c index d0ff8e0ae..684899c31 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -39,11 +39,10 @@ #include "screen-private.h" #include #include "meta-accel-parse.h" +#include "xkbcommon-hacks.h" #include -#include - #include "backends/x11/meta-backend-x11.h" #include "x11/window-x11.h" @@ -201,73 +200,31 @@ keysym_name (xkb_keysym_t keysym) static void reload_modmap (MetaKeyBindingManager *keys) { - XModifierKeymap *modmap; - int map_size; - int i; - int scroll_lock_mask = 0; + MetaBackend *backend = meta_get_backend (); + struct xkb_keymap *keymap = meta_backend_get_keymap (backend); + xkb_mod_mask_t scroll_lock_mask; - modmap = XGetModifierMapping (keys->xdisplay); - keys->ignored_modifier_mask = 0; + /* Modifiers to find. */ + struct { + char *name; + xkb_mod_mask_t *mask_p; + } mods[] = { + { "ScrollLock", &scroll_lock_mask }, + { "Meta", &keys->meta_mask }, + { "Hyper", &keys->hyper_mask }, + { "Super", &keys->super_mask }, + }; - /* Multiple bits may get set in each of these */ - keys->meta_mask = 0; - keys->hyper_mask = 0; - keys->super_mask = 0; - - /* there are 8 modifiers, and the first 3 are shift, shift lock, - * and control - */ - map_size = 8 * modmap->max_keypermod; - i = 3 * modmap->max_keypermod; - while (i < map_size) + gsize i; + for (i = 0; i < G_N_ELEMENTS (mods); i++) { - /* get the key code at this point in the map, - * see if its keysym is one we're interested in - */ - int keycode = modmap->modifiermap[i]; + xkb_mod_mask_t *mask_p = mods[i].mask_p; + xkb_mod_index_t idx = xkb_keymap_mod_get_index (keymap, mods[i].name); - if (keycode >= keys->min_keycode && - keycode <= keys->max_keycode) - { - int j = 0; - KeySym *syms = keys->keymap + - (keycode - keys->min_keycode) * keys->keysyms_per_keycode; - - while (j < keys->keysyms_per_keycode) - { - if (syms[j] != 0) - { - meta_topic (META_DEBUG_KEYBINDINGS, - "Keysym %s bound to modifier 0x%x\n", - keysym_name (syms[j]), - (1 << ( i / modmap->max_keypermod))); - } - - if (syms[j] == XKB_KEY_Scroll_Lock) - { - scroll_lock_mask |= (1 << ( i / modmap->max_keypermod)); - } - else if (syms[j] == XKB_KEY_Super_L || - syms[j] == XKB_KEY_Super_R) - { - keys->super_mask |= (1 << ( i / modmap->max_keypermod)); - } - else if (syms[j] == XKB_KEY_Hyper_L || - syms[j] == XKB_KEY_Hyper_R) - { - keys->hyper_mask |= (1 << ( i / modmap->max_keypermod)); - } - else if (syms[j] == XKB_KEY_Meta_L || - syms[j] == XKB_KEY_Meta_R) - { - keys->meta_mask |= (1 << ( i / modmap->max_keypermod)); - } - - ++j; - } - } - - ++i; + if (idx != XKB_MOD_INVALID) + *mask_p = my_xkb_keymap_mod_get_mask (keymap, idx); + else + *mask_p = 0; } keys->ignored_modifier_mask = (scroll_lock_mask | Mod2Mask | LockMask); @@ -279,8 +236,6 @@ reload_modmap (MetaKeyBindingManager *keys) keys->hyper_mask, keys->super_mask, keys->meta_mask); - - XFreeModifiermap (modmap); } /* Original code from gdk_x11_keymap_get_entries_for_keyval() in diff --git a/src/core/xkbcommon-hacks.c b/src/core/xkbcommon-hacks.c new file mode 100644 index 000000000..330f0f76d --- /dev/null +++ b/src/core/xkbcommon-hacks.c @@ -0,0 +1,112 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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 (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include "xkbcommon-hacks.h" + +/* Terrible, gross hackery to provide an implementation for xkb_keymap_mod_get_mask. + * Delete when https://github.com/xkbcommon/libxkbcommon/pull/10 is pushed. */ + +/* The structures here have been pulled from libxkbcommon. */ + +enum xkb_action_controls { + CONTROL_REPEAT = (1 << 0), + CONTROL_SLOW = (1 << 1), + CONTROL_DEBOUNCE = (1 << 2), + CONTROL_STICKY = (1 << 3), + CONTROL_MOUSEKEYS = (1 << 4), + CONTROL_MOUSEKEYS_ACCEL = (1 << 5), + CONTROL_AX = (1 << 6), + CONTROL_AX_TIMEOUT = (1 << 7), + CONTROL_AX_FEEDBACK = (1 << 8), + CONTROL_BELL = (1 << 9), + CONTROL_IGNORE_GROUP_LOCK = (1 << 10), + CONTROL_ALL = \ + (CONTROL_REPEAT | CONTROL_SLOW | CONTROL_DEBOUNCE | CONTROL_STICKY | \ + CONTROL_MOUSEKEYS | CONTROL_MOUSEKEYS_ACCEL | CONTROL_AX | \ + CONTROL_AX_TIMEOUT | CONTROL_AX_FEEDBACK | CONTROL_BELL | \ + CONTROL_IGNORE_GROUP_LOCK) +}; + +typedef uint32_t xkb_atom_t; + +/* Don't allow more modifiers than we can hold in xkb_mod_mask_t. */ +#define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * 8)) + +/* These should all go away. */ +enum mod_type { + MOD_REAL = (1 << 0), + MOD_VIRT = (1 << 1), + MOD_BOTH = (MOD_REAL | MOD_VIRT), +}; + +struct xkb_mod { + xkb_atom_t name; + enum mod_type type; + xkb_mod_mask_t mapping; /* vmod -> real mod mapping */ +}; + +struct xkb_mod_set { + struct xkb_mod mods[XKB_MAX_MODS]; + unsigned int num_mods; +}; + +/* Common keyboard description structure */ +struct xkb_keymap_real { + struct xkb_context *ctx; + + int refcnt; + enum xkb_keymap_compile_flags flags; + enum xkb_keymap_format format; + + enum xkb_action_controls enabled_ctrls; + + xkb_keycode_t min_key_code; + xkb_keycode_t max_key_code; + void *keys; + + /* aliases in no particular order */ + unsigned int num_key_aliases; + void *key_aliases; + + void *types; + unsigned int num_types; + + unsigned int num_sym_interprets; + void *sym_interprets; + + struct xkb_mod_set mods; +}; + +xkb_mod_mask_t +my_xkb_keymap_mod_get_mask(struct xkb_keymap *_keymap, xkb_mod_index_t idx) +{ + struct xkb_keymap_real *keymap = (struct xkb_keymap_real *) _keymap; + + if (idx >= keymap->mods.num_mods) + return 0; + + return keymap->mods.mods[idx].mapping; +} diff --git a/src/core/xkbcommon-hacks.h b/src/core/xkbcommon-hacks.h new file mode 100644 index 000000000..9b641180d --- /dev/null +++ b/src/core/xkbcommon-hacks.h @@ -0,0 +1,34 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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 (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre + */ + + +#ifndef XKBCOMMON_HACKS_H +#define XKBCOMMON_HACKS_H + +#include + +xkb_mod_mask_t +my_xkb_keymap_mod_get_mask(struct xkb_keymap *keymap, xkb_mod_index_t idx); + +#endif /* XKBCOMMON_HACKS_H */