kwinmodule.cpp

00001 /*
00002     $Id: kwinmodule.cpp 527725 2006-04-09 09:01:39Z lunakl $
00003 
00004     This file is part of the KDE libraries
00005     Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
00006 
00007 
00008     This library is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU Library General Public
00010     License as published by the Free Software Foundation; either
00011     version 2 of the License, or (at your option) any later version.
00012 
00013     This library is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016     Library General Public License for more details.
00017 
00018     You should have received a copy of the GNU Library General Public License
00019     along with this library; see the file COPYING.LIB.  If not, write to
00020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021     Boston, MA 02110-1301, USA.
00022 */
00023 
00024 #include <qwidget.h>
00025 #ifdef Q_WS_X11 //FIXME
00026 #include "kwinmodule.h"
00027 #include "kwin.h"
00028 #include <X11/Xatom.h>
00029 #include "kapplication.h"
00030 #include "kdebug.h"
00031 #include <qtl.h>
00032 #include <qptrlist.h>
00033 #include <klocale.h>
00034 #include <dcopclient.h>
00035 #include "netwm.h"
00036 
00037 static KWinModulePrivate* static_d = 0;
00038 
00039 static unsigned long windows_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking |
00040                      NET::NumberOfDesktops |
00041                      NET::DesktopGeometry |
00042                      NET::CurrentDesktop |
00043                      NET::DesktopNames |
00044                      NET::ActiveWindow |
00045                      NET::WorkArea |
00046                      NET::KDESystemTrayWindows,
00047                                      NET::WM2ShowingDesktop };
00048 
00049 static unsigned long desktop_properties[ 2 ] = { 
00050                      NET::NumberOfDesktops |
00051                      NET::DesktopGeometry |
00052                      NET::CurrentDesktop |
00053                      NET::DesktopNames |
00054                      NET::ActiveWindow |
00055                      NET::WorkArea |
00056                      NET::KDESystemTrayWindows,
00057                                      NET::WM2ShowingDesktop };
00058 
00059 class KWinModulePrivate : public QWidget, public NETRootInfo4
00060 {
00061 public:
00062     KWinModulePrivate(int _what)
00063     : QWidget(0,0), NETRootInfo4( qt_xdisplay(),
00064                                      _what >= KWinModule::INFO_WINDOWS ?
00065                                      windows_properties : desktop_properties,
00066                                      2,
00067                      -1, false
00068                      ),
00069           strutSignalConnected( false ),
00070           what( _what )
00071     {
00072     kapp->installX11EventFilter( this );
00073     (void ) kapp->desktop(); //trigger desktop widget creation to select root window events
00074         activate();
00075     updateStackingOrder();
00076     }
00077     ~KWinModulePrivate()
00078     {
00079     }
00080     QPtrList<KWinModule> modules;
00081 
00082     QValueList<WId> windows;
00083     QValueList<WId> stackingOrder;
00084     QValueList<WId> systemTrayWindows;
00085 
00086     struct StrutData
00087     {
00088         StrutData( WId window_, const NETStrut& strut_, int desktop_ )
00089             : window( window_ ), strut( strut_ ), desktop( desktop_ ) {};
00090         StrutData() {}; // for QValueList to be happy
00091         WId window;
00092         NETStrut strut;
00093         int desktop;
00094     };
00095     QValueList<StrutData> strutWindows;
00096     QValueList<WId> possibleStrutWindows;
00097     bool strutSignalConnected;
00098     int what;
00099 
00100     void addClient(Window);
00101     void removeClient(Window);
00102     void addSystemTrayWin(Window);
00103     void removeSystemTrayWin(Window);
00104 
00105     bool x11Event( XEvent * ev );
00106 
00107     void updateStackingOrder();
00108     bool removeStrutWindow( WId );
00109 };
00110 
00111 
00112 KWinModule::KWinModule( QObject* parent )
00113     : QObject( parent, "kwin_module" )
00114 {
00115     init(INFO_ALL);
00116 }
00117 
00118 KWinModule::KWinModule( QObject* parent, int what )
00119     : QObject( parent, "kwin_module" )
00120 {
00121     init(what);
00122 }
00123 
00124 void KWinModule::init(int what)
00125 {
00126     if (what >= INFO_WINDOWS)
00127        what = INFO_WINDOWS;
00128     else
00129        what = INFO_DESKTOP;
00130 
00131     if ( !static_d )
00132     {
00133         static_d = new KWinModulePrivate(what);
00134     }
00135     else if (static_d->what < what)
00136     {
00137         QPtrList<KWinModule> modules = static_d->modules;
00138         delete static_d;
00139         static_d = new KWinModulePrivate(what);
00140         static_d->modules = modules;
00141         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00142             (*mit)->d = static_d;
00143     }
00144     
00145     d = static_d;
00146     d->modules.append( this );
00147 }
00148 
00149 KWinModule::~KWinModule()
00150 {
00151     d->modules.removeRef( this );
00152     if ( d->modules.isEmpty() ) {
00153     delete d;
00154     static_d = 0;
00155     }
00156 }
00157 
00158 const QValueList<WId>& KWinModule::windows() const
00159 {
00160     return d->windows;
00161 }
00162 
00163 const QValueList<WId>& KWinModule::stackingOrder() const
00164 {
00165     return d->stackingOrder;
00166 }
00167 
00168 
00169 bool KWinModule::hasWId(WId w) const
00170 {
00171     return d->windows.findIndex( w ) != -1;
00172 }
00173 
00174 const QValueList<WId>& KWinModule::systemTrayWindows() const
00175 {
00176     return d->systemTrayWindows;
00177 }
00178 
00179 bool KWinModulePrivate::x11Event( XEvent * ev )
00180 {
00181     if ( ev->xany.window == qt_xrootwin() ) {
00182         int old_current_desktop = currentDesktop();
00183         WId old_active_window = activeWindow();
00184         int old_number_of_desktops = numberOfDesktops();
00185         bool old_showing_desktop = showingDesktop();
00186         unsigned long m[ 5 ];
00187     NETRootInfo::event( ev, m, 5 );
00188 
00189     if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
00190         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00191         emit (*mit)->currentDesktopChanged( currentDesktop() );
00192     if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
00193         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00194         emit (*mit)->activeWindowChanged( activeWindow() );
00195     if ( m[ PROTOCOLS ] & DesktopNames )
00196         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00197         emit (*mit)->desktopNamesChanged();
00198     if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
00199         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00200         emit (*mit)->numberOfDesktopsChanged( numberOfDesktops() );
00201     if ( m[ PROTOCOLS ] & WorkArea )
00202         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00203         emit (*mit)->workAreaChanged();
00204     if ( m[ PROTOCOLS ] & ClientListStacking ) {
00205         updateStackingOrder();
00206         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00207         emit (*mit)->stackingOrderChanged();
00208     }
00209         if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
00210         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00211         emit (*mit)->showingDesktopChanged( showingDesktop());
00212         }
00213     } else  if ( windows.findIndex( ev->xany.window ) != -1 ){
00214     NETWinInfo ni( qt_xdisplay(), ev->xany.window, qt_xrootwin(), 0 );
00215         unsigned long dirty[ 2 ];
00216     ni.event( ev, dirty, 2 );
00217     if ( ev->type ==PropertyNotify ) {
00218             if( ev->xproperty.atom == XA_WM_HINTS )
00219             dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIcon; // support for old icons
00220             else if( ev->xproperty.atom == XA_WM_NAME )
00221                 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName; // support for old name
00222             else if( ev->xproperty.atom == XA_WM_ICON_NAME )
00223                 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName; // support for old iconic name
00224         }
00225     if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 ) {
00226             removeStrutWindow( ev->xany.window );
00227             if ( possibleStrutWindows.findIndex( ev->xany.window ) == -1 )
00228             possibleStrutWindows.append( ev->xany.window );
00229     }
00230     if ( dirty[ NETWinInfo::PROTOCOLS ] || dirty[ NETWinInfo::PROTOCOLS2 ] ) {
00231         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00232         emit (*mit)->windowChanged( ev->xany.window );
00233                 emit (*mit)->windowChanged( ev->xany.window, dirty );
00234         emit (*mit)->windowChanged( ev->xany.window, dirty[ NETWinInfo::PROTOCOLS ] );
00235         if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
00236             emit (*mit)->strutChanged();
00237         }
00238     }
00239     }
00240 
00241     return false;
00242 }
00243 
00244 bool KWinModulePrivate::removeStrutWindow( WId w )
00245 {
00246     for( QValueList< StrutData >::Iterator it = strutWindows.begin();
00247          it != strutWindows.end();
00248          ++it )
00249         if( (*it).window == w ) {
00250             strutWindows.remove( it );
00251             return true;
00252         }
00253     return false;
00254 }
00255 
00256 void KWinModulePrivate::updateStackingOrder()
00257 {
00258     stackingOrder.clear();
00259     for ( int i = 0; i <  clientListStackingCount(); i++ )
00260     stackingOrder.append( clientListStacking()[i] );
00261 }
00262 
00263 void KWinModulePrivate::addClient(Window w)
00264 {
00265     if ( (what >= KWinModule::INFO_WINDOWS) && !QWidget::find( w ) )
00266     XSelectInput( qt_xdisplay(), w, PropertyChangeMask | StructureNotifyMask );
00267     bool emit_strutChanged = false;
00268     if( strutSignalConnected && modules.count() > 0 ) {
00269         NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut | NET::WMDesktop );
00270         NETStrut strut = info.strut();
00271         if ( strut.left || strut.top || strut.right || strut.bottom ) {
00272             strutWindows.append( StrutData( w, strut, info.desktop()));
00273             emit_strutChanged = true;
00274         }
00275     } else
00276         possibleStrutWindows.append( w );
00277     windows.append( w );
00278     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00279     emit (*mit)->windowAdded( w );
00280     if ( emit_strutChanged )
00281         emit (*mit)->strutChanged();
00282     }
00283 }
00284 
00285 void KWinModulePrivate::removeClient(Window w)
00286 {
00287     bool emit_strutChanged = removeStrutWindow( w );
00288     if( strutSignalConnected && possibleStrutWindows.findIndex( w ) != -1 && modules.count() > 0 ) {
00289         NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut );
00290         NETStrut strut = info.strut();
00291         if ( strut.left || strut.top || strut.right || strut.bottom ) {
00292             emit_strutChanged = true;
00293         }
00294     }
00295     possibleStrutWindows.remove( w );
00296     windows.remove( w );
00297     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00298     emit (*mit)->windowRemoved( w );
00299     if ( emit_strutChanged )
00300         emit (*mit)->strutChanged();
00301     }
00302 }
00303 
00304 void KWinModulePrivate::addSystemTrayWin(Window w)
00305 {
00306     systemTrayWindows.append( w );
00307     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00308     emit (*mit)->systemTrayWindowAdded( w );
00309 }
00310 
00311 void KWinModulePrivate::removeSystemTrayWin(Window w)
00312 {
00313     systemTrayWindows.remove( w );
00314     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00315     emit (*mit)->systemTrayWindowRemoved( w );
00316 }
00317 
00318 int KWinModule::currentDesktop() const
00319 {
00320     return d->currentDesktop();
00321 }
00322 
00323 int KWinModule::numberOfDesktops() const
00324 {
00325     return d->numberOfDesktops();
00326 }
00327 
00328 WId KWinModule::activeWindow() const
00329 {
00330     return d->activeWindow();
00331 }
00332 
00333 bool KWinModule::showingDesktop() const
00334 {
00335     return d->showingDesktop();
00336 }
00337 
00338 QRect KWinModule::workArea( int desktop ) const
00339 {
00340     int desk  = (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop();
00341     if ( desk <= 0 )
00342     return QApplication::desktop()->geometry();
00343     NETRect r = d->workArea( desk );
00344     if( r.size.width <= 0 || r.size.height <= 0 ) // not set
00345     return QApplication::desktop()->geometry();
00346     return QRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00347 }
00348 
00349 QRect KWinModule::workArea( const QValueList<WId>& exclude, int desktop ) const
00350 {
00351     QRect all = QApplication::desktop()->geometry();
00352     QRect a = all;
00353 
00354     if (desktop == -1)
00355     desktop = d->currentDesktop();
00356 
00357     QValueList<WId>::ConstIterator it1;
00358     for( it1 = d->windows.begin(); it1 != d->windows.end(); ++it1 ) {
00359 
00360     if(exclude.findIndex(*it1) != -1) continue;
00361         
00362 // Kicker (very) extensively calls this function, causing hundreds of roundtrips just
00363 // to repeatedly find out struts of all windows. Therefore strut values for strut
00364 // windows are cached here.
00365         NETStrut strut;
00366         QValueList< KWinModulePrivate::StrutData >::Iterator it2 = d->strutWindows.begin();
00367         for( ;
00368              it2 != d->strutWindows.end();
00369              ++it2 )
00370             if( (*it2).window == *it1 )
00371                 break;
00372         if( it2 != d->strutWindows.end()) {
00373             if(!((*it2).desktop == desktop || (*it2).desktop == NETWinInfo::OnAllDesktops ))
00374                 continue;
00375             strut = (*it2).strut;
00376         } else if( d->possibleStrutWindows.findIndex( *it1 ) != -1 ) {
00377             NETWinInfo info( qt_xdisplay(), (*it1), qt_xrootwin(), NET::WMStrut | NET::WMDesktop);
00378         strut = info.strut();
00379             d->possibleStrutWindows.remove( *it1 );
00380             d->strutWindows.append( KWinModulePrivate::StrutData( *it1, info.strut(), info.desktop()));
00381         if(!(info.desktop() == desktop || info.desktop() == NETWinInfo::OnAllDesktops))
00382                 continue;
00383         } else
00384             continue; // not a strut window
00385 
00386     QRect r = all;
00387     if ( strut.left > 0 )
00388         r.setLeft( r.left() + (int) strut.left );
00389     if ( strut.top > 0 )
00390         r.setTop( r.top() + (int) strut.top );
00391     if ( strut.right > 0  )
00392         r.setRight( r.right() - (int) strut.right );
00393     if ( strut.bottom > 0  )
00394         r.setBottom( r.bottom() - (int) strut.bottom );
00395 
00396     a = a.intersect(r);
00397     }
00398     return a;
00399 }
00400 
00401 void KWinModule::connectNotify( const char* signal )
00402 {
00403     if( !d->strutSignalConnected && qstrcmp( signal, SIGNAL(strutChanged())) == 0 )
00404         d->strutSignalConnected = true;
00405     QObject::connectNotify( signal );
00406 }
00407 
00408 QString KWinModule::desktopName( int desktop ) const
00409 {
00410     const char* name = d->desktopName( (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop() );
00411     if ( name && name[0] )
00412     return QString::fromUtf8( name );
00413     return i18n("Desktop %1").arg( desktop );
00414 }
00415 
00416 void KWinModule::setDesktopName( int desktop, const QString& name )
00417 {
00418     if (desktop <= 0 || desktop > (int) d->numberOfDesktops() )
00419     desktop = currentDesktop();
00420     d->setDesktopName( desktop, name.utf8().data() );
00421 }
00422 
00423 
00424 void KWinModule::doNotManage( const QString& title )
00425 {
00426     if ( !kapp->dcopClient()->isAttached() )
00427     kapp->dcopClient()->attach();
00428     QByteArray data, replyData;
00429     QCString replyType;
00430     QDataStream arg(data, IO_WriteOnly);
00431     arg << title;
00432     kapp->dcopClient()->call("kwin", "", "doNotManage(QString)",
00433                  data, replyType, replyData);
00434 }
00435 
00436 #include "kwinmodule.moc"
00437 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys