diff --git a/bridge.cpp b/bridge.cpp index 6fc172bd7a..7e529f2c6e 100644 --- a/bridge.cpp +++ b/bridge.cpp @@ -208,6 +208,11 @@ bool Bridge::compositingActive() const return c->workspace()->compositingActive(); } +QRect Bridge::transparentRect() const + { + return c->transparentRect().translated(-c->decorationRect().topLeft()); + } + bool Bridge::isClientGroupActive() { return c->clientGroup()->containsActiveClient(); diff --git a/bridge.h b/bridge.h index 05836d11c2..9bd446ccd9 100644 --- a/bridge.h +++ b/bridge.h @@ -76,6 +76,7 @@ class Bridge : public KDecorationBridgeUnstable virtual void grabXServer( bool grab ); virtual bool compositingActive() const; + virtual QRect transparentRect() const; // Window tabbing virtual bool isClientGroupActive(); diff --git a/client.cpp b/client.cpp index 4a83290867..258ed6d8cb 100644 --- a/client.cpp +++ b/client.cpp @@ -445,13 +445,23 @@ void Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect if (mode == WindowRelative) r.translate(-padding_left, -padding_top); - top = QRect(r.x(), r.y(), r.width(), padding_top + border_top); - bottom = QRect(r.x(), r.y() + r.height() - padding_bottom - border_bottom, - r.width(), padding_bottom + border_bottom); + NETStrut strut = info->frameOverlap(); + if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) + { + top = QRect(r.x(), r.y(), r.width(), r.height() / 3); + left = QRect(r.x(), r.y() + top.height(), width() / 2, r.height() / 3); + right = QRect(r.x() + left.width(), r.y() + top.height(), r.width() - left.width(), left.height()); + bottom = QRect(r.x(), r.y() + top.height() + left.height(), r.width(), r.height() - left.height() - top.height()); + return; + } + + top = QRect(r.x(), r.y(), r.width(), padding_top + border_top + strut.top); + bottom = QRect(r.x(), r.y() + r.height() - padding_bottom - border_bottom - strut.bottom, + r.width(), padding_bottom + border_bottom + strut.bottom); left = QRect(r.x(), r.y() + top.height(), - padding_left + border_left, r.height() - top.height() - bottom.height()); - right = QRect(r.x() + r.width() - padding_right - border_right, r.y() + top.height(), - padding_right + border_right, r.height() - top.height() - bottom.height()); + padding_left + border_left + strut.left, r.height() - top.height() - bottom.height()); + right = QRect(r.x() + r.width() - padding_right - border_right - strut.right, r.y() + top.height(), + padding_right + border_right + strut.right, r.height() - top.height() - bottom.height()); } QRegion Client::decorationPendingRegion() const @@ -581,6 +591,20 @@ void Client::resizeDecorationPixmaps() triggerDecorationRepaint(); } +QRect Client::transparentRect() const + { + NETStrut strut = info->frameOverlap(); + if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) + return QRect(); + + const QRect r = QRect(clientPos(), clientSize()) + .adjusted(strut.left, strut.top, -strut.right, -strut.bottom); + if (r.isValid()) + return r; + + return QRect(); + } + void Client::detectNoBorder() { if( shape()) diff --git a/client.h b/client.h index 5266b1959c..e97ceb7c79 100644 --- a/client.h +++ b/client.h @@ -358,6 +358,8 @@ class Client QRect(0, 0, width(), height()); } + QRect transparentRect() const; + QRegion decorationPendingRegion() const; enum CoordinateMode { diff --git a/deleted.cpp b/deleted.cpp index e5fef3d833..cde2c34bc2 100644 --- a/deleted.cpp +++ b/deleted.cpp @@ -68,6 +68,7 @@ void Deleted::copyToDeleted( Toplevel* c ) Toplevel::copyToDeleted( c ); desk = c->desktop(); contentsRect = QRect( c->clientPos(), c->clientSize()); + transparent_rect = c->transparentRect(); if( WinInfo* cinfo = dynamic_cast< WinInfo* >( info )) cinfo->disable(); Client* client = dynamic_cast(c); @@ -138,6 +139,11 @@ QRect Deleted::decorationRect() const return rect().adjusted(-padding_left, -padding_top, padding_top, padding_bottom); } +QRect Deleted::transparentRect() const + { + return transparent_rect; + } + } // namespace #include "deleted.moc" diff --git a/deleted.h b/deleted.h index d3aedb880d..94fda09b3f 100644 --- a/deleted.h +++ b/deleted.h @@ -39,6 +39,7 @@ class Deleted virtual int desktop() const; virtual QPoint clientPos() const; virtual QSize clientSize() const; + virtual QRect transparentRect() const; const QPixmap *topDecoPixmap() const { return &decorationPixmapTop; } const QPixmap *leftDecoPixmap() const { return &decorationPixmapLeft; } const QPixmap *bottomDecoPixmap() const { return &decorationPixmapBottom; } @@ -58,6 +59,7 @@ class Deleted double window_opacity; int desk; QRect contentsRect; // for clientPos()/clientSize() + QRect transparent_rect; QPixmap decorationPixmapLeft; QPixmap decorationPixmapRight; diff --git a/events.cpp b/events.cpp index dcac6dc9e3..2431526d72 100644 --- a/events.cpp +++ b/events.cpp @@ -634,6 +634,10 @@ bool Client::windowEvent( XEvent* e ) i.setOpacity( info->opacity()); } } + if( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2FrameOverlap ) + { + // ### Inform the decoration + } } switch (e->type) diff --git a/kcmkwin/kwindecoration/preview.cpp b/kcmkwin/kwindecoration/preview.cpp index ee15707be6..55f0339736 100644 --- a/kcmkwin/kwindecoration/preview.cpp +++ b/kcmkwin/kwindecoration/preview.cpp @@ -467,6 +467,11 @@ bool KDecorationPreviewBridge::compositingActive() const return KWindowSystem::compositingActive(); } +QRect KDecorationPreviewBridge::transparentRect() const + { + return QRect(); + } + // Window tabbing bool KDecorationPreviewBridge::isClientGroupActive() diff --git a/kcmkwin/kwindecoration/preview.h b/kcmkwin/kwindecoration/preview.h index 473d154151..fab1783e07 100644 --- a/kcmkwin/kwindecoration/preview.h +++ b/kcmkwin/kwindecoration/preview.h @@ -115,6 +115,7 @@ class KDecorationPreviewBridge virtual void grabXServer( bool grab ); virtual bool compositingActive() const; + virtual QRect transparentRect() const; // Window tabbing virtual bool isClientGroupActive(); diff --git a/lib/kcommondecoration.cpp b/lib/kcommondecoration.cpp index 750589b798..67d126f972 100644 --- a/lib/kcommondecoration.cpp +++ b/lib/kcommondecoration.cpp @@ -932,6 +932,10 @@ QRect KCommonDecoration::titleRect() const titleEdgeBottomBottom-(r_y+titleEdgeTop) ); } +QRect KCommonDecoration::transparentRect() const +{ + return wrapper->transparentRect(); +} KCommonDecorationButton::KCommonDecorationButton(ButtonType type, KCommonDecoration *parent) : QAbstractButton(parent?parent->widget():0 ), diff --git a/lib/kcommondecoration.h b/lib/kcommondecoration.h index f62f1415f0..114b680a39 100644 --- a/lib/kcommondecoration.h +++ b/lib/kcommondecoration.h @@ -233,6 +233,22 @@ class KWIN_EXPORT KCommonDecoration : public QObject, public KDecorationDefines */ QRect titleRect() const; + /** + * Returns the rectangle within the decoration that should be transparent. + * + * Usually this is the rectangle occupied by the client window, + * but a smaller rectangle may be returned if the client has specified + * that the window decoration should extend below the client area. + * + * If the client has requested that the decoration should cover the whole + * client area, a null rectangle is returned. + * + * The returned rectangle is never larger than the client area. + * + * @since 4.4 + */ + QRect transparentRect() const; + public: /** * Handles widget and layout creation, call the base implementation when subclassing this member. diff --git a/lib/kdecoration.cpp b/lib/kdecoration.cpp index e9ae5f9e3e..5085a86f6e 100644 --- a/lib/kdecoration.cpp +++ b/lib/kdecoration.cpp @@ -382,6 +382,14 @@ KDecoration::Position KDecoration::mousePosition( const QPoint& p ) const return m; } +QRect KDecoration::transparentRect() const + { + if (KDecorationBridgeUnstable *bridge2 = dynamic_cast(bridge_)) + return bridge2->transparentRect(); + else + return QRect(); + } + KDecorationUnstable::KDecorationUnstable( KDecorationBridge* bridge, KDecorationFactory* factory ) : KDecoration( bridge, factory ) diff --git a/lib/kdecoration.h b/lib/kdecoration.h index 6170ac019f..728eaae7c4 100644 --- a/lib/kdecoration.h +++ b/lib/kdecoration.h @@ -628,6 +628,20 @@ class KWIN_EXPORT KDecoration * Convenience function that returns the height of the decoration. */ int height() const; // convenience + /** + * Returns the rectangle within the window frame that should be transparent. + * Usually this rectangle is the same as the client area, and it is never + * larger. + * + * If the client has requested that the window frame is extended into the + * client area, this rectangle is smaller than the client area. + * + * If the window frame should cover the whole client area, a null rectangle + * is returned. + * + * @since 4.4 + */ + QRect transparentRect() const; /** * This function is the default handler for mouse events. All mouse events * that are not handled by the decoration itself should be passed to it diff --git a/lib/kdecorationbridge.h b/lib/kdecorationbridge.h index 09614cc680..f4f2fb44ac 100644 --- a/lib/kdecorationbridge.h +++ b/lib/kdecorationbridge.h @@ -94,6 +94,7 @@ class KWIN_EXPORT KDecorationBridgeUnstable { public: virtual bool compositingActive() const = 0; + virtual QRect transparentRect() const = 0; // Window tabbing virtual bool isClientGroupActive() = 0; diff --git a/manage.cpp b/manage.cpp index 88f69c3e76..397d67d163 100644 --- a/manage.cpp +++ b/manage.cpp @@ -91,6 +91,7 @@ bool Client::manage( Window w, bool isMapped ) NET::WM2ExtendedStrut | NET::WM2Opacity | NET::WM2FullscreenMonitors | + NET::WM2FrameOverlap | 0; info = new WinInfo( this, display(), client, rootWindow(), properties, 2 ); diff --git a/scene.cpp b/scene.cpp index 4951693ca0..bd047229c4 100644 --- a/scene.cpp +++ b/scene.cpp @@ -482,10 +482,11 @@ WindowQuadList Scene::Window::buildQuads( bool force ) const { Client *client = dynamic_cast( toplevel ); QRegion contents = clientShape(); + QRegion center = client->transparentRect(); QRegion decoration = (client && Workspace::self()->decorationHasAlpha() ? - QRegion(client->decorationRect()) : shape()) - contents; + QRegion(client->decorationRect()) : shape()) - center; ret = makeQuads( WindowQuadContents, contents ); - if( (client && !client->isShade()) || !client ) + if( !client || !(center.isEmpty() || client->isShade()) ) ret += makeQuads( WindowQuadDecoration, decoration ); else { diff --git a/toplevel.h b/toplevel.h index 19be1c436f..b8ebfc268e 100644 --- a/toplevel.h +++ b/toplevel.h @@ -66,6 +66,7 @@ class Toplevel virtual QSize clientSize() const = 0; virtual QRect visibleRect() const; // the area the window occupies on the screen virtual QRect decorationRect() const; // rect including the decoration shadows + virtual QRect transparentRect() const = 0; virtual QRegion decorationPendingRegion() const; // decoration region that needs to be repainted // prefer isXXX() instead diff --git a/unmanaged.cpp b/unmanaged.cpp index 083f9c265c..31ceb7187f 100644 --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -122,6 +122,11 @@ QSize Unmanaged::clientSize() const return size(); } +QRect Unmanaged::transparentRect() const + { + return QRect(clientPos(), clientSize()); + } + void Unmanaged::debug( kdbgstream& stream ) const { stream << "\'ID:" << window() << "\'"; diff --git a/unmanaged.h b/unmanaged.h index 42c4f9299a..708d339d0b 100644 --- a/unmanaged.h +++ b/unmanaged.h @@ -41,6 +41,7 @@ class Unmanaged virtual int desktop() const; virtual QPoint clientPos() const; virtual QSize clientSize() const; + virtual QRect transparentRect() const; protected: virtual void debug( kdbgstream& stream ) const; virtual bool shouldUnredirect() const; diff --git a/workspace.cpp b/workspace.cpp index eaf9e6a44a..428289cc9d 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -324,6 +324,7 @@ void Workspace::init() NET::WM2DesktopLayout | NET::WM2FullPlacement | NET::WM2FullscreenMonitors | + NET::WM2FrameOverlap | 0 , NET::ActionMove |