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