00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "rules.h"
00012
00013 #include <fixx11h.h>
00014 #include <kconfig.h>
00015 #include <qregexp.h>
00016 #include <ktempfile.h>
00017 #include <ksimpleconfig.h>
00018 #include <qfile.h>
00019
00020 #ifndef KCMRULES
00021 #include "client.h"
00022 #include "workspace.h"
00023 #endif
00024
00025 namespace KWinInternal
00026 {
00027
00028 Rules::Rules()
00029 : temporary_state( 0 )
00030 , wmclassmatch( UnimportantMatch )
00031 , wmclasscomplete( UnimportantMatch )
00032 , windowrolematch( UnimportantMatch )
00033 , titlematch( UnimportantMatch )
00034 , extrarolematch( UnimportantMatch )
00035 , clientmachinematch( UnimportantMatch )
00036 , types( NET::AllTypesMask )
00037 , placementrule( UnusedForceRule )
00038 , positionrule( UnusedSetRule )
00039 , sizerule( UnusedSetRule )
00040 , minsizerule( UnusedForceRule )
00041 , maxsizerule( UnusedForceRule )
00042 , ignorepositionrule( UnusedForceRule )
00043 , desktoprule( UnusedSetRule )
00044 , typerule( UnusedForceRule )
00045 , maximizevertrule( UnusedSetRule )
00046 , maximizehorizrule( UnusedSetRule )
00047 , minimizerule( UnusedSetRule )
00048 , shaderule( UnusedSetRule )
00049 , skiptaskbarrule( UnusedSetRule )
00050 , skippagerrule( UnusedSetRule )
00051 , aboverule( UnusedSetRule )
00052 , belowrule( UnusedSetRule )
00053 , fullscreenrule( UnusedSetRule )
00054 , noborderrule( UnusedSetRule )
00055 , fsplevelrule( UnusedForceRule )
00056 , acceptfocusrule( UnusedForceRule )
00057 , moveresizemoderule( UnusedForceRule )
00058 , closeablerule( UnusedForceRule )
00059 {
00060 }
00061
00062 Rules::Rules( const QString& str, bool temporary )
00063 : temporary_state( temporary ? 2 : 0 )
00064 {
00065 KTempFile file;
00066 QFile* f = file.file();
00067 if( f != NULL )
00068 {
00069 QCString s = str.utf8();
00070 f->writeBlock( s.data(), s.length());
00071 }
00072 file.close();
00073 KSimpleConfig cfg( file.name());
00074 readFromCfg( cfg );
00075 if( description.isEmpty())
00076 description = "temporary";
00077 file.unlink();
00078 }
00079
00080 #define READ_MATCH_STRING( var, func ) \
00081 var = cfg.readEntry( #var ) func; \
00082 var##match = (StringMatch) QMAX( FirstStringMatch, QMIN( LastStringMatch, cfg.readNumEntry( #var "match" )));
00083
00084 #define READ_SET_RULE( var, type, func ) \
00085 var = func ( cfg.read##type##Entry( #var )); \
00086 var##rule = readSetRule( cfg, #var "rule" );
00087
00088 #define READ_SET_RULE_DEF( var, type, func, def ) \
00089 var = func ( cfg.read##type##Entry( #var, def )); \
00090 var##rule = readSetRule( cfg, #var "rule" );
00091
00092 #define READ_SET_RULE_2( var, type, func, funcarg ) \
00093 var = func ( cfg.read##type##Entry( #var ), funcarg ); \
00094 var##rule = readSetRule( cfg, #var "rule" );
00095
00096 #define READ_FORCE_RULE( var, type, func ) \
00097 var = func ( cfg.read##type##Entry( #var )); \
00098 var##rule = readForceRule( cfg, #var "rule" );
00099
00100 #define READ_FORCE_RULE_2( var, type, func, funcarg ) \
00101 var = func ( cfg.read##type##Entry( #var ), funcarg ); \
00102 var##rule = readForceRule( cfg, #var "rule" );
00103
00104
00105 Rules::Rules( KConfig& cfg )
00106 : temporary_state( 0 )
00107 {
00108 readFromCfg( cfg );
00109 }
00110
00111 static int limit0to4( int i ) { return QMAX( 0, QMIN( 4, i )); }
00112
00113 void Rules::readFromCfg( KConfig& cfg )
00114 {
00115 description = cfg.readEntry( "description" );
00116 READ_MATCH_STRING( wmclass, .lower().latin1() );
00117 wmclasscomplete = cfg.readBoolEntry( "wmclasscomplete" );
00118 READ_MATCH_STRING( windowrole, .lower().latin1() );
00119 READ_MATCH_STRING( title, );
00120 READ_MATCH_STRING( extrarole, .lower().latin1() );
00121 READ_MATCH_STRING( clientmachine, .lower().latin1() );
00122 types = cfg.readUnsignedLongNumEntry( "types", NET::AllTypesMask );
00123 READ_FORCE_RULE_2( placement,, Placement::policyFromString, false );
00124 READ_SET_RULE_DEF( position, Point,, &invalidPoint );
00125 READ_SET_RULE( size, Size, );
00126 if( size.isEmpty() && sizerule != ( SetRule )Remember)
00127 sizerule = UnusedSetRule;
00128 READ_FORCE_RULE( minsize, Size, );
00129 if( !minsize.isValid())
00130 minsize = QSize( 1, 1 );
00131 READ_FORCE_RULE( maxsize, Size, );
00132 if( maxsize.isEmpty())
00133 maxsize = QSize( 32767, 32767 );
00134 READ_FORCE_RULE( ignoreposition, Bool, );
00135 READ_SET_RULE( desktop, Num, );
00136 type = readType( cfg, "type" );
00137 typerule = type != NET::Unknown ? readForceRule( cfg, "typerule" ) : UnusedForceRule;
00138 READ_SET_RULE( maximizevert, Bool, );
00139 READ_SET_RULE( maximizehoriz, Bool, );
00140 READ_SET_RULE( minimize, Bool, );
00141 READ_SET_RULE( shade, Bool, );
00142 READ_SET_RULE( skiptaskbar, Bool, );
00143 READ_SET_RULE( skippager, Bool, );
00144 READ_SET_RULE( above, Bool, );
00145 READ_SET_RULE( below, Bool, );
00146 READ_SET_RULE( fullscreen, Bool, );
00147 READ_SET_RULE( noborder, Bool, );
00148 READ_FORCE_RULE( fsplevel, Num, limit0to4 );
00149 READ_FORCE_RULE( acceptfocus, Bool, );
00150 READ_FORCE_RULE( moveresizemode, , Options::stringToMoveResizeMode );
00151 READ_FORCE_RULE( closeable, Bool, );
00152 }
00153
00154 #undef READ_MATCH_STRING
00155 #undef READ_SET_RULE
00156 #undef READ_SET_RULE_2
00157 #undef READ_FORCE_RULE
00158 #undef READ_FORCE_RULE_2
00159
00160 #define WRITE_MATCH_STRING( var, cast, force ) \
00161 if( !var.isEmpty() || force ) \
00162 { \
00163 cfg.writeEntry( #var, cast var ); \
00164 cfg.writeEntry( #var "match", var##match ); \
00165 } \
00166 else \
00167 { \
00168 cfg.deleteEntry( #var ); \
00169 cfg.deleteEntry( #var "match" ); \
00170 }
00171
00172 #define WRITE_SET_RULE( var, func ) \
00173 if( var##rule != UnusedSetRule ) \
00174 { \
00175 cfg.writeEntry( #var, func ( var )); \
00176 cfg.writeEntry( #var "rule", var##rule ); \
00177 } \
00178 else \
00179 { \
00180 cfg.deleteEntry( #var ); \
00181 cfg.deleteEntry( #var "rule" ); \
00182 }
00183
00184 #define WRITE_FORCE_RULE( var, func ) \
00185 if( var##rule != UnusedForceRule ) \
00186 { \
00187 cfg.writeEntry( #var, func ( var )); \
00188 cfg.writeEntry( #var "rule", var##rule ); \
00189 } \
00190 else \
00191 { \
00192 cfg.deleteEntry( #var ); \
00193 cfg.deleteEntry( #var "rule" ); \
00194 }
00195
00196 #define WRITE_WITH_DEFAULT( var, default ) \
00197 if( var != default ) \
00198 cfg.writeEntry( #var, var ); \
00199 else \
00200 cfg.deleteEntry( #var );
00201
00202
00203 void Rules::write( KConfig& cfg ) const
00204 {
00205 cfg.writeEntry( "description", description );
00206
00207 WRITE_MATCH_STRING( wmclass, (const char*), true );
00208 cfg.writeEntry( "wmclasscomplete", wmclasscomplete );
00209 WRITE_MATCH_STRING( windowrole, (const char*), false );
00210 WRITE_MATCH_STRING( title,, false );
00211 WRITE_MATCH_STRING( extrarole, (const char*), false );
00212 WRITE_MATCH_STRING( clientmachine, (const char*), false );
00213 WRITE_WITH_DEFAULT( types, NET::AllTypesMask );
00214 WRITE_FORCE_RULE( placement, Placement::policyToString );
00215 WRITE_SET_RULE( position, );
00216 WRITE_SET_RULE( size, );
00217 WRITE_FORCE_RULE( minsize, );
00218 WRITE_FORCE_RULE( maxsize, );
00219 WRITE_FORCE_RULE( ignoreposition, );
00220 WRITE_SET_RULE( desktop, );
00221 WRITE_FORCE_RULE( type, );
00222 WRITE_SET_RULE( maximizevert, );
00223 WRITE_SET_RULE( maximizehoriz, );
00224 WRITE_SET_RULE( minimize, );
00225 WRITE_SET_RULE( shade, );
00226 WRITE_SET_RULE( skiptaskbar, );
00227 WRITE_SET_RULE( skippager, );
00228 WRITE_SET_RULE( above, );
00229 WRITE_SET_RULE( below, );
00230 WRITE_SET_RULE( fullscreen, );
00231 WRITE_SET_RULE( noborder, );
00232 WRITE_FORCE_RULE( fsplevel, );
00233 WRITE_FORCE_RULE( acceptfocus, );
00234 WRITE_FORCE_RULE( moveresizemode, Options::moveResizeModeToString );
00235 WRITE_FORCE_RULE( closeable, );
00236 }
00237
00238 #undef WRITE_MATCH_STRING
00239 #undef WRITE_SET_RULE
00240 #undef WRITE_FORCE_RULE
00241 #undef WRITE_WITH_DEFAULT
00242
00243
00244 bool Rules::isEmpty() const
00245 {
00246 return( placementrule == UnusedForceRule
00247 && positionrule == UnusedSetRule
00248 && sizerule == UnusedSetRule
00249 && minsizerule == UnusedForceRule
00250 && maxsizerule == UnusedForceRule
00251 && ignorepositionrule == UnusedForceRule
00252 && desktoprule == UnusedSetRule
00253 && typerule == UnusedForceRule
00254 && maximizevertrule == UnusedSetRule
00255 && maximizehorizrule == UnusedSetRule
00256 && minimizerule == UnusedSetRule
00257 && shaderule == UnusedSetRule
00258 && skiptaskbarrule == UnusedSetRule
00259 && skippagerrule == UnusedSetRule
00260 && aboverule == UnusedSetRule
00261 && belowrule == UnusedSetRule
00262 && fullscreenrule == UnusedSetRule
00263 && noborderrule == UnusedSetRule
00264 && fsplevelrule == UnusedForceRule
00265 && acceptfocusrule == UnusedForceRule
00266 && moveresizemoderule == UnusedForceRule
00267 && closeablerule == UnusedForceRule );
00268 }
00269
00270 Rules::SetRule Rules::readSetRule( KConfig& cfg, const QString& key )
00271 {
00272 int v = cfg.readNumEntry( key );
00273 if( v >= DontAffect && v <= Remember )
00274 return static_cast< SetRule >( v );
00275 return UnusedSetRule;
00276 }
00277
00278 Rules::ForceRule Rules::readForceRule( KConfig& cfg, const QString& key )
00279 {
00280 int v = cfg.readNumEntry( key );
00281 if( v == DontAffect || v == Force )
00282 return static_cast< ForceRule >( v );
00283 return UnusedForceRule;
00284 }
00285
00286 NET::WindowType Rules::readType( KConfig& cfg, const QString& key )
00287 {
00288 int v = cfg.readNumEntry( key );
00289 if( v >= NET::Normal && v <= NET::Splash )
00290 return static_cast< NET::WindowType >( v );
00291 return NET::Unknown;
00292 }
00293
00294 bool Rules::matchType( NET::WindowType match_type ) const
00295 {
00296 if( types != NET::AllTypesMask )
00297 {
00298 if( match_type == NET::Unknown )
00299 match_type = NET::Normal;
00300 if( !NET::typeMatchesMask( match_type, types ))
00301 return false;
00302 }
00303 return true;
00304 }
00305
00306 bool Rules::matchWMClass( const QCString& match_class, const QCString& match_name ) const
00307 {
00308 if( wmclassmatch != UnimportantMatch )
00309 {
00310 QCString cwmclass = wmclasscomplete
00311 ? match_name + ' ' + match_class : match_class;
00312 if( wmclassmatch == RegExpMatch && QRegExp( wmclass ).search( cwmclass ) == -1 )
00313 return false;
00314 if( wmclassmatch == ExactMatch && wmclass != cwmclass )
00315 return false;
00316 if( wmclassmatch == SubstringMatch && !cwmclass.contains( wmclass ))
00317 return false;
00318 }
00319 return true;
00320 }
00321
00322 bool Rules::matchRole( const QCString& match_role ) const
00323 {
00324 if( windowrolematch != UnimportantMatch )
00325 {
00326 if( windowrolematch == RegExpMatch && QRegExp( windowrole ).search( match_role ) == -1 )
00327 return false;
00328 if( windowrolematch == ExactMatch && windowrole != match_role )
00329 return false;
00330 if( windowrolematch == SubstringMatch && !match_role.contains( windowrole ))
00331 return false;
00332 }
00333 return true;
00334 }
00335
00336 bool Rules::matchTitle( const QString& match_title ) const
00337 {
00338 if( titlematch != UnimportantMatch )
00339 {
00340 if( titlematch == RegExpMatch && QRegExp( title ).search( match_title ) == -1 )
00341 return false;
00342 if( titlematch == ExactMatch && title != match_title )
00343 return false;
00344 if( titlematch == SubstringMatch && !match_title.contains( title ))
00345 return false;
00346 }
00347 return true;
00348 }
00349
00350 bool Rules::matchClientMachine( const QCString& match_machine ) const
00351 {
00352 if( clientmachinematch != UnimportantMatch )
00353 {
00354
00355 if( match_machine != "localhost" && isLocalMachine( match_machine )
00356 && matchClientMachine( "localhost" ))
00357 return true;
00358 if( clientmachinematch == RegExpMatch
00359 && QRegExp( clientmachine ).search( match_machine ) == -1 )
00360 return false;
00361 if( clientmachinematch == ExactMatch
00362 && clientmachine != match_machine )
00363 return false;
00364 if( clientmachinematch == SubstringMatch
00365 && !match_machine.contains( clientmachine ))
00366 return false;
00367 }
00368 return true;
00369 }
00370
00371 #ifndef KCMRULES
00372 bool Rules::match( const Client* c ) const
00373 {
00374 if( !matchType( c->windowType( true )))
00375 return false;
00376 if( !matchWMClass( c->resourceClass(), c->resourceName()))
00377 return false;
00378 if( !matchRole( c->windowRole()))
00379 return false;
00380 if( !matchTitle( c->caption( false )))
00381 return false;
00382
00383 if( !matchClientMachine( c->wmClientMachine( false )))
00384 return false;
00385 return true;
00386 }
00387
00388 bool Rules::update( Client* c )
00389 {
00390
00391 bool updated = false;
00392 if( positionrule == ( SetRule )Remember)
00393 {
00394 if( !c->isFullScreen())
00395 {
00396 QPoint new_pos = position;
00397
00398 if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
00399 new_pos.setX( c->pos().x());
00400 if(( c->maximizeMode() & MaximizeVertical ) == 0 )
00401 new_pos.setY( c->pos().y());
00402 updated = updated || position != new_pos;
00403 position = new_pos;
00404 }
00405 }
00406 if( sizerule == ( SetRule )Remember)
00407 {
00408 if( !c->isFullScreen())
00409 {
00410 QSize new_size = size;
00411
00412 if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
00413 new_size.setWidth( c->size().width());
00414 if(( c->maximizeMode() & MaximizeVertical ) == 0 )
00415 new_size.setHeight( c->size().height());
00416 updated = updated || size != new_size;
00417 size = new_size;
00418 }
00419 }
00420 if( desktoprule == ( SetRule )Remember)
00421 {
00422 updated = updated || desktop != c->desktop();
00423 desktop = c->desktop();
00424 }
00425 if( maximizevertrule == ( SetRule )Remember)
00426 {
00427 updated = updated || maximizevert != bool( c->maximizeMode() & MaximizeVertical );
00428 maximizevert = c->maximizeMode() & MaximizeVertical;
00429 }
00430 if( maximizehorizrule == ( SetRule )Remember)
00431 {
00432 updated = updated || maximizehoriz != bool( c->maximizeMode() & MaximizeHorizontal );
00433 maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
00434 }
00435 if( minimizerule == ( SetRule )Remember)
00436 {
00437 updated = updated || minimize != c->isMinimized();
00438 minimize = c->isMinimized();
00439 }
00440 if( shaderule == ( SetRule )Remember)
00441 {
00442 updated = updated || ( shade != ( c->shadeMode() != ShadeNone ));
00443 shade = c->shadeMode() != ShadeNone;
00444 }
00445 if( skiptaskbarrule == ( SetRule )Remember)
00446 {
00447 updated = updated || skiptaskbar != c->skipTaskbar();
00448 skiptaskbar = c->skipTaskbar();
00449 }
00450 if( skippagerrule == ( SetRule )Remember)
00451 {
00452 updated = updated || skippager != c->skipPager();
00453 skippager = c->skipPager();
00454 }
00455 if( aboverule == ( SetRule )Remember)
00456 {
00457 updated = updated || above != c->keepAbove();
00458 above = c->keepAbove();
00459 }
00460 if( belowrule == ( SetRule )Remember)
00461 {
00462 updated = updated || below != c->keepBelow();
00463 below = c->keepBelow();
00464 }
00465 if( fullscreenrule == ( SetRule )Remember)
00466 {
00467 updated = updated || fullscreen != c->isFullScreen();
00468 fullscreen = c->isFullScreen();
00469 }
00470 if( noborderrule == ( SetRule )Remember)
00471 {
00472 updated = updated || noborder != c->isUserNoBorder();
00473 noborder = c->isUserNoBorder();
00474 }
00475 return updated;
00476 }
00477
00478 #define APPLY_RULE( var, name, type ) \
00479 bool Rules::apply##name( type& arg, bool init ) const \
00480 { \
00481 if( checkSetRule( var##rule, init )) \
00482 arg = this->var; \
00483 return checkSetStop( var##rule ); \
00484 }
00485
00486 #define APPLY_FORCE_RULE( var, name, type ) \
00487 bool Rules::apply##name( type& arg ) const \
00488 { \
00489 if( checkForceRule( var##rule )) \
00490 arg = this->var; \
00491 return checkForceStop( var##rule ); \
00492 }
00493
00494 APPLY_FORCE_RULE( placement, Placement, Placement::Policy )
00495
00496 bool Rules::applyGeometry( QRect& rect, bool init ) const
00497 {
00498 QPoint p = rect.topLeft();
00499 QSize s = rect.size();
00500 bool ret = false;
00501 if( applyPosition( p, init ))
00502 {
00503 rect.moveTopLeft( p );
00504 ret = true;
00505 }
00506 if( applySize( s, init ))
00507 {
00508 rect.setSize( s );
00509 ret = true;
00510 }
00511 return ret;
00512 }
00513
00514 bool Rules::applyPosition( QPoint& pos, bool init ) const
00515 {
00516 if( this->position != invalidPoint && checkSetRule( positionrule, init ))
00517 pos = this->position;
00518 return checkSetStop( positionrule );
00519 }
00520
00521 bool Rules::applySize( QSize& s, bool init ) const
00522 {
00523 if( this->size.isValid() && checkSetRule( sizerule, init ))
00524 s = this->size;
00525 return checkSetStop( sizerule );
00526 }
00527
00528 APPLY_FORCE_RULE( minsize, MinSize, QSize )
00529 APPLY_FORCE_RULE( maxsize, MaxSize, QSize )
00530 APPLY_FORCE_RULE( ignoreposition, IgnorePosition, bool )
00531 APPLY_RULE( desktop, Desktop, int )
00532 APPLY_FORCE_RULE( type, Type, NET::WindowType )
00533
00534 bool Rules::applyMaximizeHoriz( MaximizeMode& mode, bool init ) const
00535 {
00536 if( checkSetRule( maximizehorizrule, init ))
00537 mode = static_cast< MaximizeMode >(( maximizehoriz ? MaximizeHorizontal : 0 ) | ( mode & MaximizeVertical ));
00538 return checkSetStop( maximizehorizrule );
00539 }
00540
00541 bool Rules::applyMaximizeVert( MaximizeMode& mode, bool init ) const
00542 {
00543 if( checkSetRule( maximizevertrule, init ))
00544 mode = static_cast< MaximizeMode >(( maximizevert ? MaximizeVertical : 0 ) | ( mode & MaximizeHorizontal ));
00545 return checkSetStop( maximizevertrule );
00546 }
00547
00548 APPLY_RULE( minimize, Minimize, bool )
00549
00550 bool Rules::applyShade( ShadeMode& sh, bool init ) const
00551 {
00552 if( checkSetRule( shaderule, init ))
00553 {
00554 if( !this->shade )
00555 sh = ShadeNone;
00556 if( this->shade && sh == ShadeNone )
00557 sh = ShadeNormal;
00558 }
00559 return checkSetStop( shaderule );
00560 }
00561
00562 APPLY_RULE( skiptaskbar, SkipTaskbar, bool )
00563 APPLY_RULE( skippager, SkipPager, bool )
00564 APPLY_RULE( above, KeepAbove, bool )
00565 APPLY_RULE( below, KeepBelow, bool )
00566 APPLY_RULE( fullscreen, FullScreen, bool )
00567 APPLY_RULE( noborder, NoBorder, bool )
00568 APPLY_FORCE_RULE( fsplevel, FSP, int )
00569 APPLY_FORCE_RULE( acceptfocus, AcceptFocus, bool )
00570 APPLY_FORCE_RULE( moveresizemode, MoveResizeMode, Options::MoveResizeMode )
00571 APPLY_FORCE_RULE( closeable, Closeable, bool )
00572
00573 #undef APPLY_RULE
00574 #undef APPLY_FORCE_RULE
00575
00576 bool Rules::isTemporary() const
00577 {
00578 return temporary_state > 0;
00579 }
00580
00581 bool Rules::discardTemporary( bool force )
00582 {
00583 if( temporary_state == 0 )
00584 return false;
00585 if( force || --temporary_state == 0 )
00586 {
00587 delete this;
00588 return true;
00589 }
00590 return false;
00591 }
00592 #endif
00593
00594 #ifndef NDEBUG
00595 kdbgstream& operator<<( kdbgstream& stream, const Rules* r )
00596 {
00597 return stream << "[" << r->description << "]";
00598 }
00599 #endif
00600
00601 #ifndef KCMRULES
00602 void WindowRules::discardTemporary()
00603 {
00604 QValueVector< Rules* >::Iterator it2 = rules.begin();
00605 for( QValueVector< Rules* >::Iterator it = rules.begin();
00606 it != rules.end();
00607 )
00608 {
00609 if( (*it)->discardTemporary( false ))
00610 ++it;
00611 else
00612 {
00613 *it2++ = *it++;
00614 }
00615 }
00616 rules.erase( it2, rules.end());
00617 }
00618
00619 void WindowRules::update( Client* c )
00620 {
00621 bool updated = false;
00622 for( QValueVector< Rules* >::ConstIterator it = rules.begin();
00623 it != rules.end();
00624 ++it )
00625 if( (*it)->update( c ))
00626 updated = true;
00627 if( updated )
00628 Workspace::self()->rulesUpdated();
00629 }
00630
00631 #define CHECK_RULE( rule, type ) \
00632 type WindowRules::check##rule( type arg, bool init ) const \
00633 { \
00634 if( rules.count() == 0 ) \
00635 return arg; \
00636 type ret = arg; \
00637 for( QValueVector< Rules* >::ConstIterator it = rules.begin(); \
00638 it != rules.end(); \
00639 ++it ) \
00640 { \
00641 if( (*it)->apply##rule( ret, init )) \
00642 break; \
00643 } \
00644 return ret; \
00645 }
00646
00647 #define CHECK_FORCE_RULE( rule, type ) \
00648 type WindowRules::check##rule( type arg ) const \
00649 { \
00650 if( rules.count() == 0 ) \
00651 return arg; \
00652 type ret = arg; \
00653 for( QValueVector< Rules* >::ConstIterator it = rules.begin(); \
00654 it != rules.end(); \
00655 ++it ) \
00656 { \
00657 if( (*it)->apply##rule( ret )) \
00658 break; \
00659 } \
00660 return ret; \
00661 }
00662
00663 CHECK_FORCE_RULE( Placement, Placement::Policy )
00664
00665 QRect WindowRules::checkGeometry( QRect rect, bool init ) const
00666 {
00667 return QRect( checkPosition( rect.topLeft(), init ), checkSize( rect.size(), init ));
00668 }
00669
00670 CHECK_RULE( Position, QPoint )
00671 CHECK_RULE( Size, QSize )
00672 CHECK_FORCE_RULE( MinSize, QSize )
00673 CHECK_FORCE_RULE( MaxSize, QSize )
00674 CHECK_FORCE_RULE( IgnorePosition, bool )
00675 CHECK_RULE( Desktop, int )
00676 CHECK_FORCE_RULE( Type, NET::WindowType )
00677 CHECK_RULE( MaximizeVert, KDecorationDefines::MaximizeMode )
00678 CHECK_RULE( MaximizeHoriz, KDecorationDefines::MaximizeMode )
00679
00680 KDecorationDefines::MaximizeMode WindowRules::checkMaximize( MaximizeMode mode, bool init ) const
00681 {
00682 bool vert = checkMaximizeVert( mode, init ) & MaximizeVertical;
00683 bool horiz = checkMaximizeHoriz( mode, init ) & MaximizeHorizontal;
00684 return static_cast< MaximizeMode >(( vert ? MaximizeVertical : 0 ) | ( horiz ? MaximizeHorizontal : 0 ));
00685 }
00686
00687 CHECK_RULE( Minimize, bool )
00688 CHECK_RULE( Shade, ShadeMode )
00689 CHECK_RULE( SkipTaskbar, bool )
00690 CHECK_RULE( SkipPager, bool )
00691 CHECK_RULE( KeepAbove, bool )
00692 CHECK_RULE( KeepBelow, bool )
00693 CHECK_RULE( FullScreen, bool )
00694 CHECK_RULE( NoBorder, bool )
00695 CHECK_FORCE_RULE( FSP, int )
00696 CHECK_FORCE_RULE( AcceptFocus, bool )
00697 CHECK_FORCE_RULE( MoveResizeMode, Options::MoveResizeMode )
00698 CHECK_FORCE_RULE( Closeable, bool )
00699
00700 #undef CHECK_RULE
00701 #undef CHECK_FORCE_RULE
00702
00703
00704
00705 #define FORCE_RULE( rule, type, getf, setf ) \
00706 { \
00707 type val = client_rules.check##rule( getf()); \
00708 if( val != getf()) \
00709 setf( val ); \
00710 }
00711
00712 void Client::setupWindowRules( bool ignore_temporary )
00713 {
00714 client_rules = workspace()->findWindowRules( this, ignore_temporary );
00715
00716 if( isTopMenu())
00717 client_rules = WindowRules();
00718 if( isManaged())
00719 {
00720
00721
00722 QRect geom = client_rules.checkGeometry( geometry());
00723 if( geom != geometry())
00724 setGeometry( geom );
00725
00726
00727 setDesktop( desktop());
00728
00729 maximize( maximizeMode());
00730
00731 if( client_rules.checkMinimize( isMinimized()))
00732 minimize();
00733 else
00734 unminimize();
00735 setShade( shadeMode());
00736 setSkipTaskbar( skipTaskbar(), true );
00737 setSkipPager( skipPager());
00738 setKeepAbove( keepAbove());
00739 setKeepBelow( keepBelow());
00740 setFullScreen( isFullScreen(), true );
00741 setUserNoBorder( isUserNoBorder());
00742
00743
00744 if( workspace()->mostRecentlyActivatedClient() == this
00745 && !client_rules.checkAcceptFocus( true ))
00746 workspace()->activateNextClient( this );
00747
00748
00749 }
00750 }
00751
00752 #undef FORCE_RULE
00753
00754 void Client::updateWindowRules()
00755 {
00756 if( !isManaged())
00757 return;
00758 client_rules.update( this );
00759 }
00760
00761 void Client::finishWindowRules()
00762 {
00763 updateWindowRules();
00764 client_rules = WindowRules();
00765 }
00766
00767
00768
00769 WindowRules Workspace::findWindowRules( const Client* c, bool ignore_temporary )
00770 {
00771 QValueVector< Rules* > ret;
00772 for( QValueList< Rules* >::Iterator it = rules.begin();
00773 it != rules.end();
00774 )
00775 {
00776 if( ignore_temporary && (*it)->isTemporary())
00777 {
00778 ++it;
00779 continue;
00780 }
00781 if( (*it)->match( c ))
00782 {
00783 Rules* rule = *it;
00784 kdDebug( 1212 ) << "Rule found:" << rule << ":" << c << endl;
00785 if( rule->isTemporary())
00786 it = rules.remove( it );
00787 else
00788 ++it;
00789 ret.append( rule );
00790 continue;
00791 }
00792 ++it;
00793 }
00794 return WindowRules( ret );
00795 }
00796
00797 void Workspace::editWindowRules( Client* c )
00798 {
00799 KApplication::kdeinitExec( "kwin_rules_dialog", QStringList() << "--wid" << QString::number( c->window()));
00800 }
00801
00802 void Workspace::loadWindowRules()
00803 {
00804 while( !rules.isEmpty())
00805 {
00806 delete rules.front();
00807 rules.pop_front();
00808 }
00809 KConfig cfg( "kwinrulesrc", true );
00810 cfg.setGroup( "General" );
00811 int count = cfg.readNumEntry( "count" );
00812 for( int i = 1;
00813 i <= count;
00814 ++i )
00815 {
00816 cfg.setGroup( QString::number( i ));
00817 Rules* rule = new Rules( cfg );
00818 rules.append( rule );
00819 }
00820 }
00821
00822 void Workspace::writeWindowRules()
00823 {
00824 KConfig cfg( "kwinrulesrc" );
00825 cfg.setGroup( "General" );
00826 cfg.writeEntry( "count", rules.count());
00827 int i = 1;
00828 for( QValueList< Rules* >::ConstIterator it = rules.begin();
00829 it != rules.end();
00830 ++it )
00831 {
00832 if( (*it)->isTemporary())
00833 continue;
00834 cfg.setGroup( QString::number( i ));
00835 (*it)->write( cfg );
00836 ++i;
00837 }
00838 }
00839
00840 void Workspace::gotTemporaryRulesMessage( const QString& message )
00841 {
00842 bool was_temporary = false;
00843 for( QValueList< Rules* >::ConstIterator it = rules.begin();
00844 it != rules.end();
00845 ++it )
00846 if( (*it)->isTemporary())
00847 was_temporary = true;
00848 Rules* rule = new Rules( message, true );
00849 rules.prepend( rule );
00850 if( !was_temporary )
00851 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
00852 }
00853
00854 void Workspace::cleanupTemporaryRules()
00855 {
00856 bool has_temporary = false;
00857 for( QValueList< Rules* >::Iterator it = rules.begin();
00858 it != rules.end();
00859 )
00860 {
00861 if( (*it)->discardTemporary( false ))
00862 it = rules.remove( it );
00863 else
00864 {
00865 if( (*it)->isTemporary())
00866 has_temporary = true;
00867 ++it;
00868 }
00869 }
00870 if( has_temporary )
00871 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
00872 }
00873
00874 void Workspace::rulesUpdated()
00875 {
00876 rulesUpdatedTimer.start( 1000, true );
00877 }
00878
00879 #endif
00880
00881 }