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"
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
, tilingoptionrule(UnusedForceRule)
55
, ignorepositionrule(UnusedForceRule)
56
, desktoprule(UnusedSetRule)
57
, typerule(UnusedForceRule)
58
, maximizevertrule(UnusedSetRule)
59
, maximizehorizrule(UnusedSetRule)
60
, minimizerule(UnusedSetRule)
61
, shaderule(UnusedSetRule)
62
, skiptaskbarrule(UnusedSetRule)
63
, skippagerrule(UnusedSetRule)
64
, skipswitcherrule(UnusedSetRule)
65
, aboverule(UnusedSetRule)
66
, belowrule(UnusedSetRule)
67
, fullscreenrule(UnusedSetRule)
68
, noborderrule(UnusedSetRule)
69
, blockcompositingrule(UnusedForceRule)
70
, fsplevelrule(UnusedForceRule)
71
, acceptfocusrule(UnusedForceRule)
72
, moveresizemoderule(UnusedForceRule)
73
, closeablerule(UnusedForceRule)
74
, autogrouprule(UnusedForceRule)
75
, autogroupfgrule(UnusedForceRule)
76
, autogroupidrule(UnusedForceRule)
77
, strictgeometryrule(UnusedForceRule)
78
, shortcutrule(UnusedSetRule)
79
, disableglobalshortcutsrule(UnusedForceRule)
83
Rules::Rules(const QString& str, bool temporary)
84
: temporary_state(temporary ? 2 : 0)
88
QByteArray s = str.toUtf8();
89
file.write(s.data(), s.length());
92
KConfig cfg(file.fileName(), KConfig::SimpleConfig);
93
readFromCfg(cfg.group(QString()));
94
if (description.isEmpty())
95
description = "temporary";
98
#define READ_MATCH_STRING( var, func ) \
99
var = cfg.readEntry( #var ) func; \
100
var##match = (StringMatch) qMax( FirstStringMatch, \
101
qMin( LastStringMatch, static_cast< StringMatch >( cfg.readEntry( #var "match",0 ))));
103
#define READ_SET_RULE( var, func, def ) \
104
var = func ( cfg.readEntry( #var, def)); \
105
var##rule = readSetRule( cfg, #var "rule" );
107
#define READ_SET_RULE_DEF( var , func, def ) \
108
var = func ( cfg.readEntry( #var, def )); \
109
var##rule = readSetRule( cfg, #var "rule" );
111
#define READ_FORCE_RULE( var, func, def) \
112
var = func ( cfg.readEntry( #var, def)); \
113
var##rule = readForceRule( cfg, #var "rule" );
115
#define READ_FORCE_RULE2( var, def, func, funcarg ) \
116
var = func ( cfg.readEntry( #var, def),funcarg ); \
117
var##rule = readForceRule( cfg, #var "rule" );
121
Rules::Rules(const KConfigGroup& cfg)
127
static int limit0to4(int i)
129
return qMax(0, qMin(4, i));
132
void Rules::readFromCfg(const KConfigGroup& cfg)
134
description = cfg.readEntry("Description");
135
if (description.isEmpty()) // capitalized first, lowercase for backwards compatibility
136
description = cfg.readEntry("description");
137
READ_MATCH_STRING(wmclass, .toLower().toLatin1());
138
wmclasscomplete = cfg.readEntry("wmclasscomplete" , false);
139
READ_MATCH_STRING(windowrole, .toLower().toLatin1());
140
READ_MATCH_STRING(title,);
141
READ_MATCH_STRING(extrarole, .toLower().toLatin1());
142
READ_MATCH_STRING(clientmachine, .toLower().toLatin1());
143
types = cfg.readEntry("types", uint(NET::AllTypesMask));
144
READ_FORCE_RULE2(placement, QString(), Placement::policyFromString, false);
145
READ_SET_RULE_DEF(position, , invalidPoint);
146
READ_SET_RULE(size, , QSize());
147
if (size.isEmpty() && sizerule != (SetRule)Remember)
148
sizerule = UnusedSetRule;
149
READ_FORCE_RULE(minsize, , QSize());
150
if (!minsize.isValid())
151
minsize = QSize(1, 1);
152
READ_FORCE_RULE(maxsize, , QSize());
153
if (maxsize.isEmpty())
154
maxsize = QSize(32767, 32767);
155
READ_FORCE_RULE(opacityactive, , 0);
156
if (opacityactive < 0 || opacityactive > 100)
158
READ_FORCE_RULE(opacityinactive, , 0);
159
if (opacityinactive < 0 || opacityinactive > 100)
160
opacityinactive = 100;
161
READ_FORCE_RULE(tilingoption, , 0);
162
READ_FORCE_RULE(ignoreposition, , false);
163
READ_SET_RULE(desktop, , 0);
164
type = readType(cfg, "type");
165
typerule = type != NET::Unknown ? readForceRule(cfg, "typerule") : UnusedForceRule;
166
READ_SET_RULE(maximizevert, , false);
167
READ_SET_RULE(maximizehoriz, , false);
168
READ_SET_RULE(minimize, , false);
169
READ_SET_RULE(shade, , false);
170
READ_SET_RULE(skiptaskbar, , false);
171
READ_SET_RULE(skippager, , false);
172
READ_SET_RULE(skipswitcher, , false);
173
READ_SET_RULE(above, , false);
174
READ_SET_RULE(below, , false);
175
READ_SET_RULE(fullscreen, , false);
176
READ_SET_RULE(noborder, , false);
177
READ_FORCE_RULE(blockcompositing, , false);
178
READ_FORCE_RULE(fsplevel, limit0to4, 0); // fsp is 0-4
179
READ_FORCE_RULE(acceptfocus, , false);
180
READ_FORCE_RULE(moveresizemode, Options::stringToMoveResizeMode, QString());
181
READ_FORCE_RULE(closeable, , false);
182
READ_FORCE_RULE(autogroup, , false);
183
READ_FORCE_RULE(autogroupfg, , true);
184
READ_FORCE_RULE(autogroupid, , QString());
185
READ_FORCE_RULE(strictgeometry, , false);
186
READ_SET_RULE(shortcut, , QString());
187
READ_FORCE_RULE(disableglobalshortcuts, , false);
190
#undef READ_MATCH_STRING
192
#undef READ_FORCE_RULE
193
#undef READ_FORCE_RULE2
195
#define WRITE_MATCH_STRING( var, cast, force ) \
196
if ( !var.isEmpty() || force ) \
198
cfg.writeEntry( #var, cast var ); \
199
cfg.writeEntry( #var "match", (int)var##match ); \
203
cfg.deleteEntry( #var ); \
204
cfg.deleteEntry( #var "match" ); \
207
#define WRITE_SET_RULE( var, func ) \
208
if ( var##rule != UnusedSetRule ) \
210
cfg.writeEntry( #var, func ( var )); \
211
cfg.writeEntry( #var "rule", (int)var##rule ); \
215
cfg.deleteEntry( #var ); \
216
cfg.deleteEntry( #var "rule" ); \
219
#define WRITE_FORCE_RULE( var, func ) \
220
if ( var##rule != UnusedForceRule ) \
222
cfg.writeEntry( #var, func ( var )); \
223
cfg.writeEntry( #var "rule", (int)var##rule ); \
227
cfg.deleteEntry( #var ); \
228
cfg.deleteEntry( #var "rule" ); \
231
void Rules::write(KConfigGroup& cfg) const
233
cfg.writeEntry("Description", description);
234
// always write wmclass
235
WRITE_MATCH_STRING(wmclass, (const char*), true);
236
cfg.writeEntry("wmclasscomplete", wmclasscomplete);
237
WRITE_MATCH_STRING(windowrole, (const char*), false);
238
WRITE_MATCH_STRING(title, , false);
239
WRITE_MATCH_STRING(extrarole, (const char*), false);
240
WRITE_MATCH_STRING(clientmachine, (const char*), false);
241
if (types != NET::AllTypesMask)
242
cfg.writeEntry("types", uint(types));
244
cfg.deleteEntry("types");
245
WRITE_FORCE_RULE(placement, Placement::policyToString);
246
WRITE_SET_RULE(position,);
247
WRITE_SET_RULE(size,);
248
WRITE_FORCE_RULE(minsize,);
249
WRITE_FORCE_RULE(maxsize,);
250
WRITE_FORCE_RULE(opacityactive,);
251
WRITE_FORCE_RULE(opacityinactive,);
252
WRITE_FORCE_RULE(tilingoption,);
253
WRITE_FORCE_RULE(ignoreposition,);
254
WRITE_SET_RULE(desktop,);
255
WRITE_FORCE_RULE(type, int);
256
WRITE_SET_RULE(maximizevert,);
257
WRITE_SET_RULE(maximizehoriz,);
258
WRITE_SET_RULE(minimize,);
259
WRITE_SET_RULE(shade,);
260
WRITE_SET_RULE(skiptaskbar,);
261
WRITE_SET_RULE(skippager,);
262
WRITE_SET_RULE(skipswitcher,);
263
WRITE_SET_RULE(above,);
264
WRITE_SET_RULE(below,);
265
WRITE_SET_RULE(fullscreen,);
266
WRITE_SET_RULE(noborder,);
267
WRITE_FORCE_RULE(blockcompositing,);
268
WRITE_FORCE_RULE(fsplevel,);
269
WRITE_FORCE_RULE(acceptfocus,);
270
WRITE_FORCE_RULE(moveresizemode, Options::moveResizeModeToString);
271
WRITE_FORCE_RULE(closeable,);
272
WRITE_FORCE_RULE(autogroup,);
273
WRITE_FORCE_RULE(autogroupfg,);
274
WRITE_FORCE_RULE(autogroupid,);
275
WRITE_FORCE_RULE(strictgeometry,);
276
WRITE_SET_RULE(shortcut,);
277
WRITE_FORCE_RULE(disableglobalshortcuts,);
280
#undef WRITE_MATCH_STRING
281
#undef WRITE_SET_RULE
282
#undef WRITE_FORCE_RULE
284
// returns true if it doesn't affect anything
285
bool Rules::isEmpty() const
287
return(placementrule == UnusedForceRule
288
&& positionrule == UnusedSetRule
289
&& sizerule == UnusedSetRule
290
&& minsizerule == UnusedForceRule
291
&& maxsizerule == UnusedForceRule
292
&& opacityactiverule == UnusedForceRule
293
&& opacityinactiverule == UnusedForceRule
294
&& tilingoptionrule == UnusedForceRule
295
&& ignorepositionrule == UnusedForceRule
296
&& desktoprule == UnusedSetRule
297
&& typerule == UnusedForceRule
298
&& maximizevertrule == UnusedSetRule
299
&& maximizehorizrule == UnusedSetRule
300
&& minimizerule == UnusedSetRule
301
&& shaderule == UnusedSetRule
302
&& skiptaskbarrule == UnusedSetRule
303
&& skippagerrule == UnusedSetRule
304
&& skipswitcherrule == UnusedSetRule
305
&& aboverule == UnusedSetRule
306
&& belowrule == UnusedSetRule
307
&& fullscreenrule == UnusedSetRule
308
&& noborderrule == UnusedSetRule
309
&& blockcompositingrule == UnusedForceRule
310
&& fsplevelrule == UnusedForceRule
311
&& acceptfocusrule == UnusedForceRule
312
&& moveresizemoderule == UnusedForceRule
313
&& closeablerule == UnusedForceRule
314
&& autogrouprule == UnusedForceRule
315
&& autogroupfgrule == UnusedForceRule
316
&& autogroupidrule == UnusedForceRule
317
&& strictgeometryrule == UnusedForceRule
318
&& shortcutrule == UnusedSetRule
319
&& disableglobalshortcutsrule == UnusedForceRule);
322
Rules::SetRule Rules::readSetRule(const KConfigGroup& cfg, const QString& key)
324
int v = cfg.readEntry(key, 0);
325
if (v >= DontAffect && v <= ForceTemporarily)
326
return static_cast< SetRule >(v);
327
return UnusedSetRule;
330
Rules::ForceRule Rules::readForceRule(const KConfigGroup& cfg, const QString& key)
332
int v = cfg.readEntry(key, 0);
333
if (v == DontAffect || v == Force || v == ForceTemporarily)
334
return static_cast< ForceRule >(v);
335
return UnusedForceRule;
338
NET::WindowType Rules::readType(const KConfigGroup& cfg, const QString& key)
340
int v = cfg.readEntry(key, 0);
341
if (v >= NET::Normal && v <= NET::Splash)
342
return static_cast< NET::WindowType >(v);
346
bool Rules::matchType(NET::WindowType match_type) const
348
if (types != NET::AllTypesMask) {
349
if (match_type == NET::Unknown)
350
match_type = NET::Normal; // NET::Unknown->NET::Normal is only here for matching
351
if (!NET::typeMatchesMask(match_type, types))
357
bool Rules::matchWMClass(const QByteArray& match_class, const QByteArray& match_name) const
359
if (wmclassmatch != UnimportantMatch) {
361
QByteArray cwmclass = wmclasscomplete
362
? match_name + ' ' + match_class : match_class;
363
if (wmclassmatch == RegExpMatch && QRegExp(wmclass).indexIn(cwmclass) == -1)
365
if (wmclassmatch == ExactMatch && wmclass != cwmclass)
367
if (wmclassmatch == SubstringMatch && !cwmclass.contains(wmclass))
373
bool Rules::matchRole(const QByteArray& match_role) const
375
if (windowrolematch != UnimportantMatch) {
376
if (windowrolematch == RegExpMatch && QRegExp(windowrole).indexIn(match_role) == -1)
378
if (windowrolematch == ExactMatch && windowrole != match_role)
380
if (windowrolematch == SubstringMatch && !match_role.contains(windowrole))
386
bool Rules::matchTitle(const QString& match_title) const
388
if (titlematch != UnimportantMatch) {
389
if (titlematch == RegExpMatch && QRegExp(title).indexIn(match_title) == -1)
391
if (titlematch == ExactMatch && title != match_title)
393
if (titlematch == SubstringMatch && !match_title.contains(title))
399
bool Rules::matchClientMachine(const QByteArray& match_machine) const
401
if (clientmachinematch != UnimportantMatch) {
402
// if it's localhost, check also "localhost" before checking hostname
403
if (match_machine != "localhost" && isLocalMachine(match_machine)
404
&& matchClientMachine("localhost"))
406
if (clientmachinematch == RegExpMatch
407
&& QRegExp(clientmachine).indexIn(match_machine) == -1)
409
if (clientmachinematch == ExactMatch
410
&& clientmachine != match_machine)
412
if (clientmachinematch == SubstringMatch
413
&& !match_machine.contains(clientmachine))
420
bool Rules::match(const Client* c) const
422
if (!matchType(c->windowType(true)))
424
if (!matchWMClass(c->resourceClass(), c->resourceName()))
426
if (!matchRole(c->windowRole()))
428
if (!matchTitle(c->caption(false)))
431
if (!matchClientMachine(c->wmClientMachine(false)))
436
bool Rules::update(Client* c)
438
// TODO check this setting is for this client ?
439
bool updated = false;
440
if (positionrule == (SetRule)Remember) {
441
if (!c->isFullScreen()) {
442
QPoint new_pos = position;
443
// don't use the position in the direction which is maximized
444
if ((c->maximizeMode() & MaximizeHorizontal) == 0)
445
new_pos.setX(c->pos().x());
446
if ((c->maximizeMode() & MaximizeVertical) == 0)
447
new_pos.setY(c->pos().y());
448
updated = updated || position != new_pos;
452
if (sizerule == (SetRule)Remember) {
453
if (!c->isFullScreen()) {
454
QSize new_size = size;
455
// don't use the position in the direction which is maximized
456
if ((c->maximizeMode() & MaximizeHorizontal) == 0)
457
new_size.setWidth(c->size().width());
458
if ((c->maximizeMode() & MaximizeVertical) == 0)
459
new_size.setHeight(c->size().height());
460
updated = updated || size != new_size;
464
if (desktoprule == (SetRule)Remember) {
465
updated = updated || desktop != c->desktop();
466
desktop = c->desktop();
468
if (maximizevertrule == (SetRule)Remember) {
469
updated = updated || maximizevert != bool(c->maximizeMode() & MaximizeVertical);
470
maximizevert = c->maximizeMode() & MaximizeVertical;
472
if (maximizehorizrule == (SetRule)Remember) {
473
updated = updated || maximizehoriz != bool(c->maximizeMode() & MaximizeHorizontal);
474
maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
476
if (minimizerule == (SetRule)Remember) {
477
updated = updated || minimize != c->isMinimized();
478
minimize = c->isMinimized();
480
if (shaderule == (SetRule)Remember) {
481
updated = updated || (shade != (c->shadeMode() != ShadeNone));
482
shade = c->shadeMode() != ShadeNone;
484
if (skiptaskbarrule == (SetRule)Remember) {
485
updated = updated || skiptaskbar != c->skipTaskbar();
486
skiptaskbar = c->skipTaskbar();
488
if (skippagerrule == (SetRule)Remember) {
489
updated = updated || skippager != c->skipPager();
490
skippager = c->skipPager();
492
if (skipswitcherrule == (SetRule)Remember) {
493
updated = updated || skipswitcher != c->skipSwitcher();
494
skipswitcher = c->skipSwitcher();
496
if (aboverule == (SetRule)Remember) {
497
updated = updated || above != c->keepAbove();
498
above = c->keepAbove();
500
if (belowrule == (SetRule)Remember) {
501
updated = updated || below != c->keepBelow();
502
below = c->keepBelow();
504
if (fullscreenrule == (SetRule)Remember) {
505
updated = updated || fullscreen != c->isFullScreen();
506
fullscreen = c->isFullScreen();
508
if (noborderrule == (SetRule)Remember) {
509
updated = updated || noborder != c->noBorder();
510
noborder = c->noBorder();
512
if (opacityactiverule == (ForceRule)Force) {
515
if (opacityinactiverule == (ForceRule)Force) {
521
#define APPLY_RULE( var, name, type ) \
522
bool Rules::apply##name( type& arg, bool init ) const \
524
if ( checkSetRule( var##rule, init )) \
526
return checkSetStop( var##rule ); \
529
#define APPLY_FORCE_RULE( var, name, type ) \
530
bool Rules::apply##name( type& arg ) const \
532
if ( checkForceRule( var##rule )) \
534
return checkForceStop( var##rule ); \
537
APPLY_FORCE_RULE(placement, Placement, Placement::Policy)
539
bool Rules::applyGeometry(QRect& rect, bool init) const
541
QPoint p = rect.topLeft();
542
QSize s = rect.size();
543
bool ret = false; // no short-circuiting
544
if (applyPosition(p, init)) {
548
if (applySize(s, init)) {
555
bool Rules::applyPosition(QPoint& pos, bool init) const
557
if (this->position != invalidPoint && checkSetRule(positionrule, init))
558
pos = this->position;
559
return checkSetStop(positionrule);
562
bool Rules::applySize(QSize& s, bool init) const
564
if (this->size.isValid() && checkSetRule(sizerule, init))
566
return checkSetStop(sizerule);
569
APPLY_FORCE_RULE(minsize, MinSize, QSize)
570
APPLY_FORCE_RULE(maxsize, MaxSize, QSize)
571
APPLY_FORCE_RULE(opacityactive, OpacityActive, int)
572
APPLY_FORCE_RULE(opacityinactive, OpacityInactive, int)
573
APPLY_FORCE_RULE(ignoreposition, IgnorePosition, bool)
574
APPLY_FORCE_RULE(tilingoption, TilingOption, int)
576
// the cfg. entry needs to stay named the say for backwards compatibility
577
bool Rules::applyIgnoreGeometry(bool& ignore) const
579
return applyIgnorePosition(ignore);
582
APPLY_RULE(desktop, Desktop, int)
583
APPLY_FORCE_RULE(type, Type, NET::WindowType)
585
bool Rules::applyMaximizeHoriz(MaximizeMode& mode, bool init) const
587
if (checkSetRule(maximizehorizrule, init))
588
mode = static_cast< MaximizeMode >((maximizehoriz ? MaximizeHorizontal : 0) | (mode & MaximizeVertical));
589
return checkSetStop(maximizehorizrule);
592
bool Rules::applyMaximizeVert(MaximizeMode& mode, bool init) const
594
if (checkSetRule(maximizevertrule, init))
595
mode = static_cast< MaximizeMode >((maximizevert ? MaximizeVertical : 0) | (mode & MaximizeHorizontal));
596
return checkSetStop(maximizevertrule);
599
APPLY_RULE(minimize, Minimize, bool)
601
bool Rules::applyShade(ShadeMode& sh, bool init) const
603
if (checkSetRule(shaderule, init)) {
606
if (this->shade && sh == ShadeNone)
609
return checkSetStop(shaderule);
612
APPLY_RULE(skiptaskbar, SkipTaskbar, bool)
613
APPLY_RULE(skippager, SkipPager, bool)
614
APPLY_RULE(skipswitcher, SkipSwitcher, bool)
615
APPLY_RULE(above, KeepAbove, bool)
616
APPLY_RULE(below, KeepBelow, bool)
617
APPLY_RULE(fullscreen, FullScreen, bool)
618
APPLY_RULE(noborder, NoBorder, bool)
619
APPLY_FORCE_RULE(blockcompositing, BlockCompositing, bool)
620
APPLY_FORCE_RULE(fsplevel, FSP, int)
621
APPLY_FORCE_RULE(acceptfocus, AcceptFocus, bool)
622
APPLY_FORCE_RULE(moveresizemode, MoveResizeMode, Options::MoveResizeMode)
623
APPLY_FORCE_RULE(closeable, Closeable, bool)
624
APPLY_FORCE_RULE(autogroup, Autogrouping, bool)
625
APPLY_FORCE_RULE(autogroupfg, AutogroupInForeground, bool)
626
APPLY_FORCE_RULE(autogroupid, AutogroupById, QString)
627
APPLY_FORCE_RULE(strictgeometry, StrictGeometry, bool)
628
APPLY_RULE(shortcut, Shortcut, QString)
629
APPLY_FORCE_RULE(disableglobalshortcuts, DisableGlobalShortcuts, bool)
633
#undef APPLY_FORCE_RULE
635
bool Rules::isTemporary() const
637
return temporary_state > 0;
640
bool Rules::discardTemporary(bool force)
642
if (temporary_state == 0) // not temporary
644
if (force || --temporary_state == 0) { // too old
651
#define DISCARD_USED_SET_RULE( var ) \
653
if ( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) \
654
var##rule = UnusedSetRule; \
656
#define DISCARD_USED_FORCE_RULE( var ) \
658
if ( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) \
659
var##rule = UnusedForceRule; \
662
void Rules::discardUsed(bool withdrawn)
664
DISCARD_USED_FORCE_RULE(placement);
665
DISCARD_USED_SET_RULE(position);
666
DISCARD_USED_SET_RULE(size);
667
DISCARD_USED_FORCE_RULE(minsize);
668
DISCARD_USED_FORCE_RULE(maxsize);
669
DISCARD_USED_FORCE_RULE(opacityactive);
670
DISCARD_USED_FORCE_RULE(opacityinactive);
671
DISCARD_USED_FORCE_RULE(tilingoption);
672
DISCARD_USED_FORCE_RULE(ignoreposition);
673
DISCARD_USED_SET_RULE(desktop);
674
DISCARD_USED_FORCE_RULE(type);
675
DISCARD_USED_SET_RULE(maximizevert);
676
DISCARD_USED_SET_RULE(maximizehoriz);
677
DISCARD_USED_SET_RULE(minimize);
678
DISCARD_USED_SET_RULE(shade);
679
DISCARD_USED_SET_RULE(skiptaskbar);
680
DISCARD_USED_SET_RULE(skippager);
681
DISCARD_USED_SET_RULE(skipswitcher);
682
DISCARD_USED_SET_RULE(above);
683
DISCARD_USED_SET_RULE(below);
684
DISCARD_USED_SET_RULE(fullscreen);
685
DISCARD_USED_SET_RULE(noborder);
686
DISCARD_USED_FORCE_RULE(blockcompositing);
687
DISCARD_USED_FORCE_RULE(fsplevel);
688
DISCARD_USED_FORCE_RULE(acceptfocus);
689
DISCARD_USED_FORCE_RULE(moveresizemode);
690
DISCARD_USED_FORCE_RULE(closeable);
691
DISCARD_USED_FORCE_RULE(autogroup);
692
DISCARD_USED_FORCE_RULE(autogroupfg);
693
DISCARD_USED_FORCE_RULE(autogroupid);
694
DISCARD_USED_FORCE_RULE(strictgeometry);
695
DISCARD_USED_SET_RULE(shortcut);
696
DISCARD_USED_FORCE_RULE(disableglobalshortcuts);
698
#undef DISCARD_USED_SET_RULE
699
#undef DISCARD_USED_FORCE_RULE
703
QDebug& operator<<(QDebug& stream, const Rules* r)
705
return stream << "[" << r->description << ":" << r->wmclass << "]" ;
709
void WindowRules::discardTemporary()
711
QVector< Rules* >::Iterator it2 = rules.begin();
712
for (QVector< Rules* >::Iterator it = rules.begin();
715
if ((*it)->discardTemporary(true))
721
rules.erase(it2, rules.end());
724
void WindowRules::update(Client* c)
726
bool updated = false;
727
for (QVector< Rules* >::ConstIterator it = rules.constBegin();
728
it != rules.constEnd();
730
if ((*it)->update(c)) // no short-circuiting here
733
Workspace::self()->rulesUpdated();
736
#define CHECK_RULE( rule, type ) \
737
type WindowRules::check##rule( type arg, bool init ) const \
739
if ( rules.count() == 0 ) \
742
for ( QVector< Rules* >::ConstIterator it = rules.constBegin(); \
743
it != rules.constEnd(); \
746
if ( (*it)->apply##rule( ret, init )) \
752
#define CHECK_FORCE_RULE( rule, type ) \
753
type WindowRules::check##rule( type arg ) const \
755
if ( rules.count() == 0 ) \
758
for ( QVector< Rules* >::ConstIterator it = rules.begin(); \
762
if ( (*it)->apply##rule( ret )) \
768
CHECK_FORCE_RULE(Placement, Placement::Policy)
770
QRect WindowRules::checkGeometry(QRect rect, bool init) const
772
return QRect(checkPosition(rect.topLeft(), init), checkSize(rect.size(), init));
775
CHECK_RULE(Position, QPoint)
776
CHECK_RULE(Size, QSize)
777
CHECK_FORCE_RULE(MinSize, QSize)
778
CHECK_FORCE_RULE(MaxSize, QSize)
779
CHECK_FORCE_RULE(OpacityActive, int)
780
CHECK_FORCE_RULE(OpacityInactive, int)
781
CHECK_FORCE_RULE(TilingOption, int)
782
CHECK_FORCE_RULE(IgnorePosition, bool)
784
bool WindowRules::checkIgnoreGeometry(bool ignore) const
786
return checkIgnorePosition(ignore);
789
CHECK_RULE(Desktop, int)
790
CHECK_FORCE_RULE(Type, NET::WindowType)
791
CHECK_RULE(MaximizeVert, KDecorationDefines::MaximizeMode)
792
CHECK_RULE(MaximizeHoriz, KDecorationDefines::MaximizeMode)
794
KDecorationDefines::MaximizeMode WindowRules::checkMaximize(MaximizeMode mode, bool init) const
796
bool vert = checkMaximizeVert(mode, init) & MaximizeVertical;
797
bool horiz = checkMaximizeHoriz(mode, init) & MaximizeHorizontal;
798
return static_cast< MaximizeMode >((vert ? MaximizeVertical : 0) | (horiz ? MaximizeHorizontal : 0));
801
CHECK_RULE(Minimize, bool)
802
CHECK_RULE(Shade, ShadeMode)
803
CHECK_RULE(SkipTaskbar, bool)
804
CHECK_RULE(SkipPager, bool)
805
CHECK_RULE(SkipSwitcher, bool)
806
CHECK_RULE(KeepAbove, bool)
807
CHECK_RULE(KeepBelow, bool)
808
CHECK_RULE(FullScreen, bool)
809
CHECK_RULE(NoBorder, bool)
810
CHECK_FORCE_RULE(BlockCompositing, bool)
811
CHECK_FORCE_RULE(FSP, int)
812
CHECK_FORCE_RULE(AcceptFocus, bool)
813
CHECK_FORCE_RULE(MoveResizeMode, Options::MoveResizeMode)
814
CHECK_FORCE_RULE(Closeable, bool)
815
CHECK_FORCE_RULE(Autogrouping, bool)
816
CHECK_FORCE_RULE(AutogroupInForeground, bool)
817
CHECK_FORCE_RULE(AutogroupById, QString)
818
CHECK_FORCE_RULE(StrictGeometry, bool)
819
CHECK_RULE(Shortcut, QString)
820
CHECK_FORCE_RULE(DisableGlobalShortcuts, bool)
823
#undef CHECK_FORCE_RULE
827
void Client::setupWindowRules(bool ignore_temporary)
829
client_rules = workspace()->findWindowRules(this, ignore_temporary);
830
// check only after getting the rules, because there may be a rule forcing window type
831
if (isTopMenu()) // TODO cannot have restrictions
832
client_rules = WindowRules();
835
// Applies Force, ForceTemporarily and ApplyNow rules
836
// Used e.g. after the rules have been modified using the kcm.
837
void Client::applyWindowRules()
840
// Placement - does need explicit update, just like some others below
841
// Geometry : setGeometry() doesn't check rules
842
QRect orig_geom = QRect(pos(), sizeForClientSize(clientSize())); // handle shading
843
QRect geom = client_rules.checkGeometry(orig_geom);
844
if (geom != orig_geom)
846
// MinSize, MaxSize handled by Geometry
848
setDesktop(desktop());
850
maximize(maximizeMode());
851
// Minimize : functions don't check, and there are two functions
852
if (client_rules.checkMinimize(isMinimized()))
856
setShade(shadeMode());
857
setSkipTaskbar(skipTaskbar(), true);
858
setSkipPager(skipPager());
859
setSkipSwitcher(skipSwitcher());
860
setKeepAbove(keepAbove());
861
setKeepBelow(keepBelow());
862
setFullScreen(isFullScreen(), true);
863
setNoBorder(noBorder());
866
if (workspace()->mostRecentlyActivatedClient() == this
867
&& !client_rules.checkAcceptFocus(true))
868
workspace()->activateNextClient(this);
871
QSize s = adjustedSize();
874
// Autogrouping : Only checked on window manage
875
// AutogroupInForeground : Only checked on window manage
876
// AutogroupById : Only checked on window manage
878
setShortcut(rules()->checkShortcut(shortcut().toString()));
879
// see also Client::setActive()
881
setOpacity(rules()->checkOpacityActive(qRound(opacity() * 100.0)) / 100.0);
882
workspace()->disableGlobalShortcutsForClient(rules()->checkDisableGlobalShortcuts(false));
884
setOpacity(rules()->checkOpacityInactive(qRound(opacity() * 100.0)) / 100.0);
887
void Client::updateWindowRules()
889
if (!isManaged()) // not fully setup yet
891
if (workspace()->rulesUpdatesDisabled())
893
client_rules.update(this);
896
void Client::finishWindowRules()
899
client_rules = WindowRules();
904
WindowRules Workspace::findWindowRules(const Client* c, bool ignore_temporary)
906
QVector< Rules* > ret;
907
for (QList< Rules* >::Iterator it = rules.begin();
910
if (ignore_temporary && (*it)->isTemporary()) {
914
if ((*it)->match(c)) {
916
kDebug(1212) << "Rule found:" << rule << ":" << c;
917
if (rule->isTemporary())
918
it = rules.erase(it);
926
return WindowRules(ret);
929
void Workspace::editWindowRules(Client* c, bool whole_app)
933
args << "--wid" << QString::number(c->window());
935
args << "--whole-app";
936
KToolInvocation::kdeinitExec("kwin_rules_dialog", args);
939
void Workspace::loadWindowRules()
941
while (!rules.isEmpty()) {
942
delete rules.front();
945
KConfig cfg("kwinrulesrc", KConfig::NoGlobals);
946
int count = cfg.group("General").readEntry("count", 0);
950
KConfigGroup cg(&cfg, QString::number(i));
951
Rules* rule = new Rules(cg);
956
void Workspace::writeWindowRules()
958
rulesUpdatedTimer.stop();
959
KConfig cfg("kwinrulesrc", KConfig::NoGlobals);
960
QStringList groups = cfg.groupList();
961
for (QStringList::ConstIterator it = groups.constBegin();
962
it != groups.constEnd();
964
cfg.deleteGroup(*it);
965
cfg.group("General").writeEntry("count", rules.count());
967
for (QList< Rules* >::ConstIterator it = rules.constBegin();
968
it != rules.constEnd();
970
if ((*it)->isTemporary())
972
KConfigGroup cg(&cfg, QString::number(i));
978
void Workspace::gotTemporaryRulesMessage(const QString& message)
980
bool was_temporary = false;
981
for (QList< Rules* >::ConstIterator it = rules.constBegin();
982
it != rules.constEnd();
984
if ((*it)->isTemporary())
985
was_temporary = true;
986
Rules* rule = new Rules(message, true);
987
rules.prepend(rule); // highest priority first
989
QTimer::singleShot(60000, this, SLOT(cleanupTemporaryRules()));
992
void Workspace::cleanupTemporaryRules()
994
bool has_temporary = false;
995
for (QList< Rules* >::Iterator it = rules.begin();
998
if ((*it)->discardTemporary(false))
999
it = rules.erase(it);
1001
if ((*it)->isTemporary())
1002
has_temporary = true;
1007
QTimer::singleShot(60000, this, SLOT(cleanupTemporaryRules()));
1010
void Workspace::discardUsedWindowRules(Client* c, bool withdrawn)
1012
bool updated = false;
1013
for (QList< Rules* >::Iterator it = rules.begin();
1016
if (c->rules()->contains(*it)) {
1018
(*it)->discardUsed(withdrawn);
1019
if ((*it)->isEmpty()) {
1022
it = rules.erase(it);
1033
void Workspace::rulesUpdated()
1035
rulesUpdatedTimer.setSingleShot(true);
1036
rulesUpdatedTimer.start(1000);
1039
void Workspace::disableRulesUpdates(bool disable)
1041
rules_updates_disabled = disable;
1043
foreach (Client * c, clients)
1044
c->updateWindowRules();