Move NETWinInfo and few more things from Client to the base class.

svn path=/branches/work/kwin_composite/; revision=632380
icc-effect-5.14.5
Luboš Luňák 2007-02-10 21:56:24 +00:00
parent 0a9e366038
commit 24eacc4908
13 changed files with 392 additions and 572 deletions

View File

@ -161,7 +161,6 @@ Client::~Client()
assert( decoration == NULL );
assert( block_geometry_updates == 0 );
assert( !check_active_modal );
delete info;
delete bridge;
}
@ -178,12 +177,11 @@ void Client::releaseWindow( bool on_shutdown )
{
assert( !deleting );
deleting = true;
Deleted* del = Deleted::create( this );
if( effects )
{
Deleted* del = Deleted::create( this );
effects->windowClosed( del->effectWindow()); // effectWindow is already 'del'
effects->windowClosed( effectWindow());
scene->windowClosed( this, del );
del->unrefWindow();
}
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
@ -235,6 +233,8 @@ void Client::releaseWindow( bool on_shutdown )
// frame = None;
--block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
workspace()->addDamage( geometry());
disownDataPassedToDeleted();
del->unrefWindow();
deleteClient( this, Allowed );
}
@ -244,12 +244,11 @@ void Client::destroyClient()
{
assert( !deleting );
deleting = true;
Deleted* del = Deleted::create( this );
if( effects )
{
Deleted* del = Deleted::create( this );
effects->windowClosed( del->effectWindow()); // effectWindow is already 'del'
effects->windowClosed( effectWindow());
scene->windowClosed( this, del );
del->unrefWindow();
}
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
@ -273,6 +272,8 @@ void Client::destroyClient()
// frame = None;
--block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
workspace()->addDamage( geometry());
disownDataPassedToDeleted();
del->unrefWindow();
deleteClient( this, Allowed );
}
@ -1542,125 +1543,6 @@ void Client::getWindowProtocols()
}
}
static int nullErrorHandler(Display *, XErrorEvent *)
{
return 0;
}
/*!
Returns WM_WINDOW_ROLE property for a given window.
*/
QByteArray Client::staticWindowRole(WId w)
{
return getStringProperty(w, atoms->wm_window_role).toLower();
}
/*!
Returns SM_CLIENT_ID property for a given window.
*/
QByteArray Client::staticSessionId(WId w)
{
return getStringProperty(w, atoms->sm_client_id);
}
/*!
Returns WM_COMMAND property for a given window.
*/
QByteArray Client::staticWmCommand(WId w)
{
return getStringProperty(w, XA_WM_COMMAND, ' ');
}
/*!
Returns WM_CLIENT_LEADER property for a given window.
*/
Window Client::staticWmClientLeader(WId w)
{
Atom type;
int format, status;
unsigned long nitems = 0;
unsigned long extra = 0;
unsigned char *data = 0;
Window result = w;
XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
status = XGetWindowProperty( display(), w, atoms->wm_client_leader, 0, 10000,
false, XA_WINDOW, &type, &format,
&nitems, &extra, &data );
XSetErrorHandler(oldHandler);
if (status == Success )
{
if (data && nitems > 0)
result = *((Window*) data);
XFree(data);
}
return result;
}
void Client::getWmClientLeader()
{
wmClientLeaderWin = staticWmClientLeader(window());
}
/*!
Returns sessionId for this client,
taken either from its window or from the leader window.
*/
QByteArray Client::sessionId()
{
QByteArray result = staticSessionId(window());
if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
result = staticSessionId(wmClientLeaderWin);
return result;
}
/*!
Returns command property for this client,
taken either from its window or from the leader window.
*/
QByteArray Client::wmCommand()
{
QByteArray result = staticWmCommand(window());
if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
result = staticWmCommand(wmClientLeaderWin);
return result;
}
void Client::getWmClientMachine()
{
client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
if( client_machine.isEmpty())
client_machine = "localhost";
}
/*!
Returns client machine for this client,
taken either from its window or from the leader window.
*/
QByteArray Client::wmClientMachine( bool use_localhost ) const
{
QByteArray result = client_machine;
if( use_localhost )
{ // special name for the local machine (localhost)
if( result != "localhost" && isLocalMachine( result ))
result = "localhost";
}
return result;
}
/*!
Returns client leader window for this client.
Returns the client window itself if no leader window is defined.
*/
Window Client::wmClientLeader() const
{
if (wmClientLeaderWin)
return wmClientLeaderWin;
return window();
}
bool Client::wantsTabFocus() const
{
return ( isNormalWindow() || isDialog()) && wantsInput();
@ -1672,37 +1554,6 @@ bool Client::wantsInput() const
return rules()->checkAcceptFocus( input || Ptakefocus );
}
NET::WindowType Client::windowType( bool direct, int supported_types ) const
{
NET::WindowType wt = info->windowType( supported_types );
if( direct )
return wt;
NET::WindowType wt2 = rules()->checkType( wt );
if( wt != wt2 )
{
wt = wt2;
info->setWindowType( wt ); // force hint change
}
// hacks here
if( wt == NET::Menu )
{
// ugly hack to support the times when NET::Menu meant NET::TopMenu
// if it's as wide as the screen, not very high and has its upper-left
// corner a bit above the screen's upper-left cornet, it's a topmenu
if( x() == 0 && y() < 0 && y() > -10 && height() < 100
&& abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
wt = NET::TopMenu;
}
// TODO change this to rule
const char* const oo_prefix = "openoffice.org"; // QByteArray has no startsWith()
// oo_prefix is lowercase, because resourceClass() is forced to be lowercase
if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
wt = NET::Normal; // see bug #66065
if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
wt = isTransient() ? NET::Dialog : NET::Normal;
return wt;
}
bool Client::isSpecialWindow() const
{
return isDesktop() || isDock() || isSplash() || isTopMenu()
@ -1805,20 +1656,6 @@ void Client::cancelAutoRaise()
autoRaiseTimer = 0;
}
double Client::opacity() const
{
if( info->opacity() == 0xffffffff )
return 1.0;
return info->opacity() * 1.0 / 0xffffffff;
}
void Client::setOpacity( double opacity )
{
opacity = qBound( 0.0, opacity, 1.0 );
info->setOpacity( static_cast< unsigned long >( opacity * 0xffffffff ));
// we'll react on PropertyNotify
}
void Client::debug( kdbgstream& stream ) const
{
stream << "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << caption() << "\'";

View File

@ -39,7 +39,6 @@ namespace KWinInternal
class Workspace;
class Client;
class WinInfo;
class SessionInfo;
class Bridge;
@ -49,8 +48,6 @@ class Client
Q_OBJECT
public:
Client( Workspace *ws );
Window window() const;
Window frameId() const;
Window wrapperId() const;
Window decorationId() const;
@ -71,7 +68,7 @@ class Client
void removeRule( Rules* r );
void setupWindowRules( bool ignore_temporary );
void applyWindowRules();
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
@ -88,7 +85,6 @@ class Client
virtual bool eventFilter( QObject* o, QEvent* e );
bool manage( Window w, bool isMapped );
void releaseWindow( bool on_shutdown = false );
void destroyClient();
@ -179,9 +175,6 @@ class Client
void updateShape();
virtual double opacity() const;
void setOpacity( double opacity );
void setGeometry( int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet );
void setGeometry( const QRect& r, ForceGeometry_t force = NormalGeometrySet );
void move( int x, int y, ForceGeometry_t force = NormalGeometrySet );
@ -205,15 +198,6 @@ class Client
bool performMouseCommand( Options::MouseCommand, QPoint globalPos, bool handled = false );
QByteArray windowRole() const;
QByteArray sessionId();
QByteArray resourceName() const;
QByteArray resourceClass() const;
QByteArray wmCommand();
QByteArray wmClientMachine( bool use_localhost ) const;
Window wmClientLeader() const;
pid_t pid() const;
QRect adjustedClientArea( const QRect& desktop, const QRect& area ) const;
Colormap colormap() const;
@ -238,12 +222,6 @@ class Client
void gotPing( Time timestamp );
static QByteArray staticWindowRole(WId);
static QByteArray staticSessionId(WId);
static QByteArray staticWmCommand(WId);
static QByteArray staticWmClientMachine(WId);
static Window staticWmClientLeader(WId);
void checkWorkspacePosition();
void updateUserTime( Time time = CurrentTime );
Time userTime() const;
@ -253,8 +231,8 @@ class Client
// does 'delete c;'
static void deleteClient( Client* c, allowed_t );
static bool resourceMatch( const Client* c1, const Client* c2 );
static bool belongToSameApplication( const Client* c1, const Client* c2, bool active_hack = false );
static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
static void readIcons( Window win, QPixmap* icon, QPixmap* miniicon );
void minimize( bool avoid_animation = false );
@ -307,7 +285,7 @@ class Client
void unmapNotifyEvent( XUnmapEvent*e );
void destroyNotifyEvent( XDestroyWindowEvent*e );
void configureRequestEvent( XConfigureRequestEvent* e );
void propertyNotifyEvent( XPropertyEvent* e );
virtual void propertyNotifyEvent( XPropertyEvent* e );
void clientMessageEvent( XClientMessageEvent* e );
void enterNotifyEvent( XCrossingEvent* e );
void leaveNotifyEvent( XCrossingEvent* e );
@ -345,8 +323,6 @@ class Client
void getWmNormalHints();
void getMotifHints();
void getIcons();
void getWmClientLeader();
void getWmClientMachine();
void fetchName();
void fetchIconicName();
QString readName() const;
@ -392,7 +368,6 @@ class Client
Time readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
bool session ) const;
Time readUserCreationTime() const;
static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
void startupIdChanged();
Window client;
@ -469,16 +444,10 @@ class Client
QRect geom_fs_restore;
MaximizeMode maxmode_restore;
int workarea_diff_x, workarea_diff_y;
WinInfo* info;
QTimer* autoRaiseTimer;
QTimer* shadeHoverTimer;
Colormap cmap;
QByteArray resource_name;
QByteArray resource_class;
QByteArray client_machine;
QString cap_normal, cap_iconic, cap_suffix;
WId wmClientLeaderWin;
QByteArray window_role;
Group* in_group;
Window window_group;
Layer in_layer;
@ -529,20 +498,11 @@ class WinInfo : public NETWinInfo
Window rwin, const unsigned long pr[], int pr_size );
virtual void changeDesktop(int desktop);
virtual void changeState( unsigned long state, unsigned long mask );
void disable();
private:
Client * m_client;
};
inline Window Client::window() const
{
return client;
}
inline Window Client::frameId() const
{
return handle();
}
inline Window Client::wrapperId() const
{
return wrapper;
@ -600,16 +560,6 @@ inline int Client::mappingState() const
return mapping_state;
}
inline QByteArray Client::resourceName() const
{
return resource_name; // it is always lowercase
}
inline QByteArray Client::resourceClass() const
{
return resource_class; // it is always lowercase
}
inline
bool Client::isMinimized() const
{
@ -704,11 +654,6 @@ inline Colormap Client::colormap() const
return cmap;
}
inline pid_t Client::pid() const
{
return info->pid();
}
inline void Client::invalidateLayer()
{
in_layer = UnknownLayer;
@ -734,11 +679,6 @@ inline bool Client::isManaged() const
return mapping_state != WithdrawnState;
}
inline QByteArray Client::windowRole() const
{
return window_role;
}
inline QPoint Client::clientPos() const
{
return QPoint( border_left, border_top );
@ -801,8 +741,6 @@ inline void Client::removeRule( Rules* rule )
client_rules.remove( rule );
}
KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Client, Window, cl->window() == value );
KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Client, Window, cl->frameId() == value );
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value );
} // namespace

View File

@ -232,7 +232,7 @@ void Workspace::performCompositing()
{
if( Client* c = findClient( FrameIdMatchPredicate( children[ i ] )))
windows.append( c );
else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( children[ i ] )))
else if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( children[ i ] )))
windows.append( c );
}
foreach( Deleted* c, deleted ) // TODO remember stacking order somehow
@ -301,7 +301,7 @@ void Toplevel::setupCompositing()
return;
if( damage_handle != None )
return;
damage_handle = XDamageCreate( display(), handle(), XDamageReportRawRectangles );
damage_handle = XDamageCreate( display(), frameId(), XDamageReportRawRectangles );
damage_region = QRegion( 0, 0, width(), height());
effect_window = new EffectWindow();
effect_window->setWindow( this );
@ -311,11 +311,14 @@ void Toplevel::finishCompositing()
{
if( damage_handle == None )
return;
if( effect_window->window() == this ) // otherwise it's already passed to Deleted, don't free data
{
discardWindowPixmap();
delete effect_window;
}
XDamageDestroy( display(), damage_handle );
discardWindowPixmap();
damage_handle = None;
damage_region = QRegion();
delete effect_window;
effect_window = NULL;
}
@ -330,7 +333,7 @@ void Toplevel::discardWindowPixmap()
Pixmap Toplevel::createWindowPixmap() const
{
assert( compositing());
return XCompositeNameWindowPixmap( display(), handle());
return XCompositeNameWindowPixmap( display(), frameId());
}
void Toplevel::damageNotifyEvent( XDamageNotifyEvent* e )
@ -341,7 +344,7 @@ void Toplevel::damageNotifyEvent( XDamageNotifyEvent* e )
{
XEvent e2;
if( XPeekEvent( display(), &e2 ) && e2.type == Extensions::damageNotifyEvent()
&& e2.xany.window == handle())
&& e2.xany.window == frameId())
{
XNextEvent( display(), &e2 );
XDamageNotifyEvent* e = reinterpret_cast< XDamageNotifyEvent* >( &e2 );

View File

@ -11,6 +11,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "deleted.h"
#include "workspace.h"
#include "client.h"
namespace KWinInternal
{
@ -39,8 +40,9 @@ void Deleted::copyToDeleted( Toplevel* c )
{
assert( dynamic_cast< Deleted* >( c ) == NULL );
Toplevel::copyToDeleted( c );
window_opacity = c->opacity();
desk = c->desktop();
if( WinInfo* cinfo = dynamic_cast< WinInfo* >( info ))
cinfo->disable();
}
void Deleted::unrefWindow()
@ -50,16 +52,6 @@ void Deleted::unrefWindow()
deleteLater();
}
NET::WindowType Deleted::windowType( bool direct, int supported_types ) const
{
return NET::Normal; // TODO
}
double Deleted::opacity() const
{
return window_opacity;
}
int Deleted::desktop() const
{
return desk;
@ -67,7 +59,7 @@ int Deleted::desktop() const
void Deleted::debug( kdbgstream& stream ) const
{
stream << "\'ID:" << handle() << "\' (deleted)";
stream << "\'ID:" << window() << "\' (deleted)";
}
} // namespace

View File

@ -22,11 +22,9 @@ class Deleted
Q_OBJECT
public:
static Deleted* create( Toplevel* c );
virtual double opacity() const;
// used by effects to keep the window around for e.g. fadeout effects when it's destroyed
void refWindow();
void unrefWindow();
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
virtual int desktop() const;
protected:
virtual void debug( kdbgstream& stream ) const;

View File

@ -86,6 +86,10 @@ void WinInfo::changeState( unsigned long state, unsigned long mask )
m_client->setFullScreen( true, false );
}
void WinInfo::disable()
{
m_client = NULL; // only used when the object is passed to Deleted
}
// ****************************************
// RootInfo
@ -267,7 +271,7 @@ bool Workspace::workspaceEvent( XEvent * e )
if( c->windowEvent( e ))
return true;
}
else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( e->xany.window )))
else if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xany.window )))
{
if( c->windowEvent( e ))
return true;
@ -384,7 +388,7 @@ bool Workspace::workspaceEvent( XEvent * e )
{
if( e->xmap.override_redirect )
{
Unmanaged* c = findUnmanaged( HandleMatchPredicate( e->xmap.window ));
Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xmap.window ));
if( c == NULL )
c = createUnmanaged( e->xmap.window );
if( c )
@ -899,6 +903,7 @@ void Client::configureRequestEvent( XConfigureRequestEvent* e )
*/
void Client::propertyNotifyEvent( XPropertyEvent* e )
{
Toplevel::propertyNotifyEvent( e );
if( e->window != window())
return; // ignore frame/wrapper
switch ( e->atom )
@ -922,10 +927,6 @@ void Client::propertyNotifyEvent( XPropertyEvent* e )
default:
if ( e->atom == atoms->wm_protocols )
getWindowProtocols();
else if (e->atom == atoms->wm_client_leader )
getWmClientLeader();
else if( e->atom == atoms->wm_window_role )
window_role = staticWindowRole( window());
else if( e->atom == atoms->motif_wm_hints )
getMotifHints();
break;
@ -1618,11 +1619,13 @@ bool Unmanaged::windowEvent( XEvent* e )
case ConfigureNotify:
configureNotifyEvent( &e->xconfigure );
break;
case PropertyNotify:
propertyNotifyEvent( &e->xproperty );
default:
{
if( e->type == Extensions::shapeNotifyEvent() )
{
detectShape( handle());
detectShape( window());
addDamageFull();
if( compositing() )
discardWindowPixmap();
@ -1663,6 +1666,25 @@ void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
addDamageFull();
}
// ****************************************
// Toplevel
// ****************************************
void Toplevel::propertyNotifyEvent( XPropertyEvent* e )
{
if( e->window != window())
return; // ignore frame/wrapper
switch ( e->atom )
{
default:
if (e->atom == atoms->wm_client_leader )
getWmClientLeader();
else if( e->atom == atoms->wm_window_role )
getWindowRole();
break;
}
}
// ****************************************
// Group
// ****************************************

295
group.cpp
View File

@ -36,164 +36,6 @@ License. See the file "COPYING" for the exact licensing terms.
namespace KWinInternal
{
/*
Consistency checks for window relations. Since transients are determinated
using Client::transiency_list and main windows are determined using Client::transientFor()
or the group for group transients, these have to match both ways.
*/
//#define ENABLE_TRANSIENCY_CHECK
#ifdef NDEBUG
#undef ENABLE_TRANSIENCY_CHECK
#endif
#ifdef ENABLE_TRANSIENCY_CHECK
static bool transiencyCheckNonExistent = false;
bool performTransiencyCheck()
{
bool ret = true;
ClientList clients = Workspace::self()->clients;
for( ClientList::ConstIterator it1 = clients.begin();
it1 != clients.end();
++it1 )
{
if( (*it1)->deleting )
continue;
if( (*it1)->in_group == NULL )
{
kdDebug() << "TC: " << *it1 << " in not in a group" << endl;
ret = false;
}
else if( !(*it1)->in_group->members().contains( *it1 ))
{
kdDebug() << "TC: " << *it1 << " has a group " << (*it1)->in_group << " but group does not contain it" << endl;
ret = false;
}
if( !(*it1)->isTransient())
{
if( !(*it1)->mainClients().isEmpty())
{
kdDebug() << "TC: " << *it1 << " is not transient, has main clients:" << (*it1)->mainClients() << endl;
ret = false;
}
}
else
{
ClientList mains = (*it1)->mainClients();
for( ClientList::ConstIterator it2 = mains.begin();
it2 != mains.end();
++it2 )
{
if( transiencyCheckNonExistent
&& !Workspace::self()->clients.contains( *it2 )
&& !Workspace::self()->desktops.contains( *it2 ))
{
kDebug() << "TC:" << *it1 << " has non-existent main client " << endl;
kDebug() << "TC2:" << *it2 << endl; // this may crash
ret = false;
continue;
}
if( !(*it2)->transients_list.contains( *it1 ))
{
kdDebug() << "TC:" << *it1 << " has main client " << *it2 << " but main client does not have it as a transient" << endl;
ret = false;
}
}
}
ClientList trans = (*it1)->transients_list;
for( ClientList::ConstIterator it2 = trans.begin();
it2 != trans.end();
++it2 )
{
if( transiencyCheckNonExistent
&& !Workspace::self()->clients.contains( *it2 )
&& !Workspace::self()->desktops.contains( *it2 ))
{
kDebug() << "TC:" << *it1 << " has non-existent transient " << endl;
kDebug() << "TC2:" << *it2 << endl; // this may crash
ret = false;
continue;
}
if( !(*it2)->mainClients().contains( *it1 ))
{
kdDebug() << "TC:" << *it1 << " has transient " << *it2 << " but transient does not have it as a main client" << endl;
ret = false;
}
}
}
GroupList groups = Workspace::self()->groups;
for( GroupList::ConstIterator it1 = groups.begin();
it1 != groups.end();
++it1 )
{
ClientList members = (*it1)->members();
for( ClientList::ConstIterator it2 = members.begin();
it2 != members.end();
++it2 )
{
if( (*it2)->in_group != *it1 )
{
kdDebug() << "TC: Group " << *it1 << " contains client " << *it2 << " but client is not in that group" << endl;
ret = false;
}
}
}
return ret;
}
static QString transiencyCheckStartBt;
static const Client* transiencyCheckClient;
static int transiencyCheck = 0;
static void startTransiencyCheck( const QString& bt, const Client* c, bool ne )
{
if( ++transiencyCheck == 1 )
{
transiencyCheckStartBt = bt;
transiencyCheckClient = c;
}
if( ne )
transiencyCheckNonExistent = true;
}
static void checkTransiency()
{
if( --transiencyCheck == 0 )
{
if( !performTransiencyCheck())
{
kdDebug() << "BT:" << transiencyCheckStartBt << endl;
kdDebug() << "CLIENT:" << transiencyCheckClient << endl;
assert( false );
}
transiencyCheckNonExistent = false;
}
}
class TransiencyChecker
{
public:
TransiencyChecker( const QString& bt, const Client*c ) { startTransiencyCheck( bt, c, false ); }
~TransiencyChecker() { checkTransiency(); }
};
void checkNonExistentClients()
{
startTransiencyCheck( kdBacktrace(), NULL, true );
checkTransiency();
}
#define TRANSIENCY_CHECK( c ) TransiencyChecker transiency_checker( kdBacktrace(), c )
#else
#define TRANSIENCY_CHECK( c )
void checkNonExistentClients()
{
}
#endif
//********************************************
// Group
//********************************************
@ -203,8 +45,7 @@ Group::Group( Window leader_P, Workspace* workspace_P )
leader_wid( leader_P ),
_workspace( workspace_P ),
leader_info( NULL ),
user_time( -1U ),
refcount( 0 )
user_time( -1U )
{
if( leader_P != None )
{
@ -249,7 +90,6 @@ QPixmap Group::miniIcon() const
void Group::addMember( Client* member_P )
{
TRANSIENCY_CHECK( member_P );
_members.append( member_P );
// kDebug() << "GROUPADD:" << this << ":" << member_P << endl;
// kDebug() << kBacktrace() << endl;
@ -257,30 +97,11 @@ void Group::addMember( Client* member_P )
void Group::removeMember( Client* member_P )
{
TRANSIENCY_CHECK( member_P );
// kDebug() << "GROUPREMOVE:" << this << ":" << member_P << endl;
// kDebug() << kBacktrace() << endl;
Q_ASSERT( _members.contains( member_P ));
_members.removeAll( member_P );
// there are cases when automatic deleting of groups must be delayed,
// e.g. when removing a member and doing some operation on the possibly
// other members of the group (which would be however deleted already
// if there were no other members)
if( refcount == 0 && _members.isEmpty())
{
workspace()->removeGroup( this, Allowed );
delete this;
}
}
void Group::ref()
{
++refcount;
}
void Group::deref()
{
if( --refcount == 0 && _members.isEmpty())
if( _members.isEmpty())
{
workspace()->removeGroup( this, Allowed );
delete this;
@ -328,7 +149,6 @@ Group* Workspace::findGroup( Window leader ) const
// group with windows with the same client leader.
Group* Workspace::findClientLeaderGroup( const Client* c ) const
{
TRANSIENCY_CHECK( c );
Group* ret = NULL;
for( ClientList::ConstIterator it = clients.begin();
it != clients.end();
@ -346,15 +166,14 @@ Group* Workspace::findClientLeaderGroup( const Client* c ) const
// This most probably means the app uses group transients without
// setting group for its windows. Merging the two groups is a bad
// hack, but there's no really good solution for this case.
ClientList old_group = (*it)->group()->members();
Group* old_group = (*it)->group();
// old_group autodeletes when being empty
for( int pos = 0;
pos < old_group.count();
++pos )
for( int cnt = old_group->members().count();
cnt > 0;
--cnt )
{
Client* tmp = old_group[ pos ];
if( tmp != c )
tmp->changeClientLeaderGroup( ret );
Client* tmp = old_group->members().first();
tmp->checkGroup( ret ); // change group
}
}
}
@ -413,7 +232,6 @@ void Workspace::updateOnAllDesktopsOfTransients( Client* c )
// A new window has been mapped. Check if it's not a mainwindow for some already existing transient window.
void Workspace::checkTransients( Window w )
{
TRANSIENCY_CHECK( NULL );
for( ClientList::ConstIterator it = clients.begin();
it != clients.end();
++it )
@ -421,14 +239,13 @@ void Workspace::checkTransients( Window w )
}
//****************************************
// Client
// Toplevel
//****************************************
// hacks for broken apps here
// all resource classes are forced to be lowercase
bool Client::resourceMatch( const Client* c1, const Client* c2 )
bool Toplevel::resourceMatch( const Toplevel* c1, const Toplevel* c2 )
{
// xv has "xv" as resource name, and different strings starting with "XV" as resource class
if( qstrncmp( c1->resourceClass(), "xv", 2 ) == 0 && c1->resourceName() == "xv" )
@ -439,25 +256,20 @@ bool Client::resourceMatch( const Client* c1, const Client* c2 )
return c1->resourceClass() == c2->resourceClass();
}
//****************************************
// Client
//****************************************
bool Client::belongToSameApplication( const Client* c1, const Client* c2, bool active_hack )
{
bool same_app = false;
// tests that definitely mean they belong together
if( c1 == c2 )
same_app = true;
else if( c1->isTransient() && c2->hasTransient( c1, true ))
same_app = true; // c1 has c2 as mainwindow
else if( c2->isTransient() && c1->hasTransient( c2, true ))
same_app = true; // c2 has c1 as mainwindow
else if( c1->group() == c2->group())
same_app = true; // same group
else if( c1->wmClientLeader() == c2->wmClientLeader()
&& c1->wmClientLeader() != c1->window() // if WM_CLIENT_LEADER is not set, it returns window(),
&& c2->wmClientLeader() != c2->window()) // don't use in this test then
same_app = true; // same client leader
// tests that mean they most probably don't belong together
else if( c1->pid() != c2->pid()
|| c1->wmClientMachine( false ) != c2->wmClientMachine( false ))
; // different processes
@ -469,12 +281,17 @@ bool Client::belongToSameApplication( const Client* c1, const Client* c2, bool a
; // different apps
else if( !sameAppWindowRoleMatch( c1, c2, active_hack ))
; // "different" apps
else if( c1->wmClientLeader() == c2->wmClientLeader()
&& c1->wmClientLeader() != c1->window() // if WM_CLIENT_LEADER is not set, it returns window(),
&& c2->wmClientLeader() != c2->window()) // don't use in this test then
same_app = true; // same client leader
else if( c1->group() == c2->group())
same_app = true; // same group
else if( c1->pid() == 0 || c2->pid() == 0 )
; // old apps that don't have _NET_WM_PID, consider them different
// if they weren't found to match above
else
same_app = true; // looks like it's the same app
return same_app;
}
@ -579,7 +396,6 @@ bool Client::sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool ac
void Client::readTransient()
{
TRANSIENCY_CHECK( this );
Window new_transient_for_id;
if( XGetTransientForHint( display(), window(), &new_transient_for_id ))
{
@ -596,7 +412,6 @@ void Client::readTransient()
void Client::setTransient( Window new_transient_for_id )
{
TRANSIENCY_CHECK( this );
if( new_transient_for_id != transient_for_id )
{
removeFromMainClients();
@ -617,7 +432,6 @@ void Client::setTransient( Window new_transient_for_id )
void Client::removeFromMainClients()
{
TRANSIENCY_CHECK( this );
if( transientFor() != NULL )
transientFor()->removeTransient( this );
if( groupTransient())
@ -635,7 +449,6 @@ void Client::removeFromMainClients()
// related lists.
void Client::cleanGrouping()
{
TRANSIENCY_CHECK( this );
// kDebug() << "CLEANGROUPING:" << this << endl;
// for( ClientList::ConstIterator it = group()->members().begin();
// it != group()->members().end();
@ -705,7 +518,6 @@ void Client::cleanGrouping()
// Non-group transients not causing loops are checked in verifyTransientFor().
void Client::checkGroupTransients()
{
TRANSIENCY_CHECK( this );
for( ClientList::ConstIterator it1 = group()->members().begin();
it1 != group()->members().end();
++it1 )
@ -835,7 +647,6 @@ Window Client::verifyTransientFor( Window new_transient_for, bool defined )
void Client::addTransient( Client* cl )
{
TRANSIENCY_CHECK( this );
assert( !transients_list.contains( cl ));
// assert( !cl->hasTransient( this, true )); will be fixed in checkGroupTransients()
assert( cl != this );
@ -852,7 +663,6 @@ void Client::addTransient( Client* cl )
void Client::removeTransient( Client* cl )
{
TRANSIENCY_CHECK( this );
// kDebug() << "REMOVETRANS:" << this << ":" << cl << endl;
// kDebug() << kBacktrace() << endl;
transients_list.removeAll( cl );
@ -870,7 +680,6 @@ void Client::removeTransient( Client* cl )
// A new window has been mapped. Check if it's not a mainwindow for this already existing window.
void Client::checkTransient( Window w )
{
TRANSIENCY_CHECK( this );
if( original_transient_for_id != w )
return;
w = verifyTransientFor( w, true );
@ -951,10 +760,7 @@ Client* Client::findModal()
// Argument is only when some specific group needs to be set.
void Client::checkGroup( Group* set_group, bool force )
{
TRANSIENCY_CHECK( this );
Group* old_group = in_group;
if( old_group != NULL )
old_group->ref(); // turn off automatic deleting
if( set_group != NULL )
{
if( set_group != in_group )
@ -1011,21 +817,16 @@ void Client::checkGroup( Group* set_group, bool force )
in_group->addMember( this );
}
}
else // Not transient without a group, put it in its client leader group.
{ // This might be stupid if grouping was used for e.g. taskbar grouping
// or minimizing together the whole group, but as long as its used
// only for dialogs it's better to keep windows from one app in one group.
Group* new_group = workspace()->findClientLeaderGroup( this );
if( in_group != NULL && in_group != new_group )
else // not transient without a group, put it in its own group
{
if( in_group != NULL && in_group->leader() != window())
{
in_group->removeMember( this );
in_group = NULL;
}
if( new_group == NULL )
new_group = new Group( None, workspace() );
if( in_group != new_group )
if( in_group == NULL )
{
in_group = new_group;
in_group = new Group( None, workspace());
in_group->addMember( this );
}
}
@ -1042,16 +843,7 @@ void Client::checkGroup( Group* set_group, bool force )
++it;
}
if( groupTransient())
{
// no longer transient for ones in the old group
if( old_group != NULL )
{
for( ClientList::ConstIterator it = old_group->members().begin();
it != old_group->members().end();
++it )
(*it)->removeTransient( this );
}
// and make transient for all in the new group
{ // and make transient for all in the group
for( ClientList::ConstIterator it = group()->members().begin();
it != group()->members().end();
++it )
@ -1061,6 +853,25 @@ void Client::checkGroup( Group* set_group, bool force )
(*it)->addTransient( this );
}
}
#if 0 // TODO
if( groupTransient())
{
if( workspace()->findGroup( old_group )) // if it still exists
{ // it's no longer transient for windows in the old group
for( ClientList::ConstIterator it = old_group->members().begin();
it != old_group->members().end();
++it )
(*it)->removeTransient( this );
}
// and it's transiet for all windows in the new group (this one is the most recent
// in the group, so it is transient only for all previous windows)
// loops are checked in checkGroupTransients()
for( ClientList::ConstIterator it = group()->members().begin();
it != group()->members().end();
++it )
(*it)->addTransient( this );
}
#endif
// group transient splashscreens should be transient even for windows
// in group mapped later
for( ClientList::ConstIterator it = group()->members().begin();
@ -1076,25 +887,11 @@ void Client::checkGroup( Group* set_group, bool force )
addTransient( *it );
}
}
if( old_group != NULL )
old_group->deref(); // can be now deleted if empty
checkGroupTransients();
checkActiveModal();
workspace()->updateClientLayer( this );
}
// used by Workspace::findClientLeaderGroup()
void Client::changeClientLeaderGroup( Group* gr )
{
// transientFor() != NULL are in the group of their mainwindow, so keep them there
if( transientFor() != NULL )
return;
// also don't change the group for window which have group set
if( window_group )
return;
checkGroup( gr ); // change group
}
bool Client::check_active_modal = false;
void Client::checkActiveModal()

View File

@ -92,19 +92,8 @@ bool Client::manage( Window w, bool isMapped )
cmap = attr.colormap;
XClassHint classHint;
if ( XGetClassHint( display(), client, &classHint ) )
{
// Qt3.2 and older had this all lowercase, Qt3.3 capitalized resource class
// force lowercase, so that workarounds listing resource classes still work
resource_name = QByteArray( classHint.res_name ).toLower();
resource_class = QByteArray( classHint.res_class ).toLower();
XFree( classHint.res_name );
XFree( classHint.res_class );
}
ignore_focus_stealing = options->checkIgnoreFocusStealing( this ); // TODO change to rules
window_role = staticWindowRole( w );
getResourceClass();
getWindowRole();
getWmClientLeader();
getWmClientMachine();
// first only read the caption text, so that setupWindowRules() can use it for matching,
@ -112,6 +101,7 @@ bool Client::manage( Window w, bool isMapped )
// and also relies on rules already existing
cap_normal = readName();
setupWindowRules( false );
ignore_focus_stealing = options->checkIgnoreFocusStealing( this ); // TODO change to rules
setCaption( cap_normal, true );
if( Extensions::shapeAvailable())
@ -558,7 +548,7 @@ void Client::embedClient( Window w, const XWindowAttributes &attr )
Window frame = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
attr.depth, InputOutput, attr.visual,
CWColormap | CWBackPixmap | CWBorderPixel, &swa );
setHandle( frame );
setWindowHandles( client, frame );
wrapper = XCreateWindow( display(), frame, 0, 0, 1, 1, 0,
attr.depth, InputOutput, attr.visual,
CWColormap | CWBackPixmap | CWBorderPixel, &swa );

View File

@ -272,7 +272,7 @@ QRegion Scene::Window::shape() const
if( toplevel->shape() || ( c != NULL && !c->mask().isEmpty()))
{
int count, order;
XRectangle* rects = XShapeGetRectangles( display(), toplevel->handle(),
XRectangle* rects = XShapeGetRectangles( display(), toplevel->frameId(),
ShapeBounding, &count, &order );
if(rects)
{

View File

@ -10,6 +10,10 @@ License. See the file "COPYING" for the exact licensing terms.
#include "toplevel.h"
#include <kxerrorhandler.h>
#include "atoms.h"
#include "client.h"
#include "effects.h"
namespace KWinInternal
@ -17,7 +21,9 @@ namespace KWinInternal
Toplevel::Toplevel( Workspace* ws )
: vis( None )
, id( None )
, info( NULL )
, client( None )
, frame( None )
, wspace( ws )
, window_pix( None )
, damage_handle( None )
@ -30,6 +36,7 @@ Toplevel::~Toplevel()
{
assert( damage_handle == None );
discardWindowPixmap();
delete info;
}
#ifndef NDEBUG
@ -87,17 +94,208 @@ void Toplevel::copyToDeleted( Toplevel* c )
geom = c->geom;
vis = c->vis;
bit_depth = c->bit_depth;
id = c->id;
info = c->info;
client = c->client;
frame = c->frame;
wspace = c->wspace;
window_pix = c->window_pix;
c->window_pix = None;
damage_handle = None;
damage_region = c->damage_region;
is_shape = c->is_shape;
// reassign the representation for Effect classes
effect_window = c->effect_window;
effect_window->setWindow( this );
c->effect_window = NULL;
if( effect_window != NULL )
effect_window->setWindow( this );
resource_name = c->resourceName();
resource_class = c->resourceClass();
client_machine = c->wmClientMachine( false );
wmClientLeaderWin = c->wmClientLeader();
window_role = c->windowRole();
// this needs to be done already here, otherwise 'c' could very likely
// call discardWindowPixmap() in something called during cleanup
c->window_pix = None;
}
// before being deleted, remove references to everything that's now
// owner by Deleted
void Toplevel::disownDataPassedToDeleted()
{
info = NULL;
}
NET::WindowType Toplevel::windowType( bool direct, int supported_types ) const
{
NET::WindowType wt = info->windowType( supported_types );
if( direct )
return wt;
const Client* cl = dynamic_cast< const Client* >( this );
#warning TODO
// NET::WindowType wt2 = rules()->checkType( wt );
NET::WindowType wt2 = wt;
if( wt != wt2 )
{
wt = wt2;
info->setWindowType( wt ); // force hint change
}
// hacks here
if( wt == NET::Menu && cl != NULL )
{
// ugly hack to support the times when NET::Menu meant NET::TopMenu
// if it's as wide as the screen, not very high and has its upper-left
// corner a bit above the screen's upper-left cornet, it's a topmenu
if( x() == 0 && y() < 0 && y() > -10 && height() < 100
&& abs( width() - workspace()->clientArea( FullArea, cl ).width()) < 10 )
wt = NET::TopMenu;
}
// TODO change this to rule
const char* const oo_prefix = "openoffice.org"; // QByteArray has no startsWith()
// oo_prefix is lowercase, because resourceClass() is forced to be lowercase
if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
wt = NET::Normal; // see bug #66065
if( wt == NET::Unknown && cl != NULL ) // this is more or less suggested in NETWM spec
wt = cl->isTransient() ? NET::Dialog : NET::Normal;
return wt;
}
void Toplevel::getWindowRole()
{
window_role = getStringProperty( window(), atoms->wm_window_role).toLower();
}
/*!
Returns SM_CLIENT_ID property for a given window.
*/
QByteArray Toplevel::staticSessionId(WId w)
{
return getStringProperty(w, atoms->sm_client_id);
}
/*!
Returns WM_COMMAND property for a given window.
*/
QByteArray Toplevel::staticWmCommand(WId w)
{
return getStringProperty(w, XA_WM_COMMAND, ' ');
}
/*!
Returns WM_CLIENT_LEADER property for a given window.
*/
Window Toplevel::staticWmClientLeader(WId w)
{
Atom type;
int format, status;
unsigned long nitems = 0;
unsigned long extra = 0;
unsigned char *data = 0;
Window result = w;
KXErrorHandler err;
status = XGetWindowProperty( display(), w, atoms->wm_client_leader, 0, 10000,
false, XA_WINDOW, &type, &format,
&nitems, &extra, &data );
if (status == Success && !err.error( false ))
{
if (data && nitems > 0)
result = *((Window*) data);
XFree(data);
}
return result;
}
void Toplevel::getWmClientLeader()
{
wmClientLeaderWin = staticWmClientLeader(window());
}
/*!
Returns sessionId for this client,
taken either from its window or from the leader window.
*/
QByteArray Toplevel::sessionId()
{
QByteArray result = staticSessionId(window());
if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
result = staticSessionId(wmClientLeaderWin);
return result;
}
/*!
Returns command property for this client,
taken either from its window or from the leader window.
*/
QByteArray Toplevel::wmCommand()
{
QByteArray result = staticWmCommand(window());
if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
result = staticWmCommand(wmClientLeaderWin);
return result;
}
void Toplevel::getWmClientMachine()
{
client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
if( client_machine.isEmpty())
client_machine = "localhost";
}
/*!
Returns client machine for this client,
taken either from its window or from the leader window.
*/
QByteArray Toplevel::wmClientMachine( bool use_localhost ) const
{
QByteArray result = client_machine;
if( use_localhost )
{ // special name for the local machine (localhost)
if( result != "localhost" && isLocalMachine( result ))
result = "localhost";
}
return result;
}
/*!
Returns client leader window for this client.
Returns the client window itself if no leader window is defined.
*/
Window Toplevel::wmClientLeader() const
{
if (wmClientLeaderWin)
return wmClientLeaderWin;
return window();
}
void Toplevel::getResourceClass()
{
XClassHint classHint;
if( XGetClassHint( display(), window(), &classHint ) )
{
// Qt3.2 and older had this all lowercase, Qt3.3 capitalized resource class
// force lowercase, so that workarounds listing resource classes still work
resource_name = QByteArray( classHint.res_name ).toLower();
resource_class = QByteArray( classHint.res_class ).toLower();
XFree( classHint.res_name );
XFree( classHint.res_class );
}
else
{
resource_name = resource_class = QByteArray();
}
}
double Toplevel::opacity() const
{
if( info->opacity() == 0xffffffff )
return 1.0;
return info->opacity() * 1.0 / 0xffffffff;
}
void Toplevel::setOpacity( double opacity )
{
opacity = qBound( 0.0, opacity, 1.0 );
info->setOpacity( static_cast< unsigned long >( opacity * 0xffffffff ));
// we'll react on PropertyNotify
}
} // namespace

View File

@ -18,6 +18,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include "utils.h"
#include "workspace.h"
class NETWinInfo;
namespace KWinInternal
{
@ -30,7 +32,8 @@ class Toplevel
Q_OBJECT
public:
Toplevel( Workspace *ws );
Window handle() const;
Window frameId() const;
Window window() const;
Workspace* workspace() const;
QRect geometry() const;
QSize size() const;
@ -42,7 +45,7 @@ class Toplevel
int height() const;
// prefer isXXX() instead
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const = 0;
NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
bool hasNETSupport() const;
bool isDesktop() const;
bool isDock() const;
@ -59,10 +62,21 @@ class Toplevel
bool isOnCurrentDesktop() const;
bool isOnAllDesktops() const;
QByteArray windowRole() const;
QByteArray sessionId();
QByteArray resourceName() const;
QByteArray resourceClass() const;
QByteArray wmCommand();
QByteArray wmClientMachine( bool use_localhost ) const;
Window wmClientLeader() const;
pid_t pid() const;
static bool resourceMatch( const Toplevel* c1, const Toplevel* c2 );
Pixmap windowPixmap( bool allow_create = true ); // for use with compositing
Visual* visual() const;
bool shape() const;
virtual double opacity() const = 0;
void setOpacity( double opacity );
double opacity() const;
int depth() const;
bool hasAlpha() const;
void setupCompositing();
@ -76,37 +90,63 @@ class Toplevel
protected:
virtual ~Toplevel();
void setHandle( Window id );
void setWindowHandles( Window client, Window frame );
void detectShape( Window id );
virtual void propertyNotifyEvent( XPropertyEvent* e );
void damageNotifyEvent( XDamageNotifyEvent* e );
Pixmap createWindowPixmap() const;
void discardWindowPixmap();
void getWmClientLeader();
void getWmClientMachine();
void getResourceClass();
void getWindowRole();
virtual void debug( kdbgstream& stream ) const = 0;
void copyToDeleted( Toplevel* c );
void disownDataPassedToDeleted();
friend kdbgstream& operator<<( kdbgstream& stream, const Toplevel* );
QRect geom;
Visual* vis;
int bit_depth;
virtual void debug( kdbgstream& stream ) const = 0;
void copyToDeleted( Toplevel* c );
friend kdbgstream& operator<<( kdbgstream& stream, const Toplevel* );
NETWinInfo* info;
private:
static QByteArray staticWindowRole(WId);
static QByteArray staticSessionId(WId);
static QByteArray staticWmCommand(WId);
static QByteArray staticWmClientMachine(WId);
static Window staticWmClientLeader(WId);
// when adding new data members, check also copyToDeleted()
Window id;
Window client;
Window frame;
Workspace* wspace;
Pixmap window_pix;
Damage damage_handle;
QRegion damage_region;
bool is_shape;
EffectWindow* effect_window;
QByteArray resource_name;
QByteArray resource_class;
QByteArray client_machine;
WId wmClientLeaderWin;
QByteArray window_role;
// when adding new data members, check also copyToDeleted()
};
inline Window Toplevel::handle() const
inline Window Toplevel::window() const
{
return id;
return client;
}
inline void Toplevel::setHandle( Window w )
inline Window Toplevel::frameId() const
{
assert( id == None && w != None );
id = w;
return frame;
}
inline void Toplevel::setWindowHandles( Window w, Window f )
{
assert( client == None && w != None );
client = w;
assert( frame == None && f != None );
frame = f;
}
inline Workspace* Toplevel::workspace() const
@ -252,6 +292,26 @@ inline bool Toplevel::isOnCurrentDesktop() const
return isOnDesktop( workspace()->currentDesktop());
}
inline QByteArray Toplevel::resourceName() const
{
return resource_name; // it is always lowercase
}
inline QByteArray Toplevel::resourceClass() const
{
return resource_class; // it is always lowercase
}
inline QByteArray Toplevel::windowRole() const
{
return window_role;
}
inline pid_t Toplevel::pid() const
{
return info->pid();
}
#ifdef NDEBUG
inline
kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; }
@ -265,7 +325,8 @@ kdbgstream& operator<<( kdbgstream& stream, const ToplevelList& );
kdbgstream& operator<<( kdbgstream& stream, const ConstToplevelList& );
#endif
KWIN_COMPARE_PREDICATE( HandleMatchPredicate, Toplevel, Window, cl->handle() == value );
KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Toplevel, Window, cl->window() == value );
KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Toplevel, Window, cl->frameId() == value );
} // namespace

View File

@ -21,13 +21,11 @@ namespace KWinInternal
Unmanaged::Unmanaged( Workspace* ws )
: Toplevel( ws )
, info( NULL )
{
}
Unmanaged::~Unmanaged()
{
delete info;
}
bool Unmanaged::track( Window w )
@ -44,7 +42,7 @@ bool Unmanaged::track( Window w )
ungrabXServer();
return false;
}
setHandle( w );
setWindowHandles( w, w ); // the window is also the frame
XSelectInput( display(), w, StructureNotifyMask );
geom = QRect( attr.x, attr.y, attr.width, attr.height );
vis = attr.visual;
@ -71,19 +69,20 @@ bool Unmanaged::track( Window w )
void Unmanaged::release()
{
Deleted* del = Deleted::create( this );
if( effects )
{
Deleted* del = Deleted::create( this );
effects->windowClosed( del->effectWindow()); // effectWindow is already 'del'
effects->windowClosed( effectWindow());
scene->windowClosed( this, del );
del->unrefWindow();
}
finishCompositing();
workspace()->removeUnmanaged( this, Allowed );
if( Extensions::shapeAvailable())
XShapeSelectInput( display(), handle(), NoEventMask );
XSelectInput( display(), handle(), NoEventMask );
XShapeSelectInput( display(), window(), NoEventMask );
XSelectInput( display(), window(), NoEventMask );
workspace()->addDamage( geometry());
disownDataPassedToDeleted();
del->unrefWindow();
deleteUnmanaged( this, Allowed );
}
@ -92,18 +91,6 @@ void Unmanaged::deleteUnmanaged( Unmanaged* c, allowed_t )
delete c;
}
NET::WindowType Unmanaged::windowType( bool, int supported_types ) const
{
return info->windowType( supported_types );
}
double Unmanaged::opacity() const
{
if( info->opacity() == 0xffffffff )
return 1.0;
return info->opacity() * 1.0 / 0xffffffff;
}
int Unmanaged::desktop() const
{
return NET::OnAllDesktops; // TODO for some window types should be the current desktop?
@ -111,7 +98,7 @@ int Unmanaged::desktop() const
void Unmanaged::debug( kdbgstream& stream ) const
{
stream << "\'ID:" << handle() << "\'";
stream << "\'ID:" << window() << "\'";
}
} // namespace

View File

@ -27,9 +27,7 @@ class Unmanaged
bool windowEvent( XEvent* e );
void release();
bool track( Window w );
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
static void deleteUnmanaged( Unmanaged* c, allowed_t );
virtual double opacity() const;
virtual int desktop() const;
protected:
virtual void debug( kdbgstream& stream ) const;
@ -39,7 +37,6 @@ class Unmanaged
void mapNotifyEvent( XMapEvent* e );
void unmapNotifyEvent( XUnmapEvent*e );
void configureNotifyEvent( XConfigureEvent* e );
NETWinInfo* info;
};
} // namespace