• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KWin

rules.cpp

Go to the documentation of this file.
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 This program is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 This program is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 *********************************************************************/
00020 
00021 #include "rules.h"
00022 
00023 #include <fixx11h.h>
00024 #include <kconfig.h>
00025 #include <QRegExp>
00026 #include <ktemporaryfile.h>
00027 #include <QFile>
00028 #include <ktoolinvocation.h>
00029 
00030 #ifndef KCMRULES
00031 #include "client.h"
00032 #include "workspace.h"
00033 #endif
00034 
00035 namespace KWin
00036 {
00037 
00038 Rules::Rules()
00039     : temporary_state( 0 )
00040     , wmclassmatch( UnimportantMatch )
00041     , wmclasscomplete( UnimportantMatch )
00042     , windowrolematch( UnimportantMatch )
00043     , titlematch( UnimportantMatch )
00044     , extrarolematch( UnimportantMatch )
00045     , clientmachinematch( UnimportantMatch )
00046     , types( NET::AllTypesMask )
00047     , placementrule( UnusedForceRule )
00048     , positionrule( UnusedSetRule )
00049     , sizerule( UnusedSetRule )
00050     , minsizerule( UnusedForceRule )
00051     , maxsizerule( UnusedForceRule )
00052     , opacityactiverule( UnusedForceRule )
00053     , opacityinactiverule( UnusedForceRule )
00054     , ignorepositionrule( UnusedForceRule )
00055     , desktoprule( UnusedSetRule )
00056     , typerule( UnusedForceRule )
00057     , maximizevertrule( UnusedSetRule )
00058     , maximizehorizrule( UnusedSetRule )
00059     , minimizerule( UnusedSetRule )
00060     , shaderule( UnusedSetRule )
00061     , skiptaskbarrule( UnusedSetRule )
00062     , skippagerrule( UnusedSetRule )
00063     , aboverule( UnusedSetRule )
00064     , belowrule( UnusedSetRule )
00065     , fullscreenrule( UnusedSetRule )
00066     , noborderrule( UnusedSetRule )
00067     , fsplevelrule( UnusedForceRule )
00068     , acceptfocusrule( UnusedForceRule )
00069     , moveresizemoderule( UnusedForceRule )
00070     , closeablerule( UnusedForceRule )
00071     , strictgeometryrule( UnusedForceRule )
00072     , shortcutrule( UnusedSetRule )
00073     , disableglobalshortcutsrule( UnusedForceRule )
00074     {
00075     }
00076 
00077 Rules::Rules( const QString& str, bool temporary )
00078     : temporary_state( temporary ? 2 : 0 )
00079     {
00080     KTemporaryFile file;
00081     if( file.open() )
00082         {
00083         QByteArray s = str.toUtf8();
00084         file.write( s.data(), s.length());
00085         }
00086     file.flush();
00087     KConfig cfg( file.fileName(), KConfig::SimpleConfig);
00088     readFromCfg( cfg.group( QString() ) );
00089     if( description.isEmpty())
00090         description = "temporary";
00091     }
00092 
00093 #define READ_MATCH_STRING( var, func ) \
00094     var = cfg.readEntry( #var ) func; \
00095     var##match = (StringMatch) qMax( FirstStringMatch, \
00096         qMin( LastStringMatch, static_cast< StringMatch >( cfg.readEntry( #var "match",0 ))));
00097 
00098 #define READ_SET_RULE( var, func, def ) \
00099     var = func ( cfg.readEntry( #var, def)); \
00100     var##rule = readSetRule( cfg, #var "rule" );
00101 
00102 #define READ_SET_RULE_DEF( var , func, def ) \
00103     var = func ( cfg.readEntry( #var, def )); \
00104     var##rule = readSetRule( cfg, #var "rule" );
00105 
00106 #define READ_FORCE_RULE( var, func, def) \
00107     var = func ( cfg.readEntry( #var, def)); \
00108     var##rule = readForceRule( cfg, #var "rule" );
00109 
00110 #define READ_FORCE_RULE2( var, def, func, funcarg ) \
00111     var = func ( cfg.readEntry( #var, def),funcarg ); \
00112     var##rule = readForceRule( cfg, #var "rule" );
00113 
00114 
00115 
00116 Rules::Rules( const KConfigGroup& cfg )
00117     : temporary_state( 0 )
00118     {
00119     readFromCfg( cfg );
00120     }
00121 
00122 static int limit0to4( int i ) { return qMax( 0, qMin( 4, i )); }
00123 
00124 void Rules::readFromCfg( const KConfigGroup& cfg )
00125     {
00126     description = cfg.readEntry( "Description" );
00127     if( description.isEmpty()) // capitalized first, lowercase for backwards compatibility
00128         description = cfg.readEntry( "description" );
00129     READ_MATCH_STRING( wmclass, .toLower().toLatin1() );
00130     wmclasscomplete = cfg.readEntry( "wmclasscomplete" , false);
00131     READ_MATCH_STRING( windowrole, .toLower().toLatin1() );
00132     READ_MATCH_STRING( title, );
00133     READ_MATCH_STRING( extrarole, .toLower().toLatin1() );
00134     READ_MATCH_STRING( clientmachine, .toLower().toLatin1() );
00135     types = cfg.readEntry( "types", uint(NET::AllTypesMask) );
00136     READ_FORCE_RULE2( placement,QString(), Placement::policyFromString,false );
00137     READ_SET_RULE_DEF( position, , invalidPoint );
00138     READ_SET_RULE( size,, QSize());
00139     if( size.isEmpty() && sizerule != ( SetRule )Remember)
00140         sizerule = UnusedSetRule;
00141     READ_FORCE_RULE( minsize,, QSize());
00142     if( !minsize.isValid())
00143         minsize = QSize( 1, 1 );
00144     READ_FORCE_RULE( maxsize, , QSize());
00145     if( maxsize.isEmpty())
00146         maxsize = QSize( 32767, 32767 );
00147     READ_FORCE_RULE( opacityactive, , 0);
00148     if( opacityactive < 0 || opacityactive > 100 )
00149         opacityactive = 100;
00150     READ_FORCE_RULE( opacityinactive,, 0);
00151     if( opacityinactive < 0 || opacityinactive > 100 )
00152         opacityinactive = 100;
00153     READ_FORCE_RULE( ignoreposition,, false);
00154     READ_SET_RULE( desktop,,0  );
00155     type = readType( cfg, "type" );
00156     typerule = type != NET::Unknown ? readForceRule( cfg, "typerule" ) : UnusedForceRule;
00157     READ_SET_RULE( maximizevert,, false);
00158     READ_SET_RULE( maximizehoriz,, false);
00159     READ_SET_RULE( minimize,, false);
00160     READ_SET_RULE( shade,, false);
00161     READ_SET_RULE( skiptaskbar,, false);
00162     READ_SET_RULE( skippager,, false);
00163     READ_SET_RULE( above,, false);
00164     READ_SET_RULE( below,, false);
00165     READ_SET_RULE( fullscreen,, false);
00166     READ_SET_RULE( noborder,,false );
00167     READ_FORCE_RULE( fsplevel,limit0to4,0 ); // fsp is 0-4
00168     READ_FORCE_RULE( acceptfocus, , false);
00169     READ_FORCE_RULE( moveresizemode,Options::stringToMoveResizeMode, QString());
00170     READ_FORCE_RULE( closeable, , false);
00171     READ_FORCE_RULE( strictgeometry, , false);
00172     READ_SET_RULE( shortcut, ,QString() );
00173     READ_FORCE_RULE( disableglobalshortcuts, , false);
00174     }
00175 
00176 #undef READ_MATCH_STRING
00177 #undef READ_SET_RULE
00178 #undef READ_FORCE_RULE
00179 #undef READ_FORCE_RULE2
00180 
00181 #define WRITE_MATCH_STRING( var, cast, force ) \
00182     if( !var.isEmpty() || force ) \
00183         { \
00184         cfg.writeEntry( #var, cast var ); \
00185         cfg.writeEntry( #var "match", (int)var##match ); \
00186         } \
00187     else \
00188         { \
00189         cfg.deleteEntry( #var ); \
00190         cfg.deleteEntry( #var "match" ); \
00191         }
00192 
00193 #define WRITE_SET_RULE( var, func ) \
00194     if( var##rule != UnusedSetRule ) \
00195         { \
00196         cfg.writeEntry( #var, func ( var )); \
00197         cfg.writeEntry( #var "rule", (int)var##rule ); \
00198         } \
00199     else \
00200         { \
00201         cfg.deleteEntry( #var ); \
00202         cfg.deleteEntry( #var "rule" ); \
00203         }
00204 
00205 #define WRITE_FORCE_RULE( var, func ) \
00206     if( var##rule != UnusedForceRule ) \
00207         { \
00208         cfg.writeEntry( #var, func ( var )); \
00209         cfg.writeEntry( #var "rule", (int)var##rule ); \
00210         } \
00211     else \
00212         { \
00213         cfg.deleteEntry( #var ); \
00214         cfg.deleteEntry( #var "rule" ); \
00215         }
00216 
00217 void Rules::write( KConfigGroup& cfg ) const
00218     {
00219     cfg.writeEntry( "Description", description );
00220     // 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     if (types != NET::AllTypesMask)
00228         cfg.writeEntry("types", uint(types));
00229     else
00230         cfg.deleteEntry("types");
00231     WRITE_FORCE_RULE( placement, Placement::policyToString );
00232     WRITE_SET_RULE( position, );
00233     WRITE_SET_RULE( size, );
00234     WRITE_FORCE_RULE( minsize, );
00235     WRITE_FORCE_RULE( maxsize, );
00236     WRITE_FORCE_RULE( opacityactive, );
00237     WRITE_FORCE_RULE( opacityinactive, );
00238     WRITE_FORCE_RULE( ignoreposition, );
00239     WRITE_SET_RULE( desktop, );
00240     WRITE_FORCE_RULE( type, int );
00241     WRITE_SET_RULE( maximizevert, );
00242     WRITE_SET_RULE( maximizehoriz, );
00243     WRITE_SET_RULE( minimize, );
00244     WRITE_SET_RULE( shade, );
00245     WRITE_SET_RULE( skiptaskbar, );
00246     WRITE_SET_RULE( skippager, );
00247     WRITE_SET_RULE( above, );
00248     WRITE_SET_RULE( below, );
00249     WRITE_SET_RULE( fullscreen, );
00250     WRITE_SET_RULE( noborder, );
00251     WRITE_FORCE_RULE( fsplevel, );
00252     WRITE_FORCE_RULE( acceptfocus, );
00253     WRITE_FORCE_RULE( moveresizemode, Options::moveResizeModeToString );
00254     WRITE_FORCE_RULE( closeable, );
00255     WRITE_FORCE_RULE( strictgeometry, );
00256     WRITE_SET_RULE( shortcut, );
00257     WRITE_FORCE_RULE( disableglobalshortcuts, );
00258     }
00259 
00260 #undef WRITE_MATCH_STRING
00261 #undef WRITE_SET_RULE
00262 #undef WRITE_FORCE_RULE
00263 
00264 // returns true if it doesn't affect anything
00265 bool Rules::isEmpty() const
00266     {
00267     return( placementrule == UnusedForceRule
00268         && positionrule == UnusedSetRule
00269         && sizerule == UnusedSetRule
00270         && minsizerule == UnusedForceRule
00271         && maxsizerule == UnusedForceRule
00272         && opacityactiverule == UnusedForceRule
00273         && opacityinactiverule == UnusedForceRule
00274         && ignorepositionrule == UnusedForceRule
00275         && desktoprule == UnusedSetRule
00276         && typerule == UnusedForceRule
00277         && maximizevertrule == UnusedSetRule
00278         && maximizehorizrule == UnusedSetRule
00279         && minimizerule == UnusedSetRule
00280         && shaderule == UnusedSetRule
00281         && skiptaskbarrule == UnusedSetRule
00282         && skippagerrule == UnusedSetRule
00283         && aboverule == UnusedSetRule
00284         && belowrule == UnusedSetRule
00285         && fullscreenrule == UnusedSetRule
00286         && noborderrule == UnusedSetRule
00287         && fsplevelrule == UnusedForceRule
00288         && acceptfocusrule == UnusedForceRule
00289         && moveresizemoderule == UnusedForceRule
00290         && closeablerule == UnusedForceRule
00291         && strictgeometryrule == UnusedForceRule
00292         && shortcutrule == UnusedSetRule
00293         && disableglobalshortcutsrule == UnusedForceRule );
00294     }
00295 
00296 Rules::SetRule Rules::readSetRule( const KConfigGroup& cfg, const QString& key )
00297     {
00298     int v = cfg.readEntry( key,0 );
00299     if( v >= DontAffect && v <= ForceTemporarily )
00300         return static_cast< SetRule >( v );
00301     return UnusedSetRule;
00302     }
00303 
00304 Rules::ForceRule Rules::readForceRule( const KConfigGroup& cfg, const QString& key )
00305     {
00306     int v = cfg.readEntry( key,0 );
00307     if( v == DontAffect || v == Force || v == ForceTemporarily )
00308         return static_cast< ForceRule >( v );
00309     return UnusedForceRule;
00310     }
00311 
00312 NET::WindowType Rules::readType( const KConfigGroup& cfg, const QString& key )
00313     {
00314     int v = cfg.readEntry( key,0 );
00315     if( v >= NET::Normal && v <= NET::Splash )
00316         return static_cast< NET::WindowType >( v );
00317     return NET::Unknown;
00318     }
00319 
00320 bool Rules::matchType( NET::WindowType match_type ) const
00321     {
00322     if( types != NET::AllTypesMask )
00323         {
00324         if( match_type == NET::Unknown )
00325             match_type = NET::Normal; // NET::Unknown->NET::Normal is only here for matching
00326         if( !NET::typeMatchesMask( match_type, types ))
00327             return false;
00328         }
00329     return true;
00330     }
00331 
00332 bool Rules::matchWMClass( const QByteArray& match_class, const QByteArray& match_name ) const
00333     {
00334     if( wmclassmatch != UnimportantMatch )
00335         { // TODO optimize?
00336         QByteArray cwmclass = wmclasscomplete
00337             ? match_name + ' ' + match_class : match_class;
00338         if( wmclassmatch == RegExpMatch && QRegExp( wmclass ).indexIn( cwmclass ) == -1 )
00339             return false;
00340         if( wmclassmatch == ExactMatch && wmclass != cwmclass )
00341             return false;
00342         if( wmclassmatch == SubstringMatch && !cwmclass.contains( wmclass ))
00343             return false;
00344         }
00345     return true;
00346     }
00347 
00348 bool Rules::matchRole( const QByteArray& match_role ) const
00349     {
00350     if( windowrolematch != UnimportantMatch )
00351         {
00352         if( windowrolematch == RegExpMatch && QRegExp( windowrole ).indexIn( match_role ) == -1 )
00353             return false;
00354         if( windowrolematch == ExactMatch && windowrole != match_role )
00355             return false;
00356         if( windowrolematch == SubstringMatch && !match_role.contains( windowrole ))
00357             return false;
00358         }
00359     return true;
00360     }
00361 
00362 bool Rules::matchTitle( const QString& match_title ) const
00363     {
00364     if( titlematch != UnimportantMatch )
00365         {
00366         if( titlematch == RegExpMatch && QRegExp( title ).indexIn( match_title ) == -1 )
00367             return false;
00368         if( titlematch == ExactMatch && title != match_title )
00369             return false;
00370         if( titlematch == SubstringMatch && !match_title.contains( title ))
00371             return false;
00372         }
00373     return true;
00374     }
00375 
00376 bool Rules::matchClientMachine( const QByteArray& match_machine ) const
00377     {
00378     if( clientmachinematch != UnimportantMatch )
00379         {
00380         // if it's localhost, check also "localhost" before checking hostname
00381         if( match_machine != "localhost" && isLocalMachine( match_machine )
00382             && matchClientMachine( "localhost" ))
00383             return true;
00384         if( clientmachinematch == RegExpMatch
00385             && QRegExp( clientmachine ).indexIn( match_machine ) == -1 )
00386             return false;
00387         if( clientmachinematch == ExactMatch
00388             && clientmachine != match_machine )
00389             return false;
00390         if( clientmachinematch == SubstringMatch
00391             && !match_machine.contains( clientmachine ))
00392             return false;
00393         }
00394     return true;
00395     }
00396 
00397 #ifndef KCMRULES
00398 bool Rules::match( const Client* c ) const
00399     {
00400     if( !matchType( c->windowType( true )))
00401         return false;
00402     if( !matchWMClass( c->resourceClass(), c->resourceName()))
00403         return false;
00404     if( !matchRole( c->windowRole()))
00405         return false;
00406     if( !matchTitle( c->caption( false )))
00407         return false;
00408     // TODO extrarole
00409     if( !matchClientMachine( c->wmClientMachine( false )))
00410         return false;
00411     return true;
00412     }
00413 
00414 bool Rules::update( Client* c )
00415     {
00416     // TODO check this setting is for this client ?
00417     bool updated = false;
00418     if( positionrule == ( SetRule )Remember)
00419         {
00420         if( !c->isFullScreen())
00421             {
00422             QPoint new_pos = position;
00423             // don't use the position in the direction which is maximized
00424             if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
00425                 new_pos.setX( c->pos().x());
00426             if(( c->maximizeMode() & MaximizeVertical ) == 0 )
00427                 new_pos.setY( c->pos().y());
00428             updated = updated || position != new_pos;
00429             position = new_pos;
00430             }
00431         }
00432     if( sizerule == ( SetRule )Remember)
00433         {
00434         if( !c->isFullScreen())
00435             {
00436             QSize new_size = size;
00437             // don't use the position in the direction which is maximized
00438             if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
00439                 new_size.setWidth( c->size().width());
00440             if(( c->maximizeMode() & MaximizeVertical ) == 0 )
00441                 new_size.setHeight( c->size().height());
00442             updated = updated || size != new_size;
00443             size = new_size;
00444             }
00445         }
00446     if( desktoprule == ( SetRule )Remember)
00447         {
00448         updated = updated || desktop != c->desktop();
00449         desktop = c->desktop();
00450         }
00451     if( maximizevertrule == ( SetRule )Remember)
00452         {
00453         updated = updated || maximizevert != bool( c->maximizeMode() & MaximizeVertical );
00454         maximizevert = c->maximizeMode() & MaximizeVertical;
00455         }
00456     if( maximizehorizrule == ( SetRule )Remember)
00457         {
00458         updated = updated || maximizehoriz != bool( c->maximizeMode() & MaximizeHorizontal );
00459         maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
00460         }
00461     if( minimizerule == ( SetRule )Remember)
00462         {
00463         updated = updated || minimize != c->isMinimized();
00464         minimize = c->isMinimized();
00465         }
00466     if( shaderule == ( SetRule )Remember)
00467         {
00468         updated = updated || ( shade != ( c->shadeMode() != ShadeNone ));
00469         shade = c->shadeMode() != ShadeNone;
00470         }
00471     if( skiptaskbarrule == ( SetRule )Remember)
00472         {
00473         updated = updated || skiptaskbar != c->skipTaskbar();
00474         skiptaskbar = c->skipTaskbar();
00475         }
00476     if( skippagerrule == ( SetRule )Remember)
00477         {
00478         updated = updated || skippager != c->skipPager();
00479         skippager = c->skipPager();
00480         }
00481     if( aboverule == ( SetRule )Remember)
00482         {
00483         updated = updated || above != c->keepAbove();
00484         above = c->keepAbove();
00485         }
00486     if( belowrule == ( SetRule )Remember)
00487         {
00488         updated = updated || below != c->keepBelow();
00489         below = c->keepBelow();
00490         }
00491     if( fullscreenrule == ( SetRule )Remember)
00492         {
00493         updated = updated || fullscreen != c->isFullScreen();
00494         fullscreen = c->isFullScreen();
00495         }
00496     if( noborderrule == ( SetRule )Remember)
00497         {
00498         updated = updated || noborder != c->noBorder();
00499         noborder = c->noBorder();
00500         }
00501     if (opacityactiverule == ( ForceRule )Force)
00502         {
00503         // TODO
00504         }
00505     if (opacityinactiverule == ( ForceRule )Force)
00506         {
00507         // TODO
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 kdbgstream& operator<<( kdbgstream& stream, const Rules* r )
00687     {
00688     return stream << "[" << r->description << ":" << r->wmclass << "]" ;
00689     }
00690 
00691 #ifndef KCMRULES
00692 void WindowRules::discardTemporary()
00693     {
00694     QVector< Rules* >::Iterator it2 = rules.begin();
00695     for( QVector< Rules* >::Iterator it = rules.begin();
00696          it != rules.end();
00697          )
00698         {
00699         if( (*it)->discardTemporary( true ))
00700             ++it;
00701         else
00702             {
00703             *it2++ = *it++;
00704             }
00705         }
00706     rules.erase( it2, rules.end());
00707     }
00708 
00709 void WindowRules::update( Client* c )
00710     {
00711     bool updated = false;
00712     for( QVector< Rules* >::ConstIterator it = rules.begin();
00713          it != rules.end();
00714          ++it )
00715         if( (*it)->update( c )) // no short-circuiting here
00716             updated = true;
00717     if( updated )
00718         Workspace::self()->rulesUpdated();
00719     }
00720 
00721 #define CHECK_RULE( rule, type ) \
00722 type WindowRules::check##rule( type arg, bool init ) const \
00723     { \
00724     if( rules.count() == 0 ) \
00725         return arg; \
00726     type ret = arg; \
00727     for( QVector< Rules* >::ConstIterator it = rules.begin(); \
00728          it != rules.end(); \
00729          ++it ) \
00730         { \
00731         if( (*it)->apply##rule( ret, init )) \
00732             break; \
00733         } \
00734     return ret; \
00735     }
00736 
00737 #define CHECK_FORCE_RULE( rule, type ) \
00738 type WindowRules::check##rule( type arg ) const \
00739     { \
00740     if( rules.count() == 0 ) \
00741         return arg; \
00742     type ret = arg; \
00743     for( QVector< Rules* >::ConstIterator it = rules.begin(); \
00744          it != rules.end(); \
00745          ++it ) \
00746         { \
00747         if( (*it)->apply##rule( ret )) \
00748             break; \
00749         } \
00750     return ret; \
00751     }
00752 
00753 CHECK_FORCE_RULE( Placement, Placement::Policy )
00754 
00755 QRect WindowRules::checkGeometry( QRect rect, bool init ) const
00756     {
00757     return QRect( checkPosition( rect.topLeft(), init ), checkSize( rect.size(), init ));
00758     }
00759 
00760 CHECK_RULE( Position, QPoint )
00761 CHECK_RULE( Size, QSize )
00762 CHECK_FORCE_RULE( MinSize, QSize )
00763 CHECK_FORCE_RULE( MaxSize, QSize )
00764 CHECK_FORCE_RULE( OpacityActive, int )
00765 CHECK_FORCE_RULE( OpacityInactive, int )
00766 CHECK_FORCE_RULE( IgnorePosition, bool )
00767 
00768 bool WindowRules::checkIgnoreGeometry( bool ignore ) const
00769     {
00770     return checkIgnorePosition( ignore );
00771     }
00772 
00773 CHECK_RULE( Desktop, int )
00774 CHECK_FORCE_RULE( Type, NET::WindowType )
00775 CHECK_RULE( MaximizeVert, KDecorationDefines::MaximizeMode )
00776 CHECK_RULE( MaximizeHoriz, KDecorationDefines::MaximizeMode )
00777 
00778 KDecorationDefines::MaximizeMode WindowRules::checkMaximize( MaximizeMode mode, bool init ) const
00779     {
00780     bool vert = checkMaximizeVert( mode, init ) & MaximizeVertical;
00781     bool horiz = checkMaximizeHoriz( mode, init ) & MaximizeHorizontal;
00782     return static_cast< MaximizeMode >(( vert ? MaximizeVertical : 0 ) | ( horiz ? MaximizeHorizontal : 0 ));
00783     }
00784 
00785 CHECK_RULE( Minimize, bool )
00786 CHECK_RULE( Shade, ShadeMode )
00787 CHECK_RULE( SkipTaskbar, bool )
00788 CHECK_RULE( SkipPager, bool )
00789 CHECK_RULE( KeepAbove, bool )
00790 CHECK_RULE( KeepBelow, bool )
00791 CHECK_RULE( FullScreen, bool )
00792 CHECK_RULE( NoBorder, bool )
00793 CHECK_FORCE_RULE( FSP, int )
00794 CHECK_FORCE_RULE( AcceptFocus, bool )
00795 CHECK_FORCE_RULE( MoveResizeMode, Options::MoveResizeMode )
00796 CHECK_FORCE_RULE( Closeable, bool )
00797 CHECK_FORCE_RULE( StrictGeometry, bool )
00798 CHECK_RULE( Shortcut, QString )
00799 CHECK_FORCE_RULE( DisableGlobalShortcuts, bool )
00800 
00801 #undef CHECK_RULE
00802 #undef CHECK_FORCE_RULE
00803 
00804 // Client
00805 
00806 void Client::setupWindowRules( bool ignore_temporary )
00807     {
00808     client_rules = workspace()->findWindowRules( this, ignore_temporary );
00809     // check only after getting the rules, because there may be a rule forcing window type
00810     if( isTopMenu()) // TODO cannot have restrictions
00811         client_rules = WindowRules();
00812     }
00813 
00814 // Applies Force, ForceTemporarily and ApplyNow rules
00815 // Used e.g. after the rules have been modified using the kcm.
00816 void Client::applyWindowRules()
00817     {
00818     // apply force rules
00819     // Placement - does need explicit update, just like some others below
00820     // Geometry : setGeometry() doesn't check rules
00821     QRect orig_geom = QRect( pos(), sizeForClientSize( clientSize())); // handle shading
00822     QRect geom = client_rules.checkGeometry( orig_geom );
00823     if( geom != orig_geom )
00824         setGeometry( geom );
00825     // MinSize, MaxSize handled by Geometry
00826     // IgnorePosition
00827     setDesktop( desktop());
00828     // Type
00829     maximize( maximizeMode());
00830     // Minimize : functions don't check, and there are two functions
00831     if( client_rules.checkMinimize( isMinimized()))
00832         minimize();
00833     else
00834         unminimize();
00835     setShade( shadeMode());
00836     setSkipTaskbar( skipTaskbar(), true );
00837     setSkipPager( skipPager());
00838     setKeepAbove( keepAbove());
00839     setKeepBelow( keepBelow());
00840     setFullScreen( isFullScreen(), true );
00841     setNoBorder( noBorder());
00842     // FSP
00843     // AcceptFocus :
00844     if( workspace()->mostRecentlyActivatedClient() == this
00845         && !client_rules.checkAcceptFocus( true ))
00846         workspace()->activateNextClient( this );
00847     // MoveResizeMode
00848     // Closeable
00849     QSize s = adjustedSize();
00850     if( s != size())
00851         resizeWithChecks( s );
00852     // StrictGeometry
00853     setShortcut( rules()->checkShortcut( shortcut().toString()));
00854     // see also Client::setActive()
00855     if( isActive())
00856         workspace()->disableGlobalShortcutsForClient( rules()->checkDisableGlobalShortcuts( false ));
00857     }
00858 
00859 void Client::updateWindowRules()
00860     {
00861     if( !isManaged()) // not fully setup yet
00862         return;
00863     if( workspace()->rulesUpdatesDisabled())
00864         return;
00865     client_rules.update( this );
00866     }
00867 
00868 void Client::finishWindowRules()
00869     {
00870     updateWindowRules();
00871     client_rules = WindowRules();
00872     }
00873 
00874 // Workspace
00875 
00876 WindowRules Workspace::findWindowRules( const Client* c, bool ignore_temporary )
00877     {
00878     QVector< Rules* > ret;
00879     for( QList< Rules* >::Iterator it = rules.begin();
00880          it != rules.end();
00881          )
00882         {
00883         if( ignore_temporary && (*it)->isTemporary())
00884             {
00885             ++it;
00886             continue;
00887             }
00888         if( (*it)->match( c ))
00889             {
00890             Rules* rule = *it;
00891             kDebug( 1212 ) << "Rule found:" << rule << ":" << c;
00892             if( rule->isTemporary())
00893                 it = rules.erase( it );
00894             else
00895                 ++it;
00896             ret.append( rule );
00897             continue;
00898             }
00899         ++it;
00900         }
00901     return WindowRules( ret );
00902     }
00903 
00904 void Workspace::editWindowRules( Client* c, bool whole_app )
00905     {
00906     writeWindowRules();
00907     QStringList args;
00908     args << "--wid" << QString::number( c->window());
00909     if( whole_app )
00910         args << "--whole-app";
00911     KToolInvocation::kdeinitExec( "kwin_rules_dialog", args );
00912     }
00913 
00914 void Workspace::loadWindowRules()
00915     {
00916     while( !rules.isEmpty())
00917         {
00918         delete rules.front();
00919         rules.pop_front();
00920         }
00921     KConfig cfg( "kwinrulesrc", KConfig::NoGlobals );
00922     int count = cfg.group("General").readEntry( "count",0 );
00923     for( int i = 1;
00924          i <= count;
00925          ++i )
00926         {
00927             KConfigGroup cg( &cfg, QString::number( i ));
00928             Rules* rule = new Rules( cg );
00929             rules.append( rule );
00930         }
00931     }
00932 
00933 void Workspace::writeWindowRules()
00934     {
00935     rulesUpdatedTimer.stop();
00936     KConfig cfg( "kwinrulesrc", KConfig::NoGlobals );
00937     QStringList groups = cfg.groupList();
00938     for( QStringList::ConstIterator it = groups.begin();
00939          it != groups.end();
00940          ++it )
00941         cfg.deleteGroup( *it );
00942     cfg.group("General").writeEntry( "count", rules.count());
00943     int i = 1;
00944     for( QList< Rules* >::ConstIterator it = rules.begin();
00945          it != rules.end();
00946          ++it )
00947         {
00948         if( (*it)->isTemporary())
00949             continue;
00950         KConfigGroup cg( &cfg, QString::number( i ));
00951         (*it)->write( cg );
00952         ++i;
00953         }
00954     }
00955 
00956 void Workspace::gotTemporaryRulesMessage( const QString& message )
00957     {
00958     bool was_temporary = false;
00959     for( QList< Rules* >::ConstIterator it = rules.begin();
00960          it != rules.end();
00961          ++it )
00962         if( (*it)->isTemporary())
00963             was_temporary = true;
00964     Rules* rule = new Rules( message, true );
00965     rules.prepend( rule ); // highest priority first
00966     if( !was_temporary )
00967         QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
00968     }
00969 
00970 void Workspace::cleanupTemporaryRules()
00971     {
00972     bool has_temporary = false;
00973     for( QList< Rules* >::Iterator it = rules.begin();
00974          it != rules.end();
00975          )
00976         {
00977         if( (*it)->discardTemporary( false ))
00978             it = rules.erase( it );
00979         else
00980             {
00981             if( (*it)->isTemporary())
00982                 has_temporary = true;
00983             ++it;
00984             }
00985         }
00986     if( has_temporary )
00987         QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
00988     }
00989 
00990 void Workspace::discardUsedWindowRules( Client* c, bool withdrawn )
00991     {
00992     bool updated = false;
00993     for( QList< Rules* >::Iterator it = rules.begin();
00994          it != rules.end();
00995          )
00996         {
00997         if( c->rules()->contains( *it ))
00998             {
00999             updated = true;
01000             (*it)->discardUsed( withdrawn );
01001             if( (*it)->isEmpty())
01002                 {
01003                 c->removeRule( *it );
01004                 Rules* r = *it;
01005                 it = rules.erase( it );
01006                 delete r;
01007                 continue;
01008                 }
01009             }
01010         ++it;
01011         }
01012     if( updated )
01013         rulesUpdated();
01014     }
01015 
01016 void Workspace::rulesUpdated()
01017     {
01018     rulesUpdatedTimer.setSingleShot( true );
01019     rulesUpdatedTimer.start( 1000 );
01020     }
01021 
01022 void Workspace::disableRulesUpdates( bool disable )
01023     {
01024     rules_updates_disabled = disable;
01025     if( !disable )
01026         foreach( Client* c, clients )
01027             c->updateWindowRules();
01028     }
01029 
01030 #endif
01031 
01032 } // namespace

KWin

Skip menu "KWin"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal