00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "rules.h"
00022
00023 #include <fixx11h.h>
00024 #include <kconfig.h>
00025 #include <QRegExp>
00026 #include <ktemporaryfile.h>
00027 #include <QFile>
00028 #include <ktoolinvocation.h>
00029
00030 #ifndef KCMRULES
00031 #include "client.h"
00032 #include "workspace.h"
00033 #endif
00034
00035 namespace KWin
00036 {
00037
00038 Rules::Rules()
00039 : temporary_state( 0 )
00040 , wmclassmatch( UnimportantMatch )
00041 , wmclasscomplete( UnimportantMatch )
00042 , windowrolematch( UnimportantMatch )
00043 , titlematch( UnimportantMatch )
00044 , extrarolematch( UnimportantMatch )
00045 , clientmachinematch( UnimportantMatch )
00046 , types( NET::AllTypesMask )
00047 , placementrule( UnusedForceRule )
00048 , positionrule( UnusedSetRule )
00049 , sizerule( UnusedSetRule )
00050 , minsizerule( UnusedForceRule )
00051 , maxsizerule( UnusedForceRule )
00052 , opacityactiverule( UnusedForceRule )
00053 , opacityinactiverule( UnusedForceRule )
00054 , ignorepositionrule( UnusedForceRule )
00055 , desktoprule( UnusedSetRule )
00056 , typerule( UnusedForceRule )
00057 , maximizevertrule( UnusedSetRule )
00058 , maximizehorizrule( UnusedSetRule )
00059 , minimizerule( UnusedSetRule )
00060 , shaderule( UnusedSetRule )
00061 , skiptaskbarrule( UnusedSetRule )
00062 , skippagerrule( UnusedSetRule )
00063 , aboverule( UnusedSetRule )
00064 , belowrule( UnusedSetRule )
00065 , fullscreenrule( UnusedSetRule )
00066 , noborderrule( UnusedSetRule )
00067 , fsplevelrule( UnusedForceRule )
00068 , acceptfocusrule( UnusedForceRule )
00069 , moveresizemoderule( UnusedForceRule )
00070 , closeablerule( UnusedForceRule )
00071 , strictgeometryrule( UnusedForceRule )
00072 , shortcutrule( UnusedSetRule )
00073 , disableglobalshortcutsrule( UnusedForceRule )
00074 {
00075 }
00076
00077 Rules::Rules( const QString& str, bool temporary )
00078 : temporary_state( temporary ? 2 : 0 )
00079 {
00080 KTemporaryFile file;
00081 if( file.open() )
00082 {
00083 QByteArray s = str.toUtf8();
00084 file.write( s.data(), s.length());
00085 }
00086 file.flush();
00087 KConfig cfg( file.fileName(), KConfig::SimpleConfig);
00088 readFromCfg( cfg.group( QString() ) );
00089 if( description.isEmpty())
00090 description = "temporary";
00091 }
00092
00093 #define READ_MATCH_STRING( var, func ) \
00094 var = cfg.readEntry( #var ) func; \
00095 var##match = (StringMatch) qMax( FirstStringMatch, \
00096 qMin( LastStringMatch, static_cast< StringMatch >( cfg.readEntry( #var "match",0 ))));
00097
00098 #define READ_SET_RULE( var, func, def ) \
00099 var = func ( cfg.readEntry( #var, def)); \
00100 var##rule = readSetRule( cfg, #var "rule" );
00101
00102 #define READ_SET_RULE_DEF( var , func, def ) \
00103 var = func ( cfg.readEntry( #var, def )); \
00104 var##rule = readSetRule( cfg, #var "rule" );
00105
00106 #define READ_FORCE_RULE( var, func, def) \
00107 var = func ( cfg.readEntry( #var, def)); \
00108 var##rule = readForceRule( cfg, #var "rule" );
00109
00110 #define READ_FORCE_RULE2( var, def, func, funcarg ) \
00111 var = func ( cfg.readEntry( #var, def),funcarg ); \
00112 var##rule = readForceRule( cfg, #var "rule" );
00113
00114
00115
00116 Rules::Rules( const KConfigGroup& cfg )
00117 : temporary_state( 0 )
00118 {
00119 readFromCfg( cfg );
00120 }
00121
00122 static int limit0to4( int i ) { return qMax( 0, qMin( 4, i )); }
00123
00124 void Rules::readFromCfg( const KConfigGroup& cfg )
00125 {
00126 description = cfg.readEntry( "Description" );
00127 if( description.isEmpty())
00128 description = cfg.readEntry( "description" );
00129 READ_MATCH_STRING( wmclass, .toLower().toLatin1() );
00130 wmclasscomplete = cfg.readEntry( "wmclasscomplete" , false);
00131 READ_MATCH_STRING( windowrole, .toLower().toLatin1() );
00132 READ_MATCH_STRING( title, );
00133 READ_MATCH_STRING( extrarole, .toLower().toLatin1() );
00134 READ_MATCH_STRING( clientmachine, .toLower().toLatin1() );
00135 types = cfg.readEntry( "types", uint(NET::AllTypesMask) );
00136 READ_FORCE_RULE2( placement,QString(), Placement::policyFromString,false );
00137 READ_SET_RULE_DEF( position, , invalidPoint );
00138 READ_SET_RULE( size,, QSize());
00139 if( size.isEmpty() && sizerule != ( SetRule )Remember)
00140 sizerule = UnusedSetRule;
00141 READ_FORCE_RULE( minsize,, QSize());
00142 if( !minsize.isValid())
00143 minsize = QSize( 1, 1 );
00144 READ_FORCE_RULE( maxsize, , QSize());
00145 if( maxsize.isEmpty())
00146 maxsize = QSize( 32767, 32767 );
00147 READ_FORCE_RULE( opacityactive, , 0);
00148 if( opacityactive < 0 || opacityactive > 100 )
00149 opacityactive = 100;
00150 READ_FORCE_RULE( opacityinactive,, 0);
00151 if( opacityinactive < 0 || opacityinactive > 100 )
00152 opacityinactive = 100;
00153 READ_FORCE_RULE( ignoreposition,, false);
00154 READ_SET_RULE( desktop,,0 );
00155 type = readType( cfg, "type" );
00156 typerule = type != NET::Unknown ? readForceRule( cfg, "typerule" ) : UnusedForceRule;
00157 READ_SET_RULE( maximizevert,, false);
00158 READ_SET_RULE( maximizehoriz,, false);
00159 READ_SET_RULE( minimize,, false);
00160 READ_SET_RULE( shade,, false);
00161 READ_SET_RULE( skiptaskbar,, false);
00162 READ_SET_RULE( skippager,, false);
00163 READ_SET_RULE( above,, false);
00164 READ_SET_RULE( below,, false);
00165 READ_SET_RULE( fullscreen,, false);
00166 READ_SET_RULE( noborder,,false );
00167 READ_FORCE_RULE( fsplevel,limit0to4,0 );
00168 READ_FORCE_RULE( acceptfocus, , false);
00169 READ_FORCE_RULE( moveresizemode,Options::stringToMoveResizeMode, QString());
00170 READ_FORCE_RULE( closeable, , false);
00171 READ_FORCE_RULE( strictgeometry, , false);
00172 READ_SET_RULE( shortcut, ,QString() );
00173 READ_FORCE_RULE( disableglobalshortcuts, , false);
00174 }
00175
00176 #undef READ_MATCH_STRING
00177 #undef READ_SET_RULE
00178 #undef READ_FORCE_RULE
00179 #undef READ_FORCE_RULE2
00180
00181 #define WRITE_MATCH_STRING( var, cast, force ) \
00182 if( !var.isEmpty() || force ) \
00183 { \
00184 cfg.writeEntry( #var, cast var ); \
00185 cfg.writeEntry( #var "match", (int)var##match ); \
00186 } \
00187 else \
00188 { \
00189 cfg.deleteEntry( #var ); \
00190 cfg.deleteEntry( #var "match" ); \
00191 }
00192
00193 #define WRITE_SET_RULE( var, func ) \
00194 if( var##rule != UnusedSetRule ) \
00195 { \
00196 cfg.writeEntry( #var, func ( var )); \
00197 cfg.writeEntry( #var "rule", (int)var##rule ); \
00198 } \
00199 else \
00200 { \
00201 cfg.deleteEntry( #var ); \
00202 cfg.deleteEntry( #var "rule" ); \
00203 }
00204
00205 #define WRITE_FORCE_RULE( var, func ) \
00206 if( var##rule != UnusedForceRule ) \
00207 { \
00208 cfg.writeEntry( #var, func ( var )); \
00209 cfg.writeEntry( #var "rule", (int)var##rule ); \
00210 } \
00211 else \
00212 { \
00213 cfg.deleteEntry( #var ); \
00214 cfg.deleteEntry( #var "rule" ); \
00215 }
00216
00217 void Rules::write( KConfigGroup& 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 if (types != NET::AllTypesMask)
00228 cfg.writeEntry("types", uint(types));
00229 else
00230 cfg.deleteEntry("types");
00231 WRITE_FORCE_RULE( placement, Placement::policyToString );
00232 WRITE_SET_RULE( position, );
00233 WRITE_SET_RULE( size, );
00234 WRITE_FORCE_RULE( minsize, );
00235 WRITE_FORCE_RULE( maxsize, );
00236 WRITE_FORCE_RULE( opacityactive, );
00237 WRITE_FORCE_RULE( opacityinactive, );
00238 WRITE_FORCE_RULE( ignoreposition, );
00239 WRITE_SET_RULE( desktop, );
00240 WRITE_FORCE_RULE( type, int );
00241 WRITE_SET_RULE( maximizevert, );
00242 WRITE_SET_RULE( maximizehoriz, );
00243 WRITE_SET_RULE( minimize, );
00244 WRITE_SET_RULE( shade, );
00245 WRITE_SET_RULE( skiptaskbar, );
00246 WRITE_SET_RULE( skippager, );
00247 WRITE_SET_RULE( above, );
00248 WRITE_SET_RULE( below, );
00249 WRITE_SET_RULE( fullscreen, );
00250 WRITE_SET_RULE( noborder, );
00251 WRITE_FORCE_RULE( fsplevel, );
00252 WRITE_FORCE_RULE( acceptfocus, );
00253 WRITE_FORCE_RULE( moveresizemode, Options::moveResizeModeToString );
00254 WRITE_FORCE_RULE( closeable, );
00255 WRITE_FORCE_RULE( strictgeometry, );
00256 WRITE_SET_RULE( shortcut, );
00257 WRITE_FORCE_RULE( disableglobalshortcuts, );
00258 }
00259
00260 #undef WRITE_MATCH_STRING
00261 #undef WRITE_SET_RULE
00262 #undef WRITE_FORCE_RULE
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( const KConfigGroup& cfg, const QString& key )
00297 {
00298 int v = cfg.readEntry( key,0 );
00299 if( v >= DontAffect && v <= ForceTemporarily )
00300 return static_cast< SetRule >( v );
00301 return UnusedSetRule;
00302 }
00303
00304 Rules::ForceRule Rules::readForceRule( const KConfigGroup& cfg, const QString& key )
00305 {
00306 int v = cfg.readEntry( key,0 );
00307 if( v == DontAffect || v == Force || v == ForceTemporarily )
00308 return static_cast< ForceRule >( v );
00309 return UnusedForceRule;
00310 }
00311
00312 NET::WindowType Rules::readType( const KConfigGroup& cfg, const QString& key )
00313 {
00314 int v = cfg.readEntry( key,0 );
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 QByteArray& match_class, const QByteArray& match_name ) const
00333 {
00334 if( wmclassmatch != UnimportantMatch )
00335 {
00336 QByteArray cwmclass = wmclasscomplete
00337 ? match_name + ' ' + match_class : match_class;
00338 if( wmclassmatch == RegExpMatch && QRegExp( wmclass ).indexIn( 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 QByteArray& match_role ) const
00349 {
00350 if( windowrolematch != UnimportantMatch )
00351 {
00352 if( windowrolematch == RegExpMatch && QRegExp( windowrole ).indexIn( 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 QString& match_title ) const
00363 {
00364 if( titlematch != UnimportantMatch )
00365 {
00366 if( titlematch == RegExpMatch && QRegExp( title ).indexIn( 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 QByteArray& 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 && QRegExp( clientmachine ).indexIn( 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 QPoint 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 QSize 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->noBorder();
00499 noborder = c->noBorder();
00500 }
00501 if (opacityactiverule == ( ForceRule )Force)
00502 {
00503
00504 }
00505 if (opacityinactiverule == ( ForceRule )Force)
00506 {
00507
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 kdbgstream& operator<<( kdbgstream& stream, const Rules* r )
00687 {
00688 return stream << "[" << r->description << ":" << r->wmclass << "]" ;
00689 }
00690
00691 #ifndef KCMRULES
00692 void WindowRules::discardTemporary()
00693 {
00694 QVector< Rules* >::Iterator it2 = rules.begin();
00695 for( QVector< Rules* >::Iterator it = rules.begin();
00696 it != rules.end();
00697 )
00698 {
00699 if( (*it)->discardTemporary( true ))
00700 ++it;
00701 else
00702 {
00703 *it2++ = *it++;
00704 }
00705 }
00706 rules.erase( it2, rules.end());
00707 }
00708
00709 void WindowRules::update( Client* c )
00710 {
00711 bool updated = false;
00712 for( QVector< Rules* >::ConstIterator it = rules.constBegin();
00713 it != rules.constEnd();
00714 ++it )
00715 if( (*it)->update( c ))
00716 updated = true;
00717 if( updated )
00718 Workspace::self()->rulesUpdated();
00719 }
00720
00721 #define CHECK_RULE( rule, type ) \
00722 type WindowRules::check##rule( type arg, bool init ) const \
00723 { \
00724 if( rules.count() == 0 ) \
00725 return arg; \
00726 type ret = arg; \
00727 for( QVector< Rules* >::ConstIterator it = rules.constBegin(); \
00728 it != rules.constEnd(); \
00729 ++it ) \
00730 { \
00731 if( (*it)->apply##rule( ret, init )) \
00732 break; \
00733 } \
00734 return ret; \
00735 }
00736
00737 #define CHECK_FORCE_RULE( rule, type ) \
00738 type WindowRules::check##rule( type arg ) const \
00739 { \
00740 if( rules.count() == 0 ) \
00741 return arg; \
00742 type ret = arg; \
00743 for( QVector< Rules* >::ConstIterator it = rules.begin(); \
00744 it != rules.end(); \
00745 ++it ) \
00746 { \
00747 if( (*it)->apply##rule( ret )) \
00748 break; \
00749 } \
00750 return ret; \
00751 }
00752
00753 CHECK_FORCE_RULE( Placement, Placement::Policy )
00754
00755 QRect WindowRules::checkGeometry( QRect rect, bool init ) const
00756 {
00757 return QRect( checkPosition( rect.topLeft(), init ), checkSize( rect.size(), init ));
00758 }
00759
00760 CHECK_RULE( Position, QPoint )
00761 CHECK_RULE( Size, QSize )
00762 CHECK_FORCE_RULE( MinSize, QSize )
00763 CHECK_FORCE_RULE( MaxSize, QSize )
00764 CHECK_FORCE_RULE( OpacityActive, int )
00765 CHECK_FORCE_RULE( OpacityInactive, int )
00766 CHECK_FORCE_RULE( IgnorePosition, bool )
00767
00768 bool WindowRules::checkIgnoreGeometry( bool ignore ) const
00769 {
00770 return checkIgnorePosition( ignore );
00771 }
00772
00773 CHECK_RULE( Desktop, int )
00774 CHECK_FORCE_RULE( Type, NET::WindowType )
00775 CHECK_RULE( MaximizeVert, KDecorationDefines::MaximizeMode )
00776 CHECK_RULE( MaximizeHoriz, KDecorationDefines::MaximizeMode )
00777
00778 KDecorationDefines::MaximizeMode WindowRules::checkMaximize( MaximizeMode mode, bool init ) const
00779 {
00780 bool vert = checkMaximizeVert( mode, init ) & MaximizeVertical;
00781 bool horiz = checkMaximizeHoriz( mode, init ) & MaximizeHorizontal;
00782 return static_cast< MaximizeMode >(( vert ? MaximizeVertical : 0 ) | ( horiz ? MaximizeHorizontal : 0 ));
00783 }
00784
00785 CHECK_RULE( Minimize, bool )
00786 CHECK_RULE( Shade, ShadeMode )
00787 CHECK_RULE( SkipTaskbar, bool )
00788 CHECK_RULE( SkipPager, bool )
00789 CHECK_RULE( KeepAbove, bool )
00790 CHECK_RULE( KeepBelow, bool )
00791 CHECK_RULE( FullScreen, bool )
00792 CHECK_RULE( NoBorder, bool )
00793 CHECK_FORCE_RULE( FSP, int )
00794 CHECK_FORCE_RULE( AcceptFocus, bool )
00795 CHECK_FORCE_RULE( MoveResizeMode, Options::MoveResizeMode )
00796 CHECK_FORCE_RULE( Closeable, bool )
00797 CHECK_FORCE_RULE( StrictGeometry, bool )
00798 CHECK_RULE( Shortcut, QString )
00799 CHECK_FORCE_RULE( DisableGlobalShortcuts, bool )
00800
00801 #undef CHECK_RULE
00802 #undef CHECK_FORCE_RULE
00803
00804
00805
00806 void Client::setupWindowRules( bool ignore_temporary )
00807 {
00808 client_rules = workspace()->findWindowRules( this, ignore_temporary );
00809
00810 if( isTopMenu())
00811 client_rules = WindowRules();
00812 }
00813
00814
00815
00816 void Client::applyWindowRules()
00817 {
00818
00819
00820
00821 QRect orig_geom = QRect( pos(), sizeForClientSize( clientSize()));
00822 QRect geom = client_rules.checkGeometry( orig_geom );
00823 if( geom != orig_geom )
00824 setGeometry( geom );
00825
00826
00827 setDesktop( desktop());
00828
00829 maximize( maximizeMode());
00830
00831 if( client_rules.checkMinimize( isMinimized()))
00832 minimize();
00833 else
00834 unminimize();
00835 setShade( shadeMode());
00836 setSkipTaskbar( skipTaskbar(), true );
00837 setSkipPager( skipPager());
00838 setKeepAbove( keepAbove());
00839 setKeepBelow( keepBelow());
00840 setFullScreen( isFullScreen(), true );
00841 setNoBorder( noBorder());
00842
00843
00844 if( workspace()->mostRecentlyActivatedClient() == this
00845 && !client_rules.checkAcceptFocus( true ))
00846 workspace()->activateNextClient( this );
00847
00848
00849 QSize s = adjustedSize();
00850 if( s != size())
00851 resizeWithChecks( s );
00852
00853 setShortcut( rules()->checkShortcut( shortcut().toString()));
00854
00855 if( isActive())
00856 workspace()->disableGlobalShortcutsForClient( rules()->checkDisableGlobalShortcuts( false ));
00857 }
00858
00859 void Client::updateWindowRules()
00860 {
00861 if( !isManaged())
00862 return;
00863 if( workspace()->rulesUpdatesDisabled())
00864 return;
00865 client_rules.update( this );
00866 }
00867
00868 void Client::finishWindowRules()
00869 {
00870 updateWindowRules();
00871 client_rules = WindowRules();
00872 }
00873
00874
00875
00876 WindowRules Workspace::findWindowRules( const Client* c, bool ignore_temporary )
00877 {
00878 QVector< Rules* > ret;
00879 for( QList< Rules* >::Iterator it = rules.begin();
00880 it != rules.end();
00881 )
00882 {
00883 if( ignore_temporary && (*it)->isTemporary())
00884 {
00885 ++it;
00886 continue;
00887 }
00888 if( (*it)->match( c ))
00889 {
00890 Rules* rule = *it;
00891 kDebug( 1212 ) << "Rule found:" << rule << ":" << c;
00892 if( rule->isTemporary())
00893 it = rules.erase( it );
00894 else
00895 ++it;
00896 ret.append( rule );
00897 continue;
00898 }
00899 ++it;
00900 }
00901 return WindowRules( ret );
00902 }
00903
00904 void Workspace::editWindowRules( Client* c, bool whole_app )
00905 {
00906 writeWindowRules();
00907 QStringList args;
00908 args << "--wid" << QString::number( c->window());
00909 if( whole_app )
00910 args << "--whole-app";
00911 KToolInvocation::kdeinitExec( "kwin_rules_dialog", args );
00912 }
00913
00914 void Workspace::loadWindowRules()
00915 {
00916 while( !rules.isEmpty())
00917 {
00918 delete rules.front();
00919 rules.pop_front();
00920 }
00921 KConfig cfg( "kwinrulesrc", KConfig::NoGlobals );
00922 int count = cfg.group("General").readEntry( "count",0 );
00923 for( int i = 1;
00924 i <= count;
00925 ++i )
00926 {
00927 KConfigGroup cg( &cfg, QString::number( i ));
00928 Rules* rule = new Rules( cg );
00929 rules.append( rule );
00930 }
00931 }
00932
00933 void Workspace::writeWindowRules()
00934 {
00935 rulesUpdatedTimer.stop();
00936 KConfig cfg( "kwinrulesrc", KConfig::NoGlobals );
00937 QStringList groups = cfg.groupList();
00938 for( QStringList::ConstIterator it = groups.constBegin();
00939 it != groups.constEnd();
00940 ++it )
00941 cfg.deleteGroup( *it );
00942 cfg.group("General").writeEntry( "count", rules.count());
00943 int i = 1;
00944 for( QList< Rules* >::ConstIterator it = rules.constBegin();
00945 it != rules.constEnd();
00946 ++it )
00947 {
00948 if( (*it)->isTemporary())
00949 continue;
00950 KConfigGroup cg( &cfg, QString::number( i ));
00951 (*it)->write( cg );
00952 ++i;
00953 }
00954 }
00955
00956 void Workspace::gotTemporaryRulesMessage( const QString& message )
00957 {
00958 bool was_temporary = false;
00959 for( QList< Rules* >::ConstIterator it = rules.constBegin();
00960 it != rules.constEnd();
00961 ++it )
00962 if( (*it)->isTemporary())
00963 was_temporary = true;
00964 Rules* rule = new Rules( message, true );
00965 rules.prepend( rule );
00966 if( !was_temporary )
00967 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
00968 }
00969
00970 void Workspace::cleanupTemporaryRules()
00971 {
00972 bool has_temporary = false;
00973 for( QList< Rules* >::Iterator it = rules.begin();
00974 it != rules.end();
00975 )
00976 {
00977 if( (*it)->discardTemporary( false ))
00978 it = rules.erase( it );
00979 else
00980 {
00981 if( (*it)->isTemporary())
00982 has_temporary = true;
00983 ++it;
00984 }
00985 }
00986 if( has_temporary )
00987 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
00988 }
00989
00990 void Workspace::discardUsedWindowRules( Client* c, bool withdrawn )
00991 {
00992 bool updated = false;
00993 for( QList< Rules* >::Iterator it = rules.begin();
00994 it != rules.end();
00995 )
00996 {
00997 if( c->rules()->contains( *it ))
00998 {
00999 updated = true;
01000 (*it)->discardUsed( withdrawn );
01001 if( (*it)->isEmpty())
01002 {
01003 c->removeRule( *it );
01004 Rules* r = *it;
01005 it = rules.erase( it );
01006 delete r;
01007 continue;
01008 }
01009 }
01010 ++it;
01011 }
01012 if( updated )
01013 rulesUpdated();
01014 }
01015
01016 void Workspace::rulesUpdated()
01017 {
01018 rulesUpdatedTimer.setSingleShot( true );
01019 rulesUpdatedTimer.start( 1000 );
01020 }
01021
01022 void Workspace::disableRulesUpdates( bool disable )
01023 {
01024 rules_updates_disabled = disable;
01025 if( !disable )
01026 foreach( Client* c, clients )
01027 c->updateWindowRules();
01028 }
01029
01030 #endif
01031
01032 }