kwin/autotests/integration/kwin_wayland_test.cpp
2023-11-28 10:02:03 +00:00

251 lines
7.1 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwin_wayland_test.h"
#include "backends/virtual/virtual_backend.h"
#include "compositor_wayland.h"
#include "core/session.h"
#include "effect/effecthandler.h"
#include "inputmethod.h"
#include "placement.h"
#include "pluginmanager.h"
#include "utils/xcbutils.h"
#include "wayland_server.h"
#include "workspace.h"
#include "xwayland/xwayland.h"
#include "xwayland/xwaylandlauncher.h"
#include <KPluginMetaData>
#include <QAbstractEventDispatcher>
#include <QPluginLoader>
#include <QSocketNotifier>
#include <QThread>
#include <QtConcurrentRun>
// system
#include <iostream>
#include <sys/socket.h>
#include <unistd.h>
Q_IMPORT_PLUGIN(KWinIntegrationPlugin)
#if KWIN_BUILD_GLOBALSHORTCUTS
Q_IMPORT_PLUGIN(KGlobalAccelImpl)
#endif
Q_IMPORT_PLUGIN(KWindowSystemKWinPlugin)
Q_IMPORT_PLUGIN(KWinIdleTimePoller)
namespace KWin
{
WaylandTestApplication::WaylandTestApplication(OperationMode mode, int &argc, char **argv)
: Application(mode, argc, argv)
{
QStandardPaths::setTestModeEnabled(true);
const QStringList configs{
QStringLiteral("kaccessrc"),
QStringLiteral("kglobalshortcutsrc"),
};
for (const QString &config : configs) {
if (const QString &fileName = QStandardPaths::locate(QStandardPaths::ConfigLocation, config); !fileName.isEmpty()) {
QFile::remove(fileName);
}
}
QIcon::setThemeName(QStringLiteral("breeze"));
#if KWIN_BUILD_ACTIVITIES
setUseKActivities(false);
#endif
qputenv("KWIN_COMPOSE", QByteArrayLiteral("Q"));
qputenv("XDG_CURRENT_DESKTOP", QByteArrayLiteral("KDE"));
qunsetenv("XKB_DEFAULT_RULES");
qunsetenv("XKB_DEFAULT_MODEL");
qunsetenv("XKB_DEFAULT_LAYOUT");
qunsetenv("XKB_DEFAULT_VARIANT");
qunsetenv("XKB_DEFAULT_OPTIONS");
auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
KConfigGroup windowsGroup = config->group(QStringLiteral("Windows"));
windowsGroup.writeEntry("Placement", Placement::policyToString(PlacementSmart));
windowsGroup.sync();
setConfig(config);
const auto ownPath = libraryPaths().last();
removeLibraryPath(ownPath);
addLibraryPath(ownPath);
setSession(Session::create(Session::Type::Noop));
setOutputBackend(std::make_unique<VirtualBackend>());
WaylandServer::create(this);
setProcessStartupEnvironment(QProcessEnvironment::systemEnvironment());
}
WaylandTestApplication::~WaylandTestApplication()
{
setTerminating();
// need to unload all effects prior to destroying X connection as they might do X calls
// also before destroy Workspace, as effects might call into Workspace
if (effects) {
effects->unloadAllEffects();
}
m_xwayland.reset();
destroyVirtualInputDevices();
destroyColorManager();
destroyWorkspace();
destroyInputMethod();
destroyCompositor();
destroyInput();
}
void WaylandTestApplication::createVirtualInputDevices()
{
m_virtualKeyboard = std::make_unique<Test::VirtualInputDevice>();
m_virtualKeyboard->setName(QStringLiteral("Virtual Keyboard 1"));
m_virtualKeyboard->setKeyboard(true);
m_virtualPointer = std::make_unique<Test::VirtualInputDevice>();
m_virtualPointer->setName(QStringLiteral("Virtual Pointer 1"));
m_virtualPointer->setPointer(true);
m_virtualTouch = std::make_unique<Test::VirtualInputDevice>();
m_virtualTouch->setName(QStringLiteral("Virtual Touch 1"));
m_virtualTouch->setTouch(true);
input()->addInputDevice(m_virtualPointer.get());
input()->addInputDevice(m_virtualTouch.get());
input()->addInputDevice(m_virtualKeyboard.get());
}
void WaylandTestApplication::destroyVirtualInputDevices()
{
if (m_virtualPointer) {
input()->removeInputDevice(m_virtualPointer.get());
}
if (m_virtualTouch) {
input()->removeInputDevice(m_virtualTouch.get());
}
if (m_virtualKeyboard) {
input()->removeInputDevice(m_virtualKeyboard.get());
}
}
void WaylandTestApplication::performStartup()
{
if (!m_inputMethodServerToStart.isEmpty()) {
createInputMethod();
if (m_inputMethodServerToStart != QStringLiteral("internal")) {
inputMethod()->setInputMethodCommand(m_inputMethodServerToStart);
inputMethod()->setEnabled(true);
}
}
// first load options - done internally by a different thread
createOptions();
if (!outputBackend()->initialize()) {
std::exit(1);
}
// try creating the Wayland Backend
createInput();
createVirtualInputDevices();
createTabletModeManager();
WaylandCompositor::create();
createWorkspace();
createColorManager();
createPlugins();
connect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene);
}
void WaylandTestApplication::continueStartupWithScene()
{
disconnect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene);
waylandServer()->initWorkspace();
if (!waylandServer()->start()) {
qFatal("Failed to initialize the Wayland server, exiting now");
}
if (operationMode() == OperationModeXwayland) {
m_xwayland = std::make_unique<Xwl::Xwayland>(this);
m_xwayland->init();
}
notifyStarted();
}
Test::VirtualInputDevice *WaylandTestApplication::virtualPointer() const
{
return m_virtualPointer.get();
}
Test::VirtualInputDevice *WaylandTestApplication::virtualKeyboard() const
{
return m_virtualKeyboard.get();
}
Test::VirtualInputDevice *WaylandTestApplication::virtualTouch() const
{
return m_virtualTouch.get();
}
XwaylandInterface *WaylandTestApplication::xwayland() const
{
return m_xwayland.get();
}
Test::FractionalScaleManagerV1::~FractionalScaleManagerV1()
{
destroy();
}
Test::FractionalScaleV1::~FractionalScaleV1()
{
destroy();
}
int Test::FractionalScaleV1::preferredScale()
{
return m_preferredScale;
}
void Test::FractionalScaleV1::wp_fractional_scale_v1_preferred_scale(uint32_t scale)
{
m_preferredScale = scale;
}
void Test::setOutputConfig(const QList<QRect> &geometries)
{
QList<VirtualBackend::OutputInfo> converted;
std::transform(geometries.begin(), geometries.end(), std::back_inserter(converted), [](const auto &geometry) {
return VirtualBackend::OutputInfo{
.geometry = geometry,
};
});
static_cast<VirtualBackend *>(kwinApp()->outputBackend())->setVirtualOutputs(converted);
}
void Test::setOutputConfig(const QList<OutputInfo> &infos)
{
QList<VirtualBackend::OutputInfo> converted;
std::transform(infos.begin(), infos.end(), std::back_inserter(converted), [](const auto &info) {
return VirtualBackend::OutputInfo{
.geometry = info.geometry,
.scale = info.scale,
.internal = info.internal,
};
});
static_cast<VirtualBackend *>(kwinApp()->outputBackend())->setVirtualOutputs(converted);
}
}
#include "moc_kwin_wayland_test.cpp"