Add support for dimming of inactive windows (accessibility).
FEATURE: 46226 svn path=/branches/work/kwin_composite/; revision=652255
This commit is contained in:
parent
0353f3376e
commit
d2dbc77323
11 changed files with 255 additions and 254 deletions
|
@ -71,6 +71,8 @@ General TODO
|
|||
|
||||
* cursorPos() does not work reliably now (not from e.g. timers, it needs events), so it's disabled
|
||||
|
||||
* window grouping is not implemented for unmanaged windows (used e.g. by DimInactive)
|
||||
|
||||
|
||||
OpenGL TODO
|
||||
=================================
|
||||
|
@ -237,3 +239,5 @@ Effects TODO
|
|||
+ - something that presents all virtual desktops as being in grid (as in pager)
|
||||
and zooms out of the old one and into the new one
|
||||
- or whatever
|
||||
|
||||
* DimInactive flickers when switching between windows (temporarily no window becomes active)
|
||||
|
|
35
effects.cpp
35
effects.cpp
|
@ -12,6 +12,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
|
||||
#include "deleted.h"
|
||||
#include "client.h"
|
||||
#include "group.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include "kdebug.h"
|
||||
|
@ -286,6 +287,21 @@ void EffectWindowImpl::disablePainting( int reason )
|
|||
sceneWindow()->disablePainting( reason );
|
||||
}
|
||||
|
||||
void EffectWindowImpl::addRepaint( const QRect& r )
|
||||
{
|
||||
toplevel->addRepaint( r );
|
||||
}
|
||||
|
||||
void EffectWindowImpl::addRepaint( int x, int y, int w, int h )
|
||||
{
|
||||
toplevel->addRepaint( x, y, w, h );
|
||||
}
|
||||
|
||||
void EffectWindowImpl::addRepaintFull()
|
||||
{
|
||||
toplevel->addRepaintFull();
|
||||
}
|
||||
|
||||
int EffectWindowImpl::desktop() const
|
||||
{
|
||||
return toplevel->desktop();
|
||||
|
@ -304,6 +320,13 @@ QString EffectWindowImpl::caption() const
|
|||
return "";
|
||||
}
|
||||
|
||||
const EffectWindowGroup* EffectWindowImpl::group() const
|
||||
{
|
||||
if( Client* c = dynamic_cast< Client* >( toplevel ))
|
||||
return c->group()->effectGroup();
|
||||
return NULL; // TODO
|
||||
}
|
||||
|
||||
bool EffectWindowImpl::isMinimized() const
|
||||
{
|
||||
if( Client* c = dynamic_cast<Client*>( toplevel ))
|
||||
|
@ -479,5 +502,17 @@ EffectWindow* effectWindow( Scene::Window* w )
|
|||
return ret;
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// EffectWindowGroupImpl
|
||||
//****************************************
|
||||
|
||||
|
||||
EffectWindowList EffectWindowGroupImpl::members() const
|
||||
{
|
||||
EffectWindowList ret;
|
||||
foreach( Toplevel* c, group->members())
|
||||
ret.append( c->effectWindow());
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
20
effects.h
20
effects.h
|
@ -64,6 +64,9 @@ class EffectWindowImpl : public EffectWindow
|
|||
|
||||
virtual void enablePainting( int reason );
|
||||
virtual void disablePainting( int reason );
|
||||
virtual void addRepaint( const QRect& r );
|
||||
virtual void addRepaint( int x, int y, int w, int h );
|
||||
virtual void addRepaintFull();
|
||||
|
||||
virtual bool isDeleted() const;
|
||||
|
||||
|
@ -71,6 +74,7 @@ class EffectWindowImpl : public EffectWindow
|
|||
virtual int desktop() const; // prefer isOnXXX()
|
||||
virtual bool isMinimized() const;
|
||||
virtual QString caption() const;
|
||||
virtual const EffectWindowGroup* group() const;
|
||||
|
||||
virtual int x() const;
|
||||
virtual int y() const;
|
||||
|
@ -109,6 +113,22 @@ class EffectWindowImpl : public EffectWindow
|
|||
Scene::Window* sw; // This one is used only during paint pass.
|
||||
};
|
||||
|
||||
class EffectWindowGroupImpl
|
||||
: public EffectWindowGroup
|
||||
{
|
||||
public:
|
||||
EffectWindowGroupImpl( Group* g );
|
||||
virtual EffectWindowList members() const;
|
||||
private:
|
||||
Group* group;
|
||||
};
|
||||
|
||||
inline
|
||||
EffectWindowGroupImpl::EffectWindowGroupImpl( Group* g )
|
||||
: group( g )
|
||||
{
|
||||
}
|
||||
|
||||
EffectWindow* effectWindow( Toplevel* w );
|
||||
EffectWindow* effectWindow( Scene::Window* w );
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ include_directories(
|
|||
${CMAKE_SOURCE_DIR}/workspace/kwin/lib
|
||||
)
|
||||
|
||||
KWIN4_ADD_EFFECT(builtins presentwindows.cpp shadow.cpp)
|
||||
KWIN4_ADD_EFFECT(builtins presentwindows.cpp shadow.cpp diminactive.cpp)
|
||||
|
||||
install( FILES presentwindows.desktop shadow.desktop
|
||||
install( FILES presentwindows.desktop shadow.desktop diminactive.desktop
|
||||
DESTINATION ${DATA_INSTALL_DIR}/kwin/effects )
|
||||
|
|
76
effects/diminactive.cpp
Normal file
76
effects/diminactive.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*****************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
|
||||
|
||||
You can Freely distribute this program under the GNU General Public
|
||||
License. See the file "COPYING" for the exact licensing terms.
|
||||
******************************************************************/
|
||||
|
||||
|
||||
#include "diminactive.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT( DimInactive, DimInactiveEffect )
|
||||
|
||||
DimInactiveEffect::DimInactiveEffect()
|
||||
: active( NULL )
|
||||
{
|
||||
dim_panels = true; // TODO config option
|
||||
dim_by_group = true; // TODO config option
|
||||
}
|
||||
|
||||
void DimInactiveEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
bool dim = false;
|
||||
if( active == NULL )
|
||||
dim = true;
|
||||
else if( dim_by_group && active->group() == w->group())
|
||||
dim = false;
|
||||
else if( !dim_by_group && active == w )
|
||||
dim = false;
|
||||
else if( w->isDock())
|
||||
dim = dim_panels;
|
||||
else
|
||||
dim = true;
|
||||
if( dim )
|
||||
{
|
||||
data.brightness *= 0.75;
|
||||
data.saturation *= 0.75;
|
||||
}
|
||||
effects->paintWindow( w, mask, region, data );
|
||||
}
|
||||
|
||||
void DimInactiveEffect::windowActivated( EffectWindow* w )
|
||||
{
|
||||
if( active != NULL )
|
||||
{
|
||||
if( dim_by_group )
|
||||
{
|
||||
if(( w == NULL || w->group() != active->group()) && active->group() != NULL )
|
||||
{ // repaint windows that are not longer in active group
|
||||
foreach( EffectWindow* tmp, active->group()->members())
|
||||
tmp->addRepaintFull();
|
||||
}
|
||||
}
|
||||
else
|
||||
active->addRepaintFull();
|
||||
}
|
||||
active = w;
|
||||
if( active != NULL )
|
||||
if( dim_by_group )
|
||||
{
|
||||
if( active->group() != NULL )
|
||||
{ // repaint newly active windows
|
||||
foreach( EffectWindow* tmp, active->group()->members())
|
||||
tmp->addRepaintFull();
|
||||
}
|
||||
}
|
||||
else
|
||||
active->addRepaintFull();
|
||||
}
|
||||
|
||||
} // namespace
|
4
effects/diminactive.desktop
Normal file
4
effects/diminactive.desktop
Normal file
|
@ -0,0 +1,4 @@
|
|||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=DimInactive
|
||||
X-KDE-Library=kwin4_effect_builtins
|
36
effects/diminactive.h
Normal file
36
effects/diminactive.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*****************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
|
||||
|
||||
You can Freely distribute this program under the GNU General Public
|
||||
License. See the file "COPYING" for the exact licensing terms.
|
||||
******************************************************************/
|
||||
|
||||
#ifndef KWIN_DIMINACTIVE_H
|
||||
#define KWIN_DIMINACTIVE_H
|
||||
|
||||
// Include with base class for effects.
|
||||
#include <kwineffects.h>
|
||||
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class DimInactiveEffect
|
||||
: public Effect
|
||||
{
|
||||
public:
|
||||
DimInactiveEffect();
|
||||
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
||||
virtual void windowActivated( EffectWindow* c );
|
||||
private:
|
||||
EffectWindow* active;
|
||||
bool dim_panels; // do/don't dim also all panels
|
||||
bool dim_by_group; // keep visible all windows from the active window's group or only the active window
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
298
group.cpp
298
group.cpp
|
@ -21,6 +21,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
|
||||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
#include "effects.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <kstartupinfo.h>
|
||||
|
@ -36,164 +37,6 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
/*
|
||||
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 +46,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 )
|
||||
{
|
||||
|
@ -213,12 +55,14 @@ Group::Group( Window leader_P, Workspace* workspace_P )
|
|||
leader_info = new NETWinInfo( display(), leader_P, workspace()->rootWin(),
|
||||
properties, 2 );
|
||||
}
|
||||
effect_group = new EffectWindowGroupImpl( this );
|
||||
workspace()->addGroup( this, Allowed );
|
||||
}
|
||||
|
||||
Group::~Group()
|
||||
{
|
||||
delete leader_info;
|
||||
delete effect_group;
|
||||
}
|
||||
|
||||
QPixmap Group::icon() const
|
||||
|
@ -249,7 +93,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 +100,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 +152,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 +169,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 +235,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 +242,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 +259,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 +284,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 +399,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 +415,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 +435,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 +452,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 +521,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 +650,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 +666,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 +683,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 +763,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 +820,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 +846,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 +856,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 +890,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()
|
||||
|
|
12
group.h
12
group.h
|
@ -21,6 +21,7 @@ namespace KWin
|
|||
|
||||
class Client;
|
||||
class Workspace;
|
||||
class EffectWindowGroupImpl;
|
||||
|
||||
class Group
|
||||
{
|
||||
|
@ -41,8 +42,7 @@ class Group
|
|||
bool groupEvent( XEvent* e );
|
||||
void updateUserTime( Time time = CurrentTime );
|
||||
Time userTime() const;
|
||||
void ref();
|
||||
void deref();
|
||||
EffectWindowGroupImpl* effectGroup();
|
||||
private:
|
||||
void getIcons();
|
||||
void startupIdChanged();
|
||||
|
@ -52,7 +52,7 @@ class Group
|
|||
Workspace* _workspace;
|
||||
NETWinInfo* leader_info;
|
||||
Time user_time;
|
||||
int refcount;
|
||||
EffectWindowGroupImpl* effect_group;
|
||||
};
|
||||
|
||||
inline Window Group::leader() const
|
||||
|
@ -85,6 +85,12 @@ inline Time Group::userTime() const
|
|||
return user_time;
|
||||
}
|
||||
|
||||
inline
|
||||
EffectWindowGroupImpl* Group::effectGroup()
|
||||
{
|
||||
return effect_group;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -469,4 +469,13 @@ bool EffectWindow::isOnDesktop( int d ) const
|
|||
}
|
||||
|
||||
|
||||
//****************************************
|
||||
// EffectWindowGroup
|
||||
//****************************************
|
||||
|
||||
EffectWindowGroup::~EffectWindowGroup()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace KWin
|
|||
|
||||
|
||||
class EffectWindow;
|
||||
class EffectWindowGroup;
|
||||
class Effect;
|
||||
|
||||
typedef QPair< QString, Effect* > EffectPair;
|
||||
|
@ -251,6 +252,9 @@ class KWIN_EXPORT EffectWindow
|
|||
|
||||
virtual void enablePainting( int reason ) = 0;
|
||||
virtual void disablePainting( int reason ) = 0;
|
||||
virtual void addRepaint( const QRect& r ) = 0;
|
||||
virtual void addRepaint( int x, int y, int w, int h ) = 0;
|
||||
virtual void addRepaintFull() = 0;
|
||||
|
||||
virtual bool isDeleted() const = 0;
|
||||
virtual bool isMinimized() const = 0;
|
||||
|
@ -270,6 +274,7 @@ class KWIN_EXPORT EffectWindow
|
|||
virtual QRect rect() const = 0;
|
||||
|
||||
virtual QString caption() const = 0;
|
||||
virtual const EffectWindowGroup* group() const = 0;
|
||||
|
||||
virtual bool isDesktop() const = 0;
|
||||
virtual bool isDock() const = 0;
|
||||
|
@ -290,6 +295,12 @@ class KWIN_EXPORT EffectWindow
|
|||
|
||||
};
|
||||
|
||||
class KWIN_EXPORT EffectWindowGroup
|
||||
{
|
||||
public:
|
||||
virtual ~EffectWindowGroup();
|
||||
virtual EffectWindowList members() const = 0;
|
||||
};
|
||||
|
||||
extern KWIN_EXPORT EffectsHandler* effects;
|
||||
|
||||
|
|
Loading…
Reference in a new issue