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 , opacityactiverule( UnusedForceRule )
00043 , opacityinactiverule( UnusedForceRule )
00044 , ignorepositionrule( UnusedForceRule )
00045 , desktoprule( UnusedSetRule )
00046 , typerule( UnusedForceRule )
00047 , maximizevertrule( UnusedSetRule )
00048 , maximizehorizrule( UnusedSetRule )
00049 , minimizerule( UnusedSetRule )
00050 , shaderule( UnusedSetRule )
00051 , skiptaskbarrule( UnusedSetRule )
00052 , skippagerrule( UnusedSetRule )
00053 , aboverule( UnusedSetRule )
00054 , belowrule( UnusedSetRule )
00055 , fullscreenrule( UnusedSetRule )
00056 , noborderrule( UnusedSetRule )
00057 , fsplevelrule( UnusedForceRule )
00058 , acceptfocusrule( UnusedForceRule )
00059 , moveresizemoderule( UnusedForceRule )
00060 , closeablerule( UnusedForceRule )
00061 , strictgeometryrule( UnusedForceRule )
00062 , shortcutrule( UnusedSetRule )
00063 , disableglobalshortcutsrule( UnusedForceRule )
00064 {
00065 }
00066
00067 Rules::Rules( const QString& str, bool temporary )
00068 : temporary_state( temporary ? 2 : 0 )
00069 {
00070 KTempFile file;
00071 QFile* f = file.file();
00072 if( f != NULL )
00073 {
00074 QCString s = str.utf8();
00075 f->writeBlock( s.data(), s.length());
00076 }
00077 file.close();
00078 KSimpleConfig cfg( file.name());
00079 readFromCfg( cfg );
00080 if( description.isEmpty())
00081 description = "temporary";
00082 file.unlink();
00083 }
00084
00085 #define READ_MATCH_STRING( var, func ) \
00086 var = cfg.readEntry( #var ) func; \
00087 var##match = (StringMatch) QMAX( FirstStringMatch, QMIN( LastStringMatch, cfg.readNumEntry( #var "match" )));
00088
00089 #define READ_SET_RULE( var, type, func ) \
00090 var = func ( cfg.read##type##Entry( #var )); \
00091 var##rule = readSetRule( cfg, #var "rule" );
00092
00093 #define READ_SET_RULE_DEF( var, type, func, def ) \
00094 var = func ( cfg.read##type##Entry( #var, def )); \
00095 var##rule = readSetRule( cfg, #var "rule" );
00096
00097 #define READ_SET_RULE_2( var, type, func, funcarg ) \
00098 var = func ( cfg.read##type##Entry( #var ), funcarg ); \
00099 var##rule = readSetRule( cfg, #var "rule" );
00100
00101 #define READ_FORCE_RULE( var, type, func ) \
00102 var = func ( cfg.read##type##Entry( #var )); \
00103 var##rule = readForceRule( cfg, #var "rule" );
00104
00105 #define READ_FORCE_RULE_2( var, type, func, funcarg ) \
00106 var = func ( cfg.read##type##Entry( #var ), funcarg ); \
00107 var##rule = readForceRule( cfg, #var "rule" );
00108
00109
00110 Rules::Rules( KConfig& cfg )
00111 : temporary_state( 0 )
00112 {
00113 readFromCfg( cfg );
00114 }
00115
00116 static int limit0to4( int i ) { return QMAX( 0, QMIN( 4, i )); }
00117
00118 void Rules::readFromCfg( KConfig& cfg )
00119 {
00120 description = cfg.readEntry( "description" );
00121 READ_MATCH_STRING( wmclass, .lower().latin1() );
00122 wmclasscomplete = cfg.readBoolEntry( "wmclasscomplete" );
00123 READ_MATCH_STRING( windowrole, .lower().latin1() );
00124 READ_MATCH_STRING( title, );
00125 READ_MATCH_STRING( extrarole, .lower().latin1() );
00126 READ_MATCH_STRING( clientmachine, .lower().latin1() );
00127 types = cfg.readUnsignedLongNumEntry( "types", NET::AllTypesMask );
00128 READ_FORCE_RULE_2( placement,, Placement::policyFromString, false );
00129 READ_SET_RULE_DEF( position, Point,, &invalidPoint );
00130 READ_SET_RULE( size, Size, );
00131 if( size.isEmpty() && sizerule != ( SetRule )Remember)
00132 sizerule = UnusedSetRule;
00133 READ_FORCE_RULE( minsize, Size, );
00134 if( !minsize.isValid())
00135 minsize = QSize( 1, 1 );
00136 READ_FORCE_RULE( maxsize, Size, );
00137 if( maxsize.isEmpty())
00138 maxsize = QSize( 32767, 32767 );
00139 READ_FORCE_RULE( opacityactive, Num, );
00140 if( opacityactive < 0 || opacityactive > 100 )
00141 opacityactive = 100;
00142 READ_FORCE_RULE( opacityinactive, Num, );
00143 if( opacityinactive < 0 || opacityinactive > 100 )
00144 opacityinactive = 100;
00145 READ_FORCE_RULE( ignoreposition, Bool, );
00146 READ_SET_RULE( desktop, Num, );
00147 type = readType( cfg, "type" );
00148 typerule = type != NET::Unknown ? readForceRule( cfg, "typerule" ) : UnusedForceRule;
00149 READ_SET_RULE( maximizevert, Bool, );
00150 READ_SET_RULE( maximizehoriz, Bool, );
00151 READ_SET_RULE( minimize, Bool, );
00152 READ_SET_RULE( shade, Bool, );
00153 READ_SET_RULE( skiptaskbar, Bool, );
00154 READ_SET_RULE( skippager, Bool, );
00155 READ_SET_RULE( above, Bool, );
00156 READ_SET_RULE( below, Bool, );
00157 READ_SET_RULE( fullscreen, Bool, );
00158 READ_SET_RULE( noborder, Bool, );
00159 READ_FORCE_RULE( fsplevel, Num, limit0to4 );
00160 READ_FORCE_RULE( acceptfocus, Bool, );
00161 READ_FORCE_RULE( moveresizemode, , Options::stringToMoveResizeMode );
00162 READ_FORCE_RULE( closeable, Bool, );
00163 READ_FORCE_RULE( strictgeometry, Bool, );
00164 READ_SET_RULE( shortcut, , );
00165 READ_FORCE_RULE( disableglobalshortcuts, Bool, );
00166 }
00167
00168 #undef READ_MATCH_STRING
00169 #undef READ_SET_RULE
00170 #undef READ_SET_RULE_2
00171 #undef READ_FORCE_RULE
00172 #undef READ_FORCE_RULE_2
00173
00174 #define WRITE_MATCH_STRING( var, cast, force ) \
00175 if( !var.isEmpty() || force ) \
00176 { \
00177 cfg.writeEntry( #var, cast var ); \
00178 cfg.writeEntry( #var "match", var##match ); \
00179 } \
00180 else \
00181 { \
00182 cfg.deleteEntry( #var ); \
00183 cfg.deleteEntry( #var "match" ); \
00184 }
00185
00186 #define WRITE_SET_RULE( var, func ) \
00187 if( var##rule != UnusedSetRule ) \
00188 { \
00189 cfg.writeEntry( #var, func ( var )); \
00190 cfg.writeEntry( #var "rule", var##rule ); \
00191 } \
00192 else \
00193 { \
00194 cfg.deleteEntry( #var ); \
00195 cfg.deleteEntry( #var "rule" ); \
00196 }
00197
00198 #define WRITE_FORCE_RULE( var, func ) \
00199 if( var##rule != UnusedForceRule ) \
00200 { \
00201 cfg.writeEntry( #var, func ( var )); \
00202 cfg.writeEntry( #var "rule", var##rule ); \
00203 } \
00204 else \
00205 { \
00206 cfg.deleteEntry( #var ); \
00207 cfg.deleteEntry( #var "rule" ); \
00208 }
00209
00210 #define WRITE_WITH_DEFAULT( var, default ) \
00211 if( var != default ) \
00212 cfg.writeEntry( #var, var ); \
00213 else \
00214 cfg.deleteEntry( #var );
00215
00216
00217 void Rules::write( KConfig& cfg ) const
00218 {
00219 cfg.writeEntry( "description", description );
00220
00221 WRITE_MATCH_STRING( wmclass, (const char*), true );
00222 cfg.writeEntry( "wmclasscomplete", wmclasscomplete );
00223 WRITE_MATCH_STRING( windowrole, (const char*), false );
00224 WRITE_MATCH_STRING( title,, false );
00225 WRITE_MATCH_STRING( extrarole, (const char*), false );
00226 WRITE_MATCH_STRING( clientmachine, (const char*), false );
00227 WRITE_WITH_DEFAULT( types, NET::AllTypesMask );
00228 WRITE_FORCE_RULE( placement, Placement::policyToString );
00229 WRITE_SET_RULE( position, );
00230 WRITE_SET_RULE( size, );
00231 WRITE_FORCE_RULE( minsize, );
00232 WRITE_FORCE_RULE( maxsize, );
00233 WRITE_FORCE_RULE( opacityactive, );
00234 WRITE_FORCE_RULE( opacityinactive, );
00235 WRITE_FORCE_RULE( ignoreposition, );
00236 WRITE_SET_RULE( desktop, );
00237 WRITE_FORCE_RULE( type, );
00238 WRITE_SET_RULE( maximizevert, );
00239 WRITE_SET_RULE( maximizehoriz, );
00240 WRITE_SET_RULE( minimize, );
00241 WRITE_SET_RULE( shade, );
00242 WRITE_SET_RULE( skiptaskbar, );
00243 WRITE_SET_RULE( skippager, );
00244 WRITE_SET_RULE( above, );
00245 WRITE_SET_RULE( below, );
00246 WRITE_SET_RULE( fullscreen, );
00247 WRITE_SET_RULE( noborder, );
00248 WRITE_FORCE_RULE( fsplevel, );
00249 WRITE_FORCE_RULE( acceptfocus, );
00250 WRITE_FORCE_RULE( moveresizemode, Options::moveResizeModeToString );
00251 WRITE_FORCE_RULE( closeable, );
00252 WRITE_FORCE_RULE( strictgeometry, );
00253 WRITE_SET_RULE( shortcut, );
00254 WRITE_FORCE_RULE( disableglobalshortcuts, );
00255 }
00256
00257 #undef WRITE_MATCH_STRING
00258 #undef WRITE_SET_RULE
00259 #undef WRITE_FORCE_RULE
00260 #undef WRITE_WITH_DEFAULT
00261
00262
00263 bool Rules::isEmpty() const
00264 {
00265 return( placementrule == UnusedForceRule
00266 && positionrule == UnusedSetRule
00267 && sizerule == UnusedSetRule
00268 && minsizerule == UnusedForceRule
00269 && maxsizerule == UnusedForceRule
00270 && opacityactiverule == UnusedForceRule
00271 && opacityinactiverule == UnusedForceRule
00272 && ignorepositionrule == UnusedForceRule
00273 && desktoprule == UnusedSetRule
00274 && typerule == UnusedForceRule
00275 && maximizevertrule == UnusedSetRule
00276 && maximizehorizrule == UnusedSetRule
00277 && minimizerule == UnusedSetRule
00278 && shaderule == UnusedSetRule
00279 && skiptaskbarrule == UnusedSetRule
00280 && skippagerrule == UnusedSetRule
00281 && aboverule == UnusedSetRule
00282 && belowrule == UnusedSetRule
00283 && fullscreenrule == UnusedSetRule
00284 && noborderrule == UnusedSetRule
00285 && fsplevelrule == UnusedForceRule
00286 && acceptfocusrule == UnusedForceRule
00287 && moveresizemoderule == UnusedForceRule
00288 && closeablerule == UnusedForceRule
00289 && strictgeometryrule == UnusedForceRule
00290 && shortcutrule == UnusedSetRule
00291 && disableglobalshortcutsrule == UnusedForceRule );
00292 }
00293
00294 Rules::SetRule Rules::readSetRule( KConfig& cfg, const QString& key )
00295 {
00296 int v = cfg.readNumEntry( key );
00297 if( v >= DontAffect && v <= ForceTemporarily )
00298 return static_cast< SetRule >( v );
00299 return UnusedSetRule;
00300 }
00301
00302 Rules::ForceRule Rules::readForceRule( KConfig& cfg, const QString& key )
00303 {
00304 int v = cfg.readNumEntry( key );
00305 if( v == DontAffect || v == Force || v == ForceTemporarily )
00306 return static_cast< ForceRule >( v );
00307 return UnusedForceRule;
00308 }
00309
00310 NET::WindowType Rules::readType( KConfig& cfg, const QString& key )
00311 {
00312 int v = cfg.readNumEntry( key );
00313 if( v >= NET::Normal && v <= NET::Splash )
00314 return static_cast< NET::WindowType >( v );
00315 return NET::Unknown;
00316 }
00317
00318 bool Rules::matchType( NET::WindowType match_type ) const
00319 {
00320 if( types != NET::AllTypesMask )
00321 {
00322 if( match_type == NET::Unknown )
00323 match_type = NET::Normal;
00324 if( !NET::typeMatchesMask( match_type, types ))
00325 return false;
00326 }
00327 return true;
00328 }
00329
00330 bool Rules::matchWMClass( const QCString& match_class, const QCString& match_name ) const
00331 {
00332 if( wmclassmatch != UnimportantMatch )
00333 {
00334 QCString cwmclass = wmclasscomplete
00335 ? match_name + ' ' + match_class : match_class;
00336 if( wmclassmatch == RegExpMatch && QRegExp( wmclass ).search( cwmclass ) == -1 )
00337 return false;
00338 if( wmclassmatch == ExactMatch && wmclass != cwmclass )
00339 return false;
00340 if( wmclassmatch == SubstringMatch && !cwmclass.contains( wmclass ))
00341 return false;
00342 }
00343 return true;
00344 }
00345
00346 bool Rules::matchRole( const QCString& match_role ) const
00347 {
00348 if( windowrolematch != UnimportantMatch )
00349 {
00350 if( windowrolematch == RegExpMatch && QRegExp( windowrole ).search( match_role ) == -1 )
00351 return false;
00352 if( windowrolematch == ExactMatch && windowrole != match_role )
00353 return false;
00354 if( windowrolematch == SubstringMatch && !match_role.contains( windowrole ))
00355 return false;
00356 }
00357 return true;
00358 }
00359
00360 bool Rules::matchTitle( const QString& match_title ) const
00361 {
00362 if( titlematch != UnimportantMatch )
00363 {
00364 if( titlematch == RegExpMatch && QRegExp( title ).search( match_title ) == -1 )
00365 return false;
00366 if( titlematch == ExactMatch && title != match_title )
00367 return false;
00368 if( titlematch == SubstringMatch && !match_title.contains( title ))
00369 return false;
00370 }
00371 return true;
00372 }
00373
00374 bool Rules::matchClientMachine( const QCString& match_machine ) const
00375 {
00376 if( clientmachinematch != UnimportantMatch )
00377 {
00378
00379 if( match_machine != "localhost" && isLocalMachine( match_machine )
00380 && matchClientMachine( "localhost" ))
00381 return true;
00382 if( clientmachinematch == RegExpMatch
00383 && QRegExp( clientmachine ).search( match_machine ) == -1 )
00384 return false;
00385 if( clientmachinematch == ExactMatch
00386 && clientmachine != match_machine )
00387 return false;
00388 if( clientmachinematch == SubstringMatch
00389 && !match_machine.contains( clientmachine ))
00390 return false;
00391 }
00392 return true;
00393 }
00394
00395 #ifndef KCMRULES
00396 bool Rules::match( const Client* c ) const
00397 {
00398 if( !matchType( c->windowType( true )))
00399 return false;
00400 if( !matchWMClass( c->resourceClass(), c->resourceName()))
00401 return false;
00402 if( !matchRole( c->windowRole()))
00403 return false;
00404 if( !matchTitle( c->caption( false )))
00405 return false;
00406
00407 if( !matchClientMachine( c->wmClientMachine( false )))
00408 return false;
00409 return true;
00410 }
00411
00412 bool Rules::update( Client* c )
00413 {
00414
00415 bool updated = false;
00416 if( positionrule == ( SetRule )Remember)
00417 {
00418 if( !c->isFullScreen())
00419 {
00420 QPoint new_pos = position;
00421
00422 if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
00423 new_pos.setX( c->pos().x());
00424 if(( c->maximizeMode() & MaximizeVertical ) == 0 )
00425 new_pos.setY( c->pos().y());
00426 updated = updated || position != new_pos;
00427 position = new_pos;
00428 }
00429 }
00430 if( sizerule == ( SetRule )Remember)
00431 {
00432 if( !c->isFullScreen())
00433 {
00434 QSize new_size = size;
00435
00436 if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
00437 new_size.setWidth( c->size().width());
00438 if(( c->maximizeMode() & MaximizeVertical ) == 0 )
00439 new_size.setHeight( c->size().height());
00440 updated = updated || size != new_size;
00441 size = new_size;
00442 }
00443 }
00444 if( desktoprule == ( SetRule )Remember)
00445 {
00446 updated = updated || desktop != c->desktop();
00447 desktop = c->desktop();
00448 }
00449 if( maximizevertrule == ( SetRule )Remember)
00450 {
00451 updated = updated || maximizevert != bool( c->maximizeMode() & MaximizeVertical );
00452 maximizevert = c->maximizeMode() & MaximizeVertical;
00453 }
00454 if( maximizehorizrule == ( SetRule )Remember)
00455 {
00456 updated = updated || maximizehoriz != bool( c->maximizeMode() & MaximizeHorizontal );
00457 maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
00458 }
00459 if( minimizerule == ( SetRule )Remember)
00460 {
00461 updated = updated || minimize != c->isMinimized();
00462 minimize = c->isMinimized();
00463 }
00464 if( shaderule == ( SetRule )Remember)
00465 {
00466 updated = updated || ( shade != ( c->shadeMode() != ShadeNone ));
00467 shade = c->shadeMode() != ShadeNone;
00468 }
00469 if( skiptaskbarrule == ( SetRule )Remember)
00470 {
00471 updated = updated || skiptaskbar != c->skipTaskbar();
00472 skiptaskbar = c->skipTaskbar();
00473 }
00474 if( skippagerrule == ( SetRule )Remember)
00475 {
00476 updated = updated || skippager != c->skipPager();
00477 skippager = c->skipPager();
00478 }
00479 if( aboverule == ( SetRule )Remember)
00480 {
00481 updated = updated || above != c->keepAbove();
00482 above = c->keepAbove();
00483 }
00484 if( belowrule == ( SetRule )Remember)
00485 {
00486 updated = updated || below != c->keepBelow();
00487 below = c->keepBelow();
00488 }
00489 if( fullscreenrule == ( SetRule )Remember)
00490 {
00491 updated = updated || fullscreen != c->isFullScreen();
00492 fullscreen = c->isFullScreen();
00493 }
00494 if( noborderrule == ( SetRule )Remember)
00495 {
00496 updated = updated || noborder != c->isUserNoBorder();
00497 noborder = c->isUserNoBorder();
00498 }
00499 if (opacityactiverule == ( ForceRule )Force)
00500 {
00501 updated = updated || (uint) (opacityactive/100.0*0xffffffff) != c->ruleOpacityActive();
00502 opacityactive = (uint)(((double)c->ruleOpacityActive())/0xffffffff*100);
00503 }
00504 if (opacityinactiverule == ( ForceRule )Force)
00505 {
00506 updated = updated || (uint) (opacityinactive/100.0*0xffffffff) != c->ruleOpacityInactive();
00507 opacityinactive = (uint)(((double)c->ruleOpacityInactive())/0xffffffff*100);
00508 }
00509 return updated;
00510 }
00511
00512 #define APPLY_RULE( var, name, type ) \
00513 bool Rules::apply##name( type& arg, bool init ) const \
00514 { \
00515 if( checkSetRule( var##rule, init )) \
00516 arg = this->var; \
00517 return checkSetStop( var##rule ); \
00518 }
00519
00520 #define APPLY_FORCE_RULE( var, name, type ) \
00521 bool Rules::apply##name( type& arg ) const \
00522 { \
00523 if( checkForceRule( var##rule )) \
00524 arg = this->var; \
00525 return checkForceStop( var##rule ); \
00526 }
00527
00528 APPLY_FORCE_RULE( placement, Placement, Placement::Policy )
00529
00530 bool Rules::applyGeometry( QRect& rect, bool init ) const
00531 {
00532 QPoint p = rect.topLeft();
00533 QSize s = rect.size();
00534 bool ret = false;
00535 if( applyPosition( p, init ))
00536 {
00537 rect.moveTopLeft( p );
00538 ret = true;
00539 }
00540 if( applySize( s, init ))
00541 {
00542 rect.setSize( s );
00543 ret = true;
00544 }
00545 return ret;
00546 }
00547
00548 bool Rules::applyPosition( QPoint& pos, bool init ) const
00549 {
00550 if( this->position != invalidPoint && checkSetRule( positionrule, init ))
00551 pos = this->position;
00552 return checkSetStop( positionrule );
00553 }
00554
00555 bool Rules::applySize( QSize& s, bool init ) const
00556 {
00557 if( this->size.isValid() && checkSetRule( sizerule, init ))
00558 s = this->size;
00559 return checkSetStop( sizerule );
00560 }
00561
00562 APPLY_FORCE_RULE( minsize, MinSize, QSize )
00563 APPLY_FORCE_RULE( maxsize, MaxSize, QSize )
00564 APPLY_FORCE_RULE( opacityactive, OpacityActive, int )
00565 APPLY_FORCE_RULE( opacityinactive, OpacityInactive, int )
00566 APPLY_FORCE_RULE( ignoreposition, IgnorePosition, bool )
00567
00568
00569 bool Rules::applyIgnoreGeometry( bool& ignore ) const
00570 {
00571 return applyIgnorePosition( ignore );
00572 }
00573
00574 APPLY_RULE( desktop, Desktop, int )
00575 APPLY_FORCE_RULE( type, Type, NET::WindowType )
00576
00577 bool Rules::applyMaximizeHoriz( MaximizeMode& mode, bool init ) const
00578 {
00579 if( checkSetRule( maximizehorizrule, init ))
00580 mode = static_cast< MaximizeMode >(( maximizehoriz ? MaximizeHorizontal : 0 ) | ( mode & MaximizeVertical ));
00581 return checkSetStop( maximizehorizrule );
00582 }
00583
00584 bool Rules::applyMaximizeVert( MaximizeMode& mode, bool init ) const
00585 {
00586 if( checkSetRule( maximizevertrule, init ))
00587 mode = static_cast< MaximizeMode >(( maximizevert ? MaximizeVertical : 0 ) | ( mode & MaximizeHorizontal ));
00588 return checkSetStop( maximizevertrule );
00589 }
00590
00591 APPLY_RULE( minimize, Minimize, bool )
00592
00593 bool Rules::applyShade( ShadeMode& sh, bool init ) const
00594 {
00595 if( checkSetRule( shaderule, init ))
00596 {
00597 if( !this->shade )
00598 sh = ShadeNone;
00599 if( this->shade && sh == ShadeNone )
00600 sh = ShadeNormal;
00601 }
00602 return checkSetStop( shaderule );
00603 }
00604
00605 APPLY_RULE( skiptaskbar, SkipTaskbar, bool )
00606 APPLY_RULE( skippager, SkipPager, bool )
00607 APPLY_RULE( above, KeepAbove, bool )
00608 APPLY_RULE( below, KeepBelow, bool )
00609 APPLY_RULE( fullscreen, FullScreen, bool )
00610 APPLY_RULE( noborder, NoBorder, bool )
00611 APPLY_FORCE_RULE( fsplevel, FSP, int )
00612 APPLY_FORCE_RULE( acceptfocus, AcceptFocus, bool )
00613 APPLY_FORCE_RULE( moveresizemode, MoveResizeMode, Options::MoveResizeMode )
00614 APPLY_FORCE_RULE( closeable, Closeable, bool )
00615 APPLY_FORCE_RULE( strictgeometry, StrictGeometry, bool )
00616 APPLY_RULE( shortcut, Shortcut, QString )
00617 APPLY_FORCE_RULE( disableglobalshortcuts, DisableGlobalShortcuts, bool )
00618
00619
00620 #undef APPLY_RULE
00621 #undef APPLY_FORCE_RULE
00622
00623 bool Rules::isTemporary() const
00624 {
00625 return temporary_state > 0;
00626 }
00627
00628 bool Rules::discardTemporary( bool force )
00629 {
00630 if( temporary_state == 0 )
00631 return false;
00632 if( force || --temporary_state == 0 )
00633 {
00634 delete this;
00635 return true;
00636 }
00637 return false;
00638 }
00639
00640 #define DISCARD_USED_SET_RULE( var ) \
00641 do { \
00642 if( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) \
00643 var##rule = UnusedSetRule; \
00644 } while( false )
00645 #define DISCARD_USED_FORCE_RULE( var ) \
00646 do { \
00647 if( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) \
00648 var##rule = UnusedForceRule; \
00649 } while( false )
00650
00651 void Rules::discardUsed( bool withdrawn )
00652 {
00653 DISCARD_USED_FORCE_RULE( placement );
00654 DISCARD_USED_SET_RULE( position );
00655 DISCARD_USED_SET_RULE( size );
00656 DISCARD_USED_FORCE_RULE( minsize );
00657 DISCARD_USED_FORCE_RULE( maxsize );
00658 DISCARD_USED_FORCE_RULE( opacityactive );
00659 DISCARD_USED_FORCE_RULE( opacityinactive );
00660 DISCARD_USED_FORCE_RULE( ignoreposition );
00661 DISCARD_USED_SET_RULE( desktop );
00662 DISCARD_USED_FORCE_RULE( type );
00663 DISCARD_USED_SET_RULE( maximizevert );
00664 DISCARD_USED_SET_RULE( maximizehoriz );
00665 DISCARD_USED_SET_RULE( minimize );
00666 DISCARD_USED_SET_RULE( shade );
00667 DISCARD_USED_SET_RULE( skiptaskbar );
00668 DISCARD_USED_SET_RULE( skippager );
00669 DISCARD_USED_SET_RULE( above );
00670 DISCARD_USED_SET_RULE( below );
00671 DISCARD_USED_SET_RULE( fullscreen );
00672 DISCARD_USED_SET_RULE( noborder );
00673 DISCARD_USED_FORCE_RULE( fsplevel );
00674 DISCARD_USED_FORCE_RULE( acceptfocus );
00675 DISCARD_USED_FORCE_RULE( moveresizemode );
00676 DISCARD_USED_FORCE_RULE( closeable );
00677 DISCARD_USED_FORCE_RULE( strictgeometry );
00678 DISCARD_USED_SET_RULE( shortcut );
00679 DISCARD_USED_FORCE_RULE( disableglobalshortcuts );
00680 }
00681 #undef DISCARD_USED_SET_RULE
00682 #undef DISCARD_USED_FORCE_RULE
00683
00684 #endif
00685
00686 #ifndef NDEBUG
00687 kdbgstream& operator<<( kdbgstream& stream, const Rules* r )
00688 {
00689 return stream << "[" << r->description << ":" << r->wmclass << "]" ;
00690 }
00691 #endif
00692
00693 #ifndef KCMRULES
00694 void WindowRules::discardTemporary()
00695 {
00696 QValueVector< Rules* >::Iterator it2 = rules.begin();
00697 for( QValueVector< Rules* >::Iterator it = rules.begin();
00698 it != rules.end();
00699 )
00700 {
00701 if( (*it)->discardTemporary( true ))
00702 ++it;
00703 else
00704 {
00705 *it2++ = *it++;
00706 }
00707 }
00708 rules.erase( it2, rules.end());
00709 }
00710
00711 void WindowRules::update( Client* c )
00712 {
00713 bool updated = false;
00714 for( QValueVector< Rules* >::ConstIterator it = rules.begin();
00715 it != rules.end();
00716 ++it )
00717 if( (*it)->update( c ))
00718 updated = true;
00719 if( updated )
00720 Workspace::self()->rulesUpdated();
00721 }
00722
00723 #define CHECK_RULE( rule, type ) \
00724 type WindowRules::check##rule( type arg, bool init ) const \
00725 { \
00726 if( rules.count() == 0 ) \
00727 return arg; \
00728 type ret = arg; \
00729 for( QValueVector< Rules* >::ConstIterator it = rules.begin(); \
00730 it != rules.end(); \
00731 ++it ) \
00732 { \
00733 if( (*it)->apply##rule( ret, init )) \
00734 break; \
00735 } \
00736 return ret; \
00737 }
00738
00739 #define CHECK_FORCE_RULE( rule, type ) \
00740 type WindowRules::check##rule( type arg ) const \
00741 { \
00742 if( rules.count() == 0 ) \
00743 return arg; \
00744 type ret = arg; \
00745 for( QValueVector< Rules* >::ConstIterator it = rules.begin(); \
00746 it != rules.end(); \
00747 ++it ) \
00748 { \
00749 if( (*it)->apply##rule( ret )) \
00750 break; \
00751 } \
00752 return ret; \
00753 }
00754
00755 CHECK_FORCE_RULE( Placement, Placement::Policy )
00756
00757 QRect WindowRules::checkGeometry( QRect rect, bool init ) const
00758 {
00759 return QRect( checkPosition( rect.topLeft(), init ), checkSize( rect.size(), init ));
00760 }
00761
00762 CHECK_RULE( Position, QPoint )
00763 CHECK_RULE( Size, QSize )
00764 CHECK_FORCE_RULE( MinSize, QSize )
00765 CHECK_FORCE_RULE( MaxSize, QSize )
00766 CHECK_FORCE_RULE( OpacityActive, int )
00767 CHECK_FORCE_RULE( OpacityInactive, int )
00768 CHECK_FORCE_RULE( IgnorePosition, bool )
00769
00770 bool WindowRules::checkIgnoreGeometry( bool ignore ) const
00771 {
00772 return checkIgnorePosition( ignore );
00773 }
00774
00775 CHECK_RULE( Desktop, int )
00776 CHECK_FORCE_RULE( Type, NET::WindowType )
00777 CHECK_RULE( MaximizeVert, KDecorationDefines::MaximizeMode )
00778 CHECK_RULE( MaximizeHoriz, KDecorationDefines::MaximizeMode )
00779
00780 KDecorationDefines::MaximizeMode WindowRules::checkMaximize( MaximizeMode mode, bool init ) const
00781 {
00782 bool vert = checkMaximizeVert( mode, init ) & MaximizeVertical;
00783 bool horiz = checkMaximizeHoriz( mode, init ) & MaximizeHorizontal;
00784 return static_cast< MaximizeMode >(( vert ? MaximizeVertical : 0 ) | ( horiz ? MaximizeHorizontal : 0 ));
00785 }
00786
00787 CHECK_RULE( Minimize, bool )
00788 CHECK_RULE( Shade, ShadeMode )
00789 CHECK_RULE( SkipTaskbar, bool )
00790 CHECK_RULE( SkipPager, bool )
00791 CHECK_RULE( KeepAbove, bool )
00792 CHECK_RULE( KeepBelow, bool )
00793 CHECK_RULE( FullScreen, bool )
00794 CHECK_RULE( NoBorder, bool )
00795 CHECK_FORCE_RULE( FSP, int )
00796 CHECK_FORCE_RULE( AcceptFocus, bool )
00797 CHECK_FORCE_RULE( MoveResizeMode, Options::MoveResizeMode )
00798 CHECK_FORCE_RULE( Closeable, bool )
00799 CHECK_FORCE_RULE( StrictGeometry, bool )
00800 CHECK_RULE( Shortcut, QString )
00801 CHECK_FORCE_RULE( DisableGlobalShortcuts, bool )
00802
00803 #undef CHECK_RULE
00804 #undef CHECK_FORCE_RULE
00805
00806
00807
00808 void Client::setupWindowRules( bool ignore_temporary )
00809 {
00810 client_rules = workspace()->findWindowRules( this, ignore_temporary );
00811
00812 if( isTopMenu())
00813 client_rules = WindowRules();
00814 }
00815
00816
00817
00818 void Client::applyWindowRules()
00819 {
00820 checkAndSetInitialRuledOpacity();
00821
00822
00823
00824 QRect orig_geom = QRect( pos(), sizeForClientSize( clientSize()));
00825 QRect geom = client_rules.checkGeometry( orig_geom );
00826 if( geom != orig_geom )
00827 setGeometry( geom );
00828
00829
00830 setDesktop( desktop());
00831
00832 maximize( maximizeMode());
00833
00834 if( client_rules.checkMinimize( isMinimized()))
00835 minimize();
00836 else
00837 unminimize();
00838 setShade( shadeMode());
00839 setSkipTaskbar( skipTaskbar(), true );
00840 setSkipPager( skipPager());
00841 setKeepAbove( keepAbove());
00842 setKeepBelow( keepBelow());
00843 setFullScreen( isFullScreen(), true );
00844 setUserNoBorder( isUserNoBorder());
00845
00846
00847 if( workspace()->mostRecentlyActivatedClient() == this
00848 && !client_rules.checkAcceptFocus( true ))
00849 workspace()->activateNextClient( this );
00850
00851
00852 QSize s = adjustedSize();
00853 if( s != size())
00854 resizeWithChecks( s );
00855
00856 setShortcut( rules()->checkShortcut( shortcut().toString()));
00857
00858 if( isActive())
00859 workspace()->disableGlobalShortcutsForClient( rules()->checkDisableGlobalShortcuts( false ));
00860 }
00861
00862 void Client::updateWindowRules()
00863 {
00864 if( !isManaged())
00865 return;
00866 client_rules.update( this );
00867 }
00868
00869 void Client::finishWindowRules()
00870 {
00871 updateWindowRules();
00872 client_rules = WindowRules();
00873 }
00874
00875 void Client::checkAndSetInitialRuledOpacity()
00876
00877 {
00878 int tmp;
00879
00880
00881 tmp = -1;
00882 tmp = rules()->checkOpacityActive(tmp);
00883 if( tmp != -1 )
00884 {
00885 rule_opacity_active = (uint)((tmp/100.0)*0xffffffff);
00886 }
00887 else
00888 rule_opacity_active = 0;
00889
00890
00891 tmp = -1;
00892 tmp = rules()->checkOpacityInactive(tmp);
00893 if( tmp != -1 )
00894 {
00895 rule_opacity_inactive = (uint)((tmp/100.0)*0xffffffff);
00896 }
00897 else
00898 rule_opacity_inactive = 0;
00899
00900 return;
00901
00902 if( isDock() )
00903
00904 {
00905 uint tmp = rule_opacity_active ? rule_opacity_active : options->dockOpacity;
00906 setOpacity(tmp < 0xFFFFFFFF && (rule_opacity_active || options->translucentDocks), tmp);
00907 }
00908 else
00909 updateOpacity();
00910 }
00911
00912
00913
00914 WindowRules Workspace::findWindowRules( const Client* c, bool ignore_temporary )
00915 {
00916 QValueVector< Rules* > ret;
00917 for( QValueList< Rules* >::Iterator it = rules.begin();
00918 it != rules.end();
00919 )
00920 {
00921 if( ignore_temporary && (*it)->isTemporary())
00922 {
00923 ++it;
00924 continue;
00925 }
00926 if( (*it)->match( c ))
00927 {
00928 Rules* rule = *it;
00929 kdDebug( 1212 ) << "Rule found:" << rule << ":" << c << endl;
00930 if( rule->isTemporary())
00931 it = rules.remove( it );
00932 else
00933 ++it;
00934 ret.append( rule );
00935 continue;
00936 }
00937 ++it;
00938 }
00939 return WindowRules( ret );
00940 }
00941
00942 void Workspace::editWindowRules( Client* c, bool whole_app )
00943 {
00944 writeWindowRules();
00945 QStringList args;
00946 args << "--wid" << QString::number( c->window());
00947 if( whole_app )
00948 args << "--whole-app";
00949 KApplication::kdeinitExec( "kwin_rules_dialog", args );
00950 }
00951
00952 void Workspace::loadWindowRules()
00953 {
00954 while( !rules.isEmpty())
00955 {
00956 delete rules.front();
00957 rules.pop_front();
00958 }
00959 KConfig cfg( "kwinrulesrc", true );
00960 cfg.setGroup( "General" );
00961 int count = cfg.readNumEntry( "count" );
00962 for( int i = 1;
00963 i <= count;
00964 ++i )
00965 {
00966 cfg.setGroup( QString::number( i ));
00967 Rules* rule = new Rules( cfg );
00968 rules.append( rule );
00969 }
00970 }
00971
00972 void Workspace::writeWindowRules()
00973 {
00974 rulesUpdatedTimer.stop();
00975 KConfig cfg( "kwinrulesrc" );
00976 QStringList groups = cfg.groupList();
00977 for( QStringList::ConstIterator it = groups.begin();
00978 it != groups.end();
00979 ++it )
00980 cfg.deleteGroup( *it );
00981 cfg.setGroup( "General" );
00982 cfg.writeEntry( "count", rules.count());
00983 int i = 1;
00984 for( QValueList< Rules* >::ConstIterator it = rules.begin();
00985 it != rules.end();
00986 ++it )
00987 {
00988 if( (*it)->isTemporary())
00989 continue;
00990 cfg.setGroup( QString::number( i ));
00991 (*it)->write( cfg );
00992 ++i;
00993 }
00994 }
00995
00996 void Workspace::gotTemporaryRulesMessage( const QString& message )
00997 {
00998 bool was_temporary = false;
00999 for( QValueList< Rules* >::ConstIterator it = rules.begin();
01000 it != rules.end();
01001 ++it )
01002 if( (*it)->isTemporary())
01003 was_temporary = true;
01004 Rules* rule = new Rules( message, true );
01005 rules.prepend( rule );
01006 if( !was_temporary )
01007 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
01008 }
01009
01010 void Workspace::cleanupTemporaryRules()
01011 {
01012 bool has_temporary = false;
01013 for( QValueList< Rules* >::Iterator it = rules.begin();
01014 it != rules.end();
01015 )
01016 {
01017 if( (*it)->discardTemporary( false ))
01018 it = rules.remove( it );
01019 else
01020 {
01021 if( (*it)->isTemporary())
01022 has_temporary = true;
01023 ++it;
01024 }
01025 }
01026 if( has_temporary )
01027 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
01028 }
01029
01030 void Workspace::discardUsedWindowRules( Client* c, bool withdrawn )
01031 {
01032 bool updated = false;
01033 for( QValueList< Rules* >::Iterator it = rules.begin();
01034 it != rules.end();
01035 )
01036 {
01037 if( c->rules()->contains( *it ))
01038 {
01039 updated = true;
01040 (*it)->discardUsed( withdrawn );
01041 if( (*it)->isEmpty())
01042 {
01043 c->removeRule( *it );
01044 Rules* r = *it;
01045 it = rules.remove( it );
01046 delete r;
01047 continue;
01048 }
01049 }
01050 ++it;
01051 }
01052 if( updated )
01053 rulesUpdated();
01054 }
01055
01056 void Workspace::rulesUpdated()
01057 {
01058 rulesUpdatedTimer.start( 1000, true );
01059 }
01060
01061 #endif
01062
01063 }