diff --git a/abstract_client.h b/abstract_client.h --- a/abstract_client.h +++ b/abstract_client.h @@ -753,6 +753,31 @@ return false; } + /** + * Default implementation returns @c null. + * Mostly intended for X11 clients, from EWMH: + * + * If the WM_TRANSIENT_FOR property is set to None or Root window, the window should be + * treated as a transient for all other windows in the same group. It has been noted that this + * is a slight ICCCM violation, but as this behavior is pretty standard for many toolkits and + * window managers, and is extremely unlikely to break anything, it seems reasonable to document + * it as standard. + * + **/ + virtual bool groupTransient() const; + /** + * Default implementation returns @c null. + * + * Mostly for X11 clients, holds the client group + **/ + virtual const Group *group() const; + /** + * Default implementation returns @c null. + * + * Mostly for X11 clients, holds the client group + **/ + virtual Group *group(); + public Q_SLOTS: virtual void closeWindow() = 0; diff --git a/abstract_client.cpp b/abstract_client.cpp --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -2015,4 +2015,19 @@ setNoBorder(false); } +bool AbstractClient::groupTransient() const +{ + return false; +} + +const Group *AbstractClient::group() const +{ + return nullptr; +} + +Group *AbstractClient::group() +{ + return nullptr; +} + } diff --git a/client.h b/client.h --- a/client.h +++ b/client.h @@ -93,14 +93,14 @@ virtual xcb_window_t frameId() const override; bool isTransient() const override; - bool groupTransient() const; + bool groupTransient() const override; bool wasOriginallyGroupTransient() const; QList mainClients() const override; // Call once before loop , is not indirect bool hasTransient(const AbstractClient* c, bool indirect) const override; void checkTransient(xcb_window_t w); AbstractClient* findModal(bool allow_itself = false) override; - const Group* group() const; - Group* group(); + const Group* group() const override; + Group* group() override; void checkGroup(Group* gr = NULL, bool force = false); void changeClientLeaderGroup(Group* gr); void updateWindowRules(Rules::Types selection) override; diff --git a/deleted.cpp b/deleted.cpp --- a/deleted.cpp +++ b/deleted.cpp @@ -137,8 +137,7 @@ m_wasActive = client->isActive(); - const auto *x11Client = qobject_cast(client); - m_wasGroupTransient = x11Client && x11Client->groupTransient(); + m_wasGroupTransient = client->groupTransient(); } m_wasWaylandClient = qobject_cast(c) != nullptr; diff --git a/group.cpp b/group.cpp --- a/group.cpp +++ b/group.cpp @@ -839,11 +839,7 @@ for (auto it = transients().constBegin(); it != transients().constEnd(); ) { - Client *c = dynamic_cast(*it); - if (!c) { - ++it; - continue; - } + auto *c = *it; // group transients in the old group are no longer transient for it if (c->groupTransient() && c->group() != group()) { removeTransientFromList(c); diff --git a/layers.cpp b/layers.cpp --- a/layers.cpp +++ b/layers.cpp @@ -313,8 +313,8 @@ if (!nogroup && c->isTransient()) { // lower also all windows in the group, in their reversed stacking order ClientList wins; - if (Client *client = dynamic_cast(c)) { - wins = ensureStackingOrder(client->group()->members()); + if (auto group = c->group()) { + wins = ensureStackingOrder(group->members()); } for (int i = wins.size() - 1; i >= 0; @@ -672,10 +672,8 @@ // the mainwindow, but only if they're group transient (since only such dialogs // have taskbar entry in Kicker). A proper way of doing this (both kwin and kicker) // needs to be found. - if (const Client *ct = dynamic_cast(transient)) { - if (ct->isDialog() && !ct->isModal() && ct->groupTransient()) - return false; - } + if (transient->isDialog() && !transient->isModal() && transient->groupTransient()) + return false; // #63223 - don't keep transients above docks, because the dock is kept high, // and e.g. dialogs for them would be too high too // ignore this if the transient has a placement hint which indicates it should go above it's parent diff --git a/workspace.cpp b/workspace.cpp --- a/workspace.cpp +++ b/workspace.cpp @@ -767,35 +767,35 @@ (*it)->hideClient(false); return; } - const Group* group = NULL; - const Client* client = dynamic_cast(active_client); + const Group* group = nullptr; + auto client = active_client; // Go up in transiency hiearchy, if the top is found, only tool transients for the top mainwindow // will be shown; if a group transient is group, all tools in the group will be shown - while (client != NULL) { + while (client != nullptr) { if (!client->isTransient()) break; if (client->groupTransient()) { group = client->group(); break; } - client = dynamic_cast(client->transientFor()); + client = client->transientFor(); } // Use stacking order only to reduce flicker, it doesn't matter if block_stacking_updates == 0, // I.e. if it's not up to date // SELI TODO: But maybe it should - what if a new client has been added that's not in stacking order yet? - ClientList to_show, to_hide; + QVector to_show, to_hide; for (ToplevelList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) { - Client *c = qobject_cast(*it); + auto c = qobject_cast(*it); if (!c) { continue; } if (c->isUtility() || c->isMenu() || c->isToolbar()) { bool show = true; if (!c->isTransient()) { - if (c->group()->members().count() == 1) // Has its own group, keep always visible + if (!c->group() || c->group()->members().count() == 1) // Has its own group, keep always visible show = true; else if (client != NULL && c->group() == client->group()) show = true; @@ -834,7 +834,7 @@ // TODO: Since this is in stacking order, the order of taskbar entries changes :( to_show.at(i)->hideClient(false); if (also_hide) { - for (ClientList::ConstIterator it = to_hide.constBegin(); + for (auto it = to_hide.constBegin(); it != to_hide.constEnd(); ++it) // From bottommost (*it)->hideClient(true); @@ -1283,8 +1283,8 @@ lowerClient(c); if (!topDesk) topDesk = c; - if (Client *client = qobject_cast(c)) { - foreach (Client *cm, client->group()->members()) { + if (auto group = c->group()) { + foreach (Client *cm, group->members()) { cm->updateLayer(); } }