@ -11,38 +11,23 @@
# include <config-kwin.h>
# include "core/output.h"
# include "core/outputbackend.h"
# include "core/outputlayer.h"
# include "core/renderbackend.h"
# include "core/renderlayer.h"
# include "core/renderloop.h"
# include "dbusinterface.h"
# include "effects.h"
# include "ftrace.h"
# include "platformsupport/scenes/opengl/openglbackend.h"
# include "platformsupport/scenes/qpainter/qpainterbackend.h"
# include "scene/cursordelegate_opengl.h"
# include "scene/cursordelegate_qpainter.h"
# include "scene/cursorscene.h"
# include "scene/itemrenderer_opengl.h"
# include "scene/itemrenderer_qpainter.h"
# include "scene/surfaceitem.h"
# include "scene/workspacescene_opengl.h"
# include "scene/workspacescene_qpainter.h"
# include "scene/workspacescene.h"
# include "utils/common.h"
# include "wayland_server.h"
# include "workspace.h"
# include "libkwineffects/glplatform.h"
# include <KLocalizedString>
# if KWIN_BUILD_NOTIFICATIONS
# include <KNotification>
# endif
# include <KSelectionOwner>
# include <QQuickWindow>
# include <xcb/composite.h>
namespace KWin
{
@ -53,32 +38,6 @@ Compositor *Compositor::self()
return s_compositor ;
}
class CompositorSelectionOwner : public KSelectionOwner
{
Q_OBJECT
public :
CompositorSelectionOwner ( const char * selection )
: KSelectionOwner ( selection , kwinApp ( ) - > x11Connection ( ) , kwinApp ( ) - > x11RootWindow ( ) )
, m_owning ( false )
{
connect ( this , & CompositorSelectionOwner : : lostOwnership ,
this , [ this ] ( ) {
m_owning = false ;
} ) ;
}
bool owning ( ) const
{
return m_owning ;
}
void setOwning ( bool own )
{
m_owning = own ;
}
private :
bool m_owning ;
} ;
Compositor : : Compositor ( QObject * workspace )
: QObject ( workspace )
{
@ -88,11 +47,6 @@ Compositor::Compositor(QObject *workspace)
// 2 sec which should be enough to restart the compositor.
static const int compositorLostMessageDelay = 2000 ;
m_releaseSelectionTimer . setSingleShot ( true ) ;
m_releaseSelectionTimer . setInterval ( compositorLostMessageDelay ) ;
connect ( & m_releaseSelectionTimer , & QTimer : : timeout ,
this , & Compositor : : releaseCompositorSelection ) ;
m_unusedSupportPropertyTimer . setInterval ( compositorLostMessageDelay ) ;
m_unusedSupportPropertyTimer . setSingleShot ( true ) ;
connect ( & m_unusedSupportPropertyTimer , & QTimer : : timeout ,
@ -112,228 +66,9 @@ Compositor::Compositor(QObject *workspace)
Compositor : : ~ Compositor ( )
{
deleteUnusedSupportProperties ( ) ;
destroyCompositorSelection ( ) ;
s_compositor = nullptr ;
}
bool Compositor : : attemptOpenGLCompositing ( )
{
// Some broken drivers crash on glXQuery() so to prevent constant KWin crashes:
if ( openGLCompositingIsBroken ( ) ) {
qCWarning ( KWIN_CORE ) < < " KWin has detected that your OpenGL library is unsafe to use " ;
return false ;
}
createOpenGLSafePoint ( OpenGLSafePoint : : PreInit ) ;
auto safePointScope = qScopeGuard ( [ this ] ( ) {
createOpenGLSafePoint ( OpenGLSafePoint : : PostInit ) ;
} ) ;
std : : unique_ptr < OpenGLBackend > backend = kwinApp ( ) - > outputBackend ( ) - > createOpenGLBackend ( ) ;
if ( ! backend ) {
return false ;
}
if ( ! backend - > isFailed ( ) ) {
backend - > init ( ) ;
}
if ( backend - > isFailed ( ) ) {
return false ;
}
const QByteArray forceEnv = qgetenv ( " KWIN_COMPOSE " ) ;
if ( ! forceEnv . isEmpty ( ) ) {
if ( qstrcmp ( forceEnv , " O2 " ) = = 0 | | qstrcmp ( forceEnv , " O2ES " ) = = 0 ) {
qCDebug ( KWIN_CORE ) < < " OpenGL 2 compositing enforced by environment variable " ;
} else {
// OpenGL 2 disabled by environment variable
return false ;
}
} else {
if ( GLPlatform : : instance ( ) - > recommendedCompositor ( ) < OpenGLCompositing ) {
qCDebug ( KWIN_CORE ) < < " Driver does not recommend OpenGL compositing " ;
return false ;
}
}
// We only support the OpenGL 2+ shader API, not GL_ARB_shader_objects
if ( ! hasGLVersion ( 2 , 0 ) ) {
qCDebug ( KWIN_CORE ) < < " OpenGL 2.0 is not supported " ;
return false ;
}
m_scene = std : : make_unique < WorkspaceSceneOpenGL > ( backend . get ( ) ) ;
m_cursorScene = std : : make_unique < CursorScene > ( std : : make_unique < ItemRendererOpenGL > ( ) ) ;
m_backend = std : : move ( backend ) ;
// set strict binding
if ( options - > isGlStrictBindingFollowsDriver ( ) ) {
options - > setGlStrictBinding ( ! GLPlatform : : instance ( ) - > supports ( GLFeature : : LooseBinding ) ) ;
}
qCDebug ( KWIN_CORE ) < < " OpenGL compositing has been successfully initialized " ;
return true ;
}
bool Compositor : : attemptQPainterCompositing ( )
{
std : : unique_ptr < QPainterBackend > backend ( kwinApp ( ) - > outputBackend ( ) - > createQPainterBackend ( ) ) ;
if ( ! backend | | backend - > isFailed ( ) ) {
return false ;
}
m_scene = std : : make_unique < WorkspaceSceneQPainter > ( backend . get ( ) ) ;
m_cursorScene = std : : make_unique < CursorScene > ( std : : make_unique < ItemRendererQPainter > ( ) ) ;
m_backend = std : : move ( backend ) ;
qCDebug ( KWIN_CORE ) < < " QPainter compositing has been successfully initialized " ;
return true ;
}
bool Compositor : : setupStart ( )
{
if ( kwinApp ( ) - > isTerminating ( ) ) {
// Don't start while KWin is terminating. An event to restart might be lingering
// in the event queue due to graphics reset.
return false ;
}
if ( m_state ! = State : : Off ) {
return false ;
}
m_state = State : : Starting ;
if ( kwinApp ( ) - > operationMode ( ) = = Application : : OperationModeX11 ) {
if ( ! m_selectionOwner ) {
m_selectionOwner = std : : make_unique < CompositorSelectionOwner > ( " _NET_WM_CM_S0 " ) ;
connect ( m_selectionOwner . get ( ) , & CompositorSelectionOwner : : lostOwnership , this , & Compositor : : stop ) ;
}
if ( ! m_selectionOwner - > owning ( ) ) {
// Force claim ownership.
m_selectionOwner - > claim ( true ) ;
m_selectionOwner - > setOwning ( true ) ;
}
xcb_composite_redirect_subwindows ( kwinApp ( ) - > x11Connection ( ) ,
kwinApp ( ) - > x11RootWindow ( ) ,
XCB_COMPOSITE_REDIRECT_MANUAL ) ;
}
Q_EMIT aboutToToggleCompositing ( ) ;
const QVector < CompositingType > availableCompositors = kwinApp ( ) - > outputBackend ( ) - > supportedCompositors ( ) ;
QVector < CompositingType > candidateCompositors ;
// If compositing has been restarted, try to use the last used compositing type.
if ( m_selectedCompositor ! = NoCompositing ) {
candidateCompositors . append ( m_selectedCompositor ) ;
} else {
candidateCompositors = availableCompositors ;
const auto userConfigIt = std : : find ( candidateCompositors . begin ( ) , candidateCompositors . end ( ) , options - > compositingMode ( ) ) ;
if ( userConfigIt ! = candidateCompositors . end ( ) ) {
candidateCompositors . erase ( userConfigIt ) ;
candidateCompositors . prepend ( options - > compositingMode ( ) ) ;
} else {
qCWarning ( KWIN_CORE ) < < " Configured compositor not supported by Platform. Falling back to defaults " ;
}
}
for ( auto type : std : : as_const ( candidateCompositors ) ) {
bool stop = false ;
switch ( type ) {
case OpenGLCompositing :
qCDebug ( KWIN_CORE ) < < " Attempting to load the OpenGL scene " ;
stop = attemptOpenGLCompositing ( ) ;
break ;
case QPainterCompositing :
qCDebug ( KWIN_CORE ) < < " Attempting to load the QPainter scene " ;
stop = attemptQPainterCompositing ( ) ;
break ;
case NoCompositing :
qCDebug ( KWIN_CORE ) < < " Starting without compositing... " ;
stop = true ;
break ;
}
if ( stop ) {
break ;
} else if ( qEnvironmentVariableIsSet ( " KWIN_COMPOSE " ) ) {
qCCritical ( KWIN_CORE ) < < " Could not fulfill the requested compositing mode in KWIN_COMPOSE: " < < type < < " . Exiting. " ;
qApp - > quit ( ) ;
}
}
if ( ! m_backend ) {
m_state = State : : Off ;
if ( kwinApp ( ) - > operationMode ( ) = = Application : : OperationModeX11 ) {
xcb_composite_unredirect_subwindows ( kwinApp ( ) - > x11Connection ( ) ,
kwinApp ( ) - > x11RootWindow ( ) ,
XCB_COMPOSITE_REDIRECT_MANUAL ) ;
if ( m_selectionOwner ) {
m_selectionOwner - > setOwning ( false ) ;
m_selectionOwner - > release ( ) ;
}
}
if ( ! availableCompositors . contains ( NoCompositing ) ) {
qCCritical ( KWIN_CORE ) < < " The used windowing system requires compositing " ;
qCCritical ( KWIN_CORE ) < < " We are going to quit KWin now as it is broken " ;
qApp - > quit ( ) ;
}
return false ;
}
m_selectedCompositor = m_backend - > compositingType ( ) ;
if ( ! Workspace : : self ( ) & & m_backend & & m_backend - > compositingType ( ) = = QPainterCompositing ) {
// Force Software QtQuick on first startup with QPainter.
QQuickWindow : : setGraphicsApi ( QSGRendererInterface : : Software ) ;
}
Q_EMIT sceneCreated ( ) ;
return true ;
}
void Compositor : : startupWithWorkspace ( )
{
Q_ASSERT ( m_scene ) ;
m_scene - > initialize ( ) ;
m_cursorScene - > initialize ( ) ;
const QList < Output * > outputs = workspace ( ) - > outputs ( ) ;
if ( kwinApp ( ) - > operationMode ( ) = = Application : : OperationModeX11 ) {
auto workspaceLayer = new RenderLayer ( outputs . constFirst ( ) - > renderLoop ( ) ) ;
workspaceLayer - > setDelegate ( std : : make_unique < SceneDelegate > ( m_scene . get ( ) , nullptr ) ) ;
workspaceLayer - > setGeometry ( workspace ( ) - > geometry ( ) ) ;
connect ( workspace ( ) , & Workspace : : geometryChanged , workspaceLayer , [ workspaceLayer ] ( ) {
workspaceLayer - > setGeometry ( workspace ( ) - > geometry ( ) ) ;
} ) ;
addSuperLayer ( workspaceLayer ) ;
} else {
for ( Output * output : outputs ) {
addOutput ( output ) ;
}
connect ( workspace ( ) , & Workspace : : outputAdded , this , & Compositor : : addOutput ) ;
connect ( workspace ( ) , & Workspace : : outputRemoved , this , & Compositor : : removeOutput ) ;
}
m_state = State : : On ;
const auto windows = workspace ( ) - > windows ( ) ;
for ( Window * window : windows ) {
window - > setupCompositing ( ) ;
}
// Sets also the 'effects' pointer.
kwinApp ( ) - > createEffectsHandler ( this , m_scene . get ( ) ) ;
Q_EMIT compositingToggled ( true ) ;
if ( m_releaseSelectionTimer . isActive ( ) ) {
m_releaseSelectionTimer . stop ( ) ;
}
}
Output * Compositor : : findOutput ( RenderLoop * loop ) const
{
const auto outputs = workspace ( ) - > outputs ( ) ;
@ -345,125 +80,6 @@ Output *Compositor::findOutput(RenderLoop *loop) const
return nullptr ;
}
void Compositor : : addOutput ( Output * output )
{
Q_ASSERT ( kwinApp ( ) - > operationMode ( ) ! = Application : : OperationModeX11 ) ;
auto workspaceLayer = new RenderLayer ( output - > renderLoop ( ) ) ;
workspaceLayer - > setDelegate ( std : : make_unique < SceneDelegate > ( m_scene . get ( ) , output ) ) ;
workspaceLayer - > setGeometry ( output - > rect ( ) ) ;
connect ( output , & Output : : geometryChanged , workspaceLayer , [ output , workspaceLayer ] ( ) {
workspaceLayer - > setGeometry ( output - > rect ( ) ) ;
} ) ;
auto cursorLayer = new RenderLayer ( output - > renderLoop ( ) ) ;
cursorLayer - > setVisible ( false ) ;
if ( m_backend - > compositingType ( ) = = OpenGLCompositing ) {
cursorLayer - > setDelegate ( std : : make_unique < CursorDelegateOpenGL > ( output ) ) ;
} else {
cursorLayer - > setDelegate ( std : : make_unique < CursorDelegateQPainter > ( output ) ) ;
}
cursorLayer - > setParent ( workspaceLayer ) ;
cursorLayer - > setSuperlayer ( workspaceLayer ) ;
static bool valid ;
static const bool forceSoftwareCursor = qEnvironmentVariableIntValue ( " KWIN_FORCE_SW_CURSOR " , & valid ) = = 1 & & valid ;
auto updateCursorLayer = [ this , output , cursorLayer ] ( ) {
const Cursor * cursor = Cursors : : self ( ) - > currentCursor ( ) ;
const QRectF outputLocalRect = output - > mapFromGlobal ( cursor - > geometry ( ) ) ;
const auto outputLayer = m_backend - > cursorLayer ( output ) ;
if ( ! cursor - > isOnOutput ( output ) ) {
if ( outputLayer & & outputLayer - > isEnabled ( ) ) {
outputLayer - > setEnabled ( false ) ;
output - > updateCursorLayer ( ) ;
}
cursorLayer - > setVisible ( false ) ;
return true ;
}
const auto renderHardwareCursor = [ & ] ( ) {
if ( ! outputLayer | | forceSoftwareCursor ) {
return false ;
}
const QMatrix4x4 monitorMatrix = Output : : logicalToNativeMatrix ( output - > rect ( ) , output - > scale ( ) , output - > transform ( ) ) ;
QRectF nativeCursorRect = monitorMatrix . mapRect ( outputLocalRect ) ;
QSize bufferSize ( std : : ceil ( nativeCursorRect . width ( ) ) , std : : ceil ( nativeCursorRect . height ( ) ) ) ;
if ( const auto fixedSize = outputLayer - > fixedSize ( ) ) {
if ( fixedSize - > width ( ) < bufferSize . width ( ) | | fixedSize - > height ( ) < bufferSize . height ( ) ) {
return false ;
}
bufferSize = * fixedSize ;
nativeCursorRect = monitorMatrix . mapRect ( QRectF ( outputLocalRect . topLeft ( ) , QSizeF ( bufferSize ) / output - > scale ( ) ) ) ;
}
outputLayer - > setPosition ( nativeCursorRect . topLeft ( ) ) ;
outputLayer - > setHotspot ( Output : : logicalToNativeMatrix ( QRectF ( QPointF ( ) , QSizeF ( bufferSize ) / output - > scale ( ) ) , output - > scale ( ) , output - > transform ( ) ) . map ( cursor - > hotspot ( ) ) ) ;
outputLayer - > setSize ( bufferSize ) ;
if ( auto beginInfo = outputLayer - > beginFrame ( ) ) {
const RenderTarget & renderTarget = beginInfo - > renderTarget ;
RenderLayer renderLayer ( output - > renderLoop ( ) ) ;
renderLayer . setDelegate ( std : : make_unique < SceneDelegate > ( m_cursorScene . get ( ) , output ) ) ;
renderLayer . setOutputLayer ( outputLayer ) ;
renderLayer . delegate ( ) - > prePaint ( ) ;
renderLayer . delegate ( ) - > paint ( renderTarget , infiniteRegion ( ) ) ;
renderLayer . delegate ( ) - > postPaint ( ) ;
if ( ! outputLayer - > endFrame ( infiniteRegion ( ) , infiniteRegion ( ) ) ) {
return false ;
}
}
outputLayer - > setEnabled ( true ) ;
return output - > updateCursorLayer ( ) ;
} ;
if ( renderHardwareCursor ( ) ) {
cursorLayer - > setVisible ( false ) ;
return true ;
} else {
if ( outputLayer & & outputLayer - > isEnabled ( ) ) {
outputLayer - > setEnabled ( false ) ;
output - > updateCursorLayer ( ) ;
}
cursorLayer - > setVisible ( cursor - > isOnOutput ( output ) ) ;
cursorLayer - > setGeometry ( outputLocalRect ) ;
cursorLayer - > addRepaintFull ( ) ;
return false ;
}
} ;
auto moveCursorLayer = [ this , output , cursorLayer , updateCursorLayer ] ( ) {
const Cursor * cursor = Cursors : : self ( ) - > currentCursor ( ) ;
const QRectF outputLocalRect = output - > mapFromGlobal ( cursor - > geometry ( ) ) ;
const auto outputLayer = m_backend - > cursorLayer ( output ) ;
bool hardwareCursor = false ;
if ( outputLayer ) {
if ( outputLayer - > isEnabled ( ) ) {
const QMatrix4x4 monitorMatrix = Output : : logicalToNativeMatrix ( output - > rect ( ) , output - > scale ( ) , output - > transform ( ) ) ;
const QRectF nativeCursorRect = monitorMatrix . mapRect ( QRectF ( outputLocalRect . topLeft ( ) , outputLayer - > size ( ) / output - > scale ( ) ) ) ;
outputLayer - > setPosition ( nativeCursorRect . topLeft ( ) ) ;
hardwareCursor = output - > updateCursorLayer ( ) ;
} else if ( ! cursorLayer - > isVisible ( ) & & ! forceSoftwareCursor ) {
// this is for the case that the cursor wasn't visible because it was on a different output before
hardwareCursor = updateCursorLayer ( ) ;
}
}
cursorLayer - > setVisible ( cursor - > isOnOutput ( output ) & & ! hardwareCursor ) ;
cursorLayer - > setGeometry ( outputLocalRect ) ;
cursorLayer - > addRepaintFull ( ) ;
} ;
updateCursorLayer ( ) ;
connect ( output , & Output : : geometryChanged , cursorLayer , updateCursorLayer ) ;
connect ( Cursors : : self ( ) , & Cursors : : currentCursorChanged , cursorLayer , updateCursorLayer ) ;
connect ( Cursors : : self ( ) , & Cursors : : hiddenChanged , cursorLayer , updateCursorLayer ) ;
connect ( Cursors : : self ( ) , & Cursors : : positionChanged , cursorLayer , moveCursorLayer ) ;
addSuperLayer ( workspaceLayer ) ;
}
void Compositor : : removeOutput ( Output * output )
{
removeSuperLayer ( m_superlayers [ output - > renderLoop ( ) ] ) ;
}
void Compositor : : addSuperLayer ( RenderLayer * layer )
{
m_superlayers . insert ( layer - > loop ( ) , layer ) ;
@ -477,82 +93,6 @@ void Compositor::removeSuperLayer(RenderLayer *layer)
delete layer ;
}
void Compositor : : stop ( )
{
if ( m_state = = State : : Off | | m_state = = State : : Stopping ) {
return ;
}
m_state = State : : Stopping ;
Q_EMIT aboutToToggleCompositing ( ) ;
m_releaseSelectionTimer . start ( ) ;
// Some effects might need access to effect windows when they are about to
// be destroyed, for example to unreference deleted windows, so we have to
// make sure that effect windows outlive effects.
delete effects ;
effects = nullptr ;
if ( Workspace : : self ( ) ) {
const auto windows = workspace ( ) - > windows ( ) ;
for ( Window * window : windows ) {
window - > finishCompositing ( ) ;
}
if ( kwinApp ( ) - > operationMode ( ) = = Application : : OperationModeX11 ) {
xcb_composite_unredirect_subwindows ( kwinApp ( ) - > x11Connection ( ) ,
kwinApp ( ) - > x11RootWindow ( ) ,
XCB_COMPOSITE_REDIRECT_MANUAL ) ;
}
disconnect ( workspace ( ) , & Workspace : : outputAdded , this , & Compositor : : addOutput ) ;
disconnect ( workspace ( ) , & Workspace : : outputRemoved , this , & Compositor : : removeOutput ) ;
}
if ( m_backend - > compositingType ( ) = = OpenGLCompositing ) {
// some layers need a context current for destruction
static_cast < OpenGLBackend * > ( m_backend . get ( ) ) - > makeCurrent ( ) ;
}
const auto superlayers = m_superlayers ;
for ( auto it = superlayers . begin ( ) ; it ! = superlayers . end ( ) ; + + it ) {
removeSuperLayer ( * it ) ;
}
m_scene . reset ( ) ;
m_cursorScene . reset ( ) ;
m_backend . reset ( ) ;
m_state = State : : Off ;
Q_EMIT compositingToggled ( false ) ;
}
void Compositor : : destroyCompositorSelection ( )
{
m_selectionOwner . reset ( ) ;
}
void Compositor : : releaseCompositorSelection ( )
{
switch ( m_state ) {
case State : : On :
// We are compositing at the moment. Don't release.
break ;
case State : : Off :
if ( m_selectionOwner ) {
qCDebug ( KWIN_CORE ) < < " Releasing compositor selection " ;
m_selectionOwner - > setOwning ( false ) ;
m_selectionOwner - > release ( ) ;
}
break ;
case State : : Starting :
case State : : Stopping :
// Still starting or shutting down the compositor. Starting might fail
// or after stopping a restart might follow. So test again later on.
m_releaseSelectionTimer . start ( ) ;
break ;
}
}
void Compositor : : keepSupportProperty ( xcb_atom_t atom )
{
m_unusedSupportProperties . removeAll ( atom ) ;
@ -750,10 +290,6 @@ bool Compositor::openGLCompositingIsBroken() const
return false ;
}
void Compositor : : createOpenGLSafePoint ( OpenGLSafePoint safePoint )
{
}
void Compositor : : inhibit ( Window * window )
{
}
@ -764,7 +300,4 @@ void Compositor::uninhibit(Window *window)
} // namespace KWin
// included for CompositorSelectionOwner
# include "compositor.moc"
# include "moc_compositor.cpp"