From 330ea804b2feddb305010791e3147869773fb682 Mon Sep 17 00:00:00 2001 From: Rik Hemsley Date: Sun, 16 Apr 2000 09:06:03 +0000 Subject: [PATCH] Preliminary support for avoiding covering clients such as kicker which want to be permanently visible. I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change if need be. I think it's correct according to the wm spec, but the wm spec seems to be empty on gnome.org, so who knows. Windows can choose to be avoided by setting an XTextProperty with one value, which can be either 'N', 'S', 'E', or 'W', according to which screen edge they are anchored to. kwin then sets its 'clientArea' rect appropriately, so that (in theory at least) clients will not enter this area in some circumstances, such as when being mapped for the first time. You can see that this actually works if you start lots of konsoles. They don't appear over the panel. I don't know what happens if you move the panel, but I presume things will be screwed up, because I haven't looked at that yet. If you maximise a window, it'll still fill the screen, because the implementation of maximise in kwin/client.cpp doesn't take account of the workspace's clientArea rect. This is easy to fix, but I've been awake for too long, so I'll do it after 42 winks. svn path=/trunk/kdebase/kwin/; revision=46772 --- client.cpp | 56 ++++++++++++++++++++++++++++++-- client.h | 6 ++++ workspace.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++- workspace.h | 6 ++++ 4 files changed, 153 insertions(+), 4 deletions(-) diff --git a/client.cpp b/client.cpp index 95957e72f8..e4d99a4114 100644 --- a/client.cpp +++ b/client.cpp @@ -320,9 +320,10 @@ bool WindowWrapper::x11Event( XEvent * e) Creates a client on workspace \a ws for window \a w. */ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags f ) - : QWidget( parent, name, f | WStyle_Customize | WStyle_NoBorder ) + : QWidget( parent, name, f | WStyle_Customize | WStyle_NoBorder ), + avoid_(false), + anchorEdge_(AnchorNorth) { - wspace = ws; win = w; XWindowAttributes attr; @@ -359,6 +360,56 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags if ( mainClient()->isSticky() ) setSticky( TRUE ); + // Find out if we should be avoided. + + // If this atom isn't set, set it now. + Atom avoidAtom = XInternAtom(qt_xdisplay(), "_NET_AVOID_SPEC", False); + + XTextProperty avoidProp; + + Status avoidStatus = + XGetTextProperty(qt_xdisplay(), w, &avoidProp, avoidAtom); + + if (0 != avoidStatus) { + + char ** avoidList; + int avoidListCount; + + Status convertStatus = + XTextPropertyToStringList(&avoidProp, &avoidList, &avoidListCount); + + if (0 != convertStatus) { + + avoid_ = true; + + if (avoidListCount != 1) { +// qDebug("Extra values in avoidance list. Ignoring."); + } + + char * itemZero = avoidList[0]; + + switch (*itemZero) { + + case 'N': + anchorEdge_ = AnchorNorth; + break; + case 'S': + anchorEdge_ = AnchorSouth; + break; + case 'E': + anchorEdge_ = AnchorEast; + break; + case 'W': + anchorEdge_ = AnchorWest; + break; + default: + anchorEdge_ = AnchorNorth; + break; + } + + XFreeStringList(avoidList); + } + } } /*! @@ -1848,7 +1899,6 @@ QCString Client::sessionId() return result; } - NoBorderClient::NoBorderClient( Workspace *ws, WId w, QWidget *parent, const char *name ) : Client( ws, w, parent, name ) { diff --git a/client.h b/client.h index 02f7323817..f4d0e5d818 100644 --- a/client.h +++ b/client.h @@ -63,6 +63,9 @@ public: bool isTransient() const; Client* mainClient(); + bool avoid() const { return avoid_; } + int anchorEdge() const { return anchorEdge_; } + virtual bool windowEvent( XEvent * ); void manage( bool isMapped = FALSE ); @@ -230,6 +233,9 @@ private: QPixmap miniicon_pix; QRect geom_restore; QRegion mask; + + bool avoid_; + int anchorEdge_; }; inline WId Client::window() const diff --git a/workspace.cpp b/workspace.cpp index ff36965ce6..7d7eea3452 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -247,6 +247,7 @@ void Workspace::init() inf.row = 0; cci.append(inf); } + updateClientArea(); } Workspace::~Workspace() @@ -339,6 +340,7 @@ bool Workspace::workspaceEvent( XEvent * e ) if ( addDockwin( e->xmaprequest.window ) ) return TRUE; c = clientFactory( this, e->xmaprequest.window ); + updateClientArea(); if ( root != qt_xrootwin() ) { // TODO may use QWidget:.create XReparentWindow( qt_xdisplay(), c->winId(), root, 0, 0 ); @@ -500,7 +502,7 @@ QRect Workspace::geometry() const */ QRect Workspace::clientArea() const { - return geometry(); // for now + return clientArea_; } @@ -1312,6 +1314,54 @@ void Workspace::deskCleanup(CleanupType ct) } } +/*! + Lowers the client \a c taking layers, transient windows and window + groups into account. + */ +void Workspace::lowerClient( Client* c ) +{ + if ( !c ) + return; + + if ( c == desktop_client ) + return; // deny + + stacking_order.remove( c ); + stacking_order.prepend( c ); + + // Not sure what this is doing. Disable for now. +#if 0 + ClientList saveset; + + if ( c->transientFor() ) { + + saveset.append( c ); + Client* t = findClient( c->transientFor() ); + Client* tmp; + while ( t && !saveset.contains( t ) && t->transientFor() ) { + tmp = findClient( t->transientFor() ); + if ( !tmp ) + break; + saveset.append( t ); + t = tmp; + } + if ( t && !saveset.contains( t ) && t != desktop_client ) { + raiseClient( t ); + return; + } + } + + saveset.clear(); + saveset.append( c ); + raiseTransientsOf(saveset, c ); +#endif + + XLowerWindow(qt_xdisplay(), c->winId()); + + propagateClients( TRUE ); +} + + /*! Raises the client \a c taking layers, transient windows and window groups into account. @@ -2047,6 +2097,7 @@ void Workspace::slotResetAllClients() delete oldClient; newClient->manage( TRUE ); } + updateClientArea(); } /*! @@ -2117,3 +2168,39 @@ SessionInfo* Workspace::takeSessionInfo( Client* c ) return 0; } + + void +Workspace::updateClientArea() +{ + clientArea_ = geometry(); + + for (ClientList::ConstIterator it(clients.begin()); it != clients.end(); ++it) + { + if ((*it)->avoid()) { + + switch (AnchorEdge((*it)->anchorEdge())) { + + case AnchorNorth: + clientArea_ + .setTop(QMAX(clientArea_.top(), (*it)->geometry().bottom())); + break; + + case AnchorSouth: + clientArea_ + .setBottom(QMIN(clientArea_.bottom(), (*it)->geometry().top())); + break; + + case AnchorEast: + clientArea_ + .setRight(QMIN(clientArea_.right(), (*it)->geometry().left())); + break; + + case AnchorWest: + clientArea_ + .setLeft(QMAX(clientArea_.left(), (*it)->geometry().right())); + break; + } + } + } +} + diff --git a/workspace.h b/workspace.h index 4c4f3df2d9..a82965aa7a 100644 --- a/workspace.h +++ b/workspace.h @@ -23,6 +23,8 @@ class KGlobalAccel; typedef QValueList ClientList; +enum AnchorEdge { AnchorNorth, AnchorSouth, AnchorEast, AnchorWest }; + class DockWindow { public: @@ -100,6 +102,7 @@ public: void doPlacement( Client* c ); QPoint adjustClientPosition( Client* c, QPoint pos ); void raiseClient( Client* c ); + void lowerClient( Client* c ); void clientHidden( Client* ); @@ -234,6 +237,9 @@ private: Atom kwm_command; PluginMgr mgr; + + void updateClientArea(); + QRect clientArea_; }; inline WId Workspace::rootWin() const