diff --git a/activation.cpp b/activation.cpp
index 45b9176f77..d6fbc5c921 100644
--- a/activation.cpp
+++ b/activation.cpp
@@ -541,6 +541,11 @@ void Workspace::setShouldGetFocus(AbstractClient* c)
updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
}
+
+namespace FSP {
+ enum Level { None = 0, Low, Medium, High, Extreme };
+}
+
// focus_in -> the window got FocusIn event
// ignore_desktop - call comes from _NET_ACTIVE_WINDOW message, don't refuse just because of window
// is on a different desktop
@@ -557,7 +562,7 @@ bool Workspace::allowClientActivation(const KWin::AbstractClient *c, xcb_timesta
if (time == -1U)
time = c->userTime();
int level = c->rules()->checkFSP(options->focusStealingPreventionLevel());
- if (session_saving && level <= 2) { // <= normal
+ if (session_saving && level <= FSP::Medium) { // <= normal
return true;
}
AbstractClient* ac = mostRecentlyActivatedClient();
@@ -572,33 +577,52 @@ bool Workspace::allowClientActivation(const KWin::AbstractClient *c, xcb_timesta
if (!c->rules()->checkAcceptFocus(false))
return false;
}
- if (level == 0) // none
+ const int protection = ac ? ac->rules()->checkFPP(2) : 0;
+
+ // stealing is unconditionally allowed (NETWM behavior)
+ if (level == FSP::None || protection == FSP::None)
return true;
- if (level == 4) // extreme
+
+ // The active client "grabs" the focus or stealing is generally forbidden
+ if (level == FSP::Extreme || protection == FSP::Extreme)
return false;
+
+ // Desktop switching is only allowed in the "no protection" case
if (!ignore_desktop && !c->isOnCurrentDesktop())
return false; // allow only with level == 0
+
+ // No active client, it's ok to pass focus
+ // NOTICE that extreme protection needs to be handled before to allow protection on unmanged windows
if (ac == NULL || ac->isDesktop()) {
qCDebug(KWIN_CORE) << "Activation: No client active, allowing";
return true; // no active client -> always allow
}
+
// TODO window urgency -> return true?
- if (AbstractClient::belongToSameApplication(c, ac, true)) {
+
+ // Unconditionally allow intra-client passing around for lower stealing protections
+ // unless the active client has High interest
+ if (AbstractClient::belongToSameApplication(c, ac, true) && protection < FSP::High) {
qCDebug(KWIN_CORE) << "Activation: Belongs to active application";
return true;
}
- if (level == 3) // high
+
+ // High FPS, not intr-client change. Only allow if the active client has only minor interest
+ if (level > FSP::Medium && protection > FSP::Low)
return false;
+
if (time == -1U) { // no time known
qCDebug(KWIN_CORE) << "Activation: No timestamp at all";
- if (level == 1) // low
+ // Only allow for Low protection unless active client has High interest in focus
+ if (level < FSP::Medium && protection < FSP::High)
return true;
// no timestamp at all, don't activate - because there's also creation timestamp
// done on CreateNotify, this case should happen only in case application
// maps again already used window, i.e. this won't happen after app startup
return false;
}
- // level == 2 // normal
+
+ // Low or medium FSP, usertime comparism is possible
Time user_time = ac->userTime();
qCDebug(KWIN_CORE) << "Activation, compared:" << c << ":" << time << ":" << user_time
<< ":" << (NET::timestampCompare(time, user_time) >= 0);
diff --git a/kcmkwin/kwinrules/ruleswidget.cpp b/kcmkwin/kwinrules/ruleswidget.cpp
index 30db8bcf59..56ab4ae28f 100644
--- a/kcmkwin/kwinrules/ruleswidget.cpp
+++ b/kcmkwin/kwinrules/ruleswidget.cpp
@@ -121,6 +121,7 @@ RulesWidget::RulesWidget(QWidget* parent)
SETUP(shortcut, force);
// workarounds tab
SETUP(fsplevel, force);
+ SETUP(fpplevel, force);
SETUP(type, force);
SETUP(ignoregeometry, set);
SETUP(minsize, force);
@@ -206,6 +207,7 @@ void RulesWidget::updateEnableshortcut()
}
// workarounds tab
UPDATE_ENABLE_SLOT(fsplevel)
+UPDATE_ENABLE_SLOT(fpplevel)
UPDATE_ENABLE_SLOT(type)
UPDATE_ENABLE_SLOT(ignoregeometry)
UPDATE_ENABLE_SLOT(minsize)
@@ -508,6 +510,7 @@ void RulesWidget::setRules(Rules* rules)
SPINBOX_FORCE_RULE(opacityinactive,);
LINEEDIT_SET_RULE(shortcut,);
COMBOBOX_FORCE_RULE(fsplevel,);
+ COMBOBOX_FORCE_RULE(fpplevel,);
COMBOBOX_FORCE_RULE(type, typeToCombo);
CHECKBOX_SET_RULE(ignoregeometry,);
LINEEDIT_FORCE_RULE(minsize, sizeToStr);
@@ -611,6 +614,7 @@ Rules* RulesWidget::rules() const
SPINBOX_FORCE_RULE(opacityinactive,);
LINEEDIT_SET_RULE(shortcut,);
COMBOBOX_FORCE_RULE(fsplevel,);
+ COMBOBOX_FORCE_RULE(fpplevel,);
COMBOBOX_FORCE_RULE(type, comboToType);
CHECKBOX_SET_RULE(ignoregeometry,);
LINEEDIT_FORCE_RULE(minsize, strToSize);
@@ -731,6 +735,7 @@ void RulesWidget::prefillUnusedValues(const KWindowInfo& info)
SPINBOX_PREFILL(opacityinactive, , 100 /*get the actual opacity somehow*/);
//LINEEDIT_PREFILL( shortcut, );
//COMBOBOX_PREFILL( fsplevel, );
+ //COMBOBOX_PREFILL( fpplevel, );
COMBOBOX_PREFILL(type, typeToCombo, info.windowType(SUPPORTED_MANAGED_WINDOW_TYPES_MASK));
//CHECKBOX_PREFILL( ignoregeometry, );
LINEEDIT_PREFILL(minsize, sizeToStr, info.frameGeometry().size());
diff --git a/kcmkwin/kwinrules/ruleswidget.h b/kcmkwin/kwinrules/ruleswidget.h
index 6961b6ab47..a95428eb4f 100644
--- a/kcmkwin/kwinrules/ruleswidget.h
+++ b/kcmkwin/kwinrules/ruleswidget.h
@@ -92,6 +92,7 @@ private Q_SLOTS:
void updateEnableopacityinactive();
// workarounds tab
void updateEnablefsplevel();
+ void updateEnablefpplevel();
void updateEnabletype();
void updateEnableignoregeometry();
void updateEnableminsize();
diff --git a/kcmkwin/kwinrules/ruleswidgetbase.ui b/kcmkwin/kwinrules/ruleswidgetbase.ui
index 7c208e82ca..80d16728e3 100644
--- a/kcmkwin/kwinrules/ruleswidgetbase.ui
+++ b/kcmkwin/kwinrules/ruleswidgetbase.ui
@@ -1902,42 +1902,6 @@ like your complete screen area.
Appearance && &Fixes
- -
-
-
- false
-
-
-
- -
-
-
- false
-
-
-
-
- Do Not Affect
-
-
- -
-
- Force
-
-
- -
-
- Force Temporarily
-
-
-
-
- -
-
-
- Block compositing
-
-
-
-
@@ -1982,13 +1946,78 @@ like your complete screen area.
- -
+
-
+
+
+ false
+
+
+
+ -
+
+
+ Titlebar color &scheme
+
+
+
+ -
+
+
+ false
+
+
-
+
+ Do Not Affect
+
+
+ -
+
+ Force
+
+
+ -
+
+ Force Temporarily
+
+
+
+
+ -
+
+
+ false
+
+
+
+ -
Qt::Horizontal
+ -
+
+
+ false
+
+
-
+
+ Do Not Affect
+
+
+ -
+
+ Force
+
+
+ -
+
+ Force Temporarily
+
+
+
+
-
@@ -1996,20 +2025,7 @@ like your complete screen area.
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
+
-
false
@@ -2054,7 +2070,7 @@ like your complete screen area.
- -
+
-
false
@@ -2070,7 +2086,30 @@ like your complete screen area.
- -
+
-
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 8
+
+
+
+
+ -
Qt::Vertical
@@ -2086,7 +2125,169 @@ like your complete screen area.
- -
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ KWin tries to prevent windows from taking the focus
+("activate") while you're working in another window,
+but this may sometimes fail or superact.
+"None" will unconditionally allow this window to get the focus while
+"Extreme" will completely prevent it from taking the focus.
+
+
+ &Focus stealing prevention
+
+
+
+ -
+
+
+ false
+
+
-
+
+ Do Not Affect
+
+
+ -
+
+ Force
+
+
+ -
+
+ Force Temporarily
+
+
+
+
+ -
+
+
+ false
+
+
-
+
+ None
+
+
+ -
+
+ Low
+
+
+ -
+
+ Normal
+
+
+ -
+
+ High
+
+
+ -
+
+ Extreme
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ This controls the focus protection of the currenly active window.
+None will always give the focus away,
+Extreme will keep it.
+Otherwise it's interleaved with the stealing prevention
+assigned to the window that wants the focus.
+
+
+ Focus protection
+
+
+
+ -
+
+
+ false
+
+
-
+
+ Do Not Affect
+
+
+ -
+
+ Force
+
+
+ -
+
+ Force Temporarily
+
+
+
+
+ -
+
+
+ false
+
+
-
+
+ None
+
+
+ -
+
+ Low
+
+
+ -
+
+ Normal
+
+
+ -
+
+ High
+
+
+ -
+
+ Extreme
+
+
+
+
+ -
Windows may prevent to get the focus (activate) when being clicked.
@@ -2098,7 +2299,7 @@ from getting focused on a mouse click.
- -
+
-
false
@@ -2120,14 +2321,14 @@ from getting focused on a mouse click.
- -
-
-
- Qt::Horizontal
+
-
+
+
+ false
- -
+
-
When used, a window will receive
@@ -2147,7 +2348,7 @@ while it's active!
- -
+
-
false
@@ -2169,35 +2370,64 @@ while it's active!
- -
+
-
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
&Closeable
- -
-
-
- Window &type
+
-
+
+
+ false
+
-
+
+ Do Not Affect
+
+
+ -
+
+ Force
+
+
+ -
+
+ Force Temporarily
+
+
- -
+
-
false
- -
-
-
- Qt::Horizontal
+
-
+
+
+ Window &type
- -
+
-
false
@@ -2219,7 +2449,7 @@ while it's active!
- -
+
-
false
@@ -2271,131 +2501,21 @@ while it's active!
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 8
-
-
-
-
- -
-
+
-
+
Qt::Horizontal
- -
-
-
- false
+
-
+
+
+ Block compositing
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- false
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- false
-
-
-
- -
-
-
- false
-
-
-
-
- Do Not Affect
-
-
- -
-
- Force
-
-
- -
-
- Force Temporarily
-
-
-
-
- -
-
-
- false
-
-
-
-
- None
-
-
- -
-
- Low
-
-
- -
-
- Normal
-
-
- -
-
- High
-
-
- -
-
- Extreme
-
-
-
-
- -
+
-
false
@@ -2417,77 +2537,25 @@ while it's active!
- -
-
-
- false
-
-
-
-
- Do Not Affect
-
-
- -
-
- Force
-
-
- -
-
- Force Temporarily
-
-
-
-
- -
-
-
- KWin tries to prevent windows from taking the focus
-("activate") while you're working in another window,
-but this may sometimes fail or superact.
-"None" will unconditionally allow this window to get the focus while
-"Extreme" will completely prevent it from taking the focus.
-
-
- &Focus stealing prevention
-
-
-
- -
-
-
- Titlebar color &scheme
-
-
-
- -
-
+
-
+
false
- -
-
-
- false
+
-
+
+
+ Qt::Vertical
-
-
-
- Do Not Affect
-
-
- -
-
- Force
-
-
- -
-
- Force Temporarily
-
-
-
+
+
+ 20
+ 40
+
+
+
@@ -2496,16 +2564,16 @@ but this may sometimes fail or superact.
-
- KComboBox
- QComboBox
-
-
KLineEdit
QLineEdit
+
+ KComboBox
+ QComboBox
+
+
YesNoBox
QWidget
@@ -2592,6 +2660,9 @@ but this may sometimes fail or superact.
shortcut_edit
enable_noborder
rule_noborder
+ enable_decocolor
+ rule_decocolor
+ decocolor
enable_opacityactive
rule_opacityactive
opacityactive
@@ -2601,6 +2672,9 @@ but this may sometimes fail or superact.
enable_fsplevel
rule_fsplevel
fsplevel
+ enable_fpplevel
+ rule_fpplevel
+ fpplevel
enable_acceptfocus
rule_acceptfocus
enable_disableglobalshortcuts
diff --git a/rules.cpp b/rules.cpp
index b12109bf1b..79fa1dff80 100644
--- a/rules.cpp
+++ b/rules.cpp
@@ -73,6 +73,7 @@ Rules::Rules()
, decocolorrule(UnusedForceRule)
, blockcompositingrule(UnusedForceRule)
, fsplevelrule(UnusedForceRule)
+ , fpplevelrule(UnusedForceRule)
, acceptfocusrule(UnusedForceRule)
, closeablerule(UnusedForceRule)
, autogrouprule(UnusedForceRule)
@@ -182,6 +183,7 @@ void Rules::readFromCfg(const KConfigGroup& cfg)
decocolorrule = decocolor.isEmpty() ? UnusedForceRule : readForceRule(cfg, QStringLiteral("decocolorrule"));
READ_FORCE_RULE(blockcompositing, , false);
READ_FORCE_RULE(fsplevel, limit0to4, 0); // fsp is 0-4
+ READ_FORCE_RULE(fpplevel, limit0to4, 0); // fpp is 0-4
READ_FORCE_RULE(acceptfocus, , false);
READ_FORCE_RULE(closeable, , false);
READ_FORCE_RULE(autogroup, , false);
@@ -279,6 +281,7 @@ void Rules::write(KConfigGroup& cfg) const
WRITE_FORCE_RULE(decocolor, colorToString);
WRITE_FORCE_RULE(blockcompositing,);
WRITE_FORCE_RULE(fsplevel,);
+ WRITE_FORCE_RULE(fpplevel,);
WRITE_FORCE_RULE(acceptfocus,);
WRITE_FORCE_RULE(closeable,);
WRITE_FORCE_RULE(autogroup,);
@@ -322,6 +325,7 @@ bool Rules::isEmpty() const
&& decocolorrule == UnusedForceRule
&& blockcompositingrule == UnusedForceRule
&& fsplevelrule == UnusedForceRule
+ && fpplevelrule == UnusedForceRule
&& acceptfocusrule == UnusedForceRule
&& closeablerule == UnusedForceRule
&& autogrouprule == UnusedForceRule
@@ -650,6 +654,7 @@ APPLY_RULE(noborder, NoBorder, bool)
APPLY_FORCE_RULE(decocolor, DecoColor, QString)
APPLY_FORCE_RULE(blockcompositing, BlockCompositing, bool)
APPLY_FORCE_RULE(fsplevel, FSP, int)
+APPLY_FORCE_RULE(fpplevel, FPP, int)
APPLY_FORCE_RULE(acceptfocus, AcceptFocus, bool)
APPLY_FORCE_RULE(closeable, Closeable, bool)
APPLY_FORCE_RULE(autogroup, Autogrouping, bool)
@@ -718,6 +723,7 @@ void Rules::discardUsed(bool withdrawn)
DISCARD_USED_FORCE_RULE(decocolor);
DISCARD_USED_FORCE_RULE(blockcompositing);
DISCARD_USED_FORCE_RULE(fsplevel);
+ DISCARD_USED_FORCE_RULE(fpplevel);
DISCARD_USED_FORCE_RULE(acceptfocus);
DISCARD_USED_FORCE_RULE(closeable);
DISCARD_USED_FORCE_RULE(autogroup);
@@ -851,6 +857,7 @@ CHECK_RULE(NoBorder, bool)
CHECK_FORCE_RULE(DecoColor, QString)
CHECK_FORCE_RULE(BlockCompositing, bool)
CHECK_FORCE_RULE(FSP, int)
+CHECK_FORCE_RULE(FPP, int)
CHECK_FORCE_RULE(AcceptFocus, bool)
CHECK_FORCE_RULE(Closeable, bool)
CHECK_FORCE_RULE(Autogrouping, bool)
diff --git a/rules.h b/rules.h
index b6c2d3f8da..adcf606709 100644
--- a/rules.h
+++ b/rules.h
@@ -80,6 +80,7 @@ public:
QString checkDecoColor(QString schemeFile) const;
bool checkBlockCompositing(bool block) const;
int checkFSP(int fsp) const;
+ int checkFPP(int fpp) const;
bool checkAcceptFocus(bool focus) const;
bool checkCloseable(bool closeable) const;
bool checkAutogrouping(bool autogroup) const;
@@ -147,6 +148,7 @@ public:
bool applyDecoColor(QString &schemeFile) const;
bool applyBlockCompositing(bool& block) const;
bool applyFSP(int& fsp) const;
+ bool applyFPP(int& fpp) const;
bool applyAcceptFocus(bool& focus) const;
bool applyCloseable(bool& closeable) const;
bool applyAutogrouping(bool& autogroup) const;
@@ -262,7 +264,9 @@ private:
bool blockcompositing;
ForceRule blockcompositingrule;
int fsplevel;
+ int fpplevel;
ForceRule fsplevelrule;
+ ForceRule fpplevelrule;
bool acceptfocus;
ForceRule acceptfocusrule;
bool closeable;