[wayland] Pass xkb keymap to Wayland server

When creating a new xkb keymap we need to pass it to the Wayland server's
seat. As the Wayland protocol expects the keymap as a file descriptor, a
temporary file is created, mmapped and the keymap written into it. As
the Wayland protocol doesn't restrict how long the file descriptor needs
to be valid we keep any created temporary file around till the
InputRedirection gets destroyed.
This commit is contained in:
Martin Gräßlin 2015-05-28 10:17:41 +02:00
parent 988ce28943
commit 3b4c508ee3
2 changed files with 50 additions and 4 deletions

View file

@ -41,6 +41,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Qt
#include <QKeyEvent>
#include <QMouseEvent>
#include <QTemporaryFile>
// KDE
#include <kkeyserver.h>
#if HAVE_XKB
@ -50,13 +51,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// system
#include <linux/input.h>
#include <sys/mman.h>
#include <unistd.h>
namespace KWin
{
#if HAVE_XKB
Xkb::Xkb()
: m_context(xkb_context_new(static_cast<xkb_context_flags>(0)))
Xkb::Xkb(InputRedirection *input)
: m_input(input)
, m_context(xkb_context_new(static_cast<xkb_context_flags>(0)))
, m_keymap(NULL)
, m_state(NULL)
, m_shiftModifier(0)
@ -123,6 +126,47 @@ void Xkb::updateKeymap(xkb_keymap *keymap)
m_controlModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CTRL);
m_altModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_ALT);
m_metaModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_LOGO);
createKeymapFile();
}
void Xkb::createKeymapFile()
{
#if HAVE_WAYLAND
if (!waylandServer()) {
return;
}
// TODO: uninstall keymap on server?
if (!m_keymap) {
return;
}
ScopedCPointer<char> keymapString(xkb_keymap_get_as_string(m_keymap, XKB_KEYMAP_FORMAT_TEXT_V1));
if (keymapString.isNull()) {
return;
}
const uint size = qstrlen(keymapString.data()) + 1;
QTemporaryFile *tmp = new QTemporaryFile(m_input);
if (!tmp->open()) {
delete tmp;
return;
}
unlink(tmp->fileName().toUtf8().constData());
if (!tmp->resize(size)) {
delete tmp;
return;
}
uchar *address = tmp->map(0, size);
if (!address) {
return;
}
if (qstrncpy(reinterpret_cast<char*>(address), keymapString.data(), size) == nullptr) {
delete tmp;
return;
}
waylandServer()->seat()->setKeymap(tmp->handle(), size);
#endif
}
void Xkb::updateModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group)
@ -195,7 +239,7 @@ KWIN_SINGLETON_FACTORY(InputRedirection)
InputRedirection::InputRedirection(QObject *parent)
: QObject(parent)
#if HAVE_XKB
, m_xkb(new Xkb())
, m_xkb(new Xkb(this))
#endif
, m_pointerWindow()
, m_shortcuts(new GlobalShortcutsManager(this))

View file

@ -213,7 +213,7 @@ private:
class Xkb
{
public:
Xkb();
Xkb(InputRedirection *input);
~Xkb();
void installKeymap(int fd, uint32_t size);
void updateModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group);
@ -224,7 +224,9 @@ public:
Qt::KeyboardModifiers modifiers() const;
private:
void updateKeymap(xkb_keymap *keymap);
void createKeymapFile();
void updateModifiers();
InputRedirection *m_input;
xkb_context *m_context;
xkb_keymap *m_keymap;
xkb_state *m_state;