KWayland

testserver.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Martin Gräßlin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "testserver.h"
7 #include "../../server/compositor_interface.h"
8 #include "../../server/datadevicemanager_interface.h"
9 #include "../../server/display.h"
10 #include "../../server/fakeinput_interface.h"
11 #include "../../server/idle_interface.h"
12 #include "../../server/seat_interface.h"
13 #include "../../server/shell_interface.h"
14 #include "../../server/subcompositor_interface.h"
15 #include "../../server/surface_interface.h"
16 
17 #include <QCoreApplication>
18 #include <QElapsedTimer>
19 #include <QProcess>
20 #include <QStandardPaths>
21 #include <QTimer>
22 
23 // system
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 using namespace KWayland::Server;
29 
30 TestServer::TestServer(QObject *parent)
31  : QObject(parent)
32  , m_repaintTimer(new QTimer(this))
33  , m_timeSinceStart(new QElapsedTimer)
34  , m_cursorPos(QPointF(0, 0))
35 {
36 }
37 
38 TestServer::~TestServer() = default;
39 
40 void TestServer::init()
41 {
42  Q_ASSERT(!m_display);
43  m_display = new Display(this);
44  m_display->start(Display::StartMode::ConnectClientsOnly);
45  m_display->createShm();
46  m_display->createCompositor()->create();
47  m_shell = m_display->createShell(m_display);
48  connect(m_shell, &ShellInterface::surfaceCreated, this, [this](ShellSurfaceInterface *surface) {
49  m_shellSurfaces << surface;
50  // TODO: pass keyboard/pointer/touch focus on mapped
51  connect(surface, &QObject::destroyed, this, [this, surface] {
52  m_shellSurfaces.removeOne(surface);
53  });
54  });
55 
56  m_shell->create();
57  m_seat = m_display->createSeat(m_display);
58  m_seat->setHasKeyboard(true);
59  m_seat->setHasPointer(true);
60  m_seat->setHasTouch(true);
61  m_seat->create();
62  m_display->createDataDeviceManager(m_display)->create();
63  m_display->createIdle(m_display)->create();
64  m_display->createSubCompositor(m_display)->create();
65  // output
66  auto output = m_display->createOutput(m_display);
67  const QSize size(1280, 1024);
68  output->setGlobalPosition(QPoint(0, 0));
69  output->setPhysicalSize(size / 3.8);
70  output->addMode(size);
71  output->create();
72 
73  auto fakeInput = m_display->createFakeInput(m_display);
74  fakeInput->create();
75  connect(fakeInput, &FakeInputInterface::deviceCreated, this, [this](FakeInputDevice *device) {
76  device->setAuthentication(true);
77  connect(device, &FakeInputDevice::pointerMotionRequested, this, [this](const QSizeF &delta) {
78  m_seat->setTimestamp(m_timeSinceStart->elapsed());
79  m_cursorPos = m_cursorPos + QPointF(delta.width(), delta.height());
80  m_seat->setPointerPos(m_cursorPos);
81  });
82  connect(device, &FakeInputDevice::pointerButtonPressRequested, this, [this](quint32 button) {
83  m_seat->setTimestamp(m_timeSinceStart->elapsed());
84  m_seat->pointerButtonPressed(button);
85  });
86  connect(device, &FakeInputDevice::pointerButtonReleaseRequested, this, [this](quint32 button) {
87  m_seat->setTimestamp(m_timeSinceStart->elapsed());
88  m_seat->pointerButtonReleased(button);
89  });
90  connect(device, &FakeInputDevice::pointerAxisRequested, this, [this](Qt::Orientation orientation, qreal delta) {
91  m_seat->setTimestamp(m_timeSinceStart->elapsed());
92  m_seat->pointerAxis(orientation, delta);
93  });
94  connect(device, &FakeInputDevice::touchDownRequested, this, [this](quint32 id, const QPointF &pos) {
95  m_seat->setTimestamp(m_timeSinceStart->elapsed());
96  m_touchIdMapper.insert(id, m_seat->touchDown(pos));
97  });
98  connect(device, &FakeInputDevice::touchMotionRequested, this, [this](quint32 id, const QPointF &pos) {
99  m_seat->setTimestamp(m_timeSinceStart->elapsed());
100  const auto it = m_touchIdMapper.constFind(id);
101  if (it != m_touchIdMapper.constEnd()) {
102  m_seat->touchMove(it.value(), pos);
103  }
104  });
105  connect(device, &FakeInputDevice::touchUpRequested, this, [this](quint32 id) {
106  m_seat->setTimestamp(m_timeSinceStart->elapsed());
107  const auto it = m_touchIdMapper.find(id);
108  if (it != m_touchIdMapper.end()) {
109  m_seat->touchUp(it.value());
110  m_touchIdMapper.erase(it);
111  }
112  });
113  connect(device, &FakeInputDevice::touchCancelRequested, this, [this] {
114  m_seat->setTimestamp(m_timeSinceStart->elapsed());
115  m_seat->cancelTouchSequence();
116  });
117  connect(device, &FakeInputDevice::touchFrameRequested, this, [this] {
118  m_seat->setTimestamp(m_timeSinceStart->elapsed());
119  m_seat->touchFrame();
120  });
121  });
122 
123  m_repaintTimer->setInterval(1000 / 60);
124  connect(m_repaintTimer, &QTimer::timeout, this, &TestServer::repaint);
125  m_repaintTimer->start();
126  m_timeSinceStart->start();
127 }
128 
129 void TestServer::startTestApp(const QString &app, const QStringList &arguments)
130 {
131  int sx[2];
132  if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
134  return;
135  }
136  m_display->createClient(sx[0]);
137  int socket = dup(sx[1]);
138  if (socket == -1) {
140  return;
141  }
142 
143  const QString exec = QStandardPaths::findExecutable(app);
144  if (exec.isEmpty()) {
145  qWarning() << "Couldn't find executable:" << app;
147  return;
148  }
149 
150  QProcess *p = new QProcess(this);
153  environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland"));
154  environment.insert(QStringLiteral("WAYLAND_SOCKET"), QString::fromUtf8(QByteArray::number(socket)));
155  p->setProcessEnvironment(environment);
156  auto finishedSignal = static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished);
157  connect(p, finishedSignal, QCoreApplication::instance(), &QCoreApplication::exit);
158  connect(p, &QProcess::errorOccurred, this, [] {
160  });
161  p->start(exec, arguments);
162 }
163 
164 void TestServer::repaint()
165 {
166  for (auto it = m_shellSurfaces.constBegin(), end = m_shellSurfaces.constEnd(); it != end; ++it) {
167  (*it)->surface()->frameRendered(m_timeSinceStart->elapsed());
168  }
169 }
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
Represents the Resource for a org_kde_kwin_fake_input interface.
qreal height() const const
void deviceCreated(KWayland::Server::FakeInputDevice *device)
Signal emitted whenever a client bound the fake input device.
QString fromUtf8(const char *str, int size)
void setProcessEnvironment(const QProcessEnvironment &environment)
Resource for a wl_shell_surface.
void pointerMotionRequested(const QSizeF &delta)
Request a pointer motion by delta.
QProcessEnvironment systemEnvironment()
QByteArray number(int n, int base)
void touchDownRequested(quint32 id, const QPointF &pos)
Requests a touch down at pos and identified by id.
void exit(int returnCode)
void finished(int exitCode)
void touchMotionRequested(quint32 id, const QPointF &pos)
Requests a touch motion by pos and identified by id.
void touchCancelRequested()
Requests a touch cancel event.
QString findExecutable(const QString &executableName, const QStringList &paths)
void setProcessChannelMode(QProcess::ProcessChannelMode mode)
void destroyed(QObject *obj)
void pointerButtonPressRequested(quint32 button)
Requests a pointer button pressed for button.
void touchUpRequested(quint32 id)
Requests a touch up identified by id.
void pointerAxisRequested(Qt::Orientation orientation, qreal delta)
Requests a pointer axis for the given orientation by delta.
Orientation
void timeout()
bool isEmpty() const const
QCoreApplication * instance()
void insert(const QString &name, const QString &value)
Class holding the Wayland server display loop.
Definition: display.h:86
void surfaceCreated(KWayland::Server::ShellSurfaceInterface *)
Emitted whenever a new ShellSurfaceInterface gets created for a SurfaceInterface.
void touchFrameRequested()
Requests a touch frame event.
void setAuthentication(bool authenticated)
Authenticate this device to send events.
KWayland Server.
void errorOccurred(QProcess::ProcessError error)
qreal width() const const
void pointerButtonReleaseRequested(quint32 button)
Requests a pointer button release for button.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 03:56:22 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.