client: rework xkb context/keymap/state handling

- Use smart pointers from xkbcommon_support-private.

- Remove needless strdup() calls.

- Don't recreate context. And move it into qwaylanddisplay so it can
be shared in future between several keyboards. It contains things like
a logging level and include paths.

Change-Id: I5d1f667e710046e6b62aa2caf82fdb2decc24520
Reviewed-by: Johan Helsing <johan.helsing@qt.io>
This commit is contained in:
Gatis Paeglis 2018-12-13 22:04:18 +01:00
parent 9a782df3e7
commit 90fe97b017
6 changed files with 56 additions and 63 deletions

View File

@ -16,7 +16,7 @@ CONFIG -= precompile_header
CONFIG += link_pkgconfig wayland-scanner CONFIG += link_pkgconfig wayland-scanner
qtConfig(xkbcommon) { qtConfig(xkbcommon) {
QT_PRIVATE += xkbcommon_support-private QT_FOR_PRIVATE += xkbcommon_support-private
} }
qtHaveModule(linuxaccessibility_support_private): \ qtHaveModule(linuxaccessibility_support_private): \

View File

@ -142,6 +142,12 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
mWindowManagerIntegration.reset(new QWaylandWindowManagerIntegration(this)); mWindowManagerIntegration.reset(new QWaylandWindowManagerIntegration(this));
#if QT_CONFIG(xkbcommon)
mXkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
if (!mXkbContext)
qCWarning(lcQpaWayland, "failed to create xkb context");
#endif
forceRoundTrip(); forceRoundTrip();
} }

View File

@ -65,6 +65,10 @@
#include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatforminputcontextfactory_p.h>
#if QT_CONFIG(xkbcommon)
#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
#endif
struct wl_cursor_image; struct wl_cursor_image;
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -111,6 +115,10 @@ public:
QWaylandDisplay(QWaylandIntegration *waylandIntegration); QWaylandDisplay(QWaylandIntegration *waylandIntegration);
~QWaylandDisplay(void) override; ~QWaylandDisplay(void) override;
#if QT_CONFIG(xkbcommon)
struct xkb_context *xkbContext() const { return mXkbContext.get(); }
#endif
QList<QWaylandScreen *> screens() const { return mScreens; } QList<QWaylandScreen *> screens() const { return mScreens; }
QWaylandScreen *screenForOutput(struct wl_output *output) const; QWaylandScreen *screenForOutput(struct wl_output *output) const;
@ -246,6 +254,10 @@ private:
void registry_global(uint32_t id, const QString &interface, uint32_t version) override; void registry_global(uint32_t id, const QString &interface, uint32_t version) override;
void registry_global_remove(uint32_t id) override; void registry_global_remove(uint32_t id) override;
#if QT_CONFIG(xkbcommon)
QXkbCommon::ScopedXKBContext mXkbContext;
#endif
friend class QWaylandIntegration; friend class QWaylandIntegration;
}; };

View File

@ -70,10 +70,6 @@
#include <QtGui/QGuiApplication> #include <QtGui/QGuiApplication>
#if QT_CONFIG(xkbcommon)
#include <xkbcommon/xkbcommon.h>
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace QtWaylandClient { namespace QtWaylandClient {
@ -85,51 +81,34 @@ QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
} }
#if QT_CONFIG(xkbcommon) #if QT_CONFIG(xkbcommon)
bool QWaylandInputDevice::Keyboard::createDefaultKeyMap() bool QWaylandInputDevice::Keyboard::createDefaultKeymap()
{ {
if (mXkbContext && mXkbMap && mXkbState) { struct xkb_context *ctx = mParent->mQDisplay->xkbContext();
return true; if (!ctx)
} return false;
xkb_rule_names names; struct xkb_rule_names names;
names.rules = strdup("evdev"); names.rules = "evdev";
names.model = strdup("pc105"); names.model = "pc105";
names.layout = strdup("us"); names.layout = "us";
names.variant = strdup(""); names.variant = "";
names.options = strdup(""); names.options = "";
mXkbContext = xkb_context_new(xkb_context_flags(0)); mXkbKeymap.reset(xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS));
if (mXkbContext) { if (mXkbKeymap)
mXkbMap = xkb_map_new_from_names(mXkbContext, &names, xkb_map_compile_flags(0)); mXkbState.reset(xkb_state_new(mXkbKeymap.get()));
if (mXkbMap) {
mXkbState = xkb_state_new(mXkbMap);
}
}
if (!mXkbContext || !mXkbMap || !mXkbState) { if (!mXkbKeymap || !mXkbState) {
qWarning() << "xkb_map_new_from_names failed, no key input"; qCWarning(lcQpaWayland, "failed to create default keymap");
return false; return false;
} }
return true; return true;
} }
void QWaylandInputDevice::Keyboard::releaseKeyMap()
{
if (mXkbState)
xkb_state_unref(mXkbState);
if (mXkbMap)
xkb_map_unref(mXkbMap);
if (mXkbContext)
xkb_context_unref(mXkbContext);
}
#endif #endif
QWaylandInputDevice::Keyboard::~Keyboard() QWaylandInputDevice::Keyboard::~Keyboard()
{ {
#if QT_CONFIG(xkbcommon)
releaseKeyMap();
#endif
if (mFocus) if (mFocus)
QWindowSystemInterface::handleWindowActivated(nullptr); QWindowSystemInterface::handleWindowActivated(nullptr);
if (mParent->mVersion >= 3) if (mParent->mVersion >= 3)
@ -501,7 +480,7 @@ Qt::KeyboardModifiers QWaylandInputDevice::Keyboard::modifiers() const
if (!mXkbState) if (!mXkbState)
return ret; return ret;
ret = QWaylandXkb::modifiers(mXkbState); ret = QWaylandXkb::modifiers(mXkbState.get());
#endif #endif
return ret; return ret;
@ -761,16 +740,16 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd,
return; return;
} }
// Release the old keymap resources in the case they were already created in mXkbKeymap.reset(xkb_keymap_new_from_string(mParent->mQDisplay->xkbContext(), map_str,
// the key event or when the compositor issues a new map XKB_KEYMAP_FORMAT_TEXT_V1,
releaseKeyMap(); XKB_KEYMAP_COMPILE_NO_FLAGS));
mXkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
mXkbMap = xkb_map_new_from_string(mXkbContext, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
munmap(map_str, size); munmap(map_str, size);
close(fd); close(fd);
mXkbState = xkb_state_new(mXkbMap); if (mXkbKeymap)
mXkbState.reset(xkb_state_new(mXkbKeymap.get()));
else
mXkbState.reset(nullptr);
#else #else
Q_UNUSED(format); Q_UNUSED(format);
Q_UNUSED(fd); Q_UNUSED(fd);
@ -860,11 +839,10 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
mParent->mQDisplay->setLastInputDevice(mParent, serial, window); mParent->mQDisplay->setLastInputDevice(mParent, serial, window);
#if QT_CONFIG(xkbcommon) #if QT_CONFIG(xkbcommon)
if (!createDefaultKeyMap()) { if ((!mXkbKeymap || !mXkbState) && !createDefaultKeymap())
return; return;
}
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, code); xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code);
Qt::KeyboardModifiers modifiers = mParent->modifiers(); Qt::KeyboardModifiers modifiers = mParent->modifiers();
@ -878,7 +856,7 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
if (state == WL_KEYBOARD_KEY_STATE_PRESSED if (state == WL_KEYBOARD_KEY_STATE_PRESSED
#if QT_CONFIG(xkbcommon) #if QT_CONFIG(xkbcommon)
&& xkb_keymap_key_repeats(mXkbMap, code) && xkb_keymap_key_repeats(mXkbKeymap.get(), code)
#endif #endif
) { ) {
mRepeatKey = qtkey; mRepeatKey = qtkey;
@ -952,7 +930,7 @@ void QWaylandInputDevice::Keyboard::keyboard_modifiers(uint32_t serial,
Q_UNUSED(serial); Q_UNUSED(serial);
#if QT_CONFIG(xkbcommon) #if QT_CONFIG(xkbcommon)
if (mXkbState) if (mXkbState)
xkb_state_update_mask(mXkbState, xkb_state_update_mask(mXkbState.get(),
mods_depressed, mods_latched, mods_locked, mods_depressed, mods_latched, mods_locked,
0, 0, group); 0, 0, group);
mNativeModifiers = mods_depressed | mods_latched | mods_locked; mNativeModifiers = mods_depressed | mods_latched | mods_locked;

View File

@ -65,8 +65,7 @@
#include <QtWaylandClient/private/qwayland-wayland.h> #include <QtWaylandClient/private/qwayland-wayland.h>
#if QT_CONFIG(xkbcommon) #if QT_CONFIG(xkbcommon)
#include <xkbcommon/xkbcommon.h> #include <QtXkbCommonSupport/private/qxkbcommon_p.h>
#include <xkbcommon/xkbcommon-keysyms.h>
#endif #endif
#include <QtCore/QDebug> #include <QtCore/QDebug>
@ -209,11 +208,7 @@ public:
QWaylandInputDevice *mParent = nullptr; QWaylandInputDevice *mParent = nullptr;
::wl_surface *mFocus = nullptr; ::wl_surface *mFocus = nullptr;
#if QT_CONFIG(xkbcommon)
xkb_context *mXkbContext = nullptr;
xkb_keymap *mXkbMap = nullptr;
xkb_state *mXkbState = nullptr;
#endif
uint32_t mNativeModifiers = 0; uint32_t mNativeModifiers = 0;
int mRepeatKey; int mRepeatKey;
@ -222,9 +217,6 @@ public:
int mRepeatRate = 25; int mRepeatRate = 25;
int mRepeatDelay = 400; int mRepeatDelay = 400;
QString mRepeatText; QString mRepeatText;
#if QT_CONFIG(xkbcommon)
xkb_keysym_t mRepeatSym;
#endif
QTimer mRepeatTimer; QTimer mRepeatTimer;
Qt::KeyboardModifiers modifiers() const; Qt::KeyboardModifiers modifiers() const;
@ -236,12 +228,17 @@ private slots:
private: private:
#if QT_CONFIG(xkbcommon) #if QT_CONFIG(xkbcommon)
bool createDefaultKeyMap(); bool createDefaultKeymap();
void releaseKeyMap();
#endif #endif
void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers,
const QString& text = QString(), bool autorep = false, ushort count = 1); const QString& text = QString(), bool autorep = false, ushort count = 1);
#if QT_CONFIG(xkbcommon)
xkb_keysym_t mRepeatSym = XKB_KEY_NoSymbol;
QXkbCommon::ScopedXKBKeymap mXkbKeymap;
QXkbCommon::ScopedXKBState mXkbState;
#endif
}; };
class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer

View File

@ -479,7 +479,7 @@ void QWaylandIntegration::reconfigureInputContext()
mInputContext.reset(QPlatformInputContextFactory::create(defaultInputContext)); mInputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
#if QT_CONFIG(xkbcommon) #if QT_CONFIG(xkbcommon)
QXkbCommon::setXkbContext(mInputContext.data(), xkb_context_new(XKB_CONTEXT_NO_FLAGS)); QXkbCommon::setXkbContext(mInputContext.data(), mDisplay->xkbContext());
#endif #endif
// Even if compositor-side input context handling has been requested, we fallback to // Even if compositor-side input context handling has been requested, we fallback to