From 2a1f9e4489687fa276c20bddf05d3eedb0994b00 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Mon, 14 Jun 2021 16:10:01 +0000 Subject: [PATCH] [libtaskmanager/x11] Fix transient windows bug The logic for handling the active window when it is a transient, added in https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/509, had a bug (fixed in 67003f740888fa9d1bcee60cd28ce9a862d2452a). This reworks the implementation and actually makes the original feature work (a signal also wasn't properly handled). BUG: 438222 FIXED-IN: 5.22.1 (cherry picked from commit 7573ae03acc3f3c6d70af24970e689414a4204c5) --- libtaskmanager/xwindowtasksmodel.cpp | 39 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/libtaskmanager/xwindowtasksmodel.cpp b/libtaskmanager/xwindowtasksmodel.cpp index 8a45b8154..30a307fd3 100644 --- a/libtaskmanager/xwindowtasksmodel.cpp +++ b/libtaskmanager/xwindowtasksmodel.cpp @@ -56,8 +56,12 @@ public: ~Private(); QVector windows; - QMultiHash transients; + + // key=transient child, value=leader + QHash transients; + // key=leader, values=transient children QMultiHash transientsDemandingAttention; + QHash windowInfoCache; QHash appDataCache; QHash delegateGeometries; @@ -172,6 +176,12 @@ void XWindowTasksModel::Private::init() // Update IsActive for previously- and newly-active windows. QObject::connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, q, [this](WId window) { const WId oldActiveWindow = activeWindow; + + const auto leader = transients.value(window, XCB_WINDOW_NONE); + if (leader != XCB_WINDOW_NONE) { + window = leader; + } + activeWindow = window; lastActivated[activeWindow] = QTime::currentTime(); @@ -216,8 +226,8 @@ void XWindowTasksModel::Private::addWindow(WId window) const WId leader = info.transientFor(); // Handle transient. - if (leader > 0 && leader != window && leader != QX11Info::appRootWindow() && !transients.values().contains(window) && windows.contains(leader)) { - transients.insert(leader, window); + if (leader > 0 && leader != window && leader != QX11Info::appRootWindow() && !transients.contains(window) && windows.contains(leader)) { + transients.insert(window, leader); // Update demands attention state for leader. if (info.hasState(NET::DemandsAttention) && windows.contains(leader)) { @@ -255,10 +265,8 @@ void XWindowTasksModel::Private::removeWindow(WId window) q->endRemoveRows(); } else { // Could be a transient. // Removing a transient might change the demands attention state of the leader. - WId leader = transients.key(window, XCB_WINDOW_NONE); - if (leader != XCB_WINDOW_NONE) { - transients.remove(leader, window); - leader = transientsDemandingAttention.key(window, XCB_WINDOW_NONE); + if (transients.remove(window)) { + const WId leader = transientsDemandingAttention.key(window, XCB_WINDOW_NONE); if (leader != XCB_WINDOW_NONE) { transientsDemandingAttention.remove(leader, window); @@ -316,7 +324,6 @@ void XWindowTasksModel::Private::windowChanged(WId window, NET::Properties prope { if (transients.contains(window)) { transientChanged(window, properties, properties2); - return; } @@ -629,15 +636,7 @@ QVariant XWindowTasksModel::data(const QModelIndex &index, int role) const } else if (role == IsWindow) { return true; } else if (role == IsActive) { - if (window == d->activeWindow) { - return true; - } - for (const WId transient : d->transients.values(window)) { - if (transient == d->activeWindow) { - return true; - } - } - return false; + return (window == d->activeWindow); } else if (role == IsClosable) { return d->windowInfo(window)->actionSupported(NET::ActionClose); } else if (role == IsMovable) { @@ -729,10 +728,10 @@ void XWindowTasksModel::requestActivate(const QModelIndex &index) // dialog and trying to bring the window forward by clicking on it in a tasks widget // TODO: do we need to check all the transients for shaded?" } else if (!d->transients.isEmpty()) { - foreach (const WId transient, d->transients) { + const auto transients = d->transients.keys(window); + for (const auto transient : qAsConst(transients)) { KWindowInfo info(transient, NET::WMState, NET::WM2TransientFor); - - if (info.valid(true) && info.hasState(NET::Shaded) && info.transientFor() == window) { + if (info.valid(true) && info.hasState(NET::Shaded)) { window = transient; break; }