kwin Library API Documentation

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