wayland: send modifiers to clients under the mouse
This commit is contained in:
parent
ca9eb3d87d
commit
9915cfc6df
5 changed files with 106 additions and 10 deletions
|
@ -23,10 +23,12 @@
|
|||
#include "wayland_server.h"
|
||||
#include "window.h"
|
||||
#include "workspace.h"
|
||||
#include "x11window.h"
|
||||
|
||||
#include <KWayland/Client/buffer.h>
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/connection_thread.h>
|
||||
#include <KWayland/Client/keyboard.h>
|
||||
#include <KWayland/Client/pointer.h>
|
||||
#include <KWayland/Client/region.h>
|
||||
#include <KWayland/Client/seat.h>
|
||||
|
@ -35,6 +37,7 @@
|
|||
#include <KWayland/Client/surface.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -121,6 +124,7 @@ private Q_SLOTS:
|
|||
void testHideShowCursor();
|
||||
void testDefaultInputRegion();
|
||||
void testEmptyInputRegion();
|
||||
void testUnfocusedModifiers();
|
||||
|
||||
private:
|
||||
void render(KWayland::Client::Surface *surface, const QSize &size = QSize(100, 50));
|
||||
|
@ -1817,6 +1821,69 @@ void PointerInputTest::testEmptyInputRegion()
|
|||
QVERIFY(Test::waitForWindowDestroyed(window));
|
||||
}
|
||||
|
||||
void PointerInputTest::testUnfocusedModifiers()
|
||||
{
|
||||
// This test verifies that a window under the cursor gets modifier events,
|
||||
// even if it isn't focused
|
||||
|
||||
// create a Wayland window
|
||||
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||
QVERIFY(surface != nullptr);
|
||||
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
|
||||
QVERIFY(shellSurface != nullptr);
|
||||
Window *waylandWindow = Test::renderAndWaitForShown(surface.get(), QSize(10, 10), Qt::blue);
|
||||
QVERIFY(waylandWindow);
|
||||
waylandWindow->move(QPoint(0, 0));
|
||||
Test::waitForWaylandKeyboard();
|
||||
std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
|
||||
|
||||
// Create an xcb window.
|
||||
Test::XcbConnectionPtr c = Test::createX11Connection();
|
||||
QVERIFY(!xcb_connection_has_error(c.get()));
|
||||
const QRect windowGeometry(0, 0, 10, 10);
|
||||
xcb_window_t windowId = xcb_generate_id(c.get());
|
||||
xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
|
||||
windowGeometry.x(),
|
||||
windowGeometry.y(),
|
||||
windowGeometry.width(),
|
||||
windowGeometry.height(),
|
||||
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
|
||||
xcb_size_hints_t hints = {};
|
||||
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
|
||||
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
|
||||
xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
|
||||
xcb_map_window(c.get(), windowId);
|
||||
xcb_flush(c.get());
|
||||
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
|
||||
QVERIFY(windowCreatedSpy.wait());
|
||||
X11Window *x11window = windowCreatedSpy.last().first().value<X11Window *>();
|
||||
QVERIFY(waylandWindow);
|
||||
x11window->move(QPoint(10, 10));
|
||||
|
||||
workspace()->activateWindow(x11window, true);
|
||||
|
||||
// Move the pointer over the now unfocused Wayland window
|
||||
input()->pointer()->warp(waylandWindow->frameGeometry().center());
|
||||
QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), waylandWindow->surface());
|
||||
|
||||
QSignalSpy spy(keyboard.get(), &KWayland::Client::Keyboard::modifiersChanged);
|
||||
Test::keyboardKeyPressed(KEY_LEFTCTRL, 1);
|
||||
QVERIFY(spy.wait(50));
|
||||
QCOMPARE(spy.last().at(0).toInt(), XCB_MOD_MASK_CONTROL);
|
||||
|
||||
Test::keyboardKeyReleased(KEY_LEFTCTRL, 2);
|
||||
|
||||
// Destroy the x11 window.
|
||||
QSignalSpy windowClosedSpy(waylandWindow, &X11Window::closed);
|
||||
xcb_unmap_window(c.get(), windowId);
|
||||
xcb_destroy_window(c.get(), windowId);
|
||||
xcb_flush(c.get());
|
||||
c.reset();
|
||||
|
||||
// Destroy the Wayland window.
|
||||
shellSurface.reset();
|
||||
QVERIFY(Test::waitForWindowDestroyed(waylandWindow));
|
||||
}
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(KWin::PointerInputTest)
|
||||
|
|
|
@ -100,9 +100,9 @@ void KeyboardInterface::setKeymap(const QByteArray &content)
|
|||
}
|
||||
}
|
||||
|
||||
void KeyboardInterfacePrivate::sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial)
|
||||
void KeyboardInterfacePrivate::sendModifiers(SurfaceInterface *surface, quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial)
|
||||
{
|
||||
const QList<Resource *> keyboards = keyboardsForClient(focusedSurface->client());
|
||||
const QList<Resource *> keyboards = keyboardsForClient(surface->client());
|
||||
for (Resource *keyboardResource : keyboards) {
|
||||
send_modifiers(keyboardResource->handle, serial, depressed, latched, locked, group);
|
||||
}
|
||||
|
@ -129,9 +129,9 @@ KeyboardInterface::KeyboardInterface(SeatInterface *seat)
|
|||
|
||||
KeyboardInterface::~KeyboardInterface() = default;
|
||||
|
||||
void KeyboardInterfacePrivate::sendModifiers()
|
||||
void KeyboardInterfacePrivate::sendModifiers(SurfaceInterface *surface)
|
||||
{
|
||||
sendModifiers(modifiers.depressed, modifiers.latched, modifiers.locked, modifiers.group, modifiers.serial);
|
||||
sendModifiers(surface, modifiers.depressed, modifiers.latched, modifiers.locked, modifiers.group, modifiers.serial);
|
||||
}
|
||||
|
||||
void KeyboardInterface::setFocusedSurface(SurfaceInterface *surface, quint32 serial)
|
||||
|
@ -155,7 +155,19 @@ void KeyboardInterface::setFocusedSurface(SurfaceInterface *surface, quint32 ser
|
|||
});
|
||||
|
||||
d->sendEnter(d->focusedSurface, serial);
|
||||
d->sendModifiers();
|
||||
d->sendModifiers(d->focusedSurface);
|
||||
}
|
||||
|
||||
void KeyboardInterface::setModifierFocusSurface(SurfaceInterface *surface)
|
||||
{
|
||||
if (d->modifierFocusSurface == surface) {
|
||||
return;
|
||||
}
|
||||
d->modifierFocusSurface = surface;
|
||||
if (d->modifierFocusSurface && d->focusedSurface != d->modifierFocusSurface) {
|
||||
d->modifiers.serial = d->seat->display()->nextSerial();
|
||||
d->sendModifiers(d->modifierFocusSurface);
|
||||
}
|
||||
}
|
||||
|
||||
QVector<quint32> KeyboardInterfacePrivate::pressedKeys() const
|
||||
|
@ -210,12 +222,18 @@ void KeyboardInterface::sendModifiers(quint32 depressed, quint32 latched, quint3
|
|||
d->modifiers.group = group;
|
||||
changed = true;
|
||||
}
|
||||
if (!changed || !d->focusedSurface) {
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->modifiers.serial = d->seat->display()->nextSerial();
|
||||
d->sendModifiers(depressed, latched, locked, group, d->modifiers.serial);
|
||||
if (d->focusedSurface) {
|
||||
d->modifiers.serial = d->seat->display()->nextSerial();
|
||||
d->sendModifiers(d->focusedSurface, depressed, latched, locked, group, d->modifiers.serial);
|
||||
}
|
||||
if (d->modifierFocusSurface && d->focusedSurface != d->modifierFocusSurface) {
|
||||
d->modifiers.serial = d->seat->display()->nextSerial();
|
||||
d->sendModifiers(d->modifierFocusSurface, depressed, latched, locked, group, d->modifiers.serial);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardInterface::setRepeatInfo(qint32 charactersPerSecond, qint32 delay)
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
|
||||
private:
|
||||
void setFocusedSurface(SurfaceInterface *surface, quint32 serial);
|
||||
void setModifierFocusSurface(SurfaceInterface *surface);
|
||||
friend class SeatInterface;
|
||||
friend class SeatInterfacePrivate;
|
||||
friend class KeyboardInterfacePrivate;
|
||||
|
|
|
@ -23,8 +23,8 @@ public:
|
|||
KeyboardInterfacePrivate(SeatInterface *s);
|
||||
|
||||
void sendKeymap(Resource *resource);
|
||||
void sendModifiers();
|
||||
void sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial);
|
||||
void sendModifiers(SurfaceInterface *surface);
|
||||
void sendModifiers(SurfaceInterface *surface, quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial);
|
||||
|
||||
QList<Resource *> keyboardsForClient(ClientConnection *client) const;
|
||||
void sendLeave(SurfaceInterface *surface, quint32 serial);
|
||||
|
@ -38,6 +38,7 @@ public:
|
|||
SeatInterface *seat;
|
||||
SurfaceInterface *focusedSurface = nullptr;
|
||||
QMetaObject::Connection destroyConnection;
|
||||
QPointer<SurfaceInterface> modifierFocusSurface;
|
||||
QByteArray keymap;
|
||||
KWin::RamFile sharedKeymapFile;
|
||||
|
||||
|
|
|
@ -461,6 +461,9 @@ void SeatInterface::notifyPointerMotion(const QPointF &pos)
|
|||
|
||||
if (d->pointer->focusedSurface() != effectiveFocusedSurface) {
|
||||
d->pointer->sendEnter(effectiveFocusedSurface, localPosition, display()->nextSerial());
|
||||
if (d->keyboard) {
|
||||
d->keyboard->setModifierFocusSurface(effectiveFocusedSurface);
|
||||
}
|
||||
}
|
||||
|
||||
d->pointer->sendMotion(localPosition);
|
||||
|
@ -580,6 +583,9 @@ void SeatInterface::notifyPointerEnter(SurfaceInterface *surface, const QPointF
|
|||
localPosition = surface->mapToChild(effectiveFocusedSurface, localPosition);
|
||||
}
|
||||
d->pointer->sendEnter(effectiveFocusedSurface, localPosition, serial);
|
||||
if (d->keyboard) {
|
||||
d->keyboard->setModifierFocusSurface(effectiveFocusedSurface);
|
||||
}
|
||||
}
|
||||
|
||||
void SeatInterface::notifyPointerLeave()
|
||||
|
@ -599,6 +605,9 @@ void SeatInterface::notifyPointerLeave()
|
|||
|
||||
const quint32 serial = d->display->nextSerial();
|
||||
d->pointer->sendLeave(serial);
|
||||
if (d->keyboard) {
|
||||
d->keyboard->setModifierFocusSurface(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SeatInterface::setFocusedPointerSurfacePosition(const QPointF &surfacePosition)
|
||||
|
|
Loading…
Reference in a new issue