Commit e0052ced authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧

Implement the tablet wayland protocol in kwin

Summary:
Uses the tablet classes introduced in kwayland.
Depends on D26858

Test Plan:
Scratched my tablet with a magic stick and it did things depending on the pressure.
https://youtu.be/GGx0TlNJlzs

Reviewers: #kwin, #plasma, zzag, davidedmundson

Reviewed By: #kwin, #plasma, zzag, davidedmundson

Subscribers: davidedmundson, zzag, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D26859
parent bb04ab39
......@@ -654,6 +654,9 @@ set(kwinLibs
)
add_library(kwin SHARED ${kwin_SRCS})
if (Libinput_VERSION_STRING VERSION_GREATER 1.14)
target_compile_definitions(kwin PRIVATE -DLIBINPUT_HAS_TOTEM)
endif ()
set_target_properties(kwin PROPERTIES
VERSION ${PROJECT_VERSION}
......
......@@ -916,3 +916,21 @@ libinput_event_get_tablet_tool_event(struct libinput_event *event)
}
return nullptr;
}
int
libinput_device_tablet_pad_get_num_strips(struct libinput_device *device)
{
return device->stripCount;
}
int
libinput_device_tablet_pad_get_num_rings(struct libinput_device *device)
{
return device->ringCount;
}
int
libinput_device_tablet_pad_get_num_buttons(struct libinput_device *device)
{
return device->buttonCount;
}
......@@ -105,6 +105,9 @@ struct libinput_device {
enum libinput_config_click_method defaultClickMethod = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
enum libinput_config_click_method clickMethod = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
bool setClickMethodReturnValue = 0;
uint32_t buttonCount = 0;
uint32_t stripCount = 0;
uint32_t ringCount = 0;
};
struct libinput_event {
......
......@@ -28,6 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "wayland_server.h"
#include "workspace.h"
#include "keyboard_input.h"
#include "input_event.h"
#include "libinput/connection.h"
#include "libinput/device.h"
#include <kwinglplatform.h>
......@@ -486,7 +487,7 @@ void DebugConsoleFilter::switchEvent(SwitchEvent *event)
m_textEdit->ensureCursorVisible();
}
void DebugConsoleFilter::tabletToolEvent(QTabletEvent *event)
void DebugConsoleFilter::tabletToolEvent(TabletEvent *event)
{
QString typeString;
{
......
......@@ -153,7 +153,7 @@ public:
void switchEvent(SwitchEvent *event) override;
void tabletToolEvent(QTabletEvent *event) override;
void tabletToolEvent(TabletEvent *event) override;
void tabletToolButtonEvent(const QSet<uint> &pressedButtons) override;
void tabletPadButtonEvent(const QSet<uint> &pressedButtons) override;
void tabletPadStripEvent(int number, int position, bool isFinger) override;
......
......@@ -36,24 +36,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef KWIN_BUILD_TABBOX
#include "tabbox/tabbox.h"
#endif
#include "unmanaged.h"
#include "screenedge.h"
#include "screens.h"
#include "workspace.h"
#include "internal_client.h"
#include "libinput/connection.h"
#include "libinput/device.h"
#include "platform.h"
#include "popup_input_filter.h"
#include "screenedge.h"
#include "screens.h"
#include "unmanaged.h"
#include "wayland_server.h"
#include "workspace.h"
#include "xdgshellclient.h"
#include "xwl/xwayland_interface.h"
#include "internal_client.h"
#include "cursor.h"
#include <KDecoration2/Decoration>
#include <KGlobalAccel>
#include <KWayland/Server/display.h>
#include <KWayland/Server/fakeinput_interface.h>
#include <KWayland/Server/seat_interface.h>
#include <KWayland/Server/relativepointer_interface.h>
#include <KWayland/Server/seat_interface.h>
#include <KWayland/Server/surface_interface.h>
#include <KWayland/Server/tablet_interface.h>
#include <decorations/decoratedclient.h>
#include <KDecoration2/Decoration>
#include <KGlobalAccel>
//screenlocker
#include <KScreenLocker/KsldApp>
......@@ -176,7 +180,7 @@ bool InputEventFilter::switchEvent(SwitchEvent *event)
return false;
}
bool InputEventFilter::tabletToolEvent(QTabletEvent *event)
bool InputEventFilter::tabletToolEvent(TabletEvent *event)
{
Q_UNUSED(event)
return false;
......@@ -1531,17 +1535,174 @@ public:
}
};
static KWayland::Server::SeatInterface *findSeat()
{
auto server = waylandServer();
if (!server) {
return nullptr;
}
return server->seat();
}
/**
* Useful when there's no proper tablet support on the clients
*/
class FakeTabletInputFilter : public InputEventFilter
class TabletInputFilter : public QObject, public InputEventFilter
{
public:
FakeTabletInputFilter()
TabletInputFilter()
{
}
static KWayland::Server::TabletSeatInterface *findTabletSeat()
{
auto server = waylandServer();
if (!server) {
return nullptr;
}
KWayland::Server::TabletManagerInterface *manager = server->tabletManager();
return manager->seat(findSeat());
}
void integrateDevice(LibInput::Device *device)
{
if (device->isTabletTool()) {
KWayland::Server::TabletSeatInterface *tabletSeat = findTabletSeat();
struct udev_device *const udev_device = libinput_device_get_udev_device(device->device());
const char *devnode = udev_device_get_devnode(udev_device);
tabletSeat->addTablet(device->vendor(), device->product(), device->sysName(), device->name(), {QString::fromUtf8(devnode)});
}
}
void removeDevice(const QString &sysname)
{
KWayland::Server::TabletSeatInterface *tabletSeat = findTabletSeat();
tabletSeat->removeTablet(sysname);
}
bool tabletToolEvent(TabletEvent *event) override
{
if (!workspace()) {
return false;
}
KWayland::Server::TabletSeatInterface *tabletSeat = findTabletSeat();
auto tool = tabletSeat->toolByHardwareSerial(event->serialId());
if (!tool) {
using namespace KWayland::Server;
const QVector<InputRedirection::Capability> capabilities = event->capabilities();
const auto f = [](InputRedirection::Capability cap) {
switch (cap) {
case InputRedirection::Tilt:
return TabletToolInterface::Tilt;
case InputRedirection::Pressure:
return TabletToolInterface::Pressure;
case InputRedirection::Distance:
return TabletToolInterface::Distance;
case InputRedirection::Rotation:
return TabletToolInterface::Rotation;
case InputRedirection::Slider:
return TabletToolInterface::Slider;
case InputRedirection::Wheel:
return TabletToolInterface::Wheel;
}
return TabletToolInterface::Wheel;
};
QVector<TabletToolInterface::Capability> ifaceCapabilities;
ifaceCapabilities.resize(capabilities.size());
std::transform(capabilities.constBegin(), capabilities.constEnd(), ifaceCapabilities.begin(), f);
TabletToolInterface::Type toolType = TabletToolInterface::Type::Pen;
switch (event->toolType()) {
case InputRedirection::Pen:
toolType = TabletToolInterface::Type::Pen;
break;
case InputRedirection::Eraser:
toolType = TabletToolInterface::Type::Eraser;
break;
case InputRedirection::Brush:
toolType = TabletToolInterface::Type::Brush;
break;
case InputRedirection::Pencil:
toolType = TabletToolInterface::Type::Pencil;
break;
case InputRedirection::Airbrush:
toolType = TabletToolInterface::Type::Airbrush;
break;
case InputRedirection::Finger:
toolType = TabletToolInterface::Type::Finger;
break;
case InputRedirection::Mouse:
toolType = TabletToolInterface::Type::Mouse;
break;
case InputRedirection::Lens:
toolType = TabletToolInterface::Type::Lens;
break;
case InputRedirection::Totem:
toolType = TabletToolInterface::Type::Totem;
break;
}
tool = tabletSeat->addTool(toolType, event->serialId(), event->uniqueId(), ifaceCapabilities);
const auto cursor = new Cursor(tool);
Cursors::self()->addCursor(cursor);
m_cursorByTool[tool] = cursor;
connect(tool->cursor(), &TabletCursor::changed, cursor, &Cursor::cursorChanged);
connect(tool->cursor(), &TabletCursor::changed, cursor, [cursor, tool] {
// cursor->setImage(tool->cursor()->image());
QPixmap redRect(20, 20);
redRect.fill(Qt::red);
cursor->setImage(redRect.toImage());
cursor->setHotspot(tool->cursor()->hotspot());
});
emit cursor->cursorChanged();
}
KWayland::Server::TabletInterface *tablet = tabletSeat->tabletByName(event->tabletSysName());
Toplevel *toplevel = input()->findToplevel(event->globalPos());
if (!toplevel || !toplevel->surface()) {
return false;
}
KWayland::Server::SurfaceInterface *surface = toplevel->surface();
tool->setCurrentSurface(surface);
if (!tool->isClientSupported() || !tablet->isSurfaceSupported(surface)) {
return emulateTabletEvent(event);
}
switch (event->type()) {
case QEvent::TabletMove: {
const auto pos = event->globalPosF() - toplevel->pos();
tool->sendMotion(pos);
m_cursorByTool[tool]->setPos(pos.toPoint());
break;
} case QEvent::TabletEnterProximity: {
tool->sendProximityIn(tablet);
break;
} case QEvent::TabletLeaveProximity:
tool->sendProximityOut();
break;
case QEvent::TabletPress:
tool->sendDown();
break;
case QEvent::TabletRelease:
tool->sendUp();
break;
default:
qCWarning(KWIN_CORE) << "Unexpected tablet event type" << event;
break;
}
const quint32 MAX_VAL = 65535;
tool->sendPressure(MAX_VAL * event->pressure());
tool->sendFrame(event->timestamp());
waylandServer()->simulateUserActivity();
return true;
}
bool tabletToolEvent(QTabletEvent *event) override
bool emulateTabletEvent(TabletEvent *event)
{
if (!workspace()) {
return false;
......@@ -1569,6 +1730,7 @@ public:
waylandServer()->simulateUserActivity();
return true;
}
QHash<KWayland::Server::TabletToolInterface*, Cursor*> m_cursorByTool;
};
class DragAndDropInputFilter : public InputEventFilter
......@@ -1932,7 +2094,16 @@ void InputRedirection::setupInputFilters()
if (waylandServer()) {
installInputEventFilter(new WindowActionInputFilter);
installInputEventFilter(new ForwardInputFilter);
installInputEventFilter(new FakeTabletInputFilter);
if (m_libInput) {
m_tabletSupport = new TabletInputFilter;
for (LibInput::Device *dev : m_libInput->devices()) {
m_tabletSupport->integrateDevice(dev);
}
connect(m_libInput, &LibInput::Connection::deviceAdded, m_tabletSupport, &TabletInputFilter::integrateDevice);
connect(m_libInput, &LibInput::Connection::deviceRemovedSysName, m_tabletSupport, &TabletInputFilter::removeDevice);
installInputEventFilter(m_tabletSupport);
}
}
}
......@@ -1950,15 +2121,6 @@ void InputRedirection::reconfigure()
}
}
static KWayland::Server::SeatInterface *findSeat()
{
auto server = waylandServer();
if (!server) {
return nullptr;
}
return server->seat();
}
void InputRedirection::setupLibInput()
{
if (!Application::usesLibinput()) {
......@@ -2087,6 +2249,7 @@ void InputRedirection::setupLibInput()
}
);
}
setupTouchpadShortcuts();
}
......
......@@ -51,6 +51,8 @@ class TabletInputRedirection;
class TouchInputRedirection;
class WindowSelectorFilter;
class SwitchEvent;
class TabletEvent;
class TabletInputFilter;
namespace Decoration
{
......@@ -100,6 +102,26 @@ public:
Proximity,
Tip
};
enum TabletToolType {
Pen,
Eraser,
Brush,
Pencil,
Airbrush,
Finger,
Mouse,
Lens,
Totem,
};
enum Capability {
Tilt,
Pressure,
Distance,
Rotation,
Slider,
Wheel,
};
~InputRedirection() override;
void init();
......@@ -297,6 +319,7 @@ private:
PointerInputRedirection *m_pointer;
TabletInputRedirection *m_tablet;
TouchInputRedirection *m_touch;
TabletInputFilter *m_tabletSupport = nullptr;
GlobalShortcutsManager *m_shortcuts;
......@@ -382,7 +405,7 @@ public:
virtual bool switchEvent(SwitchEvent *event);
virtual bool tabletToolEvent(QTabletEvent *event);
virtual bool tabletToolEvent(TabletEvent *event);
virtual bool tabletToolButtonEvent(const QSet<uint> &buttons);
virtual bool tabletPadButtonEvent(const QSet<uint> &buttons);
virtual bool tabletPadStripEvent(int number, int position, bool isFinger);
......
......@@ -65,4 +65,17 @@ SwitchEvent::SwitchEvent(State state, quint32 timestamp, quint64 timestampMicros
setTimestamp(timestamp);
}
TabletEvent::TabletEvent(Type t, const QPointF &pos, const QPointF &globalPos,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z,
Qt::KeyboardModifiers keyState, qint64 uniqueID,
Qt::MouseButton button, Qt::MouseButtons buttons, InputRedirection::TabletToolType toolType, const QVector<InputRedirection::Capability> &capabilities, quint64 serialId, const QString &tabletSysName)
: QTabletEvent(t, pos, globalPos, device, pointerType, pressure, xTilt, yTilt, tangentialPressure, rotation, z, keyState, uniqueID, button, buttons)
, m_toolType(toolType)
, m_capabilities(capabilities)
, m_serialId(serialId)
, m_tabletSysName(tabletSysName)
{
}
}
......@@ -176,6 +176,29 @@ private:
LibInput::Device *m_device;
};
class TabletEvent : public QTabletEvent
{
public:
TabletEvent(Type t, const QPointF &pos, const QPointF &globalPos,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z,
Qt::KeyboardModifiers keyState, qint64 uniqueID,
Qt::MouseButton button, Qt::MouseButtons buttons, InputRedirection::TabletToolType toolType,
const QVector<InputRedirection::Capability> &capabilities,
quint64 serialId, const QString &tabletSysname);
InputRedirection::TabletToolType toolType() const { return m_toolType; }
QVector<InputRedirection::Capability> capabilities() const { return m_capabilities; }
quint64 serialId() const { return m_serialId; }
QString tabletSysName() { return m_tabletSysName; }
private:
const InputRedirection::TabletToolType m_toolType;
const QVector<InputRedirection::Capability> m_capabilities;
const quint64 m_serialId;
const QString m_tabletSysName;
};
}
#endif
......@@ -121,7 +121,7 @@ void InputEventSpy::switchEvent(SwitchEvent *event)
Q_UNUSED(event)
}
void InputEventSpy::tabletToolEvent(QTabletEvent *event)
void InputEventSpy::tabletToolEvent(TabletEvent *event)
{
Q_UNUSED(event)
}
......
......@@ -33,7 +33,7 @@ class KeyEvent;
class MouseEvent;
class WheelEvent;
class SwitchEvent;
class TabletEvent;
/**
* Base class for spying on input events inside InputRedirection.
......@@ -85,7 +85,7 @@ public:
virtual void switchEvent(SwitchEvent *event);
virtual void tabletToolEvent(QTabletEvent *event);
virtual void tabletToolEvent(TabletEvent *event);
virtual void tabletToolButtonEvent(const QSet<uint> &pressedButtons);
virtual void tabletPadButtonEvent(const QSet<uint> &pressedButtons);
virtual void tabletPadStripEvent(int number, int position, bool isFinger);
......
......@@ -528,12 +528,62 @@ void Connection::processEvents()
}
auto serial = libinput_tablet_tool_get_serial(tte->tool());
auto toolId = libinput_tablet_tool_get_tool_id(tte->tool());
auto type = libinput_tablet_tool_get_type(tte->tool());
InputRedirection::TabletToolType toolType;
switch (type) {
case LIBINPUT_TABLET_TOOL_TYPE_PEN:
toolType = InputRedirection::Pen;
break;
case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
toolType = InputRedirection::Eraser;
break;
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
toolType = InputRedirection::Brush;
break;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
toolType = InputRedirection::Pencil;
break;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
toolType = InputRedirection::Airbrush;
break;
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
toolType = InputRedirection::Mouse;
break;
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
toolType = InputRedirection::Lens;
break;
#ifdef LIBINPUT_HAS_TOTEM
case LIBINPUT_TABLET_TOOL_TYPE_TOTEM:
toolType = InputRedirection::Totem;
break;
#endif
}
QVector<InputRedirection::Capability> capabilities;
if (libinput_tablet_tool_has_pressure(tte->tool())) {
capabilities << InputRedirection::Pressure;
}
if (libinput_tablet_tool_has_distance(tte->tool())) {
capabilities << InputRedirection::Distance;
}
if (libinput_tablet_tool_has_rotation(tte->tool())) {
capabilities << InputRedirection::Rotation;
}
if (libinput_tablet_tool_has_tilt(tte->tool())) {
capabilities << InputRedirection::Tilt;
}
if (libinput_tablet_tool_has_slider(tte->tool())) {
capabilities << InputRedirection::Slider;
}
if (libinput_tablet_tool_has_wheel(tte->tool())) {
capabilities << InputRedirection::Wheel;
}
emit tabletToolEvent(tabletEventType,
tte->transformedPosition(m_size), tte->pressure(),
tte->xTilt(), tte->yTilt(), tte->rotation(),
tte->isTipDown(), tte->isNearby(), serial,
toolId, event->device());
toolId, toolType, capabilities, tte->time(),
event->device());
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: {
......
......@@ -133,7 +133,11 @@ Q_SIGNALS:
void tabletToolEvent(KWin::InputRedirection::TabletEventType type, const QPointF &pos,
qreal pressure, int xTilt, int yTilt, qreal rotation, bool tipDown,
bool tipNear, quint64 serialId, quint64 toolId, LibInput::Device *device);
bool tipNear, quint64 serialId, quint64 toolId,
InputRedirection::TabletToolType toolType,
const QVector<InputRedirection::Capability> &capabilities,
quint32 time,
LibInput::Device *device);
void tabletToolButtonEvent(uint button, bool isPressed);
void tabletPadButtonEvent(uint button, bool isPressed);
......
......@@ -158,12 +158,7 @@ Device::Device(libinput_device *device, QObject *parent)
, m_pointer(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_POINTER))
, m_touch(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TOUCH))
, m_tabletTool(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TABLET_TOOL))
#if 0
// next libinput version
, m_tabletPad(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TABLET_PAD))
#else
, m_tabletPad(false)
#endif
, m_supportsGesture(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_GESTURE))
, m_switch(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_SWITCH))
, m_lidSwitch(m_switch ? libinput_device_switch_has_switch(m_device, LIBINPUT_SWITCH_LID) : false)
......@@ -427,6 +422,16 @@ void Device::setLmrTapButtonMap(bool set)
}
}
int Device::stripsCount() const
{
return libinput_device_tablet_pad_get_num_strips(m_device);
}
int Device::ringsCount() const
{
return libinput_device_tablet_pad_get_num_rings(m_device);
}
#define CONFIG(method, condition, function, variable, key) \
void Device::method(bool set) \
{ \
......
......@@ -472,6 +472,9 @@ public:
return m_tabletSwitch;
}
int stripsCount() const;
int ringsCount() const;
/**
* All created Devices
*/
......
......@@ -196,6 +196,10 @@ class TabletToolEvent : public Event
public:
TabletToolEvent(libinput_event *event, libinput_event_type type);
uint32_t time() const
{
return libinput_event_tablet_tool_get_time(m_tabletToolEvent);
}
bool xHasChanged() const {
return libinput_event_tablet_tool_x_has_changed(m_tabletToolEvent);
}
......
......@@ -59,7 +59,7 @@ void ModifierOnlyShortcuts::keyEvent(KeyEvent *event)
m_pressedKeys.remove(event->nativeScanCode());
if (m_pressedKeys.isEmpty() &&
event->modifiersRelevantForGlobalShortcuts() == Qt::NoModifier &&
!workspace()->globalShortcutsDisabled()) {
workspace() && !workspace()->globalShortcutsDisabled()) {
if (m_modifier != Qt::NoModifier) {
const auto list = options->modifierOnlyDBusShortcut(m_modifier);
if (list.size() >= 4) {
......
......@@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "abstract_client.h"
#include "decorations/decoratedclient.h"
#include "input.h"
#include "input_event.h"
#include "input_event_spy.h"
#include "libinput/device.h"
#include "pointer_input.h"
......@@ -60,10 +61,11 @@ void TabletInputRedirection::tabletToolEvent(KWin::InputRedirection::TabletEvent
const QPointF &pos, qreal pressure,
int xTilt, int yTilt, qreal rotation,
bool tipDown, bool tipNear, quint64 serialId,
quint64 toolId, LibInput::Device *device)
quint64 toolId,
InputRedirection::TabletToolType toolType,
const QVector<InputRedirection::Capability> &capabilities,
quint32 time, LibInput::Device *device)
{
Q_UNUSED(device)
Q_UNUSED(toolId)
if (!inited()) {
return;
}
......@@ -83,13 +85,14 @@ void TabletInputRedirection::tabletToolEvent(KWin::InputRedirection::TabletEvent
}
const auto button = m_tipDown ? Qt::LeftButton : Qt::NoButton;
QTabletEvent ev(t, pos, pos, QTabletEvent::Stylus, QTabletEvent::Pen, pressure,
TabletEvent ev(t, pos, pos, QTabletEvent::Stylus, QTabletEvent::Pen, pressure,
xTilt, yTilt,
0, // tangentialPressure
rotation,
0, // z
Qt::NoModifier, serialId, button, button);
Qt::NoModifier, toolId, button, button, toolType, capabilities, serialId, device->sysName());
ev.setTimestamp(time);
input()->processSpies(std::bind(&InputEventSpy::tabletToolEvent, std::placeholders::_1, &ev));
input()->processFilters(
std::bind(&InputEventFilter::tabletToolEvent, std::placeholders::_1, &ev));
......
......@@ -26,11 +26,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QObject>
#include <QPointF>
#include <QPointer>
#include <QTabletEvent>
namespace KWin
{
class InputRedirection;
class Toplevel;
namespace Decoration
......@@ -54,7 +52,9 @@ public:
void tabletToolEvent(KWin::InputRedirection::TabletEventType type, const QPointF &pos,
qreal pressure, int xTilt, int yTilt, qreal rotation, bool tipDown,
bool tipNear, quint64 serialId, quint64 toolId, LibInput::Device *device);
bool tipNear, quint64 serialId, quint64 toolId,
InputRedirection::TabletToolType toolType, const QVector<InputRedirection::Capability> &capabilities,
quint32 time, LibInput::Device *device);
void tabletToolButtonEvent(uint button, bool isPressed);
void tabletPadButtonEvent(uint button, bool isPressed);
......
......@@ -315,6 +315,8 @@ bool WaylandServer::init(const QByteArray &socketName, InitializationFlags flags
}
);
m_tabletManager = m_display->createTabletManagerInterface(m_display);
m_xdgShell = m_display->createXdgShell(XdgShellInterfaceVersion::Stable, m_display);
m_xdgShell->create();
connect(m_xdgShell, &XdgShellInterface::surfaceCreated, this, &WaylandServer::createSurface<XdgShellSurfaceInterface>);
......