File indexing completed on 2024-05-12 05:30:34

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "kwin_wayland_test.h"
0010 
0011 #include "backends/virtual/virtual_backend.h"
0012 #include "compositor_wayland.h"
0013 #include "core/session.h"
0014 #include "effect/effecthandler.h"
0015 #include "inputmethod.h"
0016 #include "placement.h"
0017 #include "pluginmanager.h"
0018 #include "utils/xcbutils.h"
0019 #include "wayland_server.h"
0020 #include "workspace.h"
0021 #include "xwayland/xwayland.h"
0022 #include "xwayland/xwaylandlauncher.h"
0023 
0024 #include <KPluginMetaData>
0025 
0026 #include <QAbstractEventDispatcher>
0027 #include <QPluginLoader>
0028 #include <QSocketNotifier>
0029 #include <QThread>
0030 #include <QtConcurrentRun>
0031 
0032 // system
0033 #include <iostream>
0034 #include <sys/socket.h>
0035 #include <unistd.h>
0036 
0037 Q_IMPORT_PLUGIN(KWinIntegrationPlugin)
0038 #if KWIN_BUILD_GLOBALSHORTCUTS
0039 Q_IMPORT_PLUGIN(KGlobalAccelImpl)
0040 #endif
0041 Q_IMPORT_PLUGIN(KWindowSystemKWinPlugin)
0042 Q_IMPORT_PLUGIN(KWinIdleTimePoller)
0043 
0044 namespace KWin
0045 {
0046 
0047 WaylandTestApplication::WaylandTestApplication(OperationMode mode, int &argc, char **argv)
0048     : Application(mode, argc, argv)
0049 {
0050     QStandardPaths::setTestModeEnabled(true);
0051 
0052     const QStringList configs{
0053         QStringLiteral("kaccessrc"),
0054         QStringLiteral("kglobalshortcutsrc"),
0055     };
0056     for (const QString &config : configs) {
0057         if (const QString &fileName = QStandardPaths::locate(QStandardPaths::ConfigLocation, config); !fileName.isEmpty()) {
0058             QFile::remove(fileName);
0059         }
0060     }
0061 
0062     QIcon::setThemeName(QStringLiteral("breeze"));
0063 #if KWIN_BUILD_ACTIVITIES
0064     setUseKActivities(false);
0065 #endif
0066     qputenv("KWIN_COMPOSE", QByteArrayLiteral("Q"));
0067     qputenv("XDG_CURRENT_DESKTOP", QByteArrayLiteral("KDE"));
0068     qunsetenv("XKB_DEFAULT_RULES");
0069     qunsetenv("XKB_DEFAULT_MODEL");
0070     qunsetenv("XKB_DEFAULT_LAYOUT");
0071     qunsetenv("XKB_DEFAULT_VARIANT");
0072     qunsetenv("XKB_DEFAULT_OPTIONS");
0073 
0074     auto breezerc = KSharedConfig::openConfig(QStringLiteral("breezerc"));
0075     breezerc->group(QStringLiteral("Common")).writeEntry(QStringLiteral("OutlineIntensity"), QStringLiteral("OutlineOff"));
0076     breezerc->sync();
0077 
0078     auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
0079     KConfigGroup windowsGroup = config->group(QStringLiteral("Windows"));
0080     windowsGroup.writeEntry("Placement", Placement::policyToString(PlacementSmart));
0081     windowsGroup.sync();
0082     setConfig(config);
0083 
0084     const auto ownPath = libraryPaths().last();
0085     removeLibraryPath(ownPath);
0086     addLibraryPath(ownPath);
0087 
0088     setSession(Session::create(Session::Type::Noop));
0089     setOutputBackend(std::make_unique<VirtualBackend>());
0090     WaylandServer::create(this);
0091     setProcessStartupEnvironment(QProcessEnvironment::systemEnvironment());
0092 }
0093 
0094 WaylandTestApplication::~WaylandTestApplication()
0095 {
0096     setTerminating();
0097     // need to unload all effects prior to destroying X connection as they might do X calls
0098     // also before destroy Workspace, as effects might call into Workspace
0099     if (effects) {
0100         effects->unloadAllEffects();
0101     }
0102     m_xwayland.reset();
0103     destroyVirtualInputDevices();
0104     destroyColorManager();
0105     destroyWorkspace();
0106     destroyInputMethod();
0107     destroyCompositor();
0108     destroyInput();
0109 }
0110 
0111 void WaylandTestApplication::createVirtualInputDevices()
0112 {
0113     m_virtualKeyboard = std::make_unique<Test::VirtualInputDevice>();
0114     m_virtualKeyboard->setName(QStringLiteral("Virtual Keyboard 1"));
0115     m_virtualKeyboard->setKeyboard(true);
0116 
0117     m_virtualPointer = std::make_unique<Test::VirtualInputDevice>();
0118     m_virtualPointer->setName(QStringLiteral("Virtual Pointer 1"));
0119     m_virtualPointer->setPointer(true);
0120 
0121     m_virtualTouch = std::make_unique<Test::VirtualInputDevice>();
0122     m_virtualTouch->setName(QStringLiteral("Virtual Touch 1"));
0123     m_virtualTouch->setTouch(true);
0124 
0125     input()->addInputDevice(m_virtualPointer.get());
0126     input()->addInputDevice(m_virtualTouch.get());
0127     input()->addInputDevice(m_virtualKeyboard.get());
0128 }
0129 
0130 void WaylandTestApplication::destroyVirtualInputDevices()
0131 {
0132     if (m_virtualPointer) {
0133         input()->removeInputDevice(m_virtualPointer.get());
0134     }
0135     if (m_virtualTouch) {
0136         input()->removeInputDevice(m_virtualTouch.get());
0137     }
0138     if (m_virtualKeyboard) {
0139         input()->removeInputDevice(m_virtualKeyboard.get());
0140     }
0141 }
0142 
0143 void WaylandTestApplication::performStartup()
0144 {
0145     if (!m_inputMethodServerToStart.isEmpty()) {
0146         createInputMethod();
0147         if (m_inputMethodServerToStart != QStringLiteral("internal")) {
0148             inputMethod()->setInputMethodCommand(m_inputMethodServerToStart);
0149             inputMethod()->setEnabled(true);
0150         }
0151     }
0152 
0153     // first load options - done internally by a different thread
0154     createOptions();
0155     if (!outputBackend()->initialize()) {
0156         std::exit(1);
0157     }
0158 
0159     // try creating the Wayland Backend
0160     createInput();
0161     createVirtualInputDevices();
0162     createTabletModeManager();
0163 
0164     WaylandCompositor::create();
0165     createWorkspace();
0166     createColorManager();
0167     createPlugins();
0168 
0169     connect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene);
0170 }
0171 
0172 void WaylandTestApplication::continueStartupWithScene()
0173 {
0174     disconnect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene);
0175 
0176     waylandServer()->initWorkspace();
0177 
0178     if (!waylandServer()->start()) {
0179         qFatal("Failed to initialize the Wayland server, exiting now");
0180     }
0181 
0182     if (operationMode() == OperationModeXwayland) {
0183         m_xwayland = std::make_unique<Xwl::Xwayland>(this);
0184         m_xwayland->init();
0185     }
0186 
0187     notifyStarted();
0188 }
0189 
0190 Test::VirtualInputDevice *WaylandTestApplication::virtualPointer() const
0191 {
0192     return m_virtualPointer.get();
0193 }
0194 
0195 Test::VirtualInputDevice *WaylandTestApplication::virtualKeyboard() const
0196 {
0197     return m_virtualKeyboard.get();
0198 }
0199 
0200 Test::VirtualInputDevice *WaylandTestApplication::virtualTouch() const
0201 {
0202     return m_virtualTouch.get();
0203 }
0204 
0205 XwaylandInterface *WaylandTestApplication::xwayland() const
0206 {
0207     return m_xwayland.get();
0208 }
0209 
0210 Test::FractionalScaleManagerV1::~FractionalScaleManagerV1()
0211 {
0212     destroy();
0213 }
0214 
0215 Test::FractionalScaleV1::~FractionalScaleV1()
0216 {
0217     destroy();
0218 }
0219 
0220 int Test::FractionalScaleV1::preferredScale()
0221 {
0222     return m_preferredScale;
0223 }
0224 
0225 void Test::FractionalScaleV1::wp_fractional_scale_v1_preferred_scale(uint32_t scale)
0226 {
0227     m_preferredScale = scale;
0228 }
0229 
0230 void Test::setOutputConfig(const QList<QRect> &geometries)
0231 {
0232     QList<VirtualBackend::OutputInfo> converted;
0233     std::transform(geometries.begin(), geometries.end(), std::back_inserter(converted), [](const auto &geometry) {
0234         return VirtualBackend::OutputInfo{
0235             .geometry = geometry,
0236         };
0237     });
0238     static_cast<VirtualBackend *>(kwinApp()->outputBackend())->setVirtualOutputs(converted);
0239 }
0240 
0241 void Test::setOutputConfig(const QList<OutputInfo> &infos)
0242 {
0243     QList<VirtualBackend::OutputInfo> converted;
0244     std::transform(infos.begin(), infos.end(), std::back_inserter(converted), [](const auto &info) {
0245         return VirtualBackend::OutputInfo{
0246             .geometry = info.geometry,
0247             .scale = info.scale,
0248             .internal = info.internal,
0249         };
0250     });
0251     static_cast<VirtualBackend *>(kwinApp()->outputBackend())->setVirtualOutputs(converted);
0252 }
0253 }
0254 
0255 #include "moc_kwin_wayland_test.cpp"