Move NETWinInfo and few more things from Client to the base class.
svn path=/branches/work/kwin_composite/; revision=632380icc-effect-5.14.5
parent
0a9e366038
commit
24eacc4908
179
client.cpp
179
client.cpp
|
@ -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() << "\'";
|
||||
|
|
70
client.h
70
client.h
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
16
deleted.cpp
16
deleted.cpp
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
36
events.cpp
36
events.cpp
|
@ -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
295
group.cpp
|
@ -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()
|
||||
|
|
18
manage.cpp
18
manage.cpp
|
@ -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 );
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
210
toplevel.cpp
210
toplevel.cpp
|
@ -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
|
||||
|
|
89
toplevel.h
89
toplevel.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue