From a4791e629d6d0e6a988a222e70b82bb3555d3759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Fri, 13 Nov 2015 00:37:01 +0100 Subject: [PATCH] Add rule to protect the focus on a window This allows to pin the focus on certain window as well as to more easily give it away on others (typically launchers) BUG: 185060 CCBUG: 337798 FIXED-IN: 5.5 REVIEW: 126059 --- activation.cpp | 38 +- kcmkwin/kwinrules/ruleswidget.cpp | 5 + kcmkwin/kwinrules/ruleswidget.h | 1 + kcmkwin/kwinrules/ruleswidgetbase.ui | 594 +++++++++++++++------------ rules.cpp | 7 + rules.h | 4 + 6 files changed, 382 insertions(+), 267 deletions(-) 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 -
kcombobox.h
-
KLineEdit QLineEdit
klineedit.h
+ + KComboBox + QComboBox +
kcombobox.h
+
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;