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 *********************************************************************/
26 #include <ktemporaryfile.h>
28 #include <ktoolinvocation.h>
32 #include "workspace.h"
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 )
83 QByteArray s
= str
.toUtf8();
84 file
.write( s
.data(), s
.length());
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 )
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 )
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
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 ); \
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 ); \
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 ); \
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
));
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
);
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
))
332 bool Rules::matchWMClass( const QByteArray
& match_class
, const QByteArray
& match_name
) const
334 if( wmclassmatch
!= UnimportantMatch
)
336 QByteArray cwmclass
= wmclasscomplete
337 ? match_name
+ ' ' + match_class
: match_class
;
338 if( wmclassmatch
== RegExpMatch
&& QRegExp( wmclass
).indexIn( cwmclass
) == -1 )
340 if( wmclassmatch
== ExactMatch
&& wmclass
!= cwmclass
)
342 if( wmclassmatch
== SubstringMatch
&& !cwmclass
.contains( wmclass
))
348 bool Rules::matchRole( const QByteArray
& match_role
) const
350 if( windowrolematch
!= UnimportantMatch
)
352 if( windowrolematch
== RegExpMatch
&& QRegExp( windowrole
).indexIn( match_role
) == -1 )
354 if( windowrolematch
== ExactMatch
&& windowrole
!= match_role
)
356 if( windowrolematch
== SubstringMatch
&& !match_role
.contains( windowrole
))
362 bool Rules::matchTitle( const QString
& match_title
) const
364 if( titlematch
!= UnimportantMatch
)
366 if( titlematch
== RegExpMatch
&& QRegExp( title
).indexIn( match_title
) == -1 )
368 if( titlematch
== ExactMatch
&& title
!= match_title
)
370 if( titlematch
== SubstringMatch
&& !match_title
.contains( title
))
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" ))
384 if( clientmachinematch
== RegExpMatch
385 && QRegExp( clientmachine
).indexIn( match_machine
) == -1 )
387 if( clientmachinematch
== ExactMatch
388 && clientmachine
!= match_machine
)
390 if( clientmachinematch
== SubstringMatch
391 && !match_machine
.contains( clientmachine
))
398 bool Rules::match( const Client
* c
) const
400 if( !matchType( c
->windowType( true )))
402 if( !matchWMClass( c
->resourceClass(), c
->resourceName()))
404 if( !matchRole( c
->windowRole()))
406 if( !matchTitle( c
->caption( false )))
409 if( !matchClientMachine( c
->wmClientMachine( false )))
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
;
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
;
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
)
505 if (opacityinactiverule
== ( ForceRule
)Force
)
512 #define APPLY_RULE( var, name, type ) \
513 bool Rules::apply##name( type& arg, bool init ) const \
515 if( checkSetRule( var##rule, init )) \
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 )) \
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
);
540 if( applySize( s
, init
))
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
))
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
))
599 if( this->shade
&& sh
== ShadeNone
)
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 )
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
632 if( force
|| --temporary_state
== 0 ) // too old
640 #define DISCARD_USED_SET_RULE( var ) \
642 if( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) \
643 var##rule = UnusedSetRule; \
645 #define DISCARD_USED_FORCE_RULE( var ) \
647 if( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) \
648 var##rule = UnusedForceRule; \
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
686 kdbgstream
& operator<<( kdbgstream
& stream
, const Rules
* r
)
688 return stream
<< "[" << r
->description
<< ":" << r
->wmclass
<< "]" ;
692 void WindowRules::discardTemporary()
694 QVector
< Rules
* >::Iterator it2
= rules
.begin();
695 for( QVector
< Rules
* >::Iterator it
= rules
.begin();
699 if( (*it
)->discardTemporary( true ))
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();
715 if( (*it
)->update( c
)) // no short-circuiting here
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 ) \
727 for( QVector< Rules* >::ConstIterator it = rules.constBegin(); \
728 it != rules.constEnd(); \
731 if( (*it)->apply##rule( ret, init )) \
737 #define CHECK_FORCE_RULE( rule, type ) \
738 type WindowRules::check##rule( type arg ) const \
740 if( rules.count() == 0 ) \
743 for( QVector< Rules* >::ConstIterator it = rules.begin(); \
747 if( (*it)->apply##rule( 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 )
802 #undef CHECK_FORCE_RULE
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()
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
)
825 // MinSize, MaxSize handled by Geometry
827 setDesktop( desktop());
829 maximize( maximizeMode());
830 // Minimize : functions don't check, and there are two functions
831 if( client_rules
.checkMinimize( isMinimized()))
835 setShade( shadeMode());
836 setSkipTaskbar( skipTaskbar(), true );
837 setSkipPager( skipPager());
838 setKeepAbove( keepAbove());
839 setKeepBelow( keepBelow());
840 setFullScreen( isFullScreen(), true );
841 setNoBorder( noBorder());
844 if( workspace()->mostRecentlyActivatedClient() == this
845 && !client_rules
.checkAcceptFocus( true ))
846 workspace()->activateNextClient( this );
849 QSize s
= adjustedSize();
851 resizeWithChecks( s
);
853 setShortcut( rules()->checkShortcut( shortcut().toString()));
854 // see also Client::setActive()
856 workspace()->disableGlobalShortcutsForClient( rules()->checkDisableGlobalShortcuts( false ));
859 void Client::updateWindowRules()
861 if( !isManaged()) // not fully setup yet
863 if( workspace()->rulesUpdatesDisabled())
865 client_rules
.update( this );
868 void Client::finishWindowRules()
871 client_rules
= WindowRules();
876 WindowRules
Workspace::findWindowRules( const Client
* c
, bool ignore_temporary
)
878 QVector
< Rules
* > ret
;
879 for( QList
< Rules
* >::Iterator it
= rules
.begin();
883 if( ignore_temporary
&& (*it
)->isTemporary())
888 if( (*it
)->match( c
))
891 kDebug( 1212 ) << "Rule found:" << rule
<< ":" << c
;
892 if( rule
->isTemporary())
893 it
= rules
.erase( it
);
901 return WindowRules( ret
);
904 void Workspace::editWindowRules( Client
* c
, bool whole_app
)
908 args
<< "--wid" << QString::number( c
->window());
910 args
<< "--whole-app";
911 KToolInvocation::kdeinitExec( "kwin_rules_dialog", args
);
914 void Workspace::loadWindowRules()
916 while( !rules
.isEmpty())
918 delete rules
.front();
921 KConfig
cfg( "kwinrulesrc", KConfig::NoGlobals
);
922 int count
= cfg
.group("General").readEntry( "count",0 );
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();
941 cfg
.deleteGroup( *it
);
942 cfg
.group("General").writeEntry( "count", rules
.count());
944 for( QList
< Rules
* >::ConstIterator it
= rules
.constBegin();
945 it
!= rules
.constEnd();
948 if( (*it
)->isTemporary())
950 KConfigGroup
cg( &cfg
, QString::number( 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();
962 if( (*it
)->isTemporary())
963 was_temporary
= true;
964 Rules
* rule
= new Rules( message
, true );
965 rules
.prepend( rule
); // highest priority first
967 QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
970 void Workspace::cleanupTemporaryRules()
972 bool has_temporary
= false;
973 for( QList
< Rules
* >::Iterator it
= rules
.begin();
977 if( (*it
)->discardTemporary( false ))
978 it
= rules
.erase( it
);
981 if( (*it
)->isTemporary())
982 has_temporary
= true;
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();
997 if( c
->rules()->contains( *it
))
1000 (*it
)->discardUsed( withdrawn
);
1001 if( (*it
)->isEmpty())
1003 c
->removeRule( *it
);
1005 it
= rules
.erase( it
);
1016 void Workspace::rulesUpdated()
1018 rulesUpdatedTimer
.setSingleShot( true );
1019 rulesUpdatedTimer
.start( 1000 );
1022 void Workspace::disableRulesUpdates( bool disable
)
1024 rules_updates_disabled
= disable
;
1026 foreach( Client
* c
, clients
)
1027 c
->updateWindowRules();