File indexing completed on 2024-05-05 17:35:49

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 "composite.h"
0013 #include "core/outputbackend.h"
0014 #include "core/session.h"
0015 #include "effects.h"
0016 #include "inputmethod.h"
0017 #include "placement.h"
0018 #include "pluginmanager.h"
0019 #include "utils/xcbutils.h"
0020 #include "wayland_server.h"
0021 #include "workspace.h"
0022 #include "xwayland/xwayland.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 Q_IMPORT_PLUGIN(KGlobalAccelImpl)
0039 Q_IMPORT_PLUGIN(KWindowSystemKWinPlugin)
0040 Q_IMPORT_PLUGIN(KWinIdleTimePoller)
0041 
0042 namespace KWin
0043 {
0044 
0045 WaylandTestApplication::WaylandTestApplication(OperationMode mode, int &argc, char **argv)
0046     : Application(mode, argc, argv)
0047 {
0048     QStandardPaths::setTestModeEnabled(true);
0049     // TODO: add a test move to kglobalaccel instead?
0050     QFile{QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("kglobalshortcutsrc"))}.remove();
0051     QIcon::setThemeName(QStringLiteral("breeze"));
0052 #if KWIN_BUILD_ACTIVITIES
0053     setUseKActivities(false);
0054 #endif
0055     qputenv("KWIN_COMPOSE", QByteArrayLiteral("Q"));
0056     qputenv("XDG_CURRENT_DESKTOP", QByteArrayLiteral("KDE"));
0057     qunsetenv("XKB_DEFAULT_RULES");
0058     qunsetenv("XKB_DEFAULT_MODEL");
0059     qunsetenv("XKB_DEFAULT_LAYOUT");
0060     qunsetenv("XKB_DEFAULT_VARIANT");
0061     qunsetenv("XKB_DEFAULT_OPTIONS");
0062 
0063     auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
0064     KConfigGroup windowsGroup = config->group("Windows");
0065     windowsGroup.writeEntry("Placement", Placement::policyToString(PlacementSmart));
0066     windowsGroup.sync();
0067     setConfig(config);
0068 
0069     const auto ownPath = libraryPaths().last();
0070     removeLibraryPath(ownPath);
0071     addLibraryPath(ownPath);
0072 
0073     setSession(Session::create(Session::Type::Noop));
0074     setOutputBackend(std::make_unique<VirtualBackend>());
0075     WaylandServer::create(this);
0076     setProcessStartupEnvironment(QProcessEnvironment::systemEnvironment());
0077 }
0078 
0079 WaylandTestApplication::~WaylandTestApplication()
0080 {
0081     setTerminating();
0082     // need to unload all effects prior to destroying X connection as they might do X calls
0083     // also before destroy Workspace, as effects might call into Workspace
0084     if (effects) {
0085         static_cast<EffectsHandlerImpl *>(effects)->unloadAllEffects();
0086     }
0087     m_xwayland.reset();
0088     destroyVirtualInputDevices();
0089     destroyColorManager();
0090     destroyWorkspace();
0091     destroyInputMethod();
0092     destroyCompositor();
0093     destroyInput();
0094 }
0095 
0096 void WaylandTestApplication::createVirtualInputDevices()
0097 {
0098     m_virtualKeyboard.reset(new Test::VirtualInputDevice());
0099     m_virtualKeyboard->setName(QStringLiteral("Virtual Keyboard 1"));
0100     m_virtualKeyboard->setKeyboard(true);
0101 
0102     m_virtualPointer.reset(new Test::VirtualInputDevice());
0103     m_virtualPointer->setName(QStringLiteral("Virtual Pointer 1"));
0104     m_virtualPointer->setPointer(true);
0105 
0106     m_virtualTouch.reset(new Test::VirtualInputDevice());
0107     m_virtualTouch->setName(QStringLiteral("Virtual Touch 1"));
0108     m_virtualTouch->setTouch(true);
0109 
0110     input()->addInputDevice(m_virtualPointer.get());
0111     input()->addInputDevice(m_virtualTouch.get());
0112     input()->addInputDevice(m_virtualKeyboard.get());
0113 }
0114 
0115 void WaylandTestApplication::destroyVirtualInputDevices()
0116 {
0117     input()->removeInputDevice(m_virtualPointer.get());
0118     input()->removeInputDevice(m_virtualTouch.get());
0119     input()->removeInputDevice(m_virtualKeyboard.get());
0120 }
0121 
0122 void WaylandTestApplication::performStartup()
0123 {
0124     if (!m_inputMethodServerToStart.isEmpty()) {
0125         createInputMethod();
0126         if (m_inputMethodServerToStart != QStringLiteral("internal")) {
0127             inputMethod()->setInputMethodCommand(m_inputMethodServerToStart);
0128             inputMethod()->setEnabled(true);
0129         }
0130     }
0131 
0132     // first load options - done internally by a different thread
0133     createOptions();
0134     if (!outputBackend()->initialize()) {
0135         std::exit(1);
0136     }
0137 
0138     // try creating the Wayland Backend
0139     createInput();
0140     createVirtualInputDevices();
0141 
0142     WaylandCompositor::create();
0143     connect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene);
0144 }
0145 
0146 void WaylandTestApplication::finalizeStartup()
0147 {
0148     if (m_xwayland) {
0149         disconnect(m_xwayland.get(), &Xwl::Xwayland::errorOccurred, this, &WaylandTestApplication::finalizeStartup);
0150         disconnect(m_xwayland.get(), &Xwl::Xwayland::started, this, &WaylandTestApplication::finalizeStartup);
0151     }
0152     notifyStarted();
0153 }
0154 
0155 void WaylandTestApplication::continueStartupWithScene()
0156 {
0157     disconnect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene);
0158 
0159     createWorkspace();
0160     createColorManager();
0161     createPlugins();
0162 
0163     waylandServer()->initWorkspace();
0164 
0165     if (!waylandServer()->start()) {
0166         qFatal("Failed to initialize the Wayland server, exiting now");
0167     }
0168 
0169     if (operationMode() == OperationModeWaylandOnly) {
0170         finalizeStartup();
0171         return;
0172     }
0173 
0174     m_xwayland = std::make_unique<Xwl::Xwayland>(this);
0175     connect(m_xwayland.get(), &Xwl::Xwayland::errorOccurred, this, &WaylandTestApplication::finalizeStartup);
0176     connect(m_xwayland.get(), &Xwl::Xwayland::started, this, &WaylandTestApplication::finalizeStartup);
0177     m_xwayland->start();
0178 }
0179 
0180 Test::VirtualInputDevice *WaylandTestApplication::virtualPointer() const
0181 {
0182     return m_virtualPointer.get();
0183 }
0184 
0185 Test::VirtualInputDevice *WaylandTestApplication::virtualKeyboard() const
0186 {
0187     return m_virtualKeyboard.get();
0188 }
0189 
0190 Test::VirtualInputDevice *WaylandTestApplication::virtualTouch() const
0191 {
0192     return m_virtualTouch.get();
0193 }
0194 
0195 XwaylandInterface *WaylandTestApplication::xwayland() const
0196 {
0197     return m_xwayland.get();
0198 }
0199 
0200 Test::FractionalScaleManagerV1::~FractionalScaleManagerV1()
0201 {
0202     destroy();
0203 }
0204 
0205 Test::FractionalScaleV1::~FractionalScaleV1()
0206 {
0207     destroy();
0208 }
0209 
0210 int Test::FractionalScaleV1::preferredScale()
0211 {
0212     return m_preferredScale;
0213 }
0214 
0215 void Test::FractionalScaleV1::wp_fractional_scale_v1_preferred_scale(uint32_t scale)
0216 {
0217     m_preferredScale = scale;
0218 }
0219 }