twinmodule.cpp
00001 /* 00002 $Id$ 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 <tqwidget.h> 00025 #ifdef Q_WS_X11 //FIXME 00026 #include "twinmodule.h" 00027 #include "twin.h" 00028 #include <X11/Xatom.h> 00029 #include "tdeapplication.h" 00030 #include "kdebug.h" 00031 #include <tqtl.h> 00032 #include <tqptrlist.h> 00033 #include <tdelocale.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 TQWidget, public NETRootInfo4 00062 { 00063 public: 00064 KWinModulePrivate(int _what) 00065 : TQWidget(0,0), NETRootInfo4( tqt_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 TQPtrList<KWinModule> modules; 00083 00084 TQValueList<WId> windows; 00085 TQValueList<WId> stackingOrder; 00086 TQValueList<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 TQValueList to be happy 00093 WId window; 00094 NETStrut strut; 00095 int desktop; 00096 }; 00097 TQValueList<StrutData> strutWindows; 00098 TQValueList<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 TQSize numberOfViewports(int desktop) const; 00113 TQPoint currentViewport(int desktop) const; 00114 }; 00115 00116 KWinModule::KWinModule( TQObject* parent ) 00117 : TQObject( parent, "twin_module" ) 00118 { 00119 init(INFO_ALL); 00120 } 00121 00122 KWinModule::KWinModule( TQObject* parent, int what ) 00123 : TQObject( parent, "twin_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 TQPtrList<KWinModule> modules = static_d->modules; 00142 delete static_d; 00143 static_d = new KWinModulePrivate(what); 00144 static_d->modules = modules; 00145 for ( TQPtrListIterator<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 TQValueList<WId>& KWinModule::windows() const 00163 { 00164 return d->windows; 00165 } 00166 00167 const TQValueList<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 TQValueList<WId>& KWinModule::systemTrayWindows() const 00179 { 00180 return d->systemTrayWindows; 00181 } 00182 00183 TQSize KWinModulePrivate::numberOfViewports(int desktop) const 00184 { 00185 NETSize netdesktop = desktopGeometry(desktop); 00186 TQSize s(netdesktop.width / TQApplication::desktop()->width(), 00187 netdesktop.height / TQApplication::desktop()->height()); 00188 00189 // workaround some twin bugs 00190 if (s.width() < 1) s.setWidth(1); 00191 if (s.height() < 1) s.setHeight(1); 00192 return s; 00193 } 00194 00195 TQPoint KWinModulePrivate::currentViewport(int desktop) const 00196 { 00197 NETPoint netviewport = desktopViewport(desktop); 00198 00199 return TQPoint(1+(netviewport.x / TQApplication::desktop()->width()), 00200 1+(netviewport.y / TQApplication::desktop()->height())); 00201 } 00202 00203 bool KWinModulePrivate::x11Event( XEvent * ev ) 00204 { 00205 if ( ev->xany.window == tqt_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 ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00215 emit (*mit)->currentDesktopChanged( currentDesktop() ); 00216 if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window ) 00217 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00218 emit (*mit)->activeWindowChanged( activeWindow() ); 00219 if ( m[ PROTOCOLS ] & DesktopViewport ) { 00220 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00221 emit (*mit)->currentDesktopViewportChanged(currentDesktop(), 00222 currentViewport(currentDesktop())); 00223 } 00224 if ( m[ PROTOCOLS ] & DesktopGeometry ) { 00225 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00226 emit (*mit)->desktopGeometryChanged(currentDesktop()); 00227 } 00228 if ( m[ PROTOCOLS ] & DesktopNames ) 00229 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00230 emit (*mit)->desktopNamesChanged(); 00231 if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops ) 00232 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00233 emit (*mit)->numberOfDesktopsChanged( numberOfDesktops() ); 00234 if ( m[ PROTOCOLS ] & WorkArea ) 00235 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00236 emit (*mit)->workAreaChanged(); 00237 if ( m[ PROTOCOLS ] & ClientListStacking ) { 00238 updateStackingOrder(); 00239 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00240 emit (*mit)->stackingOrderChanged(); 00241 } 00242 if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) { 00243 for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) 00244 emit (*mit)->showingDesktopChanged( showingDesktop()); 00245 } 00246 } else if ( windows.findIndex( ev->xany.window ) != -1 ){ 00247 NETWinInfo ni( tqt_xdisplay(), ev->xany.window, tqt_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; // support for old icons 00253 else if( ev->xproperty.atom == XA_WM_NAME ) 00254 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName; // support for old name 00255 else if( ev->xproperty.atom == XA_WM_ICON_NAME ) 00256 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName; // support for old iconic name 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 ( TQPtrListIterator<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( TQValueList< 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) && !TQWidget::find( w ) ) 00299 XSelectInput( tqt_xdisplay(), w, PropertyChangeMask | StructureNotifyMask ); 00300 bool emit_strutChanged = false; 00301 if( strutSignalConnected && modules.count() > 0 ) { 00302 NETWinInfo info( tqt_xdisplay(), w, tqt_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 ( TQPtrListIterator<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( tqt_xdisplay(), w, tqt_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 ( TQPtrListIterator<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 ( TQPtrListIterator<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 ( TQPtrListIterator<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 TQSize KWinModule::numberOfViewports(int desktop) const 00362 { 00363 return d->numberOfViewports(desktop); 00364 } 00365 00366 TQPoint 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 TQRect KWinModule::workArea( int desktop ) const 00382 { 00383 int desk = (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop(); 00384 if ( desk <= 0 ) 00385 return TQApplication::desktop()->geometry(); 00386 NETRect r = d->workArea( desk ); 00387 if( r.size.width <= 0 || r.size.height <= 0 ) // not set 00388 return TQApplication::desktop()->geometry(); 00389 return TQRect( r.pos.x, r.pos.y, r.size.width, r.size.height ); 00390 } 00391 00392 TQRect KWinModule::workArea( const TQValueList<WId>& exclude, int desktop ) const 00393 { 00394 TQRect all = TQApplication::desktop()->geometry(); 00395 TQRect a = all; 00396 00397 if (desktop == -1) 00398 desktop = d->currentDesktop(); 00399 00400 TQValueList<WId>::ConstIterator it1; 00401 for( it1 = d->windows.begin(); it1 != d->windows.end(); ++it1 ) { 00402 00403 if(exclude.findIndex(*it1) != -1) continue; 00404 00405 // Kicker (very) extensively calls this function, causing hundreds of roundtrips just 00406 // to repeatedly find out struts of all windows. Therefore strut values for strut 00407 // windows are cached here. 00408 NETStrut strut; 00409 TQValueList< 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( tqt_xdisplay(), (*it1), tqt_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; // not a strut window 00428 00429 TQRect 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 TQRect tmp; 00440 tmp = a.intersect(r); 00441 a = tmp; 00442 } 00443 return a; 00444 } 00445 00446 void KWinModule::connectNotify( const char* signal ) 00447 { 00448 if( !d->strutSignalConnected && qstrcmp( signal, TQT_SIGNAL(strutChanged())) == 0 ) 00449 d->strutSignalConnected = true; 00450 TQObject::connectNotify( signal ); 00451 } 00452 00453 TQString KWinModule::desktopName( int desktop ) const 00454 { 00455 const char* name = d->desktopName( (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop() ); 00456 if ( name && name[0] ) 00457 return TQString::fromUtf8( name ); 00458 return i18n("Desktop %1").arg( desktop ); 00459 } 00460 00461 void KWinModule::setDesktopName( int desktop, const TQString& name ) 00462 { 00463 if (desktop <= 0 || desktop > (int) d->numberOfDesktops() ) 00464 desktop = currentDesktop(); 00465 d->setDesktopName( desktop, name.utf8().data() ); 00466 } 00467 00468 00469 void KWinModule::doNotManage( const TQString& title ) 00470 { 00471 if ( !kapp->dcopClient()->isAttached() ) 00472 kapp->dcopClient()->attach(); 00473 TQByteArray data, replyData; 00474 TQCString replyType; 00475 TQDataStream arg(data, IO_WriteOnly); 00476 arg << title; 00477 kapp->dcopClient()->call("twin", "", "doNotManage(TQString)", 00478 data, replyType, replyData); 00479 } 00480 00481 #include "twinmodule.moc" 00482 #endif