2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2004 Lubos Lunak <l.lunak@kde.org>
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#include "rules.h"
|
|
|
|
|
|
|
|
#include <kconfig.h>
|
2014-03-17 15:24:10 +00:00
|
|
|
#include <KXMessages>
|
2007-04-29 17:35:43 +00:00
|
|
|
#include <QRegExp>
|
2013-08-10 21:19:41 +00:00
|
|
|
#include <QTemporaryFile>
|
2007-04-29 17:35:43 +00:00
|
|
|
#include <QFile>
|
2013-11-05 12:42:33 +00:00
|
|
|
#include <QFileInfo>
|
2013-09-02 11:14:39 +00:00
|
|
|
#include <QDebug>
|
2018-11-08 21:08:06 +00:00
|
|
|
#include <QDir>
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#ifndef KCMRULES
|
2019-09-24 08:48:08 +00:00
|
|
|
#include "x11client.h"
|
2013-01-07 07:07:27 +00:00
|
|
|
#include "client_machine.h"
|
2013-04-03 10:19:27 +00:00
|
|
|
#include "screens.h"
|
2007-04-29 17:35:43 +00:00
|
|
|
#include "workspace.h"
|
|
|
|
#endif
|
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
#include "rulesettings.h"
|
|
|
|
#include "rulebooksettings.h"
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
|
|
|
Rules::Rules()
|
2011-01-30 14:34:42 +00:00
|
|
|
: temporary_state(0)
|
|
|
|
, wmclassmatch(UnimportantMatch)
|
|
|
|
, wmclasscomplete(UnimportantMatch)
|
|
|
|
, windowrolematch(UnimportantMatch)
|
|
|
|
, titlematch(UnimportantMatch)
|
|
|
|
, clientmachinematch(UnimportantMatch)
|
|
|
|
, types(NET::AllTypesMask)
|
|
|
|
, placementrule(UnusedForceRule)
|
|
|
|
, positionrule(UnusedSetRule)
|
|
|
|
, sizerule(UnusedSetRule)
|
|
|
|
, minsizerule(UnusedForceRule)
|
|
|
|
, maxsizerule(UnusedForceRule)
|
|
|
|
, opacityactiverule(UnusedForceRule)
|
|
|
|
, opacityinactiverule(UnusedForceRule)
|
2013-03-24 18:13:00 +00:00
|
|
|
, ignoregeometryrule(UnusedSetRule)
|
2011-01-30 14:34:42 +00:00
|
|
|
, desktoprule(UnusedSetRule)
|
2012-08-24 16:48:50 +00:00
|
|
|
, screenrule(UnusedSetRule)
|
2012-05-17 14:32:06 +00:00
|
|
|
, activityrule(UnusedSetRule)
|
2011-01-30 14:34:42 +00:00
|
|
|
, typerule(UnusedForceRule)
|
|
|
|
, maximizevertrule(UnusedSetRule)
|
|
|
|
, maximizehorizrule(UnusedSetRule)
|
|
|
|
, minimizerule(UnusedSetRule)
|
|
|
|
, shaderule(UnusedSetRule)
|
|
|
|
, skiptaskbarrule(UnusedSetRule)
|
|
|
|
, skippagerrule(UnusedSetRule)
|
|
|
|
, skipswitcherrule(UnusedSetRule)
|
|
|
|
, aboverule(UnusedSetRule)
|
|
|
|
, belowrule(UnusedSetRule)
|
|
|
|
, fullscreenrule(UnusedSetRule)
|
|
|
|
, noborderrule(UnusedSetRule)
|
2013-11-05 12:42:33 +00:00
|
|
|
, decocolorrule(UnusedForceRule)
|
2011-03-20 14:42:05 +00:00
|
|
|
, blockcompositingrule(UnusedForceRule)
|
2011-01-30 14:34:42 +00:00
|
|
|
, fsplevelrule(UnusedForceRule)
|
2015-11-12 23:37:01 +00:00
|
|
|
, fpplevelrule(UnusedForceRule)
|
2011-01-30 14:34:42 +00:00
|
|
|
, acceptfocusrule(UnusedForceRule)
|
|
|
|
, closeablerule(UnusedForceRule)
|
|
|
|
, autogrouprule(UnusedForceRule)
|
|
|
|
, autogroupfgrule(UnusedForceRule)
|
|
|
|
, autogroupidrule(UnusedForceRule)
|
|
|
|
, strictgeometryrule(UnusedForceRule)
|
|
|
|
, shortcutrule(UnusedSetRule)
|
|
|
|
, disableglobalshortcutsrule(UnusedForceRule)
|
2018-03-11 16:13:32 +00:00
|
|
|
, desktopfilerule(UnusedSetRule)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
Rules::Rules(const QString& str, bool temporary)
|
|
|
|
: temporary_state(temporary ? 2 : 0)
|
|
|
|
{
|
2013-08-10 21:19:41 +00:00
|
|
|
QTemporaryFile file;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (file.open()) {
|
2007-04-29 17:35:43 +00:00
|
|
|
QByteArray s = str.toUtf8();
|
2011-01-30 14:34:42 +00:00
|
|
|
file.write(s.data(), s.length());
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
file.flush();
|
2020-02-18 13:52:08 +00:00
|
|
|
auto cfg = KSharedConfig::openConfig(file.fileName(), KConfig::SimpleConfig);
|
|
|
|
RuleSettings settings(cfg, QString());
|
|
|
|
readFromSettings(&settings);
|
2011-01-30 14:34:42 +00:00
|
|
|
if (description.isEmpty())
|
2013-07-23 05:02:52 +00:00
|
|
|
description = QStringLiteral("temporary");
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
#define READ_MATCH_STRING(var, func) \
|
|
|
|
var = settings->var() func; \
|
|
|
|
var##match = static_cast<StringMatch>(settings->var##match())
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
#define READ_SET_RULE(var) \
|
|
|
|
var = settings->var(); \
|
|
|
|
var##rule = static_cast<SetRule>(settings->var##rule())
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
#define READ_FORCE_RULE(var, func) \
|
|
|
|
var = func(settings->var()); \
|
|
|
|
var##rule = convertForceRule(settings->var##rule())
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
Rules::Rules(const RuleSettings *settings)
|
2011-01-30 14:34:42 +00:00
|
|
|
: temporary_state(0)
|
|
|
|
{
|
2020-02-18 13:52:08 +00:00
|
|
|
readFromSettings(settings);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
void Rules::readFromSettings(const RuleSettings *settings)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2020-02-18 13:52:08 +00:00
|
|
|
description = settings->description();
|
|
|
|
if (description.isEmpty()) {
|
|
|
|
description = settings->descriptionLegacy();
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
READ_MATCH_STRING(wmclass, .toLower().toLatin1());
|
2020-02-18 13:52:08 +00:00
|
|
|
wmclasscomplete = settings->wmclasscomplete();
|
2016-08-25 11:30:25 +00:00
|
|
|
READ_MATCH_STRING(windowrole, .toLower().toLatin1());
|
2011-01-30 14:34:42 +00:00
|
|
|
READ_MATCH_STRING(title,);
|
|
|
|
READ_MATCH_STRING(clientmachine, .toLower().toLatin1());
|
2020-02-18 13:52:08 +00:00
|
|
|
types = NET::WindowTypeMask(settings->types());
|
|
|
|
READ_FORCE_RULE(placement,);
|
|
|
|
READ_SET_RULE(position);
|
|
|
|
READ_SET_RULE(size);
|
|
|
|
if (size.isEmpty() && sizerule != static_cast<SetRule>(Remember))
|
2007-04-29 17:35:43 +00:00
|
|
|
sizerule = UnusedSetRule;
|
2020-02-18 13:52:08 +00:00
|
|
|
READ_FORCE_RULE(minsize,);
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!minsize.isValid())
|
|
|
|
minsize = QSize(1, 1);
|
2020-02-18 13:52:08 +00:00
|
|
|
READ_FORCE_RULE(maxsize,);
|
2011-01-30 14:34:42 +00:00
|
|
|
if (maxsize.isEmpty())
|
|
|
|
maxsize = QSize(32767, 32767);
|
2020-02-18 13:52:08 +00:00
|
|
|
READ_FORCE_RULE(opacityactive,);
|
|
|
|
READ_FORCE_RULE(opacityinactive,);
|
|
|
|
READ_SET_RULE(ignoregeometry);
|
|
|
|
READ_SET_RULE(desktop);
|
|
|
|
READ_SET_RULE(screen);
|
|
|
|
READ_SET_RULE(activity);
|
|
|
|
READ_FORCE_RULE(type, static_cast<NET::WindowType>);
|
|
|
|
if (type == NET::Unknown)
|
|
|
|
typerule = UnusedForceRule;
|
|
|
|
READ_SET_RULE(maximizevert);
|
|
|
|
READ_SET_RULE(maximizehoriz);
|
|
|
|
READ_SET_RULE(minimize);
|
|
|
|
READ_SET_RULE(shade);
|
|
|
|
READ_SET_RULE(skiptaskbar);
|
|
|
|
READ_SET_RULE(skippager);
|
|
|
|
READ_SET_RULE(skipswitcher);
|
|
|
|
READ_SET_RULE(above);
|
|
|
|
READ_SET_RULE(below);
|
|
|
|
READ_SET_RULE(fullscreen);
|
|
|
|
READ_SET_RULE(noborder);
|
|
|
|
|
|
|
|
READ_FORCE_RULE(decocolor, getDecoColor);
|
|
|
|
if (decocolor.isEmpty())
|
|
|
|
decocolorrule = UnusedForceRule;
|
|
|
|
|
|
|
|
READ_FORCE_RULE(blockcompositing,);
|
|
|
|
READ_FORCE_RULE(fsplevel,);
|
|
|
|
READ_FORCE_RULE(fpplevel,);
|
|
|
|
READ_FORCE_RULE(acceptfocus,);
|
|
|
|
READ_FORCE_RULE(closeable,);
|
|
|
|
READ_FORCE_RULE(autogroup,);
|
|
|
|
READ_FORCE_RULE(autogroupfg,);
|
|
|
|
READ_FORCE_RULE(autogroupid,);
|
|
|
|
READ_FORCE_RULE(strictgeometry,);
|
|
|
|
READ_SET_RULE(shortcut);
|
|
|
|
READ_FORCE_RULE(disableglobalshortcuts,);
|
|
|
|
READ_SET_RULE(desktopfile);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#undef READ_MATCH_STRING
|
|
|
|
#undef READ_SET_RULE
|
|
|
|
#undef READ_FORCE_RULE
|
|
|
|
#undef READ_FORCE_RULE2
|
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
#define WRITE_MATCH_STRING(var, capital, force) \
|
|
|
|
settings->set##capital##match(var##match); \
|
|
|
|
if (!var.isEmpty() || force) \
|
2011-01-30 14:34:42 +00:00
|
|
|
{ \
|
2020-02-18 13:52:08 +00:00
|
|
|
settings->set##capital(var); \
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
#define WRITE_SET_RULE(var, capital, func) \
|
|
|
|
settings->set##capital##rule(var##rule); \
|
|
|
|
if (var##rule != UnusedSetRule) \
|
2011-01-30 14:34:42 +00:00
|
|
|
{ \
|
2020-02-18 13:52:08 +00:00
|
|
|
settings->set##capital(func(var)); \
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
#define WRITE_FORCE_RULE(var, capital, func) \
|
|
|
|
settings->set##capital##rule(var##rule); \
|
2011-01-30 14:34:42 +00:00
|
|
|
if ( var##rule != UnusedForceRule ) \
|
|
|
|
{ \
|
2020-02-18 13:52:08 +00:00
|
|
|
settings->set##capital(func(var)); \
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
void Rules::write(RuleSettings *settings) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2020-02-18 13:52:08 +00:00
|
|
|
settings->setDescription(description);
|
2007-04-29 17:35:43 +00:00
|
|
|
// always write wmclass
|
2020-02-18 13:52:08 +00:00
|
|
|
WRITE_MATCH_STRING(wmclass, Wmclass, true);
|
|
|
|
settings->setWmclasscomplete(wmclasscomplete);
|
|
|
|
WRITE_MATCH_STRING(windowrole, Windowrole, false);
|
|
|
|
WRITE_MATCH_STRING(title, Title, false);
|
|
|
|
WRITE_MATCH_STRING(clientmachine, Clientmachine, false);
|
|
|
|
settings->setTypes(types);
|
|
|
|
WRITE_FORCE_RULE(placement, Placement,);
|
|
|
|
WRITE_SET_RULE(position, Position,);
|
|
|
|
WRITE_SET_RULE(size, Size,);
|
|
|
|
WRITE_FORCE_RULE(minsize, Minsize,);
|
|
|
|
WRITE_FORCE_RULE(maxsize, Maxsize,);
|
|
|
|
WRITE_FORCE_RULE(opacityactive, Opacityactive,);
|
|
|
|
WRITE_FORCE_RULE(opacityinactive, Opacityinactive,);
|
|
|
|
WRITE_SET_RULE(ignoregeometry, Ignoregeometry,);
|
|
|
|
WRITE_SET_RULE(desktop, Desktop,);
|
|
|
|
WRITE_SET_RULE(screen, Screen,);
|
|
|
|
WRITE_SET_RULE(activity, Activity,);
|
|
|
|
WRITE_FORCE_RULE(type, Type,);
|
|
|
|
WRITE_SET_RULE(maximizevert, Maximizevert,);
|
|
|
|
WRITE_SET_RULE(maximizehoriz, Maximizehoriz,);
|
|
|
|
WRITE_SET_RULE(minimize, Minimize,);
|
|
|
|
WRITE_SET_RULE(shade, Shade,);
|
|
|
|
WRITE_SET_RULE(skiptaskbar, Skiptaskbar,);
|
|
|
|
WRITE_SET_RULE(skippager, Skippager,);
|
|
|
|
WRITE_SET_RULE(skipswitcher, Skipswitcher,);
|
|
|
|
WRITE_SET_RULE(above, Above,);
|
|
|
|
WRITE_SET_RULE(below, Below,);
|
|
|
|
WRITE_SET_RULE(fullscreen, Fullscreen,);
|
|
|
|
WRITE_SET_RULE(noborder, Noborder,);
|
2014-01-19 15:17:07 +00:00
|
|
|
auto colorToString = [](const QString &value) -> QString {
|
2015-11-05 14:14:06 +00:00
|
|
|
if (value.endsWith(QLatin1String(".colors"))) {
|
2013-11-05 12:42:33 +00:00
|
|
|
return QFileInfo(value).baseName();
|
|
|
|
} else {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
};
|
2020-02-18 13:52:08 +00:00
|
|
|
WRITE_FORCE_RULE(decocolor, Decocolor, colorToString);
|
|
|
|
WRITE_FORCE_RULE(blockcompositing, Blockcompositing,);
|
|
|
|
WRITE_FORCE_RULE(fsplevel, Fsplevel,);
|
|
|
|
WRITE_FORCE_RULE(fpplevel, Fpplevel,);
|
|
|
|
WRITE_FORCE_RULE(acceptfocus, Acceptfocus,);
|
|
|
|
WRITE_FORCE_RULE(closeable, Closeable,);
|
|
|
|
WRITE_FORCE_RULE(autogroup, Autogroup,);
|
|
|
|
WRITE_FORCE_RULE(autogroupfg, Autogroupfg,);
|
|
|
|
WRITE_FORCE_RULE(autogroupid, Autogroupid,);
|
|
|
|
WRITE_FORCE_RULE(strictgeometry, Strictgeometry,);
|
|
|
|
WRITE_SET_RULE(shortcut, Shortcut,);
|
|
|
|
WRITE_FORCE_RULE(disableglobalshortcuts, Disableglobalshortcuts,);
|
|
|
|
WRITE_SET_RULE(desktopfile, Desktopfile,);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#undef WRITE_MATCH_STRING
|
|
|
|
#undef WRITE_SET_RULE
|
|
|
|
#undef WRITE_FORCE_RULE
|
|
|
|
|
|
|
|
// returns true if it doesn't affect anything
|
|
|
|
bool Rules::isEmpty() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
return(placementrule == UnusedForceRule
|
|
|
|
&& positionrule == UnusedSetRule
|
|
|
|
&& sizerule == UnusedSetRule
|
|
|
|
&& minsizerule == UnusedForceRule
|
|
|
|
&& maxsizerule == UnusedForceRule
|
|
|
|
&& opacityactiverule == UnusedForceRule
|
|
|
|
&& opacityinactiverule == UnusedForceRule
|
2013-03-24 18:13:00 +00:00
|
|
|
&& ignoregeometryrule == UnusedSetRule
|
2011-01-30 14:34:42 +00:00
|
|
|
&& desktoprule == UnusedSetRule
|
2012-08-24 16:48:50 +00:00
|
|
|
&& screenrule == UnusedSetRule
|
2012-05-17 14:32:06 +00:00
|
|
|
&& activityrule == UnusedSetRule
|
2011-01-30 14:34:42 +00:00
|
|
|
&& typerule == UnusedForceRule
|
|
|
|
&& maximizevertrule == UnusedSetRule
|
|
|
|
&& maximizehorizrule == UnusedSetRule
|
|
|
|
&& minimizerule == UnusedSetRule
|
|
|
|
&& shaderule == UnusedSetRule
|
|
|
|
&& skiptaskbarrule == UnusedSetRule
|
|
|
|
&& skippagerrule == UnusedSetRule
|
|
|
|
&& skipswitcherrule == UnusedSetRule
|
|
|
|
&& aboverule == UnusedSetRule
|
|
|
|
&& belowrule == UnusedSetRule
|
|
|
|
&& fullscreenrule == UnusedSetRule
|
|
|
|
&& noborderrule == UnusedSetRule
|
2013-11-05 12:42:33 +00:00
|
|
|
&& decocolorrule == UnusedForceRule
|
2011-03-20 14:42:05 +00:00
|
|
|
&& blockcompositingrule == UnusedForceRule
|
2011-01-30 14:34:42 +00:00
|
|
|
&& fsplevelrule == UnusedForceRule
|
2015-11-12 23:37:01 +00:00
|
|
|
&& fpplevelrule == UnusedForceRule
|
2011-01-30 14:34:42 +00:00
|
|
|
&& acceptfocusrule == UnusedForceRule
|
|
|
|
&& closeablerule == UnusedForceRule
|
|
|
|
&& autogrouprule == UnusedForceRule
|
|
|
|
&& autogroupfgrule == UnusedForceRule
|
|
|
|
&& autogroupidrule == UnusedForceRule
|
|
|
|
&& strictgeometryrule == UnusedForceRule
|
|
|
|
&& shortcutrule == UnusedSetRule
|
2018-03-11 16:13:32 +00:00
|
|
|
&& disableglobalshortcutsrule == UnusedForceRule
|
|
|
|
&& desktopfilerule == UnusedSetRule);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
Rules::ForceRule Rules::convertForceRule(int v)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (v == DontAffect || v == Force || v == ForceTemporarily)
|
2020-02-18 13:52:08 +00:00
|
|
|
return static_cast<ForceRule>(v);
|
2007-04-29 17:35:43 +00:00
|
|
|
return UnusedForceRule;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-02-18 13:52:08 +00:00
|
|
|
QString Rules::getDecoColor(const QString &themeName)
|
2013-11-05 12:42:33 +00:00
|
|
|
{
|
|
|
|
if (themeName.isEmpty()) {
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
// find the actual scheme file
|
|
|
|
return QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
2015-11-05 14:14:06 +00:00
|
|
|
QLatin1String("color-schemes/") + themeName + QLatin1String(".colors"));
|
2013-11-05 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::matchType(NET::WindowType match_type) const
|
|
|
|
{
|
|
|
|
if (types != NET::AllTypesMask) {
|
|
|
|
if (match_type == NET::Unknown)
|
2007-04-29 17:35:43 +00:00
|
|
|
match_type = NET::Normal; // NET::Unknown->NET::Normal is only here for matching
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!NET::typeMatchesMask(match_type, types))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::matchWMClass(const QByteArray& match_class, const QByteArray& match_name) const
|
|
|
|
{
|
|
|
|
if (wmclassmatch != UnimportantMatch) {
|
|
|
|
// TODO optimize?
|
2007-04-29 17:35:43 +00:00
|
|
|
QByteArray cwmclass = wmclasscomplete
|
2011-01-30 14:34:42 +00:00
|
|
|
? match_name + ' ' + match_class : match_class;
|
2013-07-23 05:02:52 +00:00
|
|
|
if (wmclassmatch == RegExpMatch && QRegExp(QString::fromUtf8(wmclass)).indexIn(QString::fromUtf8(cwmclass)) == -1)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (wmclassmatch == ExactMatch && wmclass != cwmclass)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (wmclassmatch == SubstringMatch && !cwmclass.contains(wmclass))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::matchRole(const QByteArray& match_role) const
|
|
|
|
{
|
|
|
|
if (windowrolematch != UnimportantMatch) {
|
2013-07-23 05:02:52 +00:00
|
|
|
if (windowrolematch == RegExpMatch && QRegExp(QString::fromUtf8(windowrole)).indexIn(QString::fromUtf8(match_role)) == -1)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (windowrolematch == ExactMatch && windowrole != match_role)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (windowrolematch == SubstringMatch && !match_role.contains(windowrole))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::matchTitle(const QString& match_title) const
|
|
|
|
{
|
|
|
|
if (titlematch != UnimportantMatch) {
|
|
|
|
if (titlematch == RegExpMatch && QRegExp(title).indexIn(match_title) == -1)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (titlematch == ExactMatch && title != match_title)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (titlematch == SubstringMatch && !match_title.contains(title))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-01-07 07:07:27 +00:00
|
|
|
bool Rules::matchClientMachine(const QByteArray& match_machine, bool local) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (clientmachinematch != UnimportantMatch) {
|
2007-04-29 17:35:43 +00:00
|
|
|
// if it's localhost, check also "localhost" before checking hostname
|
2013-01-07 07:07:27 +00:00
|
|
|
if (match_machine != "localhost" && local
|
|
|
|
&& matchClientMachine("localhost", true))
|
2007-04-29 17:35:43 +00:00
|
|
|
return true;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (clientmachinematch == RegExpMatch
|
2013-07-23 05:02:52 +00:00
|
|
|
&& QRegExp(QString::fromUtf8(clientmachine)).indexIn(QString::fromUtf8(match_machine)) == -1)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (clientmachinematch == ExactMatch
|
|
|
|
&& clientmachine != match_machine)
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (clientmachinematch == SubstringMatch
|
|
|
|
&& !match_machine.contains(clientmachine))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#ifndef KCMRULES
|
2017-10-01 14:38:57 +00:00
|
|
|
bool Rules::match(const AbstractClient* c) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (!matchType(c->windowType(true)))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!matchWMClass(c->resourceClass(), c->resourceName()))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2016-08-25 11:30:25 +00:00
|
|
|
if (!matchRole(c->windowRole().toLower()))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2013-01-07 07:07:27 +00:00
|
|
|
if (!matchClientMachine(c->clientMachine()->hostName(), c->clientMachine()->isLocal()))
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2015-09-27 19:15:35 +00:00
|
|
|
if (titlematch != UnimportantMatch) // track title changes to rematch rules
|
2017-10-01 14:38:57 +00:00
|
|
|
QObject::connect(c, &AbstractClient::captionChanged, c, &AbstractClient::evaluateWindowRules,
|
2015-09-27 19:15:35 +00:00
|
|
|
// QueuedConnection, because title may change before
|
|
|
|
// the client is ready (could segfault!)
|
|
|
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection|Qt::UniqueConnection));
|
2017-08-20 07:35:15 +00:00
|
|
|
if (!matchTitle(c->captionNormal()))
|
2015-09-27 19:15:35 +00:00
|
|
|
return false;
|
2007-04-29 17:35:43 +00:00
|
|
|
return true;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2012-02-05 17:50:23 +00:00
|
|
|
#define NOW_REMEMBER(_T_, _V_) ((selection & _T_) && (_V_##rule == (SetRule)Remember))
|
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
bool Rules::update(AbstractClient* c, int selection)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
// TODO check this setting is for this client ?
|
|
|
|
bool updated = false;
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Position, position) {
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!c->isFullScreen()) {
|
2007-04-29 17:35:43 +00:00
|
|
|
QPoint new_pos = position;
|
|
|
|
// don't use the position in the direction which is maximized
|
2011-01-30 14:34:42 +00:00
|
|
|
if ((c->maximizeMode() & MaximizeHorizontal) == 0)
|
|
|
|
new_pos.setX(c->pos().x());
|
|
|
|
if ((c->maximizeMode() & MaximizeVertical) == 0)
|
|
|
|
new_pos.setY(c->pos().y());
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || position != new_pos;
|
|
|
|
position = new_pos;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Size, size) {
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!c->isFullScreen()) {
|
2007-04-29 17:35:43 +00:00
|
|
|
QSize new_size = size;
|
|
|
|
// don't use the position in the direction which is maximized
|
2011-01-30 14:34:42 +00:00
|
|
|
if ((c->maximizeMode() & MaximizeHorizontal) == 0)
|
|
|
|
new_size.setWidth(c->size().width());
|
|
|
|
if ((c->maximizeMode() & MaximizeVertical) == 0)
|
|
|
|
new_size.setHeight(c->size().height());
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || size != new_size;
|
|
|
|
size = new_size;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Desktop, desktop) {
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || desktop != c->desktop();
|
|
|
|
desktop = c->desktop();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-08-24 16:48:50 +00:00
|
|
|
if NOW_REMEMBER(Screen, screen) {
|
|
|
|
updated = updated || screen != c->screen();
|
|
|
|
screen = c->screen();
|
|
|
|
}
|
2012-05-17 14:32:06 +00:00
|
|
|
if NOW_REMEMBER(Activity, activity) {
|
2020-11-05 20:54:07 +00:00
|
|
|
updated = updated || activity != c->activities();
|
|
|
|
activity = c->activities();
|
2012-05-17 14:32:06 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(MaximizeVert, maximizevert) {
|
2011-01-30 14:34:42 +00:00
|
|
|
updated = updated || maximizevert != bool(c->maximizeMode() & MaximizeVertical);
|
2007-04-29 17:35:43 +00:00
|
|
|
maximizevert = c->maximizeMode() & MaximizeVertical;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(MaximizeHoriz, maximizehoriz) {
|
2011-01-30 14:34:42 +00:00
|
|
|
updated = updated || maximizehoriz != bool(c->maximizeMode() & MaximizeHorizontal);
|
2007-04-29 17:35:43 +00:00
|
|
|
maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Minimize, minimize) {
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || minimize != c->isMinimized();
|
|
|
|
minimize = c->isMinimized();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Shade, shade) {
|
2011-01-30 14:34:42 +00:00
|
|
|
updated = updated || (shade != (c->shadeMode() != ShadeNone));
|
2007-04-29 17:35:43 +00:00
|
|
|
shade = c->shadeMode() != ShadeNone;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(SkipTaskbar, skiptaskbar) {
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || skiptaskbar != c->skipTaskbar();
|
|
|
|
skiptaskbar = c->skipTaskbar();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(SkipPager, skippager) {
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || skippager != c->skipPager();
|
|
|
|
skippager = c->skipPager();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(SkipSwitcher, skipswitcher) {
|
2010-05-03 20:04:44 +00:00
|
|
|
updated = updated || skipswitcher != c->skipSwitcher();
|
|
|
|
skipswitcher = c->skipSwitcher();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Above, above) {
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || above != c->keepAbove();
|
|
|
|
above = c->keepAbove();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Below, below) {
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || below != c->keepBelow();
|
|
|
|
below = c->keepBelow();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(Fullscreen, fullscreen) {
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = updated || fullscreen != c->isFullScreen();
|
|
|
|
fullscreen = c->isFullScreen();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-02-05 17:50:23 +00:00
|
|
|
if NOW_REMEMBER(NoBorder, noborder) {
|
2008-03-23 00:12:11 +00:00
|
|
|
updated = updated || noborder != c->noBorder();
|
|
|
|
noborder = c->noBorder();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2018-03-11 16:13:32 +00:00
|
|
|
if NOW_REMEMBER(DesktopFile, desktopfile) {
|
|
|
|
updated = updated || desktopfile != c->desktopFileName();
|
|
|
|
desktopfile = c->desktopFileName();
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return updated;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2012-02-05 17:50:23 +00:00
|
|
|
#undef NOW_REMEMBER
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
#define APPLY_RULE( var, name, type ) \
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::apply##name( type& arg, bool init ) const \
|
2007-04-29 17:35:43 +00:00
|
|
|
{ \
|
2011-01-30 14:34:42 +00:00
|
|
|
if ( checkSetRule( var##rule, init )) \
|
|
|
|
arg = this->var; \
|
|
|
|
return checkSetStop( var##rule ); \
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define APPLY_FORCE_RULE( var, name, type ) \
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::apply##name( type& arg ) const \
|
2007-04-29 17:35:43 +00:00
|
|
|
{ \
|
2011-01-30 14:34:42 +00:00
|
|
|
if ( checkForceRule( var##rule )) \
|
|
|
|
arg = this->var; \
|
|
|
|
return checkForceStop( var##rule ); \
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
APPLY_FORCE_RULE(placement, Placement, Placement::Policy)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::applyGeometry(QRect& rect, bool init) const
|
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
QPoint p = rect.topLeft();
|
|
|
|
QSize s = rect.size();
|
|
|
|
bool ret = false; // no short-circuiting
|
2011-01-30 14:34:42 +00:00
|
|
|
if (applyPosition(p, init)) {
|
|
|
|
rect.moveTopLeft(p);
|
2007-04-29 17:35:43 +00:00
|
|
|
ret = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if (applySize(s, init)) {
|
|
|
|
rect.setSize(s);
|
2007-04-29 17:35:43 +00:00
|
|
|
ret = true;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::applyPosition(QPoint& pos, bool init) const
|
|
|
|
{
|
|
|
|
if (this->position != invalidPoint && checkSetRule(positionrule, init))
|
2007-04-29 17:35:43 +00:00
|
|
|
pos = this->position;
|
2011-01-30 14:34:42 +00:00
|
|
|
return checkSetStop(positionrule);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::applySize(QSize& s, bool init) const
|
|
|
|
{
|
|
|
|
if (this->size.isValid() && checkSetRule(sizerule, init))
|
2007-04-29 17:35:43 +00:00
|
|
|
s = this->size;
|
2011-01-30 14:34:42 +00:00
|
|
|
return checkSetStop(sizerule);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
APPLY_FORCE_RULE(minsize, MinSize, QSize)
|
|
|
|
APPLY_FORCE_RULE(maxsize, MaxSize, QSize)
|
|
|
|
APPLY_FORCE_RULE(opacityactive, OpacityActive, int)
|
|
|
|
APPLY_FORCE_RULE(opacityinactive, OpacityInactive, int)
|
2013-03-24 18:13:00 +00:00
|
|
|
APPLY_RULE(ignoregeometry, IgnoreGeometry, bool)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
APPLY_RULE(desktop, Desktop, int)
|
2012-08-24 16:48:50 +00:00
|
|
|
APPLY_RULE(screen, Screen, int)
|
2020-11-05 20:54:07 +00:00
|
|
|
APPLY_RULE(activity, Activity, QStringList)
|
2011-01-30 14:34:42 +00:00
|
|
|
APPLY_FORCE_RULE(type, Type, NET::WindowType)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::applyMaximizeHoriz(MaximizeMode& mode, bool init) const
|
|
|
|
{
|
|
|
|
if (checkSetRule(maximizehorizrule, init))
|
|
|
|
mode = static_cast< MaximizeMode >((maximizehoriz ? MaximizeHorizontal : 0) | (mode & MaximizeVertical));
|
|
|
|
return checkSetStop(maximizehorizrule);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::applyMaximizeVert(MaximizeMode& mode, bool init) const
|
|
|
|
{
|
|
|
|
if (checkSetRule(maximizevertrule, init))
|
|
|
|
mode = static_cast< MaximizeMode >((maximizevert ? MaximizeVertical : 0) | (mode & MaximizeHorizontal));
|
|
|
|
return checkSetStop(maximizevertrule);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
APPLY_RULE(minimize, Minimize, bool)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::applyShade(ShadeMode& sh, bool init) const
|
|
|
|
{
|
|
|
|
if (checkSetRule(shaderule, init)) {
|
|
|
|
if (!this->shade)
|
2007-04-29 17:35:43 +00:00
|
|
|
sh = ShadeNone;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (this->shade && sh == ShadeNone)
|
2007-04-29 17:35:43 +00:00
|
|
|
sh = ShadeNormal;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return checkSetStop(shaderule);
|
|
|
|
}
|
|
|
|
|
|
|
|
APPLY_RULE(skiptaskbar, SkipTaskbar, bool)
|
|
|
|
APPLY_RULE(skippager, SkipPager, bool)
|
|
|
|
APPLY_RULE(skipswitcher, SkipSwitcher, bool)
|
|
|
|
APPLY_RULE(above, KeepAbove, bool)
|
|
|
|
APPLY_RULE(below, KeepBelow, bool)
|
|
|
|
APPLY_RULE(fullscreen, FullScreen, bool)
|
|
|
|
APPLY_RULE(noborder, NoBorder, bool)
|
2013-11-05 12:42:33 +00:00
|
|
|
APPLY_FORCE_RULE(decocolor, DecoColor, QString)
|
2011-03-20 14:42:05 +00:00
|
|
|
APPLY_FORCE_RULE(blockcompositing, BlockCompositing, bool)
|
2011-01-30 14:34:42 +00:00
|
|
|
APPLY_FORCE_RULE(fsplevel, FSP, int)
|
2015-11-12 23:37:01 +00:00
|
|
|
APPLY_FORCE_RULE(fpplevel, FPP, int)
|
2011-01-30 14:34:42 +00:00
|
|
|
APPLY_FORCE_RULE(acceptfocus, AcceptFocus, bool)
|
|
|
|
APPLY_FORCE_RULE(closeable, Closeable, bool)
|
|
|
|
APPLY_FORCE_RULE(autogroup, Autogrouping, bool)
|
|
|
|
APPLY_FORCE_RULE(autogroupfg, AutogroupInForeground, bool)
|
|
|
|
APPLY_FORCE_RULE(autogroupid, AutogroupById, QString)
|
|
|
|
APPLY_FORCE_RULE(strictgeometry, StrictGeometry, bool)
|
|
|
|
APPLY_RULE(shortcut, Shortcut, QString)
|
|
|
|
APPLY_FORCE_RULE(disableglobalshortcuts, DisableGlobalShortcuts, bool)
|
2018-03-11 16:13:32 +00:00
|
|
|
APPLY_RULE(desktopfile, DesktopFile, QString)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
#undef APPLY_RULE
|
|
|
|
#undef APPLY_FORCE_RULE
|
|
|
|
|
|
|
|
bool Rules::isTemporary() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
return temporary_state > 0;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Rules::discardTemporary(bool force)
|
|
|
|
{
|
|
|
|
if (temporary_state == 0) // not temporary
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (force || --temporary_state == 0) { // too old
|
2007-04-29 17:35:43 +00:00
|
|
|
delete this;
|
|
|
|
return true;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#define DISCARD_USED_SET_RULE( var ) \
|
|
|
|
do { \
|
2018-05-07 19:59:17 +00:00
|
|
|
if ( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) { \
|
2011-01-30 14:34:42 +00:00
|
|
|
var##rule = UnusedSetRule; \
|
2018-05-07 19:59:17 +00:00
|
|
|
changed = true; \
|
|
|
|
} \
|
2011-01-30 14:34:42 +00:00
|
|
|
} while ( false )
|
2007-04-29 17:35:43 +00:00
|
|
|
#define DISCARD_USED_FORCE_RULE( var ) \
|
|
|
|
do { \
|
2018-05-07 19:59:17 +00:00
|
|
|
if ( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) { \
|
2011-01-30 14:34:42 +00:00
|
|
|
var##rule = UnusedForceRule; \
|
2018-05-07 19:59:17 +00:00
|
|
|
changed = true; \
|
|
|
|
} \
|
2011-01-30 14:34:42 +00:00
|
|
|
} while ( false )
|
|
|
|
|
2018-05-07 19:59:17 +00:00
|
|
|
bool Rules::discardUsed(bool withdrawn)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2018-05-07 19:59:17 +00:00
|
|
|
bool changed = false;
|
2011-01-30 14:34:42 +00:00
|
|
|
DISCARD_USED_FORCE_RULE(placement);
|
|
|
|
DISCARD_USED_SET_RULE(position);
|
|
|
|
DISCARD_USED_SET_RULE(size);
|
|
|
|
DISCARD_USED_FORCE_RULE(minsize);
|
|
|
|
DISCARD_USED_FORCE_RULE(maxsize);
|
|
|
|
DISCARD_USED_FORCE_RULE(opacityactive);
|
|
|
|
DISCARD_USED_FORCE_RULE(opacityinactive);
|
2013-03-24 18:13:00 +00:00
|
|
|
DISCARD_USED_SET_RULE(ignoregeometry);
|
2011-01-30 14:34:42 +00:00
|
|
|
DISCARD_USED_SET_RULE(desktop);
|
2012-08-24 16:48:50 +00:00
|
|
|
DISCARD_USED_SET_RULE(screen);
|
2012-05-17 14:32:06 +00:00
|
|
|
DISCARD_USED_SET_RULE(activity);
|
2011-01-30 14:34:42 +00:00
|
|
|
DISCARD_USED_FORCE_RULE(type);
|
|
|
|
DISCARD_USED_SET_RULE(maximizevert);
|
|
|
|
DISCARD_USED_SET_RULE(maximizehoriz);
|
|
|
|
DISCARD_USED_SET_RULE(minimize);
|
|
|
|
DISCARD_USED_SET_RULE(shade);
|
|
|
|
DISCARD_USED_SET_RULE(skiptaskbar);
|
|
|
|
DISCARD_USED_SET_RULE(skippager);
|
|
|
|
DISCARD_USED_SET_RULE(skipswitcher);
|
|
|
|
DISCARD_USED_SET_RULE(above);
|
|
|
|
DISCARD_USED_SET_RULE(below);
|
|
|
|
DISCARD_USED_SET_RULE(fullscreen);
|
|
|
|
DISCARD_USED_SET_RULE(noborder);
|
2013-11-05 12:42:33 +00:00
|
|
|
DISCARD_USED_FORCE_RULE(decocolor);
|
2011-03-20 14:42:05 +00:00
|
|
|
DISCARD_USED_FORCE_RULE(blockcompositing);
|
2011-01-30 14:34:42 +00:00
|
|
|
DISCARD_USED_FORCE_RULE(fsplevel);
|
2015-11-12 23:37:01 +00:00
|
|
|
DISCARD_USED_FORCE_RULE(fpplevel);
|
2011-01-30 14:34:42 +00:00
|
|
|
DISCARD_USED_FORCE_RULE(acceptfocus);
|
|
|
|
DISCARD_USED_FORCE_RULE(closeable);
|
|
|
|
DISCARD_USED_FORCE_RULE(autogroup);
|
|
|
|
DISCARD_USED_FORCE_RULE(autogroupfg);
|
|
|
|
DISCARD_USED_FORCE_RULE(autogroupid);
|
|
|
|
DISCARD_USED_FORCE_RULE(strictgeometry);
|
|
|
|
DISCARD_USED_SET_RULE(shortcut);
|
|
|
|
DISCARD_USED_FORCE_RULE(disableglobalshortcuts);
|
2018-03-11 16:13:32 +00:00
|
|
|
DISCARD_USED_SET_RULE(desktopfile);
|
2018-05-07 19:59:17 +00:00
|
|
|
|
|
|
|
return changed;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
#undef DISCARD_USED_SET_RULE
|
|
|
|
#undef DISCARD_USED_FORCE_RULE
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QDebug& operator<<(QDebug& stream, const Rules* r)
|
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
return stream << "[" << r->description << ":" << r->wmclass << "]" ;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#ifndef KCMRULES
|
|
|
|
void WindowRules::discardTemporary()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
QVector< Rules* >::Iterator it2 = rules.begin();
|
2011-01-30 14:34:42 +00:00
|
|
|
for (QVector< Rules* >::Iterator it = rules.begin();
|
|
|
|
it != rules.end();
|
|
|
|
) {
|
|
|
|
if ((*it)->discardTemporary(true))
|
2007-04-29 17:35:43 +00:00
|
|
|
++it;
|
2011-01-30 14:34:42 +00:00
|
|
|
else {
|
2007-04-29 17:35:43 +00:00
|
|
|
*it2++ = *it++;
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
rules.erase(it2, rules.end());
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
void WindowRules::update(AbstractClient* c, int selection)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
bool updated = false;
|
2011-01-30 14:34:42 +00:00
|
|
|
for (QVector< Rules* >::ConstIterator it = rules.constBegin();
|
|
|
|
it != rules.constEnd();
|
|
|
|
++it)
|
2012-02-05 17:50:23 +00:00
|
|
|
if ((*it)->update(c, selection)) // no short-circuiting here
|
2007-04-29 17:35:43 +00:00
|
|
|
updated = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (updated)
|
2013-04-26 12:40:35 +00:00
|
|
|
RuleBook::self()->requestDiskStorage();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#define CHECK_RULE( rule, type ) \
|
2011-01-30 14:34:42 +00:00
|
|
|
type WindowRules::check##rule( type arg, bool init ) const \
|
2007-04-29 17:35:43 +00:00
|
|
|
{ \
|
2011-01-30 14:34:42 +00:00
|
|
|
if ( rules.count() == 0 ) \
|
|
|
|
return arg; \
|
|
|
|
type ret = arg; \
|
|
|
|
for ( QVector< Rules* >::ConstIterator it = rules.constBegin(); \
|
|
|
|
it != rules.constEnd(); \
|
|
|
|
++it ) \
|
2007-04-29 17:35:43 +00:00
|
|
|
{ \
|
2011-01-30 14:34:42 +00:00
|
|
|
if ( (*it)->apply##rule( ret, init )) \
|
|
|
|
break; \
|
2007-04-29 17:35:43 +00:00
|
|
|
} \
|
2011-01-30 14:34:42 +00:00
|
|
|
return ret; \
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define CHECK_FORCE_RULE( rule, type ) \
|
2011-01-30 14:34:42 +00:00
|
|
|
type WindowRules::check##rule( type arg ) const \
|
2007-04-29 17:35:43 +00:00
|
|
|
{ \
|
2011-01-30 14:34:42 +00:00
|
|
|
if ( rules.count() == 0 ) \
|
|
|
|
return arg; \
|
|
|
|
type ret = arg; \
|
|
|
|
for ( QVector< Rules* >::ConstIterator it = rules.begin(); \
|
|
|
|
it != rules.end(); \
|
|
|
|
++it ) \
|
2007-04-29 17:35:43 +00:00
|
|
|
{ \
|
2011-01-30 14:34:42 +00:00
|
|
|
if ( (*it)->apply##rule( ret )) \
|
|
|
|
break; \
|
2007-04-29 17:35:43 +00:00
|
|
|
} \
|
2011-01-30 14:34:42 +00:00
|
|
|
return ret; \
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
CHECK_FORCE_RULE(Placement, Placement::Policy)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRect WindowRules::checkGeometry(QRect rect, bool init) const
|
|
|
|
{
|
|
|
|
return QRect(checkPosition(rect.topLeft(), init), checkSize(rect.size(), init));
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK_RULE(Position, QPoint)
|
|
|
|
CHECK_RULE(Size, QSize)
|
|
|
|
CHECK_FORCE_RULE(MinSize, QSize)
|
|
|
|
CHECK_FORCE_RULE(MaxSize, QSize)
|
|
|
|
CHECK_FORCE_RULE(OpacityActive, int)
|
|
|
|
CHECK_FORCE_RULE(OpacityInactive, int)
|
2013-03-24 18:13:00 +00:00
|
|
|
CHECK_RULE(IgnoreGeometry, bool)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
CHECK_RULE(Desktop, int)
|
2020-11-05 20:54:07 +00:00
|
|
|
CHECK_RULE(Activity, QStringList)
|
2011-01-30 14:34:42 +00:00
|
|
|
CHECK_FORCE_RULE(Type, NET::WindowType)
|
2014-12-02 12:49:08 +00:00
|
|
|
CHECK_RULE(MaximizeVert, MaximizeMode)
|
|
|
|
CHECK_RULE(MaximizeHoriz, MaximizeMode)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2014-12-02 12:49:08 +00:00
|
|
|
MaximizeMode WindowRules::checkMaximize(MaximizeMode mode, bool init) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
bool vert = checkMaximizeVert(mode, init) & MaximizeVertical;
|
|
|
|
bool horiz = checkMaximizeHoriz(mode, init) & MaximizeHorizontal;
|
|
|
|
return static_cast< MaximizeMode >((vert ? MaximizeVertical : 0) | (horiz ? MaximizeHorizontal : 0));
|
|
|
|
}
|
|
|
|
|
2012-08-24 16:48:50 +00:00
|
|
|
int WindowRules::checkScreen(int screen, bool init) const
|
|
|
|
{
|
|
|
|
if ( rules.count() == 0 )
|
|
|
|
return screen;
|
|
|
|
int ret = screen;
|
|
|
|
for ( QVector< Rules* >::ConstIterator it = rules.constBegin(); it != rules.constEnd(); ++it ) {
|
|
|
|
if ( (*it)->applyScreen( ret, init ))
|
|
|
|
break;
|
|
|
|
}
|
2013-04-03 10:19:27 +00:00
|
|
|
if (ret >= Screens::self()->count())
|
2012-08-24 16:48:50 +00:00
|
|
|
ret = screen;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
CHECK_RULE(Minimize, bool)
|
|
|
|
CHECK_RULE(Shade, ShadeMode)
|
|
|
|
CHECK_RULE(SkipTaskbar, bool)
|
|
|
|
CHECK_RULE(SkipPager, bool)
|
|
|
|
CHECK_RULE(SkipSwitcher, bool)
|
|
|
|
CHECK_RULE(KeepAbove, bool)
|
|
|
|
CHECK_RULE(KeepBelow, bool)
|
|
|
|
CHECK_RULE(FullScreen, bool)
|
|
|
|
CHECK_RULE(NoBorder, bool)
|
2013-11-05 12:42:33 +00:00
|
|
|
CHECK_FORCE_RULE(DecoColor, QString)
|
2011-03-20 14:42:05 +00:00
|
|
|
CHECK_FORCE_RULE(BlockCompositing, bool)
|
2011-01-30 14:34:42 +00:00
|
|
|
CHECK_FORCE_RULE(FSP, int)
|
2015-11-12 23:37:01 +00:00
|
|
|
CHECK_FORCE_RULE(FPP, int)
|
2011-01-30 14:34:42 +00:00
|
|
|
CHECK_FORCE_RULE(AcceptFocus, bool)
|
|
|
|
CHECK_FORCE_RULE(Closeable, bool)
|
|
|
|
CHECK_FORCE_RULE(Autogrouping, bool)
|
|
|
|
CHECK_FORCE_RULE(AutogroupInForeground, bool)
|
|
|
|
CHECK_FORCE_RULE(AutogroupById, QString)
|
|
|
|
CHECK_FORCE_RULE(StrictGeometry, bool)
|
|
|
|
CHECK_RULE(Shortcut, QString)
|
|
|
|
CHECK_FORCE_RULE(DisableGlobalShortcuts, bool)
|
2018-03-11 16:13:32 +00:00
|
|
|
CHECK_RULE(DesktopFile, QString)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#undef CHECK_RULE
|
|
|
|
#undef CHECK_FORCE_RULE
|
|
|
|
|
|
|
|
// Client
|
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
void AbstractClient::setupWindowRules(bool ignore_temporary)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2017-10-01 14:38:57 +00:00
|
|
|
disconnect(this, &AbstractClient::captionChanged, this, &AbstractClient::evaluateWindowRules);
|
|
|
|
m_rules = RuleBook::self()->find(this, ignore_temporary);
|
2007-04-29 17:35:43 +00:00
|
|
|
// check only after getting the rules, because there may be a rule forcing window type
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
// Applies Force, ForceTemporarily and ApplyNow rules
|
|
|
|
// Used e.g. after the rules have been modified using the kcm.
|
2017-10-01 14:38:57 +00:00
|
|
|
void AbstractClient::applyWindowRules()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
// apply force rules
|
|
|
|
// Placement - does need explicit update, just like some others below
|
|
|
|
// Geometry : setGeometry() doesn't check rules
|
2017-10-01 14:38:57 +00:00
|
|
|
auto client_rules = rules();
|
Refactor geometry constraints code
Summary:
Currently, there are a couple of issues with sizeForClientSize(). First
of all, we have a method called clientSizeToFrameSize() which does similar
thing except applying geometry constraints and checking window rules. The
other issue is that sizeForClientSize() is doing a bit too much, it checks
window rules, it applies a bunch of geometry constrains. Sometimes it
does not perform conversion between client sizes and frame sizes!
This change attempts to address those issues by replacing sizeForClientSize
with two similar methods and changing semantics of some methods of the
X11Client class.
The most significant difference between sizeForClientSize() and the new
methods is that neither constrainClientSize() nor constrainFrameSize()
check window rules. This is up to users of those methods. In many places,
we don't have to check window rules because we check isResizable(),
which returns false if the frame size is enforced by a window rule.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D26828
2020-02-12 10:38:40 +00:00
|
|
|
QRect orig_geom = QRect(pos(), adjustedSize()); // handle shading
|
2017-10-01 14:38:57 +00:00
|
|
|
QRect geom = client_rules->checkGeometry(orig_geom);
|
2011-01-30 14:34:42 +00:00
|
|
|
if (geom != orig_geom)
|
Rework async geometry updates
Window management features were written with synchronous geometry
updates in mind. Currently, this poses a big problem on Wayland because
geometry updates are done in asynchronous fashion there.
At the moment, geometry is updated in a so called pseudo-asynchronous
fashion, meaning that the frame geometry will be reset to the old value
once geometry updates are unblocked. The main drawback of this approach
is that it is too error prone, the data flow is hard to comprehend, etc.
It is worth noting that there is already a machinery to perform async
geometry which is used during interactive move/resize operations.
This change extends the move/resize geometry usage beyond interactive
move/resize to make asynchronous geometry updates less error prone and
easier to comprehend.
With the proposed solution, all geometry updates must be done on the
move/resize geometry first. After that, the new geometry is passed on to
the Client-specific implementation of moveResizeInternal().
To be more specific, the frameGeometry() returns the current frame
geometry, it is primarily useful only to the scene. If you want to move
or resize a window, you need to use moveResizeGeometry() because it
corresponds to the last requested frame geometry.
It is worth noting that the moveResizeGeometry() returns the desired
bounding geometry. The client may commit the xdg_toplevel surface with a
slightly smaller window geometry, for example to enforce a specific
aspect ratio. The client is not allowed to resize beyond the size as
indicated in moveResizeGeometry().
The data flow is very simple: moveResize() updates the move/resize
geometry and calls the client-specific implementation of the
moveResizeInternal() method. Based on whether a configure event is
needed, moveResizeInternal() will update the frameGeometry() either
immediately or after the client commits a new buffer.
Unfortunately, both the compositor and xdg-shell clients try to update
the window geometry. It means that it's possible to have conflicts
between the two. With this change, the compositor's move resize geometry
will be synced only if there are no pending configure events, meaning
that the user doesn't try to resize the window.
2021-04-30 18:26:09 +00:00
|
|
|
moveResize(geom);
|
2007-04-29 17:35:43 +00:00
|
|
|
// MinSize, MaxSize handled by Geometry
|
2013-03-24 18:13:00 +00:00
|
|
|
// IgnoreGeometry
|
2011-01-30 14:34:42 +00:00
|
|
|
setDesktop(desktop());
|
2012-08-24 16:48:50 +00:00
|
|
|
workspace()->sendClientToScreen(this, screen());
|
2012-05-17 14:32:06 +00:00
|
|
|
setOnActivities(activities());
|
2007-04-29 17:35:43 +00:00
|
|
|
// Type
|
2011-01-30 14:34:42 +00:00
|
|
|
maximize(maximizeMode());
|
2007-04-29 17:35:43 +00:00
|
|
|
// Minimize : functions don't check, and there are two functions
|
2017-10-01 14:38:57 +00:00
|
|
|
if (client_rules->checkMinimize(isMinimized()))
|
2007-04-29 17:35:43 +00:00
|
|
|
minimize();
|
|
|
|
else
|
|
|
|
unminimize();
|
2011-01-30 14:34:42 +00:00
|
|
|
setShade(shadeMode());
|
2015-06-06 20:08:12 +00:00
|
|
|
setOriginalSkipTaskbar(skipTaskbar());
|
2011-01-30 14:34:42 +00:00
|
|
|
setSkipPager(skipPager());
|
|
|
|
setSkipSwitcher(skipSwitcher());
|
|
|
|
setKeepAbove(keepAbove());
|
|
|
|
setKeepBelow(keepBelow());
|
|
|
|
setFullScreen(isFullScreen(), true);
|
|
|
|
setNoBorder(noBorder());
|
2013-11-05 12:42:33 +00:00
|
|
|
updateColorScheme();
|
2007-04-29 17:35:43 +00:00
|
|
|
// FSP
|
|
|
|
// AcceptFocus :
|
2011-01-30 14:34:42 +00:00
|
|
|
if (workspace()->mostRecentlyActivatedClient() == this
|
2017-10-01 14:38:57 +00:00
|
|
|
&& !client_rules->checkAcceptFocus(true))
|
2011-01-30 14:34:42 +00:00
|
|
|
workspace()->activateNextClient(this);
|
2007-04-29 17:35:43 +00:00
|
|
|
// Closeable
|
|
|
|
QSize s = adjustedSize();
|
2019-06-23 17:54:34 +00:00
|
|
|
if (s != size() && s.isValid())
|
2011-01-30 14:34:42 +00:00
|
|
|
resizeWithChecks(s);
|
2009-11-16 11:26:37 +00:00
|
|
|
// Autogrouping : Only checked on window manage
|
2009-11-17 10:41:32 +00:00
|
|
|
// AutogroupInForeground : Only checked on window manage
|
2009-11-16 13:31:02 +00:00
|
|
|
// AutogroupById : Only checked on window manage
|
2007-04-29 17:35:43 +00:00
|
|
|
// StrictGeometry
|
2011-01-30 14:34:42 +00:00
|
|
|
setShortcut(rules()->checkShortcut(shortcut().toString()));
|
2019-09-24 08:48:08 +00:00
|
|
|
// see also X11Client::setActive()
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isActive()) {
|
|
|
|
setOpacity(rules()->checkOpacityActive(qRound(opacity() * 100.0)) / 100.0);
|
|
|
|
workspace()->disableGlobalShortcutsForClient(rules()->checkDisableGlobalShortcuts(false));
|
|
|
|
} else
|
|
|
|
setOpacity(rules()->checkOpacityInactive(qRound(opacity() * 100.0)) / 100.0);
|
2018-03-11 16:13:32 +00:00
|
|
|
setDesktopFileName(rules()->checkDesktopFile(desktopFileName()).toUtf8());
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-09-24 08:48:08 +00:00
|
|
|
void X11Client::updateWindowRules(Rules::Types selection)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (!isManaged()) // not fully setup yet
|
2007-04-29 17:35:43 +00:00
|
|
|
return;
|
2017-10-01 14:38:57 +00:00
|
|
|
AbstractClient::updateWindowRules(selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractClient::updateWindowRules(Rules::Types selection)
|
|
|
|
{
|
2013-04-26 12:40:35 +00:00
|
|
|
if (RuleBook::self()->areUpdatesDisabled())
|
2007-04-30 12:24:10 +00:00
|
|
|
return;
|
2017-10-01 14:38:57 +00:00
|
|
|
m_rules.update(this, selection);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
void AbstractClient::finishWindowRules()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2012-02-05 17:50:23 +00:00
|
|
|
updateWindowRules(Rules::All);
|
2017-10-01 14:38:57 +00:00
|
|
|
m_rules = WindowRules();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
// Workspace
|
2013-04-26 12:40:35 +00:00
|
|
|
KWIN_SINGLETON_FACTORY(RuleBook)
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
RuleBook::RuleBook(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
, m_updateTimer(new QTimer(this))
|
|
|
|
, m_updatesDisabled(false)
|
2017-09-02 09:09:41 +00:00
|
|
|
, m_temporaryRulesMessages()
|
2013-04-26 12:40:35 +00:00
|
|
|
{
|
2020-07-20 08:07:08 +00:00
|
|
|
initializeX11();
|
|
|
|
connect(kwinApp(), &Application::x11ConnectionChanged, this, &RuleBook::initializeX11);
|
|
|
|
connect(kwinApp(), &Application::x11ConnectionAboutToBeDestroyed, this, &RuleBook::cleanupX11);
|
2020-09-23 18:39:59 +00:00
|
|
|
connect(m_updateTimer, &QTimer::timeout, this, &RuleBook::save);
|
2013-04-26 12:40:35 +00:00
|
|
|
m_updateTimer->setInterval(1000);
|
|
|
|
m_updateTimer->setSingleShot(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
RuleBook::~RuleBook()
|
|
|
|
{
|
|
|
|
save();
|
|
|
|
deleteAll();
|
|
|
|
}
|
|
|
|
|
2020-07-20 08:07:08 +00:00
|
|
|
void RuleBook::initializeX11()
|
2017-09-02 09:09:41 +00:00
|
|
|
{
|
|
|
|
auto c = kwinApp()->x11Connection();
|
|
|
|
if (!c) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_temporaryRulesMessages.reset(new KXMessages(c, kwinApp()->x11RootWindow(), "_KDE_NET_WM_TEMPORARY_RULES", nullptr));
|
2020-09-23 18:39:59 +00:00
|
|
|
connect(m_temporaryRulesMessages.data(), &KXMessages::gotMessage, this, &RuleBook::temporaryRulesMessage);
|
2017-09-02 09:09:41 +00:00
|
|
|
}
|
|
|
|
|
2020-07-20 08:07:08 +00:00
|
|
|
void RuleBook::cleanupX11()
|
|
|
|
{
|
|
|
|
m_temporaryRulesMessages.reset();
|
|
|
|
}
|
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
void RuleBook::deleteAll()
|
|
|
|
{
|
|
|
|
qDeleteAll(m_rules);
|
|
|
|
m_rules.clear();
|
|
|
|
}
|
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
WindowRules RuleBook::find(const AbstractClient* c, bool ignore_temporary)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
QVector< Rules* > ret;
|
2013-04-26 12:40:35 +00:00
|
|
|
for (QList< Rules* >::Iterator it = m_rules.begin();
|
|
|
|
it != m_rules.end();
|
2011-01-30 14:34:42 +00:00
|
|
|
) {
|
|
|
|
if (ignore_temporary && (*it)->isTemporary()) {
|
2007-04-29 17:35:43 +00:00
|
|
|
++it;
|
|
|
|
continue;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if ((*it)->match(c)) {
|
2007-04-29 17:35:43 +00:00
|
|
|
Rules* rule = *it;
|
2014-12-05 10:42:15 +00:00
|
|
|
qCDebug(KWIN_CORE) << "Rule found:" << rule << ":" << c;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (rule->isTemporary())
|
2013-04-26 12:40:35 +00:00
|
|
|
it = m_rules.erase(it);
|
2007-04-29 17:35:43 +00:00
|
|
|
else
|
|
|
|
++it;
|
2011-01-30 14:34:42 +00:00
|
|
|
ret.append(rule);
|
2007-04-29 17:35:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
++it;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return WindowRules(ret);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2015-03-06 08:33:18 +00:00
|
|
|
void RuleBook::edit(AbstractClient* c, bool whole_app)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-04-26 12:40:35 +00:00
|
|
|
save();
|
2007-04-29 17:35:43 +00:00
|
|
|
QStringList args;
|
2018-12-23 07:56:15 +00:00
|
|
|
args << QStringLiteral("--uuid") << c->internalId().toString();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (whole_app)
|
2013-07-23 05:02:52 +00:00
|
|
|
args << QStringLiteral("--whole-app");
|
2015-12-15 09:22:03 +00:00
|
|
|
QProcess *p = new Process(this);
|
2015-07-07 15:35:57 +00:00
|
|
|
p->setArguments(args);
|
|
|
|
p->setProcessEnvironment(kwinApp()->processStartupEnvironment());
|
2018-11-08 21:08:06 +00:00
|
|
|
const QFileInfo buildDirBinary{QDir{QCoreApplication::applicationDirPath()}, QStringLiteral("kwin_rules_dialog")};
|
|
|
|
p->setProgram(buildDirBinary.exists() ? buildDirBinary.absoluteFilePath() : QStringLiteral(KWIN_RULES_DIALOG_BIN));
|
2018-12-23 07:56:15 +00:00
|
|
|
p->setProcessChannelMode(QProcess::MergedChannels);
|
2015-08-11 06:36:36 +00:00
|
|
|
connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), p, &QProcess::deleteLater);
|
2020-01-25 20:34:15 +00:00
|
|
|
connect(p, &QProcess::errorOccurred, this, [p](QProcess::ProcessError e) {
|
|
|
|
if (e == QProcess::FailedToStart) {
|
|
|
|
qCDebug(KWIN_CORE) << "Failed to start" << p->program();
|
2015-07-07 15:35:57 +00:00
|
|
|
}
|
2020-01-25 20:34:15 +00:00
|
|
|
});
|
2015-07-07 15:35:57 +00:00
|
|
|
p->start();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
void RuleBook::load()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-04-26 12:40:35 +00:00
|
|
|
deleteAll();
|
2018-02-11 17:27:34 +00:00
|
|
|
if (!m_config) {
|
|
|
|
m_config = KSharedConfig::openConfig(QStringLiteral(KWIN_NAME "rulesrc"), KConfig::NoGlobals);
|
2018-05-05 07:11:34 +00:00
|
|
|
} else {
|
|
|
|
m_config->reparseConfiguration();
|
2018-02-11 17:27:34 +00:00
|
|
|
}
|
2020-02-18 13:52:08 +00:00
|
|
|
m_rules = RuleBookSettings(m_config).rules().toList();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
void RuleBook::save()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-04-26 12:40:35 +00:00
|
|
|
m_updateTimer->stop();
|
2018-05-07 19:35:34 +00:00
|
|
|
if (!m_config) {
|
2019-11-26 17:48:29 +00:00
|
|
|
qCWarning(KWIN_CORE) << "RuleBook::save invoked without prior invocation of RuleBook::load";
|
2018-05-07 19:35:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-02-18 13:52:08 +00:00
|
|
|
QVector<Rules *> filteredRules;
|
|
|
|
for (const auto &rule : qAsConst(m_rules)) {
|
|
|
|
if (!rule->isTemporary()) {
|
|
|
|
filteredRules.append(rule);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2020-02-18 13:52:08 +00:00
|
|
|
RuleBookSettings settings(m_config);
|
|
|
|
settings.setRules(filteredRules);
|
|
|
|
settings.save();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
void RuleBook::temporaryRulesMessage(const QString& message)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
bool was_temporary = false;
|
2013-04-26 12:40:35 +00:00
|
|
|
for (QList< Rules* >::ConstIterator it = m_rules.constBegin();
|
|
|
|
it != m_rules.constEnd();
|
2011-01-30 14:34:42 +00:00
|
|
|
++it)
|
|
|
|
if ((*it)->isTemporary())
|
2007-04-29 17:35:43 +00:00
|
|
|
was_temporary = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
Rules* rule = new Rules(message, true);
|
2013-04-26 12:40:35 +00:00
|
|
|
m_rules.prepend(rule); // highest priority first
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!was_temporary)
|
2020-09-23 18:39:59 +00:00
|
|
|
QTimer::singleShot(60000, this, &RuleBook::cleanupTemporaryRules);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
void RuleBook::cleanupTemporaryRules()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
bool has_temporary = false;
|
2013-04-26 12:40:35 +00:00
|
|
|
for (QList< Rules* >::Iterator it = m_rules.begin();
|
|
|
|
it != m_rules.end();
|
2011-01-30 14:34:42 +00:00
|
|
|
) {
|
2013-05-31 17:14:34 +00:00
|
|
|
if ((*it)->discardTemporary(false)) { // deletes (*it)
|
2013-04-26 12:40:35 +00:00
|
|
|
it = m_rules.erase(it);
|
|
|
|
} else {
|
2011-01-30 14:34:42 +00:00
|
|
|
if ((*it)->isTemporary())
|
2007-04-29 17:35:43 +00:00
|
|
|
has_temporary = true;
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
if (has_temporary)
|
2020-09-23 18:39:59 +00:00
|
|
|
QTimer::singleShot(60000, this, &RuleBook::cleanupTemporaryRules);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2017-10-01 19:37:18 +00:00
|
|
|
void RuleBook::discardUsed(AbstractClient* c, bool withdrawn)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2007-04-29 17:35:43 +00:00
|
|
|
bool updated = false;
|
2013-04-26 12:40:35 +00:00
|
|
|
for (QList< Rules* >::Iterator it = m_rules.begin();
|
|
|
|
it != m_rules.end();
|
2011-01-30 14:34:42 +00:00
|
|
|
) {
|
|
|
|
if (c->rules()->contains(*it)) {
|
2018-05-07 19:59:17 +00:00
|
|
|
if ((*it)->discardUsed(withdrawn)) {
|
|
|
|
updated = true;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
if ((*it)->isEmpty()) {
|
|
|
|
c->removeRule(*it);
|
2007-04-29 17:35:43 +00:00
|
|
|
Rules* r = *it;
|
2013-04-26 12:40:35 +00:00
|
|
|
it = m_rules.erase(it);
|
2007-04-29 17:35:43 +00:00
|
|
|
delete r;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
++it;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
if (updated)
|
2013-04-26 12:40:35 +00:00
|
|
|
requestDiskStorage();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
void RuleBook::requestDiskStorage()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-04-26 12:40:35 +00:00
|
|
|
m_updateTimer->start();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-26 12:40:35 +00:00
|
|
|
void RuleBook::setUpdatesDisabled(bool disable)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-04-26 12:40:35 +00:00
|
|
|
m_updatesDisabled = disable;
|
2012-02-05 17:50:23 +00:00
|
|
|
if (!disable) {
|
2021-06-08 07:02:14 +00:00
|
|
|
Q_FOREACH (X11Client *c, Workspace::self()->clientList())
|
2012-02-05 17:50:23 +00:00
|
|
|
c->updateWindowRules(Rules::All);
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-30 12:24:10 +00:00
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
} // namespace
|