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