diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,9 @@ # Dependencies set(REQUIRED_QT_VERSION 5.12.0) -find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Concurrent Gui) +find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Concurrent Gui WaylandClient) + +find_package(QtWaylandScanner REQUIRED) find_package(Wayland 1.15 COMPONENTS Client Server) set_package_properties(Wayland PROPERTIES @@ -64,6 +66,8 @@ if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ecm_install_po_files_as_qm(po) endif() + +find_package(QtWaylandScanner REQUIRED) add_subdirectory(src) if (BUILD_TESTING) diff --git a/autotests/server/CMakeLists.txt b/autotests/server/CMakeLists.txt --- a/autotests/server/CMakeLists.txt +++ b/autotests/server/CMakeLists.txt @@ -45,3 +45,15 @@ target_link_libraries( testNoXdgRuntimeDir Qt5::Test KF5::WaylandServer) add_test(NAME kwayland-testNoXdgRuntimeDir COMMAND testNoXdgRuntimeDir) ecm_mark_as_test(testNoXdgRuntimeDir) + +######################################################## +# Test Tablet Interface +######################################################## +ecm_add_qtwayland_client_protocol(TABLET_SRCS + PROTOCOL ${WaylandProtocols_DATADIR}/unstable/tablet/tablet-unstable-v2.xml + BASENAME tablet-unstable-v2 +) +add_executable(testTabletInterface test_tablet_interface.cpp ${TABLET_SRCS}) +target_link_libraries( testTabletInterface Qt5::Test KF5::WaylandServer KF5::WaylandClient Wayland::Client) +add_test(NAME kwayland-testTabletInterface COMMAND testTabletInterface) +ecm_mark_as_test(testTabletInterface) diff --git a/autotests/server/test_tablet_interface.cpp b/autotests/server/test_tablet_interface.cpp new file mode 100644 --- /dev/null +++ b/autotests/server/test_tablet_interface.cpp @@ -0,0 +1,281 @@ +/******************************************************************** +Copyright 2020 Aleix Pol Gonzalez + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +// Qt +#include +#include +#include +// WaylandServer +#include "../../src/server/display.h" +#include "../../src/server/tablet_interface.h" +#include "../../src/server/seat_interface.h" +#include "../../src/server/compositor_interface.h" + +#include "../../src/client/connection_thread.h" +#include "../../src/client/event_queue.h" +#include "../../src/client/registry.h" +#include "../../src/client/compositor.h" +#include "../../src/client/seat.h" + +#include "qwayland-tablet-unstable-v2.h" + +using namespace KWayland::Server; + +class Tablet : public QtWayland::zwp_tablet_v2 +{ +public: + Tablet(::zwp_tablet_v2 *t) : QtWayland::zwp_tablet_v2(t) {} +}; + +class Tool : public QObject, public QtWayland::zwp_tablet_tool_v2 +{ + Q_OBJECT +public: + Tool(::zwp_tablet_tool_v2 *t) : QtWayland::zwp_tablet_tool_v2(t) {} + + void zwp_tablet_tool_v2_proximity_in(uint32_t /*serial*/, struct ::zwp_tablet_v2 * /*tablet*/, struct ::wl_surface * surface) override { + surfaceApproximated[surface]++; + } + + void zwp_tablet_tool_v2_frame(uint32_t time) override { + Q_EMIT frame(time); + } + + QHash surfaceApproximated; +Q_SIGNALS: + void frame(quint32 time); +}; + +class TabletSeat : public QObject, public QtWayland::zwp_tablet_seat_v2 +{ + Q_OBJECT +public: + TabletSeat(::zwp_tablet_seat_v2 *seat) : QtWayland::zwp_tablet_seat_v2(seat) {} + + void zwp_tablet_seat_v2_tablet_added(struct ::zwp_tablet_v2 *id) override { + m_tablets << new Tablet(id); + Q_EMIT tabletAdded(); + } + void zwp_tablet_seat_v2_tool_added(struct ::zwp_tablet_tool_v2 *id) override { + m_tools << new Tool(id); + Q_EMIT toolAdded(); + } + + QVector m_tablets; + QVector m_tools; + +Q_SIGNALS: + void toolAdded(); + void tabletAdded(); +}; + +class TestTabletInterface : public QObject +{ + Q_OBJECT +public: + TestTabletInterface() {} + ~TestTabletInterface() override; + +private Q_SLOTS: + void initTestCase(); + void testAdd(); + void testInteractSimple(); + void testInteractSurfaceChange(); + +private: + KWayland::Client::ConnectionThread* m_connection; + KWayland::Client::EventQueue* m_queue; + KWayland::Client::Compositor* m_clientCompositor; + KWayland::Client::Seat* m_clientSeat = nullptr; + + QThread* m_thread; + Display m_display; + SeatInterface* m_seat; + CompositorInterface* m_serverCompositor; + + TabletSeat *m_tabletSeatClient = nullptr; + TabletManagerInterface* m_tabletManager; + + TabletInterface* m_tablet; + TabletToolInterface* m_tool; + + QVector m_surfaces; +}; + +static const QString s_socketName = QStringLiteral("kwin-wayland-server-tablet-test-0"); + +void TestTabletInterface::initTestCase() +{ + m_display.setSocketName(s_socketName); + m_display.start(); + QVERIFY(m_display.isRunning()); + + m_seat = m_display.createSeat(this); + m_seat->create(); + m_serverCompositor = m_display.createCompositor(this); + m_serverCompositor->create(); + m_tabletManager = m_display.createTabletManagerInterface(this); + QVERIFY(m_serverCompositor->isValid()); + connect(m_serverCompositor, &CompositorInterface::surfaceCreated, this, [this] (SurfaceInterface* surface) { + m_surfaces += surface; + }); + + // setup connection + m_connection = new KWayland::Client::ConnectionThread; + QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + QVERIFY(!m_connection->connections().isEmpty()); + + m_queue = new KWayland::Client::EventQueue(this); + QVERIFY(!m_queue->isValid()); + m_queue->setup(m_connection); + QVERIFY(m_queue->isValid()); + + auto registry = new KWayland::Client::Registry(this); + connect(registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this, registry](const QByteArray &interface, quint32 name, quint32 version){ + if (interface == "zwp_tablet_manager_v2") { + auto tabletClient = new QtWayland::zwp_tablet_manager_v2(registry->registry(), name, version); + auto _seat = tabletClient->get_tablet_seat(*m_clientSeat); + m_tabletSeatClient = new TabletSeat(_seat); + } + }); + connect(registry, &KWayland::Client::Registry::seatAnnounced, this, [this, registry](quint32 name, quint32 version) { + m_clientSeat = registry->createSeat(name, version); + }); + registry->setEventQueue(m_queue); + QSignalSpy compositorSpy(registry, &KWayland::Client::Registry::compositorAnnounced); + registry->create(m_connection->display()); + QVERIFY(registry->isValid()); + registry->setup(); + wl_display_flush(m_connection->display()); + + QVERIFY(compositorSpy.wait()); + m_clientCompositor = registry->createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); + QVERIFY(m_clientCompositor->isValid()); + + QSignalSpy surfaceSpy(m_serverCompositor, &CompositorInterface::surfaceCreated); + for(int i = 0; i<3; ++i) { + m_clientCompositor->createSurface(this); + } + QVERIFY(surfaceSpy.count() < 3 && surfaceSpy.wait(200)); + QVERIFY(m_surfaces.count() == 3); + QVERIFY(m_tabletSeatClient); +} + +TestTabletInterface::~TestTabletInterface() +{ + if (m_queue) { + delete m_queue; + m_queue = nullptr; + } + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + delete m_tabletSeatClient; + m_connection->deleteLater(); + m_connection = nullptr; +} + +void TestTabletInterface::testAdd() +{ + TabletSeatInterface* seatInterface = m_tabletManager->seat(m_seat); + QVERIFY(seatInterface); + + QSignalSpy tabletSpy(m_tabletSeatClient, &TabletSeat::tabletAdded); + m_tablet = seatInterface->addTablet(1, 2, QStringLiteral("event33"), QStringLiteral("my tablet"), {QStringLiteral("/test/event33")}); + QVERIFY(m_tablet); + QVERIFY(tabletSpy.wait() || tabletSpy.count() == 1); + QCOMPARE(m_tabletSeatClient->m_tablets.count(), 1); + + QSignalSpy toolSpy(m_tabletSeatClient, &TabletSeat::toolAdded); + m_tool = seatInterface->addTool(KWayland::Server::TabletToolInterface::Pen, 0,0, {TabletToolInterface::Tilt, TabletToolInterface::Pressure}); + QVERIFY(m_tool); + QVERIFY(toolSpy.wait() || toolSpy.count() == 1); + QCOMPARE(m_tabletSeatClient->m_tools.count(), 1); + + QVERIFY(!m_tool->isClientSupported()); //There's no surface in it yet + m_tool->setCurrentSurface(nullptr); + QVERIFY(!m_tool->isClientSupported()); //There's no surface in it + + QCOMPARE(m_surfaces.count(), 3); + for (SurfaceInterface* surface : m_surfaces) { + m_tool->setCurrentSurface(surface); + } + m_tool->setCurrentSurface(nullptr); +} + +static uint s_serial = 0; +void TestTabletInterface::testInteractSimple() +{ + QSignalSpy frameSpy(m_tabletSeatClient->m_tools[0], &Tool::frame); + + QVERIFY(!m_tool->isClientSupported()); + m_tool->setCurrentSurface(m_surfaces[0]); + QVERIFY(m_tool->isClientSupported() && m_tablet->resourceForSurface(m_surfaces[0])); + m_tool->sendProximityIn(m_tablet); + m_tool->sendPressure(0); + m_tool->sendFrame(s_serial++); + m_tool->sendMotion({3,3}); + m_tool->sendFrame(s_serial++); + m_tool->sendProximityOut(); + QVERIFY(m_tool->isClientSupported()); + m_tool->sendFrame(s_serial++); + QVERIFY(!m_tool->isClientSupported()); + + QVERIFY(frameSpy.wait(500)); + QCOMPARE(m_tabletSeatClient->m_tools[0]->surfaceApproximated.count(), 1); +} + +void TestTabletInterface::testInteractSurfaceChange() +{ + m_tabletSeatClient->m_tools[0]->surfaceApproximated.clear(); + QSignalSpy frameSpy(m_tabletSeatClient->m_tools[0], &Tool::frame); + QVERIFY(!m_tool->isClientSupported()); + m_tool->setCurrentSurface(m_surfaces[0]); + QVERIFY(m_tool->isClientSupported() && m_tablet->resourceForSurface(m_surfaces[0])); + m_tool->sendProximityIn(m_tablet); + m_tool->sendPressure(0); + m_tool->sendFrame(s_serial++); + + m_tool->setCurrentSurface(m_surfaces[1]); + QVERIFY(m_tool->isClientSupported()); + + m_tool->sendMotion({3,3}); + m_tool->sendFrame(s_serial++); + m_tool->sendProximityOut(); + QVERIFY(m_tool->isClientSupported()); + m_tool->sendFrame(s_serial++); + QVERIFY(!m_tool->isClientSupported()); + + QVERIFY(frameSpy.wait(500)); + QCOMPARE(m_tabletSeatClient->m_tools[0]->surfaceApproximated.count(), 2); +} + +QTEST_GUILESS_MAIN(TestTabletInterface) +#include "test_tablet_interface.moc" diff --git a/src/client/buffer.cpp b/src/client/buffer.cpp --- a/src/client/buffer.cpp +++ b/src/client/buffer.cpp @@ -30,7 +30,7 @@ namespace Client { -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_buffer_listener Buffer::Private::s_listener = { Buffer::Private::releasedCallback }; diff --git a/src/client/dataoffer.cpp b/src/client/dataoffer.cpp --- a/src/client/dataoffer.cpp +++ b/src/client/dataoffer.cpp @@ -52,7 +52,7 @@ static const struct wl_data_offer_listener s_listener; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_data_offer_listener DataOffer::Private::s_listener = { offerCallback, sourceActionsCallback, diff --git a/src/client/dpms.cpp b/src/client/dpms.cpp --- a/src/client/dpms.cpp +++ b/src/client/dpms.cpp @@ -131,7 +131,7 @@ }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const org_kde_kwin_dpms_listener Dpms::Private::s_listener = { supportedCallback, modeCallback, diff --git a/src/client/registry.cpp b/src/client/registry.cpp --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -514,7 +514,7 @@ return d->queue; } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_registry_listener Registry::Private::s_registryListener = { globalAnnounce, globalRemove diff --git a/src/client/remote_access.cpp b/src/client/remote_access.cpp --- a/src/client/remote_access.cpp +++ b/src/client/remote_access.cpp @@ -162,7 +162,7 @@ emit p->q->parametersObtained(); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN org_kde_kwin_remote_buffer_listener RemoteBuffer::Private::s_listener = { paramsCallback }; diff --git a/src/client/server_decoration.cpp b/src/client/server_decoration.cpp --- a/src/client/server_decoration.cpp +++ b/src/client/server_decoration.cpp @@ -67,7 +67,7 @@ ServerSideDecoration *q; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const org_kde_kwin_server_decoration_manager_listener ServerSideDecorationManager::Private::s_listener = { defaultModeCallback }; @@ -178,7 +178,7 @@ return deco; } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const org_kde_kwin_server_decoration_listener ServerSideDecoration::Private::s_listener = { modeCallback }; diff --git a/src/client/shadow.cpp b/src/client/shadow.cpp --- a/src/client/shadow.cpp +++ b/src/client/shadow.cpp @@ -166,7 +166,7 @@ org_kde_kwin_shadow_commit(d->shadow); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN #define attach( __PART__, __WAYLAND_PART__ ) \ void Shadow::attach##__PART__(wl_buffer *buffer) \ { \ diff --git a/src/client/shell.cpp b/src/client/shell.cpp --- a/src/client/shell.cpp +++ b/src/client/shell.cpp @@ -234,7 +234,7 @@ d->surface.destroy(); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_shell_surface_listener ShellSurface::Private::s_listener = { pingCallback, configureCallback, diff --git a/src/client/surface.cpp b/src/client/surface.cpp --- a/src/client/surface.cpp +++ b/src/client/surface.cpp @@ -161,7 +161,7 @@ emit q->frameRendered(); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_callback_listener Surface::Private::s_listener = { frameCallback }; diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -50,6 +50,7 @@ subcompositor_interface.cpp surface_interface.cpp surfacerole.cpp + tablet_interface.cpp textinput_interface.cpp textinput_interface_v0.cpp textinput_interface_v2.cpp @@ -221,6 +222,11 @@ BASENAME linux-dmabuf-unstable-v1 ) +ecm_add_qtwayland_server_protocol(SERVER_LIB_SRCS + PROTOCOL ${WaylandProtocols_DATADIR}/unstable/tablet/tablet-unstable-v2.xml + BASENAME tablet-unstable-v2 +) + set(SERVER_GENERATED_SRCS ${CMAKE_CURRENT_BINARY_DIR}/wayland-blur-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-blur-server-protocol.h @@ -278,6 +284,8 @@ ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-server-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-v6-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-v6-server-protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-tablet-unstable-v2.h + ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-tablet-unstable-v2.cpp ) set_source_files_properties(${SERVER_GENERATED_SRCS} PROPERTIES SKIP_AUTOMOC ON) @@ -362,6 +370,7 @@ slide_interface.h subcompositor_interface.h surface_interface.h + tablet_interface.h textinput_interface.h touch_interface.h xdgdecoration_interface.h diff --git a/src/server/appmenu_interface.cpp b/src/server/appmenu_interface.cpp --- a/src/server/appmenu_interface.cpp +++ b/src/server/appmenu_interface.cpp @@ -55,7 +55,7 @@ const quint32 AppMenuManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_appmenu_manager_interface AppMenuManagerInterface::Private::s_interface = { createCallback }; @@ -127,7 +127,7 @@ static const struct org_kde_kwin_appmenu_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_appmenu_interface AppMenuInterface::Private::s_interface = { setAddressCallback, resourceDestroyedCallback diff --git a/src/server/blur_interface.cpp b/src/server/blur_interface.cpp --- a/src/server/blur_interface.cpp +++ b/src/server/blur_interface.cpp @@ -59,7 +59,7 @@ const quint32 BlurManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_blur_manager_interface BlurManagerInterface::Private::s_interface = { createCallback, unsetCallback @@ -155,7 +155,7 @@ static const struct org_kde_kwin_blur_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_blur_interface BlurInterface::Private::s_interface = { commitCallback, setRegionCallback, diff --git a/src/server/compositor_interface.cpp b/src/server/compositor_interface.cpp --- a/src/server/compositor_interface.cpp +++ b/src/server/compositor_interface.cpp @@ -59,7 +59,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_compositor_interface CompositorInterface::Private::s_interface = { createSurfaceCallback, createRegionCallback diff --git a/src/server/contrast_interface.cpp b/src/server/contrast_interface.cpp --- a/src/server/contrast_interface.cpp +++ b/src/server/contrast_interface.cpp @@ -60,7 +60,7 @@ const quint32 ContrastManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_contrast_manager_interface ContrastManagerInterface::Private::s_interface = { createCallback, unsetCallback @@ -165,7 +165,7 @@ static const struct org_kde_kwin_contrast_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_contrast_interface ContrastInterface::Private::s_interface = { commitCallback, setRegionCallback, diff --git a/src/server/datadevice_interface.cpp b/src/server/datadevice_interface.cpp --- a/src/server/datadevice_interface.cpp +++ b/src/server/datadevice_interface.cpp @@ -75,7 +75,7 @@ static const struct wl_data_device_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_data_device_interface DataDeviceInterface::Private::s_interface = { startDragCallback, setSelectionCallback, diff --git a/src/server/datadevicemanager_interface.cpp b/src/server/datadevicemanager_interface.cpp --- a/src/server/datadevicemanager_interface.cpp +++ b/src/server/datadevicemanager_interface.cpp @@ -58,7 +58,7 @@ const qint32 DataDeviceManagerInterface::Private::s_dataDeviceVersion = 3; const qint32 DataDeviceManagerInterface::Private::s_dataSourceVersion = 3; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_data_device_manager_interface DataDeviceManagerInterface::Private::s_interface = { createDataSourceCallback, getDataDeviceCallback diff --git a/src/server/dataoffer_interface.cpp b/src/server/dataoffer_interface.cpp --- a/src/server/dataoffer_interface.cpp +++ b/src/server/dataoffer_interface.cpp @@ -32,7 +32,7 @@ namespace Server { -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_data_offer_interface DataOfferInterface::Private::s_interface = { acceptCallback, receiveCallback, diff --git a/src/server/datasource_interface.cpp b/src/server/datasource_interface.cpp --- a/src/server/datasource_interface.cpp +++ b/src/server/datasource_interface.cpp @@ -54,7 +54,7 @@ const static struct wl_data_source_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_data_source_interface DataSourceInterface::Private::s_interface = { offerCallback, resourceDestroyedCallback, diff --git a/src/server/display.h b/src/server/display.h --- a/src/server/display.h +++ b/src/server/display.h @@ -93,6 +93,7 @@ class EglStreamControllerInterface; class KeyStateInterface; class LinuxDmabufUnstableV1Interface; +class TabletManagerInterface; /** * @brief Class holding the Wayland server display loop. @@ -324,6 +325,8 @@ */ EglStreamControllerInterface *createEglStreamControllerInterface(QObject *parent = nullptr); + TabletManagerInterface* createTabletManagerInterface(QObject* parent = nullptr); + /** * Gets the ClientConnection for the given @p client. * If there is no ClientConnection yet for the given @p client, it will be created. diff --git a/src/server/display.cpp b/src/server/display.cpp --- a/src/server/display.cpp +++ b/src/server/display.cpp @@ -58,6 +58,7 @@ #include "eglstream_controller_interface.h" #include "keystate_interface.h" #include "linuxdmabuf_v1_interface.h" +#include "tablet_interface.h" #include #include @@ -537,6 +538,13 @@ return d; } +TabletManagerInterface *Display::createTabletManagerInterface(QObject* parent) +{ + auto d = new TabletManagerInterface(this, parent); + connect(this, &Display::aboutToTerminate, d, [d] { delete d; }); + return d; +} + void Display::createShm() { Q_ASSERT(d->display); diff --git a/src/server/dpms_interface.cpp b/src/server/dpms_interface.cpp --- a/src/server/dpms_interface.cpp +++ b/src/server/dpms_interface.cpp @@ -28,7 +28,7 @@ const quint32 DpmsManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_dpms_manager_interface DpmsManagerInterface::Private::s_interface = { getDpmsCallback }; @@ -75,7 +75,7 @@ DpmsManagerInterface::~DpmsManagerInterface() = default; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_dpms_interface DpmsInterface::Private::s_interface = { setCallback, resourceDestroyedCallback diff --git a/src/server/eglstream_controller_interface.cpp b/src/server/eglstream_controller_interface.cpp --- a/src/server/eglstream_controller_interface.cpp +++ b/src/server/eglstream_controller_interface.cpp @@ -32,7 +32,7 @@ const quint32 EglStreamControllerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_eglstream_controller_interface EglStreamControllerInterface::Private::s_interface = { attachStreamConsumer, attachStreamConsumerAttribs diff --git a/src/server/fakeinput_interface.cpp b/src/server/fakeinput_interface.cpp --- a/src/server/fakeinput_interface.cpp +++ b/src/server/fakeinput_interface.cpp @@ -79,7 +79,7 @@ const quint32 FakeInputInterface::Private::s_version = 4; QList FakeInputInterface::Private::touchIds = QList(); -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_fake_input_interface FakeInputInterface::Private::s_interface = { authenticateCallback, pointerMotionCallback, diff --git a/src/server/idle_interface.cpp b/src/server/idle_interface.cpp --- a/src/server/idle_interface.cpp +++ b/src/server/idle_interface.cpp @@ -78,7 +78,7 @@ const quint32 IdleInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_idle_interface IdleInterface::Private::s_interface = { getIdleTimeoutCallback }; @@ -170,7 +170,7 @@ return reinterpret_cast(d.data()); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_idle_timeout_interface IdleTimeoutInterface::Private::s_interface = { resourceDestroyedCallback, simulateUserActivityCallback diff --git a/src/server/idleinhibit_interface_v1.cpp b/src/server/idleinhibit_interface_v1.cpp --- a/src/server/idleinhibit_interface_v1.cpp +++ b/src/server/idleinhibit_interface_v1.cpp @@ -48,7 +48,7 @@ const quint32 IdleInhibitManagerUnstableV1Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_idle_inhibit_manager_v1_interface IdleInhibitManagerUnstableV1Interface::Private::s_interface = { destroyCallback, createInhibitorCallback @@ -104,7 +104,7 @@ IdleInhibitManagerUnstableV1Interface::~IdleInhibitManagerUnstableV1Interface() = default; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_idle_inhibitor_v1_interface IdleInhibitorInterface::Private::s_interface = { resourceDestroyedCallback }; diff --git a/src/server/keyboard_interface.cpp b/src/server/keyboard_interface.cpp --- a/src/server/keyboard_interface.cpp +++ b/src/server/keyboard_interface.cpp @@ -71,7 +71,7 @@ sendModifiers(); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_keyboard_interface KeyboardInterface::Private::s_interface { resourceDestroyedCallback }; diff --git a/src/server/linuxdmabuf_v1_interface.cpp b/src/server/linuxdmabuf_v1_interface.cpp --- a/src/server/linuxdmabuf_v1_interface.cpp +++ b/src/server/linuxdmabuf_v1_interface.cpp @@ -174,7 +174,7 @@ params->create(client, new_id, QSize(width, height), format, flags); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_linux_dmabuf_v1_interface V1Iface::Private::s_implementation = { [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); }, // unbind createParamsCallback @@ -184,7 +184,7 @@ [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); } // destroy }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_linux_buffer_params_v1_interface V1Iface::Private::Params::s_interface = { destroy, add, diff --git a/src/server/output_interface.cpp b/src/server/output_interface.cpp --- a/src/server/output_interface.cpp +++ b/src/server/output_interface.cpp @@ -91,7 +91,7 @@ s_privates.removeAll(this); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_output_interface OutputInterface::Private::s_interface = { releaseCallback }; diff --git a/src/server/plasmashell_interface.cpp b/src/server/plasmashell_interface.cpp --- a/src/server/plasmashell_interface.cpp +++ b/src/server/plasmashell_interface.cpp @@ -58,7 +58,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_plasma_shell_interface PlasmaShellInterface::Private::s_interface = { createSurfaceCallback }; @@ -157,7 +157,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_plasma_surface_interface PlasmaShellSurfaceInterface::Private::s_interface = { resourceDestroyedCallback, setOutputCallback, diff --git a/src/server/plasmavirtualdesktop_interface.cpp b/src/server/plasmavirtualdesktop_interface.cpp --- a/src/server/plasmavirtualdesktop_interface.cpp +++ b/src/server/plasmavirtualdesktop_interface.cpp @@ -93,7 +93,7 @@ const quint32 PlasmaVirtualDesktopManagementInterface::Private::s_version = 2; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_plasma_virtual_desktop_management_interface PlasmaVirtualDesktopManagementInterface::Private::s_interface = { getVirtualDesktopCallback, requestCreateVirtualDesktopCallback, @@ -289,7 +289,7 @@ //// PlasmaVirtualDesktopInterface -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_plasma_virtual_desktop_interface PlasmaVirtualDesktopInterface::Private::s_interface = { requestActivateCallback }; diff --git a/src/server/plasmawindowmanagement_interface.cpp b/src/server/plasmawindowmanagement_interface.cpp --- a/src/server/plasmawindowmanagement_interface.cpp +++ b/src/server/plasmawindowmanagement_interface.cpp @@ -133,7 +133,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_plasma_window_management_interface PlasmaWindowManagementInterface::Private::s_interface = { showDesktopCallback, getWindowCallback @@ -293,7 +293,7 @@ return d->plasmaVirtualDesktopManagementInterface; } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_plasma_window_interface PlasmaWindowInterface::Private::s_interface = { setStateCallback, setVirtualDesktopCallback, diff --git a/src/server/pointer_interface.cpp b/src/server/pointer_interface.cpp --- a/src/server/pointer_interface.cpp +++ b/src/server/pointer_interface.cpp @@ -220,7 +220,7 @@ wl_pointer_send_frame(resource); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_pointer_interface PointerInterface::Private::s_interface = { setCursorCallback, resourceDestroyedCallback diff --git a/src/server/pointerconstraints_interface_v1.cpp b/src/server/pointerconstraints_interface_v1.cpp --- a/src/server/pointerconstraints_interface_v1.cpp +++ b/src/server/pointerconstraints_interface_v1.cpp @@ -76,7 +76,7 @@ const quint32 PointerConstraintsUnstableV1Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_pointer_constraints_v1_interface PointerConstraintsUnstableV1Interface::Private::s_interface = { destroyCallback, lockPointerCallback, @@ -160,7 +160,7 @@ PointerConstraintsUnstableV1Interface::~PointerConstraintsUnstableV1Interface() = default; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_locked_pointer_v1_interface LockedPointerUnstableV1Interface::Private::s_interface = { resourceDestroyedCallback, setCursorPositionHintCallback, @@ -234,7 +234,7 @@ static const struct zwp_confined_pointer_v1_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_confined_pointer_v1_interface ConfinedPointerUnstableV1Interface::Private::s_interface = { resourceDestroyedCallback, setRegionCallback diff --git a/src/server/pointergestures_interface_v1.cpp b/src/server/pointergestures_interface_v1.cpp --- a/src/server/pointergestures_interface_v1.cpp +++ b/src/server/pointergestures_interface_v1.cpp @@ -54,7 +54,7 @@ const quint32 PointerGesturesUnstableV1Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_pointer_gestures_v1_interface PointerGesturesUnstableV1Interface::Private::s_interface = { getSwipeGestureCallback, getPinchGestureCallback @@ -135,7 +135,7 @@ static const struct zwp_pointer_gesture_swipe_v1_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_pointer_gesture_swipe_v1_interface PointerSwipeGestureUnstableV1Interface::Private::s_interface = { resourceDestroyedCallback }; @@ -222,7 +222,7 @@ static const struct zwp_pointer_gesture_pinch_v1_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_pointer_gesture_pinch_v1_interface PointerPinchGestureUnstableV1Interface::Private::s_interface = { resourceDestroyedCallback }; diff --git a/src/server/qtsurfaceextension_interface.cpp b/src/server/qtsurfaceextension_interface.cpp --- a/src/server/qtsurfaceextension_interface.cpp +++ b/src/server/qtsurfaceextension_interface.cpp @@ -59,7 +59,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct qt_surface_extension_interface QtSurfaceExtensionInterface::Private::s_interface = { createSurfaceCallback }; @@ -143,7 +143,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct qt_extended_surface_interface QtExtendedSurfaceInterface::Private::s_interface = { updateGenericPropertyCallback, setContentOrientationMaskCallback, diff --git a/src/server/region_interface.cpp b/src/server/region_interface.cpp --- a/src/server/region_interface.cpp +++ b/src/server/region_interface.cpp @@ -48,7 +48,7 @@ static const struct wl_region_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_region_interface RegionInterface::Private::s_interface = { resourceDestroyedCallback, addCallback, diff --git a/src/server/relativepointer_interface_v1.cpp b/src/server/relativepointer_interface_v1.cpp --- a/src/server/relativepointer_interface_v1.cpp +++ b/src/server/relativepointer_interface_v1.cpp @@ -52,7 +52,7 @@ const quint32 RelativePointerManagerUnstableV1Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_relative_pointer_manager_v1_interface RelativePointerManagerUnstableV1Interface::Private::s_interface = { destroyCallback, getRelativePointerCallback @@ -124,7 +124,7 @@ static const struct zwp_relative_pointer_v1_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_relative_pointer_v1_interface RelativePointerUnstableV1Interface::Private::s_interface = { resourceDestroyedCallback }; diff --git a/src/server/remote_access_interface.cpp b/src/server/remote_access_interface.cpp --- a/src/server/remote_access_interface.cpp +++ b/src/server/remote_access_interface.cpp @@ -220,7 +220,7 @@ sentBuffers[buf->fd()] = holder; } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_remote_access_manager_interface RemoteAccessManagerInterface::Private::s_interface = { getBufferCallback, releaseCallback @@ -344,7 +344,7 @@ const BufferHandle *wrapped; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_remote_buffer_interface RemoteBufferInterface::Private::s_interface = { resourceDestroyedCallback }; diff --git a/src/server/seat_interface.cpp b/src/server/seat_interface.cpp --- a/src/server/seat_interface.cpp +++ b/src/server/seat_interface.cpp @@ -57,7 +57,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_seat_interface SeatInterface::Private::s_interface = { getPointerCallback, getKeyboardCallback, diff --git a/src/server/server_decoration_interface.cpp b/src/server/server_decoration_interface.cpp --- a/src/server/server_decoration_interface.cpp +++ b/src/server/server_decoration_interface.cpp @@ -60,7 +60,7 @@ const quint32 ServerSideDecorationManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_server_decoration_manager_interface ServerSideDecorationManagerInterface::Private::s_interface = { createCallback }; @@ -185,7 +185,7 @@ static QVector s_all; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_server_decoration_interface ServerSideDecorationInterface::Private::s_interface = { resourceDestroyedCallback, requestModeCallback diff --git a/src/server/server_decoration_palette_interface.cpp b/src/server/server_decoration_palette_interface.cpp --- a/src/server/server_decoration_palette_interface.cpp +++ b/src/server/server_decoration_palette_interface.cpp @@ -55,7 +55,7 @@ const quint32 ServerSideDecorationPaletteManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_server_decoration_palette_manager_interface ServerSideDecorationPaletteManagerInterface::Private::s_interface = { createCallback }; @@ -127,7 +127,7 @@ static const struct org_kde_kwin_server_decoration_palette_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_server_decoration_palette_interface ServerSideDecorationPaletteInterface::Private::s_interface = { setPaletteCallback, resourceDestroyedCallback diff --git a/src/server/shadow_interface.cpp b/src/server/shadow_interface.cpp --- a/src/server/shadow_interface.cpp +++ b/src/server/shadow_interface.cpp @@ -56,7 +56,7 @@ const quint32 ShadowManagerInterface::Private::s_version = 2; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_shadow_manager_interface ShadowManagerInterface::Private::s_interface = { createCallback, unsetCallback, @@ -191,7 +191,7 @@ static const struct org_kde_kwin_shadow_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_shadow_interface ShadowInterface::Private::s_interface = { commitCallback, attachLeftCallback, diff --git a/src/server/shell_interface.cpp b/src/server/shell_interface.cpp --- a/src/server/shell_interface.cpp +++ b/src/server/shell_interface.cpp @@ -58,7 +58,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_shell_interface ShellInterface::Private::s_interface = { createSurfaceCallback }; @@ -167,7 +167,7 @@ pingTimer->setInterval(1000); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_shell_surface_interface ShellSurfaceInterface::Private::s_interface = { pongCallback, moveCallback, diff --git a/src/server/slide_interface.cpp b/src/server/slide_interface.cpp --- a/src/server/slide_interface.cpp +++ b/src/server/slide_interface.cpp @@ -57,7 +57,7 @@ const quint32 SlideManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_slide_manager_interface SlideManagerInterface::Private::s_interface = { createCallback, unsetCallback @@ -148,7 +148,7 @@ static const struct org_kde_kwin_slide_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct org_kde_kwin_slide_interface SlideInterface::Private::s_interface = { commitCallback, setLocationCallback, diff --git a/src/server/subcompositor_interface.cpp b/src/server/subcompositor_interface.cpp --- a/src/server/subcompositor_interface.cpp +++ b/src/server/subcompositor_interface.cpp @@ -54,7 +54,7 @@ const quint32 SubCompositorInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_subcompositor_interface SubCompositorInterface::Private::s_interface = { destroyCallback, subsurfaceCallback @@ -127,7 +127,7 @@ SubCompositorInterface::~SubCompositorInterface() = default; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_subsurface_interface SubSurfaceInterface::Private::s_interface = { resourceDestroyedCallback, setPositionCallback, diff --git a/src/server/surface_interface.cpp b/src/server/surface_interface.cpp --- a/src/server/surface_interface.cpp +++ b/src/server/surface_interface.cpp @@ -265,7 +265,7 @@ } } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_surface_interface SurfaceInterface::Private::s_interface = { resourceDestroyedCallback, attachCallback, diff --git a/src/server/tablet_interface.h b/src/server/tablet_interface.h new file mode 100644 --- /dev/null +++ b/src/server/tablet_interface.h @@ -0,0 +1,155 @@ +/******************************************************************** +Copyright 2019 Aleix Pol Gonzalez + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#ifndef WAYLAND_SERVER_TABLET_INTERFACE_H +#define WAYLAND_SERVER_TABLET_INTERFACE_H + +#include +#include + +#include "resource.h" + +namespace KWayland +{ +namespace Server +{ + +class TabletSeatInterface; +class Display; +class SeatInterface; +class SurfaceInterface; +class TabletInterface; + +/** + * This is an implementation of wayland-protocols/unstable/tablet/tablet-unstable-v2.xml + * + * This class is just the means to get a @class TabletSeatInterface, which is + * the class that will have all of the information we need. + */ + +class KWAYLANDSERVER_EXPORT TabletManagerInterface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletManagerInterface(); + + TabletSeatInterface* seat(SeatInterface* seat) const; + +private: + friend class Display; + explicit TabletManagerInterface(Display *d, QObject *parent); + class Private; + QScopedPointer d; +}; + +class KWAYLANDSERVER_EXPORT TabletToolInterface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletToolInterface(); + + enum Type { + Pen = 0x140, ///< Pen + Eraser = 0x141, ///< Eraser + Brush = 0x142, ///< Brush + Pencil = 0x143, ///< Pencil + Airbrush = 0x144, ///< Airbrush + Finger = 0x145, ///< Finger + Mouse = 0x146, ///< Mouse + Lens = 0x147, ///< Lens + Totem + }; + Q_ENUM(Type) + + enum Capability { + Tilt = 1, ///< Tilt axeis + Pressure = 2, ///< Pressure axis + Distance = 3, ///< Distance axis + Rotation = 4, ///< Z-rotation axis + Slider = 5, ///< Slider axis + Wheel = 6 ///< Wheel axis + }; + Q_ENUM(Capability) + + void setCurrentSurface(SurfaceInterface *surface); + bool isClientSupported() const; + + void sendRemoved(); + void sendProximityIn(TabletInterface *tablet); + void sendProximityOut(); + void sendUp(); + void sendDown(); + void sendPressure(quint32 pressure); + void sendDistance(quint32 distance); + void sendTilt(qreal degreesX, qreal degreesY); + void sendRotation(qreal degrees); + void sendSlider(qint32 position); + void sendWheel(qint32 degrees, qint32 clicks); + void sendButton(quint32 button, bool pressed); + void sendFrame(quint32 time); + void sendMotion(const QPointF &pos); + +private: + friend class TabletSeatInterface; + explicit TabletToolInterface(Display* display, Type type, quint32 hsh, quint32 hsl, quint32 hih, quint32 hil, const QVector &capability, QObject *parent); + class Private; + QScopedPointer d; +}; + +class KWAYLANDSERVER_EXPORT TabletInterface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletInterface(); + + wl_resource* resourceForSurface(SurfaceInterface* surface); + +private: + friend class TabletSeatInterface; + friend class TabletToolInterface; + explicit TabletInterface(quint32 vendorId, quint32 productId, const QString &name, const QStringList &paths, QObject* parent); + class Private; + QScopedPointer d; +}; + +class KWAYLANDSERVER_EXPORT TabletSeatInterface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletSeatInterface(); + + TabletInterface* addTablet(quint32 vendorId, quint32 productId, const QString &sysname, const QString &name, const QStringList &paths); + TabletToolInterface* addTool(TabletToolInterface::Type type, quint64 hardwareSerial, quint64 hardwareId, const QVector &capabilities); + + TabletToolInterface* toolByHardwareId(quint64 hardwareId) const; + TabletInterface* tabletByName(const QString &name) const; + +private: + friend class TabletManagerInterface; + explicit TabletSeatInterface(Display* display, QObject* parent); + class Private; + QScopedPointer d; +}; + +} +} + +Q_DECLARE_METATYPE(KWayland::Server::TabletSeatInterface*) + +#endif diff --git a/src/server/tablet_interface.cpp b/src/server/tablet_interface.cpp new file mode 100644 --- /dev/null +++ b/src/server/tablet_interface.cpp @@ -0,0 +1,381 @@ +/******************************************************************** +Copyright 2019 Aleix Pol Gonzalez + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#include "tablet_interface.h" +#include "resource_p.h" +#include "seat_interface.h" +#include "display.h" +#include "surface_interface.h" + +#include +#include "qwayland-server-tablet-unstable-v2.h" + +using namespace KWayland; +using namespace Server; + +static int s_version = 1; + +class TabletInterface::Private : public QtWaylandServer::zwp_tablet_v2 +{ +public: + Private(uint32_t vendorId, uint32_t productId, const QString name, const QStringList &paths) + : zwp_tablet_v2() + , m_vendorId(vendorId) + , m_productId(productId) + , m_name(name) + , m_paths(paths) + {} + + const uint32_t m_vendorId; + const uint32_t m_productId; + const QString m_name; + const QStringList m_paths; +}; + +TabletInterface::TabletInterface(uint32_t vendorId, uint32_t productId, + const QString &name, const QStringList &paths, + QObject* parent) + : QObject(parent) + , d(new Private(vendorId, productId, name, paths)) +{ +} + +TabletInterface::~TabletInterface() = default; + +wl_resource * TabletInterface::resourceForSurface(SurfaceInterface* surface) +{ + auto *client = surface->client(); + const auto r = d->resourceMap().value(*client); + return r ? r->handle : nullptr; +} + +class TabletToolInterface::Private : public QtWaylandServer::zwp_tablet_tool_v2 +{ +public: + Private(Display* display, Type type, uint32_t hsh, uint32_t hsl, uint32_t hih, + uint32_t hil, const QVector& capabilities) + : zwp_tablet_tool_v2() + , m_display(display) + , m_type(type) + , m_hardwareSerialHigh(hsh) + , m_hardwareSerialLow(hsl) + , m_hardwareIdHigh(hih) + , m_hardwareIdLow(hil) + , m_capabilities(capabilities) + {} + + Display* const m_display; + + wl_resource* targetResource() { + auto *client = m_surface->client(); + const auto r = resourceMap().value(*client); + return r ? r->handle : nullptr; + } + + quint64 hardwareSerial() const { + return quint64(quint64(m_hardwareIdHigh) << 32) + m_hardwareIdLow; + } + + bool m_cleanup = false; + QPointer m_surface; + QPointer m_lastTablet; + const uint32_t m_type; + const uint32_t m_hardwareSerialHigh, m_hardwareSerialLow; + const uint32_t m_hardwareIdHigh, m_hardwareIdLow; + const QVector m_capabilities; +}; + +TabletToolInterface::TabletToolInterface(Display* display, Type type, uint32_t hsh, + uint32_t hsl, uint32_t hih, uint32_t hil, + const QVector& capabilities, + QObject *parent) + : QObject(parent) + , d(new Private(display, type, hsh, hsl, hih, hil, capabilities)) +{} + +TabletToolInterface::~TabletToolInterface() = default; + +void TabletToolInterface::setCurrentSurface(SurfaceInterface* surface) +{ + if (d->m_surface == surface) + return; + + const auto lastTablet = d->m_lastTablet; + if (d->m_surface && d->resourceMap().contains(*d->m_surface->client())) { + sendProximityOut(); + sendFrame(0); + } + + d->m_surface = surface; + + if (lastTablet && lastTablet->resourceForSurface(surface)) { + sendProximityIn(lastTablet); + } else { + d->m_lastTablet = lastTablet; + } +} + +bool TabletToolInterface::isClientSupported() const +{ + return d->m_surface && d->targetResource(); +} + +void TabletToolInterface::sendButton(uint32_t button, bool pressed) +{ + d->send_button(d->targetResource(), d->m_display->nextSerial(), button, + pressed ? QtWaylandServer::zwp_tablet_tool_v2::button_state_pressed + : QtWaylandServer::zwp_tablet_tool_v2::button_state_released); +} + +void TabletToolInterface::sendMotion(const QPointF& pos) +{ + d->send_motion(d->targetResource(), wl_fixed_from_double(pos.x()), + wl_fixed_from_double(pos.y())); +} + +void TabletToolInterface::sendDistance(uint32_t distance) +{ + d->send_distance(d->targetResource(), distance); +} + +void TabletToolInterface::sendFrame(uint32_t time) +{ + d->send_frame(d->targetResource(), time); + + if (d->m_cleanup) { + d->m_surface = nullptr; + d->m_lastTablet = nullptr; + d->m_cleanup = false; + } +} + +void TabletToolInterface::sendPressure(uint32_t pressure) +{ + d->send_pressure(d->targetResource(), pressure); +} + +void TabletToolInterface::sendRotation(qreal rotation) +{ + d->send_rotation(d->targetResource(), wl_fixed_from_double(rotation)); +} + +void TabletToolInterface::sendSlider(int32_t position) +{ + d->send_slider(d->targetResource(), position); +} + +void TabletToolInterface::sendTilt(qreal degreesX, qreal degreesY) +{ + d->send_tilt(d->targetResource(), wl_fixed_from_double(degreesX), + wl_fixed_from_double(degreesY)); +} + +void TabletToolInterface::sendWheel(int32_t degrees, int32_t clicks) +{ + d->send_wheel(d->targetResource(), degrees, clicks); +} + +void TabletToolInterface::sendProximityIn(TabletInterface* tablet) +{ + auto tabletResource = tablet->resourceForSurface(d->m_surface); + d->send_proximity_in(d->targetResource(), d->m_display->nextSerial(), + tabletResource, d->m_surface->resource()); + d->m_lastTablet = tablet; +} + +void TabletToolInterface::sendProximityOut() +{ + d->send_proximity_out(d->targetResource()); + d->m_cleanup = true; +} + +void TabletToolInterface::sendDown() +{ + d->send_down(d->targetResource(), d->m_display->nextSerial()); +} + +void TabletToolInterface::sendUp() +{ + d->send_up(d->targetResource()); +} + +void TabletToolInterface::sendRemoved() +{ + for (auto *resource : d->resourceMap()) { + d->send_removed(resource->handle); + } +} + +class TabletSeatInterface::Private : public QtWaylandServer::zwp_tablet_seat_v2 +{ +public: + Private(Display* display, TabletSeatInterface* q) + : zwp_tablet_seat_v2() + , q(q) + , m_display(display) + { + } + + void zwp_tablet_seat_v2_bind_resource(Resource *resource) override { + for (auto iface : qAsConst(m_tablets)) + sendTabletAdded(resource, iface); + + for (auto *tool : qAsConst(m_tools)) + sendToolAdded(resource, tool); + +// for (auto r : qAsConst(m_pads)) +// send_pad_added(resource->handle, r->resource()); + } + + void sendToolAdded(Resource* resource, TabletToolInterface* tool) { + auto *toolResource = tool->d->add(resource->client(), resource->version())->handle; + send_tool_added(resource->handle, toolResource); + + tool->d->send_type(toolResource, tool->d->m_type); + tool->d->send_hardware_serial(toolResource, tool->d->m_hardwareSerialHigh, + tool->d->m_hardwareSerialLow); + tool->d->send_hardware_id_wacom(toolResource, tool->d->m_hardwareIdHigh, + tool->d->m_hardwareIdLow); + for (uint32_t cap : qAsConst(tool->d->m_capabilities)) { + tool->d->send_capability(toolResource, cap); + } + tool->d->send_done(toolResource); + } + void sendTabletAdded(Resource* resource, TabletInterface* tablet) { + auto *tabletResource = tablet->d->add(resource->client(), resource->version())->handle; + send_tablet_added(resource->handle, tabletResource); + + tablet->d->send_name(tabletResource, tablet->d->m_name); + if (tablet->d->m_vendorId && tablet->d->m_productId) { + tablet->d->send_id(tabletResource, tablet->d->m_vendorId, tablet->d->m_productId); + } + for (const auto &path : qAsConst(tablet->d->m_paths)) { + tablet->d->send_path(tabletResource, path); + } + tablet->d->send_done(tabletResource); + } + + TabletSeatInterface* const q; + QVector m_tools; + QHash m_tablets; + Display* const m_display; +}; + +TabletSeatInterface::TabletSeatInterface(Display* display, QObject* parent) + : QObject(parent) + , d(new Private(display, this)) +{ +} + +TabletSeatInterface::~TabletSeatInterface() = default; + +TabletToolInterface* TabletSeatInterface::addTool(TabletToolInterface::Type type, + quint64 hardwareSerial, + quint64 hardwareId, + const QVector &capabilities) +{ + constexpr auto MAX_UINT_32 = std::numeric_limits::max(); + auto tool = new TabletToolInterface(d->m_display, + type, hardwareSerial >> 32, hardwareSerial & MAX_UINT_32, + hardwareId >> 32, hardwareId & MAX_UINT_32, capabilities, this); + for (auto *resource : d->resourceMap()) { + d->sendToolAdded(resource, tool); + } + + d->m_tools.append(tool); + QObject::connect(tool, &QObject::destroyed, this, + [this] (QObject* object) { d->m_tools.removeAll(static_cast(object)); } + ); + return tool; +} + +TabletInterface* TabletSeatInterface::addTablet(uint32_t vendorId, uint32_t productId, + const QString &sysname, + const QString &name, + const QStringList &paths) +{ + auto iface = new TabletInterface(vendorId, productId, name, paths, this); + + for (auto r : d->resourceMap()) { + d->sendTabletAdded(r, iface); + } + + d->m_tablets[sysname] = iface; + QObject::connect(iface, &QObject::destroyed, this, + [this, sysname] { d->m_tablets.remove(sysname); } + ); + return iface; +} + +TabletToolInterface * TabletSeatInterface::toolByHardwareId(quint64 serialId) const +{ + for (auto tool : d->m_tools) { + if (tool->d->hardwareSerial() == serialId) + return tool; + } + return nullptr; +} + +TabletInterface * TabletSeatInterface::tabletByName(const QString& name) const +{ + return d->m_tablets.value(name); +} + +class TabletManagerInterface::Private : public QtWaylandServer::zwp_tablet_manager_v2 +{ +public: + Private(Display *display, TabletManagerInterface* q) + : zwp_tablet_manager_v2(*display, s_version) + , q(q) + , m_display(display) + {} + + void zwp_tablet_manager_v2_get_tablet_seat(Resource * resource, uint32_t tablet_seat, + struct ::wl_resource * seat_resource) override { + auto seat = SeatInterface::get(seat_resource); + TabletSeatInterface* tsi = get(seat); + tsi->d->add(resource->client(), tablet_seat, s_version); + } + + TabletSeatInterface* get(SeatInterface* seat) + { + auto& tabletSeat = m_seats[seat]; + if (!tabletSeat) { + tabletSeat = new TabletSeatInterface(m_display, q); + } + return tabletSeat; + } + + TabletManagerInterface* const q; + Display* const m_display; + QHash m_seats; +}; + +TabletManagerInterface::TabletManagerInterface(Display *display, QObject *parent) + : QObject(parent) + , d(new Private(display, this)) +{ +} + +TabletSeatInterface* TabletManagerInterface::seat(SeatInterface* seat) const +{ + return d->get(seat); +} + +TabletManagerInterface::~TabletManagerInterface() = default; diff --git a/src/server/textinput_interface_v0.cpp b/src/server/textinput_interface_v0.cpp --- a/src/server/textinput_interface_v0.cpp +++ b/src/server/textinput_interface_v0.cpp @@ -75,7 +75,7 @@ quint32 latestState = 0; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_text_input_interface TextInputUnstableV0Interface::Private::s_interface = { activateCallback, deactivateCallback, @@ -373,7 +373,7 @@ }; const quint32 TextInputManagerUnstableV0Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_text_input_manager_interface TextInputManagerUnstableV0Interface::Private::s_interface = { createTextInputCallback }; diff --git a/src/server/textinput_interface_v2.cpp b/src/server/textinput_interface_v2.cpp --- a/src/server/textinput_interface_v2.cpp +++ b/src/server/textinput_interface_v2.cpp @@ -70,7 +70,7 @@ void disable(); }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_text_input_v2_interface TextInputUnstableV2Interface::Private::s_interface = { resourceDestroyedCallback, enableCallback, @@ -349,7 +349,7 @@ }; const quint32 TextInputManagerUnstableV2Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zwp_text_input_manager_v2_interface TextInputManagerUnstableV2Interface::Private::s_interface = { destroyCallback, getTextInputCallback diff --git a/src/server/touch_interface.cpp b/src/server/touch_interface.cpp --- a/src/server/touch_interface.cpp +++ b/src/server/touch_interface.cpp @@ -47,7 +47,7 @@ static const struct wl_touch_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct wl_touch_interface TouchInterface::Private::s_interface = { resourceDestroyedCallback }; diff --git a/src/server/xdgdecoration_interface.cpp b/src/server/xdgdecoration_interface.cpp --- a/src/server/xdgdecoration_interface.cpp +++ b/src/server/xdgdecoration_interface.cpp @@ -68,7 +68,7 @@ XdgDecorationManagerInterface::~XdgDecorationManagerInterface() {} -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_decoration_manager_v1_interface XdgDecorationManagerInterface::Private::s_interface = { destroyCallback, getToplevelDecorationCallback @@ -153,7 +153,7 @@ static const struct zxdg_toplevel_decoration_v1_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_toplevel_decoration_v1_interface XdgDecorationInterface::Private::s_interface = { resourceDestroyedCallback, setModeCallback, diff --git a/src/server/xdgforeign_v2_interface.cpp b/src/server/xdgforeign_v2_interface.cpp --- a/src/server/xdgforeign_v2_interface.cpp +++ b/src/server/xdgforeign_v2_interface.cpp @@ -61,7 +61,7 @@ const quint32 XdgExporterUnstableV2Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_exporter_v2_interface XdgExporterUnstableV2Interface::Private::s_interface = { destroyCallback, exportCallback @@ -192,7 +192,7 @@ const quint32 XdgImporterUnstableV2Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_importer_v2_interface XdgImporterUnstableV2Interface::Private::s_interface = { destroyCallback, importCallback @@ -367,7 +367,7 @@ static const struct zxdg_exported_v2_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_exported_v2_interface XdgExportedUnstableV2Interface::Private::s_interface = { resourceDestroyedCallback }; @@ -412,7 +412,7 @@ static const struct zxdg_imported_v2_interface s_interface; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_imported_v2_interface XdgImportedUnstableV2Interface::Private::s_interface = { resourceDestroyedCallback, setParentOfCallback diff --git a/src/server/xdgoutput_interface.cpp b/src/server/xdgoutput_interface.cpp --- a/src/server/xdgoutput_interface.cpp +++ b/src/server/xdgoutput_interface.cpp @@ -56,7 +56,7 @@ const quint32 XdgOutputManagerInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_output_manager_v1_interface XdgOutputManagerInterface::Private::s_interface = { destroyCallback, getXdgOutputCallback @@ -292,7 +292,7 @@ zxdg_output_v1_send_done(d->resource); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_output_v1_interface XdgOutputV1Interface::Private::s_interface = { resourceDestroyedCallback }; diff --git a/src/server/xdgshell_stable_interface.cpp b/src/server/xdgshell_stable_interface.cpp --- a/src/server/xdgshell_stable_interface.cpp +++ b/src/server/xdgshell_stable_interface.cpp @@ -245,7 +245,7 @@ const quint32 XdgShellStableInterface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct xdg_wm_base_interface XdgShellStableInterface::Private::s_interface = { destroyCallback, createPositionerCallback, @@ -457,7 +457,7 @@ } } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct xdg_surface_interface XdgSurfaceStableInterface::Private::s_interface = { destroyCallback, getTopLevelCallback, @@ -611,7 +611,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct xdg_positioner_interface XdgPositionerStableInterface::Private::s_interface = { resourceDestroyedCallback, setSizeCallback, @@ -929,7 +929,7 @@ XdgTopLevelStableInterface::Private::~Private() = default; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct xdg_popup_interface XdgPopupStableInterface::Private::s_interface = { resourceDestroyedCallback, grabCallback diff --git a/src/server/xdgshell_v5_interface.cpp b/src/server/xdgshell_v5_interface.cpp --- a/src/server/xdgshell_v5_interface.cpp +++ b/src/server/xdgshell_v5_interface.cpp @@ -87,7 +87,7 @@ const quint32 XdgShellV5Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_shell_v5_interface XdgShellV5Interface::Private::s_interface = { destroyCallback, useUnstableVersionCallback, @@ -321,7 +321,7 @@ } } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_surface_v5_interface XdgSurfaceV5Interface::Private::s_interface = { resourceDestroyedCallback, setParentCallback, @@ -501,7 +501,7 @@ return serial; } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_popup_v5_interface XdgPopupV5Interface::Private::s_interface = { resourceDestroyedCallback }; diff --git a/src/server/xdgshell_v6_interface.cpp b/src/server/xdgshell_v6_interface.cpp --- a/src/server/xdgshell_v6_interface.cpp +++ b/src/server/xdgshell_v6_interface.cpp @@ -247,7 +247,7 @@ const quint32 XdgShellV6Interface::Private::s_version = 1; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_shell_v6_interface XdgShellV6Interface::Private::s_interface = { destroyCallback, createPositionerCallback, @@ -456,7 +456,7 @@ } } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_surface_v6_interface XdgSurfaceV6Interface::Private::s_interface = { destroyCallback, getTopLevelCallback, @@ -613,7 +613,7 @@ { } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_positioner_v6_interface XdgPositionerV6Interface::Private::s_interface = { resourceDestroyedCallback, setSizeCallback, @@ -914,7 +914,7 @@ XdgTopLevelV6Interface::Private::~Private() = default; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef K_DOXYGEN const struct zxdg_popup_v6_interface XdgPopupV6Interface::Private::s_interface = { resourceDestroyedCallback, grabCallback diff --git a/src/tools/generator.cpp b/src/tools/generator.cpp --- a/src/tools/generator.cpp +++ b/src/tools/generator.cpp @@ -928,7 +928,7 @@ void Generator::generateServerPrivateInterfaceClass(const Interface &interface) { - *m_stream.localData() << QStringLiteral("#ifndef DOXYGEN_SHOULD_SKIP_THIS\n"); + *m_stream.localData() << QStringLiteral("#ifndef K_DOXYGEN\n"); *m_stream.localData() << QStringLiteral("const struct %2_interface %1::Private::s_interface = {\n").arg(interface.kwaylandServerName()).arg(interface.name()); bool first = true; for (auto r: interface.requests()) {