You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1078 lines
33 KiB
1078 lines
33 KiB
/*****************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 2004 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 "rules.h"
|
|
|
|
#include <fixx11h.h>
|
|
#include <tdeconfig.h>
|
|
#include <tqregexp.h>
|
|
#include <tdetempfile.h>
|
|
#include <ksimpleconfig.h>
|
|
#include <tqfile.h>
|
|
|
|
#ifndef KCMRULES
|
|
#include "client.h"
|
|
#include "workspace.h"
|
|
#endif
|
|
|
|
namespace KWinInternal
|
|
{
|
|
|
|
Rules::Rules()
|
|
: temporary_state( 0 )
|
|
, wmclassmatch( UnimportantMatch )
|
|
, wmclasscomplete( UnimportantMatch )
|
|
, windowrolematch( UnimportantMatch )
|
|
, titlematch( UnimportantMatch )
|
|
, extrarolematch( UnimportantMatch )
|
|
, clientmachinematch( UnimportantMatch )
|
|
, types( NET::AllTypesMask )
|
|
, placementrule( UnusedForceRule )
|
|
, positionrule( UnusedSetRule )
|
|
, sizerule( UnusedSetRule )
|
|
, minsizerule( UnusedForceRule )
|
|
, maxsizerule( UnusedForceRule )
|
|
, opacityactiverule( UnusedForceRule )
|
|
, opacityinactiverule( UnusedForceRule )
|
|
, ignorepositionrule( UnusedForceRule )
|
|
, desktoprule( UnusedSetRule )
|
|
, typerule( UnusedForceRule )
|
|
, maximizevertrule( UnusedSetRule )
|
|
, maximizehorizrule( UnusedSetRule )
|
|
, minimizerule( UnusedSetRule )
|
|
, shaderule( UnusedSetRule )
|
|
, skiptaskbarrule( UnusedSetRule )
|
|
, skippagerrule( UnusedSetRule )
|
|
, aboverule( UnusedSetRule )
|
|
, belowrule( UnusedSetRule )
|
|
, fullscreenrule( UnusedSetRule )
|
|
, noborderrule( UnusedSetRule )
|
|
, fsplevelrule( UnusedForceRule )
|
|
, acceptfocusrule( UnusedForceRule )
|
|
, moveresizemoderule( UnusedForceRule )
|
|
, closeablerule( UnusedForceRule )
|
|
, strictgeometryrule( UnusedForceRule )
|
|
, shortcutrule( UnusedSetRule )
|
|
, disableglobalshortcutsrule( UnusedForceRule )
|
|
{
|
|
}
|
|
|
|
Rules::Rules( const TQString& str, bool temporary )
|
|
: temporary_state( temporary ? 2 : 0 )
|
|
{
|
|
KTempFile file;
|
|
TQFile* f = file.file();
|
|
if( f != NULL )
|
|
{
|
|
TQCString s = str.utf8();
|
|
f->writeBlock( s.data(), s.length());
|
|
}
|
|
file.close();
|
|
KSimpleConfig cfg( file.name());
|
|
readFromCfg( cfg );
|
|
if( description.isEmpty())
|
|
description = "temporary";
|
|
file.unlink();
|
|
}
|
|
|
|
#define READ_MATCH_STRING( var, func ) \
|
|
var = cfg.readEntry( #var ) func; \
|
|
var##match = (StringMatch) TQMAX( FirstStringMatch, TQMIN( LastStringMatch, cfg.readNumEntry( #var "match" )));
|
|
|
|
#define READ_SET_RULE( var, type, func ) \
|
|
var = func ( cfg.read##type##Entry( #var )); \
|
|
var##rule = readSetRule( cfg, #var "rule" );
|
|
|
|
#define READ_SET_RULE_DEF( var, type, func, def ) \
|
|
var = func ( cfg.read##type##Entry( #var, def )); \
|
|
var##rule = readSetRule( cfg, #var "rule" );
|
|
|
|
#define READ_SET_RULE_2( var, type, func, funcarg ) \
|
|
var = func ( cfg.read##type##Entry( #var ), funcarg ); \
|
|
var##rule = readSetRule( cfg, #var "rule" );
|
|
|
|
#define READ_FORCE_RULE( var, type, func ) \
|
|
var = func ( cfg.read##type##Entry( #var )); \
|
|
var##rule = readForceRule( cfg, #var "rule" );
|
|
|
|
#define READ_FORCE_RULE_2( var, type, func, funcarg ) \
|
|
var = func ( cfg.read##type##Entry( #var ), funcarg ); \
|
|
var##rule = readForceRule( cfg, #var "rule" );
|
|
|
|
|
|
Rules::Rules( TDEConfig& cfg )
|
|
: temporary_state( 0 )
|
|
{
|
|
readFromCfg( cfg );
|
|
}
|
|
|
|
static int limit0to4( int i ) { return QMAX( 0, QMIN( 4, i )); }
|
|
|
|
void Rules::readFromCfg( TDEConfig& cfg )
|
|
{
|
|
description = cfg.readEntry( "Description" );
|
|
if( description.isEmpty()) // capitalized first, lowercase for backwards compatibility
|
|
description = cfg.readEntry( "description" );
|
|
READ_MATCH_STRING( wmclass, .lower().latin1() );
|
|
wmclasscomplete = cfg.readBoolEntry( "wmclasscomplete" );
|
|
READ_MATCH_STRING( windowrole, .lower().latin1() );
|
|
READ_MATCH_STRING( title, );
|
|
READ_MATCH_STRING( extrarole, .lower().latin1() );
|
|
READ_MATCH_STRING( clientmachine, .lower().latin1() );
|
|
types = cfg.readUnsignedLongNumEntry( "types", NET::AllTypesMask );
|
|
READ_FORCE_RULE_2( placement,, Placement::policyFromString, false );
|
|
READ_SET_RULE_DEF( position, Point,, &invalidPoint );
|
|
READ_SET_RULE( size, Size, );
|
|
if( size.isEmpty() && sizerule != ( SetRule )Remember)
|
|
sizerule = UnusedSetRule;
|
|
READ_FORCE_RULE( minsize, Size, );
|
|
if( !minsize.isValid())
|
|
minsize = TQSize( 1, 1 );
|
|
READ_FORCE_RULE( maxsize, Size, );
|
|
if( maxsize.isEmpty())
|
|
maxsize = TQSize( 32767, 32767 );
|
|
READ_FORCE_RULE( opacityactive, Num, );
|
|
if( opacityactive < 0 || opacityactive > 100 )
|
|
opacityactive = 100;
|
|
READ_FORCE_RULE( opacityinactive, Num, );
|
|
if( opacityinactive < 0 || opacityinactive > 100 )
|
|
opacityinactive = 100;
|
|
READ_FORCE_RULE( ignoreposition, Bool, );
|
|
READ_SET_RULE( desktop, Num, );
|
|
type = readType( cfg, "type" );
|
|
typerule = type != NET::Unknown ? readForceRule( cfg, "typerule" ) : UnusedForceRule;
|
|
READ_SET_RULE( maximizevert, Bool, );
|
|
READ_SET_RULE( maximizehoriz, Bool, );
|
|
READ_SET_RULE( minimize, Bool, );
|
|
READ_SET_RULE( shade, Bool, );
|
|
READ_SET_RULE( skiptaskbar, Bool, );
|
|
READ_SET_RULE( skippager, Bool, );
|
|
READ_SET_RULE( above, Bool, );
|
|
READ_SET_RULE( below, Bool, );
|
|
READ_SET_RULE( fullscreen, Bool, );
|
|
READ_SET_RULE( noborder, Bool, );
|
|
READ_FORCE_RULE( fsplevel, Num, limit0to4 ); // fsp is 0-4
|
|
READ_FORCE_RULE( acceptfocus, Bool, );
|
|
READ_FORCE_RULE( moveresizemode, , Options::stringToMoveResizeMode );
|
|
READ_FORCE_RULE( closeable, Bool, );
|
|
READ_FORCE_RULE( strictgeometry, Bool, );
|
|
READ_SET_RULE( shortcut, , );
|
|
READ_FORCE_RULE( disableglobalshortcuts, Bool, );
|
|
}
|
|
|
|
#undef READ_MATCH_STRING
|
|
#undef READ_SET_RULE
|
|
#undef READ_SET_RULE_2
|
|
#undef READ_FORCE_RULE
|
|
#undef READ_FORCE_RULE_2
|
|
|
|
#define WRITE_MATCH_STRING( var, cast, force ) \
|
|
if( !var.isEmpty() || force ) \
|
|
{ \
|
|
cfg.writeEntry( #var, cast var ); \
|
|
cfg.writeEntry( #var "match", var##match ); \
|
|
} \
|
|
else \
|
|
{ \
|
|
cfg.deleteEntry( #var ); \
|
|
cfg.deleteEntry( #var "match" ); \
|
|
}
|
|
|
|
#define WRITE_SET_RULE( var, func ) \
|
|
if( var##rule != UnusedSetRule ) \
|
|
{ \
|
|
cfg.writeEntry( #var, func ( var )); \
|
|
cfg.writeEntry( #var "rule", var##rule ); \
|
|
} \
|
|
else \
|
|
{ \
|
|
cfg.deleteEntry( #var ); \
|
|
cfg.deleteEntry( #var "rule" ); \
|
|
}
|
|
|
|
#define WRITE_FORCE_RULE( var, func ) \
|
|
if( var##rule != UnusedForceRule ) \
|
|
{ \
|
|
cfg.writeEntry( #var, func ( var )); \
|
|
cfg.writeEntry( #var "rule", var##rule ); \
|
|
} \
|
|
else \
|
|
{ \
|
|
cfg.deleteEntry( #var ); \
|
|
cfg.deleteEntry( #var "rule" ); \
|
|
}
|
|
|
|
#define WRITE_WITH_DEFAULT( var, default ) \
|
|
if( var != default ) \
|
|
cfg.writeEntry( #var, var ); \
|
|
else \
|
|
cfg.deleteEntry( #var );
|
|
|
|
|
|
void Rules::write( TDEConfig& cfg ) const
|
|
{
|
|
cfg.writeEntry( "Description", description );
|
|
// always write wmclass
|
|
WRITE_MATCH_STRING( wmclass, (const char*), true );
|
|
cfg.writeEntry( "wmclasscomplete", wmclasscomplete );
|
|
WRITE_MATCH_STRING( windowrole, (const char*), false );
|
|
WRITE_MATCH_STRING( title,, false );
|
|
WRITE_MATCH_STRING( extrarole, (const char*), false );
|
|
WRITE_MATCH_STRING( clientmachine, (const char*), false );
|
|
WRITE_WITH_DEFAULT( types, NET::AllTypesMask );
|
|
WRITE_FORCE_RULE( placement, Placement::policyToString );
|
|
WRITE_SET_RULE( position, );
|
|
WRITE_SET_RULE( size, );
|
|
WRITE_FORCE_RULE( minsize, );
|
|
WRITE_FORCE_RULE( maxsize, );
|
|
WRITE_FORCE_RULE( opacityactive, );
|
|
WRITE_FORCE_RULE( opacityinactive, );
|
|
WRITE_FORCE_RULE( ignoreposition, );
|
|
WRITE_SET_RULE( desktop, );
|
|
WRITE_FORCE_RULE( type, );
|
|
WRITE_SET_RULE( maximizevert, );
|
|
WRITE_SET_RULE( maximizehoriz, );
|
|
WRITE_SET_RULE( minimize, );
|
|
WRITE_SET_RULE( shade, );
|
|
WRITE_SET_RULE( skiptaskbar, );
|
|
WRITE_SET_RULE( skippager, );
|
|
WRITE_SET_RULE( above, );
|
|
WRITE_SET_RULE( below, );
|
|
WRITE_SET_RULE( fullscreen, );
|
|
WRITE_SET_RULE( noborder, );
|
|
WRITE_FORCE_RULE( fsplevel, );
|
|
WRITE_FORCE_RULE( acceptfocus, );
|
|
WRITE_FORCE_RULE( moveresizemode, Options::moveResizeModeToString );
|
|
WRITE_FORCE_RULE( closeable, );
|
|
WRITE_FORCE_RULE( strictgeometry, );
|
|
WRITE_SET_RULE( shortcut, );
|
|
WRITE_FORCE_RULE( disableglobalshortcuts, );
|
|
}
|
|
|
|
#undef WRITE_MATCH_STRING
|
|
#undef WRITE_SET_RULE
|
|
#undef WRITE_FORCE_RULE
|
|
#undef WRITE_WITH_DEFAULT
|
|
|
|
// returns true if it doesn't affect anything
|
|
bool Rules::isEmpty() const
|
|
{
|
|
return( placementrule == UnusedForceRule
|
|
&& positionrule == UnusedSetRule
|
|
&& sizerule == UnusedSetRule
|
|
&& minsizerule == UnusedForceRule
|
|
&& maxsizerule == UnusedForceRule
|
|
&& opacityactiverule == UnusedForceRule
|
|
&& opacityinactiverule == UnusedForceRule
|
|
&& ignorepositionrule == UnusedForceRule
|
|
&& desktoprule == UnusedSetRule
|
|
&& typerule == UnusedForceRule
|
|
&& maximizevertrule == UnusedSetRule
|
|
&& maximizehorizrule == UnusedSetRule
|
|
&& minimizerule == UnusedSetRule
|
|
&& shaderule == UnusedSetRule
|
|
&& skiptaskbarrule == UnusedSetRule
|
|
&& skippagerrule == UnusedSetRule
|
|
&& aboverule == UnusedSetRule
|
|
&& belowrule == UnusedSetRule
|
|
&& fullscreenrule == UnusedSetRule
|
|
&& noborderrule == UnusedSetRule
|
|
&& fsplevelrule == UnusedForceRule
|
|
&& acceptfocusrule == UnusedForceRule
|
|
&& moveresizemoderule == UnusedForceRule
|
|
&& closeablerule == UnusedForceRule
|
|
&& strictgeometryrule == UnusedForceRule
|
|
&& shortcutrule == UnusedSetRule
|
|
&& disableglobalshortcutsrule == UnusedForceRule );
|
|
}
|
|
|
|
Rules::SetRule Rules::readSetRule( TDEConfig& cfg, const TQString& key )
|
|
{
|
|
int v = cfg.readNumEntry( key );
|
|
if( v >= DontAffect && v <= ForceTemporarily )
|
|
return static_cast< SetRule >( v );
|
|
return UnusedSetRule;
|
|
}
|
|
|
|
Rules::ForceRule Rules::readForceRule( TDEConfig& cfg, const TQString& key )
|
|
{
|
|
int v = cfg.readNumEntry( key );
|
|
if( v == DontAffect || v == Force || v == ForceTemporarily )
|
|
return static_cast< ForceRule >( v );
|
|
return UnusedForceRule;
|
|
}
|
|
|
|
NET::WindowType Rules::readType( TDEConfig& cfg, const TQString& key )
|
|
{
|
|
int v = cfg.readNumEntry( key );
|
|
if( v >= NET::Normal && v <= NET::Splash )
|
|
return static_cast< NET::WindowType >( v );
|
|
return NET::Unknown;
|
|
}
|
|
|
|
bool Rules::matchType( NET::WindowType match_type ) const
|
|
{
|
|
if( types != NET::AllTypesMask )
|
|
{
|
|
if( match_type == NET::Unknown )
|
|
match_type = NET::Normal; // NET::Unknown->NET::Normal is only here for matching
|
|
if( !NET::typeMatchesMask( match_type, types ))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Rules::matchWMClass( const TQCString& match_class, const TQCString& match_name ) const
|
|
{
|
|
if( wmclassmatch != UnimportantMatch )
|
|
{ // TODO optimize?
|
|
TQCString cwmclass = wmclasscomplete
|
|
? match_name + ' ' + match_class : match_class;
|
|
if( wmclassmatch == RegExpMatch && TQRegExp( wmclass ).search( cwmclass ) == -1 )
|
|
return false;
|
|
if( wmclassmatch == ExactMatch && wmclass != cwmclass )
|
|
return false;
|
|
if( wmclassmatch == SubstringMatch && !cwmclass.contains( wmclass ))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Rules::matchRole( const TQCString& match_role ) const
|
|
{
|
|
if( windowrolematch != UnimportantMatch )
|
|
{
|
|
if( windowrolematch == RegExpMatch && TQRegExp( windowrole ).search( match_role ) == -1 )
|
|
return false;
|
|
if( windowrolematch == ExactMatch && windowrole != match_role )
|
|
return false;
|
|
if( windowrolematch == SubstringMatch && !match_role.contains( windowrole ))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Rules::matchTitle( const TQString& match_title ) const
|
|
{
|
|
if( titlematch != UnimportantMatch )
|
|
{
|
|
if( titlematch == RegExpMatch && TQRegExp( title ).search( match_title ) == -1 )
|
|
return false;
|
|
if( titlematch == ExactMatch && title != match_title )
|
|
return false;
|
|
if( titlematch == SubstringMatch && !match_title.contains( title ))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Rules::matchClientMachine( const TQCString& match_machine ) const
|
|
{
|
|
if( clientmachinematch != UnimportantMatch )
|
|
{
|
|
// if it's localhost, check also "localhost" before checking hostname
|
|
if( match_machine != "localhost" && isLocalMachine( match_machine )
|
|
&& matchClientMachine( "localhost" ))
|
|
return true;
|
|
if( clientmachinematch == RegExpMatch
|
|
&& TQRegExp( clientmachine ).search( match_machine ) == -1 )
|
|
return false;
|
|
if( clientmachinematch == ExactMatch
|
|
&& clientmachine != match_machine )
|
|
return false;
|
|
if( clientmachinematch == SubstringMatch
|
|
&& !match_machine.contains( clientmachine ))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#ifndef KCMRULES
|
|
bool Rules::match( const Client* c ) const
|
|
{
|
|
if( !matchType( c->windowType( true )))
|
|
return false;
|
|
if( !matchWMClass( c->resourceClass(), c->resourceName()))
|
|
return false;
|
|
if( !matchRole( c->windowRole()))
|
|
return false;
|
|
if( !matchTitle( c->caption( false )))
|
|
return false;
|
|
// TODO extrarole
|
|
if( !matchClientMachine( c->wmClientMachine( false )))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool Rules::update( Client* c )
|
|
{
|
|
// TODO check this setting is for this client ?
|
|
bool updated = false;
|
|
if( positionrule == ( SetRule )Remember)
|
|
{
|
|
if( !c->isFullScreen())
|
|
{
|
|
TQPoint new_pos = position;
|
|
// don't use the position in the direction which is maximized
|
|
if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
|
|
new_pos.setX( c->pos().x());
|
|
if(( c->maximizeMode() & MaximizeVertical ) == 0 )
|
|
new_pos.setY( c->pos().y());
|
|
updated = updated || position != new_pos;
|
|
position = new_pos;
|
|
}
|
|
}
|
|
if( sizerule == ( SetRule )Remember)
|
|
{
|
|
if( !c->isFullScreen())
|
|
{
|
|
TQSize new_size = size;
|
|
// don't use the position in the direction which is maximized
|
|
if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
|
|
new_size.setWidth( c->size().width());
|
|
if(( c->maximizeMode() & MaximizeVertical ) == 0 )
|
|
new_size.setHeight( c->size().height());
|
|
updated = updated || size != new_size;
|
|
size = new_size;
|
|
}
|
|
}
|
|
if( desktoprule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || desktop != c->desktop();
|
|
desktop = c->desktop();
|
|
}
|
|
if( maximizevertrule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || maximizevert != bool( c->maximizeMode() & MaximizeVertical );
|
|
maximizevert = c->maximizeMode() & MaximizeVertical;
|
|
}
|
|
if( maximizehorizrule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || maximizehoriz != bool( c->maximizeMode() & MaximizeHorizontal );
|
|
maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
|
|
}
|
|
if( minimizerule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || minimize != c->isMinimized();
|
|
minimize = c->isMinimized();
|
|
}
|
|
if( shaderule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || ( shade != ( c->shadeMode() != ShadeNone ));
|
|
shade = c->shadeMode() != ShadeNone;
|
|
}
|
|
if( skiptaskbarrule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || skiptaskbar != c->skipTaskbar();
|
|
skiptaskbar = c->skipTaskbar();
|
|
}
|
|
if( skippagerrule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || skippager != c->skipPager();
|
|
skippager = c->skipPager();
|
|
}
|
|
if( aboverule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || above != c->keepAbove();
|
|
above = c->keepAbove();
|
|
}
|
|
if( belowrule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || below != c->keepBelow();
|
|
below = c->keepBelow();
|
|
}
|
|
if( fullscreenrule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || fullscreen != c->isFullScreen();
|
|
fullscreen = c->isFullScreen();
|
|
}
|
|
if( noborderrule == ( SetRule )Remember)
|
|
{
|
|
updated = updated || noborder != c->isUserNoBorder();
|
|
noborder = c->isUserNoBorder();
|
|
}
|
|
if (opacityactiverule == ( ForceRule )Force)
|
|
{
|
|
updated = updated || (uint) (opacityactive/100.0*0xffffffff) != c->ruleOpacityActive();
|
|
opacityactive = (uint)(((double)c->ruleOpacityActive())/0xffffffff*100);
|
|
}
|
|
if (opacityinactiverule == ( ForceRule )Force)
|
|
{
|
|
updated = updated || (uint) (opacityinactive/100.0*0xffffffff) != c->ruleOpacityInactive();
|
|
opacityinactive = (uint)(((double)c->ruleOpacityInactive())/0xffffffff*100);
|
|
}
|
|
return updated;
|
|
}
|
|
|
|
#define APPLY_RULE( var, name, type ) \
|
|
bool Rules::apply##name( type& arg, bool init ) const \
|
|
{ \
|
|
if( checkSetRule( var##rule, init )) \
|
|
arg = this->var; \
|
|
return checkSetStop( var##rule ); \
|
|
}
|
|
|
|
#define APPLY_FORCE_RULE( var, name, type ) \
|
|
bool Rules::apply##name( type& arg ) const \
|
|
{ \
|
|
if( checkForceRule( var##rule )) \
|
|
arg = this->var; \
|
|
return checkForceStop( var##rule ); \
|
|
}
|
|
|
|
APPLY_FORCE_RULE( placement, Placement, Placement::Policy )
|
|
|
|
bool Rules::applyGeometry( TQRect& rect, bool init ) const
|
|
{
|
|
TQPoint p = rect.topLeft();
|
|
TQSize s = rect.size();
|
|
bool ret = false; // no short-circuiting
|
|
if( applyPosition( p, init ))
|
|
{
|
|
rect.moveTopLeft( p );
|
|
ret = true;
|
|
}
|
|
if( applySize( s, init ))
|
|
{
|
|
rect.setSize( s );
|
|
ret = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool Rules::applyPosition( TQPoint& pos, bool init ) const
|
|
{
|
|
if( this->position != invalidPoint && checkSetRule( positionrule, init ))
|
|
pos = this->position;
|
|
return checkSetStop( positionrule );
|
|
}
|
|
|
|
bool Rules::applySize( TQSize& s, bool init ) const
|
|
{
|
|
if( this->size.isValid() && checkSetRule( sizerule, init ))
|
|
s = this->size;
|
|
return checkSetStop( sizerule );
|
|
}
|
|
|
|
APPLY_FORCE_RULE( minsize, MinSize, TQSize )
|
|
APPLY_FORCE_RULE( maxsize, MaxSize, TQSize )
|
|
APPLY_FORCE_RULE( opacityactive, OpacityActive, int )
|
|
APPLY_FORCE_RULE( opacityinactive, OpacityInactive, int )
|
|
APPLY_FORCE_RULE( ignoreposition, IgnorePosition, bool )
|
|
|
|
// the cfg. entry needs to stay named the say for backwards compatibility
|
|
bool Rules::applyIgnoreGeometry( bool& ignore ) const
|
|
{
|
|
return applyIgnorePosition( ignore );
|
|
}
|
|
|
|
APPLY_RULE( desktop, Desktop, int )
|
|
APPLY_FORCE_RULE( type, Type, NET::WindowType )
|
|
|
|
bool Rules::applyMaximizeHoriz( MaximizeMode& mode, bool init ) const
|
|
{
|
|
if( checkSetRule( maximizehorizrule, init ))
|
|
mode = static_cast< MaximizeMode >(( maximizehoriz ? MaximizeHorizontal : 0 ) | ( mode & MaximizeVertical ));
|
|
return checkSetStop( maximizehorizrule );
|
|
}
|
|
|
|
bool Rules::applyMaximizeVert( MaximizeMode& mode, bool init ) const
|
|
{
|
|
if( checkSetRule( maximizevertrule, init ))
|
|
mode = static_cast< MaximizeMode >(( maximizevert ? MaximizeVertical : 0 ) | ( mode & MaximizeHorizontal ));
|
|
return checkSetStop( maximizevertrule );
|
|
}
|
|
|
|
APPLY_RULE( minimize, Minimize, bool )
|
|
|
|
bool Rules::applyShade( ShadeMode& sh, bool init ) const
|
|
{
|
|
if( checkSetRule( shaderule, init ))
|
|
{
|
|
if( !this->shade )
|
|
sh = ShadeNone;
|
|
if( this->shade && sh == ShadeNone )
|
|
sh = ShadeNormal;
|
|
}
|
|
return checkSetStop( shaderule );
|
|
}
|
|
|
|
APPLY_RULE( skiptaskbar, SkipTaskbar, bool )
|
|
APPLY_RULE( skippager, SkipPager, bool )
|
|
APPLY_RULE( above, KeepAbove, bool )
|
|
APPLY_RULE( below, KeepBelow, bool )
|
|
APPLY_RULE( fullscreen, FullScreen, bool )
|
|
APPLY_RULE( noborder, NoBorder, bool )
|
|
APPLY_FORCE_RULE( fsplevel, FSP, int )
|
|
APPLY_FORCE_RULE( acceptfocus, AcceptFocus, bool )
|
|
APPLY_FORCE_RULE( moveresizemode, MoveResizeMode, Options::MoveResizeMode )
|
|
APPLY_FORCE_RULE( closeable, Closeable, bool )
|
|
APPLY_FORCE_RULE( strictgeometry, StrictGeometry, bool )
|
|
APPLY_RULE( shortcut, Shortcut, TQString )
|
|
APPLY_FORCE_RULE( disableglobalshortcuts, DisableGlobalShortcuts, bool )
|
|
|
|
|
|
#undef APPLY_RULE
|
|
#undef APPLY_FORCE_RULE
|
|
|
|
bool Rules::isTemporary() const
|
|
{
|
|
return temporary_state > 0;
|
|
}
|
|
|
|
bool Rules::discardTemporary( bool force )
|
|
{
|
|
if( temporary_state == 0 ) // not temporary
|
|
return false;
|
|
if( force || --temporary_state == 0 ) // too old
|
|
{
|
|
delete this;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#define DISCARD_USED_SET_RULE( var ) \
|
|
do { \
|
|
if( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) \
|
|
var##rule = UnusedSetRule; \
|
|
} while( false )
|
|
#define DISCARD_USED_FORCE_RULE( var ) \
|
|
do { \
|
|
if( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) \
|
|
var##rule = UnusedForceRule; \
|
|
} while( false )
|
|
|
|
void Rules::discardUsed( bool withdrawn )
|
|
{
|
|
DISCARD_USED_FORCE_RULE( placement );
|
|
DISCARD_USED_SET_RULE( position );
|
|
DISCARD_USED_SET_RULE( size );
|
|
DISCARD_USED_FORCE_RULE( minsize );
|
|
DISCARD_USED_FORCE_RULE( maxsize );
|
|
DISCARD_USED_FORCE_RULE( opacityactive );
|
|
DISCARD_USED_FORCE_RULE( opacityinactive );
|
|
DISCARD_USED_FORCE_RULE( ignoreposition );
|
|
DISCARD_USED_SET_RULE( desktop );
|
|
DISCARD_USED_FORCE_RULE( type );
|
|
DISCARD_USED_SET_RULE( maximizevert );
|
|
DISCARD_USED_SET_RULE( maximizehoriz );
|
|
DISCARD_USED_SET_RULE( minimize );
|
|
DISCARD_USED_SET_RULE( shade );
|
|
DISCARD_USED_SET_RULE( skiptaskbar );
|
|
DISCARD_USED_SET_RULE( skippager );
|
|
DISCARD_USED_SET_RULE( above );
|
|
DISCARD_USED_SET_RULE( below );
|
|
DISCARD_USED_SET_RULE( fullscreen );
|
|
DISCARD_USED_SET_RULE( noborder );
|
|
DISCARD_USED_FORCE_RULE( fsplevel );
|
|
DISCARD_USED_FORCE_RULE( acceptfocus );
|
|
DISCARD_USED_FORCE_RULE( moveresizemode );
|
|
DISCARD_USED_FORCE_RULE( closeable );
|
|
DISCARD_USED_FORCE_RULE( strictgeometry );
|
|
DISCARD_USED_SET_RULE( shortcut );
|
|
DISCARD_USED_FORCE_RULE( disableglobalshortcuts );
|
|
}
|
|
#undef DISCARD_USED_SET_RULE
|
|
#undef DISCARD_USED_FORCE_RULE
|
|
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
kdbgstream& operator<<( kdbgstream& stream, const Rules* r )
|
|
{
|
|
return stream << "[" << r->description << ":" << r->wmclass << "]" ;
|
|
}
|
|
#endif
|
|
|
|
#ifndef KCMRULES
|
|
void WindowRules::discardTemporary()
|
|
{
|
|
TQValueVector< Rules* >::Iterator it2 = rules.begin();
|
|
for( TQValueVector< Rules* >::Iterator it = rules.begin();
|
|
it != rules.end();
|
|
)
|
|
{
|
|
if( (*it)->discardTemporary( true ))
|
|
++it;
|
|
else
|
|
{
|
|
*it2++ = *it++;
|
|
}
|
|
}
|
|
rules.erase( it2, rules.end());
|
|
}
|
|
|
|
void WindowRules::update( Client* c )
|
|
{
|
|
bool updated = false;
|
|
for( TQValueVector< Rules* >::ConstIterator it = rules.begin();
|
|
it != rules.end();
|
|
++it )
|
|
if( (*it)->update( c )) // no short-circuiting here
|
|
updated = true;
|
|
if( updated )
|
|
Workspace::self()->rulesUpdated();
|
|
}
|
|
|
|
#define CHECK_RULE( rule, type ) \
|
|
type WindowRules::check##rule( type arg, bool init ) const \
|
|
{ \
|
|
if( rules.count() == 0 ) \
|
|
return arg; \
|
|
type ret = arg; \
|
|
for( TQValueVector< Rules* >::ConstIterator it = rules.begin(); \
|
|
it != rules.end(); \
|
|
++it ) \
|
|
{ \
|
|
if( (*it)->apply##rule( ret, init )) \
|
|
break; \
|
|
} \
|
|
return ret; \
|
|
}
|
|
|
|
#define CHECK_FORCE_RULE( rule, type ) \
|
|
type WindowRules::check##rule( type arg ) const \
|
|
{ \
|
|
if( rules.count() == 0 ) \
|
|
return arg; \
|
|
type ret = arg; \
|
|
for( TQValueVector< Rules* >::ConstIterator it = rules.begin(); \
|
|
it != rules.end(); \
|
|
++it ) \
|
|
{ \
|
|
if( (*it)->apply##rule( ret )) \
|
|
break; \
|
|
} \
|
|
return ret; \
|
|
}
|
|
|
|
CHECK_FORCE_RULE( Placement, Placement::Policy )
|
|
|
|
TQRect WindowRules::checkGeometry( TQRect rect, bool init ) const
|
|
{
|
|
return TQRect( checkPosition( rect.topLeft(), init ), checkSize( rect.size(), init ));
|
|
}
|
|
|
|
CHECK_RULE( Position, TQPoint )
|
|
CHECK_RULE( Size, TQSize )
|
|
CHECK_FORCE_RULE( MinSize, TQSize )
|
|
CHECK_FORCE_RULE( MaxSize, TQSize )
|
|
CHECK_FORCE_RULE( OpacityActive, int )
|
|
CHECK_FORCE_RULE( OpacityInactive, int )
|
|
CHECK_FORCE_RULE( IgnorePosition, bool )
|
|
|
|
bool WindowRules::checkIgnoreGeometry( bool ignore ) const
|
|
{
|
|
return checkIgnorePosition( ignore );
|
|
}
|
|
|
|
CHECK_RULE( Desktop, int )
|
|
CHECK_FORCE_RULE( Type, NET::WindowType )
|
|
CHECK_RULE( MaximizeVert, KDecorationDefines::MaximizeMode )
|
|
CHECK_RULE( MaximizeHoriz, KDecorationDefines::MaximizeMode )
|
|
|
|
KDecorationDefines::MaximizeMode WindowRules::checkMaximize( MaximizeMode mode, bool init ) const
|
|
{
|
|
bool vert = checkMaximizeVert( mode, init ) & MaximizeVertical;
|
|
bool horiz = checkMaximizeHoriz( mode, init ) & MaximizeHorizontal;
|
|
return static_cast< MaximizeMode >(( vert ? MaximizeVertical : 0 ) | ( horiz ? MaximizeHorizontal : 0 ));
|
|
}
|
|
|
|
CHECK_RULE( Minimize, bool )
|
|
CHECK_RULE( Shade, ShadeMode )
|
|
CHECK_RULE( SkipTaskbar, bool )
|
|
CHECK_RULE( SkipPager, bool )
|
|
CHECK_RULE( KeepAbove, bool )
|
|
CHECK_RULE( KeepBelow, bool )
|
|
CHECK_RULE( FullScreen, bool )
|
|
CHECK_RULE( NoBorder, bool )
|
|
CHECK_FORCE_RULE( FSP, int )
|
|
CHECK_FORCE_RULE( AcceptFocus, bool )
|
|
CHECK_FORCE_RULE( MoveResizeMode, Options::MoveResizeMode )
|
|
CHECK_FORCE_RULE( Closeable, bool )
|
|
CHECK_FORCE_RULE( StrictGeometry, bool )
|
|
CHECK_RULE( Shortcut, TQString )
|
|
CHECK_FORCE_RULE( DisableGlobalShortcuts, bool )
|
|
|
|
#undef CHECK_RULE
|
|
#undef CHECK_FORCE_RULE
|
|
|
|
// Client
|
|
|
|
void Client::setupWindowRules( bool ignore_temporary )
|
|
{
|
|
client_rules = workspace()->findWindowRules( this, ignore_temporary );
|
|
// check only after getting the rules, because there may be a rule forcing window type
|
|
if( isTopMenu()) // TODO cannot have restrictions
|
|
client_rules = WindowRules();
|
|
}
|
|
|
|
// Applies Force, ForceTemporarily and ApplyNow rules
|
|
// Used e.g. after the rules have been modified using the kcm.
|
|
void Client::applyWindowRules()
|
|
{
|
|
checkAndSetInitialRuledOpacity();
|
|
// apply force rules
|
|
// Placement - does need explicit update, just like some others below
|
|
// Geometry : setGeometry() doesn't check rules
|
|
TQRect orig_geom = TQRect( pos(), sizeForClientSize( clientSize())); // handle shading
|
|
TQRect geom = client_rules.checkGeometry( orig_geom );
|
|
if( geom != orig_geom )
|
|
setGeometry( geom );
|
|
// MinSize, MaxSize handled by Geometry
|
|
// IgnorePosition
|
|
setDesktop( desktop());
|
|
// Type
|
|
maximize( maximizeMode());
|
|
// Minimize : functions don't check, and there are two functions
|
|
if( client_rules.checkMinimize( isMinimized()))
|
|
minimize();
|
|
else
|
|
unminimize();
|
|
setShade( shadeMode());
|
|
setSkipTaskbar( skipTaskbar(), true );
|
|
setSkipPager( skipPager());
|
|
setKeepAbove( keepAbove());
|
|
setKeepBelow( keepBelow());
|
|
setFullScreen( isFullScreen(), true );
|
|
setUserNoBorder( isUserNoBorder());
|
|
// FSP
|
|
// AcceptFocus :
|
|
if( workspace()->mostRecentlyActivatedClient() == this
|
|
&& !client_rules.checkAcceptFocus( true ))
|
|
workspace()->activateNextClient( this );
|
|
// MoveResizeMode
|
|
// Closeable
|
|
TQSize s = adjustedSize();
|
|
if( s != size())
|
|
resizeWithChecks( s );
|
|
// StrictGeometry
|
|
setShortcut( rules()->checkShortcut( shortcut().toString()));
|
|
// see also Client::setActive()
|
|
if( isActive())
|
|
workspace()->disableGlobalShortcutsForClient( rules()->checkDisableGlobalShortcuts( false ));
|
|
}
|
|
|
|
void Client::updateWindowRules()
|
|
{
|
|
if( !isManaged()) // not fully setup yet
|
|
return;
|
|
if( workspace()->rulesUpdatesDisabled())
|
|
return;
|
|
client_rules.update( this );
|
|
}
|
|
|
|
void Client::finishWindowRules()
|
|
{
|
|
updateWindowRules();
|
|
client_rules = WindowRules();
|
|
}
|
|
|
|
void Client::checkAndSetInitialRuledOpacity()
|
|
//apply twin-rules for window-translucency upon hitting apply or starting to manage client
|
|
{
|
|
int tmp;
|
|
|
|
//active translucency
|
|
tmp = -1;
|
|
tmp = rules()->checkOpacityActive(tmp);
|
|
if( tmp != -1 ) //rule did apply and returns valid value
|
|
{
|
|
rule_opacity_active = (uint)((tmp/100.0)*0xffffffff);
|
|
}
|
|
else
|
|
rule_opacity_active = 0;
|
|
|
|
//inactive translucency
|
|
tmp = -1;
|
|
tmp = rules()->checkOpacityInactive(tmp);
|
|
if( tmp != -1 ) //rule did apply and returns valid value
|
|
{
|
|
rule_opacity_inactive = (uint)((tmp/100.0)*0xffffffff);
|
|
}
|
|
else
|
|
rule_opacity_inactive = 0;
|
|
|
|
return;
|
|
|
|
if( isDock() )
|
|
//workaround for docks, as they don't have active/inactive settings and don't aut, therefore we take only the active one...
|
|
{
|
|
uint tmp = rule_opacity_active ? rule_opacity_active : options->dockOpacity;
|
|
setOpacity(tmp < 0xFFFFFFFF && (rule_opacity_active || options->translucentDocks), tmp);
|
|
}
|
|
else
|
|
updateOpacity();
|
|
}
|
|
|
|
// Workspace
|
|
|
|
WindowRules Workspace::findWindowRules( const Client* c, bool ignore_temporary )
|
|
{
|
|
TQValueVector< Rules* > ret;
|
|
for( TQValueList< Rules* >::Iterator it = rules.begin();
|
|
it != rules.end();
|
|
)
|
|
{
|
|
if( ignore_temporary && (*it)->isTemporary())
|
|
{
|
|
++it;
|
|
continue;
|
|
}
|
|
if( (*it)->match( c ))
|
|
{
|
|
Rules* rule = *it;
|
|
kdDebug( 1212 ) << "Rule found:" << rule << ":" << c << endl;
|
|
if( rule->isTemporary())
|
|
it = rules.remove( it );
|
|
else
|
|
++it;
|
|
ret.append( rule );
|
|
continue;
|
|
}
|
|
++it;
|
|
}
|
|
return WindowRules( ret );
|
|
}
|
|
|
|
void Workspace::editWindowRules( Client* c, bool whole_app )
|
|
{
|
|
writeWindowRules();
|
|
TQStringList args;
|
|
args << "--wid" << TQString::number( c->window());
|
|
if( whole_app )
|
|
args << "--whole-app";
|
|
TDEApplication::tdeinitExec( "twin_rules_dialog", args );
|
|
}
|
|
|
|
void Workspace::loadWindowRules()
|
|
{
|
|
while( !rules.isEmpty())
|
|
{
|
|
delete rules.front();
|
|
rules.pop_front();
|
|
}
|
|
TDEConfig cfg( "twinrulesrc", true );
|
|
cfg.setGroup( "General" );
|
|
int count = cfg.readNumEntry( "count" );
|
|
for( int i = 1;
|
|
i <= count;
|
|
++i )
|
|
{
|
|
cfg.setGroup( TQString::number( i ));
|
|
Rules* rule = new Rules( cfg );
|
|
rules.append( rule );
|
|
}
|
|
}
|
|
|
|
void Workspace::writeWindowRules()
|
|
{
|
|
rulesUpdatedTimer.stop();
|
|
TDEConfig cfg( "twinrulesrc" );
|
|
TQStringList groups = cfg.groupList();
|
|
for( TQStringList::ConstIterator it = groups.begin();
|
|
it != groups.end();
|
|
++it )
|
|
cfg.deleteGroup( *it );
|
|
cfg.setGroup( "General" );
|
|
cfg.writeEntry( "count", rules.count());
|
|
int i = 1;
|
|
for( TQValueList< Rules* >::ConstIterator it = rules.begin();
|
|
it != rules.end();
|
|
++it )
|
|
{
|
|
if( (*it)->isTemporary())
|
|
continue;
|
|
cfg.setGroup( TQString::number( i ));
|
|
(*it)->write( cfg );
|
|
++i;
|
|
}
|
|
}
|
|
|
|
void Workspace::gotTemporaryRulesMessage( const TQString& message )
|
|
{
|
|
bool was_temporary = false;
|
|
for( TQValueList< Rules* >::ConstIterator it = rules.begin();
|
|
it != rules.end();
|
|
++it )
|
|
if( (*it)->isTemporary())
|
|
was_temporary = true;
|
|
Rules* rule = new Rules( message, true );
|
|
rules.prepend( rule ); // highest priority first
|
|
if( !was_temporary )
|
|
TQTimer::singleShot( 60000, this, TQT_SLOT( cleanupTemporaryRules()));
|
|
}
|
|
|
|
void Workspace::cleanupTemporaryRules()
|
|
{
|
|
bool has_temporary = false;
|
|
for( TQValueList< Rules* >::Iterator it = rules.begin();
|
|
it != rules.end();
|
|
)
|
|
{
|
|
if( (*it)->discardTemporary( false ))
|
|
it = rules.remove( it );
|
|
else
|
|
{
|
|
if( (*it)->isTemporary())
|
|
has_temporary = true;
|
|
++it;
|
|
}
|
|
}
|
|
if( has_temporary )
|
|
TQTimer::singleShot( 60000, this, TQT_SLOT( cleanupTemporaryRules()));
|
|
}
|
|
|
|
void Workspace::discardUsedWindowRules( Client* c, bool withdrawn )
|
|
{
|
|
bool updated = false;
|
|
for( TQValueList< Rules* >::Iterator it = rules.begin();
|
|
it != rules.end();
|
|
)
|
|
{
|
|
if( c->rules()->contains( *it ))
|
|
{
|
|
updated = true;
|
|
(*it)->discardUsed( withdrawn );
|
|
if( (*it)->isEmpty())
|
|
{
|
|
c->removeRule( *it );
|
|
Rules* r = *it;
|
|
it = rules.remove( it );
|
|
delete r;
|
|
continue;
|
|
}
|
|
}
|
|
++it;
|
|
}
|
|
if( updated )
|
|
rulesUpdated();
|
|
}
|
|
|
|
void Workspace::rulesUpdated()
|
|
{
|
|
rulesUpdatedTimer.start( 1000, true );
|
|
}
|
|
|
|
void Workspace::disableRulesUpdates( bool disable )
|
|
{
|
|
rules_updates_disabled = disable;
|
|
if( !disable )
|
|
for( ClientList::ConstIterator it = clients.begin();
|
|
it != clients.end();
|
|
++it )
|
|
(*it)->updateWindowRules();
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace
|