File indexing completed on 2024-11-10 04:57:42
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "compositor_x11.h" 0011 #include "core/outputbackend.h" 0012 #include "core/overlaywindow.h" 0013 #include "core/renderbackend.h" 0014 #include "core/renderlayer.h" 0015 #include "effect/effecthandler.h" 0016 #include "opengl/glplatform.h" 0017 #include "options.h" 0018 #include "platformsupport/scenes/opengl/openglbackend.h" 0019 #include "scene/surfaceitem_x11.h" 0020 #include "scene/workspacescene_opengl.h" 0021 #include "utils/common.h" 0022 #include "utils/xcbutils.h" 0023 #include "window.h" 0024 #include "workspace.h" 0025 #include "x11syncmanager.h" 0026 0027 #include <KCrash> 0028 #include <KGlobalAccel> 0029 #include <KLocalizedString> 0030 #include <KSelectionOwner> 0031 0032 #include <QAction> 0033 #include <QOpenGLContext> 0034 #include <QThread> 0035 0036 Q_DECLARE_METATYPE(KWin::X11Compositor::SuspendReason) 0037 0038 namespace KWin 0039 { 0040 0041 class X11CompositorSelectionOwner : public KSelectionOwner 0042 { 0043 Q_OBJECT 0044 0045 public: 0046 X11CompositorSelectionOwner(const char *selection) 0047 : KSelectionOwner(selection, kwinApp()->x11Connection(), kwinApp()->x11RootWindow()) 0048 , m_owning(false) 0049 { 0050 connect(this, &X11CompositorSelectionOwner::lostOwnership, this, [this]() { 0051 m_owning = false; 0052 }); 0053 } 0054 bool owning() const 0055 { 0056 return m_owning; 0057 } 0058 void setOwning(bool own) 0059 { 0060 m_owning = own; 0061 } 0062 0063 private: 0064 bool m_owning; 0065 }; 0066 0067 X11Compositor *X11Compositor::create(QObject *parent) 0068 { 0069 Q_ASSERT(!s_compositor); 0070 auto *compositor = new X11Compositor(parent); 0071 s_compositor = compositor; 0072 return compositor; 0073 } 0074 0075 X11Compositor::X11Compositor(QObject *parent) 0076 : Compositor(parent) 0077 , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) 0078 { 0079 if (qEnvironmentVariableIsSet("KWIN_MAX_FRAMES_TESTED")) { 0080 m_framesToTestForSafety = qEnvironmentVariableIntValue("KWIN_MAX_FRAMES_TESTED"); 0081 } 0082 0083 connect(options, &Options::configChanged, this, [this]() { 0084 if (m_suspended) { 0085 stop(); 0086 } else { 0087 reinitialize(); 0088 } 0089 }); 0090 0091 m_releaseSelectionTimer.setSingleShot(true); 0092 m_releaseSelectionTimer.setInterval(2000); 0093 connect(&m_releaseSelectionTimer, &QTimer::timeout, this, &X11Compositor::releaseCompositorSelection); 0094 0095 QAction *toggleAction = new QAction(this); 0096 toggleAction->setProperty("componentName", QStringLiteral("kwin")); 0097 toggleAction->setObjectName("Suspend Compositing"); 0098 toggleAction->setText(i18n("Suspend Compositing")); 0099 KGlobalAccel::self()->setDefaultShortcut(toggleAction, QList<QKeySequence>() << (Qt::SHIFT | Qt::ALT | Qt::Key_F12)); 0100 KGlobalAccel::self()->setShortcut(toggleAction, QList<QKeySequence>() << (Qt::SHIFT | Qt::ALT | Qt::Key_F12)); 0101 connect(toggleAction, &QAction::triggered, this, &X11Compositor::toggle); 0102 } 0103 0104 X11Compositor::~X11Compositor() 0105 { 0106 Q_EMIT aboutToDestroy(); 0107 if (m_openGLFreezeProtectionThread) { 0108 m_openGLFreezeProtectionThread->quit(); 0109 m_openGLFreezeProtectionThread->wait(); 0110 } 0111 stop(); // this can't be called in the destructor of Compositor 0112 destroyCompositorSelection(); 0113 } 0114 0115 X11SyncManager *X11Compositor::syncManager() const 0116 { 0117 return m_syncManager.get(); 0118 } 0119 0120 void X11Compositor::toggle() 0121 { 0122 if (m_suspended) { 0123 // Direct user call; clear all bits. 0124 resume(AllReasonSuspend); 0125 } else { 0126 // But only set the user one (sufficient to suspend). 0127 suspend(UserSuspend); 0128 } 0129 } 0130 0131 void X11Compositor::reinitialize() 0132 { 0133 // Resume compositing if suspended. 0134 m_suspended = NoReasonSuspend; 0135 m_inhibitors.clear(); 0136 Compositor::reinitialize(); 0137 } 0138 0139 void X11Compositor::suspend(X11Compositor::SuspendReason reason) 0140 { 0141 Q_ASSERT(reason != NoReasonSuspend); 0142 m_suspended |= reason; 0143 stop(); 0144 } 0145 0146 void X11Compositor::resume(X11Compositor::SuspendReason reason) 0147 { 0148 Q_ASSERT(reason != NoReasonSuspend); 0149 m_suspended &= ~reason; 0150 if (reason & BlockRuleSuspend) { 0151 m_inhibitors.clear(); 0152 } 0153 start(); 0154 } 0155 0156 void X11Compositor::destroyCompositorSelection() 0157 { 0158 m_selectionOwner.reset(); 0159 } 0160 0161 void X11Compositor::releaseCompositorSelection() 0162 { 0163 switch (m_state) { 0164 case State::On: 0165 // We are compositing at the moment. Don't release. 0166 break; 0167 case State::Off: 0168 if (m_selectionOwner) { 0169 qCDebug(KWIN_CORE) << "Releasing compositor selection"; 0170 m_selectionOwner->setOwning(false); 0171 m_selectionOwner->release(); 0172 } 0173 break; 0174 case State::Starting: 0175 case State::Stopping: 0176 // Still starting or shutting down the compositor. Starting might fail 0177 // or after stopping a restart might follow. So test again later on. 0178 m_releaseSelectionTimer.start(); 0179 break; 0180 } 0181 } 0182 0183 bool X11Compositor::attemptOpenGLCompositing() 0184 { 0185 // Some broken drivers crash on glXQuery() so to prevent constant KWin crashes: 0186 if (openGLCompositingIsBroken()) { 0187 qCWarning(KWIN_CORE) << "KWin has detected that your OpenGL library is unsafe to use"; 0188 return false; 0189 } 0190 0191 createOpenGLSafePoint(OpenGLSafePoint::PreInit); 0192 auto safePointScope = qScopeGuard([this]() { 0193 createOpenGLSafePoint(OpenGLSafePoint::PostInit); 0194 }); 0195 0196 std::unique_ptr<OpenGLBackend> backend = kwinApp()->outputBackend()->createOpenGLBackend(); 0197 if (!backend) { 0198 return false; 0199 } 0200 if (!backend->isFailed()) { 0201 backend->init(); 0202 } 0203 if (backend->isFailed()) { 0204 return false; 0205 } 0206 0207 const QByteArray forceEnv = qgetenv("KWIN_COMPOSE"); 0208 if (!forceEnv.isEmpty()) { 0209 if (qstrcmp(forceEnv, "O2") == 0 || qstrcmp(forceEnv, "O2ES") == 0) { 0210 qCDebug(KWIN_CORE) << "OpenGL 2 compositing enforced by environment variable"; 0211 } else { 0212 // OpenGL 2 disabled by environment variable 0213 return false; 0214 } 0215 } else { 0216 if (GLPlatform::instance()->recommendedCompositor() < OpenGLCompositing) { 0217 qCDebug(KWIN_CORE) << "Driver does not recommend OpenGL compositing"; 0218 return false; 0219 } 0220 } 0221 0222 // We only support the OpenGL 2+ shader API, not GL_ARB_shader_objects 0223 if (!hasGLVersion(2, 0)) { 0224 qCDebug(KWIN_CORE) << "OpenGL 2.0 is not supported"; 0225 return false; 0226 } 0227 0228 m_scene = std::make_unique<WorkspaceSceneOpenGL>(backend.get()); 0229 m_backend = std::move(backend); 0230 0231 // set strict binding 0232 if (options->isGlStrictBindingFollowsDriver()) { 0233 options->setGlStrictBinding(!GLPlatform::instance()->supports(GLFeature::LooseBinding)); 0234 } 0235 0236 qCDebug(KWIN_CORE) << "OpenGL compositing has been successfully initialized"; 0237 return true; 0238 } 0239 0240 void X11Compositor::start() 0241 { 0242 if (m_suspended) { 0243 QStringList reasons; 0244 if (m_suspended & UserSuspend) { 0245 reasons << QStringLiteral("Disabled by User"); 0246 } 0247 if (m_suspended & BlockRuleSuspend) { 0248 reasons << QStringLiteral("Disabled by Window"); 0249 } 0250 qCInfo(KWIN_CORE) << "Compositing is suspended, reason:" << reasons; 0251 return; 0252 } else if (!compositingPossible()) { 0253 qCWarning(KWIN_CORE) << "Compositing is not possible"; 0254 return; 0255 } 0256 0257 if (kwinApp()->isTerminating()) { 0258 return; 0259 } 0260 if (m_state != State::Off) { 0261 return; 0262 } 0263 0264 Q_EMIT aboutToToggleCompositing(); 0265 m_state = State::Starting; 0266 0267 // Claim special _NET_WM_CM_S0 selection and redirect child windows of the root window. 0268 if (!m_selectionOwner) { 0269 m_selectionOwner = std::make_unique<X11CompositorSelectionOwner>("_NET_WM_CM_S0"); 0270 connect(m_selectionOwner.get(), &X11CompositorSelectionOwner::lostOwnership, this, &X11Compositor::stop); 0271 } 0272 if (!m_selectionOwner->owning()) { 0273 // Force claim ownership. 0274 m_selectionOwner->claim(true); 0275 m_selectionOwner->setOwning(true); 0276 } 0277 0278 xcb_composite_redirect_subwindows(kwinApp()->x11Connection(), 0279 kwinApp()->x11RootWindow(), 0280 XCB_COMPOSITE_REDIRECT_MANUAL); 0281 0282 // Decide what compositing types can be used. 0283 QList<CompositingType> candidateCompositors = kwinApp()->outputBackend()->supportedCompositors(); 0284 const auto userConfigIt = std::find(candidateCompositors.begin(), candidateCompositors.end(), options->compositingMode()); 0285 if (userConfigIt != candidateCompositors.end()) { 0286 candidateCompositors.erase(userConfigIt); 0287 candidateCompositors.prepend(options->compositingMode()); 0288 } else { 0289 qCWarning(KWIN_CORE) << "Configured compositor not supported by Platform. Falling back to defaults"; 0290 } 0291 0292 for (auto type : std::as_const(candidateCompositors)) { 0293 bool stop = false; 0294 switch (type) { 0295 case OpenGLCompositing: 0296 qCDebug(KWIN_CORE) << "Attempting to load the OpenGL scene"; 0297 stop = attemptOpenGLCompositing(); 0298 break; 0299 case QPainterCompositing: 0300 qCDebug(KWIN_CORE) << "QPainter compositing is unsupported on X11"; 0301 break; 0302 case NoCompositing: 0303 qCDebug(KWIN_CORE) << "Starting without compositing..."; 0304 stop = true; 0305 break; 0306 } 0307 0308 if (stop) { 0309 break; 0310 } else if (qEnvironmentVariableIsSet("KWIN_COMPOSE")) { 0311 qCCritical(KWIN_CORE) << "Could not fulfill the requested compositing mode in KWIN_COMPOSE:" << type << ". Exiting."; 0312 qApp->quit(); 0313 } 0314 } 0315 0316 if (!m_backend) { 0317 m_state = State::Off; 0318 0319 xcb_composite_unredirect_subwindows(kwinApp()->x11Connection(), 0320 kwinApp()->x11RootWindow(), 0321 XCB_COMPOSITE_REDIRECT_MANUAL); 0322 if (m_selectionOwner) { 0323 m_selectionOwner->setOwning(false); 0324 m_selectionOwner->release(); 0325 } 0326 return; 0327 } 0328 0329 Q_EMIT sceneCreated(); 0330 0331 kwinApp()->setX11CompositeWindow(backend()->overlayWindow()->window()); 0332 0333 auto workspaceLayer = new RenderLayer(workspace()->outputs()[0]->renderLoop()); 0334 workspaceLayer->setDelegate(std::make_unique<SceneDelegate>(m_scene.get(), nullptr)); 0335 workspaceLayer->setGeometry(workspace()->geometry()); 0336 connect(workspace(), &Workspace::geometryChanged, workspaceLayer, [workspaceLayer]() { 0337 workspaceLayer->setGeometry(workspace()->geometry()); 0338 }); 0339 addSuperLayer(workspaceLayer); 0340 0341 m_state = State::On; 0342 0343 const auto windows = workspace()->windows(); 0344 for (Window *window : windows) { 0345 window->setupCompositing(); 0346 } 0347 0348 // Sets also the 'effects' pointer. 0349 kwinApp()->createEffectsHandler(this, m_scene.get()); 0350 0351 m_syncManager.reset(X11SyncManager::create()); 0352 if (m_releaseSelectionTimer.isActive()) { 0353 m_releaseSelectionTimer.stop(); 0354 } 0355 0356 Q_EMIT compositingToggled(true); 0357 } 0358 0359 void X11Compositor::stop() 0360 { 0361 if (m_state == State::Off || m_state == State::Stopping) { 0362 return; 0363 } 0364 m_state = State::Stopping; 0365 Q_EMIT aboutToToggleCompositing(); 0366 0367 m_releaseSelectionTimer.start(); 0368 0369 // Some effects might need access to effect windows when they are about to 0370 // be destroyed, for example to unreference deleted windows, so we have to 0371 // make sure that effect windows outlive effects. 0372 delete effects; 0373 effects = nullptr; 0374 0375 if (Workspace::self()) { 0376 const auto windows = workspace()->windows(); 0377 for (Window *window : windows) { 0378 window->finishCompositing(); 0379 } 0380 xcb_composite_unredirect_subwindows(kwinApp()->x11Connection(), 0381 kwinApp()->x11RootWindow(), 0382 XCB_COMPOSITE_REDIRECT_MANUAL); 0383 } 0384 0385 if (m_backend->compositingType() == OpenGLCompositing) { 0386 // some layers need a context current for destruction 0387 static_cast<OpenGLBackend *>(m_backend.get())->makeCurrent(); 0388 } 0389 0390 const auto superlayers = m_superlayers; 0391 for (auto it = superlayers.begin(); it != superlayers.end(); ++it) { 0392 removeSuperLayer(*it); 0393 } 0394 0395 m_syncManager.reset(); 0396 m_scene.reset(); 0397 m_backend.reset(); 0398 0399 kwinApp()->setX11CompositeWindow(XCB_WINDOW_NONE); 0400 0401 m_state = State::Off; 0402 Q_EMIT compositingToggled(false); 0403 } 0404 0405 void X11Compositor::composite(RenderLoop *renderLoop) 0406 { 0407 if (backend()->overlayWindow() && !backend()->overlayWindow()->isVisible()) { 0408 // Return since nothing is visible. 0409 return; 0410 } 0411 0412 QList<Window *> windows = workspace()->stackingOrder(); 0413 QList<SurfaceItemX11 *> dirtyItems; 0414 0415 // Reset the damage state of each window and fetch the damage region 0416 // without waiting for a reply 0417 for (Window *window : std::as_const(windows)) { 0418 SurfaceItemX11 *surfaceItem = static_cast<SurfaceItemX11 *>(window->surfaceItem()); 0419 if (surfaceItem->fetchDamage()) { 0420 dirtyItems.append(surfaceItem); 0421 } 0422 } 0423 0424 if (dirtyItems.count() > 0) { 0425 if (m_syncManager) { 0426 m_syncManager->triggerFence(); 0427 } 0428 xcb_flush(kwinApp()->x11Connection()); 0429 } 0430 0431 // Get the replies 0432 for (SurfaceItemX11 *item : std::as_const(dirtyItems)) { 0433 item->waitForDamage(); 0434 } 0435 0436 if (m_framesToTestForSafety > 0 && (backend()->compositingType() & OpenGLCompositing)) { 0437 createOpenGLSafePoint(OpenGLSafePoint::PreFrame); 0438 } 0439 0440 Compositor::composite(renderLoop); 0441 0442 if (m_syncManager) { 0443 if (!m_syncManager->endFrame()) { 0444 qCDebug(KWIN_CORE) << "Aborting explicit synchronization with the X command stream."; 0445 qCDebug(KWIN_CORE) << "Future frames will be rendered unsynchronized."; 0446 m_syncManager.reset(); 0447 } 0448 } 0449 0450 if (m_framesToTestForSafety > 0) { 0451 if (backend()->compositingType() & OpenGLCompositing) { 0452 createOpenGLSafePoint(OpenGLSafePoint::PostFrame); 0453 } 0454 m_framesToTestForSafety--; 0455 if (m_framesToTestForSafety == 0 && (backend()->compositingType() & OpenGLCompositing)) { 0456 createOpenGLSafePoint(OpenGLSafePoint::PostLastGuardedFrame); 0457 } 0458 } 0459 } 0460 0461 void X11Compositor::inhibit(Window *window) 0462 { 0463 m_inhibitors.insert(window); 0464 // Do NOT attempt to call suspend(true) from within the eventchain! 0465 if (!(m_suspended & BlockRuleSuspend)) { 0466 QMetaObject::invokeMethod( 0467 this, [this]() { 0468 suspend(BlockRuleSuspend); 0469 }, 0470 Qt::QueuedConnection); 0471 } 0472 } 0473 0474 void X11Compositor::uninhibit(Window *window) 0475 { 0476 if (!m_inhibitors.remove(window)) { 0477 return; 0478 } 0479 if (m_suspended & BlockRuleSuspend) { 0480 if (m_inhibitors.isEmpty()) { 0481 // Do NOT attempt to call suspend(false) from within the eventchain! 0482 QMetaObject::invokeMethod( 0483 this, [this]() { 0484 resume(BlockRuleSuspend); 0485 }, 0486 Qt::QueuedConnection); 0487 } 0488 } 0489 } 0490 0491 X11Compositor *X11Compositor::self() 0492 { 0493 return qobject_cast<X11Compositor *>(Compositor::self()); 0494 } 0495 0496 bool X11Compositor::openGLCompositingIsBroken() const 0497 { 0498 auto timestamp = KConfigGroup(kwinApp()->config(), QStringLiteral("Compositing")).readEntry(QLatin1String("LastFailureTimestamp"), 0); 0499 if (timestamp > 0) { 0500 if (QDateTime::currentSecsSinceEpoch() - timestamp < 60) { 0501 return true; 0502 } 0503 } 0504 0505 return false; 0506 } 0507 0508 QString X11Compositor::compositingNotPossibleReason() const 0509 { 0510 // first off, check whether we figured that we'll crash on detection because of a buggy driver 0511 KConfigGroup gl_workaround_group(kwinApp()->config(), QStringLiteral("Compositing")); 0512 if (gl_workaround_group.readEntry("Backend", "OpenGL") == QLatin1String("OpenGL") && openGLCompositingIsBroken()) { 0513 return i18n("<b>OpenGL compositing (the default) has crashed KWin in the past.</b><br>" 0514 "This was most likely due to a driver bug." 0515 "<p>If you think that you have meanwhile upgraded to a stable driver,<br>" 0516 "you can reset this protection but <b>be aware that this might result in an immediate crash!</b></p>"); 0517 } 0518 0519 if (!Xcb::Extensions::self()->isCompositeAvailable() || !Xcb::Extensions::self()->isDamageAvailable()) { 0520 return i18n("Required X extensions (XComposite and XDamage) are not available."); 0521 } 0522 if (!Xcb::Extensions::self()->hasGlx()) { 0523 return i18n("GLX/OpenGL is not available."); 0524 } 0525 return QString(); 0526 } 0527 0528 bool X11Compositor::compositingPossible() const 0529 { 0530 // first off, check whether we figured that we'll crash on detection because of a buggy driver 0531 KConfigGroup gl_workaround_group(kwinApp()->config(), QStringLiteral("Compositing")); 0532 if (gl_workaround_group.readEntry("Backend", "OpenGL") == QLatin1String("OpenGL") && openGLCompositingIsBroken()) { 0533 qCWarning(KWIN_CORE) << "Compositing disabled: video driver seems unstable. If you think it's a false positive, please try again in a few minutes."; 0534 return false; 0535 } 0536 0537 if (!Xcb::Extensions::self()->isCompositeAvailable()) { 0538 qCWarning(KWIN_CORE) << "Compositing disabled: no composite extension available"; 0539 return false; 0540 } 0541 if (!Xcb::Extensions::self()->isDamageAvailable()) { 0542 qCWarning(KWIN_CORE) << "Compositing disabled: no damage extension available"; 0543 return false; 0544 } 0545 if (Xcb::Extensions::self()->hasGlx()) { 0546 return true; 0547 } 0548 if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { 0549 return true; 0550 } else if (qstrcmp(qgetenv("KWIN_COMPOSE"), "O2ES") == 0) { 0551 return true; 0552 } 0553 qCWarning(KWIN_CORE) << "Compositing disabled: no OpenGL support"; 0554 return false; 0555 } 0556 0557 void X11Compositor::createOpenGLSafePoint(OpenGLSafePoint safePoint) 0558 { 0559 auto group = KConfigGroup(kwinApp()->config(), QStringLiteral("Compositing")); 0560 switch (safePoint) { 0561 case OpenGLSafePoint::PreInit: 0562 // Explicitly write the failure timestamp so that if we crash during 0563 // OpenGL init, we know we should not try again. 0564 group.writeEntry(QLatin1String("LastFailureTimestamp"), QDateTime::currentSecsSinceEpoch()); 0565 group.sync(); 0566 // Deliberately continue with PreFrame 0567 Q_FALLTHROUGH(); 0568 case OpenGLSafePoint::PreFrame: 0569 if (m_openGLFreezeProtectionThread == nullptr) { 0570 Q_ASSERT(m_openGLFreezeProtection == nullptr); 0571 m_openGLFreezeProtectionThread = std::make_unique<QThread>(); 0572 m_openGLFreezeProtectionThread->setObjectName("FreezeDetector"); 0573 m_openGLFreezeProtectionThread->start(); 0574 m_openGLFreezeProtection = std::make_unique<QTimer>(); 0575 m_openGLFreezeProtection->setInterval(15000); 0576 m_openGLFreezeProtection->setSingleShot(true); 0577 m_openGLFreezeProtection->start(); 0578 const QString configName = kwinApp()->config()->name(); 0579 m_openGLFreezeProtection->moveToThread(m_openGLFreezeProtectionThread.get()); 0580 connect( 0581 m_openGLFreezeProtection.get(), &QTimer::timeout, m_openGLFreezeProtection.get(), 0582 [configName] { 0583 auto group = KConfigGroup(KSharedConfig::openConfig(configName), QStringLiteral("Compositing")); 0584 group.writeEntry(QLatin1String("LastFailureTimestamp"), QDateTime::currentSecsSinceEpoch()); 0585 group.sync(); 0586 KCrash::setDrKonqiEnabled(false); 0587 qFatal("Freeze in OpenGL initialization detected"); 0588 }, 0589 Qt::DirectConnection); 0590 } else { 0591 Q_ASSERT(m_openGLFreezeProtection); 0592 QMetaObject::invokeMethod(m_openGLFreezeProtection.get(), QOverload<>::of(&QTimer::start), Qt::QueuedConnection); 0593 } 0594 break; 0595 case OpenGLSafePoint::PostInit: 0596 group.deleteEntry(QLatin1String("LastFailureTimestamp")); 0597 group.sync(); 0598 // Deliberately continue with PostFrame 0599 Q_FALLTHROUGH(); 0600 case OpenGLSafePoint::PostFrame: 0601 QMetaObject::invokeMethod(m_openGLFreezeProtection.get(), &QTimer::stop, Qt::QueuedConnection); 0602 break; 0603 case OpenGLSafePoint::PostLastGuardedFrame: 0604 m_openGLFreezeProtectionThread->quit(); 0605 m_openGLFreezeProtectionThread->wait(); 0606 m_openGLFreezeProtectionThread.reset(); 0607 m_openGLFreezeProtection.reset(); 0608 break; 0609 } 0610 } 0611 0612 } // namespace KWin 0613 0614 #include "compositor_x11.moc" 0615 #include "moc_compositor_x11.cpp"