Merge remote-tracking branch 'origin/5.13' into dev
Conflicts: src/client/qwaylanddisplay_p.h src/client/qwaylandwindow.cpp Change-Id: I50eb5c83a8b81e4bdb032b68d41f429b17d0a74d
This commit is contained in:
commit
8607ca5ca2
@ -178,7 +178,7 @@ Copyright © 2015, 2016 Jan Arne Petersen"
|
||||
"Name": "Wayland EGLStream Controller Protocol",
|
||||
"QDocModule": "qtwaylandcompositor",
|
||||
"QtUsage": "Used in the Qt Wayland Compositor",
|
||||
"Files": "wayland-eglstream-controller.xml",
|
||||
"Files": "wl-eglstream-controller.xml",
|
||||
|
||||
"Description": "Allows clients to request that the compositor creates its EGLStream.",
|
||||
"Homepage": "https://github.com/NVIDIA/egl-wayland",
|
||||
|
@ -15,8 +15,9 @@ use_gold_linker: CONFIG += no_linker_version_script
|
||||
CONFIG -= precompile_header
|
||||
CONFIG += link_pkgconfig wayland-scanner
|
||||
|
||||
qtConfig(xkbcommon): \
|
||||
QMAKE_USE_PRIVATE += xkbcommon
|
||||
qtConfig(xkbcommon) {
|
||||
QT_FOR_PRIVATE += xkbcommon_support-private
|
||||
}
|
||||
|
||||
qtHaveModule(linuxaccessibility_support_private): \
|
||||
QT += linuxaccessibility_support_private
|
||||
@ -49,7 +50,6 @@ SOURCES += qwaylandintegration.cpp \
|
||||
qwaylandtouch.cpp \
|
||||
qwaylandqtkey.cpp \
|
||||
../shared/qwaylandmimehelper.cpp \
|
||||
../shared/qwaylandxkb.cpp \
|
||||
../shared/qwaylandinputmethodeventbuilder.cpp \
|
||||
qwaylandabstractdecoration.cpp \
|
||||
qwaylanddecorationfactory.cpp \
|
||||
@ -84,7 +84,6 @@ HEADERS += qwaylandintegration_p.h \
|
||||
qtwaylandclientglobal_p.h \
|
||||
../shared/qwaylandinputmethodeventbuilder_p.h \
|
||||
../shared/qwaylandmimehelper_p.h \
|
||||
../shared/qwaylandxkb_p.h \
|
||||
../shared/qwaylandsharedmemoryformathelper_p.h \
|
||||
|
||||
qtConfig(clipboard) {
|
||||
|
@ -109,21 +109,21 @@ QWaylandBradientDecoration::QWaylandBradientDecoration()
|
||||
|
||||
QRectF QWaylandBradientDecoration::closeButtonRect() const
|
||||
{
|
||||
const int windowRight = waylandWindow()->windowGeometry().right() + 1;
|
||||
const int windowRight = waylandWindow()->windowContentGeometry().right() + 1;
|
||||
return QRectF(windowRight - BUTTON_WIDTH - BUTTON_SPACING * 0 - BUTTONS_RIGHT_MARGIN,
|
||||
(margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH);
|
||||
}
|
||||
|
||||
QRectF QWaylandBradientDecoration::maximizeButtonRect() const
|
||||
{
|
||||
const int windowRight = waylandWindow()->windowGeometry().right() + 1;
|
||||
const int windowRight = waylandWindow()->windowContentGeometry().right() + 1;
|
||||
return QRectF(windowRight - BUTTON_WIDTH * 2 - BUTTON_SPACING * 1 - BUTTONS_RIGHT_MARGIN,
|
||||
(margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH);
|
||||
}
|
||||
|
||||
QRectF QWaylandBradientDecoration::minimizeButtonRect() const
|
||||
{
|
||||
const int windowRight = waylandWindow()->windowGeometry().right() + 1;
|
||||
const int windowRight = waylandWindow()->windowContentGeometry().right() + 1;
|
||||
return QRectF(windowRight - BUTTON_WIDTH * 3 - BUTTON_SPACING * 2 - BUTTONS_RIGHT_MARGIN,
|
||||
(margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH);
|
||||
}
|
||||
@ -136,7 +136,7 @@ QMargins QWaylandBradientDecoration::margins() const
|
||||
void QWaylandBradientDecoration::paint(QPaintDevice *device)
|
||||
{
|
||||
bool active = window()->handle()->isActive();
|
||||
QRect wg = waylandWindow()->windowGeometry();
|
||||
QRect wg = waylandWindow()->windowContentGeometry();
|
||||
QRect clips[] =
|
||||
{
|
||||
QRect(wg.left(), wg.top(), wg.width(), margins().top()),
|
||||
@ -267,7 +267,7 @@ bool QWaylandBradientDecoration::handleMouse(QWaylandInputDevice *inputDevice, c
|
||||
Q_UNUSED(global);
|
||||
|
||||
// Figure out what area mouse is in
|
||||
QRect wg = waylandWindow()->windowGeometry();
|
||||
QRect wg = waylandWindow()->windowContentGeometry();
|
||||
if (local.y() <= wg.top() + margins().top()) {
|
||||
processMouseTop(inputDevice,local,b,mods);
|
||||
} else if (local.y() > wg.bottom() - margins().bottom()) {
|
||||
@ -312,7 +312,7 @@ bool QWaylandBradientDecoration::handleTouch(QWaylandInputDevice *inputDevice, c
|
||||
|
||||
void QWaylandBradientDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
|
||||
{
|
||||
QRect wg = waylandWindow()->windowGeometry();
|
||||
QRect wg = waylandWindow()->windowContentGeometry();
|
||||
Q_UNUSED(mods);
|
||||
if (local.y() <= wg.top() + margins().bottom()) {
|
||||
if (local.x() <= margins().left()) {
|
||||
|
@ -70,6 +70,8 @@
|
||||
|
||||
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
|
||||
|
||||
#include <QtCore/private/qcore_unix_p.h>
|
||||
|
||||
#include <QtCore/QAbstractEventDispatcher>
|
||||
#include <QtGui/qpa/qwindowsysteminterface.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
@ -91,13 +93,6 @@ struct wl_surface *QWaylandDisplay::createSurface(void *handle)
|
||||
return surface;
|
||||
}
|
||||
|
||||
QWaylandShellSurface *QWaylandDisplay::createShellSurface(QWaylandWindow *window)
|
||||
{
|
||||
if (!mWaylandIntegration->shellIntegration())
|
||||
return nullptr;
|
||||
return mWaylandIntegration->shellIntegration()->createShellSurface(window);
|
||||
}
|
||||
|
||||
struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
|
||||
{
|
||||
struct ::wl_region *region = mCompositor.create_region();
|
||||
@ -111,12 +106,18 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
|
||||
::wl_subsurface *QWaylandDisplay::createSubSurface(QWaylandWindow *window, QWaylandWindow *parent)
|
||||
{
|
||||
if (!mSubCompositor) {
|
||||
qCWarning(lcQpaWayland) << "Can't create subsurface, not supported by the compositor.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mSubCompositor->get_subsurface(window->wlSurface(), parent->wlSurface());
|
||||
}
|
||||
|
||||
QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const
|
||||
{
|
||||
return mWaylandIntegration->shellIntegration();
|
||||
}
|
||||
|
||||
QWaylandClientBufferIntegration * QWaylandDisplay::clientBufferIntegration() const
|
||||
{
|
||||
return mWaylandIntegration->clientBufferIntegration();
|
||||
@ -143,7 +144,18 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
|
||||
|
||||
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();
|
||||
|
||||
if (!mWaitingScreens.isEmpty()) {
|
||||
// Give wl_output.done and zxdg_output_v1.done events a chance to arrive
|
||||
forceRoundTrip();
|
||||
}
|
||||
}
|
||||
|
||||
QWaylandDisplay::~QWaylandDisplay(void)
|
||||
@ -158,6 +170,7 @@ QWaylandDisplay::~QWaylandDisplay(void)
|
||||
QWindowSystemInterface::handleScreenRemoved(screen);
|
||||
}
|
||||
mScreens.clear();
|
||||
qDeleteAll(mWaitingScreens);
|
||||
|
||||
#if QT_CONFIG(wayland_datadevice)
|
||||
delete mDndSelectionHandler.take();
|
||||
@ -194,7 +207,6 @@ void QWaylandDisplay::flushRequests()
|
||||
wl_display_flush(mDisplay);
|
||||
}
|
||||
|
||||
|
||||
void QWaylandDisplay::blockingReadEvents()
|
||||
{
|
||||
if (wl_display_dispatch(mDisplay) < 0) {
|
||||
@ -208,6 +220,41 @@ void QWaylandDisplay::exitWithError()
|
||||
::exit(1);
|
||||
}
|
||||
|
||||
wl_event_queue *QWaylandDisplay::createEventQueue()
|
||||
{
|
||||
return wl_display_create_queue(mDisplay);
|
||||
}
|
||||
|
||||
void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout)
|
||||
{
|
||||
if (!condition())
|
||||
return;
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN);
|
||||
while (timeout == -1 || timer.elapsed() < timeout) {
|
||||
while (wl_display_prepare_read_queue(mDisplay, queue) != 0)
|
||||
wl_display_dispatch_queue_pending(mDisplay, queue);
|
||||
|
||||
wl_display_flush(mDisplay);
|
||||
|
||||
const int remaining = qMax(timeout - timer.elapsed(), 0ll);
|
||||
const int pollTimeout = timeout == -1 ? -1 : remaining;
|
||||
if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0)
|
||||
wl_display_read_events(mDisplay);
|
||||
else
|
||||
wl_display_cancel_read(mDisplay);
|
||||
|
||||
if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0) {
|
||||
checkError();
|
||||
exitWithError();
|
||||
}
|
||||
if (!condition())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
||||
{
|
||||
for (int i = 0; i < mScreens.size(); ++i) {
|
||||
@ -218,6 +265,14 @@ QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen)
|
||||
{
|
||||
if (!mWaitingScreens.removeOne(screen))
|
||||
return;
|
||||
mScreens.append(screen);
|
||||
QWindowSystemInterface::handleScreenAdded(screen);
|
||||
}
|
||||
|
||||
void QWaylandDisplay::waitForScreens()
|
||||
{
|
||||
flushRequests();
|
||||
@ -242,11 +297,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||||
struct ::wl_registry *registry = object();
|
||||
|
||||
if (interface == QStringLiteral("wl_output")) {
|
||||
QWaylandScreen *screen = new QWaylandScreen(this, version, id);
|
||||
mScreens.append(screen);
|
||||
// We need to get the output events before creating surfaces
|
||||
forceRoundTrip();
|
||||
QWindowSystemInterface::handleScreenAdded(screen);
|
||||
mWaitingScreens << new QWaylandScreen(this, version, id);
|
||||
} else if (interface == QStringLiteral("wl_compositor")) {
|
||||
mCompositorVersion = qMin((int)version, 3);
|
||||
mCompositor.init(registry, id, mCompositorVersion);
|
||||
@ -267,11 +318,11 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||||
mTouchExtension.reset(new QWaylandTouchExtension(this, id));
|
||||
} else if (interface == QStringLiteral("zqt_key_v1")) {
|
||||
mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
|
||||
} else if (interface == QStringLiteral("zwp_text_input_manager_v2")) {
|
||||
} else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) {
|
||||
mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
|
||||
foreach (QWaylandInputDevice *inputDevice, mInputDevices) {
|
||||
for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
|
||||
inputDevice->setTextInput(new QWaylandTextInput(this, mTextInputManager->get_text_input(inputDevice->wl_seat())));
|
||||
}
|
||||
mWaylandIntegration->reconfigureInputContext();
|
||||
} else if (interface == QStringLiteral("qt_hardware_integration")) {
|
||||
bool disableHardwareIntegration = qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_HW_INTEGRATION");
|
||||
if (!disableHardwareIntegration) {
|
||||
@ -282,7 +333,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||||
}
|
||||
} else if (interface == QLatin1String("zxdg_output_manager_v1")) {
|
||||
mXdgOutputManager.reset(new QtWayland::zxdg_output_manager_v1(registry, id, qMin(2, int(version))));
|
||||
for (auto *screen : qAsConst(mScreens))
|
||||
for (auto *screen : qAsConst(mWaitingScreens))
|
||||
screen->initXdgOutput(xdgOutputManager());
|
||||
forceRoundTrip();
|
||||
}
|
||||
@ -299,6 +350,14 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
|
||||
RegistryGlobal &global = mGlobals[i];
|
||||
if (global.id == id) {
|
||||
if (global.interface == QStringLiteral("wl_output")) {
|
||||
for (auto *screen : mWaitingScreens) {
|
||||
if (screen->outputId() == id) {
|
||||
mWaitingScreens.removeOne(screen);
|
||||
delete screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (QWaylandScreen *screen, mScreens) {
|
||||
if (screen->outputId() == id) {
|
||||
mScreens.removeOne(screen);
|
||||
@ -307,6 +366,12 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (global.interface == QStringLiteral("zwp_text_input_manager_v2")) {
|
||||
mTextInputManager.reset();
|
||||
for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
|
||||
inputDevice->setTextInput(nullptr);
|
||||
mWaylandIntegration->reconfigureInputContext();
|
||||
}
|
||||
mGlobals.removeAt(i);
|
||||
break;
|
||||
}
|
||||
|
@ -63,6 +63,12 @@
|
||||
#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
|
||||
#include <QtWaylandClient/private/qwaylandshm_p.h>
|
||||
|
||||
#include <qpa/qplatforminputcontextfactory_p.h>
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
|
||||
#endif
|
||||
|
||||
struct wl_cursor_image;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -92,8 +98,8 @@ class QWaylandQtKeyExtension;
|
||||
class QWaylandWindow;
|
||||
class QWaylandIntegration;
|
||||
class QWaylandHardwareIntegration;
|
||||
class QWaylandShellSurface;
|
||||
class QWaylandSurface;
|
||||
class QWaylandShellIntegration;
|
||||
class QWaylandCursor;
|
||||
class QWaylandCursorTheme;
|
||||
|
||||
@ -110,18 +116,23 @@ public:
|
||||
QWaylandDisplay(QWaylandIntegration *waylandIntegration);
|
||||
~QWaylandDisplay(void) override;
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
struct xkb_context *xkbContext() const { return mXkbContext.get(); }
|
||||
#endif
|
||||
|
||||
QList<QWaylandScreen *> screens() const { return mScreens; }
|
||||
|
||||
QWaylandScreen *screenForOutput(struct wl_output *output) const;
|
||||
void handleScreenInitialized(QWaylandScreen *screen);
|
||||
|
||||
struct wl_surface *createSurface(void *handle);
|
||||
QWaylandShellSurface *createShellSurface(QWaylandWindow *window);
|
||||
struct ::wl_region *createRegion(const QRegion &qregion);
|
||||
struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent);
|
||||
|
||||
QWaylandShellIntegration *shellIntegration() const;
|
||||
QWaylandClientBufferIntegration *clientBufferIntegration() const;
|
||||
|
||||
QWaylandWindowManagerIntegration *windowManagerIntegration() const;
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
QWaylandCursor *waylandCursor();
|
||||
QWaylandCursorTheme *loadCursorTheme(const QString &name, int pixelSize);
|
||||
@ -145,6 +156,7 @@ public:
|
||||
QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); }
|
||||
QtWayland::zxdg_output_manager_v1 *xdgOutputManager() const { return mXdgOutputManager.data(); }
|
||||
|
||||
bool usingInputContextFromCompositor() const { return mUsingInputContextFromCompositor; }
|
||||
|
||||
struct RegistryGlobal {
|
||||
uint32_t id;
|
||||
@ -181,6 +193,9 @@ public:
|
||||
void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice);
|
||||
void handleWindowDestroyed(QWaylandWindow *window);
|
||||
|
||||
wl_event_queue *createEventQueue();
|
||||
void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
|
||||
|
||||
public slots:
|
||||
void blockingReadEvents();
|
||||
void flushRequests();
|
||||
@ -206,6 +221,7 @@ private:
|
||||
struct wl_display *mDisplay = nullptr;
|
||||
QtWayland::wl_compositor mCompositor;
|
||||
QScopedPointer<QWaylandShm> mShm;
|
||||
QList<QWaylandScreen *> mWaitingScreens;
|
||||
QList<QWaylandScreen *> mScreens;
|
||||
QList<QWaylandInputDevice *> mInputDevices;
|
||||
QList<Listener> mRegistryListeners;
|
||||
@ -238,8 +254,17 @@ private:
|
||||
struct wl_callback *mSyncCallback = nullptr;
|
||||
static const wl_callback_listener syncCallbackListener;
|
||||
|
||||
bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
|
||||
bool mUsingInputContextFromCompositor = false;
|
||||
|
||||
void registry_global(uint32_t id, const QString &interface, uint32_t version) override;
|
||||
void registry_global_remove(uint32_t id) override;
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
QXkbCommon::ScopedXKBContext mXkbContext;
|
||||
#endif
|
||||
|
||||
friend class QWaylandIntegration;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -50,7 +50,6 @@
|
||||
#include "qwaylandinputdevice_p.h"
|
||||
#include "qwaylandinputmethodeventbuilder_p.h"
|
||||
#include "qwaylandwindow_p.h"
|
||||
#include "qwaylandxkb_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -315,6 +314,7 @@ void QWaylandTextInput::zwp_text_input_v2_delete_surrounding_text(uint32_t befor
|
||||
|
||||
void QWaylandTextInput::zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers)
|
||||
{
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
if (m_resetCallback) {
|
||||
qCDebug(qLcQpaInputMethods()) << "discard keysym: reset not confirmed";
|
||||
return;
|
||||
@ -325,13 +325,18 @@ void QWaylandTextInput::zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, ui
|
||||
|
||||
Qt::KeyboardModifiers qtModifiers = modifiersToQtModifiers(modifiers);
|
||||
|
||||
QEvent::Type type = QWaylandXkb::toQtEventType(state);
|
||||
QString text;
|
||||
int qtkey;
|
||||
std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, qtModifiers);
|
||||
QEvent::Type type = state == WL_KEYBOARD_KEY_STATE_PRESSED ? QEvent::KeyPress : QEvent::KeyRelease;
|
||||
QString text = QXkbCommon::lookupStringNoKeysymTransformations(sym);
|
||||
int qtkey = QXkbCommon::keysymToQtKey(sym, qtModifiers);
|
||||
|
||||
QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(),
|
||||
time, type, qtkey, qtModifiers, text);
|
||||
#else
|
||||
Q_UNUSED(time);
|
||||
Q_UNUSED(sym);
|
||||
Q_UNUSED(state);
|
||||
Q_UNUSED(modifiers);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QWaylandTextInput::zwp_text_input_v2_language(const QString &language)
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include "qwaylandcursor_p.h"
|
||||
#include "qwaylanddisplay_p.h"
|
||||
#include "qwaylandshmbackingstore_p.h"
|
||||
#include "../shared/qwaylandxkb_p.h"
|
||||
#include "qwaylandinputcontext_p.h"
|
||||
|
||||
#include <QtGui/private/qpixmap_raster_p.h>
|
||||
@ -71,10 +70,6 @@
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
#include <xkbcommon/xkbcommon-compose.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
@ -84,85 +79,51 @@ Q_LOGGING_CATEGORY(lcQpaWaylandInput, "qt.qpa.wayland.input");
|
||||
QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
|
||||
: mParent(p)
|
||||
{
|
||||
connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey()));
|
||||
mRepeatTimer.callOnTimeout([&]() {
|
||||
if (!focusWindow()) {
|
||||
// We destroyed the keyboard focus surface, but the server didn't get the message yet...
|
||||
// or the server didn't send an enter event first.
|
||||
return;
|
||||
}
|
||||
mRepeatTimer.setInterval(mRepeatRate);
|
||||
handleKey(mRepeatKey.time, QEvent::KeyRelease, mRepeatKey.key, mRepeatKey.modifiers,
|
||||
mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers,
|
||||
mRepeatKey.text, true);
|
||||
handleKey(mRepeatKey.time, QEvent::KeyPress, mRepeatKey.key, mRepeatKey.modifiers,
|
||||
mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers,
|
||||
mRepeatKey.text, true);
|
||||
});
|
||||
}
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
bool QWaylandInputDevice::Keyboard::createDefaultKeyMap()
|
||||
bool QWaylandInputDevice::Keyboard::createDefaultKeymap()
|
||||
{
|
||||
if (mXkbContext && mXkbMap && mXkbState) {
|
||||
return true;
|
||||
}
|
||||
struct xkb_context *ctx = mParent->mQDisplay->xkbContext();
|
||||
if (!ctx)
|
||||
return false;
|
||||
|
||||
xkb_rule_names names;
|
||||
names.rules = strdup("evdev");
|
||||
names.model = strdup("pc105");
|
||||
names.layout = strdup("us");
|
||||
names.variant = strdup("");
|
||||
names.options = strdup("");
|
||||
struct xkb_rule_names names;
|
||||
names.rules = "evdev";
|
||||
names.model = "pc105";
|
||||
names.layout = "us";
|
||||
names.variant = "";
|
||||
names.options = "";
|
||||
|
||||
mXkbContext = xkb_context_new(xkb_context_flags(0));
|
||||
if (mXkbContext) {
|
||||
mXkbMap = xkb_map_new_from_names(mXkbContext, &names, xkb_map_compile_flags(0));
|
||||
if (mXkbMap) {
|
||||
mXkbState = xkb_state_new(mXkbMap);
|
||||
}
|
||||
}
|
||||
mXkbKeymap.reset(xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS));
|
||||
if (mXkbKeymap)
|
||||
mXkbState.reset(xkb_state_new(mXkbKeymap.get()));
|
||||
|
||||
if (!mXkbContext || !mXkbMap || !mXkbState) {
|
||||
qWarning() << "xkb_map_new_from_names failed, no key input";
|
||||
if (!mXkbKeymap || !mXkbState) {
|
||||
qCWarning(lcQpaWayland, "failed to create default keymap");
|
||||
return false;
|
||||
}
|
||||
createComposeState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Keyboard::releaseKeyMap()
|
||||
{
|
||||
if (mXkbState)
|
||||
xkb_state_unref(mXkbState);
|
||||
if (mXkbMap)
|
||||
xkb_map_unref(mXkbMap);
|
||||
if (mXkbContext)
|
||||
xkb_context_unref(mXkbContext);
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Keyboard::createComposeState()
|
||||
{
|
||||
static const char *locale = nullptr;
|
||||
if (!locale) {
|
||||
locale = getenv("LC_ALL");
|
||||
if (!locale)
|
||||
locale = getenv("LC_CTYPE");
|
||||
if (!locale)
|
||||
locale = getenv("LANG");
|
||||
if (!locale)
|
||||
locale = "C";
|
||||
}
|
||||
|
||||
mXkbComposeTable = xkb_compose_table_new_from_locale(mXkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
if (mXkbComposeTable)
|
||||
mXkbComposeState = xkb_compose_state_new(mXkbComposeTable, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Keyboard::releaseComposeState()
|
||||
{
|
||||
if (mXkbComposeState)
|
||||
xkb_compose_state_unref(mXkbComposeState);
|
||||
if (mXkbComposeTable)
|
||||
xkb_compose_table_unref(mXkbComposeTable);
|
||||
mXkbComposeState = nullptr;
|
||||
mXkbComposeTable = nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
QWaylandInputDevice::Keyboard::~Keyboard()
|
||||
{
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
releaseComposeState();
|
||||
releaseKeyMap();
|
||||
#endif
|
||||
if (mFocus)
|
||||
QWindowSystemInterface::handleWindowActivated(nullptr);
|
||||
if (mParent->mVersion >= 3)
|
||||
@ -402,9 +363,9 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mQDisplay->textInputManager()) {
|
||||
mTextInput = new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat()));
|
||||
}
|
||||
if (mQDisplay->textInputManager())
|
||||
mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())));
|
||||
|
||||
}
|
||||
|
||||
QWaylandInputDevice::~QWaylandInputDevice()
|
||||
@ -487,12 +448,12 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const
|
||||
|
||||
void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput)
|
||||
{
|
||||
mTextInput = textInput;
|
||||
mTextInput.reset(textInput);
|
||||
}
|
||||
|
||||
QWaylandTextInput *QWaylandInputDevice::textInput() const
|
||||
{
|
||||
return mTextInput;
|
||||
return mTextInput.data();
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button)
|
||||
@ -521,6 +482,17 @@ QPointF QWaylandInputDevice::pointerSurfacePosition() const
|
||||
return mPointer ? mPointer->mSurfacePos : QPointF();
|
||||
}
|
||||
|
||||
QList<int> QWaylandInputDevice::possibleKeys(const QKeyEvent *event) const
|
||||
{
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
if (mKeyboard && mKeyboard->mXkbState)
|
||||
return QXkbCommon::possibleKeys(mKeyboard->mXkbState.get(), event);
|
||||
#else
|
||||
Q_UNUSED(event);
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers QWaylandInputDevice::modifiers() const
|
||||
{
|
||||
if (!mKeyboard)
|
||||
@ -537,7 +509,7 @@ Qt::KeyboardModifiers QWaylandInputDevice::Keyboard::modifiers() const
|
||||
if (!mXkbState)
|
||||
return ret;
|
||||
|
||||
ret = QWaylandXkb::modifiers(mXkbState);
|
||||
ret = QXkbCommon::modifiers(mXkbState.get());
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
@ -1045,8 +1017,10 @@ bool QWaylandInputDevice::Pointer::isDefinitelyTerminated(QtWayland::wl_pointer:
|
||||
|
||||
void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, uint32_t size)
|
||||
{
|
||||
mKeymapFormat = format;
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
||||
qCWarning(lcQpaWayland) << "unknown keymap format:" << format;
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
@ -1057,21 +1031,19 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd,
|
||||
return;
|
||||
}
|
||||
|
||||
// Release the old keymap resources in the case they were already created in
|
||||
// the key event or when the compositor issues a new map
|
||||
releaseComposeState();
|
||||
releaseKeyMap();
|
||||
mXkbKeymap.reset(xkb_keymap_new_from_string(mParent->mQDisplay->xkbContext(), map_str,
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS));
|
||||
QXkbCommon::verifyHasLatinLayout(mXkbKeymap.get());
|
||||
|
||||
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);
|
||||
close(fd);
|
||||
|
||||
mXkbState = xkb_state_new(mXkbMap);
|
||||
createComposeState();
|
||||
|
||||
if (mXkbKeymap)
|
||||
mXkbState.reset(xkb_state_new(mXkbKeymap.get()));
|
||||
else
|
||||
mXkbState.reset(nullptr);
|
||||
#else
|
||||
Q_UNUSED(format);
|
||||
Q_UNUSED(fd);
|
||||
Q_UNUSED(size);
|
||||
#endif
|
||||
@ -1118,28 +1090,34 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf
|
||||
handleFocusLost();
|
||||
}
|
||||
|
||||
static void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
|
||||
quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers,
|
||||
const QString& text = QString(), bool autorep = false, ushort count = 1)
|
||||
void QWaylandInputDevice::Keyboard::handleKey(ulong timestamp, QEvent::Type type, int key,
|
||||
Qt::KeyboardModifiers modifiers, quint32 nativeScanCode,
|
||||
quint32 nativeVirtualKey, quint32 nativeModifiers,
|
||||
const QString &text, bool autorepeat, ushort count)
|
||||
{
|
||||
QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
|
||||
bool filtered = false;
|
||||
|
||||
if (inputContext) {
|
||||
QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
|
||||
text, autorep, count);
|
||||
if (inputContext && !mParent->mQDisplay->usingInputContextFromCompositor()) {
|
||||
QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey,
|
||||
nativeModifiers, text, autorepeat, count);
|
||||
event.setTimestamp(timestamp);
|
||||
filtered = inputContext->filterEvent(&event);
|
||||
}
|
||||
|
||||
if (!filtered) {
|
||||
QWindowSystemInterface::handleExtendedKeyEvent(tlw, timestamp, type, key, modifiers,
|
||||
nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
|
||||
QWindowSystemInterface::handleExtendedKeyEvent(focusWindow()->window(), timestamp, type, key, modifiers,
|
||||
nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorepeat, count);
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
||||
{
|
||||
if (mKeymapFormat != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 && mKeymapFormat != WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
|
||||
qCWarning(lcQpaWayland) << Q_FUNC_INFO << "unknown keymap format:" << mKeymapFormat;
|
||||
return;
|
||||
}
|
||||
|
||||
auto *window = focusWindow();
|
||||
if (!window) {
|
||||
// We destroyed the keyboard focus surface, but the server didn't get the message yet...
|
||||
@ -1147,102 +1125,52 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t code = key + 8;
|
||||
bool isDown = state != WL_KEYBOARD_KEY_STATE_RELEASED;
|
||||
QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease;
|
||||
QString text;
|
||||
int qtkey = key + 8; // qt-compositor substracts 8 for some reason
|
||||
mParent->mSerial = serial;
|
||||
|
||||
const bool isDown = state != WL_KEYBOARD_KEY_STATE_RELEASED;
|
||||
if (isDown)
|
||||
mParent->mQDisplay->setLastInputDevice(mParent, serial, window);
|
||||
|
||||
if (mKeymapFormat == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
if (!createDefaultKeyMap()) {
|
||||
return;
|
||||
}
|
||||
if ((!mXkbKeymap || !mXkbState) && !createDefaultKeymap())
|
||||
return;
|
||||
|
||||
QString composedText;
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, code);
|
||||
if (mXkbComposeState) {
|
||||
if (isDown)
|
||||
xkb_compose_state_feed(mXkbComposeState, sym);
|
||||
xkb_compose_status status = xkb_compose_state_get_status(mXkbComposeState);
|
||||
auto code = key + 8; // map to wl_keyboard::keymap_format::keymap_format_xkb_v1
|
||||
|
||||
switch (status) {
|
||||
case XKB_COMPOSE_COMPOSED: {
|
||||
int size = xkb_compose_state_get_utf8(mXkbComposeState, nullptr, 0);
|
||||
QVarLengthArray<char, 32> buffer(size + 1);
|
||||
xkb_compose_state_get_utf8(mXkbComposeState, buffer.data(), buffer.size());
|
||||
composedText = QString::fromUtf8(buffer.constData());
|
||||
sym = xkb_compose_state_get_one_sym(mXkbComposeState);
|
||||
xkb_compose_state_reset(mXkbComposeState);
|
||||
} break;
|
||||
case XKB_COMPOSE_COMPOSING:
|
||||
case XKB_COMPOSE_CANCELLED:
|
||||
return;
|
||||
case XKB_COMPOSE_NOTHING:
|
||||
break;
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code);
|
||||
|
||||
Qt::KeyboardModifiers modifiers = mParent->modifiers();
|
||||
|
||||
int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, mXkbState.get(), code);
|
||||
QString text = QXkbCommon::lookupString(mXkbState.get(), code);
|
||||
|
||||
QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease;
|
||||
handleKey(time, type, qtkey, modifiers, code, sym, mNativeModifiers, text);
|
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(mXkbKeymap.get(), code)) {
|
||||
mRepeatKey.key = qtkey;
|
||||
mRepeatKey.code = code;
|
||||
mRepeatKey.time = time;
|
||||
mRepeatKey.text = text;
|
||||
mRepeatKey.modifiers = modifiers;
|
||||
mRepeatKey.nativeModifiers = mNativeModifiers;
|
||||
mRepeatKey.nativeVirtualKey = sym;
|
||||
mRepeatTimer.setInterval(mRepeatDelay);
|
||||
mRepeatTimer.start();
|
||||
} else if (mRepeatKey.code == code) {
|
||||
mRepeatTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers modifiers = mParent->modifiers();
|
||||
|
||||
std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers);
|
||||
|
||||
if (!composedText.isNull())
|
||||
text = composedText;
|
||||
|
||||
sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text);
|
||||
#else
|
||||
// Generic fallback for single hard keys: Assume 'key' is a Qt key code.
|
||||
sendKey(window->window(), time, type, qtkey, Qt::NoModifier, code, 0, 0);
|
||||
Q_UNUSED(time);
|
||||
Q_UNUSED(key);
|
||||
qCWarning(lcQpaWayland, "xkbcommon not available on this build, not performing key mapping");
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
&& xkb_keymap_key_repeats(mXkbMap, code)
|
||||
#endif
|
||||
) {
|
||||
mRepeatKey = qtkey;
|
||||
mRepeatCode = code;
|
||||
mRepeatTime = time;
|
||||
mRepeatText = text;
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
mRepeatSym = sym;
|
||||
#endif
|
||||
mRepeatTimer.setInterval(mRepeatDelay);
|
||||
mRepeatTimer.start();
|
||||
} else if (mRepeatCode == code) {
|
||||
mRepeatTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Keyboard::repeatKey()
|
||||
{
|
||||
auto *window = focusWindow();
|
||||
if (!window) {
|
||||
// We destroyed the keyboard focus surface, but the server didn't get the message yet...
|
||||
// or the server didn't send an enter event first.
|
||||
} else if (mKeymapFormat == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
|
||||
// raw scan code
|
||||
return;
|
||||
}
|
||||
|
||||
mRepeatTimer.setInterval(mRepeatRate);
|
||||
sendKey(window->window(), mRepeatTime, QEvent::KeyRelease, mRepeatKey, modifiers(), mRepeatCode,
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
mRepeatSym, mNativeModifiers,
|
||||
#else
|
||||
0, 0,
|
||||
#endif
|
||||
mRepeatText, true);
|
||||
|
||||
sendKey(window->window(), mRepeatTime, QEvent::KeyPress, mRepeatKey, modifiers(), mRepeatCode,
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
mRepeatSym, mNativeModifiers,
|
||||
#else
|
||||
0, 0,
|
||||
#endif
|
||||
mRepeatText, true);
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
|
||||
@ -1275,12 +1203,11 @@ void QWaylandInputDevice::Keyboard::keyboard_modifiers(uint32_t serial,
|
||||
Q_UNUSED(serial);
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
if (mXkbState)
|
||||
xkb_state_update_mask(mXkbState,
|
||||
xkb_state_update_mask(mXkbState.get(),
|
||||
mods_depressed, mods_latched, mods_locked,
|
||||
0, 0, group);
|
||||
mNativeModifiers = mods_depressed | mods_latched | mods_locked;
|
||||
#else
|
||||
Q_UNUSED(serial);
|
||||
Q_UNUSED(mods_depressed);
|
||||
Q_UNUSED(mods_latched);
|
||||
Q_UNUSED(mods_locked);
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
|
||||
#include <QtWaylandClient/private/qwaylandwindow_p.h>
|
||||
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QSocketNotifier>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
@ -64,8 +65,7 @@
|
||||
#include <QtWaylandClient/private/qwayland-wayland.h>
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
|
||||
#endif
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
@ -76,11 +76,6 @@
|
||||
struct wl_cursor_image;
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
struct xkb_compose_state;
|
||||
struct xkb_compose_table;
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
@ -130,6 +125,8 @@ public:
|
||||
QWaylandWindow *keyboardFocus() const;
|
||||
QWaylandWindow *touchFocus() const;
|
||||
|
||||
QList<int> possibleKeys(const QKeyEvent *event) const;
|
||||
|
||||
QPointF pointerSurfacePosition() const;
|
||||
|
||||
Qt::KeyboardModifiers modifiers() const;
|
||||
@ -166,7 +163,7 @@ private:
|
||||
Pointer *mPointer = nullptr;
|
||||
Touch *mTouch = nullptr;
|
||||
|
||||
QWaylandTextInput *mTextInput = nullptr;
|
||||
QScopedPointer<QWaylandTextInput> mTextInput;
|
||||
|
||||
uint32_t mTime = 0;
|
||||
uint32_t mSerial = 0;
|
||||
@ -215,41 +212,44 @@ public:
|
||||
|
||||
QWaylandInputDevice *mParent = nullptr;
|
||||
::wl_surface *mFocus = nullptr;
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
xkb_context *mXkbContext = nullptr;
|
||||
xkb_keymap *mXkbMap = nullptr;
|
||||
xkb_state *mXkbState = nullptr;
|
||||
xkb_compose_table *mXkbComposeTable = nullptr;
|
||||
xkb_compose_state *mXkbComposeState = nullptr;
|
||||
#endif
|
||||
|
||||
uint32_t mNativeModifiers = 0;
|
||||
|
||||
int mRepeatKey;
|
||||
uint32_t mRepeatCode;
|
||||
uint32_t mRepeatTime;
|
||||
struct repeatKey {
|
||||
int key;
|
||||
uint32_t code;
|
||||
uint32_t time;
|
||||
QString text;
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
uint32_t nativeVirtualKey;
|
||||
uint32_t nativeModifiers;
|
||||
} mRepeatKey;
|
||||
|
||||
QTimer mRepeatTimer;
|
||||
int mRepeatRate = 25;
|
||||
int mRepeatDelay = 400;
|
||||
QString mRepeatText;
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
xkb_keysym_t mRepeatSym;
|
||||
#endif
|
||||
QTimer mRepeatTimer;
|
||||
|
||||
uint32_t mKeymapFormat = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1;
|
||||
|
||||
Qt::KeyboardModifiers modifiers() const;
|
||||
|
||||
private slots:
|
||||
void repeatKey();
|
||||
void handleFocusDestroyed();
|
||||
void handleFocusLost();
|
||||
|
||||
private:
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
bool createDefaultKeyMap();
|
||||
void releaseKeyMap();
|
||||
void createComposeState();
|
||||
void releaseComposeState();
|
||||
bool createDefaultKeymap();
|
||||
#endif
|
||||
void handleKey(ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
|
||||
quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers,
|
||||
const QString &text, bool autorepeat = false, ushort count = 1);
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
QXkbCommon::ScopedXKBKeymap mXkbKeymap;
|
||||
QXkbCommon::ScopedXKBState mXkbState;
|
||||
#endif
|
||||
friend class QWaylandInputDevice;
|
||||
};
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer
|
||||
|
@ -90,6 +90,10 @@
|
||||
#include <QtLinuxAccessibilitySupport/private/bridge_p.h>
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
@ -146,20 +150,8 @@ QWaylandIntegration::QWaylandIntegration()
|
||||
#if QT_CONFIG(draganddrop)
|
||||
mDrag.reset(new QWaylandDrag(mDisplay.data()));
|
||||
#endif
|
||||
QString icStr = QPlatformInputContextFactory::requested();
|
||||
if (!icStr.isNull()) {
|
||||
mInputContext.reset(QPlatformInputContextFactory::create(icStr));
|
||||
} else {
|
||||
//try to use the input context using the wl_text_input interface
|
||||
QPlatformInputContext *ctx = new QWaylandInputContext(mDisplay.data());
|
||||
mInputContext.reset(ctx);
|
||||
|
||||
//use the traditional way for on screen keyboards for now
|
||||
if (!mInputContext.data()->isValid()) {
|
||||
ctx = QPlatformInputContextFactory::create();
|
||||
mInputContext.reset(ctx);
|
||||
}
|
||||
}
|
||||
reconfigureInputContext();
|
||||
}
|
||||
|
||||
QWaylandIntegration::~QWaylandIntegration()
|
||||
@ -301,6 +293,13 @@ QWaylandDisplay *QWaylandIntegration::display() const
|
||||
return mDisplay.data();
|
||||
}
|
||||
|
||||
QList<int> QWaylandIntegration::possibleKeys(const QKeyEvent *event) const
|
||||
{
|
||||
if (auto *seat = mDisplay->currentInputDevice())
|
||||
return seat->possibleKeys(event);
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList QWaylandIntegration::themeNames() const
|
||||
{
|
||||
return GenericWaylandTheme::themeNames();
|
||||
@ -462,6 +461,42 @@ void QWaylandIntegration::initializeInputDeviceIntegration()
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandIntegration::reconfigureInputContext()
|
||||
{
|
||||
if (!mDisplay) {
|
||||
// This function can be called from QWaylandDisplay::registry_global() when we
|
||||
// are in process of constructing QWaylandDisplay. Configuring input context
|
||||
// in that case is done by calling reconfigureInputContext() from QWaylandIntegration
|
||||
// constructor, after QWaylandDisplay has been constructed.
|
||||
return;
|
||||
}
|
||||
|
||||
const QString &requested = QPlatformInputContextFactory::requested();
|
||||
if (requested == QLatin1String("qtvirtualkeyboard"))
|
||||
qCWarning(lcQpaWayland) << "qtvirtualkeyboard currently is not supported at client-side,"
|
||||
" use QT_IM_MODULE=qtvirtualkeyboard at compositor-side.";
|
||||
|
||||
if (requested.isNull())
|
||||
mInputContext.reset(new QWaylandInputContext(mDisplay.data()));
|
||||
else
|
||||
mInputContext.reset(QPlatformInputContextFactory::create(requested));
|
||||
|
||||
const QString defaultInputContext(QStringLiteral("compose"));
|
||||
if ((!mInputContext || !mInputContext->isValid()) && requested != defaultInputContext)
|
||||
mInputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
QXkbCommon::setXkbContext(mInputContext.data(), mDisplay->xkbContext());
|
||||
#endif
|
||||
|
||||
// Even if compositor-side input context handling has been requested, we fallback to
|
||||
// client-side handling if compositor does not provide the text-input extension. This
|
||||
// is why we need to check here which input context actually is being used.
|
||||
mDisplay->mUsingInputContextFromCompositor = qobject_cast<QWaylandInputContext *>(mInputContext.data());
|
||||
|
||||
qCDebug(lcQpaWayland) << "using input method:" << inputContext()->metaObject()->className();
|
||||
}
|
||||
|
||||
QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QString &integrationName)
|
||||
{
|
||||
if (QWaylandShellIntegrationFactory::keys().contains(integrationName)) {
|
||||
|
@ -106,6 +106,8 @@ public:
|
||||
|
||||
QWaylandDisplay *display() const;
|
||||
|
||||
QList<int> possibleKeys(const QKeyEvent *event) const override;
|
||||
|
||||
QStringList themeNames() const override;
|
||||
|
||||
QPlatformTheme *createPlatformTheme(const QString &name) const override;
|
||||
@ -116,6 +118,8 @@ public:
|
||||
virtual QWaylandServerBufferIntegration *serverBufferIntegration() const;
|
||||
virtual QWaylandShellIntegration *shellIntegration() const;
|
||||
|
||||
void reconfigureInputContext();
|
||||
|
||||
private:
|
||||
// NOTE: mDisplay *must* be destructed after mDrag and mClientBufferIntegration
|
||||
// and mShellIntegration.
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "qwaylandscreen_p.h"
|
||||
|
||||
#include "qwaylanddisplay_p.h"
|
||||
#include "qwaylandintegration_p.h"
|
||||
#include "qwaylandcursor_p.h"
|
||||
#include "qwaylandwindow_p.h"
|
||||
|
||||
@ -60,6 +61,14 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin
|
||||
{
|
||||
if (auto *xdgOutputManager = waylandDisplay->xdgOutputManager())
|
||||
initXdgOutput(xdgOutputManager);
|
||||
|
||||
if (version < WL_OUTPUT_DONE_SINCE_VERSION) {
|
||||
qCWarning(lcQpaWayland) << "wl_output done event not supported by compositor,"
|
||||
<< "QScreen may not work correctly";
|
||||
mWaylandDisplay->forceRoundTrip(); // Give the compositor a chance to send geometry etc.
|
||||
mOutputDone = true; // Fake the done event
|
||||
maybeInitialize();
|
||||
}
|
||||
}
|
||||
|
||||
QWaylandScreen::~QWaylandScreen()
|
||||
@ -68,6 +77,24 @@ QWaylandScreen::~QWaylandScreen()
|
||||
zxdg_output_v1::destroy();
|
||||
}
|
||||
|
||||
void QWaylandScreen::maybeInitialize()
|
||||
{
|
||||
Q_ASSERT(!mInitialized);
|
||||
|
||||
if (!mOutputDone)
|
||||
return;
|
||||
|
||||
if (mWaylandDisplay->xdgOutputManager() && !mXdgOutputDone)
|
||||
return;
|
||||
|
||||
mInitialized = true;
|
||||
mWaylandDisplay->handleScreenInitialized(this);
|
||||
|
||||
updateOutputProperties();
|
||||
if (zxdg_output_v1::isInitialized())
|
||||
updateXdgOutputProperties();
|
||||
}
|
||||
|
||||
void QWaylandScreen::initXdgOutput(QtWayland::zxdg_output_manager_v1 *xdgOutputManager)
|
||||
{
|
||||
Q_ASSERT(xdgOutputManager);
|
||||
@ -233,10 +260,15 @@ void QWaylandScreen::output_scale(int32_t factor)
|
||||
|
||||
void QWaylandScreen::output_done()
|
||||
{
|
||||
// the done event is sent after all the geometry and the mode events are sent,
|
||||
// and the last mode event to be sent is the active one, so we can trust the
|
||||
// values of mGeometry and mRefreshRate here
|
||||
mOutputDone = true;
|
||||
if (mInitialized)
|
||||
updateOutputProperties();
|
||||
else
|
||||
maybeInitialize();
|
||||
}
|
||||
|
||||
void QWaylandScreen::updateOutputProperties()
|
||||
{
|
||||
if (mTransform >= 0) {
|
||||
bool isPortrait = mGeometry.height() > mGeometry.width();
|
||||
switch (mTransform) {
|
||||
@ -263,7 +295,9 @@ void QWaylandScreen::output_done()
|
||||
QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation);
|
||||
mTransform = -1;
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleScreenRefreshRateChange(screen(), refreshRate());
|
||||
|
||||
if (!zxdg_output_v1::isInitialized())
|
||||
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), geometry());
|
||||
}
|
||||
@ -281,7 +315,11 @@ void QWaylandScreen::zxdg_output_v1_logical_size(int32_t width, int32_t height)
|
||||
|
||||
void QWaylandScreen::zxdg_output_v1_done()
|
||||
{
|
||||
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), geometry());
|
||||
mXdgOutputDone = true;
|
||||
if (mInitialized)
|
||||
updateXdgOutputProperties();
|
||||
else
|
||||
maybeInitialize();
|
||||
}
|
||||
|
||||
void QWaylandScreen::zxdg_output_v1_name(const QString &name)
|
||||
@ -289,6 +327,12 @@ void QWaylandScreen::zxdg_output_v1_name(const QString &name)
|
||||
mOutputName = name;
|
||||
}
|
||||
|
||||
void QWaylandScreen::updateXdgOutputProperties()
|
||||
{
|
||||
Q_ASSERT(zxdg_output_v1::isInitialized());
|
||||
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), geometry());
|
||||
}
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -71,6 +71,8 @@ public:
|
||||
QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id);
|
||||
~QWaylandScreen() override;
|
||||
|
||||
void maybeInitialize();
|
||||
|
||||
void initXdgOutput(QtWayland::zxdg_output_manager_v1 *xdgOutputManager);
|
||||
|
||||
QWaylandDisplay *display() const;
|
||||
@ -116,12 +118,14 @@ private:
|
||||
int32_t transform) override;
|
||||
void output_scale(int32_t factor) override;
|
||||
void output_done() override;
|
||||
void updateOutputProperties();
|
||||
|
||||
// XdgOutput
|
||||
void zxdg_output_v1_logical_position(int32_t x, int32_t y) override;
|
||||
void zxdg_output_v1_logical_size(int32_t width, int32_t height) override;
|
||||
void zxdg_output_v1_done() override;
|
||||
void zxdg_output_v1_name(const QString &name) override;
|
||||
void updateXdgOutputProperties();
|
||||
|
||||
int m_outputId;
|
||||
QWaylandDisplay *mWaylandDisplay = nullptr;
|
||||
@ -137,6 +141,9 @@ private:
|
||||
QSize mPhysicalSize;
|
||||
QString mOutputName;
|
||||
Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
|
||||
bool mOutputDone = false;
|
||||
bool mXdgOutputDone = false;
|
||||
bool mInitialized = false;
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
QScopedPointer<QWaylandCursor> mWaylandCursor;
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "qwaylandnativeinterface_p.h"
|
||||
#include "qwaylanddecorationfactory_p.h"
|
||||
#include "qwaylandshmbackingstore_p.h"
|
||||
#include "qwaylandshellintegration_p.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QPointer>
|
||||
@ -62,6 +63,7 @@
|
||||
#include <QtGui/private/qwindow_p.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -74,6 +76,7 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
|
||||
QWaylandWindow::QWaylandWindow(QWindow *window)
|
||||
: QPlatformWindow(window)
|
||||
, mDisplay(waylandScreen()->display())
|
||||
, mFrameQueue(mDisplay->createEventQueue())
|
||||
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
|
||||
{
|
||||
static WId id = 1;
|
||||
@ -127,8 +130,9 @@ void QWaylandWindow::initWindow()
|
||||
}
|
||||
} else if (shouldCreateShellSurface()) {
|
||||
Q_ASSERT(!mShellSurface);
|
||||
Q_ASSERT(mDisplay->shellIntegration());
|
||||
|
||||
mShellSurface = mDisplay->createShellSurface(this);
|
||||
mShellSurface = mDisplay->shellIntegration()->createShellSurface(this);
|
||||
if (mShellSurface) {
|
||||
// Set initial surface title
|
||||
setWindowTitle(window()->title());
|
||||
@ -204,6 +208,9 @@ void QWaylandWindow::initializeWlSurface()
|
||||
|
||||
bool QWaylandWindow::shouldCreateShellSurface() const
|
||||
{
|
||||
if (!mDisplay->shellIntegration())
|
||||
return false;
|
||||
|
||||
if (shouldCreateSubSurface())
|
||||
return false;
|
||||
|
||||
@ -339,7 +346,7 @@ void QWaylandWindow::setGeometry(const QRect &rect)
|
||||
sendExposeEvent(exposeGeometry);
|
||||
|
||||
if (mShellSurface)
|
||||
mShellSurface->setWindowGeometry(windowGeometry());
|
||||
mShellSurface->setWindowGeometry(windowContentGeometry());
|
||||
}
|
||||
|
||||
void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset)
|
||||
@ -357,6 +364,8 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect)
|
||||
{
|
||||
if (!(mShellSurface && mShellSurface->handleExpose(rect)))
|
||||
QWindowSystemInterface::handleExposeEvent(window(), rect);
|
||||
else
|
||||
qCDebug(lcQpaWayland) << "sendExposeEvent: intercepted by shell extension, not sending";
|
||||
mLastExposeGeometry = rect;
|
||||
}
|
||||
|
||||
@ -494,15 +503,8 @@ void QWaylandWindow::applyConfigure()
|
||||
void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
|
||||
{
|
||||
Q_ASSERT(!buffer->committed());
|
||||
if (mFrameCallback) {
|
||||
wl_callback_destroy(mFrameCallback);
|
||||
mFrameCallback = nullptr;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
mFrameCallback = mSurface->frame();
|
||||
wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
|
||||
mWaitingForFrameSync = true;
|
||||
handleUpdate();
|
||||
buffer->setBusy();
|
||||
|
||||
mSurface->attach(buffer->buffer(), x, y);
|
||||
@ -566,32 +568,61 @@ void QWaylandWindow::commit()
|
||||
}
|
||||
|
||||
const wl_callback_listener QWaylandWindow::callbackListener = {
|
||||
QWaylandWindow::frameCallback
|
||||
[](void *data, wl_callback *callback, uint32_t time) {
|
||||
Q_UNUSED(callback);
|
||||
Q_UNUSED(time);
|
||||
auto *window = static_cast<QWaylandWindow*>(data);
|
||||
if (window->thread() != QThread::currentThread())
|
||||
QMetaObject::invokeMethod(window, [=] { window->handleFrameCallback(); }, Qt::QueuedConnection);
|
||||
else
|
||||
window->handleFrameCallback();
|
||||
}
|
||||
};
|
||||
|
||||
void QWaylandWindow::frameCallback(void *data, struct wl_callback *callback, uint32_t time)
|
||||
void QWaylandWindow::handleFrameCallback()
|
||||
{
|
||||
Q_UNUSED(time);
|
||||
Q_UNUSED(callback);
|
||||
QWaylandWindow *self = static_cast<QWaylandWindow*>(data);
|
||||
bool wasExposed = isExposed();
|
||||
|
||||
self->mWaitingForFrameSync = false;
|
||||
if (self->mUpdateRequested) {
|
||||
self->mUpdateRequested = false;
|
||||
self->deliverUpdateRequest();
|
||||
if (mFrameCallbackTimerId != -1) {
|
||||
killTimer(mFrameCallbackTimerId);
|
||||
mFrameCallbackTimerId = -1;
|
||||
}
|
||||
|
||||
mWaitingForFrameCallback = false;
|
||||
mFrameCallbackTimedOut = false;
|
||||
|
||||
if (!wasExposed && isExposed())
|
||||
sendExposeEvent(QRect(QPoint(), geometry().size()));
|
||||
if (wasExposed && hasPendingUpdateRequest())
|
||||
deliverUpdateRequest();
|
||||
}
|
||||
|
||||
QMutex QWaylandWindow::mFrameSyncMutex;
|
||||
|
||||
void QWaylandWindow::waitForFrameSync()
|
||||
bool QWaylandWindow::waitForFrameSync(int timeout)
|
||||
{
|
||||
QMutexLocker locker(&mFrameSyncMutex);
|
||||
if (!mWaitingForFrameSync)
|
||||
return;
|
||||
mDisplay->flushRequests();
|
||||
while (mWaitingForFrameSync)
|
||||
mDisplay->blockingReadEvents();
|
||||
if (!mWaitingForFrameCallback)
|
||||
return true;
|
||||
|
||||
wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(mFrameCallback), mFrameQueue);
|
||||
mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout);
|
||||
|
||||
if (mWaitingForFrameCallback) {
|
||||
qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
||||
mFrameCallbackTimedOut = true;
|
||||
mWaitingForUpdate = false;
|
||||
sendExposeEvent(QRect());
|
||||
}
|
||||
|
||||
// Stop current frame timer if any, can't use killTimer directly, because we might be on a diffent thread
|
||||
if (mFrameCallbackTimerId != -1) {
|
||||
int id = mFrameCallbackTimerId;
|
||||
mFrameCallbackTimerId = -1;
|
||||
QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
return !mWaitingForFrameCallback;
|
||||
}
|
||||
|
||||
QMargins QWaylandWindow::frameMargins() const
|
||||
@ -613,7 +644,7 @@ QSize QWaylandWindow::surfaceSize() const
|
||||
* Window geometry as defined by the xdg-shell spec (in wl_surface coordinates)
|
||||
* topLeft is where the shadow stops and the decorations border start.
|
||||
*/
|
||||
QRect QWaylandWindow::windowGeometry() const
|
||||
QRect QWaylandWindow::windowContentGeometry() const
|
||||
{
|
||||
return QRect(QPoint(), surfaceSize());
|
||||
}
|
||||
@ -833,7 +864,7 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
if (e.type == QWaylandPointerEvent::Enter) {
|
||||
QRect contentGeometry = windowGeometry().marginsRemoved(frameMargins());
|
||||
QRect contentGeometry = windowContentGeometry().marginsRemoved(frameMargins());
|
||||
if (contentGeometry.contains(e.local.toPoint()))
|
||||
restoreMouseCursor(inputDevice);
|
||||
}
|
||||
@ -944,9 +975,19 @@ void QWaylandWindow::requestActivateWindow()
|
||||
|
||||
bool QWaylandWindow::isExposed() const
|
||||
{
|
||||
if (!window()->isVisible())
|
||||
return false;
|
||||
|
||||
if (mFrameCallbackTimedOut)
|
||||
return false;
|
||||
|
||||
if (mShellSurface)
|
||||
return window()->isVisible() && mShellSurface->isExposed();
|
||||
return QPlatformWindow::isExposed();
|
||||
return mShellSurface->isExposed();
|
||||
|
||||
if (mSubSurfaceWindow)
|
||||
return mSubSurfaceWindow->parent()->isExposed();
|
||||
|
||||
return !(shouldCreateShellSurface() || shouldCreateSubSurface());
|
||||
}
|
||||
|
||||
bool QWaylandWindow::isActive() const
|
||||
@ -1015,12 +1056,107 @@ QVariant QWaylandWindow::property(const QString &name, const QVariant &defaultVa
|
||||
return m_properties.value(name, defaultValue);
|
||||
}
|
||||
|
||||
void QWaylandWindow::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == mFallbackUpdateTimerId) {
|
||||
killTimer(mFallbackUpdateTimerId);
|
||||
mFallbackUpdateTimerId = -1;
|
||||
qCDebug(lcWaylandBackingstore) << "mFallbackUpdateTimer timed out";
|
||||
|
||||
if (!isExposed()) {
|
||||
qCDebug(lcWaylandBackingstore) << "Fallback update timer: Window not exposed,"
|
||||
<< "not delivering update request.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWaitingForUpdate && hasPendingUpdateRequest() && !mWaitingForFrameCallback) {
|
||||
qCWarning(lcWaylandBackingstore) << "Delivering update request through fallback timer,"
|
||||
<< "may not be in sync with display";
|
||||
deliverUpdateRequest();
|
||||
}
|
||||
}
|
||||
|
||||
if (event->timerId() == mFrameCallbackTimerId) {
|
||||
killTimer(mFrameCallbackTimerId);
|
||||
mFrameCallbackTimerId = -1;
|
||||
qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
||||
mFrameCallbackTimedOut = true;
|
||||
mWaitingForUpdate = false;
|
||||
sendExposeEvent(QRect());
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandWindow::requestUpdate()
|
||||
{
|
||||
if (!mWaitingForFrameSync)
|
||||
QPlatformWindow::requestUpdate();
|
||||
else
|
||||
mUpdateRequested = true;
|
||||
Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
|
||||
|
||||
// If we have a frame callback all is good and will be taken care of there
|
||||
if (mWaitingForFrameCallback)
|
||||
return;
|
||||
|
||||
// If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
|
||||
if (mWaitingForUpdate) {
|
||||
// Ideally, we should just have returned here, but we're not guaranteed that the client
|
||||
// will actually update, so start this timer to deliver another request update after a while
|
||||
// *IF* the client doesn't update.
|
||||
int fallbackTimeout = 100;
|
||||
mFallbackUpdateTimerId = startTimer(fallbackTimeout);
|
||||
return;
|
||||
}
|
||||
|
||||
// Some applications (such as Qt Quick) depend on updates being delivered asynchronously,
|
||||
// so use invokeMethod to delay the delivery a bit.
|
||||
QMetaObject::invokeMethod(this, [this] {
|
||||
// Things might have changed in the meantime
|
||||
if (hasPendingUpdateRequest() && !mWaitingForUpdate && !mWaitingForFrameCallback)
|
||||
deliverUpdateRequest();
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
// Should be called whenever we commit a buffer (directly through wl_surface.commit or indirectly
|
||||
// with eglSwapBuffers) to know when it's time to commit the next one.
|
||||
// Can be called from the render thread (without locking anything) so make sure to not make races in this method.
|
||||
void QWaylandWindow::handleUpdate()
|
||||
{
|
||||
// TODO: Should sync subsurfaces avoid requesting frame callbacks?
|
||||
|
||||
if (mFrameCallback) {
|
||||
wl_callback_destroy(mFrameCallback);
|
||||
mFrameCallback = nullptr;
|
||||
}
|
||||
|
||||
if (mFallbackUpdateTimerId != -1) {
|
||||
// Ideally, we would stop the fallback timer here, but since we're on another thread,
|
||||
// it's not allowed. Instead we set mFallbackUpdateTimer to -1 here, so we'll just
|
||||
// ignore it if it times out before it's cleaned up by the invokeMethod call.
|
||||
int id = mFallbackUpdateTimerId;
|
||||
mFallbackUpdateTimerId = -1;
|
||||
QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
mFrameCallback = mSurface->frame();
|
||||
wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
|
||||
mWaitingForFrameCallback = true;
|
||||
mWaitingForUpdate = false;
|
||||
|
||||
// Stop current frame timer if any, can't use killTimer directly, see comment above.
|
||||
if (mFrameCallbackTimerId != -1) {
|
||||
int id = mFrameCallbackTimerId;
|
||||
mFrameCallbackTimerId = -1;
|
||||
QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
// Start a timer for handling the case when the compositor stops sending frame callbacks.
|
||||
QMetaObject::invokeMethod(this, [=] { // Again; can't do it directly
|
||||
if (mWaitingForFrameCallback)
|
||||
mFrameCallbackTimerId = startTimer(100);
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void QWaylandWindow::deliverUpdateRequest()
|
||||
{
|
||||
mWaitingForUpdate = true;
|
||||
QPlatformWindow::deliverUpdateRequest();
|
||||
}
|
||||
|
||||
void QWaylandWindow::addAttachOffset(const QPoint point)
|
||||
|
@ -121,11 +121,11 @@ public:
|
||||
|
||||
void commit();
|
||||
|
||||
void waitForFrameSync();
|
||||
bool waitForFrameSync(int timeout);
|
||||
|
||||
QMargins frameMargins() const override;
|
||||
QSize surfaceSize() const;
|
||||
QRect windowGeometry() const;
|
||||
QRect windowContentGeometry() const;
|
||||
|
||||
QWaylandSurface *waylandSurface() const { return mSurface.data(); }
|
||||
::wl_surface *wlSurface();
|
||||
@ -194,7 +194,10 @@ public:
|
||||
|
||||
bool startSystemMove(const QPoint &pos) override;
|
||||
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void requestUpdate() override;
|
||||
void handleUpdate();
|
||||
void deliverUpdateRequest() override;
|
||||
|
||||
public slots:
|
||||
void applyConfigure();
|
||||
@ -214,10 +217,17 @@ protected:
|
||||
Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton;
|
||||
|
||||
WId mWindowId;
|
||||
bool mWaitingForFrameSync = false;
|
||||
bool mWaitingForFrameCallback = false;
|
||||
bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
|
||||
int mFrameCallbackTimerId = -1; // Started on commit, reset on frame callback
|
||||
struct ::wl_callback *mFrameCallback = nullptr;
|
||||
struct ::wl_event_queue *mFrameQueue = nullptr;
|
||||
QWaitCondition mFrameSyncWait;
|
||||
|
||||
// True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
|
||||
bool mWaitingForUpdate = false;
|
||||
int mFallbackUpdateTimerId = -1; // Started when waiting for app to commit
|
||||
|
||||
QMutex mResizeLock;
|
||||
bool mWaitingToApplyConfigure = false;
|
||||
bool mCanResize = true;
|
||||
@ -254,11 +264,10 @@ private:
|
||||
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
|
||||
void handleScreensChanged();
|
||||
|
||||
bool mUpdateRequested = false;
|
||||
QRect mLastExposeGeometry;
|
||||
|
||||
static const wl_callback_listener callbackListener;
|
||||
static void frameCallback(void *data, struct wl_callback *wl_callback, uint32_t time);
|
||||
void handleFrameCallback();
|
||||
|
||||
static QMutex mFrameSyncMutex;
|
||||
static QWaylandWindow *mMouseGrab;
|
||||
|
@ -1,395 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Jolla Ltd
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qwaylandxkb_p.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QString>
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
static const uint32_t KeyTbl[] = {
|
||||
XKB_KEY_Escape, Qt::Key_Escape,
|
||||
XKB_KEY_Tab, Qt::Key_Tab,
|
||||
XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab,
|
||||
XKB_KEY_BackSpace, Qt::Key_Backspace,
|
||||
XKB_KEY_Return, Qt::Key_Return,
|
||||
XKB_KEY_Insert, Qt::Key_Insert,
|
||||
XKB_KEY_Delete, Qt::Key_Delete,
|
||||
XKB_KEY_Clear, Qt::Key_Delete,
|
||||
XKB_KEY_Pause, Qt::Key_Pause,
|
||||
XKB_KEY_Print, Qt::Key_Print,
|
||||
|
||||
XKB_KEY_Home, Qt::Key_Home,
|
||||
XKB_KEY_End, Qt::Key_End,
|
||||
XKB_KEY_Left, Qt::Key_Left,
|
||||
XKB_KEY_Up, Qt::Key_Up,
|
||||
XKB_KEY_Right, Qt::Key_Right,
|
||||
XKB_KEY_Down, Qt::Key_Down,
|
||||
XKB_KEY_Prior, Qt::Key_PageUp,
|
||||
XKB_KEY_Next, Qt::Key_PageDown,
|
||||
|
||||
XKB_KEY_Shift_L, Qt::Key_Shift,
|
||||
XKB_KEY_Shift_R, Qt::Key_Shift,
|
||||
XKB_KEY_Shift_Lock, Qt::Key_Shift,
|
||||
XKB_KEY_Control_L, Qt::Key_Control,
|
||||
XKB_KEY_Control_R, Qt::Key_Control,
|
||||
XKB_KEY_Meta_L, Qt::Key_Meta,
|
||||
XKB_KEY_Meta_R, Qt::Key_Meta,
|
||||
XKB_KEY_Alt_L, Qt::Key_Alt,
|
||||
XKB_KEY_Alt_R, Qt::Key_Alt,
|
||||
XKB_KEY_Caps_Lock, Qt::Key_CapsLock,
|
||||
XKB_KEY_Num_Lock, Qt::Key_NumLock,
|
||||
XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock,
|
||||
XKB_KEY_Super_L, Qt::Key_Super_L,
|
||||
XKB_KEY_Super_R, Qt::Key_Super_R,
|
||||
XKB_KEY_Menu, Qt::Key_Menu,
|
||||
XKB_KEY_Hyper_L, Qt::Key_Hyper_L,
|
||||
XKB_KEY_Hyper_R, Qt::Key_Hyper_R,
|
||||
XKB_KEY_Help, Qt::Key_Help,
|
||||
|
||||
XKB_KEY_KP_Space, Qt::Key_Space,
|
||||
XKB_KEY_KP_Tab, Qt::Key_Tab,
|
||||
XKB_KEY_KP_Enter, Qt::Key_Enter,
|
||||
XKB_KEY_KP_Home, Qt::Key_Home,
|
||||
XKB_KEY_KP_Left, Qt::Key_Left,
|
||||
XKB_KEY_KP_Up, Qt::Key_Up,
|
||||
XKB_KEY_KP_Right, Qt::Key_Right,
|
||||
XKB_KEY_KP_Down, Qt::Key_Down,
|
||||
XKB_KEY_KP_Prior, Qt::Key_PageUp,
|
||||
XKB_KEY_KP_Next, Qt::Key_PageDown,
|
||||
XKB_KEY_KP_End, Qt::Key_End,
|
||||
XKB_KEY_KP_Begin, Qt::Key_Clear,
|
||||
XKB_KEY_KP_Insert, Qt::Key_Insert,
|
||||
XKB_KEY_KP_Delete, Qt::Key_Delete,
|
||||
XKB_KEY_KP_Equal, Qt::Key_Equal,
|
||||
XKB_KEY_KP_Multiply, Qt::Key_Asterisk,
|
||||
XKB_KEY_KP_Add, Qt::Key_Plus,
|
||||
XKB_KEY_KP_Separator, Qt::Key_Comma,
|
||||
XKB_KEY_KP_Subtract, Qt::Key_Minus,
|
||||
XKB_KEY_KP_Decimal, Qt::Key_Period,
|
||||
XKB_KEY_KP_Divide, Qt::Key_Slash,
|
||||
|
||||
XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr,
|
||||
XKB_KEY_Multi_key, Qt::Key_Multi_key,
|
||||
XKB_KEY_Codeinput, Qt::Key_Codeinput,
|
||||
XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate,
|
||||
XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
|
||||
XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
|
||||
|
||||
XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
|
||||
XKB_KEY_script_switch, Qt::Key_Mode_switch,
|
||||
|
||||
XKB_KEY_XF86Back, Qt::Key_Back,
|
||||
XKB_KEY_XF86Forward, Qt::Key_Forward,
|
||||
XKB_KEY_XF86Stop, Qt::Key_Stop,
|
||||
XKB_KEY_XF86Refresh, Qt::Key_Refresh,
|
||||
XKB_KEY_XF86Favorites, Qt::Key_Favorites,
|
||||
XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia,
|
||||
XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl,
|
||||
XKB_KEY_XF86HomePage, Qt::Key_HomePage,
|
||||
XKB_KEY_XF86Search, Qt::Key_Search,
|
||||
XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown,
|
||||
XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute,
|
||||
XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
|
||||
XKB_KEY_XF86AudioPlay, Qt::Key_MediaTogglePlayPause,
|
||||
XKB_KEY_XF86AudioStop, Qt::Key_MediaStop,
|
||||
XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious,
|
||||
XKB_KEY_XF86AudioNext, Qt::Key_MediaNext,
|
||||
XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord,
|
||||
XKB_KEY_XF86AudioPause, Qt::Key_MediaPause,
|
||||
XKB_KEY_XF86Mail, Qt::Key_LaunchMail,
|
||||
XKB_KEY_XF86Calculator, Qt::Key_Calculator,
|
||||
XKB_KEY_XF86Memo, Qt::Key_Memo,
|
||||
XKB_KEY_XF86ToDoList, Qt::Key_ToDoList,
|
||||
XKB_KEY_XF86Calendar, Qt::Key_Calendar,
|
||||
XKB_KEY_XF86PowerDown, Qt::Key_PowerDown,
|
||||
XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust,
|
||||
XKB_KEY_XF86Standby, Qt::Key_Standby,
|
||||
XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp,
|
||||
XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown,
|
||||
XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff,
|
||||
XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp,
|
||||
XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown,
|
||||
XKB_KEY_XF86PowerOff, Qt::Key_PowerOff,
|
||||
XKB_KEY_XF86WakeUp, Qt::Key_WakeUp,
|
||||
XKB_KEY_XF86Eject, Qt::Key_Eject,
|
||||
XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver,
|
||||
XKB_KEY_XF86WWW, Qt::Key_WWW,
|
||||
XKB_KEY_XF86Sleep, Qt::Key_Sleep,
|
||||
XKB_KEY_XF86LightBulb, Qt::Key_LightBulb,
|
||||
XKB_KEY_XF86Shop, Qt::Key_Shop,
|
||||
XKB_KEY_XF86History, Qt::Key_History,
|
||||
XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite,
|
||||
XKB_KEY_XF86HotLinks, Qt::Key_HotLinks,
|
||||
XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust,
|
||||
XKB_KEY_XF86Finance, Qt::Key_Finance,
|
||||
XKB_KEY_XF86Community, Qt::Key_Community,
|
||||
XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind,
|
||||
XKB_KEY_XF86BackForward, Qt::Key_BackForward,
|
||||
XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft,
|
||||
XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight,
|
||||
XKB_KEY_XF86Book, Qt::Key_Book,
|
||||
XKB_KEY_XF86CD, Qt::Key_CD,
|
||||
XKB_KEY_XF86Calculater, Qt::Key_Calculator,
|
||||
XKB_KEY_XF86Clear, Qt::Key_Clear,
|
||||
XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab,
|
||||
XKB_KEY_XF86Close, Qt::Key_Close,
|
||||
XKB_KEY_XF86Copy, Qt::Key_Copy,
|
||||
XKB_KEY_XF86Cut, Qt::Key_Cut,
|
||||
XKB_KEY_XF86Display, Qt::Key_Display,
|
||||
XKB_KEY_XF86DOS, Qt::Key_DOS,
|
||||
XKB_KEY_XF86Documents, Qt::Key_Documents,
|
||||
XKB_KEY_XF86Excel, Qt::Key_Excel,
|
||||
XKB_KEY_XF86Explorer, Qt::Key_Explorer,
|
||||
XKB_KEY_XF86Game, Qt::Key_Game,
|
||||
XKB_KEY_XF86Go, Qt::Key_Go,
|
||||
XKB_KEY_XF86iTouch, Qt::Key_iTouch,
|
||||
XKB_KEY_XF86LogOff, Qt::Key_LogOff,
|
||||
XKB_KEY_XF86Market, Qt::Key_Market,
|
||||
XKB_KEY_XF86Meeting, Qt::Key_Meeting,
|
||||
XKB_KEY_XF86MenuKB, Qt::Key_MenuKB,
|
||||
XKB_KEY_XF86MenuPB, Qt::Key_MenuPB,
|
||||
XKB_KEY_XF86MySites, Qt::Key_MySites,
|
||||
XKB_KEY_XF86New, Qt::Key_New,
|
||||
XKB_KEY_XF86News, Qt::Key_News,
|
||||
XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome,
|
||||
XKB_KEY_XF86Open, Qt::Key_Open,
|
||||
XKB_KEY_XF86Option, Qt::Key_Option,
|
||||
XKB_KEY_XF86Paste, Qt::Key_Paste,
|
||||
XKB_KEY_XF86Phone, Qt::Key_Phone,
|
||||
XKB_KEY_XF86Reply, Qt::Key_Reply,
|
||||
XKB_KEY_XF86Reload, Qt::Key_Reload,
|
||||
XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows,
|
||||
XKB_KEY_XF86RotationPB, Qt::Key_RotationPB,
|
||||
XKB_KEY_XF86RotationKB, Qt::Key_RotationKB,
|
||||
XKB_KEY_XF86Save, Qt::Key_Save,
|
||||
XKB_KEY_XF86Send, Qt::Key_Send,
|
||||
XKB_KEY_XF86Spell, Qt::Key_Spell,
|
||||
XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen,
|
||||
XKB_KEY_XF86Support, Qt::Key_Support,
|
||||
XKB_KEY_XF86TaskPane, Qt::Key_TaskPane,
|
||||
XKB_KEY_XF86Terminal, Qt::Key_Terminal,
|
||||
XKB_KEY_XF86Tools, Qt::Key_Tools,
|
||||
XKB_KEY_XF86Travel, Qt::Key_Travel,
|
||||
XKB_KEY_XF86Video, Qt::Key_Video,
|
||||
XKB_KEY_XF86Word, Qt::Key_Word,
|
||||
XKB_KEY_XF86Xfer, Qt::Key_Xfer,
|
||||
XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn,
|
||||
XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut,
|
||||
XKB_KEY_XF86Away, Qt::Key_Away,
|
||||
XKB_KEY_XF86Messenger, Qt::Key_Messenger,
|
||||
XKB_KEY_XF86WebCam, Qt::Key_WebCam,
|
||||
XKB_KEY_XF86MailForward, Qt::Key_MailForward,
|
||||
XKB_KEY_XF86Pictures, Qt::Key_Pictures,
|
||||
XKB_KEY_XF86Music, Qt::Key_Music,
|
||||
XKB_KEY_XF86Battery, Qt::Key_Battery,
|
||||
XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
|
||||
XKB_KEY_XF86WLAN, Qt::Key_WLAN,
|
||||
XKB_KEY_XF86UWB, Qt::Key_UWB,
|
||||
XKB_KEY_XF86AudioForward, Qt::Key_AudioForward,
|
||||
XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat,
|
||||
XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay,
|
||||
XKB_KEY_XF86Subtitle, Qt::Key_Subtitle,
|
||||
XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack,
|
||||
XKB_KEY_XF86Time, Qt::Key_Time,
|
||||
XKB_KEY_XF86Select, Qt::Key_Select,
|
||||
XKB_KEY_XF86View, Qt::Key_View,
|
||||
XKB_KEY_XF86TopMenu, Qt::Key_TopMenu,
|
||||
XKB_KEY_XF86Red, Qt::Key_Red,
|
||||
XKB_KEY_XF86Green, Qt::Key_Green,
|
||||
XKB_KEY_XF86Yellow, Qt::Key_Yellow,
|
||||
XKB_KEY_XF86Blue, Qt::Key_Blue,
|
||||
XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
|
||||
XKB_KEY_XF86Suspend, Qt::Key_Suspend,
|
||||
XKB_KEY_XF86Hibernate, Qt::Key_Hibernate,
|
||||
XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle,
|
||||
XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn,
|
||||
XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff,
|
||||
XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute,
|
||||
XKB_KEY_XF86Launch0, Qt::Key_Launch0,
|
||||
XKB_KEY_XF86Launch1, Qt::Key_Launch1,
|
||||
XKB_KEY_XF86Launch2, Qt::Key_Launch2,
|
||||
XKB_KEY_XF86Launch3, Qt::Key_Launch3,
|
||||
XKB_KEY_XF86Launch4, Qt::Key_Launch4,
|
||||
XKB_KEY_XF86Launch5, Qt::Key_Launch5,
|
||||
XKB_KEY_XF86Launch6, Qt::Key_Launch6,
|
||||
XKB_KEY_XF86Launch7, Qt::Key_Launch7,
|
||||
XKB_KEY_XF86Launch8, Qt::Key_Launch8,
|
||||
XKB_KEY_XF86Launch9, Qt::Key_Launch9,
|
||||
XKB_KEY_XF86LaunchA, Qt::Key_LaunchA,
|
||||
XKB_KEY_XF86LaunchB, Qt::Key_LaunchB,
|
||||
XKB_KEY_XF86LaunchC, Qt::Key_LaunchC,
|
||||
XKB_KEY_XF86LaunchD, Qt::Key_LaunchD,
|
||||
XKB_KEY_XF86LaunchE, Qt::Key_LaunchE,
|
||||
XKB_KEY_XF86LaunchF, Qt::Key_LaunchF,
|
||||
|
||||
0, 0
|
||||
};
|
||||
|
||||
static int lookupKeysym(xkb_keysym_t key)
|
||||
{
|
||||
int code = 0;
|
||||
int i = 0;
|
||||
while (KeyTbl[i]) {
|
||||
if (key == KeyTbl[i]) {
|
||||
code = (int)KeyTbl[i+1];
|
||||
break;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static xkb_keysym_t toKeysymFromTable(uint32_t key)
|
||||
{
|
||||
for (int i = 0; KeyTbl[i]; i += 2) {
|
||||
if (key == KeyTbl[i + 1])
|
||||
return KeyTbl[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::pair<int, QString> QWaylandXkb::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers)
|
||||
{
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
QString text;
|
||||
uint utf32 = xkb_keysym_to_utf32(keysym);
|
||||
if (utf32)
|
||||
text = QString::fromUcs4(&utf32, 1);
|
||||
|
||||
int code = 0;
|
||||
|
||||
if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) {
|
||||
code = Qt::Key_F1 + (int(keysym) - XKB_KEY_F1);
|
||||
} else if (keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_9) {
|
||||
if (keysym >= XKB_KEY_KP_0) {
|
||||
// numeric keypad keys
|
||||
code = Qt::Key_0 + ((int)keysym - XKB_KEY_KP_0);
|
||||
} else {
|
||||
code = lookupKeysym(keysym);
|
||||
}
|
||||
modifiers |= Qt::KeypadModifier;
|
||||
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
|
||||
&& text.unicode()->unicode() != 0x7f
|
||||
&& !(keysym >= XKB_KEY_dead_grave && keysym <= XKB_KEY_dead_currency)) {
|
||||
code = text.unicode()->toUpper().unicode();
|
||||
} else {
|
||||
// any other keys
|
||||
code = lookupKeysym(keysym);
|
||||
}
|
||||
|
||||
// Map control + letter to proper text
|
||||
if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) {
|
||||
utf32 &= ~0x60;
|
||||
text = QString::fromUcs4(&utf32, 1);
|
||||
}
|
||||
|
||||
return { code, text };
|
||||
#else
|
||||
Q_UNUSED(modifiers)
|
||||
return { keysym, "" };
|
||||
#endif
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers QWaylandXkb::modifiers(struct xkb_state *state)
|
||||
{
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
|
||||
|
||||
xkb_state_component cstate = static_cast<xkb_state_component>(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED | XKB_STATE_LOCKED);
|
||||
|
||||
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, cstate))
|
||||
modifiers |= Qt::ShiftModifier;
|
||||
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, cstate))
|
||||
modifiers |= Qt::ControlModifier;
|
||||
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, cstate))
|
||||
modifiers |= Qt::AltModifier;
|
||||
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, cstate))
|
||||
modifiers |= Qt::MetaModifier;
|
||||
|
||||
return modifiers;
|
||||
#else
|
||||
Q_UNUSED(state)
|
||||
return Qt::NoModifier;
|
||||
#endif
|
||||
}
|
||||
|
||||
QEvent::Type QWaylandXkb::toQtEventType(uint32_t state)
|
||||
{
|
||||
return state != 0 ? QEvent::KeyPress : QEvent::KeyRelease;
|
||||
}
|
||||
|
||||
QVector<xkb_keysym_t> QWaylandXkb::toKeysym(QKeyEvent *event)
|
||||
{
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
QVector<xkb_keysym_t> keysyms;
|
||||
if (event->key() >= Qt::Key_F1 && event->key() <= Qt::Key_F35) {
|
||||
keysyms.append(XKB_KEY_F1 + (event->key() - Qt::Key_F1));
|
||||
} else if (event->modifiers() & Qt::KeypadModifier) {
|
||||
if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9)
|
||||
keysyms.append(XKB_KEY_KP_0 + (event->key() - Qt::Key_0));
|
||||
else
|
||||
keysyms.append(toKeysymFromTable(event->key()));
|
||||
} else if (!event->text().isEmpty()) {
|
||||
// From libxkbcommon keysym-utf.c:
|
||||
// "We allow to represent any UCS character in the range U-00000000 to
|
||||
// U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff."
|
||||
foreach (uint utf32, event->text().toUcs4()) {
|
||||
keysyms.append(utf32 | 0x01000000);
|
||||
}
|
||||
} else {
|
||||
keysyms.append(toKeysymFromTable(event->key()));
|
||||
}
|
||||
return keysyms;
|
||||
#else
|
||||
return QVector<xkb_keysym_t>() << event->nativeScanCode();
|
||||
#endif
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -1,73 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Jolla Ltd
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QWAYLANDXKB_H
|
||||
#define QWAYLANDXKB_H
|
||||
|
||||
#include <QtGui/private/qtguiglobal_p.h>
|
||||
#include <Qt>
|
||||
#include <QEvent>
|
||||
|
||||
#if QT_CONFIG(xkbcommon)
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#else
|
||||
typedef quint32 xkb_keysym_t;
|
||||
struct xkb_state;
|
||||
#endif
|
||||
|
||||
#include <utility>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QKeyEvent;
|
||||
|
||||
class QWaylandXkb
|
||||
{
|
||||
public:
|
||||
static std::pair<int, QString> keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers);
|
||||
static Qt::KeyboardModifiers modifiers(struct xkb_state *state);
|
||||
|
||||
static QEvent::Type toQtEventType(uint32_t state);
|
||||
static QVector<xkb_keysym_t> toKeysym(QKeyEvent *event);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
@ -13,3 +13,5 @@ SUBDIRS += \
|
||||
xdgoutput \
|
||||
xdgshell \
|
||||
xdgshellv6
|
||||
|
||||
qtConfig(im): SUBDIRS += inputcontext
|
||||
|
6
tests/auto/wayland/inputcontext/inputcontext.pro
Normal file
6
tests/auto/wayland/inputcontext/inputcontext.pro
Normal file
@ -0,0 +1,6 @@
|
||||
include (../shared/shared.pri)
|
||||
|
||||
QT += waylandcompositor
|
||||
|
||||
TARGET = tst_inputcontext
|
||||
SOURCES += tst_inputcontext.cpp
|
184
tests/auto/wayland/inputcontext/tst_inputcontext.cpp
Normal file
184
tests/auto/wayland/inputcontext/tst_inputcontext.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "mockcompositor.h"
|
||||
#include "textinput.h"
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtGui/qpa/qplatforminputcontext.h>
|
||||
#include <QtGui/qpa/qplatformintegration.h>
|
||||
#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
using namespace MockCompositor;
|
||||
|
||||
class tst_inputcontext : public QObject, private DefaultCompositor
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void selectingInputContext_data();
|
||||
void selectingInputContext();
|
||||
void inputContextReconfigurationWhenTogglingTextInputExtension();
|
||||
|
||||
private:
|
||||
QByteArray inputContextName() const;
|
||||
void ensureTextInputPresentOnCompositor();
|
||||
void ensureTextInputNotPresentOnCompositor();
|
||||
|
||||
QByteArray mComposeModule = QByteArray("QComposeInputContext"); // default input context
|
||||
QByteArray mIbusModule = QByteArray("QIBusPlatformInputContext");
|
||||
QByteArray mWaylandModule = QByteArray("QtWaylandClient::QWaylandInputContext");
|
||||
|
||||
TextInputManager *mTextInputManager = nullptr;
|
||||
};
|
||||
|
||||
void tst_inputcontext::initTestCase()
|
||||
{
|
||||
// Verify that plugins are present and valid
|
||||
QPlatformInputContext *context = QPlatformInputContextFactory::create(QStringLiteral("compose"));
|
||||
QVERIFY(context && context->isValid());
|
||||
|
||||
context = QPlatformInputContextFactory::create(QStringLiteral("ibus"));
|
||||
// The ibus plugin depends on properly configured system services, if plugin is not valid
|
||||
// verify that wayland qpa plugin properly fallbacks to default input context.
|
||||
if (!context || !context->isValid())
|
||||
mIbusModule = mComposeModule;
|
||||
}
|
||||
|
||||
QByteArray tst_inputcontext::inputContextName() const
|
||||
{
|
||||
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
|
||||
if (platformIntegration->inputContext())
|
||||
return platformIntegration->inputContext()->metaObject()->className();
|
||||
|
||||
return QByteArray("");
|
||||
}
|
||||
|
||||
void tst_inputcontext::ensureTextInputPresentOnCompositor()
|
||||
{
|
||||
exec([&] {
|
||||
QVector<TextInputManager *> extensions = getAll<TextInputManager>();
|
||||
if (extensions.length() > 1)
|
||||
QFAIL("TextInputManager is a singleton, hence there should not be more then one object returned");
|
||||
if (extensions.length() == 0)
|
||||
add<TextInputManager>();
|
||||
});
|
||||
}
|
||||
|
||||
void tst_inputcontext::ensureTextInputNotPresentOnCompositor()
|
||||
{
|
||||
exec([&] {
|
||||
QVector<TextInputManager *> extensions = getAll<TextInputManager>();
|
||||
if (extensions.length() > 1)
|
||||
QFAIL("TextInputManager is a singleton, hence there should not be more then one object returned");
|
||||
if (extensions.length() == 1)
|
||||
remove(extensions.first());
|
||||
});
|
||||
}
|
||||
|
||||
void tst_inputcontext::selectingInputContext_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("requestedModule");
|
||||
QTest::addColumn<QByteArray>("expectedModule");
|
||||
|
||||
// Test compositor without Text Input extension
|
||||
QTest::newRow("ibus") << QByteArray("ibus") << mIbusModule;
|
||||
QTest::newRow("compose") << QByteArray("compose") << mComposeModule;
|
||||
QTest::newRow("empty") << QByteArray("") << mComposeModule;
|
||||
QTest::newRow("null") << QByteArray() << mComposeModule;
|
||||
QTest::newRow("fake") << QByteArray("fake") << mComposeModule;
|
||||
|
||||
// Test compositor with Text Input extension
|
||||
QTest::newRow("ibus:text-input") << QByteArray("ibus") << mIbusModule;
|
||||
QTest::newRow("compose:text-input") << QByteArray("compose") << mComposeModule;
|
||||
QTest::newRow("empty:text-input") << QByteArray("") << mComposeModule;
|
||||
QTest::newRow("null:text-input") << QByteArray() << mWaylandModule;
|
||||
QTest::newRow("fake:text-input") << QByteArray("fake") << mComposeModule;
|
||||
}
|
||||
|
||||
void tst_inputcontext::selectingInputContext()
|
||||
{
|
||||
QFETCH(QByteArray, requestedModule);
|
||||
QFETCH(QByteArray, expectedModule);
|
||||
|
||||
if (requestedModule.isNull())
|
||||
qunsetenv("QT_IM_MODULE");
|
||||
else
|
||||
qputenv("QT_IM_MODULE", requestedModule);
|
||||
|
||||
const bool withTextInputAtCompositorSide = QByteArray(QTest::currentDataTag()).endsWith(":text-input");
|
||||
|
||||
if (withTextInputAtCompositorSide)
|
||||
ensureTextInputPresentOnCompositor();
|
||||
else
|
||||
ensureTextInputNotPresentOnCompositor();
|
||||
|
||||
int argc = 0;
|
||||
QGuiApplication app(argc, nullptr); // loads the platform plugin
|
||||
|
||||
QCOMPARE(inputContextName(), expectedModule);
|
||||
}
|
||||
|
||||
void tst_inputcontext::inputContextReconfigurationWhenTogglingTextInputExtension()
|
||||
{
|
||||
qunsetenv("QT_IM_MODULE");
|
||||
|
||||
ensureTextInputPresentOnCompositor();
|
||||
int argc = 0;
|
||||
QGuiApplication app(argc, nullptr); // loads the platform plugin
|
||||
QCOMPARE(inputContextName(), mWaylandModule);
|
||||
|
||||
// remove text input extension after the platform plugin has been loaded
|
||||
ensureTextInputNotPresentOnCompositor();
|
||||
// QTRY_* because we need to spin the event loop for wayland QPA plugin
|
||||
// to handle registry_global_remove()
|
||||
QTRY_COMPARE(inputContextName(), mComposeModule);
|
||||
|
||||
// add text input extension after the platform plugin has been loaded
|
||||
ensureTextInputPresentOnCompositor();
|
||||
// QTRY_* because we need to spin the event loop for wayland QPA plugin
|
||||
// to handle registry_global()
|
||||
QTRY_COMPARE(inputContextName(), mWaylandModule);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
qputenv("XDG_RUNTIME_DIR", ".");
|
||||
qputenv("QT_QPA_PLATFORM", "wayland");
|
||||
|
||||
tst_inputcontext tc;
|
||||
QTEST_SET_MAIN_SOURCE_PATH
|
||||
return QTest::qExec(&tc, argc, argv);
|
||||
}
|
||||
|
||||
#include "tst_inputcontext.moc"
|
@ -215,10 +215,7 @@ void tst_output::screenOrder()
|
||||
QTRY_COMPARE(QGuiApplication::screens().size(), 3);
|
||||
const auto screens = QGuiApplication::screens();
|
||||
|
||||
QEXPECT_FAIL(nullptr, "TODO: fix screen order", Continue);
|
||||
QCOMPARE(screens[1]->model(), "Screen 1");
|
||||
|
||||
QEXPECT_FAIL(nullptr, "TODO: fix screen order", Continue);
|
||||
QCOMPARE(screens[2]->model(), "Screen 2");
|
||||
|
||||
exec([=] {
|
||||
|
@ -4,7 +4,8 @@ QMAKE_USE += wayland-server
|
||||
|
||||
WAYLANDSERVERSOURCES += \
|
||||
$$PWD/../../../../src/3rdparty/protocol/wayland.xml \
|
||||
$$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml
|
||||
$$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml \
|
||||
$$PWD/../../../../src/3rdparty/protocol/text-input-unstable-v2.xml
|
||||
|
||||
INCLUDEPATH += ../shared
|
||||
|
||||
@ -13,11 +14,13 @@ HEADERS += \
|
||||
$$PWD/coreprotocol.h \
|
||||
$$PWD/datadevice.h \
|
||||
$$PWD/mockcompositor.h \
|
||||
$$PWD/xdgshell.h
|
||||
$$PWD/xdgshell.h \
|
||||
$$PWD/textinput.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/corecompositor.cpp \
|
||||
$$PWD/coreprotocol.cpp \
|
||||
$$PWD/datadevice.cpp \
|
||||
$$PWD/mockcompositor.cpp \
|
||||
$$PWD/xdgshell.cpp
|
||||
$$PWD/xdgshell.cpp \
|
||||
$$PWD/textinput.cpp
|
||||
|
45
tests/auto/wayland/shared/textinput.cpp
Normal file
45
tests/auto/wayland/shared/textinput.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "textinput.h"
|
||||
|
||||
namespace MockCompositor {
|
||||
|
||||
TextInputManager::TextInputManager(CoreCompositor *compositor)
|
||||
{
|
||||
init(compositor->m_display, 1);
|
||||
}
|
||||
|
||||
void TextInputManager::zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, wl_resource *seatResource)
|
||||
{
|
||||
Q_UNUSED(resource);
|
||||
Q_UNUSED(id);
|
||||
Q_UNUSED(seatResource);
|
||||
}
|
||||
|
||||
} // namespace MockCompositor
|
51
tests/auto/wayland/shared/textinput.h
Normal file
51
tests/auto/wayland/shared/textinput.h
Normal file
@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MOCKCOMPOSITOR_TEXTINPUT_H
|
||||
#define MOCKCOMPOSITOR_TEXTINPUT_H
|
||||
|
||||
#include "coreprotocol.h"
|
||||
#include <qwayland-server-text-input-unstable-v2.h>
|
||||
|
||||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
||||
|
||||
namespace MockCompositor {
|
||||
|
||||
class TextInputManager : public Global, public QtWaylandServer::zwp_text_input_manager_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TextInputManager(CoreCompositor *compositor);
|
||||
|
||||
protected:
|
||||
void zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seatResource) override;
|
||||
};
|
||||
|
||||
} // namespace MockCompositor
|
||||
|
||||
#endif // MOCKCOMPOSITOR_TEXTINPUT_H
|
@ -65,7 +65,7 @@ void tst_xdgshell::showMinimized()
|
||||
|
||||
// Make sure the window on the compositor side is/was created here, and not after the test
|
||||
// finishes, as that may mess up for later tests.
|
||||
QCOMPOSITOR_TRY_VERIFY(surface());
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface());
|
||||
QVERIFY(!window.isExposed());
|
||||
}
|
||||
|
||||
@ -426,9 +426,16 @@ void tst_xdgshell::switchPopups()
|
||||
|
||||
void tst_xdgshell::pongs()
|
||||
{
|
||||
QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
|
||||
// Create and show a window to trigger shell integration initialzation,
|
||||
// otherwise we don't have anything to send ping events to.
|
||||
QRasterWindow window;
|
||||
window.resize(200, 200);
|
||||
window.show();
|
||||
|
||||
// Verify that the client has bound to the global
|
||||
QCOMPOSITOR_TRY_COMPARE(get<XdgWmBase>()->resourceMap().size(), 1);
|
||||
|
||||
QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
|
||||
const uint serial = exec([=] { return nextSerial(); });
|
||||
exec([=] {
|
||||
auto *base = get<XdgWmBase>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user