add more spacing
[personal-kdebase.git] / workspace / kwin / rules.cpp
blobd34ec8eec57f9e8f58b7f7778ec3838b8bcd0db0
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2004 Lubos Lunak <l.lunak@kde.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
21 #include "rules.h"
23 #include <fixx11h.h>
24 #include <kconfig.h>
25 #include <QRegExp>
26 #include <ktemporaryfile.h>
27 #include <QFile>
28 #include <ktoolinvocation.h>
30 #ifndef KCMRULES
31 #include "client.h"
32 #include "workspace.h"
33 #endif
35 namespace KWin
38 Rules::Rules()
39 : temporary_state( 0 )
40 , wmclassmatch( UnimportantMatch )
41 , wmclasscomplete( UnimportantMatch )
42 , windowrolematch( UnimportantMatch )
43 , titlematch( UnimportantMatch )
44 , extrarolematch( UnimportantMatch )
45 , clientmachinematch( UnimportantMatch )
46 , types( NET::AllTypesMask )
47 , placementrule( UnusedForceRule )
48 , positionrule( UnusedSetRule )
49 , sizerule( UnusedSetRule )
50 , minsizerule( UnusedForceRule )
51 , maxsizerule( UnusedForceRule )
52 , opacityactiverule( UnusedForceRule )
53 , opacityinactiverule( UnusedForceRule )
54 , ignorepositionrule( UnusedForceRule )
55 , desktoprule( UnusedSetRule )
56 , typerule( UnusedForceRule )
57 , maximizevertrule( UnusedSetRule )
58 , maximizehorizrule( UnusedSetRule )
59 , minimizerule( UnusedSetRule )
60 , shaderule( UnusedSetRule )
61 , skiptaskbarrule( UnusedSetRule )
62 , skippagerrule( UnusedSetRule )
63 , aboverule( UnusedSetRule )
64 , belowrule( UnusedSetRule )
65 , fullscreenrule( UnusedSetRule )
66 , noborderrule( UnusedSetRule )
67 , fsplevelrule( UnusedForceRule )
68 , acceptfocusrule( UnusedForceRule )
69 , moveresizemoderule( UnusedForceRule )
70 , closeablerule( UnusedForceRule )
71 , strictgeometryrule( UnusedForceRule )
72 , shortcutrule( UnusedSetRule )
73 , disableglobalshortcutsrule( UnusedForceRule )
77 Rules::Rules( const QString& str, bool temporary )
78 : temporary_state( temporary ? 2 : 0 )
80 KTemporaryFile file;
81 if( file.open() )
83 QByteArray s = str.toUtf8();
84 file.write( s.data(), s.length());
86 file.flush();
87 KConfig cfg( file.fileName(), KConfig::SimpleConfig);
88 readFromCfg( cfg.group( QString() ) );
89 if( description.isEmpty())
90 description = "temporary";
93 #define READ_MATCH_STRING( var, func ) \
94 var = cfg.readEntry( #var ) func; \
95 var##match = (StringMatch) qMax( FirstStringMatch, \
96 qMin( LastStringMatch, static_cast< StringMatch >( cfg.readEntry( #var "match",0 ))));
98 #define READ_SET_RULE( var, func, def ) \
99 var = func ( cfg.readEntry( #var, def)); \
100 var##rule = readSetRule( cfg, #var "rule" );
102 #define READ_SET_RULE_DEF( var , func, def ) \
103 var = func ( cfg.readEntry( #var, def )); \
104 var##rule = readSetRule( cfg, #var "rule" );
106 #define READ_FORCE_RULE( var, func, def) \
107 var = func ( cfg.readEntry( #var, def)); \
108 var##rule = readForceRule( cfg, #var "rule" );
110 #define READ_FORCE_RULE2( var, def, func, funcarg ) \
111 var = func ( cfg.readEntry( #var, def),funcarg ); \
112 var##rule = readForceRule( cfg, #var "rule" );
116 Rules::Rules( const KConfigGroup& cfg )
117 : temporary_state( 0 )
119 readFromCfg( cfg );
122 static int limit0to4( int i ) { return qMax( 0, qMin( 4, i )); }
124 void Rules::readFromCfg( const KConfigGroup& cfg )
126 description = cfg.readEntry( "Description" );
127 if( description.isEmpty()) // capitalized first, lowercase for backwards compatibility
128 description = cfg.readEntry( "description" );
129 READ_MATCH_STRING( wmclass, .toLower().toLatin1() );
130 wmclasscomplete = cfg.readEntry( "wmclasscomplete" , false);
131 READ_MATCH_STRING( windowrole, .toLower().toLatin1() );
132 READ_MATCH_STRING( title, );
133 READ_MATCH_STRING( extrarole, .toLower().toLatin1() );
134 READ_MATCH_STRING( clientmachine, .toLower().toLatin1() );
135 types = cfg.readEntry( "types", uint(NET::AllTypesMask) );
136 READ_FORCE_RULE2( placement,QString(), Placement::policyFromString,false );
137 READ_SET_RULE_DEF( position, , invalidPoint );
138 READ_SET_RULE( size,, QSize());
139 if( size.isEmpty() && sizerule != ( SetRule )Remember)
140 sizerule = UnusedSetRule;
141 READ_FORCE_RULE( minsize,, QSize());
142 if( !minsize.isValid())
143 minsize = QSize( 1, 1 );
144 READ_FORCE_RULE( maxsize, , QSize());
145 if( maxsize.isEmpty())
146 maxsize = QSize( 32767, 32767 );
147 READ_FORCE_RULE( opacityactive, , 0);
148 if( opacityactive < 0 || opacityactive > 100 )
149 opacityactive = 100;
150 READ_FORCE_RULE( opacityinactive,, 0);
151 if( opacityinactive < 0 || opacityinactive > 100 )
152 opacityinactive = 100;
153 READ_FORCE_RULE( ignoreposition,, false);
154 READ_SET_RULE( desktop,,0 );
155 type = readType( cfg, "type" );
156 typerule = type != NET::Unknown ? readForceRule( cfg, "typerule" ) : UnusedForceRule;
157 READ_SET_RULE( maximizevert,, false);
158 READ_SET_RULE( maximizehoriz,, false);
159 READ_SET_RULE( minimize,, false);
160 READ_SET_RULE( shade,, false);
161 READ_SET_RULE( skiptaskbar,, false);
162 READ_SET_RULE( skippager,, false);
163 READ_SET_RULE( above,, false);
164 READ_SET_RULE( below,, false);
165 READ_SET_RULE( fullscreen,, false);
166 READ_SET_RULE( noborder,,false );
167 READ_FORCE_RULE( fsplevel,limit0to4,0 ); // fsp is 0-4
168 READ_FORCE_RULE( acceptfocus, , false);
169 READ_FORCE_RULE( moveresizemode,Options::stringToMoveResizeMode, QString());
170 READ_FORCE_RULE( closeable, , false);
171 READ_FORCE_RULE( strictgeometry, , false);
172 READ_SET_RULE( shortcut, ,QString() );
173 READ_FORCE_RULE( disableglobalshortcuts, , false);
176 #undef READ_MATCH_STRING
177 #undef READ_SET_RULE
178 #undef READ_FORCE_RULE
179 #undef READ_FORCE_RULE2
181 #define WRITE_MATCH_STRING( var, cast, force ) \
182 if( !var.isEmpty() || force ) \
184 cfg.writeEntry( #var, cast var ); \
185 cfg.writeEntry( #var "match", (int)var##match ); \
187 else \
189 cfg.deleteEntry( #var ); \
190 cfg.deleteEntry( #var "match" ); \
193 #define WRITE_SET_RULE( var, func ) \
194 if( var##rule != UnusedSetRule ) \
196 cfg.writeEntry( #var, func ( var )); \
197 cfg.writeEntry( #var "rule", (int)var##rule ); \
199 else \
201 cfg.deleteEntry( #var ); \
202 cfg.deleteEntry( #var "rule" ); \
205 #define WRITE_FORCE_RULE( var, func ) \
206 if( var##rule != UnusedForceRule ) \
208 cfg.writeEntry( #var, func ( var )); \
209 cfg.writeEntry( #var "rule", (int)var##rule ); \
211 else \
213 cfg.deleteEntry( #var ); \
214 cfg.deleteEntry( #var "rule" ); \
217 void Rules::write( KConfigGroup& cfg ) const
219 cfg.writeEntry( "Description", description );
220 // always write wmclass
221 WRITE_MATCH_STRING( wmclass, (const char*), true );
222 cfg.writeEntry( "wmclasscomplete", wmclasscomplete );
223 WRITE_MATCH_STRING( windowrole, (const char*), false );
224 WRITE_MATCH_STRING( title,, false );
225 WRITE_MATCH_STRING( extrarole, (const char*), false );
226 WRITE_MATCH_STRING( clientmachine, (const char*), false );
227 if (types != NET::AllTypesMask)
228 cfg.writeEntry("types", uint(types));
229 else
230 cfg.deleteEntry("types");
231 WRITE_FORCE_RULE( placement, Placement::policyToString );
232 WRITE_SET_RULE( position, );
233 WRITE_SET_RULE( size, );
234 WRITE_FORCE_RULE( minsize, );
235 WRITE_FORCE_RULE( maxsize, );
236 WRITE_FORCE_RULE( opacityactive, );
237 WRITE_FORCE_RULE( opacityinactive, );
238 WRITE_FORCE_RULE( ignoreposition, );
239 WRITE_SET_RULE( desktop, );
240 WRITE_FORCE_RULE( type, int );
241 WRITE_SET_RULE( maximizevert, );
242 WRITE_SET_RULE( maximizehoriz, );
243 WRITE_SET_RULE( minimize, );
244 WRITE_SET_RULE( shade, );
245 WRITE_SET_RULE( skiptaskbar, );
246 WRITE_SET_RULE( skippager, );
247 WRITE_SET_RULE( above, );
248 WRITE_SET_RULE( below, );
249 WRITE_SET_RULE( fullscreen, );
250 WRITE_SET_RULE( noborder, );
251 WRITE_FORCE_RULE( fsplevel, );
252 WRITE_FORCE_RULE( acceptfocus, );
253 WRITE_FORCE_RULE( moveresizemode, Options::moveResizeModeToString );
254 WRITE_FORCE_RULE( closeable, );
255 WRITE_FORCE_RULE( strictgeometry, );
256 WRITE_SET_RULE( shortcut, );
257 WRITE_FORCE_RULE( disableglobalshortcuts, );
260 #undef WRITE_MATCH_STRING
261 #undef WRITE_SET_RULE
262 #undef WRITE_FORCE_RULE
264 // returns true if it doesn't affect anything
265 bool Rules::isEmpty() const
267 return( placementrule == UnusedForceRule
268 && positionrule == UnusedSetRule
269 && sizerule == UnusedSetRule
270 && minsizerule == UnusedForceRule
271 && maxsizerule == UnusedForceRule
272 && opacityactiverule == UnusedForceRule
273 && opacityinactiverule == UnusedForceRule
274 && ignorepositionrule == UnusedForceRule
275 && desktoprule == UnusedSetRule
276 && typerule == UnusedForceRule
277 && maximizevertrule == UnusedSetRule
278 && maximizehorizrule == UnusedSetRule
279 && minimizerule == UnusedSetRule
280 && shaderule == UnusedSetRule
281 && skiptaskbarrule == UnusedSetRule
282 && skippagerrule == UnusedSetRule
283 && aboverule == UnusedSetRule
284 && belowrule == UnusedSetRule
285 && fullscreenrule == UnusedSetRule
286 && noborderrule == UnusedSetRule
287 && fsplevelrule == UnusedForceRule
288 && acceptfocusrule == UnusedForceRule
289 && moveresizemoderule == UnusedForceRule
290 && closeablerule == UnusedForceRule
291 && strictgeometryrule == UnusedForceRule
292 && shortcutrule == UnusedSetRule
293 && disableglobalshortcutsrule == UnusedForceRule );
296 Rules::SetRule Rules::readSetRule( const KConfigGroup& cfg, const QString& key )
298 int v = cfg.readEntry( key,0 );
299 if( v >= DontAffect && v <= ForceTemporarily )
300 return static_cast< SetRule >( v );
301 return UnusedSetRule;
304 Rules::ForceRule Rules::readForceRule( const KConfigGroup& cfg, const QString& key )
306 int v = cfg.readEntry( key,0 );
307 if( v == DontAffect || v == Force || v == ForceTemporarily )
308 return static_cast< ForceRule >( v );
309 return UnusedForceRule;
312 NET::WindowType Rules::readType( const KConfigGroup& cfg, const QString& key )
314 int v = cfg.readEntry( key,0 );
315 if( v >= NET::Normal && v <= NET::Splash )
316 return static_cast< NET::WindowType >( v );
317 return NET::Unknown;
320 bool Rules::matchType( NET::WindowType match_type ) const
322 if( types != NET::AllTypesMask )
324 if( match_type == NET::Unknown )
325 match_type = NET::Normal; // NET::Unknown->NET::Normal is only here for matching
326 if( !NET::typeMatchesMask( match_type, types ))
327 return false;
329 return true;
332 bool Rules::matchWMClass( const QByteArray& match_class, const QByteArray& match_name ) const
334 if( wmclassmatch != UnimportantMatch )
335 { // TODO optimize?
336 QByteArray cwmclass = wmclasscomplete
337 ? match_name + ' ' + match_class : match_class;
338 if( wmclassmatch == RegExpMatch && QRegExp( wmclass ).indexIn( cwmclass ) == -1 )
339 return false;
340 if( wmclassmatch == ExactMatch && wmclass != cwmclass )
341 return false;
342 if( wmclassmatch == SubstringMatch && !cwmclass.contains( wmclass ))
343 return false;
345 return true;
348 bool Rules::matchRole( const QByteArray& match_role ) const
350 if( windowrolematch != UnimportantMatch )
352 if( windowrolematch == RegExpMatch && QRegExp( windowrole ).indexIn( match_role ) == -1 )
353 return false;
354 if( windowrolematch == ExactMatch && windowrole != match_role )
355 return false;
356 if( windowrolematch == SubstringMatch && !match_role.contains( windowrole ))
357 return false;
359 return true;
362 bool Rules::matchTitle( const QString& match_title ) const
364 if( titlematch != UnimportantMatch )
366 if( titlematch == RegExpMatch && QRegExp( title ).indexIn( match_title ) == -1 )
367 return false;
368 if( titlematch == ExactMatch && title != match_title )
369 return false;
370 if( titlematch == SubstringMatch && !match_title.contains( title ))
371 return false;
373 return true;
376 bool Rules::matchClientMachine( const QByteArray& match_machine ) const
378 if( clientmachinematch != UnimportantMatch )
380 // if it's localhost, check also "localhost" before checking hostname
381 if( match_machine != "localhost" && isLocalMachine( match_machine )
382 && matchClientMachine( "localhost" ))
383 return true;
384 if( clientmachinematch == RegExpMatch
385 && QRegExp( clientmachine ).indexIn( match_machine ) == -1 )
386 return false;
387 if( clientmachinematch == ExactMatch
388 && clientmachine != match_machine )
389 return false;
390 if( clientmachinematch == SubstringMatch
391 && !match_machine.contains( clientmachine ))
392 return false;
394 return true;
397 #ifndef KCMRULES
398 bool Rules::match( const Client* c ) const
400 if( !matchType( c->windowType( true )))
401 return false;
402 if( !matchWMClass( c->resourceClass(), c->resourceName()))
403 return false;
404 if( !matchRole( c->windowRole()))
405 return false;
406 if( !matchTitle( c->caption( false )))
407 return false;
408 // TODO extrarole
409 if( !matchClientMachine( c->wmClientMachine( false )))
410 return false;
411 return true;
414 bool Rules::update( Client* c )
416 // TODO check this setting is for this client ?
417 bool updated = false;
418 if( positionrule == ( SetRule )Remember)
420 if( !c->isFullScreen())
422 QPoint new_pos = position;
423 // don't use the position in the direction which is maximized
424 if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
425 new_pos.setX( c->pos().x());
426 if(( c->maximizeMode() & MaximizeVertical ) == 0 )
427 new_pos.setY( c->pos().y());
428 updated = updated || position != new_pos;
429 position = new_pos;
432 if( sizerule == ( SetRule )Remember)
434 if( !c->isFullScreen())
436 QSize new_size = size;
437 // don't use the position in the direction which is maximized
438 if(( c->maximizeMode() & MaximizeHorizontal ) == 0 )
439 new_size.setWidth( c->size().width());
440 if(( c->maximizeMode() & MaximizeVertical ) == 0 )
441 new_size.setHeight( c->size().height());
442 updated = updated || size != new_size;
443 size = new_size;
446 if( desktoprule == ( SetRule )Remember)
448 updated = updated || desktop != c->desktop();
449 desktop = c->desktop();
451 if( maximizevertrule == ( SetRule )Remember)
453 updated = updated || maximizevert != bool( c->maximizeMode() & MaximizeVertical );
454 maximizevert = c->maximizeMode() & MaximizeVertical;
456 if( maximizehorizrule == ( SetRule )Remember)
458 updated = updated || maximizehoriz != bool( c->maximizeMode() & MaximizeHorizontal );
459 maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
461 if( minimizerule == ( SetRule )Remember)
463 updated = updated || minimize != c->isMinimized();
464 minimize = c->isMinimized();
466 if( shaderule == ( SetRule )Remember)
468 updated = updated || ( shade != ( c->shadeMode() != ShadeNone ));
469 shade = c->shadeMode() != ShadeNone;
471 if( skiptaskbarrule == ( SetRule )Remember)
473 updated = updated || skiptaskbar != c->skipTaskbar();
474 skiptaskbar = c->skipTaskbar();
476 if( skippagerrule == ( SetRule )Remember)
478 updated = updated || skippager != c->skipPager();
479 skippager = c->skipPager();
481 if( aboverule == ( SetRule )Remember)
483 updated = updated || above != c->keepAbove();
484 above = c->keepAbove();
486 if( belowrule == ( SetRule )Remember)
488 updated = updated || below != c->keepBelow();
489 below = c->keepBelow();
491 if( fullscreenrule == ( SetRule )Remember)
493 updated = updated || fullscreen != c->isFullScreen();
494 fullscreen = c->isFullScreen();
496 if( noborderrule == ( SetRule )Remember)
498 updated = updated || noborder != c->noBorder();
499 noborder = c->noBorder();
501 if (opacityactiverule == ( ForceRule )Force)
503 // TODO
505 if (opacityinactiverule == ( ForceRule )Force)
507 // TODO
509 return updated;
512 #define APPLY_RULE( var, name, type ) \
513 bool Rules::apply##name( type& arg, bool init ) const \
515 if( checkSetRule( var##rule, init )) \
516 arg = this->var; \
517 return checkSetStop( var##rule ); \
520 #define APPLY_FORCE_RULE( var, name, type ) \
521 bool Rules::apply##name( type& arg ) const \
523 if( checkForceRule( var##rule )) \
524 arg = this->var; \
525 return checkForceStop( var##rule ); \
528 APPLY_FORCE_RULE( placement, Placement, Placement::Policy )
530 bool Rules::applyGeometry( QRect& rect, bool init ) const
532 QPoint p = rect.topLeft();
533 QSize s = rect.size();
534 bool ret = false; // no short-circuiting
535 if( applyPosition( p, init ))
537 rect.moveTopLeft( p );
538 ret = true;
540 if( applySize( s, init ))
542 rect.setSize( s );
543 ret = true;
545 return ret;
548 bool Rules::applyPosition( QPoint& pos, bool init ) const
550 if( this->position != invalidPoint && checkSetRule( positionrule, init ))
551 pos = this->position;
552 return checkSetStop( positionrule );
555 bool Rules::applySize( QSize& s, bool init ) const
557 if( this->size.isValid() && checkSetRule( sizerule, init ))
558 s = this->size;
559 return checkSetStop( sizerule );
562 APPLY_FORCE_RULE( minsize, MinSize, QSize )
563 APPLY_FORCE_RULE( maxsize, MaxSize, QSize )
564 APPLY_FORCE_RULE( opacityactive, OpacityActive, int )
565 APPLY_FORCE_RULE( opacityinactive, OpacityInactive, int )
566 APPLY_FORCE_RULE( ignoreposition, IgnorePosition, bool )
568 // the cfg. entry needs to stay named the say for backwards compatibility
569 bool Rules::applyIgnoreGeometry( bool& ignore ) const
571 return applyIgnorePosition( ignore );
574 APPLY_RULE( desktop, Desktop, int )
575 APPLY_FORCE_RULE( type, Type, NET::WindowType )
577 bool Rules::applyMaximizeHoriz( MaximizeMode& mode, bool init ) const
579 if( checkSetRule( maximizehorizrule, init ))
580 mode = static_cast< MaximizeMode >(( maximizehoriz ? MaximizeHorizontal : 0 ) | ( mode & MaximizeVertical ));
581 return checkSetStop( maximizehorizrule );
584 bool Rules::applyMaximizeVert( MaximizeMode& mode, bool init ) const
586 if( checkSetRule( maximizevertrule, init ))
587 mode = static_cast< MaximizeMode >(( maximizevert ? MaximizeVertical : 0 ) | ( mode & MaximizeHorizontal ));
588 return checkSetStop( maximizevertrule );
591 APPLY_RULE( minimize, Minimize, bool )
593 bool Rules::applyShade( ShadeMode& sh, bool init ) const
595 if( checkSetRule( shaderule, init ))
597 if( !this->shade )
598 sh = ShadeNone;
599 if( this->shade && sh == ShadeNone )
600 sh = ShadeNormal;
602 return checkSetStop( shaderule );
605 APPLY_RULE( skiptaskbar, SkipTaskbar, bool )
606 APPLY_RULE( skippager, SkipPager, bool )
607 APPLY_RULE( above, KeepAbove, bool )
608 APPLY_RULE( below, KeepBelow, bool )
609 APPLY_RULE( fullscreen, FullScreen, bool )
610 APPLY_RULE( noborder, NoBorder, bool )
611 APPLY_FORCE_RULE( fsplevel, FSP, int )
612 APPLY_FORCE_RULE( acceptfocus, AcceptFocus, bool )
613 APPLY_FORCE_RULE( moveresizemode, MoveResizeMode, Options::MoveResizeMode )
614 APPLY_FORCE_RULE( closeable, Closeable, bool )
615 APPLY_FORCE_RULE( strictgeometry, StrictGeometry, bool )
616 APPLY_RULE( shortcut, Shortcut, QString )
617 APPLY_FORCE_RULE( disableglobalshortcuts, DisableGlobalShortcuts, bool )
620 #undef APPLY_RULE
621 #undef APPLY_FORCE_RULE
623 bool Rules::isTemporary() const
625 return temporary_state > 0;
628 bool Rules::discardTemporary( bool force )
630 if( temporary_state == 0 ) // not temporary
631 return false;
632 if( force || --temporary_state == 0 ) // too old
634 delete this;
635 return true;
637 return false;
640 #define DISCARD_USED_SET_RULE( var ) \
641 do { \
642 if( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) \
643 var##rule = UnusedSetRule; \
644 } while( false )
645 #define DISCARD_USED_FORCE_RULE( var ) \
646 do { \
647 if( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) \
648 var##rule = UnusedForceRule; \
649 } while( false )
651 void Rules::discardUsed( bool withdrawn )
653 DISCARD_USED_FORCE_RULE( placement );
654 DISCARD_USED_SET_RULE( position );
655 DISCARD_USED_SET_RULE( size );
656 DISCARD_USED_FORCE_RULE( minsize );
657 DISCARD_USED_FORCE_RULE( maxsize );
658 DISCARD_USED_FORCE_RULE( opacityactive );
659 DISCARD_USED_FORCE_RULE( opacityinactive );
660 DISCARD_USED_FORCE_RULE( ignoreposition );
661 DISCARD_USED_SET_RULE( desktop );
662 DISCARD_USED_FORCE_RULE( type );
663 DISCARD_USED_SET_RULE( maximizevert );
664 DISCARD_USED_SET_RULE( maximizehoriz );
665 DISCARD_USED_SET_RULE( minimize );
666 DISCARD_USED_SET_RULE( shade );
667 DISCARD_USED_SET_RULE( skiptaskbar );
668 DISCARD_USED_SET_RULE( skippager );
669 DISCARD_USED_SET_RULE( above );
670 DISCARD_USED_SET_RULE( below );
671 DISCARD_USED_SET_RULE( fullscreen );
672 DISCARD_USED_SET_RULE( noborder );
673 DISCARD_USED_FORCE_RULE( fsplevel );
674 DISCARD_USED_FORCE_RULE( acceptfocus );
675 DISCARD_USED_FORCE_RULE( moveresizemode );
676 DISCARD_USED_FORCE_RULE( closeable );
677 DISCARD_USED_FORCE_RULE( strictgeometry );
678 DISCARD_USED_SET_RULE( shortcut );
679 DISCARD_USED_FORCE_RULE( disableglobalshortcuts );
681 #undef DISCARD_USED_SET_RULE
682 #undef DISCARD_USED_FORCE_RULE
684 #endif
686 kdbgstream& operator<<( kdbgstream& stream, const Rules* r )
688 return stream << "[" << r->description << ":" << r->wmclass << "]" ;
691 #ifndef KCMRULES
692 void WindowRules::discardTemporary()
694 QVector< Rules* >::Iterator it2 = rules.begin();
695 for( QVector< Rules* >::Iterator it = rules.begin();
696 it != rules.end();
699 if( (*it)->discardTemporary( true ))
700 ++it;
701 else
703 *it2++ = *it++;
706 rules.erase( it2, rules.end());
709 void WindowRules::update( Client* c )
711 bool updated = false;
712 for( QVector< Rules* >::ConstIterator it = rules.constBegin();
713 it != rules.constEnd();
714 ++it )
715 if( (*it)->update( c )) // no short-circuiting here
716 updated = true;
717 if( updated )
718 Workspace::self()->rulesUpdated();
721 #define CHECK_RULE( rule, type ) \
722 type WindowRules::check##rule( type arg, bool init ) const \
724 if( rules.count() == 0 ) \
725 return arg; \
726 type ret = arg; \
727 for( QVector< Rules* >::ConstIterator it = rules.constBegin(); \
728 it != rules.constEnd(); \
729 ++it ) \
731 if( (*it)->apply##rule( ret, init )) \
732 break; \
734 return ret; \
737 #define CHECK_FORCE_RULE( rule, type ) \
738 type WindowRules::check##rule( type arg ) const \
740 if( rules.count() == 0 ) \
741 return arg; \
742 type ret = arg; \
743 for( QVector< Rules* >::ConstIterator it = rules.begin(); \
744 it != rules.end(); \
745 ++it ) \
747 if( (*it)->apply##rule( ret )) \
748 break; \
750 return ret; \
753 CHECK_FORCE_RULE( Placement, Placement::Policy )
755 QRect WindowRules::checkGeometry( QRect rect, bool init ) const
757 return QRect( checkPosition( rect.topLeft(), init ), checkSize( rect.size(), init ));
760 CHECK_RULE( Position, QPoint )
761 CHECK_RULE( Size, QSize )
762 CHECK_FORCE_RULE( MinSize, QSize )
763 CHECK_FORCE_RULE( MaxSize, QSize )
764 CHECK_FORCE_RULE( OpacityActive, int )
765 CHECK_FORCE_RULE( OpacityInactive, int )
766 CHECK_FORCE_RULE( IgnorePosition, bool )
768 bool WindowRules::checkIgnoreGeometry( bool ignore ) const
770 return checkIgnorePosition( ignore );
773 CHECK_RULE( Desktop, int )
774 CHECK_FORCE_RULE( Type, NET::WindowType )
775 CHECK_RULE( MaximizeVert, KDecorationDefines::MaximizeMode )
776 CHECK_RULE( MaximizeHoriz, KDecorationDefines::MaximizeMode )
778 KDecorationDefines::MaximizeMode WindowRules::checkMaximize( MaximizeMode mode, bool init ) const
780 bool vert = checkMaximizeVert( mode, init ) & MaximizeVertical;
781 bool horiz = checkMaximizeHoriz( mode, init ) & MaximizeHorizontal;
782 return static_cast< MaximizeMode >(( vert ? MaximizeVertical : 0 ) | ( horiz ? MaximizeHorizontal : 0 ));
785 CHECK_RULE( Minimize, bool )
786 CHECK_RULE( Shade, ShadeMode )
787 CHECK_RULE( SkipTaskbar, bool )
788 CHECK_RULE( SkipPager, bool )
789 CHECK_RULE( KeepAbove, bool )
790 CHECK_RULE( KeepBelow, bool )
791 CHECK_RULE( FullScreen, bool )
792 CHECK_RULE( NoBorder, bool )
793 CHECK_FORCE_RULE( FSP, int )
794 CHECK_FORCE_RULE( AcceptFocus, bool )
795 CHECK_FORCE_RULE( MoveResizeMode, Options::MoveResizeMode )
796 CHECK_FORCE_RULE( Closeable, bool )
797 CHECK_FORCE_RULE( StrictGeometry, bool )
798 CHECK_RULE( Shortcut, QString )
799 CHECK_FORCE_RULE( DisableGlobalShortcuts, bool )
801 #undef CHECK_RULE
802 #undef CHECK_FORCE_RULE
804 // Client
806 void Client::setupWindowRules( bool ignore_temporary )
808 client_rules = workspace()->findWindowRules( this, ignore_temporary );
809 // check only after getting the rules, because there may be a rule forcing window type
810 if( isTopMenu()) // TODO cannot have restrictions
811 client_rules = WindowRules();
814 // Applies Force, ForceTemporarily and ApplyNow rules
815 // Used e.g. after the rules have been modified using the kcm.
816 void Client::applyWindowRules()
818 // apply force rules
819 // Placement - does need explicit update, just like some others below
820 // Geometry : setGeometry() doesn't check rules
821 QRect orig_geom = QRect( pos(), sizeForClientSize( clientSize())); // handle shading
822 QRect geom = client_rules.checkGeometry( orig_geom );
823 if( geom != orig_geom )
824 setGeometry( geom );
825 // MinSize, MaxSize handled by Geometry
826 // IgnorePosition
827 setDesktop( desktop());
828 // Type
829 maximize( maximizeMode());
830 // Minimize : functions don't check, and there are two functions
831 if( client_rules.checkMinimize( isMinimized()))
832 minimize();
833 else
834 unminimize();
835 setShade( shadeMode());
836 setSkipTaskbar( skipTaskbar(), true );
837 setSkipPager( skipPager());
838 setKeepAbove( keepAbove());
839 setKeepBelow( keepBelow());
840 setFullScreen( isFullScreen(), true );
841 setNoBorder( noBorder());
842 // FSP
843 // AcceptFocus :
844 if( workspace()->mostRecentlyActivatedClient() == this
845 && !client_rules.checkAcceptFocus( true ))
846 workspace()->activateNextClient( this );
847 // MoveResizeMode
848 // Closeable
849 QSize s = adjustedSize();
850 if( s != size())
851 resizeWithChecks( s );
852 // StrictGeometry
853 setShortcut( rules()->checkShortcut( shortcut().toString()));
854 // see also Client::setActive()
855 if( isActive())
856 workspace()->disableGlobalShortcutsForClient( rules()->checkDisableGlobalShortcuts( false ));
859 void Client::updateWindowRules()
861 if( !isManaged()) // not fully setup yet
862 return;
863 if( workspace()->rulesUpdatesDisabled())
864 return;
865 client_rules.update( this );
868 void Client::finishWindowRules()
870 updateWindowRules();
871 client_rules = WindowRules();
874 // Workspace
876 WindowRules Workspace::findWindowRules( const Client* c, bool ignore_temporary )
878 QVector< Rules* > ret;
879 for( QList< Rules* >::Iterator it = rules.begin();
880 it != rules.end();
883 if( ignore_temporary && (*it)->isTemporary())
885 ++it;
886 continue;
888 if( (*it)->match( c ))
890 Rules* rule = *it;
891 kDebug( 1212 ) << "Rule found:" << rule << ":" << c;
892 if( rule->isTemporary())
893 it = rules.erase( it );
894 else
895 ++it;
896 ret.append( rule );
897 continue;
899 ++it;
901 return WindowRules( ret );
904 void Workspace::editWindowRules( Client* c, bool whole_app )
906 writeWindowRules();
907 QStringList args;
908 args << "--wid" << QString::number( c->window());
909 if( whole_app )
910 args << "--whole-app";
911 KToolInvocation::kdeinitExec( "kwin_rules_dialog", args );
914 void Workspace::loadWindowRules()
916 while( !rules.isEmpty())
918 delete rules.front();
919 rules.pop_front();
921 KConfig cfg( "kwinrulesrc", KConfig::NoGlobals );
922 int count = cfg.group("General").readEntry( "count",0 );
923 for( int i = 1;
924 i <= count;
925 ++i )
927 KConfigGroup cg( &cfg, QString::number( i ));
928 Rules* rule = new Rules( cg );
929 rules.append( rule );
933 void Workspace::writeWindowRules()
935 rulesUpdatedTimer.stop();
936 KConfig cfg( "kwinrulesrc", KConfig::NoGlobals );
937 QStringList groups = cfg.groupList();
938 for( QStringList::ConstIterator it = groups.constBegin();
939 it != groups.constEnd();
940 ++it )
941 cfg.deleteGroup( *it );
942 cfg.group("General").writeEntry( "count", rules.count());
943 int i = 1;
944 for( QList< Rules* >::ConstIterator it = rules.constBegin();
945 it != rules.constEnd();
946 ++it )
948 if( (*it)->isTemporary())
949 continue;
950 KConfigGroup cg( &cfg, QString::number( i ));
951 (*it)->write( cg );
952 ++i;
956 void Workspace::gotTemporaryRulesMessage( const QString& message )
958 bool was_temporary = false;
959 for( QList< Rules* >::ConstIterator it = rules.constBegin();
960 it != rules.constEnd();
961 ++it )
962 if( (*it)->isTemporary())
963 was_temporary = true;
964 Rules* rule = new Rules( message, true );
965 rules.prepend( rule ); // highest priority first
966 if( !was_temporary )
967 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
970 void Workspace::cleanupTemporaryRules()
972 bool has_temporary = false;
973 for( QList< Rules* >::Iterator it = rules.begin();
974 it != rules.end();
977 if( (*it)->discardTemporary( false ))
978 it = rules.erase( it );
979 else
981 if( (*it)->isTemporary())
982 has_temporary = true;
983 ++it;
986 if( has_temporary )
987 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
990 void Workspace::discardUsedWindowRules( Client* c, bool withdrawn )
992 bool updated = false;
993 for( QList< Rules* >::Iterator it = rules.begin();
994 it != rules.end();
997 if( c->rules()->contains( *it ))
999 updated = true;
1000 (*it)->discardUsed( withdrawn );
1001 if( (*it)->isEmpty())
1003 c->removeRule( *it );
1004 Rules* r = *it;
1005 it = rules.erase( it );
1006 delete r;
1007 continue;
1010 ++it;
1012 if( updated )
1013 rulesUpdated();
1016 void Workspace::rulesUpdated()
1018 rulesUpdatedTimer.setSingleShot( true );
1019 rulesUpdatedTimer.start( 1000 );
1022 void Workspace::disableRulesUpdates( bool disable )
1024 rules_updates_disabled = disable;
1025 if( !disable )
1026 foreach( Client* c, clients )
1027 c->updateWindowRules();
1030 #endif
1032 } // namespace