You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
483 lines
15 KiB
483 lines
15 KiB
/*
|
|
$Id$
|
|
|
|
This file is part of the KDE libraries
|
|
Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <tqwidget.h>
|
|
#ifdef Q_WS_X11 //FIXME
|
|
#include "twinmodule.h"
|
|
#include "twin.h"
|
|
#include <X11/Xatom.h>
|
|
#include "kapplication.h"
|
|
#include "kdebug.h"
|
|
#include <tqtl.h>
|
|
#include <tqptrlist.h>
|
|
#include <klocale.h>
|
|
#include <dcopclient.h>
|
|
#include "netwm.h"
|
|
|
|
static KWinModulePrivate* static_d = 0;
|
|
|
|
static unsigned long windows_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking |
|
|
NET::NumberOfDesktops |
|
|
NET::DesktopGeometry |
|
|
NET::DesktopViewport |
|
|
NET::CurrentDesktop |
|
|
NET::DesktopNames |
|
|
NET::ActiveWindow |
|
|
NET::WorkArea |
|
|
NET::KDESystemTrayWindows,
|
|
NET::WM2ShowingDesktop };
|
|
|
|
static unsigned long desktop_properties[ 2 ] = {
|
|
NET::NumberOfDesktops |
|
|
NET::DesktopGeometry |
|
|
NET::DesktopViewport |
|
|
NET::CurrentDesktop |
|
|
NET::DesktopNames |
|
|
NET::ActiveWindow |
|
|
NET::WorkArea |
|
|
NET::KDESystemTrayWindows,
|
|
NET::WM2ShowingDesktop };
|
|
|
|
class KWinModulePrivate : public TQWidget, public NETRootInfo4
|
|
{
|
|
public:
|
|
KWinModulePrivate(int _what)
|
|
: TQWidget(0,0), NETRootInfo4( tqt_xdisplay(),
|
|
_what >= KWinModule::INFO_WINDOWS ?
|
|
windows_properties : desktop_properties,
|
|
2,
|
|
-1, false
|
|
),
|
|
strutSignalConnected( false ),
|
|
what( _what )
|
|
{
|
|
kapp->installX11EventFilter( this );
|
|
(void ) kapp->desktop(); //trigger desktop widget creation to select root window events
|
|
activate();
|
|
updateStackingOrder();
|
|
}
|
|
~KWinModulePrivate()
|
|
{
|
|
}
|
|
TQPtrList<KWinModule> modules;
|
|
|
|
TQValueList<WId> windows;
|
|
TQValueList<WId> stackingOrder;
|
|
TQValueList<WId> systemTrayWindows;
|
|
|
|
struct StrutData
|
|
{
|
|
StrutData( WId window_, const NETStrut& strut_, int desktop_ )
|
|
: window( window_ ), strut( strut_ ), desktop( desktop_ ) {};
|
|
StrutData() {}; // for TQValueList to be happy
|
|
WId window;
|
|
NETStrut strut;
|
|
int desktop;
|
|
};
|
|
TQValueList<StrutData> strutWindows;
|
|
TQValueList<WId> possibleStrutWindows;
|
|
bool strutSignalConnected;
|
|
int what;
|
|
|
|
void addClient(Window);
|
|
void removeClient(Window);
|
|
void addSystemTrayWin(Window);
|
|
void removeSystemTrayWin(Window);
|
|
|
|
bool x11Event( XEvent * ev );
|
|
|
|
void updateStackingOrder();
|
|
bool removeStrutWindow( WId );
|
|
|
|
TQSize numberOfViewports(int desktop) const;
|
|
TQPoint currentViewport(int desktop) const;
|
|
};
|
|
|
|
KWinModule::KWinModule( TQObject* parent )
|
|
: TQObject( parent, "twin_module" )
|
|
{
|
|
init(INFO_ALL);
|
|
}
|
|
|
|
KWinModule::KWinModule( TQObject* parent, int what )
|
|
: TQObject( parent, "twin_module" )
|
|
{
|
|
init(what);
|
|
}
|
|
|
|
void KWinModule::init(int what)
|
|
{
|
|
if (what >= INFO_WINDOWS)
|
|
what = INFO_WINDOWS;
|
|
else
|
|
what = INFO_DESKTOP;
|
|
|
|
if ( !static_d )
|
|
{
|
|
static_d = new KWinModulePrivate(what);
|
|
}
|
|
else if (static_d->what < what)
|
|
{
|
|
TQPtrList<KWinModule> modules = static_d->modules;
|
|
delete static_d;
|
|
static_d = new KWinModulePrivate(what);
|
|
static_d->modules = modules;
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
(*mit)->d = static_d;
|
|
}
|
|
|
|
d = static_d;
|
|
d->modules.append( this );
|
|
}
|
|
|
|
KWinModule::~KWinModule()
|
|
{
|
|
d->modules.removeRef( this );
|
|
if ( d->modules.isEmpty() ) {
|
|
delete d;
|
|
static_d = 0;
|
|
}
|
|
}
|
|
|
|
const TQValueList<WId>& KWinModule::windows() const
|
|
{
|
|
return d->windows;
|
|
}
|
|
|
|
const TQValueList<WId>& KWinModule::stackingOrder() const
|
|
{
|
|
return d->stackingOrder;
|
|
}
|
|
|
|
|
|
bool KWinModule::hasWId(WId w) const
|
|
{
|
|
return d->windows.findIndex( w ) != -1;
|
|
}
|
|
|
|
const TQValueList<WId>& KWinModule::systemTrayWindows() const
|
|
{
|
|
return d->systemTrayWindows;
|
|
}
|
|
|
|
TQSize KWinModulePrivate::numberOfViewports(int desktop) const
|
|
{
|
|
NETSize netdesktop = desktopGeometry(desktop);
|
|
TQSize s(netdesktop.width / TQApplication::desktop()->width(),
|
|
netdesktop.height / TQApplication::desktop()->height());
|
|
|
|
// workaround some twin bugs
|
|
if (s.width() < 1) s.setWidth(1);
|
|
if (s.height() < 1) s.setHeight(1);
|
|
return s;
|
|
}
|
|
|
|
TQPoint KWinModulePrivate::currentViewport(int desktop) const
|
|
{
|
|
NETPoint netviewport = desktopViewport(desktop);
|
|
|
|
return TQPoint(1+(netviewport.x / TQApplication::desktop()->width()),
|
|
1+(netviewport.y / TQApplication::desktop()->height()));
|
|
}
|
|
|
|
bool KWinModulePrivate::x11Event( XEvent * ev )
|
|
{
|
|
if ( ev->xany.window == tqt_xrootwin() ) {
|
|
int old_current_desktop = currentDesktop();
|
|
WId old_active_window = activeWindow();
|
|
int old_number_of_desktops = numberOfDesktops();
|
|
bool old_showing_desktop = showingDesktop();
|
|
unsigned long m[ 5 ];
|
|
NETRootInfo::event( ev, m, 5 );
|
|
|
|
if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->currentDesktopChanged( currentDesktop() );
|
|
if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->activeWindowChanged( activeWindow() );
|
|
if ( m[ PROTOCOLS ] & DesktopViewport ) {
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->currentDesktopViewportChanged(currentDesktop(),
|
|
currentViewport(currentDesktop()));
|
|
}
|
|
if ( m[ PROTOCOLS ] & DesktopGeometry ) {
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->desktopGeometryChanged(currentDesktop());
|
|
}
|
|
if ( m[ PROTOCOLS ] & DesktopNames )
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->desktopNamesChanged();
|
|
if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->numberOfDesktopsChanged( numberOfDesktops() );
|
|
if ( m[ PROTOCOLS ] & WorkArea )
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->workAreaChanged();
|
|
if ( m[ PROTOCOLS ] & ClientListStacking ) {
|
|
updateStackingOrder();
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->stackingOrderChanged();
|
|
}
|
|
if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->showingDesktopChanged( showingDesktop());
|
|
}
|
|
} else if ( windows.findIndex( ev->xany.window ) != -1 ){
|
|
NETWinInfo ni( tqt_xdisplay(), ev->xany.window, tqt_xrootwin(), 0 );
|
|
unsigned long dirty[ 2 ];
|
|
ni.event( ev, dirty, 2 );
|
|
if ( ev->type ==PropertyNotify ) {
|
|
if( ev->xproperty.atom == XA_WM_HINTS )
|
|
dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIcon; // support for old icons
|
|
else if( ev->xproperty.atom == XA_WM_NAME )
|
|
dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName; // support for old name
|
|
else if( ev->xproperty.atom == XA_WM_ICON_NAME )
|
|
dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName; // support for old iconic name
|
|
}
|
|
if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 ) {
|
|
removeStrutWindow( ev->xany.window );
|
|
if ( possibleStrutWindows.findIndex( ev->xany.window ) == -1 )
|
|
possibleStrutWindows.append( ev->xany.window );
|
|
}
|
|
if ( dirty[ NETWinInfo::PROTOCOLS ] || dirty[ NETWinInfo::PROTOCOLS2 ] ) {
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
|
|
emit (*mit)->windowChanged( ev->xany.window );
|
|
emit (*mit)->windowChanged( ev->xany.window, dirty );
|
|
emit (*mit)->windowChanged( ev->xany.window, dirty[ NETWinInfo::PROTOCOLS ] );
|
|
if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
|
|
emit (*mit)->strutChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool KWinModulePrivate::removeStrutWindow( WId w )
|
|
{
|
|
for( TQValueList< StrutData >::Iterator it = strutWindows.begin();
|
|
it != strutWindows.end();
|
|
++it )
|
|
if( (*it).window == w ) {
|
|
strutWindows.remove( it );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void KWinModulePrivate::updateStackingOrder()
|
|
{
|
|
stackingOrder.clear();
|
|
for ( int i = 0; i < clientListStackingCount(); i++ )
|
|
stackingOrder.append( clientListStacking()[i] );
|
|
}
|
|
|
|
void KWinModulePrivate::addClient(Window w)
|
|
{
|
|
if ( (what >= KWinModule::INFO_WINDOWS) && !TQWidget::find( w ) )
|
|
XSelectInput( tqt_xdisplay(), w, PropertyChangeMask | StructureNotifyMask );
|
|
bool emit_strutChanged = false;
|
|
if( strutSignalConnected && modules.count() > 0 ) {
|
|
NETWinInfo info( tqt_xdisplay(), w, tqt_xrootwin(), NET::WMStrut | NET::WMDesktop );
|
|
NETStrut strut = info.strut();
|
|
if ( strut.left || strut.top || strut.right || strut.bottom ) {
|
|
strutWindows.append( StrutData( w, strut, info.desktop()));
|
|
emit_strutChanged = true;
|
|
}
|
|
} else
|
|
possibleStrutWindows.append( w );
|
|
windows.append( w );
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
|
|
emit (*mit)->windowAdded( w );
|
|
if ( emit_strutChanged )
|
|
emit (*mit)->strutChanged();
|
|
}
|
|
}
|
|
|
|
void KWinModulePrivate::removeClient(Window w)
|
|
{
|
|
bool emit_strutChanged = removeStrutWindow( w );
|
|
if( strutSignalConnected && possibleStrutWindows.findIndex( w ) != -1 && modules.count() > 0 ) {
|
|
NETWinInfo info( tqt_xdisplay(), w, tqt_xrootwin(), NET::WMStrut );
|
|
NETStrut strut = info.strut();
|
|
if ( strut.left || strut.top || strut.right || strut.bottom ) {
|
|
emit_strutChanged = true;
|
|
}
|
|
}
|
|
possibleStrutWindows.remove( w );
|
|
windows.remove( w );
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
|
|
emit (*mit)->windowRemoved( w );
|
|
if ( emit_strutChanged )
|
|
emit (*mit)->strutChanged();
|
|
}
|
|
}
|
|
|
|
void KWinModulePrivate::addSystemTrayWin(Window w)
|
|
{
|
|
systemTrayWindows.append( w );
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->systemTrayWindowAdded( w );
|
|
}
|
|
|
|
void KWinModulePrivate::removeSystemTrayWin(Window w)
|
|
{
|
|
systemTrayWindows.remove( w );
|
|
for ( TQPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
|
|
emit (*mit)->systemTrayWindowRemoved( w );
|
|
}
|
|
|
|
int KWinModule::currentDesktop() const
|
|
{
|
|
return d->currentDesktop();
|
|
}
|
|
|
|
int KWinModule::numberOfDesktops() const
|
|
{
|
|
return d->numberOfDesktops();
|
|
}
|
|
|
|
TQSize KWinModule::numberOfViewports(int desktop) const
|
|
{
|
|
return d->numberOfViewports(desktop);
|
|
}
|
|
|
|
TQPoint KWinModule::currentViewport(int desktop) const
|
|
{
|
|
return d->currentViewport(desktop);
|
|
}
|
|
|
|
WId KWinModule::activeWindow() const
|
|
{
|
|
return d->activeWindow();
|
|
}
|
|
|
|
bool KWinModule::showingDesktop() const
|
|
{
|
|
return d->showingDesktop();
|
|
}
|
|
|
|
TQRect KWinModule::workArea( int desktop ) const
|
|
{
|
|
int desk = (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop();
|
|
if ( desk <= 0 )
|
|
return TQApplication::desktop()->geometry();
|
|
NETRect r = d->workArea( desk );
|
|
if( r.size.width <= 0 || r.size.height <= 0 ) // not set
|
|
return TQApplication::desktop()->geometry();
|
|
return TQRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
|
|
}
|
|
|
|
TQRect KWinModule::workArea( const TQValueList<WId>& exclude, int desktop ) const
|
|
{
|
|
TQRect all = TQApplication::desktop()->geometry();
|
|
TQRect a = all;
|
|
|
|
if (desktop == -1)
|
|
desktop = d->currentDesktop();
|
|
|
|
TQValueList<WId>::ConstIterator it1;
|
|
for( it1 = d->windows.begin(); it1 != d->windows.end(); ++it1 ) {
|
|
|
|
if(exclude.findIndex(*it1) != -1) continue;
|
|
|
|
// Kicker (very) extensively calls this function, causing hundreds of roundtrips just
|
|
// to repeatedly find out struts of all windows. Therefore strut values for strut
|
|
// windows are cached here.
|
|
NETStrut strut;
|
|
TQValueList< KWinModulePrivate::StrutData >::Iterator it2 = d->strutWindows.begin();
|
|
for( ;
|
|
it2 != d->strutWindows.end();
|
|
++it2 )
|
|
if( (*it2).window == *it1 )
|
|
break;
|
|
if( it2 != d->strutWindows.end()) {
|
|
if(!((*it2).desktop == desktop || (*it2).desktop == NETWinInfo::OnAllDesktops ))
|
|
continue;
|
|
strut = (*it2).strut;
|
|
} else if( d->possibleStrutWindows.findIndex( *it1 ) != -1 ) {
|
|
NETWinInfo info( tqt_xdisplay(), (*it1), tqt_xrootwin(), NET::WMStrut | NET::WMDesktop);
|
|
strut = info.strut();
|
|
d->possibleStrutWindows.remove( *it1 );
|
|
d->strutWindows.append( KWinModulePrivate::StrutData( *it1, info.strut(), info.desktop()));
|
|
if(!(info.desktop() == desktop || info.desktop() == NETWinInfo::OnAllDesktops))
|
|
continue;
|
|
} else
|
|
continue; // not a strut window
|
|
|
|
TQRect r = all;
|
|
if ( strut.left > 0 )
|
|
r.setLeft( r.left() + (int) strut.left );
|
|
if ( strut.top > 0 )
|
|
r.setTop( r.top() + (int) strut.top );
|
|
if ( strut.right > 0 )
|
|
r.setRight( r.right() - (int) strut.right );
|
|
if ( strut.bottom > 0 )
|
|
r.setBottom( r.bottom() - (int) strut.bottom );
|
|
|
|
TQRect tmp;
|
|
tmp = a.intersect(r);
|
|
a = tmp;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
void KWinModule::connectNotify( const char* signal )
|
|
{
|
|
if( !d->strutSignalConnected && qstrcmp( signal, TQT_SIGNAL(strutChanged())) == 0 )
|
|
d->strutSignalConnected = true;
|
|
TQObject::connectNotify( signal );
|
|
}
|
|
|
|
TQString KWinModule::desktopName( int desktop ) const
|
|
{
|
|
const char* name = d->desktopName( (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop() );
|
|
if ( name && name[0] )
|
|
return TQString::fromUtf8( name );
|
|
return i18n("Desktop %1").arg( desktop );
|
|
}
|
|
|
|
void KWinModule::setDesktopName( int desktop, const TQString& name )
|
|
{
|
|
if (desktop <= 0 || desktop > (int) d->numberOfDesktops() )
|
|
desktop = currentDesktop();
|
|
d->setDesktopName( desktop, name.utf8().data() );
|
|
}
|
|
|
|
|
|
void KWinModule::doNotManage( const TQString& title )
|
|
{
|
|
if ( !kapp->dcopClient()->isAttached() )
|
|
kapp->dcopClient()->attach();
|
|
TQByteArray data, replyData;
|
|
TQCString replyType;
|
|
TQDataStream arg(data, IO_WriteOnly);
|
|
arg << title;
|
|
kapp->dcopClient()->call("twin", "", "doNotManage(TQString)",
|
|
data, replyType, replyData);
|
|
}
|
|
|
|
#include "twinmodule.moc"
|
|
#endif
|