File indexing completed on 2024-11-10 04:56:00
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"