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