diff --git a/kstyle/breezeshadowhelper.h b/kstyle/breezeshadowhelper.h --- a/kstyle/breezeshadowhelper.h +++ b/kstyle/breezeshadowhelper.h @@ -3,6 +3,7 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * + * Copyright (C) 2020 by Vlad Zahorodnii * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -23,26 +24,12 @@ #include "breezetileset.h" #include "config-breeze.h" -#include -#include +#include + #include #include - -#if BREEZE_HAVE_X11 -#include -#endif - -#if BREEZE_HAVE_KWAYLAND -namespace KWayland -{ - namespace Client - { - class ShadowManager; - class ShmPool; - class Surface; - } -} -#endif +#include +#include namespace Breeze { @@ -131,9 +118,6 @@ //* unregister widget void objectDeleted( QObject* ); - //* initializes the Wayland specific parts - void initializeWayland(); - protected: //* true if widget is a menu @@ -151,75 +135,48 @@ //* accept widget bool acceptWidget( QWidget* ) const; - // create pixmap handles from tileset - const QVector& createPixmapHandles(); - - // create pixmap handle from pixmap - quint32 createPixmap( const QPixmap& ); - //* installs shadow on given widget in a platform independent way bool installShadows( QWidget * ); //* uninstalls shadow on given widget in a platform independent way - void uninstallShadows( QWidget * ) const; - - //* install shadow X11 property on given widget - /** - shadow atom and property specification available at - https://community.kde.org/KWin/Shadow - */ - bool installX11Shadows( QWidget* ); - - //* uninstall shadow X11 property on given widget - void uninstallX11Shadows( QWidget* ) const; - - //* install shadow on given widget for Wayland - bool installWaylandShadows( QWidget * ); - - //* uninstall shadow on given widget for Wayland - void uninstallWaylandShadows( QWidget* ) const; + void uninstallShadows( QWidget * ); //* gets the shadow margins for the given widget QMargins shadowMargins( QWidget* ) const; + //* gets or creates shared kwindowsystem shadow tiles + KWindowShadowTile::Ptr getOrCreateLeftTile(); + KWindowShadowTile::Ptr getOrCreateTopLeftTile(); + KWindowShadowTile::Ptr getOrCreateTopTile(); + KWindowShadowTile::Ptr getOrCreateTopRightTile(); + KWindowShadowTile::Ptr getOrCreateRightTile(); + KWindowShadowTile::Ptr getOrCreateBottomRightTile(); + KWindowShadowTile::Ptr getOrCreateBottomTile(); + KWindowShadowTile::Ptr getOrCreateBottomLeftTile(); + private: //* helper Helper& _helper; //* registered widgets - QMap _widgets; - - //* tileset - TileSet _shadowTiles; - - //* number of pixmaps - enum { numPixmaps = 8 }; - - //* pixmaps - QVector _pixmaps; + QSet _widgets; - #if BREEZE_HAVE_X11 + //* managed shadows + QMap _shadows; - //* graphical context - xcb_gcontext_t _gc = 0; + //* shared platform shadow tiles + QWeakPointer _leftTile; + QWeakPointer _topLeftTile; + QWeakPointer _topTile; + QWeakPointer _topRightTile; + QWeakPointer _rightTile; + QWeakPointer _bottomRightTile; + QWeakPointer _bottomTile; + QWeakPointer _bottomLeftTile; - //* shadow atom - xcb_atom_t _atom = 0; - - #endif - - #if BREEZE_HAVE_KWAYLAND - - //* registered widgets to wayland surface mappings - QMap _widgetSurfaces; - - //* The Wayland shadow manager to create Shadows for Surfaces (QWindow) - QPointer _shadowManager; - - //* The Wayland Shared memory pool to share the shadow pixmaps with compositor - QPointer _shmPool; - #endif + //* tileset + TileSet _shadowTiles; }; diff --git a/kstyle/breezeshadowhelper.cpp b/kstyle/breezeshadowhelper.cpp --- a/kstyle/breezeshadowhelper.cpp +++ b/kstyle/breezeshadowhelper.cpp @@ -1,6 +1,6 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * - * Copyright (C) 2018 by Vlad Zagorodniy * + * Copyright (C) 2018, 2020 by Vlad Zahorodnii * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -32,22 +32,10 @@ #include #include #include +#include #include #include -#if BREEZE_HAVE_X11 -#include -#endif - -#if BREEZE_HAVE_KWAYLAND -#include -#include -#include -#include -#include -#include -#endif - namespace { using Breeze::CompositeShadowParams; @@ -82,8 +70,6 @@ namespace Breeze { - const char ShadowHelper::netWMShadowAtomName[] ="_KDE_NET_WM_SHADOW"; - //_____________________________________________________ CompositeShadowParams ShadowHelper::lookupShadowParams(int shadowSizeEnum) { @@ -111,61 +97,25 @@ QObject( parent ), _helper( helper ) { - // delay till event dispatcher is running as Wayland is highly async - QMetaObject::invokeMethod(this, "initializeWayland", Qt::QueuedConnection); } //_______________________________________________________ ShadowHelper::~ShadowHelper() { - - #if BREEZE_HAVE_X11 - if( Helper::isX11() ) - { foreach( const quint32& value, _pixmaps ) xcb_free_pixmap( Helper::connection(), value ); } - #endif - - } - - //_______________________________________________________ - void ShadowHelper::initializeWayland() - { - #if BREEZE_HAVE_KWAYLAND - if( !Helper::isWayland() ) return; - - using namespace KWayland::Client; - auto connection = ConnectionThread::fromApplication( this ); - if( !connection ) { - return; - } - auto registry = new Registry( connection ); - registry->create( connection ); - connect(registry, &Registry::interfacesAnnounced, this, - [registry, this] { - const auto interface = registry->interface( Registry::Interface::Shadow ); - if( interface.name != 0 ) { - _shadowManager = registry->createShadowManager( interface.name, interface.version, registry ); - } - const auto shmInterface = registry->interface( Registry::Interface::Shm ); - if( shmInterface.name != 0 ) { - _shmPool = registry->createShmPool( shmInterface.name, shmInterface.version, registry ); - } - } - ); - - registry->setup(); - connection->roundtrip(); - #endif + qDeleteAll( _shadows ); } //______________________________________________ void ShadowHelper::reset() { - #if BREEZE_HAVE_X11 - if( Helper::isX11() ) - { foreach( const quint32& value, _pixmaps ) xcb_free_pixmap( Helper::connection(), value ); } - #endif - - _pixmaps.clear(); + _leftTile = nullptr; + _topLeftTile = nullptr; + _topTile = nullptr; + _topRightTile = nullptr; + _rightTile = nullptr; + _bottomRightTile = nullptr; + _bottomTile = nullptr; + _bottomLeftTile = nullptr; _shadowTiles = TileSet(); } @@ -181,8 +131,8 @@ { return false; } // try create shadow directly - if( installShadows( widget ) ) _widgets.insert( widget, widget->winId() ); - else _widgets.insert( widget, 0 ); + installShadows( widget ); + _widgets.insert( widget ); // install event filter widget->removeEventFilter( this ); @@ -206,55 +156,49 @@ void ShadowHelper::loadConfig() { + // uninstall "old" shadows + qDeleteAll( _shadows ); + _shadows.clear(); + // reset reset(); // update property for registered widgets - for( QMap::const_iterator iter = _widgets.constBegin(); iter != _widgets.constEnd(); ++iter ) - { installShadows( iter.key() ); } + for( QWidget* widget : _widgets ) + { installShadows( widget ); } } //_______________________________________________________ bool ShadowHelper::eventFilter( QObject* object, QEvent* event ) { - if( Helper::isWayland() ) - { - - #if BREEZE_HAVE_KWAYLAND - QWidget* widget( static_cast( object ) ); - if( event->type() == QEvent::Paint ) - { - - auto iter = _widgetSurfaces.constFind( widget ); - if( iter == _widgetSurfaces.constEnd() ) - { - // install shadows and update winId - installShadows( widget ); - } - - } else if( event->type() == QEvent::Hide ) { - - auto iter = _widgetSurfaces.find( widget ); - if( iter != _widgetSurfaces.end() ) - { - _widgetSurfaces.erase( iter ); - } - - } - #endif - - } else if( Helper::isX11() ) { + if( Helper::isX11() ) { // check event type if( event->type() != QEvent::WinIdChange ) return false; // cast widget QWidget* widget( static_cast( object ) ); - // install shadows and update winId - if( installShadows( widget ) ) - { _widgets.insert( widget, widget->winId() ); } + // reinstall shadows + uninstallShadows( widget ); + installShadows( widget ); + } else { + + if( event->type() != QEvent::PlatformSurface ) return false; + + QWidget* widget( static_cast( object ) ); + QPlatformSurfaceEvent* surfaceEvent( static_cast( event ) ); + + switch( surfaceEvent->surfaceEventType() ) + { + case QPlatformSurfaceEvent::SurfaceCreated: + installShadows( widget ); + break; + case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: + uninstallShadows( widget ); + break; + } } return false; @@ -347,7 +291,12 @@ //_______________________________________________________ void ShadowHelper::objectDeleted( QObject* object ) - { _widgets.remove( static_cast( object ) ); } + { + + QWidget* widget( static_cast( object ) ); + _widgets.remove( widget ); + uninstallShadows( widget ); + } //_______________________________________________________ bool ShadowHelper::isMenu( QWidget* widget ) const @@ -391,171 +340,39 @@ return false; } - //______________________________________________ - const QVector& ShadowHelper::createPixmapHandles() - { - - /** - shadow atom and property specification available at - https://community.kde.org/KWin/Shadow - */ - - // create atom - #if BREEZE_HAVE_X11 - if( !_atom && Helper::isX11() ) _atom = _helper.createAtom( QLatin1String( netWMShadowAtomName ) ); - #endif - - // make sure size is valid - if( _pixmaps.empty() ) - { - _pixmaps = QVector { - createPixmap( _shadowTiles.pixmap( 1 ) ), - createPixmap( _shadowTiles.pixmap( 2 ) ), - createPixmap( _shadowTiles.pixmap( 5 ) ), - createPixmap( _shadowTiles.pixmap( 8 ) ), - createPixmap( _shadowTiles.pixmap( 7 ) ), - createPixmap( _shadowTiles.pixmap( 6 ) ), - createPixmap( _shadowTiles.pixmap( 3 ) ), - createPixmap( _shadowTiles.pixmap( 0 ) ) - }; - } - - // return relevant list of pixmap handles - return _pixmaps; - - } - - //______________________________________________ - quint32 ShadowHelper::createPixmap( const QPixmap& source ) - { - - // do nothing for invalid pixmaps - if( source.isNull() ) return 0; - if( !Helper::isX11() ) return 0; - - /* - in some cases, pixmap handle is invalid. This is the case notably - when Qt uses to RasterEngine. In this case, we create an X11 Pixmap - explicitly and draw the source pixmap on it. - */ - - #if BREEZE_HAVE_X11 - - const int width( source.width() ); - const int height( source.height() ); - - // create X11 pixmap - xcb_pixmap_t pixmap = xcb_generate_id( Helper::connection() ); - xcb_create_pixmap( Helper::connection(), 32, pixmap, QX11Info::appRootWindow(), width, height ); - - // create gc - if( !_gc ) - { - _gc = xcb_generate_id( Helper::connection() ); - xcb_create_gc( Helper::connection(), _gc, pixmap, 0, nullptr ); - } - - // create image from QPixmap and assign to pixmap - QImage image( source.toImage() ); - xcb_put_image( Helper::connection(), XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, _gc, image.width(), image.height(), 0, 0, 0, 32, image.sizeInBytes(), image.constBits()); - - return pixmap; - - #else - return 0; - #endif - - } - //_______________________________________________________ bool ShadowHelper::installShadows( QWidget* widget ) { - if( !widget ) return false; + Q_ASSERT( !_shadows.contains( widget ) ); - /* - From bespin code. Supposedly prevent playing with some 'pseudo-widgets' - that have winId matching some other -random- window - */ - if( !(widget->testAttribute(Qt::WA_WState_Created) && widget->internalWinId() )) - { return false; } + // Decorate only toplevel widgets. + if( !widget || !widget->isWindow() ) return false; + + // The widget is not backed by a native window, bail out. + if( !widget->windowHandle() ) return false; // create shadow tiles if needed shadowTiles(); if( !_shadowTiles.isValid() ) return false; - if( Helper::isX11() ) return installX11Shadows( widget ); - if( Helper::isWayland() ) return installWaylandShadows( widget ); - - return false; - } - - //_______________________________________________________ - bool ShadowHelper::installX11Shadows( QWidget* widget ) - { - #if BREEZE_HAVE_X11 - #ifndef QT_NO_XRENDER - - // create pixmap handles if needed - QVector data( createPixmapHandles() ); - if( data.size() != numPixmaps ) return false; - - const QMargins margins = shadowMargins( widget ); - const quint32 topSize = margins.top(); - const quint32 bottomSize = margins.bottom(); - const quint32 leftSize( margins.left() ); - const quint32 rightSize( margins.right() ); - - // assign to data and xcb property - data << QVector{topSize, rightSize, bottomSize, leftSize}; - xcb_change_property( Helper::connection(), XCB_PROP_MODE_REPLACE, widget->winId(), _atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData() ); - xcb_flush( Helper::connection() ); - - return true; + KWindowShadow *shadow = new KWindowShadow(); - #endif - #endif - - return false; + shadow->setLeftTile( getOrCreateLeftTile() ); + shadow->setTopLeftTile( getOrCreateTopLeftTile() ); + shadow->setTopTile( getOrCreateTopTile() ); + shadow->setTopRightTile( getOrCreateTopRightTile() ); + shadow->setRightTile( getOrCreateRightTile() ); + shadow->setBottomRightTile( getOrCreateBottomRightTile() ); + shadow->setBottomTile( getOrCreateBottomTile() ); + shadow->setBottomLeftTile( getOrCreateBottomLeftTile() ); + shadow->setPadding( shadowMargins(widget) ); + shadow->setWindow( widget->windowHandle() ); + shadow->create(); - } - - //_______________________________________________________ - bool ShadowHelper::installWaylandShadows( QWidget* widget ) - { - #if BREEZE_HAVE_KWAYLAND - if( widget->windowHandle()->parent() ) return false; - if( !_shadowManager || !_shmPool ) return false; - - // create shadow - using namespace KWayland::Client; - auto s = Surface::fromWindow( widget->windowHandle() ); - if( !s ) return false; - - auto shadow = _shadowManager->createShadow( s, widget ); - if( !shadow->isValid() ) return false; - - // add the shadow elements - shadow->attachTop( _shmPool->createBuffer( _shadowTiles.pixmap( 1 ).toImage() ) ); - shadow->attachTopRight( _shmPool->createBuffer( _shadowTiles.pixmap( 2 ).toImage() ) ); - shadow->attachRight( _shmPool->createBuffer( _shadowTiles.pixmap( 5 ).toImage() ) ); - shadow->attachBottomRight( _shmPool->createBuffer( _shadowTiles.pixmap( 8 ).toImage() ) ); - shadow->attachBottom( _shmPool->createBuffer( _shadowTiles.pixmap( 7 ).toImage() ) ); - shadow->attachBottomLeft( _shmPool->createBuffer( _shadowTiles.pixmap( 6 ).toImage() ) ); - shadow->attachLeft( _shmPool->createBuffer( _shadowTiles.pixmap( 3 ).toImage() ) ); - shadow->attachTopLeft( _shmPool->createBuffer( _shadowTiles.pixmap( 0 ).toImage() ) ); - - shadow->setOffsets( shadowMargins( widget ) ); - shadow->commit(); - s->commit( Surface::CommitFlag::None ); - _widgetSurfaces.insert(widget, s); + _shadows.insert( widget, shadow ); return true; - #else - Q_UNUSED( widget ); - #endif - - return false; } //_______________________________________________________ @@ -621,40 +438,113 @@ } //_______________________________________________________ - void ShadowHelper::uninstallShadows( QWidget* widget ) const + void ShadowHelper::uninstallShadows( QWidget* widget ) { - if( !( widget && widget->testAttribute(Qt::WA_WState_Created) ) ) return; - if( Helper::isX11() ) uninstallX11Shadows( widget ); - if( Helper::isWayland() ) uninstallWaylandShadows( widget ); + delete _shadows.take( widget ); } //_______________________________________________________ - void ShadowHelper::uninstallX11Shadows( QWidget* widget ) const + KWindowShadowTile::Ptr ShadowHelper::getOrCreateLeftTile() { - #if BREEZE_HAVE_X11 - xcb_delete_property( Helper::connection(), widget->winId(), _atom); - #else - Q_UNUSED( widget ) - #endif + if( _leftTile ) return _leftTile; + + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 3 ).toImage() ); + _leftTile = tile; + + return tile; } //_______________________________________________________ - void ShadowHelper::uninstallWaylandShadows( QWidget* widget ) const + KWindowShadowTile::Ptr ShadowHelper::getOrCreateTopLeftTile() { - #if BREEZE_HAVE_KWAYLAND - if( widget->windowHandle() && widget->windowHandle()->parent() ) return; - if( !_shadowManager ) return; + if( _topLeftTile ) return _topLeftTile; - using namespace KWayland::Client; - auto s = Surface::fromWindow( widget->windowHandle() ); - if( !s ) return; + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 0 ).toImage() ); - _shadowManager->removeShadow( s ); - s->commit( Surface::CommitFlag::None ); - #else - Q_UNUSED( widget ) - #endif + _topLeftTile = tile; + + return tile; + } + + //_______________________________________________________ + KWindowShadowTile::Ptr ShadowHelper::getOrCreateTopTile() + { + if( _topTile ) return _topTile; + + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 1 ).toImage() ); + + _topTile = tile; + + return tile; + } + + //_______________________________________________________ + KWindowShadowTile::Ptr ShadowHelper::getOrCreateTopRightTile() + { + if( _topRightTile ) return _topRightTile; + + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 2 ).toImage() ); + + _topRightTile = tile; + + return tile; + } + + //_______________________________________________________ + KWindowShadowTile::Ptr ShadowHelper::getOrCreateRightTile() + { + if( _rightTile ) return _rightTile; + + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 5 ).toImage() ); + + _rightTile = tile; + + return tile; + } + + //_______________________________________________________ + KWindowShadowTile::Ptr ShadowHelper::getOrCreateBottomRightTile() + { + if( _bottomRightTile ) return _bottomRightTile; + + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 8 ).toImage() ); + + _bottomRightTile = tile; + + return tile; + } + + //_______________________________________________________ + KWindowShadowTile::Ptr ShadowHelper::getOrCreateBottomTile() + { + if( _bottomTile ) return _bottomTile; + + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 7 ).toImage() ); + + _bottomTile = tile; + + return tile; + } + + //_______________________________________________________ + KWindowShadowTile::Ptr ShadowHelper::getOrCreateBottomLeftTile() + { + if( _bottomLeftTile ) return _bottomLeftTile; + + KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); + tile->setImage( _shadowTiles.pixmap( 6 ).toImage() ); + + _bottomLeftTile = tile; + + return tile; } }