00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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();
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() {};
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 QSize s(netdesktop.width / QApplication::desktop()->width(),
00187 netdesktop.height / QApplication::desktop()->height());
00188
00189
00190 if (s.width() < 1) s.setWidth(1);
00191 if (s.height() < 1) s.setHeight(1);
00192 return s;
00193 }
00194
00195 QPoint KWinModulePrivate::currentViewport(int desktop) const
00196 {
00197 NETPoint netviewport = desktopViewport(desktop);
00198
00199 return QPoint(1+(netviewport.x / QApplication::desktop()->width()),
00200 1+(netviewport.y / QApplication::desktop()->height()));
00201 }
00202
00203 bool KWinModulePrivate::x11Event( XEvent * ev )
00204 {
00205 if ( ev->xany.window == qt_xrootwin() ) {
00206 int old_current_desktop = currentDesktop();
00207 WId old_active_window = activeWindow();
00208 int old_number_of_desktops = numberOfDesktops();
00209 bool old_showing_desktop = showingDesktop();
00210 unsigned long m[ 5 ];
00211 NETRootInfo::event( ev, m, 5 );
00212
00213 if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
00214 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00215 emit (*mit)->currentDesktopChanged( currentDesktop() );
00216 if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
00217 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00218 emit (*mit)->activeWindowChanged( activeWindow() );
00219 if ( m[ PROTOCOLS ] & DesktopViewport ) {
00220 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00221 emit (*mit)->currentDesktopViewportChanged(currentDesktop(),
00222 currentViewport(currentDesktop()));
00223 }
00224 if ( m[ PROTOCOLS ] & DesktopGeometry ) {
00225 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00226 emit (*mit)->desktopGeometryChanged(currentDesktop());
00227 }
00228 if ( m[ PROTOCOLS ] & DesktopNames )
00229 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00230 emit (*mit)->desktopNamesChanged();
00231 if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
00232 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00233 emit (*mit)->numberOfDesktopsChanged( numberOfDesktops() );
00234 if ( m[ PROTOCOLS ] & WorkArea )
00235 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00236 emit (*mit)->workAreaChanged();
00237 if ( m[ PROTOCOLS ] & ClientListStacking ) {
00238 updateStackingOrder();
00239 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00240 emit (*mit)->stackingOrderChanged();
00241 }
00242 if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
00243 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00244 emit (*mit)->showingDesktopChanged( showingDesktop());
00245 }
00246 } else if ( windows.findIndex( ev->xany.window ) != -1 ){
00247 NETWinInfo ni( qt_xdisplay(), ev->xany.window, qt_xrootwin(), 0 );
00248 unsigned long dirty[ 2 ];
00249 ni.event( ev, dirty, 2 );
00250 if ( ev->type ==PropertyNotify ) {
00251 if( ev->xproperty.atom == XA_WM_HINTS )
00252 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIcon;
00253 else if( ev->xproperty.atom == XA_WM_NAME )
00254 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName;
00255 else if( ev->xproperty.atom == XA_WM_ICON_NAME )
00256 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName;
00257 }
00258 if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 ) {
00259 removeStrutWindow( ev->xany.window );
00260 if ( possibleStrutWindows.findIndex( ev->xany.window ) == -1 )
00261 possibleStrutWindows.append( ev->xany.window );
00262 }
00263 if ( dirty[ NETWinInfo::PROTOCOLS ] || dirty[ NETWinInfo::PROTOCOLS2 ] ) {
00264 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00265 emit (*mit)->windowChanged( ev->xany.window );
00266 emit (*mit)->windowChanged( ev->xany.window, dirty );
00267 emit (*mit)->windowChanged( ev->xany.window, dirty[ NETWinInfo::PROTOCOLS ] );
00268 if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
00269 emit (*mit)->strutChanged();
00270 }
00271 }
00272 }
00273
00274 return false;
00275 }
00276
00277 bool KWinModulePrivate::removeStrutWindow( WId w )
00278 {
00279 for( QValueList< StrutData >::Iterator it = strutWindows.begin();
00280 it != strutWindows.end();
00281 ++it )
00282 if( (*it).window == w ) {
00283 strutWindows.remove( it );
00284 return true;
00285 }
00286 return false;
00287 }
00288
00289 void KWinModulePrivate::updateStackingOrder()
00290 {
00291 stackingOrder.clear();
00292 for ( int i = 0; i < clientListStackingCount(); i++ )
00293 stackingOrder.append( clientListStacking()[i] );
00294 }
00295
00296 void KWinModulePrivate::addClient(Window w)
00297 {
00298 if ( (what >= KWinModule::INFO_WINDOWS) && !QWidget::find( w ) )
00299 XSelectInput( qt_xdisplay(), w, PropertyChangeMask | StructureNotifyMask );
00300 bool emit_strutChanged = false;
00301 if( strutSignalConnected && modules.count() > 0 ) {
00302 NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut | NET::WMDesktop );
00303 NETStrut strut = info.strut();
00304 if ( strut.left || strut.top || strut.right || strut.bottom ) {
00305 strutWindows.append( StrutData( w, strut, info.desktop()));
00306 emit_strutChanged = true;
00307 }
00308 } else
00309 possibleStrutWindows.append( w );
00310 windows.append( w );
00311 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00312 emit (*mit)->windowAdded( w );
00313 if ( emit_strutChanged )
00314 emit (*mit)->strutChanged();
00315 }
00316 }
00317
00318 void KWinModulePrivate::removeClient(Window w)
00319 {
00320 bool emit_strutChanged = removeStrutWindow( w );
00321 if( strutSignalConnected && possibleStrutWindows.findIndex( w ) != -1 && modules.count() > 0 ) {
00322 NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut );
00323 NETStrut strut = info.strut();
00324 if ( strut.left || strut.top || strut.right || strut.bottom ) {
00325 emit_strutChanged = true;
00326 }
00327 }
00328 possibleStrutWindows.remove( w );
00329 windows.remove( w );
00330 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
00331 emit (*mit)->windowRemoved( w );
00332 if ( emit_strutChanged )
00333 emit (*mit)->strutChanged();
00334 }
00335 }
00336
00337 void KWinModulePrivate::addSystemTrayWin(Window w)
00338 {
00339 systemTrayWindows.append( w );
00340 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00341 emit (*mit)->systemTrayWindowAdded( w );
00342 }
00343
00344 void KWinModulePrivate::removeSystemTrayWin(Window w)
00345 {
00346 systemTrayWindows.remove( w );
00347 for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
00348 emit (*mit)->systemTrayWindowRemoved( w );
00349 }
00350
00351 int KWinModule::currentDesktop() const
00352 {
00353 return d->currentDesktop();
00354 }
00355
00356 int KWinModule::numberOfDesktops() const
00357 {
00358 return d->numberOfDesktops();
00359 }
00360
00361 QSize KWinModule::numberOfViewports(int desktop) const
00362 {
00363 return d->numberOfViewports(desktop);
00364 }
00365
00366 QPoint KWinModule::currentViewport(int desktop) const
00367 {
00368 return d->currentViewport(desktop);
00369 }
00370
00371 WId KWinModule::activeWindow() const
00372 {
00373 return d->activeWindow();
00374 }
00375
00376 bool KWinModule::showingDesktop() const
00377 {
00378 return d->showingDesktop();
00379 }
00380
00381 QRect KWinModule::workArea( int desktop ) const
00382 {
00383 int desk = (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop();
00384 if ( desk <= 0 )
00385 return QApplication::desktop()->geometry();
00386 NETRect r = d->workArea( desk );
00387 if( r.size.width <= 0 || r.size.height <= 0 )
00388 return QApplication::desktop()->geometry();
00389 return QRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00390 }
00391
00392 QRect KWinModule::workArea( const QValueList<WId>& exclude, int desktop ) const
00393 {
00394 QRect all = QApplication::desktop()->geometry();
00395 QRect a = all;
00396
00397 if (desktop == -1)
00398 desktop = d->currentDesktop();
00399
00400 QValueList<WId>::ConstIterator it1;
00401 for( it1 = d->windows.begin(); it1 != d->windows.end(); ++it1 ) {
00402
00403 if(exclude.findIndex(*it1) != -1) continue;
00404
00405
00406
00407
00408 NETStrut strut;
00409 QValueList< KWinModulePrivate::StrutData >::Iterator it2 = d->strutWindows.begin();
00410 for( ;
00411 it2 != d->strutWindows.end();
00412 ++it2 )
00413 if( (*it2).window == *it1 )
00414 break;
00415 if( it2 != d->strutWindows.end()) {
00416 if(!((*it2).desktop == desktop || (*it2).desktop == NETWinInfo::OnAllDesktops ))
00417 continue;
00418 strut = (*it2).strut;
00419 } else if( d->possibleStrutWindows.findIndex( *it1 ) != -1 ) {
00420 NETWinInfo info( qt_xdisplay(), (*it1), qt_xrootwin(), NET::WMStrut | NET::WMDesktop);
00421 strut = info.strut();
00422 d->possibleStrutWindows.remove( *it1 );
00423 d->strutWindows.append( KWinModulePrivate::StrutData( *it1, info.strut(), info.desktop()));
00424 if(!(info.desktop() == desktop || info.desktop() == NETWinInfo::OnAllDesktops))
00425 continue;
00426 } else
00427 continue;
00428
00429 QRect r = all;
00430 if ( strut.left > 0 )
00431 r.setLeft( r.left() + (int) strut.left );
00432 if ( strut.top > 0 )
00433 r.setTop( r.top() + (int) strut.top );
00434 if ( strut.right > 0 )
00435 r.setRight( r.right() - (int) strut.right );
00436 if ( strut.bottom > 0 )
00437 r.setBottom( r.bottom() - (int) strut.bottom );
00438
00439 a = a.intersect(r);
00440 }
00441 return a;
00442 }
00443
00444 void KWinModule::connectNotify( const char* signal )
00445 {
00446 if( !d->strutSignalConnected && qstrcmp( signal, SIGNAL(strutChanged())) == 0 )
00447 d->strutSignalConnected = true;
00448 QObject::connectNotify( signal );
00449 }
00450
00451 QString KWinModule::desktopName( int desktop ) const
00452 {
00453 const char* name = d->desktopName( (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop() );
00454 if ( name && name[0] )
00455 return QString::fromUtf8( name );
00456 return i18n("Desktop %1").arg( desktop );
00457 }
00458
00459 void KWinModule::setDesktopName( int desktop, const QString& name )
00460 {
00461 if (desktop <= 0 || desktop > (int) d->numberOfDesktops() )
00462 desktop = currentDesktop();
00463 d->setDesktopName( desktop, name.utf8().data() );
00464 }
00465
00466
00467 void KWinModule::doNotManage( const QString& title )
00468 {
00469 if ( !kapp->dcopClient()->isAttached() )
00470 kapp->dcopClient()->attach();
00471 QByteArray data, replyData;
00472 QCString replyType;
00473 QDataStream arg(data, IO_WriteOnly);
00474 arg << title;
00475 kapp->dcopClient()->call("kwin", "", "doNotManage(QString)",
00476 data, replyType, replyData);
00477 }
00478
00479 #include "kwinmodule.moc"
00480 #endif