kwin/autotests/integration/kwin_wayland_test.cpp
Yifan Zhu ad13765348 pointer_input: implement edge barrier between screens
Allow users to configure a virtual edge barrier between screens.
The pointer will only cross over to the other screen after the distance
travelled surpasses edgeBarrier.

Reduce the speed during interactive moveresize, at edges that trigger,
and at the corner.

Only supports wayland. Doesn't have X11 support since it is far too
complicated there.

BUG: 416570
BUG: 451744
2024-03-08 12:03:28 -08:00

268 lines
7.6 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 "wayland_server.h"
#include "workspace.h"
#if KWIN_BUILD_X11
#include "utils/xcbutils.h"
#include "xwayland/xwayland.h"
#include "xwayland/xwaylandlauncher.h"
#endif
#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 breezerc = KSharedConfig::openConfig(QStringLiteral("breezerc"));
breezerc->group(QStringLiteral("Common")).writeEntry(QStringLiteral("OutlineIntensity"), QStringLiteral("OutlineOff"));
breezerc->sync();
auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
KConfigGroup windowsGroup = config->group(QStringLiteral("Windows"));
windowsGroup.writeEntry("Placement", Placement::policyToString(PlacementSmart));
windowsGroup.sync();
KConfigGroup edgeBarrierGroup = config->group(QStringLiteral("EdgeBarrier"));
edgeBarrierGroup.writeEntry("EdgeBarrier", 0);
edgeBarrierGroup.writeEntry("CornerBarrier", false);
edgeBarrierGroup.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();
}
#if KWIN_BUILD_X11
m_xwayland.reset();
#endif
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 KWIN_BUILD_X11
if (operationMode() == OperationModeXwayland) {
m_xwayland = std::make_unique<Xwl::Xwayland>(this);
m_xwayland->init();
}
#endif
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();
}
#if KWIN_BUILD_X11
XwaylandInterface *WaylandTestApplication::xwayland() const
{
return m_xwayland.get();
}
#endif
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"