rules.cpp

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