ad13765348
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
268 lines
7.6 KiB
C++
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"
|