wayland: Implement cursor-shape-v1
References: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/194
This commit is contained in:
parent
9f18d5fdfc
commit
6cd56d5192
17 changed files with 495 additions and 91 deletions
|
@ -203,7 +203,7 @@ set_package_properties(Wayland PROPERTIES
|
|||
PURPOSE "Required for building KWin with Wayland support"
|
||||
)
|
||||
|
||||
find_package(WaylandProtocols 1.31)
|
||||
find_package(WaylandProtocols 1.32)
|
||||
set_package_properties(WaylandProtocols PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Collection of Wayland protocols that add functionality not available in the Wayland core protocol"
|
||||
|
|
|
@ -15,6 +15,7 @@ qt6_generate_wayland_protocol_client_sources(KWinIntegrationTestFramework
|
|||
${WaylandProtocols_DATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
|
||||
${WaylandProtocols_DATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml
|
||||
${WaylandProtocols_DATADIR}/staging/fractional-scale/fractional-scale-v1.xml
|
||||
${WaylandProtocols_DATADIR}/staging/cursor-shape/cursor-shape-v1.xml
|
||||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-device-v2.xml
|
||||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-management-v2.xml
|
||||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-screen-edge-v1.xml
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <KWayland/Client/surface.h>
|
||||
#include <optional>
|
||||
|
||||
#include "qwayland-cursor-shape-v1.h"
|
||||
#include "qwayland-fractional-scale-v1.h"
|
||||
#include "qwayland-idle-inhibit-unstable-v1.h"
|
||||
#include "qwayland-input-method-unstable-v1.h"
|
||||
|
@ -42,6 +43,7 @@ class Compositor;
|
|||
class Output;
|
||||
class PlasmaShell;
|
||||
class PlasmaWindowManagement;
|
||||
class Pointer;
|
||||
class PointerConstraints;
|
||||
class Seat;
|
||||
class ServerSideDecorationManager;
|
||||
|
@ -504,6 +506,21 @@ public:
|
|||
~AutoHideScreenEdgeV1() override;
|
||||
};
|
||||
|
||||
class CursorShapeManagerV1 : public QObject, public QtWayland::wp_cursor_shape_manager_v1
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~CursorShapeManagerV1() override;
|
||||
};
|
||||
|
||||
class CursorShapeDeviceV1 : public QObject, public QtWayland::wp_cursor_shape_device_v1
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CursorShapeDeviceV1(CursorShapeManagerV1 *manager, KWayland::Client::Pointer *pointer);
|
||||
~CursorShapeDeviceV1() override;
|
||||
};
|
||||
|
||||
enum class AdditionalWaylandInterface {
|
||||
Seat = 1 << 0,
|
||||
Decoration = 1 << 1,
|
||||
|
@ -523,6 +540,7 @@ enum class AdditionalWaylandInterface {
|
|||
FractionalScaleManagerV1 = 1 << 15,
|
||||
ScreencastingV1 = 1 << 16,
|
||||
ScreenEdgeV1 = 1 << 17,
|
||||
CursorShapeV1 = 1 << 18,
|
||||
};
|
||||
Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface)
|
||||
|
||||
|
@ -669,6 +687,7 @@ XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *
|
|||
XdgToplevelDecorationV1 *createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent = nullptr);
|
||||
IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface);
|
||||
AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border);
|
||||
CursorShapeDeviceV1 *createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer);
|
||||
|
||||
/**
|
||||
* Creates a shared memory buffer of @p size in @p color and attaches it to the @p surface.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "core/output.h"
|
||||
#include "cursor.h"
|
||||
#include "cursorsource.h"
|
||||
#include "libkwineffects/kwineffects.h"
|
||||
#include "options.h"
|
||||
#include "pointer_input.h"
|
||||
|
@ -107,6 +108,7 @@ private Q_SLOTS:
|
|||
void testMouseActionActiveWindow_data();
|
||||
void testMouseActionActiveWindow();
|
||||
void testCursorImage();
|
||||
void testCursorShapeV1();
|
||||
void testEffectOverrideCursorImage();
|
||||
void testPopup();
|
||||
void testDecoCancelsPopup();
|
||||
|
@ -159,7 +161,7 @@ void PointerInputTest::initTestCase()
|
|||
|
||||
void PointerInputTest::init()
|
||||
{
|
||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::Decoration | Test::AdditionalWaylandInterface::XdgDecorationV1));
|
||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::Decoration | Test::AdditionalWaylandInterface::XdgDecorationV1 | Test::AdditionalWaylandInterface::CursorShapeV1));
|
||||
QVERIFY(Test::waitForWaylandPointer());
|
||||
m_compositor = Test::waylandCompositor();
|
||||
m_seat = Test::waylandSeat();
|
||||
|
@ -1151,6 +1153,51 @@ void PointerInputTest::testCursorImage()
|
|||
QCOMPARE(kwinApp()->cursorImage().image(), fallbackCursor);
|
||||
}
|
||||
|
||||
static QByteArray currentCursorShape()
|
||||
{
|
||||
if (auto source = qobject_cast<ShapeCursorSource *>(Cursors::self()->currentCursor()->source())) {
|
||||
return source->shape();
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
void PointerInputTest::testCursorShapeV1()
|
||||
{
|
||||
// this test verifies the integration of the cursor-shape-v1 protocol
|
||||
|
||||
// get the pointer
|
||||
std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
|
||||
std::unique_ptr<Test::CursorShapeDeviceV1> cursorShapeDevice(Test::createCursorShapeDeviceV1(pointer.get()));
|
||||
|
||||
// move cursor somewhere the new window won't open
|
||||
input()->pointer()->warp(QPointF(800, 800));
|
||||
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
|
||||
|
||||
// create a window
|
||||
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
|
||||
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 100), Qt::cyan);
|
||||
QVERIFY(window);
|
||||
|
||||
// move the pointer to the center of the window
|
||||
QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
|
||||
input()->pointer()->warp(window->frameGeometry().center());
|
||||
QVERIFY(enteredSpy.wait());
|
||||
|
||||
// set a custom cursor shape
|
||||
QSignalSpy cursorChanged(Cursors::self(), &Cursors::currentCursorChanged);
|
||||
cursorShapeDevice->set_shape(enteredSpy.last().at(0).value<quint32>(), Test::CursorShapeDeviceV1::shape_text);
|
||||
QVERIFY(cursorChanged.wait());
|
||||
QCOMPARE(currentCursorShape(), QByteArray("text"));
|
||||
|
||||
// cursor shape won't be changed if the window has no pointer focus
|
||||
input()->pointer()->warp(QPointF(800, 800));
|
||||
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
|
||||
cursorShapeDevice->set_shape(enteredSpy.last().at(0).value<quint32>(), Test::CursorShapeDeviceV1::shape_grab);
|
||||
QVERIFY(Test::waylandSync());
|
||||
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
|
||||
}
|
||||
|
||||
class HelperEffect : public Effect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -1168,16 +1215,14 @@ void PointerInputTest::testEffectOverrideCursorImage()
|
|||
// this test verifies the effect cursor override handling
|
||||
|
||||
// we need a pointer to get the enter event and set a cursor
|
||||
auto pointer = m_seat->createPointer(m_seat);
|
||||
QVERIFY(pointer);
|
||||
QVERIFY(pointer->isValid());
|
||||
QSignalSpy enteredSpy(pointer, &KWayland::Client::Pointer::entered);
|
||||
QSignalSpy leftSpy(pointer, &KWayland::Client::Pointer::left);
|
||||
std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
|
||||
std::unique_ptr<Test::CursorShapeDeviceV1> cursorShapeDevice(Test::createCursorShapeDeviceV1(pointer.get()));
|
||||
QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
|
||||
QSignalSpy leftSpy(pointer.get(), &KWayland::Client::Pointer::left);
|
||||
QSignalSpy cursorChanged(Cursors::self(), &Cursors::currentCursorChanged);
|
||||
|
||||
// move cursor somewhere the new window won't open
|
||||
input()->pointer()->warp(QPointF(800, 800));
|
||||
// here we should have the fallback cursor
|
||||
const QImage fallback = kwinApp()->cursorImage().image();
|
||||
QVERIFY(!fallback.isNull());
|
||||
|
||||
// now let's create a window
|
||||
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
|
||||
|
@ -1194,34 +1239,26 @@ void PointerInputTest::testEffectOverrideCursorImage()
|
|||
QVERIFY(!exclusiveContains(window->frameGeometry(), QPoint(800, 800)));
|
||||
input()->pointer()->warp(window->frameGeometry().center());
|
||||
QVERIFY(enteredSpy.wait());
|
||||
// cursor image should still be fallback
|
||||
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
|
||||
cursorShapeDevice->set_shape(enteredSpy.last().at(0).value<quint32>(), Test::CursorShapeDeviceV1::shape_wait);
|
||||
QVERIFY(cursorChanged.wait());
|
||||
QCOMPARE(currentCursorShape(), QByteArray("wait"));
|
||||
|
||||
// now create an effect and set an override cursor
|
||||
std::unique_ptr<HelperEffect> effect(new HelperEffect);
|
||||
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
|
||||
const QImage sizeAll = kwinApp()->cursorImage().image();
|
||||
QVERIFY(!sizeAll.isNull());
|
||||
QVERIFY(sizeAll != fallback);
|
||||
QVERIFY(leftSpy.wait());
|
||||
QCOMPARE(currentCursorShape(), QByteArray("size_all"));
|
||||
|
||||
// let's change to arrow cursor, this should be our fallback
|
||||
effects->defineCursor(Qt::ArrowCursor);
|
||||
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
|
||||
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
|
||||
|
||||
// back to size all
|
||||
effects->defineCursor(Qt::SizeAllCursor);
|
||||
QCOMPARE(kwinApp()->cursorImage().image(), sizeAll);
|
||||
QCOMPARE(currentCursorShape(), QByteArray("size_all"));
|
||||
|
||||
// move cursor outside the window area
|
||||
input()->pointer()->warp(QPointF(800, 800));
|
||||
// and end the override, which should switch to fallback
|
||||
effects->stopMouseInterception(effect.get());
|
||||
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
|
||||
|
||||
// start mouse interception again
|
||||
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
|
||||
QCOMPARE(kwinApp()->cursorImage().image(), sizeAll);
|
||||
QCOMPARE(currentCursorShape(), QByteArray("size_all"));
|
||||
|
||||
// move cursor to area of window
|
||||
input()->pointer()->warp(window->frameGeometry().center());
|
||||
|
@ -1232,7 +1269,9 @@ void PointerInputTest::testEffectOverrideCursorImage()
|
|||
// after ending the interception we should get an enter event
|
||||
effects->stopMouseInterception(effect.get());
|
||||
QVERIFY(enteredSpy.wait());
|
||||
QVERIFY(kwinApp()->cursorImage().image().isNull());
|
||||
cursorShapeDevice->set_shape(enteredSpy.last().at(0).value<quint32>(), Test::CursorShapeDeviceV1::shape_crosshair);
|
||||
QVERIFY(cursorChanged.wait());
|
||||
QCOMPARE(currentCursorShape(), QByteArray("cross"));
|
||||
}
|
||||
|
||||
void PointerInputTest::testPopup()
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <KWayland/Client/output.h>
|
||||
#include <KWayland/Client/plasmashell.h>
|
||||
#include <KWayland/Client/plasmawindowmanagement.h>
|
||||
#include <KWayland/Client/pointer.h>
|
||||
#include <KWayland/Client/pointerconstraints.h>
|
||||
#include <KWayland/Client/registry.h>
|
||||
#include <KWayland/Client/seat.h>
|
||||
|
@ -244,6 +245,21 @@ AutoHideScreenEdgeV1::~AutoHideScreenEdgeV1()
|
|||
destroy();
|
||||
}
|
||||
|
||||
CursorShapeManagerV1::~CursorShapeManagerV1()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
CursorShapeDeviceV1::CursorShapeDeviceV1(CursorShapeManagerV1 *manager, KWayland::Client::Pointer *pointer)
|
||||
: QtWayland::wp_cursor_shape_device_v1(manager->get_pointer(*pointer))
|
||||
{
|
||||
}
|
||||
|
||||
CursorShapeDeviceV1::~CursorShapeDeviceV1()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
KWayland::Client::ConnectionThread *connection = nullptr;
|
||||
|
@ -275,6 +291,7 @@ static struct
|
|||
FractionalScaleManagerV1 *fractionalScaleManagerV1 = nullptr;
|
||||
ScreencastingV1 *screencastingV1 = nullptr;
|
||||
ScreenEdgeManagerV1 *screenEdgeManagerV1 = nullptr;
|
||||
CursorShapeManagerV1 *cursorShapeManagerV1 = nullptr;
|
||||
} s_waylandConnection;
|
||||
|
||||
MockInputMethod *inputMethod()
|
||||
|
@ -460,6 +477,12 @@ bool setupWaylandConnection(AdditionalWaylandInterfaces flags)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (flags &AdditionalWaylandInterface::CursorShapeV1) {
|
||||
if (interface == wp_cursor_shape_manager_v1_interface.name) {
|
||||
s_waylandConnection.cursorShapeManagerV1 = new CursorShapeManagerV1();
|
||||
s_waylandConnection.cursorShapeManagerV1->init(*registry, name, version);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced);
|
||||
|
@ -590,6 +613,8 @@ void destroyWaylandConnection()
|
|||
s_waylandConnection.screencastingV1 = nullptr;
|
||||
delete s_waylandConnection.screenEdgeManagerV1;
|
||||
s_waylandConnection.screenEdgeManagerV1 = nullptr;
|
||||
delete s_waylandConnection.cursorShapeManagerV1;
|
||||
s_waylandConnection.cursorShapeManagerV1 = nullptr;
|
||||
|
||||
delete s_waylandConnection.queue; // Must be destroyed last
|
||||
s_waylandConnection.queue = nullptr;
|
||||
|
@ -1009,6 +1034,17 @@ AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surf
|
|||
return new AutoHideScreenEdgeV1(manager, surface, border);
|
||||
}
|
||||
|
||||
CursorShapeDeviceV1 *createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer)
|
||||
{
|
||||
CursorShapeManagerV1 *manager = s_waylandConnection.cursorShapeManagerV1;
|
||||
if (!manager) {
|
||||
qWarning() << "Could not create a wp_cursor_shape_device_v1 because wp_cursor_shape_manager_v1 global is not bound";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new CursorShapeDeviceV1(manager, pointer);
|
||||
}
|
||||
|
||||
bool waitForWindowClosed(Window *window)
|
||||
{
|
||||
QSignalSpy closedSpy(window, &Window::closed);
|
||||
|
|
|
@ -1956,27 +1956,35 @@ public:
|
|||
explicit SurfaceCursor(KWaylandServer::TabletToolV2Interface *tool)
|
||||
: Cursor(tool)
|
||||
{
|
||||
connect(tool, &KWaylandServer::TabletToolV2Interface::cursorChanged, this, [this](KWaylandServer::TabletCursorV2 *tcursor) {
|
||||
if (!tcursor || tcursor->enteredSerial() == 0) {
|
||||
if (!m_defaultSource) {
|
||||
m_defaultSource = std::make_unique<ShapeCursorSource>();
|
||||
connect(tool, &KWaylandServer::TabletToolV2Interface::cursorChanged, this, [this](const KWaylandServer::TabletCursorSourceV2 &cursor) {
|
||||
if (auto surfaceCursor = std::get_if<KWaylandServer::TabletSurfaceCursorV2 *>(&cursor)) {
|
||||
// If the cursor is unset, fallback to the cross cursor.
|
||||
if ((*surfaceCursor) && (*surfaceCursor)->enteredSerial()) {
|
||||
if (!m_surfaceSource) {
|
||||
m_surfaceSource = std::make_unique<SurfaceCursorSource>();
|
||||
}
|
||||
m_surfaceSource->update((*surfaceCursor)->surface(), (*surfaceCursor)->hotspot());
|
||||
setSource(m_surfaceSource.get());
|
||||
return;
|
||||
}
|
||||
static WaylandCursorImage defaultCursor;
|
||||
m_defaultSource->setTheme(defaultCursor.theme());
|
||||
m_defaultSource->setShape(Qt::CrossCursor);
|
||||
setSource(m_defaultSource.get());
|
||||
} else {
|
||||
if (!m_surfaceSource) {
|
||||
m_surfaceSource = std::make_unique<SurfaceCursorSource>();
|
||||
}
|
||||
m_surfaceSource->update(tcursor->surface(), tcursor->hotspot());
|
||||
setSource(m_surfaceSource.get());
|
||||
}
|
||||
|
||||
QByteArray shape;
|
||||
if (auto shapeCursor = std::get_if<QByteArray>(&cursor)) {
|
||||
shape = *shapeCursor;
|
||||
} else {
|
||||
shape = QByteArrayLiteral("cross");
|
||||
}
|
||||
|
||||
static WaylandCursorImage defaultCursor;
|
||||
m_shapeSource->setTheme(defaultCursor.theme());
|
||||
m_shapeSource->setShape(shape);
|
||||
setSource(m_shapeSource.get());
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ShapeCursorSource> m_defaultSource;
|
||||
std::unique_ptr<ShapeCursorSource> m_shapeSource;
|
||||
std::unique_ptr<SurfaceCursorSource> m_surfaceSource;
|
||||
};
|
||||
|
||||
|
|
|
@ -862,7 +862,8 @@ CursorImage::CursorImage(PointerInputRedirection *parent)
|
|||
m_moveResizeCursor = std::make_unique<ShapeCursorSource>();
|
||||
m_windowSelectionCursor = std::make_unique<ShapeCursorSource>();
|
||||
m_decoration.cursor = std::make_unique<ShapeCursorSource>();
|
||||
m_serverCursor.cursor = std::make_unique<SurfaceCursorSource>();
|
||||
m_serverCursor.surface = std::make_unique<SurfaceCursorSource>();
|
||||
m_serverCursor.shape = std::make_unique<ShapeCursorSource>();
|
||||
|
||||
#if KWIN_BUILD_SCREENLOCKER
|
||||
if (waylandServer()->hasScreenLockerIntegration()) {
|
||||
|
@ -886,6 +887,7 @@ CursorImage::CursorImage(PointerInputRedirection *parent)
|
|||
m_moveResizeCursor->setTheme(m_waylandImage.theme());
|
||||
m_windowSelectionCursor->setTheme(m_waylandImage.theme());
|
||||
m_decoration.cursor->setTheme(m_waylandImage.theme());
|
||||
m_serverCursor.shape->setTheme(m_waylandImage.theme());
|
||||
|
||||
connect(&m_waylandImage, &WaylandCursorImage::themeChanged, this, [this] {
|
||||
m_effectsCursor->setTheme(m_waylandImage.theme());
|
||||
|
@ -893,6 +895,7 @@ CursorImage::CursorImage(PointerInputRedirection *parent)
|
|||
m_moveResizeCursor->setTheme(m_waylandImage.theme());
|
||||
m_windowSelectionCursor->setTheme(m_waylandImage.theme());
|
||||
m_decoration.cursor->setTheme(m_waylandImage.theme());
|
||||
m_serverCursor.shape->setTheme(m_waylandImage.theme());
|
||||
});
|
||||
|
||||
KWaylandServer::PointerInterface *pointer = waylandServer()->seat()->pointer();
|
||||
|
@ -907,8 +910,8 @@ CursorImage::~CursorImage() = default;
|
|||
|
||||
void CursorImage::updateCursorOutputs(const QPointF &pos)
|
||||
{
|
||||
if (m_currentSource == m_serverCursor.cursor.get()) {
|
||||
auto cursorSurface = m_serverCursor.cursor->surface();
|
||||
if (m_currentSource == m_serverCursor.surface.get()) {
|
||||
auto cursorSurface = m_serverCursor.surface->surface();
|
||||
if (cursorSurface) {
|
||||
const QRectF cursorGeometry(pos - m_currentSource->hotspot(), m_currentSource->size());
|
||||
cursorSurface->setOutputs(waylandServer()->display()->outputsIntersecting(cursorGeometry.toAlignedRect()));
|
||||
|
@ -918,8 +921,8 @@ void CursorImage::updateCursorOutputs(const QPointF &pos)
|
|||
|
||||
void CursorImage::markAsRendered(std::chrono::milliseconds timestamp)
|
||||
{
|
||||
if (m_currentSource == m_serverCursor.cursor.get()) {
|
||||
auto cursorSurface = m_serverCursor.cursor->surface();
|
||||
if (m_currentSource == m_serverCursor.surface.get()) {
|
||||
auto cursorSurface = m_serverCursor.surface->surface();
|
||||
if (cursorSurface) {
|
||||
cursorSurface->frameRendered(timestamp.count());
|
||||
}
|
||||
|
@ -970,9 +973,15 @@ void CursorImage::updateMoveResize()
|
|||
reevaluteSource();
|
||||
}
|
||||
|
||||
void CursorImage::updateServerCursor(KWaylandServer::Cursor *cursor)
|
||||
void CursorImage::updateServerCursor(const KWaylandServer::PointerCursor &cursor)
|
||||
{
|
||||
m_serverCursor.cursor->update(cursor->surface(), cursor->hotspot());
|
||||
if (auto surfaceCursor = std::get_if<KWaylandServer::Cursor *>(&cursor)) {
|
||||
m_serverCursor.surface->update((*surfaceCursor)->surface(), (*surfaceCursor)->hotspot());
|
||||
m_serverCursor.cursor = m_serverCursor.surface.get();
|
||||
} else if (auto shapeCursor = std::get_if<QByteArray>(&cursor)) {
|
||||
m_serverCursor.shape->setShape(*shapeCursor);
|
||||
m_serverCursor.cursor = m_serverCursor.shape.get();
|
||||
}
|
||||
reevaluteSource();
|
||||
}
|
||||
|
||||
|
@ -1040,7 +1049,7 @@ void WaylandCursorImage::updateCursorTheme()
|
|||
void CursorImage::reevaluteSource()
|
||||
{
|
||||
if (waylandServer()->isScreenLocked()) {
|
||||
setSource(m_serverCursor.cursor.get());
|
||||
setSource(m_serverCursor.cursor);
|
||||
return;
|
||||
}
|
||||
if (input()->isSelectingWindow()) {
|
||||
|
@ -1061,7 +1070,7 @@ void CursorImage::reevaluteSource()
|
|||
}
|
||||
const KWaylandServer::PointerInterface *pointer = waylandServer()->seat()->pointer();
|
||||
if (pointer && pointer->focusedSurface()) {
|
||||
setSource(m_serverCursor.cursor.get());
|
||||
setSource(m_serverCursor.cursor);
|
||||
return;
|
||||
}
|
||||
setSource(m_fallbackCursor.get());
|
||||
|
|
|
@ -222,7 +222,7 @@ Q_SIGNALS:
|
|||
|
||||
private:
|
||||
void reevaluteSource();
|
||||
void updateServerCursor(KWaylandServer::Cursor *cursor);
|
||||
void updateServerCursor(const std::variant<KWaylandServer::Cursor *, QByteArray> &cursor);
|
||||
void updateDecoration();
|
||||
void updateDecorationCursor();
|
||||
void updateMoveResize();
|
||||
|
@ -246,7 +246,9 @@ private:
|
|||
struct
|
||||
{
|
||||
QMetaObject::Connection connection;
|
||||
std::unique_ptr<SurfaceCursorSource> cursor;
|
||||
std::unique_ptr<SurfaceCursorSource> surface;
|
||||
std::unique_ptr<ShapeCursorSource> shape;
|
||||
CursorSource *cursor = nullptr;
|
||||
} m_serverCursor;
|
||||
};
|
||||
|
||||
|
|
|
@ -212,6 +212,10 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
|
|||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-screen-edge-v1.xml
|
||||
BASENAME kde-screen-edge-v1
|
||||
)
|
||||
ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/staging/cursor-shape/cursor-shape-v1.xml
|
||||
BASENAME cursor-shape-v1
|
||||
)
|
||||
|
||||
target_sources(kwin PRIVATE
|
||||
abstract_data_source.cpp
|
||||
|
@ -222,6 +226,7 @@ target_sources(kwin PRIVATE
|
|||
compositor_interface.cpp
|
||||
contenttype_v1_interface.cpp
|
||||
contrast_interface.cpp
|
||||
cursorshape_v1_interface.cpp
|
||||
datacontroldevice_v1_interface.cpp
|
||||
datacontroldevicemanager_v1_interface.cpp
|
||||
datacontroloffer_v1_interface.cpp
|
||||
|
@ -305,6 +310,7 @@ install(FILES
|
|||
compositor_interface.h
|
||||
contenttype_v1_interface.h
|
||||
contrast_interface.h
|
||||
cursorshape_v1_interface.h
|
||||
datacontroldevice_v1_interface.h
|
||||
datacontroldevicemanager_v1_interface.h
|
||||
datacontroloffer_v1_interface.h
|
||||
|
|
|
@ -1328,7 +1328,7 @@ void TestWaylandSeat::testCursor()
|
|||
p->setCursor(nullptr);
|
||||
QVERIFY(cursorChangedSpy.wait());
|
||||
QCOMPARE(cursorChangedSpy.count(), 1);
|
||||
auto cursor = cursorChangedSpy.last().first().value<KWaylandServer::Cursor *>();
|
||||
auto cursor = std::get<KWaylandServer::Cursor *>(cursorChangedSpy.last().first().value<KWaylandServer::PointerCursor>());
|
||||
QVERIFY(cursor);
|
||||
QVERIFY(!cursor->surface());
|
||||
QCOMPARE(cursor->hotspot(), QPoint());
|
||||
|
|
209
src/wayland/cursorshape_v1_interface.cpp
Normal file
209
src/wayland/cursorshape_v1_interface.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#include "wayland/cursorshape_v1_interface.h"
|
||||
#include "wayland/display.h"
|
||||
#include "wayland/pointer_interface.h"
|
||||
#include "wayland/surface_interface.h"
|
||||
#include "wayland/tablet_v2_interface.h"
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
#include "qwayland-server-cursor-shape-v1.h"
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
|
||||
static constexpr int s_version = 1;
|
||||
|
||||
class CursorShapeManagerV1InterfacePrivate : public QtWaylandServer::wp_cursor_shape_manager_v1
|
||||
{
|
||||
public:
|
||||
CursorShapeManagerV1InterfacePrivate(Display *display);
|
||||
|
||||
protected:
|
||||
void wp_cursor_shape_manager_v1_destroy(Resource *resource) override;
|
||||
void wp_cursor_shape_manager_v1_get_pointer(Resource *resource, uint32_t cursor_shape_device, struct ::wl_resource *pointer) override;
|
||||
void wp_cursor_shape_manager_v1_get_tablet_tool_v2(Resource *resource, uint32_t cursor_shape_device, struct ::wl_resource *tablet_tool) override;
|
||||
};
|
||||
|
||||
class CursorShapeDeviceV1Interface : public QtWaylandServer::wp_cursor_shape_device_v1
|
||||
{
|
||||
public:
|
||||
CursorShapeDeviceV1Interface(PointerInterface *pointer, wl_resource *resource);
|
||||
CursorShapeDeviceV1Interface(TabletToolV2Interface *tabletTool, wl_resource *resource);
|
||||
|
||||
QPointer<PointerInterface> pointer;
|
||||
QPointer<TabletToolV2Interface> tabletTool;
|
||||
|
||||
protected:
|
||||
void wp_cursor_shape_device_v1_destroy_resource(Resource *resource) override;
|
||||
void wp_cursor_shape_device_v1_destroy(Resource *resource) override;
|
||||
void wp_cursor_shape_device_v1_set_shape(Resource *resource, uint32_t serial, uint32_t shape) override;
|
||||
};
|
||||
|
||||
CursorShapeManagerV1InterfacePrivate::CursorShapeManagerV1InterfacePrivate(Display *display)
|
||||
: QtWaylandServer::wp_cursor_shape_manager_v1(*display, s_version)
|
||||
{
|
||||
}
|
||||
|
||||
void CursorShapeManagerV1InterfacePrivate::wp_cursor_shape_manager_v1_destroy(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void CursorShapeManagerV1InterfacePrivate::wp_cursor_shape_manager_v1_get_pointer(Resource *resource, uint32_t cursor_shape_device, struct ::wl_resource *pointer)
|
||||
{
|
||||
wl_resource *device = wl_resource_create(resource->client(), &wp_cursor_shape_device_v1_interface, resource->version(), cursor_shape_device);
|
||||
if (!device) {
|
||||
wl_resource_post_no_memory(resource->handle);
|
||||
return;
|
||||
}
|
||||
new CursorShapeDeviceV1Interface(PointerInterface::get(pointer), device);
|
||||
}
|
||||
|
||||
void CursorShapeManagerV1InterfacePrivate::wp_cursor_shape_manager_v1_get_tablet_tool_v2(Resource *resource, uint32_t cursor_shape_device, struct ::wl_resource *tablet_tool)
|
||||
{
|
||||
wl_resource *device = wl_resource_create(resource->client(), &wp_cursor_shape_device_v1_interface, resource->version(), cursor_shape_device);
|
||||
if (!device) {
|
||||
wl_resource_post_no_memory(resource->handle);
|
||||
return;
|
||||
}
|
||||
new CursorShapeDeviceV1Interface(TabletToolV2Interface::get(tablet_tool), device);
|
||||
}
|
||||
|
||||
CursorShapeManagerV1Interface::CursorShapeManagerV1Interface(Display *display, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(std::make_unique<CursorShapeManagerV1InterfacePrivate>(display))
|
||||
{
|
||||
}
|
||||
|
||||
CursorShapeManagerV1Interface::~CursorShapeManagerV1Interface()
|
||||
{
|
||||
}
|
||||
|
||||
CursorShapeDeviceV1Interface::CursorShapeDeviceV1Interface(PointerInterface *pointer, wl_resource *resource)
|
||||
: QtWaylandServer::wp_cursor_shape_device_v1(resource)
|
||||
, pointer(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
CursorShapeDeviceV1Interface::CursorShapeDeviceV1Interface(TabletToolV2Interface *tabletTool, wl_resource *resource)
|
||||
: QtWaylandServer::wp_cursor_shape_device_v1(resource)
|
||||
, tabletTool(tabletTool)
|
||||
{
|
||||
}
|
||||
|
||||
void CursorShapeDeviceV1Interface::wp_cursor_shape_device_v1_destroy_resource(Resource *resource)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void CursorShapeDeviceV1Interface::wp_cursor_shape_device_v1_destroy(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
static QByteArray shapeName(uint32_t shape)
|
||||
{
|
||||
switch (shape) {
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_default:
|
||||
return QByteArrayLiteral("default");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_context_menu:
|
||||
return QByteArrayLiteral("context-menu");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_help:
|
||||
return QByteArrayLiteral("whats_this");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_pointer:
|
||||
return QByteArrayLiteral("pointing_hand");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_progress:
|
||||
return QByteArrayLiteral("left_ptr_watch");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_wait:
|
||||
return QByteArrayLiteral("wait");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_cell:
|
||||
return QByteArrayLiteral("cell");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_crosshair:
|
||||
return QByteArrayLiteral("cross");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_text:
|
||||
return QByteArrayLiteral("text");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_vertical_text:
|
||||
return QByteArrayLiteral("vertical-text");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_alias:
|
||||
return QByteArrayLiteral("dnd-link");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_copy:
|
||||
return QByteArrayLiteral("dnd-copy");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_move:
|
||||
return QByteArrayLiteral("dnd-move");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_no_drop:
|
||||
return QByteArrayLiteral("no-drop");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_not_allowed:
|
||||
return QByteArrayLiteral("not-allowed");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_grab:
|
||||
return QByteArrayLiteral("openhand");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_grabbing:
|
||||
return QByteArrayLiteral("closedhand");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_e_resize:
|
||||
return QByteArrayLiteral("e-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_n_resize:
|
||||
return QByteArrayLiteral("n-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_ne_resize:
|
||||
return QByteArrayLiteral("ne-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_nw_resize:
|
||||
return QByteArrayLiteral("nw-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_s_resize:
|
||||
return QByteArrayLiteral("s-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_se_resize:
|
||||
return QByteArrayLiteral("se-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_sw_resize:
|
||||
return QByteArrayLiteral("sw-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_w_resize:
|
||||
return QByteArrayLiteral("w-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_ew_resize:
|
||||
return QByteArrayLiteral("size_hor");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_ns_resize:
|
||||
return QByteArrayLiteral("size_ver");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_nesw_resize:
|
||||
return QByteArrayLiteral("size_bdiag");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_nwse_resize:
|
||||
return QByteArrayLiteral("size_fdiag");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_col_resize:
|
||||
return QByteArrayLiteral("col-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_row_resize:
|
||||
return QByteArrayLiteral("row-resize");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_all_scroll:
|
||||
return QByteArrayLiteral("all-scroll");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_zoom_in:
|
||||
return QByteArrayLiteral("zoom-in");
|
||||
case QtWaylandServer::wp_cursor_shape_device_v1::shape_zoom_out:
|
||||
return QByteArrayLiteral("zoom-out");
|
||||
default:
|
||||
return QByteArrayLiteral("left_ptr");
|
||||
}
|
||||
}
|
||||
|
||||
void CursorShapeDeviceV1Interface::wp_cursor_shape_device_v1_set_shape(Resource *resource, uint32_t serial, uint32_t shape)
|
||||
{
|
||||
if (shape < shape_default || shape > shape_zoom_out) {
|
||||
wl_resource_post_error(resource->handle, error_invalid_shape, "unknown cursor shape");
|
||||
return;
|
||||
}
|
||||
if (pointer) {
|
||||
if (!pointer->focusedSurface() || pointer->focusedSurface()->client()->client() != resource->client()) {
|
||||
return;
|
||||
}
|
||||
if (pointer->focusedSerial() == serial) {
|
||||
Q_EMIT pointer->cursorChanged(shapeName(shape));
|
||||
}
|
||||
} else if (tabletTool) {
|
||||
if (!tabletTool->currentSurface() || tabletTool->currentSurface()->client()->client() != resource->client()) {
|
||||
return;
|
||||
}
|
||||
if (tabletTool->proximitySerial() == serial) {
|
||||
Q_EMIT tabletTool->cursorChanged(shapeName(shape));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace KWaylandServer
|
31
src/wayland/cursorshape_v1_interface.h
Normal file
31
src/wayland/cursorshape_v1_interface.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kwin_export.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
|
||||
class CursorShapeManagerV1InterfacePrivate;
|
||||
class Display;
|
||||
|
||||
class KWIN_EXPORT CursorShapeManagerV1Interface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CursorShapeManagerV1Interface(Display *display, QObject *parent = nullptr);
|
||||
~CursorShapeManagerV1Interface() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<CursorShapeManagerV1InterfacePrivate> d;
|
||||
};
|
||||
|
||||
} // namespace KWaylandServer
|
|
@ -147,6 +147,11 @@ SurfaceInterface *PointerInterface::focusedSurface() const
|
|||
return d->focusedSurface;
|
||||
}
|
||||
|
||||
quint32 PointerInterface::focusedSerial() const
|
||||
{
|
||||
return d->focusedSerial;
|
||||
}
|
||||
|
||||
void PointerInterface::sendEnter(SurfaceInterface *surface, const QPointF &position, quint32 serial)
|
||||
{
|
||||
if (d->focusedSurface == surface) {
|
||||
|
|
|
@ -25,6 +25,8 @@ class SurfaceInterface;
|
|||
enum class PointerAxisSource;
|
||||
enum class PointerButtonState : quint32;
|
||||
|
||||
using PointerCursor = std::variant<Cursor *, QByteArray>;
|
||||
|
||||
/**
|
||||
* The PointerInterface class represents one or more input devices such as mice, which control
|
||||
* the pointer location. It corresponds to the Wayland interface @c wl_pointer.
|
||||
|
@ -42,6 +44,7 @@ public:
|
|||
* the effective focused surface.
|
||||
*/
|
||||
SurfaceInterface *focusedSurface() const;
|
||||
quint32 focusedSerial() const;
|
||||
|
||||
/**
|
||||
* Returns the seat to which this pointer belongs to.
|
||||
|
@ -65,7 +68,7 @@ Q_SIGNALS:
|
|||
* This signal is emitted whenever the cursor surface changes. As long as there is no
|
||||
* any focused surface, the cursor cannot be changed.
|
||||
*/
|
||||
void cursorChanged(KWaylandServer::Cursor *cursor);
|
||||
void cursorChanged(const PointerCursor &cursor);
|
||||
/**
|
||||
* This signal is emitted whenever the focused pointer surface changes.
|
||||
*/
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "display.h"
|
||||
#include "seat_interface.h"
|
||||
#include "surface_interface.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "qwayland-server-tablet-unstable-v2.h"
|
||||
#include <QHash>
|
||||
|
@ -68,10 +69,10 @@ TabletPadV2Interface *TabletV2Interface::pad() const
|
|||
return d->m_pad;
|
||||
}
|
||||
|
||||
class TabletCursorV2Private
|
||||
class TabletSurfaceCursorV2Private
|
||||
{
|
||||
public:
|
||||
TabletCursorV2Private(TabletCursorV2 *q)
|
||||
TabletSurfaceCursorV2Private(TabletSurfaceCursorV2 *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
@ -88,32 +89,32 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
TabletCursorV2 *const q;
|
||||
TabletSurfaceCursorV2 *const q;
|
||||
|
||||
quint32 m_serial = 0;
|
||||
QPointer<SurfaceInterface> m_surface;
|
||||
QPoint m_hotspot;
|
||||
};
|
||||
|
||||
TabletCursorV2::TabletCursorV2()
|
||||
TabletSurfaceCursorV2::TabletSurfaceCursorV2()
|
||||
: QObject()
|
||||
, d(new TabletCursorV2Private(this))
|
||||
, d(new TabletSurfaceCursorV2Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
TabletCursorV2::~TabletCursorV2() = default;
|
||||
TabletSurfaceCursorV2::~TabletSurfaceCursorV2() = default;
|
||||
|
||||
QPoint TabletCursorV2::hotspot() const
|
||||
QPoint TabletSurfaceCursorV2::hotspot() const
|
||||
{
|
||||
return d->m_hotspot;
|
||||
}
|
||||
|
||||
quint32 TabletCursorV2::enteredSerial() const
|
||||
quint32 TabletSurfaceCursorV2::enteredSerial() const
|
||||
{
|
||||
return d->m_serial;
|
||||
}
|
||||
|
||||
SurfaceInterface *TabletCursorV2::surface() const
|
||||
SurfaceInterface *TabletSurfaceCursorV2::surface() const
|
||||
{
|
||||
return d->m_surface;
|
||||
}
|
||||
|
@ -162,17 +163,18 @@ public:
|
|||
|
||||
void zwp_tablet_tool_v2_bind_resource(QtWaylandServer::zwp_tablet_tool_v2::Resource *resource) override
|
||||
{
|
||||
TabletCursorV2 *&c = m_cursors[resource->handle];
|
||||
TabletSurfaceCursorV2 *&c = m_cursors[resource->handle];
|
||||
if (!c)
|
||||
c = new TabletCursorV2;
|
||||
c = new TabletSurfaceCursorV2;
|
||||
}
|
||||
|
||||
void zwp_tablet_tool_v2_set_cursor(Resource *resource, uint32_t serial, struct ::wl_resource *_surface, int32_t hotspot_x, int32_t hotspot_y) override
|
||||
{
|
||||
TabletCursorV2 *c = m_cursors[resource->handle];
|
||||
TabletSurfaceCursorV2 *c = m_cursors[resource->handle];
|
||||
c->d->update(serial, SurfaceInterface::get(_surface), {hotspot_x, hotspot_y});
|
||||
if (resource->handle == targetResource())
|
||||
q->cursorChanged(c);
|
||||
if (resource->handle == targetResource()) {
|
||||
Q_EMIT q->cursorChanged(c);
|
||||
}
|
||||
}
|
||||
|
||||
void zwp_tablet_tool_v2_destroy_resource(Resource *resource) override
|
||||
|
@ -189,6 +191,7 @@ public:
|
|||
}
|
||||
|
||||
Display *const m_display;
|
||||
quint32 m_proximitySerial = 0;
|
||||
bool m_cleanup = false;
|
||||
bool m_removed = false;
|
||||
QPointer<SurfaceInterface> m_surface;
|
||||
|
@ -197,7 +200,7 @@ public:
|
|||
const uint32_t m_hardwareSerialHigh, m_hardwareSerialLow;
|
||||
const uint32_t m_hardwareIdHigh, m_hardwareIdLow;
|
||||
const QVector<TabletToolV2Interface::Capability> m_capabilities;
|
||||
QHash<wl_resource *, TabletCursorV2 *> m_cursors;
|
||||
QHash<wl_resource *, TabletSurfaceCursorV2 *> m_cursors;
|
||||
TabletToolV2Interface *const q;
|
||||
};
|
||||
|
||||
|
@ -220,11 +223,24 @@ TabletToolV2Interface::~TabletToolV2Interface()
|
|||
}
|
||||
}
|
||||
|
||||
TabletToolV2Interface *TabletToolV2Interface::get(wl_resource *resource)
|
||||
{
|
||||
if (TabletToolV2InterfacePrivate *tabletToolPrivate = resource_cast<TabletToolV2InterfacePrivate *>(resource)) {
|
||||
return tabletToolPrivate->q;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TabletToolV2Interface::hasCapability(Capability capability) const
|
||||
{
|
||||
return d->m_capabilities.contains(capability);
|
||||
}
|
||||
|
||||
SurfaceInterface *TabletToolV2Interface::currentSurface() const
|
||||
{
|
||||
return d->m_surface;
|
||||
}
|
||||
|
||||
void TabletToolV2Interface::setCurrentSurface(SurfaceInterface *surface)
|
||||
{
|
||||
if (d->m_surface == surface)
|
||||
|
@ -247,6 +263,11 @@ void TabletToolV2Interface::setCurrentSurface(SurfaceInterface *surface)
|
|||
Q_EMIT cursorChanged(d->m_cursors.value(d->targetResource()));
|
||||
}
|
||||
|
||||
quint32 TabletToolV2Interface::proximitySerial() const
|
||||
{
|
||||
return d->m_proximitySerial;
|
||||
}
|
||||
|
||||
bool TabletToolV2Interface::isClientSupported() const
|
||||
{
|
||||
return d->m_surface && d->targetResource();
|
||||
|
@ -310,7 +331,10 @@ void TabletToolV2Interface::sendWheel(int32_t degrees, int32_t clicks)
|
|||
void TabletToolV2Interface::sendProximityIn(TabletV2Interface *tablet)
|
||||
{
|
||||
wl_resource *tabletResource = tablet->d->resourceForSurface(d->m_surface);
|
||||
d->send_proximity_in(d->targetResource(), d->m_display->nextSerial(), tabletResource, d->m_surface->resource());
|
||||
quint32 serial = d->m_display->nextSerial();
|
||||
|
||||
d->send_proximity_in(d->targetResource(), serial, tabletResource, d->m_surface->resource());
|
||||
d->m_proximitySerial = serial;
|
||||
d->m_lastTablet = tablet;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,14 +11,16 @@
|
|||
#include <QVector>
|
||||
#include <memory>
|
||||
|
||||
struct wl_resource;
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
class ClientConnection;
|
||||
class Display;
|
||||
class SeatInterface;
|
||||
class SurfaceInterface;
|
||||
class TabletCursorV2;
|
||||
class TabletCursorV2Private;
|
||||
class TabletSurfaceCursorV2;
|
||||
class TabletSurfaceCursorV2Private;
|
||||
class TabletManagerV2InterfacePrivate;
|
||||
class TabletSeatV2Interface;
|
||||
class TabletSeatV2InterfacePrivate;
|
||||
|
@ -54,6 +56,26 @@ private:
|
|||
std::unique_ptr<TabletManagerV2InterfacePrivate> d;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT TabletSurfaceCursorV2 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~TabletSurfaceCursorV2() override;
|
||||
QPoint hotspot() const;
|
||||
quint32 enteredSerial() const;
|
||||
SurfaceInterface *surface() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void changed();
|
||||
|
||||
private:
|
||||
TabletSurfaceCursorV2();
|
||||
const std::unique_ptr<TabletSurfaceCursorV2Private> d;
|
||||
friend class TabletToolV2InterfacePrivate;
|
||||
};
|
||||
|
||||
using TabletCursorSourceV2 = std::variant<TabletSurfaceCursorV2 *, QByteArray>;
|
||||
|
||||
class KWIN_EXPORT TabletToolV2Interface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -93,8 +115,12 @@ public:
|
|||
* @see TabletV2Interface::isSurfaceSupported
|
||||
*/
|
||||
void setCurrentSurface(SurfaceInterface *surface);
|
||||
SurfaceInterface *currentSurface() const;
|
||||
|
||||
bool isClientSupported() const;
|
||||
|
||||
quint32 proximitySerial() const;
|
||||
|
||||
void sendProximityIn(TabletV2Interface *tablet);
|
||||
void sendProximityOut();
|
||||
void sendUp();
|
||||
|
@ -109,8 +135,10 @@ public:
|
|||
void sendFrame(quint32 time);
|
||||
void sendMotion(const QPointF &pos);
|
||||
|
||||
static TabletToolV2Interface *get(wl_resource *resource);
|
||||
|
||||
Q_SIGNALS:
|
||||
void cursorChanged(TabletCursorV2 *cursor) const;
|
||||
void cursorChanged(const TabletCursorSourceV2 &cursor);
|
||||
|
||||
private:
|
||||
friend class TabletSeatV2InterfacePrivate;
|
||||
|
@ -125,24 +153,6 @@ private:
|
|||
std::unique_ptr<TabletToolV2InterfacePrivate> d;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT TabletCursorV2 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~TabletCursorV2() override;
|
||||
QPoint hotspot() const;
|
||||
quint32 enteredSerial() const;
|
||||
SurfaceInterface *surface() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void changed();
|
||||
|
||||
private:
|
||||
TabletCursorV2();
|
||||
const std::unique_ptr<TabletCursorV2Private> d;
|
||||
friend class TabletToolV2InterfacePrivate;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT TabletPadV2Interface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "wayland/appmenu_interface.h"
|
||||
#include "wayland/compositor_interface.h"
|
||||
#include "wayland/contenttype_v1_interface.h"
|
||||
#include "wayland/cursorshape_v1_interface.h"
|
||||
#include "wayland/datacontroldevicemanager_v1_interface.h"
|
||||
#include "wayland/datadevicemanager_interface.h"
|
||||
#include "wayland/display.h"
|
||||
|
@ -413,6 +414,7 @@ bool WaylandServer::init(InitializationFlags flags)
|
|||
new RelativePointerManagerV1Interface(m_display, m_display);
|
||||
m_dataDeviceManager = new DataDeviceManagerInterface(m_display, m_display);
|
||||
new DataControlDeviceManagerV1Interface(m_display, m_display);
|
||||
new CursorShapeManagerV1Interface(m_display, m_display);
|
||||
|
||||
const auto kwinConfig = kwinApp()->config();
|
||||
if (kwinConfig->group("Wayland").readEntry("EnablePrimarySelection", true)) {
|
||||
|
|
Loading…
Reference in a new issue