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 <tdeconfig.h> 00015 #include <tqregexp.h> 00016 #include <tdetempfile.h> 00017 #include <ksimpleconfig.h> 00018 #include <tqfile.h> 00019 00020 #ifndef KCMRULES 00021 #include "client.h" 00022 #include "workspace.h" 00023 #endif 00024 00025 namespace KWinInternal 00026 { 00027 00028 Rules::Rules() 00029 : temporary_state( 0 ) 00030 , wmclassmatch( UnimportantMatch ) 00031 , wmclasscomplete( UnimportantMatch ) 00032 , windowrolematch( UnimportantMatch ) 00033 , titlematch( UnimportantMatch ) 00034 , extrarolematch( UnimportantMatch ) 00035 , clientmachinematch( UnimportantMatch ) 00036 , types( NET::AllTypesMask ) 00037 , placementrule( UnusedForceRule ) 00038 , positionrule( UnusedSetRule ) 00039 , sizerule( UnusedSetRule ) 00040 , minsizerule( UnusedForceRule ) 00041 , maxsizerule( UnusedForceRule ) 00042 , opacityactiverule( UnusedForceRule ) 00043 , opacityinactiverule( UnusedForceRule ) 00044 , ignorepositionrule( UnusedForceRule ) 00045 , desktoprule( UnusedSetRule ) 00046 , typerule( UnusedForceRule ) 00047 , maximizevertrule( UnusedSetRule ) 00048 , maximizehorizrule( UnusedSetRule ) 00049 , minimizerule( UnusedSetRule ) 00050 , shaderule( UnusedSetRule ) 00051 , skiptaskbarrule( UnusedSetRule ) 00052 , skippagerrule( UnusedSetRule ) 00053 , aboverule( UnusedSetRule ) 00054 , belowrule( UnusedSetRule ) 00055 , fullscreenrule( UnusedSetRule ) 00056 , noborderrule( UnusedSetRule ) 00057 , fsplevelrule( UnusedForceRule ) 00058 , acceptfocusrule( UnusedForceRule ) 00059 , moveresizemoderule( UnusedForceRule ) 00060 , closeablerule( UnusedForceRule ) 00061 , strictgeometryrule( UnusedForceRule ) 00062 , shortcutrule( UnusedSetRule ) 00063 , disableglobalshortcutsrule( UnusedForceRule ) 00064 { 00065 } 00066 00067 Rules::Rules( const TQString& str, bool temporary ) 00068 : temporary_state( temporary ? 2 : 0 ) 00069 { 00070 KTempFile file; 00071 TQFile* f = file.file(); 00072 if( f != NULL ) 00073 { 00074 TQCString s = str.utf8(); 00075 f->writeBlock( s.data(), s.length()); 00076 } 00077 file.close(); 00078 KSimpleConfig cfg( file.name()); 00079 readFromCfg( cfg ); 00080 if( description.isEmpty()) 00081 description = "temporary"; 00082 file.unlink(); 00083 } 00084 00085 #define READ_MATCH_STRING( var, func ) \ 00086 var = cfg.readEntry( #var ) func; \ 00087 var##match = (StringMatch) TQMAX( FirstStringMatch, TQMIN( LastStringMatch, cfg.readNumEntry( #var "match" ))); 00088 00089 #define READ_SET_RULE( var, type, func ) \ 00090 var = func ( cfg.read##type##Entry( #var )); \ 00091 var##rule = readSetRule( cfg, #var "rule" ); 00092 00093 #define READ_SET_RULE_DEF( var, type, func, def ) \ 00094 var = func ( cfg.read##type##Entry( #var, def )); \ 00095 var##rule = readSetRule( cfg, #var "rule" ); 00096 00097 #define READ_SET_RULE_2( var, type, func, funcarg ) \ 00098 var = func ( cfg.read##type##Entry( #var ), funcarg ); \ 00099 var##rule = readSetRule( cfg, #var "rule" ); 00100 00101 #define READ_FORCE_RULE( var, type, func ) \ 00102 var = func ( cfg.read##type##Entry( #var )); \ 00103 var##rule = readForceRule( cfg, #var "rule" ); 00104 00105 #define READ_FORCE_RULE_2( var, type, func, funcarg ) \ 00106 var = func ( cfg.read##type##Entry( #var ), funcarg ); \ 00107 var##rule = readForceRule( cfg, #var "rule" ); 00108 00109 00110 Rules::Rules( TDEConfig& cfg ) 00111 : temporary_state( 0 ) 00112 { 00113 readFromCfg( cfg ); 00114 } 00115 00116 static int limit0to4( int i ) { return TQMAX( 0, TQMIN( 4, i )); } 00117 00118 void Rules::readFromCfg( TDEConfig& cfg ) 00119 { 00120 description = cfg.readEntry( "Description" ); 00121 if( description.isEmpty()) // capitalized first, lowercase for backwards compatibility 00122 description = cfg.readEntry( "description" ); 00123 READ_MATCH_STRING( wmclass, .lower().latin1() ); 00124 wmclasscomplete = cfg.readBoolEntry( "wmclasscomplete" ); 00125 READ_MATCH_STRING( windowrole, .lower().latin1() ); 00126 READ_MATCH_STRING( title, ); 00127 READ_MATCH_STRING( extrarole, .lower().latin1() ); 00128 READ_MATCH_STRING( clientmachine, .lower().latin1() ); 00129 types = cfg.readUnsignedLongNumEntry( "types", NET::AllTypesMask ); 00130 READ_FORCE_RULE_2( placement,, Placement::policyFromString, false ); 00131 READ_SET_RULE_DEF( position, Point,, &invalidPoint ); 00132 READ_SET_RULE( size, Size, ); 00133 if( size.isEmpty() && sizerule != ( SetRule )Remember) 00134 sizerule = UnusedSetRule; 00135 READ_FORCE_RULE( minsize, Size, ); 00136 if( !minsize.isValid()) 00137 minsize = TQSize( 1, 1 ); 00138 READ_FORCE_RULE( maxsize, Size, ); 00139 if( maxsize.isEmpty()) 00140 maxsize = TQSize( 32767, 32767 ); 00141 READ_FORCE_RULE( opacityactive, Num, ); 00142 if( opacityactive < 0 || opacityactive > 100 ) 00143 opacityactive = 100; 00144 READ_FORCE_RULE( opacityinactive, Num, ); 00145 if( opacityinactive < 0 || opacityinactive > 100 ) 00146 opacityinactive = 100; 00147 READ_FORCE_RULE( ignoreposition, Bool, ); 00148 READ_SET_RULE( desktop, Num, ); 00149 type = readType( cfg, "type" ); 00150 typerule = type != NET::Unknown ? readForceRule( cfg, "typerule" ) : UnusedForceRule; 00151 READ_SET_RULE( maximizevert, Bool, ); 00152 READ_SET_RULE( maximizehoriz, Bool, ); 00153 READ_SET_RULE( minimize, Bool, ); 00154 READ_SET_RULE( shade, Bool, ); 00155 READ_SET_RULE( skiptaskbar, Bool, ); 00156 READ_SET_RULE( skippager, Bool, ); 00157 READ_SET_RULE( above, Bool, ); 00158 READ_SET_RULE( below, Bool, ); 00159 READ_SET_RULE( fullscreen, Bool, ); 00160 READ_SET_RULE( noborder, Bool, ); 00161 READ_FORCE_RULE( fsplevel, Num, limit0to4 ); // fsp is 0-4 00162 READ_FORCE_RULE( acceptfocus, Bool, ); 00163 READ_FORCE_RULE( moveresizemode, , Options::stringToMoveResizeMode ); 00164 READ_FORCE_RULE( closeable, Bool, ); 00165 READ_FORCE_RULE( strictgeometry, Bool, ); 00166 READ_SET_RULE( shortcut, , ); 00167 READ_FORCE_RULE( disableglobalshortcuts, Bool, ); 00168 } 00169 00170 #undef READ_MATCH_STRING 00171 #undef READ_SET_RULE 00172 #undef READ_SET_RULE_2 00173 #undef READ_FORCE_RULE 00174 #undef READ_FORCE_RULE_2 00175 00176 #define WRITE_MATCH_STRING( var, cast, force ) \ 00177 if( !var.isEmpty() || force ) \ 00178 { \ 00179 cfg.writeEntry( #var, cast var ); \ 00180 cfg.writeEntry( #var "match", var##match ); \ 00181 } \ 00182 else \ 00183 { \ 00184 cfg.deleteEntry( #var ); \ 00185 cfg.deleteEntry( #var "match" ); \ 00186 } 00187 00188 #define WRITE_SET_RULE( var, func ) \ 00189 if( var##rule != UnusedSetRule ) \ 00190 { \ 00191 cfg.writeEntry( #var, func ( var )); \ 00192 cfg.writeEntry( #var "rule", var##rule ); \ 00193 } \ 00194 else \ 00195 { \ 00196 cfg.deleteEntry( #var ); \ 00197 cfg.deleteEntry( #var "rule" ); \ 00198 } 00199 00200 #define WRITE_FORCE_RULE( var, func ) \ 00201 if( var##rule != UnusedForceRule ) \ 00202 { \ 00203 cfg.writeEntry( #var, func ( var )); \ 00204 cfg.writeEntry( #var "rule", var##rule ); \ 00205 } \ 00206 else \ 00207 { \ 00208 cfg.deleteEntry( #var ); \ 00209 cfg.deleteEntry( #var "rule" ); \ 00210 } 00211 00212 #define WRITE_WITH_DEFAULT( var, default ) \ 00213 if( var != default ) \ 00214 cfg.writeEntry( #var, var ); \ 00215 else \ 00216 cfg.deleteEntry( #var ); 00217 00218 00219 void Rules::write( TDEConfig& cfg ) const 00220 { 00221 cfg.writeEntry( "Description", description ); 00222 // always write wmclass 00223 WRITE_MATCH_STRING( wmclass, (const char*), true ); 00224 cfg.writeEntry( "wmclasscomplete", wmclasscomplete ); 00225 WRITE_MATCH_STRING( windowrole, (const char*), false ); 00226 WRITE_MATCH_STRING( title,, false ); 00227 WRITE_MATCH_STRING( extrarole, (const char*), false ); 00228 WRITE_MATCH_STRING( clientmachine, (const char*), false ); 00229 WRITE_WITH_DEFAULT( types, NET::AllTypesMask ); 00230 WRITE_FORCE_RULE( placement, Placement::policyToString ); 00231 WRITE_SET_RULE( position, ); 00232 WRITE_SET_RULE( size, ); 00233 WRITE_FORCE_RULE( minsize, ); 00234 WRITE_FORCE_RULE( maxsize, ); 00235 WRITE_FORCE_RULE( opacityactive, ); 00236 WRITE_FORCE_RULE( opacityinactive, ); 00237 WRITE_FORCE_RULE( ignoreposition, ); 00238 WRITE_SET_RULE( desktop, ); 00239 WRITE_FORCE_RULE( type, ); 00240 WRITE_SET_RULE( maximizevert, ); 00241 WRITE_SET_RULE( maximizehoriz, ); 00242 WRITE_SET_RULE( minimize, ); 00243 WRITE_SET_RULE( shade, ); 00244 WRITE_SET_RULE( skiptaskbar, ); 00245 WRITE_SET_RULE( skippager, ); 00246 WRITE_SET_RULE( above, ); 00247 WRITE_SET_RULE( below, ); 00248 WRITE_SET_RULE( fullscreen, ); 00249 WRITE_SET_RULE( noborder, ); 00250 WRITE_FORCE_RULE( fsplevel, ); 00251 WRITE_FORCE_RULE( acceptfocus, ); 00252 WRITE_FORCE_RULE( moveresizemode, Options::moveResizeModeToString ); 00253 WRITE_FORCE_RULE( closeable, ); 00254 WRITE_FORCE_RULE( strictgeometry, ); 00255 WRITE_SET_RULE( shortcut, ); 00256 WRITE_FORCE_RULE( disableglobalshortcuts, ); 00257 } 00258 00259 #undef WRITE_MATCH_STRING 00260 #undef WRITE_SET_RULE 00261 #undef WRITE_FORCE_RULE 00262 #undef WRITE_WITH_DEFAULT 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( TDEConfig& cfg, const TQString& key ) 00297 { 00298 int v = cfg.readNumEntry( key ); 00299 if( v >= DontAffect && v <= ForceTemporarily ) 00300 return static_cast< SetRule >( v ); 00301 return UnusedSetRule; 00302 } 00303 00304 Rules::ForceRule Rules::readForceRule( TDEConfig& cfg, const TQString& key ) 00305 { 00306 int v = cfg.readNumEntry( key ); 00307 if( v == DontAffect || v == Force || v == ForceTemporarily ) 00308 return static_cast< ForceRule >( v ); 00309 return UnusedForceRule; 00310 } 00311 00312 NET::WindowType Rules::readType( TDEConfig& cfg, const TQString& key ) 00313 { 00314 int v = cfg.readNumEntry( key ); 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 TQCString& match_class, const TQCString& match_name ) const 00333 { 00334 if( wmclassmatch != UnimportantMatch ) 00335 { // TODO optimize? 00336 TQCString cwmclass = wmclasscomplete 00337 ? match_name + ' ' + match_class : match_class; 00338 if( wmclassmatch == RegExpMatch && TQRegExp( wmclass ).search( 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 TQCString& match_role ) const 00349 { 00350 if( windowrolematch != UnimportantMatch ) 00351 { 00352 if( windowrolematch == RegExpMatch && TQRegExp( windowrole ).search( 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 TQString& match_title ) const 00363 { 00364 if( titlematch != UnimportantMatch ) 00365 { 00366 if( titlematch == RegExpMatch && TQRegExp( title ).search( 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 TQCString& 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 && TQRegExp( clientmachine ).search( 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 TQPoint 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 TQSize 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->isUserNoBorder(); 00499 noborder = c->isUserNoBorder(); 00500 } 00501 if (opacityactiverule == ( ForceRule )Force) 00502 { 00503 updated = updated || (uint) (opacityactive/100.0*0xffffffff) != c->ruleOpacityActive(); 00504 opacityactive = (uint)(((double)c->ruleOpacityActive())/0xffffffff*100); 00505 } 00506 if (opacityinactiverule == ( ForceRule )Force) 00507 { 00508 updated = updated || (uint) (opacityinactive/100.0*0xffffffff) != c->ruleOpacityInactive(); 00509 opacityinactive = (uint)(((double)c->ruleOpacityInactive())/0xffffffff*100); 00510 } 00511 return updated; 00512 } 00513 00514 #define APPLY_RULE( var, name, type ) \ 00515 bool Rules::apply##name( type& arg, bool init ) const \ 00516 { \ 00517 if( checkSetRule( var##rule, init )) \ 00518 arg = this->var; \ 00519 return checkSetStop( var##rule ); \ 00520 } 00521 00522 #define APPLY_FORCE_RULE( var, name, type ) \ 00523 bool Rules::apply##name( type& arg ) const \ 00524 { \ 00525 if( checkForceRule( var##rule )) \ 00526 arg = this->var; \ 00527 return checkForceStop( var##rule ); \ 00528 } 00529 00530 APPLY_FORCE_RULE( placement, Placement, Placement::Policy ) 00531 00532 bool Rules::applyGeometry( TQRect& rect, bool init ) const 00533 { 00534 TQPoint p = rect.topLeft(); 00535 TQSize s = rect.size(); 00536 bool ret = false; // no short-circuiting 00537 if( applyPosition( p, init )) 00538 { 00539 rect.moveTopLeft( p ); 00540 ret = true; 00541 } 00542 if( applySize( s, init )) 00543 { 00544 rect.setSize( s ); 00545 ret = true; 00546 } 00547 return ret; 00548 } 00549 00550 bool Rules::applyPosition( TQPoint& pos, bool init ) const 00551 { 00552 if( this->position != invalidPoint && checkSetRule( positionrule, init )) 00553 pos = this->position; 00554 return checkSetStop( positionrule ); 00555 } 00556 00557 bool Rules::applySize( TQSize& s, bool init ) const 00558 { 00559 if( this->size.isValid() && checkSetRule( sizerule, init )) 00560 s = this->size; 00561 return checkSetStop( sizerule ); 00562 } 00563 00564 APPLY_FORCE_RULE( minsize, MinSize, TQSize ) 00565 APPLY_FORCE_RULE( maxsize, MaxSize, TQSize ) 00566 APPLY_FORCE_RULE( opacityactive, OpacityActive, int ) 00567 APPLY_FORCE_RULE( opacityinactive, OpacityInactive, int ) 00568 APPLY_FORCE_RULE( ignoreposition, IgnorePosition, bool ) 00569 00570 // the cfg. entry needs to stay named the say for backwards compatibility 00571 bool Rules::applyIgnoreGeometry( bool& ignore ) const 00572 { 00573 return applyIgnorePosition( ignore ); 00574 } 00575 00576 APPLY_RULE( desktop, Desktop, int ) 00577 APPLY_FORCE_RULE( type, Type, NET::WindowType ) 00578 00579 bool Rules::applyMaximizeHoriz( MaximizeMode& mode, bool init ) const 00580 { 00581 if( checkSetRule( maximizehorizrule, init )) 00582 mode = static_cast< MaximizeMode >(( maximizehoriz ? MaximizeHorizontal : 0 ) | ( mode & MaximizeVertical )); 00583 return checkSetStop( maximizehorizrule ); 00584 } 00585 00586 bool Rules::applyMaximizeVert( MaximizeMode& mode, bool init ) const 00587 { 00588 if( checkSetRule( maximizevertrule, init )) 00589 mode = static_cast< MaximizeMode >(( maximizevert ? MaximizeVertical : 0 ) | ( mode & MaximizeHorizontal )); 00590 return checkSetStop( maximizevertrule ); 00591 } 00592 00593 APPLY_RULE( minimize, Minimize, bool ) 00594 00595 bool Rules::applyShade( ShadeMode& sh, bool init ) const 00596 { 00597 if( checkSetRule( shaderule, init )) 00598 { 00599 if( !this->shade ) 00600 sh = ShadeNone; 00601 if( this->shade && sh == ShadeNone ) 00602 sh = ShadeNormal; 00603 } 00604 return checkSetStop( shaderule ); 00605 } 00606 00607 APPLY_RULE( skiptaskbar, SkipTaskbar, bool ) 00608 APPLY_RULE( skippager, SkipPager, bool ) 00609 APPLY_RULE( above, KeepAbove, bool ) 00610 APPLY_RULE( below, KeepBelow, bool ) 00611 APPLY_RULE( fullscreen, FullScreen, bool ) 00612 APPLY_RULE( noborder, NoBorder, bool ) 00613 APPLY_FORCE_RULE( fsplevel, FSP, int ) 00614 APPLY_FORCE_RULE( acceptfocus, AcceptFocus, bool ) 00615 APPLY_FORCE_RULE( moveresizemode, MoveResizeMode, Options::MoveResizeMode ) 00616 APPLY_FORCE_RULE( closeable, Closeable, bool ) 00617 APPLY_FORCE_RULE( strictgeometry, StrictGeometry, bool ) 00618 APPLY_RULE( shortcut, Shortcut, TQString ) 00619 APPLY_FORCE_RULE( disableglobalshortcuts, DisableGlobalShortcuts, bool ) 00620 00621 00622 #undef APPLY_RULE 00623 #undef APPLY_FORCE_RULE 00624 00625 bool Rules::isTemporary() const 00626 { 00627 return temporary_state > 0; 00628 } 00629 00630 bool Rules::discardTemporary( bool force ) 00631 { 00632 if( temporary_state == 0 ) // not temporary 00633 return false; 00634 if( force || --temporary_state == 0 ) // too old 00635 { 00636 delete this; 00637 return true; 00638 } 00639 return false; 00640 } 00641 00642 #define DISCARD_USED_SET_RULE( var ) \ 00643 do { \ 00644 if( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) \ 00645 var##rule = UnusedSetRule; \ 00646 } while( false ) 00647 #define DISCARD_USED_FORCE_RULE( var ) \ 00648 do { \ 00649 if( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) \ 00650 var##rule = UnusedForceRule; \ 00651 } while( false ) 00652 00653 void Rules::discardUsed( bool withdrawn ) 00654 { 00655 DISCARD_USED_FORCE_RULE( placement ); 00656 DISCARD_USED_SET_RULE( position ); 00657 DISCARD_USED_SET_RULE( size ); 00658 DISCARD_USED_FORCE_RULE( minsize ); 00659 DISCARD_USED_FORCE_RULE( maxsize ); 00660 DISCARD_USED_FORCE_RULE( opacityactive ); 00661 DISCARD_USED_FORCE_RULE( opacityinactive ); 00662 DISCARD_USED_FORCE_RULE( ignoreposition ); 00663 DISCARD_USED_SET_RULE( desktop ); 00664 DISCARD_USED_FORCE_RULE( type ); 00665 DISCARD_USED_SET_RULE( maximizevert ); 00666 DISCARD_USED_SET_RULE( maximizehoriz ); 00667 DISCARD_USED_SET_RULE( minimize ); 00668 DISCARD_USED_SET_RULE( shade ); 00669 DISCARD_USED_SET_RULE( skiptaskbar ); 00670 DISCARD_USED_SET_RULE( skippager ); 00671 DISCARD_USED_SET_RULE( above ); 00672 DISCARD_USED_SET_RULE( below ); 00673 DISCARD_USED_SET_RULE( fullscreen ); 00674 DISCARD_USED_SET_RULE( noborder ); 00675 DISCARD_USED_FORCE_RULE( fsplevel ); 00676 DISCARD_USED_FORCE_RULE( acceptfocus ); 00677 DISCARD_USED_FORCE_RULE( moveresizemode ); 00678 DISCARD_USED_FORCE_RULE( closeable ); 00679 DISCARD_USED_FORCE_RULE( strictgeometry ); 00680 DISCARD_USED_SET_RULE( shortcut ); 00681 DISCARD_USED_FORCE_RULE( disableglobalshortcuts ); 00682 } 00683 #undef DISCARD_USED_SET_RULE 00684 #undef DISCARD_USED_FORCE_RULE 00685 00686 #endif 00687 00688 #ifndef NDEBUG 00689 kdbgstream& operator<<( kdbgstream& stream, const Rules* r ) 00690 { 00691 return stream << "[" << r->description << ":" << r->wmclass << "]" ; 00692 } 00693 #endif 00694 00695 #ifndef KCMRULES 00696 void WindowRules::discardTemporary() 00697 { 00698 TQValueVector< Rules* >::Iterator it2 = rules.begin(); 00699 for( TQValueVector< Rules* >::Iterator it = rules.begin(); 00700 it != rules.end(); 00701 ) 00702 { 00703 if( (*it)->discardTemporary( true )) 00704 ++it; 00705 else 00706 { 00707 *it2++ = *it++; 00708 } 00709 } 00710 rules.erase( it2, rules.end()); 00711 } 00712 00713 void WindowRules::update( Client* c ) 00714 { 00715 bool updated = false; 00716 for( TQValueVector< Rules* >::ConstIterator it = rules.begin(); 00717 it != rules.end(); 00718 ++it ) 00719 if( (*it)->update( c )) // no short-circuiting here 00720 updated = true; 00721 if( updated ) 00722 Workspace::self()->rulesUpdated(); 00723 } 00724 00725 #define CHECK_RULE( rule, type ) \ 00726 type WindowRules::check##rule( type arg, bool init ) const \ 00727 { \ 00728 if( rules.count() == 0 ) \ 00729 return arg; \ 00730 type ret = arg; \ 00731 for( TQValueVector< Rules* >::ConstIterator it = rules.begin(); \ 00732 it != rules.end(); \ 00733 ++it ) \ 00734 { \ 00735 if( (*it)->apply##rule( ret, init )) \ 00736 break; \ 00737 } \ 00738 return ret; \ 00739 } 00740 00741 #define CHECK_FORCE_RULE( rule, type ) \ 00742 type WindowRules::check##rule( type arg ) const \ 00743 { \ 00744 if( rules.count() == 0 ) \ 00745 return arg; \ 00746 type ret = arg; \ 00747 for( TQValueVector< Rules* >::ConstIterator it = rules.begin(); \ 00748 it != rules.end(); \ 00749 ++it ) \ 00750 { \ 00751 if( (*it)->apply##rule( ret )) \ 00752 break; \ 00753 } \ 00754 return ret; \ 00755 } 00756 00757 CHECK_FORCE_RULE( Placement, Placement::Policy ) 00758 00759 TQRect WindowRules::checkGeometry( TQRect rect, bool init ) const 00760 { 00761 return TQRect( checkPosition( rect.topLeft(), init ), checkSize( rect.size(), init )); 00762 } 00763 00764 CHECK_RULE( Position, TQPoint ) 00765 CHECK_RULE( Size, TQSize ) 00766 CHECK_FORCE_RULE( MinSize, TQSize ) 00767 CHECK_FORCE_RULE( MaxSize, TQSize ) 00768 CHECK_FORCE_RULE( OpacityActive, int ) 00769 CHECK_FORCE_RULE( OpacityInactive, int ) 00770 CHECK_FORCE_RULE( IgnorePosition, bool ) 00771 00772 bool WindowRules::checkIgnoreGeometry( bool ignore ) const 00773 { 00774 return checkIgnorePosition( ignore ); 00775 } 00776 00777 CHECK_RULE( Desktop, int ) 00778 CHECK_FORCE_RULE( Type, NET::WindowType ) 00779 CHECK_RULE( MaximizeVert, KDecorationDefines::MaximizeMode ) 00780 CHECK_RULE( MaximizeHoriz, KDecorationDefines::MaximizeMode ) 00781 00782 KDecorationDefines::MaximizeMode WindowRules::checkMaximize( MaximizeMode mode, bool init ) const 00783 { 00784 bool vert = checkMaximizeVert( mode, init ) & MaximizeVertical; 00785 bool horiz = checkMaximizeHoriz( mode, init ) & MaximizeHorizontal; 00786 return static_cast< MaximizeMode >(( vert ? MaximizeVertical : 0 ) | ( horiz ? MaximizeHorizontal : 0 )); 00787 } 00788 00789 CHECK_RULE( Minimize, bool ) 00790 CHECK_RULE( Shade, ShadeMode ) 00791 CHECK_RULE( SkipTaskbar, bool ) 00792 CHECK_RULE( SkipPager, bool ) 00793 CHECK_RULE( KeepAbove, bool ) 00794 CHECK_RULE( KeepBelow, bool ) 00795 CHECK_RULE( FullScreen, bool ) 00796 CHECK_RULE( NoBorder, bool ) 00797 CHECK_FORCE_RULE( FSP, int ) 00798 CHECK_FORCE_RULE( AcceptFocus, bool ) 00799 CHECK_FORCE_RULE( MoveResizeMode, Options::MoveResizeMode ) 00800 CHECK_FORCE_RULE( Closeable, bool ) 00801 CHECK_FORCE_RULE( StrictGeometry, bool ) 00802 CHECK_RULE( Shortcut, TQString ) 00803 CHECK_FORCE_RULE( DisableGlobalShortcuts, bool ) 00804 00805 #undef CHECK_RULE 00806 #undef CHECK_FORCE_RULE 00807 00808 // Client 00809 00810 void Client::setupWindowRules( bool ignore_temporary ) 00811 { 00812 client_rules = workspace()->findWindowRules( this, ignore_temporary ); 00813 // check only after getting the rules, because there may be a rule forcing window type 00814 if( isTopMenu()) // TODO cannot have restrictions 00815 client_rules = WindowRules(); 00816 } 00817 00818 // Applies Force, ForceTemporarily and ApplyNow rules 00819 // Used e.g. after the rules have been modified using the kcm. 00820 void Client::applyWindowRules() 00821 { 00822 checkAndSetInitialRuledOpacity(); 00823 // apply force rules 00824 // Placement - does need explicit update, just like some others below 00825 // Geometry : setGeometry() doesn't check rules 00826 TQRect orig_geom = TQRect( pos(), sizeForClientSize( clientSize())); // handle shading 00827 TQRect geom = client_rules.checkGeometry( orig_geom ); 00828 if( geom != orig_geom ) 00829 setGeometry( geom ); 00830 // MinSize, MaxSize handled by Geometry 00831 // IgnorePosition 00832 setDesktop( desktop()); 00833 // Type 00834 maximize( maximizeMode()); 00835 // Minimize : functions don't check, and there are two functions 00836 if( client_rules.checkMinimize( isMinimized())) 00837 minimize(); 00838 else 00839 unminimize(); 00840 setShade( shadeMode()); 00841 setSkipTaskbar( skipTaskbar(), true ); 00842 setSkipPager( skipPager()); 00843 setKeepAbove( keepAbove()); 00844 setKeepBelow( keepBelow()); 00845 setFullScreen( isFullScreen(), true ); 00846 setUserNoBorder( isUserNoBorder()); 00847 // FSP 00848 // AcceptFocus : 00849 if( workspace()->mostRecentlyActivatedClient() == this 00850 && !client_rules.checkAcceptFocus( true )) 00851 workspace()->activateNextClient( this ); 00852 // MoveResizeMode 00853 // Closeable 00854 TQSize s = adjustedSize(); 00855 if( s != size()) 00856 resizeWithChecks( s ); 00857 // StrictGeometry 00858 setShortcut( rules()->checkShortcut( shortcut().toString())); 00859 // see also Client::setActive() 00860 if( isActive()) 00861 workspace()->disableGlobalShortcutsForClient( rules()->checkDisableGlobalShortcuts( false )); 00862 } 00863 00864 void Client::updateWindowRules() 00865 { 00866 if( !isManaged()) // not fully setup yet 00867 return; 00868 if( workspace()->rulesUpdatesDisabled()) 00869 return; 00870 client_rules.update( this ); 00871 } 00872 00873 void Client::finishWindowRules() 00874 { 00875 updateWindowRules(); 00876 client_rules = WindowRules(); 00877 } 00878 00879 void Client::checkAndSetInitialRuledOpacity() 00880 //apply twin-rules for window-translucency upon hitting apply or starting to manage client 00881 { 00882 int tmp; 00883 00884 //active translucency 00885 tmp = -1; 00886 tmp = rules()->checkOpacityActive(tmp); 00887 if( tmp != -1 ) //rule did apply and returns valid value 00888 { 00889 rule_opacity_active = (uint)((tmp/100.0)*0xffffffff); 00890 } 00891 else 00892 rule_opacity_active = 0; 00893 00894 //inactive translucency 00895 tmp = -1; 00896 tmp = rules()->checkOpacityInactive(tmp); 00897 if( tmp != -1 ) //rule did apply and returns valid value 00898 { 00899 rule_opacity_inactive = (uint)((tmp/100.0)*0xffffffff); 00900 } 00901 else 00902 rule_opacity_inactive = 0; 00903 00904 return; 00905 00906 if( isDock() ) 00907 //workaround for docks, as they don't have active/inactive settings and don't aut, therefore we take only the active one... 00908 { 00909 uint tmp = rule_opacity_active ? rule_opacity_active : options->dockOpacity; 00910 setOpacity(tmp < 0xFFFFFFFF && (rule_opacity_active || options->translucentDocks), tmp); 00911 } 00912 else 00913 updateOpacity(); 00914 } 00915 00916 // Workspace 00917 00918 WindowRules Workspace::findWindowRules( const Client* c, bool ignore_temporary ) 00919 { 00920 TQValueVector< Rules* > ret; 00921 for( TQValueList< Rules* >::Iterator it = rules.begin(); 00922 it != rules.end(); 00923 ) 00924 { 00925 if( ignore_temporary && (*it)->isTemporary()) 00926 { 00927 ++it; 00928 continue; 00929 } 00930 if( (*it)->match( c )) 00931 { 00932 Rules* rule = *it; 00933 kdDebug( 1212 ) << "Rule found:" << rule << ":" << c << endl; 00934 if( rule->isTemporary()) 00935 it = rules.remove( it ); 00936 else 00937 ++it; 00938 ret.append( rule ); 00939 continue; 00940 } 00941 ++it; 00942 } 00943 return WindowRules( ret ); 00944 } 00945 00946 void Workspace::editWindowRules( Client* c, bool whole_app ) 00947 { 00948 writeWindowRules(); 00949 TQStringList args; 00950 args << "--wid" << TQString::number( c->window()); 00951 if( whole_app ) 00952 args << "--whole-app"; 00953 TDEApplication::tdeinitExec( "twin_rules_dialog", args ); 00954 } 00955 00956 void Workspace::loadWindowRules() 00957 { 00958 while( !rules.isEmpty()) 00959 { 00960 delete rules.front(); 00961 rules.pop_front(); 00962 } 00963 TDEConfig cfg( "twinrulesrc", true ); 00964 cfg.setGroup( "General" ); 00965 int count = cfg.readNumEntry( "count" ); 00966 for( int i = 1; 00967 i <= count; 00968 ++i ) 00969 { 00970 cfg.setGroup( TQString::number( i )); 00971 Rules* rule = new Rules( cfg ); 00972 rules.append( rule ); 00973 } 00974 } 00975 00976 void Workspace::writeWindowRules() 00977 { 00978 rulesUpdatedTimer.stop(); 00979 TDEConfig cfg( "twinrulesrc" ); 00980 TQStringList groups = cfg.groupList(); 00981 for( TQStringList::ConstIterator it = groups.begin(); 00982 it != groups.end(); 00983 ++it ) 00984 cfg.deleteGroup( *it ); 00985 cfg.setGroup( "General" ); 00986 cfg.writeEntry( "count", rules.count()); 00987 int i = 1; 00988 for( TQValueList< Rules* >::ConstIterator it = rules.begin(); 00989 it != rules.end(); 00990 ++it ) 00991 { 00992 if( (*it)->isTemporary()) 00993 continue; 00994 cfg.setGroup( TQString::number( i )); 00995 (*it)->write( cfg ); 00996 ++i; 00997 } 00998 } 00999 01000 void Workspace::gotTemporaryRulesMessage( const TQString& message ) 01001 { 01002 bool was_temporary = false; 01003 for( TQValueList< Rules* >::ConstIterator it = rules.begin(); 01004 it != rules.end(); 01005 ++it ) 01006 if( (*it)->isTemporary()) 01007 was_temporary = true; 01008 Rules* rule = new Rules( message, true ); 01009 rules.prepend( rule ); // highest priority first 01010 if( !was_temporary ) 01011 TQTimer::singleShot( 60000, this, TQT_SLOT( cleanupTemporaryRules())); 01012 } 01013 01014 void Workspace::cleanupTemporaryRules() 01015 { 01016 bool has_temporary = false; 01017 for( TQValueList< Rules* >::Iterator it = rules.begin(); 01018 it != rules.end(); 01019 ) 01020 { 01021 if( (*it)->discardTemporary( false )) 01022 it = rules.remove( it ); 01023 else 01024 { 01025 if( (*it)->isTemporary()) 01026 has_temporary = true; 01027 ++it; 01028 } 01029 } 01030 if( has_temporary ) 01031 TQTimer::singleShot( 60000, this, TQT_SLOT( cleanupTemporaryRules())); 01032 } 01033 01034 void Workspace::discardUsedWindowRules( Client* c, bool withdrawn ) 01035 { 01036 bool updated = false; 01037 for( TQValueList< Rules* >::Iterator it = rules.begin(); 01038 it != rules.end(); 01039 ) 01040 { 01041 if( c->rules()->contains( *it )) 01042 { 01043 updated = true; 01044 (*it)->discardUsed( withdrawn ); 01045 if( (*it)->isEmpty()) 01046 { 01047 c->removeRule( *it ); 01048 Rules* r = *it; 01049 it = rules.remove( it ); 01050 delete r; 01051 continue; 01052 } 01053 } 01054 ++it; 01055 } 01056 if( updated ) 01057 rulesUpdated(); 01058 } 01059 01060 void Workspace::rulesUpdated() 01061 { 01062 rulesUpdatedTimer.start( 1000, true ); 01063 } 01064 01065 void Workspace::disableRulesUpdates( bool disable ) 01066 { 01067 rules_updates_disabled = disable; 01068 if( !disable ) 01069 for( ClientList::ConstIterator it = clients.begin(); 01070 it != clients.end(); 01071 ++it ) 01072 (*it)->updateWindowRules(); 01073 } 01074 01075 #endif 01076 01077 } // namespace