kwinmodule.cpp

00001 /*
00002     $Id: kwinmodule.cpp 590563 2006-09-30 13:33:05Z mueller $
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::DesktopViewport |
00043                      NET::CurrentDesktop |
00044                      NET::DesktopNames |
00045                      NET::ActiveWindow |
00046                      NET::WorkArea |
00047                      NET::KDESystemTrayWindows,
00048                                      NET::WM2ShowingDesktop };
00049 
00050 static unsigned long desktop_properties[ 2 ] = { 
00051                      NET::NumberOfDesktops |
00052                      NET::DesktopGeometry |
00053                                      NET::DesktopViewport |
00054                      NET::CurrentDesktop |
00055                      NET::DesktopNames |
00056                      NET::ActiveWindow |
00057                      NET::WorkArea |
00058                      NET::KDESystemTrayWindows,
00059                                      NET::WM2ShowingDesktop };
00060 
00061 class KWinModulePrivate : public QWidget, public NETRootInfo4
00062 {
00063 public:
00064     KWinModulePrivate(int _what)
00065     : QWidget(0,0), NETRootInfo4( qt_xdisplay(),
00066                                      _what >= KWinModule::INFO_WINDOWS ?
00067                                      windows_properties : desktop_properties,
00068                                      2,
00069                      -1, false
00070                      ),
00071           strutSignalConnected( false ),
00072           what( _what )
00073     {
00074     kapp->installX11EventFilter( this );
00075     (void ) kapp->desktop(); //trigger desktop widget creation to select root window events
00076         activate();
00077     updateStackingOrder();
00078     }
00079     ~KWinModulePrivate()
00080     {
00081     }
00082     QPtrList<KWinModule> modules;
00083 
00084     QValueList<WId> windows;
00085     QValueList<WId> stackingOrder;
00086     QValueList<WId> systemTrayWindows;
00087 
00088     struct StrutData
00089     {
00090         StrutData( WId window_, const NETStrut& strut_, int desktop_ )
00091             : window( window_ ), strut( strut_ ), desktop( desktop_ ) {};
00092         StrutData() {}; // for QValueList to be happy
00093         WId window;
00094         NETStrut strut;
00095         int desktop;
00096     };
00097     QValueList<StrutData> strutWindows;
00098     QValueList<WId> possibleStrutWindows;
00099     bool strutSignalConnected;
00100     int what;
00101 
00102     void addClient(Window);
00103     void removeClient(Window);
00104     void addSystemTrayWin(Window);
00105     void removeSystemTrayWin(Window);
00106 
00107     bool x11Event( XEvent * ev );
00108 
00109     void updateStackingOrder();
00110     bool removeStrutWindow( WId );
00111 
00112     QSize numberOfViewports(int desktop) const;
00113     QPoint currentViewport(int desktop) const;
00114 };
00115 
00116 KWinModule::KWinModule( QObject* parent )
00117     : QObject( parent, "kwin_module" )
00118 {
00119     init(INFO_ALL);
00120 }
00121 
00122 KWinModule::KWinModule( QObject* parent, int what )
00123     : QObject( parent, "kwin_module" )
00124 {
00125     init(what);
00126 }
00127 
00128 void KWinModule::init(int what)
00129 {
00130     if (what >= INFO_WINDOWS)
00131        what = INFO_WINDOWS;
00132     else
00133        what = INFO_DESKTOP;
00134 
00135     if ( !static_d )
00136     {
00137         static_d = new KWinModulePrivate(what);
00138     }
00139     else if (static_d->what < what)
00140     {
00141         QPtrList<KWinModule> modules = static_d->modules;
00142         delete static_d;
00143         static_d = new KWinModulePrivate(what);
00144         static_d->modules = modules;
00145         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00146             (*mit)->d = static_d;
00147     }
00148     
00149     d = static_d;
00150     d->modules.append( this );
00151 }
00152 
00153 KWinModule::~KWinModule()
00154 {
00155     d->modules.removeRef( this );
00156     if ( d->modules.isEmpty() ) {
00157     delete d;
00158     static_d = 0;
00159     }
00160 }
00161 
00162 const QValueList<WId>& KWinModule::windows() const
00163 {
00164     return d->windows;
00165 }
00166 
00167 const QValueList<WId>& KWinModule::stackingOrder() const
00168 {
00169     return d->stackingOrder;
00170 }
00171 
00172 
00173 bool KWinModule::hasWId(WId w) const
00174 {
00175     return d->windows.findIndex( w ) != -1;
00176 }
00177 
00178 const QValueList<WId>& KWinModule::systemTrayWindows() const
00179 {
00180     return d->systemTrayWindows;
00181 }
00182 
00183 QSize KWinModulePrivate::numberOfViewports(int desktop) const
00184 {
00185     NETSize netdesktop = desktopGeometry(desktop);
00186 
00187     return QSize(netdesktop.width / QApplication::desktop()->width(),
00188             netdesktop.height / QApplication::desktop()->height());
00189 }
00190 
00191 QPoint KWinModulePrivate::currentViewport(int desktop) const
00192 {
00193     NETPoint netviewport = desktopViewport(desktop);
00194 
00195     return QPoint(1+(netviewport.x / QApplication::desktop()->width()),
00196             1+(netviewport.y / QApplication::desktop()->height()));
00197 }
00198 
00199 bool KWinModulePrivate::x11Event( XEvent * ev )
00200 {
00201     if ( ev->xany.window == qt_xrootwin() ) {
00202         int old_current_desktop = currentDesktop();
00203         WId old_active_window = activeWindow();
00204         int old_number_of_desktops = numberOfDesktops();
00205         bool old_showing_desktop = showingDesktop();
00206         unsigned long m[ 5 ];
00207     NETRootInfo::event( ev, m, 5 );
00208 
00209     if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
00210         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00211         emit (*mit)->currentDesktopChanged( currentDesktop() );
00212     if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
00213         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00214         emit (*mit)->activeWindowChanged( activeWindow() );
00215     if ( m[ PROTOCOLS ] & DesktopViewport ) {
00216         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00217         emit (*mit)->currentDesktopViewportChanged(currentDesktop(),
00218                         currentViewport(currentDesktop()));
00219         }
00220     if ( m[ PROTOCOLS ] & DesktopGeometry ) {
00221         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00222         emit (*mit)->desktopGeometryChanged(currentDesktop());
00223     }
00224     if ( m[ PROTOCOLS ] & DesktopNames )
00225         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00226         emit (*mit)->desktopNamesChanged();
00227     if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
00228         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00229         emit (*mit)->numberOfDesktopsChanged( numberOfDesktops() );
00230     if ( m[ PROTOCOLS ] & WorkArea )
00231         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00232         emit (*mit)->workAreaChanged();
00233     if ( m[ PROTOCOLS ] & ClientListStacking ) {
00234         updateStackingOrder();
00235         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00236         emit (*mit)->stackingOrderChanged();
00237     }
00238         if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
00239         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00240         emit (*mit)->showingDesktopChanged( showingDesktop());
00241         }
00242     } else  if ( windows.findIndex( ev->xany.window ) != -1 ){
00243     NETWinInfo ni( qt_xdisplay(), ev->xany.window, qt_xrootwin(), 0 );
00244         unsigned long dirty[ 2 ];
00245     ni.event( ev, dirty, 2 );
00246     if ( ev->type ==PropertyNotify ) {
00247             if( ev->xproperty.atom == XA_WM_HINTS )
00248             dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIcon; // support for old icons
00249             else if( ev->xproperty.atom == XA_WM_NAME )
00250                 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName; // support for old name
00251             else if( ev->xproperty.atom == XA_WM_ICON_NAME )
00252                 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName; // support for old iconic name
00253         }
00254     if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 ) {
00255             removeStrutWindow( ev->xany.window );
00256             if ( possibleStrutWindows.findIndex( ev->xany.window ) == -1 )
00257             possibleStrutWindows.append( ev->xany.window );
00258     }
00259     if ( dirty[ NETWinInfo::PROTOCOLS ] || dirty[ NETWinInfo::PROTOCOLS2 ] ) {
00260         for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00261         emit (*mit)->windowChanged( ev->xany.window );
00262                 emit (*mit)->windowChanged( ev->xany.window, dirty );
00263         emit (*mit)->windowChanged( ev->xany.window, dirty[ NETWinInfo::PROTOCOLS ] );
00264         if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
00265             emit (*mit)->strutChanged();
00266         }
00267     }
00268     }
00269 
00270     return false;
00271 }
00272 
00273 bool KWinModulePrivate::removeStrutWindow( WId w )
00274 {
00275     for( QValueList< StrutData >::Iterator it = strutWindows.begin();
00276          it != strutWindows.end();
00277          ++it )
00278         if( (*it).window == w ) {
00279             strutWindows.remove( it );
00280             return true;
00281         }
00282     return false;
00283 }
00284 
00285 void KWinModulePrivate::updateStackingOrder()
00286 {
00287     stackingOrder.clear();
00288     for ( int i = 0; i <  clientListStackingCount(); i++ )
00289     stackingOrder.append( clientListStacking()[i] );
00290 }
00291 
00292 void KWinModulePrivate::addClient(Window w)
00293 {
00294     if ( (what >= KWinModule::INFO_WINDOWS) && !QWidget::find( w ) )
00295     XSelectInput( qt_xdisplay(), w, PropertyChangeMask | StructureNotifyMask );
00296     bool emit_strutChanged = false;
00297     if( strutSignalConnected && modules.count() > 0 ) {
00298         NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut | NET::WMDesktop );
00299         NETStrut strut = info.strut();
00300         if ( strut.left || strut.top || strut.right || strut.bottom ) {
00301             strutWindows.append( StrutData( w, strut, info.desktop()));
00302             emit_strutChanged = true;
00303         }
00304     } else
00305         possibleStrutWindows.append( w );
00306     windows.append( w );
00307     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00308     emit (*mit)->windowAdded( w );
00309     if ( emit_strutChanged )
00310         emit (*mit)->strutChanged();
00311     }
00312 }
00313 
00314 void KWinModulePrivate::removeClient(Window w)
00315 {
00316     bool emit_strutChanged = removeStrutWindow( w );
00317     if( strutSignalConnected && possibleStrutWindows.findIndex( w ) != -1 && modules.count() > 0 ) {
00318         NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut );
00319         NETStrut strut = info.strut();
00320         if ( strut.left || strut.top || strut.right || strut.bottom ) {
00321             emit_strutChanged = true;
00322         }
00323     }
00324     possibleStrutWindows.remove( w );
00325     windows.remove( w );
00326     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00327     emit (*mit)->windowRemoved( w );
00328     if ( emit_strutChanged )
00329         emit (*mit)->strutChanged();
00330     }
00331 }
00332 
00333 void KWinModulePrivate::addSystemTrayWin(Window w)
00334 {
00335     systemTrayWindows.append( w );
00336     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00337     emit (*mit)->systemTrayWindowAdded( w );
00338 }
00339 
00340 void KWinModulePrivate::removeSystemTrayWin(Window w)
00341 {
00342     systemTrayWindows.remove( w );
00343     for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00344     emit (*mit)->systemTrayWindowRemoved( w );
00345 }
00346 
00347 int KWinModule::currentDesktop() const
00348 {
00349     return d->currentDesktop();
00350 }
00351 
00352 int KWinModule::numberOfDesktops() const
00353 {
00354     return d->numberOfDesktops();
00355 }
00356 
00357 QSize KWinModule::numberOfViewports(int desktop) const
00358 {
00359     return d->numberOfViewports(desktop);
00360 }
00361 
00362 QPoint KWinModule::currentViewport(int desktop) const
00363 {
00364     return d->currentViewport(desktop);
00365 }
00366 
00367 WId KWinModule::activeWindow() const
00368 {
00369     return d->activeWindow();
00370 }
00371 
00372 bool KWinModule::showingDesktop() const
00373 {
00374     return d->showingDesktop();
00375 }
00376 
00377 QRect KWinModule::workArea( int desktop ) const
00378 {
00379     int desk  = (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop();
00380     if ( desk <= 0 )
00381     return QApplication::desktop()->geometry();
00382     NETRect r = d->workArea( desk );
00383     if( r.size.width <= 0 || r.size.height <= 0 ) // not set
00384     return QApplication::desktop()->geometry();
00385     return QRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00386 }
00387 
00388 QRect KWinModule::workArea( const QValueList<WId>& exclude, int desktop ) const
00389 {
00390     QRect all = QApplication::desktop()->geometry();
00391     QRect a = all;
00392 
00393     if (desktop == -1)
00394     desktop = d->currentDesktop();
00395 
00396     QValueList<WId>::ConstIterator it1;
00397     for( it1 = d->windows.begin(); it1 != d->windows.end(); ++it1 ) {
00398 
00399     if(exclude.findIndex(*it1) != -1) continue;
00400         
00401 // Kicker (very) extensively calls this function, causing hundreds of roundtrips just
00402 // to repeatedly find out struts of all windows. Therefore strut values for strut
00403 // windows are cached here.
00404         NETStrut strut;
00405         QValueList< KWinModulePrivate::StrutData >::Iterator it2 = d->strutWindows.begin();
00406         for( ;
00407              it2 != d->strutWindows.end();
00408              ++it2 )
00409             if( (*it2).window == *it1 )
00410                 break;
00411         if( it2 != d->strutWindows.end()) {
00412             if(!((*it2).desktop == desktop || (*it2).desktop == NETWinInfo::OnAllDesktops ))
00413                 continue;
00414             strut = (*it2).strut;
00415         } else if( d->possibleStrutWindows.findIndex( *it1 ) != -1 ) {
00416             NETWinInfo info( qt_xdisplay(), (*it1), qt_xrootwin(), NET::WMStrut | NET::WMDesktop);
00417         strut = info.strut();
00418             d->possibleStrutWindows.remove( *it1 );
00419             d->strutWindows.append( KWinModulePrivate::StrutData( *it1, info.strut(), info.desktop()));
00420         if(!(info.desktop() == desktop || info.desktop() == NETWinInfo::OnAllDesktops))
00421                 continue;
00422         } else
00423             continue; // not a strut window
00424 
00425     QRect r = all;
00426     if ( strut.left > 0 )
00427         r.setLeft( r.left() + (int) strut.left );
00428     if ( strut.top > 0 )
00429         r.setTop( r.top() + (int) strut.top );
00430     if ( strut.right > 0  )
00431         r.setRight( r.right() - (int) strut.right );
00432     if ( strut.bottom > 0  )
00433         r.setBottom( r.bottom() - (int) strut.bottom );
00434 
00435     a = a.intersect(r);
00436     }
00437     return a;
00438 }
00439 
00440 void KWinModule::connectNotify( const char* signal )
00441 {
00442     if( !d->strutSignalConnected && qstrcmp( signal, SIGNAL(strutChanged())) == 0 )
00443         d->strutSignalConnected = true;
00444     QObject::connectNotify( signal );
00445 }
00446 
00447 QString KWinModule::desktopName( int desktop ) const
00448 {
00449     const char* name = d->desktopName( (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop() );
00450     if ( name && name[0] )
00451     return QString::fromUtf8( name );
00452     return i18n("Desktop %1").arg( desktop );
00453 }
00454 
00455 void KWinModule::setDesktopName( int desktop, const QString& name )
00456 {
00457     if (desktop <= 0 || desktop > (int) d->numberOfDesktops() )
00458     desktop = currentDesktop();
00459     d->setDesktopName( desktop, name.utf8().data() );
00460 }
00461 
00462 
00463 void KWinModule::doNotManage( const QString& title )
00464 {
00465     if ( !kapp->dcopClient()->isAttached() )
00466     kapp->dcopClient()->attach();
00467     QByteArray data, replyData;
00468     QCString replyType;
00469     QDataStream arg(data, IO_WriteOnly);
00470     arg << title;
00471     kapp->dcopClient()->call("kwin", "", "doNotManage(QString)",
00472                  data, replyType, replyData);
00473 }
00474 
00475 #include "kwinmodule.moc"
00476 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys