Commit d1522eb4 authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧 Committed by Aleix Pol Gonzalez
Browse files

Move allowWindowActivation into X11Window

It helps to contextualise the method as it's using several x11-isms,
some of them possible ot abstract.
In any case, the method is only called with X11Window and it's the only
case where it makes sense doing so.
parent fa36628a
Pipeline #172119 passed with stage
in 13 minutes and 56 seconds
......@@ -549,112 +549,6 @@ void Workspace::setShouldGetFocus(Window *window)
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
bool Workspace::allowWindowActivation(const KWin::Window *window, xcb_timestamp_t time, bool focus_in, bool ignore_desktop)
{
// options->focusStealingPreventionLevel :
// 0 - none - old KWin behaviour, new windows always get focus
// 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed
// 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed,
// this is the default
// 3 - high - new window gets focus only if it belongs to the active application,
// or when no window is currently active
// 4 - extreme - no window gets focus without user intervention
if (time == -1U) {
time = window->userTime();
}
int level = window->rules()->checkFSP(options->focusStealingPreventionLevel());
if (sessionManager()->state() == SessionState::Saving && level <= FSP::Medium) { // <= normal
return true;
}
Window *ac = mostRecentlyActivatedWindow();
if (focus_in) {
if (should_get_focus.contains(const_cast<Window *>(window))) {
return true; // FocusIn was result of KWin's action
}
// Before getting FocusIn, the active Client already
// got FocusOut, and therefore got deactivated.
ac = m_lastActiveWindow;
}
if (time == 0) { // explicitly asked not to get focus
if (!window->rules()->checkAcceptFocus(false)) {
return false;
}
}
const int protection = ac ? ac->rules()->checkFPP(2) : 0;
// stealing is unconditionally allowed (NETWM behavior)
if (level == FSP::None || protection == FSP::None) {
return true;
}
// The active window "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 && !window->isOnCurrentDesktop()) {
return false; // allow only with level == 0
}
// No active window, it's ok to pass focus
// NOTICE that extreme protection needs to be handled before to allow protection on unmanged windows
if (ac == nullptr || ac->isDesktop()) {
qCDebug(KWIN_CORE) << "Activation: No window active, allowing";
return true; // no active window -> always allow
}
// TODO window urgency -> return true?
// Unconditionally allow intra-window passing around for lower stealing protections
// unless the active window has High interest
if (Window::belongToSameApplication(window, ac, Window::SameApplicationCheck::RelaxedForActive) && protection < FSP::High) {
qCDebug(KWIN_CORE) << "Activation: Belongs to active application";
return true;
}
if (!window->isOnCurrentDesktop()) { // we allowed explicit self-activation across virtual desktops
return false; // inside a window or if no window was active, but not otherwise
}
// High FPS, not intr-window change. Only allow if the active window 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";
// Only allow for Low protection unless active window 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;
}
// Low or medium FSP, usertime comparism is possible
const xcb_timestamp_t user_time = ac->userTime();
qCDebug(KWIN_CORE) << "Activation, compared:" << window << ":" << time << ":" << user_time
<< ":" << (NET::timestampCompare(time, user_time) >= 0);
return NET::timestampCompare(time, user_time) >= 0; // time >= user_time
}
// basically the same like allowWindowActivation(), this time allowing
// a window to be fully raised upon its own request (XRaiseWindow),
// if refused, it will be raised only on top of windows belonging
......@@ -882,7 +776,7 @@ void X11Window::startupIdChanged()
}
const xcb_timestamp_t timestamp = asn_id.timestamp();
if (timestamp != 0) {
bool activate = workspace()->allowWindowActivation(this, timestamp);
bool activate = allowWindowActivation(timestamp);
if (asn_data.desktop() != 0 && !isOnCurrentDesktop()) {
activate = false; // it was started on different desktop than current one
}
......@@ -901,6 +795,113 @@ void X11Window::updateUrgency()
}
}
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
bool X11Window::allowWindowActivation(xcb_timestamp_t time, bool focus_in, bool ignore_desktop)
{
auto window = this;
// options->focusStealingPreventionLevel :
// 0 - none - old KWin behaviour, new windows always get focus
// 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed
// 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed,
// this is the default
// 3 - high - new window gets focus only if it belongs to the active application,
// or when no window is currently active
// 4 - extreme - no window gets focus without user intervention
if (time == -1U) {
time = window->userTime();
}
const FSP::Level level = (FSP::Level)window->rules()->checkFSP(options->focusStealingPreventionLevel());
if (workspace()->sessionManager()->state() == SessionState::Saving && level <= FSP::Medium) { // <= normal
return true;
}
Window *ac = workspace()->mostRecentlyActivatedWindow();
if (focus_in) {
if (workspace()->inShouldGetFocus(window)) {
return true; // FocusIn was result of KWin's action
}
// Before getting FocusIn, the active Client already
// got FocusOut, and therefore got deactivated.
ac = workspace()->lastActiveWindow();
}
if (time == 0) { // explicitly asked not to get focus
if (!window->rules()->checkAcceptFocus(false)) {
return false;
}
}
const FSP::Level protection = (FSP::Level)(ac ? ac->rules()->checkFPP(2) : FSP::None);
// stealing is unconditionally allowed (NETWM behavior)
if (level == FSP::None || protection == FSP::None) {
return true;
}
// The active window "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 && !window->isOnCurrentDesktop()) {
return false; // allow only with level == 0
}
// No active window, it's ok to pass focus
// NOTICE that extreme protection needs to be handled before to allow protection on unmanged windows
if (ac == nullptr || ac->isDesktop()) {
qCDebug(KWIN_CORE) << "Activation: No window active, allowing";
return true; // no active window -> always allow
}
// TODO window urgency -> return true?
// Unconditionally allow intra-window passing around for lower stealing protections
// unless the active window has High interest
if (Window::belongToSameApplication(window, ac, Window::SameApplicationCheck::RelaxedForActive) && protection < FSP::High) {
qCDebug(KWIN_CORE) << "Activation: Belongs to active application";
return true;
}
if (!window->isOnCurrentDesktop()) { // we allowed explicit self-activation across virtual desktops
return false; // inside a window or if no window was active, but not otherwise
}
// High FPS, not intr-window change. Only allow if the active window 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";
// Only allow for Low protection unless active window 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;
}
// Low or medium FSP, usertime comparism is possible
const xcb_timestamp_t user_time = ac->userTime();
qCDebug(KWIN_CORE) << "Activation, compared:" << window << ":" << time << ":" << user_time
<< ":" << (NET::timestampCompare(time, user_time) >= 0);
return NET::timestampCompare(time, user_time) >= 0; // time >= user_time
}
//****************************************
// Group
//****************************************
......
......@@ -533,7 +533,7 @@ bool X11Window::mapRequestEvent(xcb_map_request_event_t *e)
setShade(ShadeNone);
}
if (!isOnCurrentDesktop()) {
if (workspace()->allowWindowActivation(this)) {
if (allowWindowActivation()) {
workspace()->activateWindow(this);
} else {
demandAttention();
......@@ -1102,7 +1102,7 @@ void X11Window::focusInEvent(xcb_focus_in_event_t *e)
window->cancelFocusOutTimer();
});
// check if this window is in should_get_focus list or if activation is allowed
bool activate = workspace()->allowWindowActivation(this, -1U, true);
bool activate = allowWindowActivation(-1U, true);
workspace()->gotFocusIn(this); // remove from should_get_focus list
if (activate) {
setActive(true);
......
......@@ -164,13 +164,12 @@ void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_ti
return; // WORKAROUND? With > 1 plasma activities, we cause this ourselves. bug #240673
} else { // NET::FromApplication
X11Window *c2;
if (workspace->allowWindowActivation(c, timestamp, false, true)) {
if (c->allowWindowActivation(timestamp, false, true)) {
workspace->activateWindow(c);
// if activation of the requestor's window would be allowed, allow activation too
} else if (active_window != XCB_WINDOW_NONE
&& (c2 = workspace->findClient(Predicate::WindowMatch, active_window)) != nullptr
&& workspace->allowWindowActivation(c2,
timestampCompare(timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false, true)) {
&& c2->allowWindowActivation(timestampCompare(timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false, true)) {
workspace->activateWindow(c);
} else {
c->demandAttention();
......
......@@ -179,8 +179,6 @@ public:
};
Q_DECLARE_FLAGS(ActivityFlags, ActivityFlag)
bool takeActivity(Window *window, ActivityFlags flags);
bool allowWindowActivation(const Window *window, xcb_timestamp_t time = -1U, bool focus_in = false,
bool ignore_desktop = false);
bool restoreFocus();
void gotFocusIn(const Window *window);
void setShouldGetFocus(Window *window);
......@@ -417,6 +415,15 @@ public:
*/
void setInitialDesktop(int desktop);
bool inShouldGetFocus(Window *w) const
{
return should_get_focus.contains(w);
}
Window *lastActiveWindow() const
{
return m_lastActiveWindow;
}
public Q_SLOTS:
void performWindowOperation(KWin::Window *window, Options::WindowOperation op);
// Keybindings
......
......@@ -892,7 +892,7 @@ bool X11Window::manage(xcb_window_t w, bool isMapped)
if (session) {
allow = session->active && (!workspace()->wasUserInteraction() || workspace()->activeWindow() == nullptr || workspace()->activeWindow()->isDesktop());
} else {
allow = workspace()->allowWindowActivation(this, userTime(), false);
allow = allowWindowActivation(userTime(), false);
}
const bool isSessionSaving = workspace()->sessionManager()->state() == SessionState::Saving;
......
......@@ -305,6 +305,9 @@ public:
void handleSync();
void handleSyncTimeout();
bool allowWindowActivation(xcb_timestamp_t time = -1U, bool focus_in = false,
bool ignore_desktop = false);
static void cleanupX11();
public Q_SLOTS:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment