From f0c6f062413b6f15fbd1acef94c88f0f9e7d77e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Sun, 8 Apr 2012 10:07:35 +0200 Subject: [PATCH] Stacking Order becomes a list of Toplevel Windows The common usage of stacking order is to loop through the list and find a specific Client. All these usages still need to find a Client. For that the loops are adjusted to first cast the Toplevel into a Client and continue if the current item is no Client. At the moment all entries in the stacking order should still be Clients as the Deleted are not yet added. --- activation.cpp | 7 ++- bridge.cpp | 18 +++--- client.cpp | 11 +++- geometry.cpp | 6 +- layers.cpp | 105 +++++++++++++++++++--------------- placement.cpp | 46 +++++++++------ tabbox/tabbox.cpp | 17 +++--- tiling/tiling.cpp | 6 +- tiling/tilinglayout.cpp | 8 ++- useractions.cpp | 25 ++++---- workspace.cpp | 122 ++++++++++++++++++++++++++-------------- workspace.h | 8 +-- 12 files changed, 235 insertions(+), 144 deletions(-) diff --git a/activation.cpp b/activation.cpp index 451394f40..298728719 100644 --- a/activation.cpp +++ b/activation.cpp @@ -406,9 +406,12 @@ static inline bool isUsableFocusCandidate(Client *c, Client *prev, bool respectS Client *Workspace::clientUnderMouse(int screen) const { - QList::const_iterator it = stackingOrder().constEnd(); + ToplevelList::const_iterator it = stackingOrder().constEnd(); while (it != stackingOrder().constBegin()) { - Client *client = *(--it); + Client *client = qobject_cast(*(--it)); + if (!client) { + continue; + } // rule out clients which are not really visible. // the screen test is rather superflous for xrandr & twinview since the geometry would differ -> TODO: might be dropped diff --git a/bridge.cpp b/bridge.cpp index 897d432b5..32d4c841c 100644 --- a/bridge.cpp +++ b/bridge.cpp @@ -172,25 +172,29 @@ Qt::WFlags Bridge::initialWFlags() const QRegion Bridge::unobscuredRegion(const QRegion& r) const { QRegion reg(r); - const ClientList stacking_order = c->workspace()->stackingOrder(); + const ToplevelList stacking_order = c->workspace()->stackingOrder(); int pos = stacking_order.indexOf(c); ++pos; for (; pos < stacking_order.count(); ++pos) { - if (!stacking_order[pos]->isShown(true)) + Client *client = qobject_cast(stacking_order[pos]); + if (!client) { + continue; + } + if (!client->isShown(true)) continue; // these don't obscure the window if (c->isOnAllDesktops()) { - if (!stacking_order[ pos ]->isOnCurrentDesktop()) + if (!client->isOnCurrentDesktop()) continue; } else { - if (!stacking_order[ pos ]->isOnDesktop(c->desktop())) + if (!client->isOnDesktop(c->desktop())) continue; } /* the clients all have their mask-regions in local coords so we have to translate them to a shared coord system we choose ours */ - int dx = stacking_order[ pos ]->x() - c->x(); - int dy = stacking_order[ pos ]->y() - c->y(); - QRegion creg = stacking_order[ pos ]->mask(); + int dx = client->x() - c->x(); + int dy = client->y() - c->y(); + QRegion creg = client->mask(); creg.translate(dx, dy); reg -= creg; if (reg.isEmpty()) { diff --git a/client.cpp b/client.cpp index dd8699dfc..c9eb61aef 100644 --- a/client.cpp +++ b/client.cpp @@ -1115,9 +1115,14 @@ void Client::setShade(ShadeMode mode) if ((shade_mode == ShadeHover || shade_mode == ShadeActivated) && rules()->checkAcceptFocus(input)) setActive(true); if (shade_mode == ShadeHover) { - ClientList order = workspace()->stackingOrder(); - int idx = order.indexOf(this) + 1; // this is likely related to the index parameter?! - shade_below = (idx < order.count()) ? order.at(idx) : NULL; + ToplevelList order = workspace()->stackingOrder(); + // this is likely related to the index parameter?! + for (int idx = order.indexOf(this) + 1; idx < order.count(); ++idx) { + shade_below = qobject_cast(order.at(idx)); + if (shade_below) { + break; + } + } if (shade_below && shade_below->isNormalWindow()) workspace()->raiseClient(this); else diff --git a/geometry.cpp b/geometry.cpp index 6cb6f8ab2..847ce6195 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -772,8 +772,10 @@ void Workspace::cascadeDesktop() Q_ASSERT(block_stacking_updates == 0); initPositioning->reinitCascading(currentDesktop()); QRect area = clientArea(PlacementArea, QPoint(0, 0), currentDesktop()); - foreach (Client * client, stackingOrder()) { - if ((!client->isOnDesktop(currentDesktop())) || + foreach (Toplevel *toplevel, stackingOrder()) { + Client *client = qobject_cast(toplevel); + if (!client || + (!client->isOnDesktop(currentDesktop())) || (client->isMinimized()) || (client->isOnAllDesktops()) || (!client->isMovable())) diff --git a/layers.cpp b/layers.cpp index f2dac714d..549f40eb5 100644 --- a/layers.cpp +++ b/layers.cpp @@ -115,13 +115,7 @@ void Workspace::updateStackingOrder(bool propagate_new_clients) blocked_propagating_new_clients = true; return; } - ToplevelList constrainedOrder = constrainedStackingOrder(); - ClientList new_stacking_order; - foreach (Toplevel *t, constrainedOrder) { - if (Client *c = qobject_cast(t)) { - new_stacking_order << c; - } - } + ToplevelList new_stacking_order = constrainedStackingOrder(); bool changed = (new_stacking_order != stacking_order || force_restacking); force_restacking = false; stacking_order = new_stacking_order; @@ -169,8 +163,8 @@ void Workspace::propagateClients(bool propagate_new_clients) } #endif for (int i = stacking_order.size() - 1; i >= 0; i--) { - Client *client = stacking_order.at(i); - if (client->hiddenPreview()) { + Client *client = qobject_cast(stacking_order.at(i)); + if (!client || client->hiddenPreview()) { continue; } @@ -185,9 +179,10 @@ void Workspace::propagateClients(bool propagate_new_clients) // (as far as pure X stacking order is concerned), in order to avoid having // these windows that should be unmapped to interfere with other windows for (int i = stacking_order.size() - 1; i >= 0; i--) { - if (!stacking_order.at(i)->hiddenPreview()) + Client *client = qobject_cast(stacking_order.at(i)); + if (!client || !client->hiddenPreview()) continue; - newWindowStack << (Window*)stacking_order.at(i)->frameId(); + newWindowStack << (Window*)client->frameId(); } // TODO isn't it too inefficient to restack always all clients? // TODO don't restack not visible windows? @@ -208,7 +203,7 @@ void Workspace::propagateClients(bool propagate_new_clients) cl = new Window[ stacking_order.count()]; pos = 0; - for (ClientList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) + for (ToplevelList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) cl[pos++] = (*it)->window(); rootInfo->setClientListStacking(cl, pos); delete [] cl; @@ -227,7 +222,7 @@ void Workspace::propagateClients(bool propagate_new_clients) Client* Workspace::topClientOnDesktop(int desktop, int screen, bool unconstrained, bool only_normal) const { // TODO Q_ASSERT( block_stacking_updates == 0 ); - ClientList list; + ToplevelList list; if (!unconstrained) list = stacking_order; else @@ -235,13 +230,17 @@ Client* Workspace::topClientOnDesktop(int desktop, int screen, bool unconstraine for (int i = list.size() - 1; i >= 0; --i) { - if (list.at(i)->isOnDesktop(desktop) && list.at(i)->isShown(false) && list.at(i)->isOnCurrentActivity()) { - if (screen != -1 && list.at(i)->screen() != screen) + Client *c = qobject_cast(list.at(i)); + if (!c) { + continue; + } + if (c->isOnDesktop(desktop) && c->isShown(false) && c->isOnCurrentActivity()) { + if (screen != -1 && c->screen() != screen) continue; if (!only_normal) - return list.at(i); - if (list.at(i)->wantsTabFocus() && !list.at(i)->isSpecialWindow()) - return list.at(i); + return c; + if (c->wantsTabFocus() && !c->isSpecialWindow()) + return c; } } return 0; @@ -252,16 +251,18 @@ Client* Workspace::findDesktop(bool topmost, int desktop) const // TODO Q_ASSERT( block_stacking_updates == 0 ); if (topmost) { for (int i = stacking_order.size() - 1; i >= 0; i--) { - if (stacking_order.at(i)->isOnDesktop(desktop) && stacking_order.at(i)->isDesktop() - && stacking_order.at(i)->isShown(true)) - return stacking_order.at(i); - } - } else { // bottom-most - foreach (Client * c, stacking_order) { - if (c->isOnDesktop(desktop) && c->isDesktop() + Client *c = qobject_cast(stacking_order.at(i)); + if (c && c->isOnDesktop(desktop) && c->isDesktop() && c->isShown(true)) return c; } + } else { // bottom-most + foreach (Toplevel * c, stacking_order) { + Client *client = qobject_cast(c); + if (client && c->isOnDesktop(desktop) && c->isDesktop() + && client->isShown(true)) + return client; + } } return NULL; } @@ -323,10 +324,10 @@ void Workspace::lowerClientWithinApplication(Client* c) unconstrained_stacking_order.removeAll(c); bool lowered = false; // first try to put it below the bottom-most window of the application - for (ClientList::Iterator it = unconstrained_stacking_order.begin(); + for (ToplevelList::Iterator it = unconstrained_stacking_order.begin(); it != unconstrained_stacking_order.end(); ++it) - if (Client::belongToSameApplication(*it, c)) { + if (Client::belongToSameApplication(qobject_cast(*it), c)) { unconstrained_stacking_order.insert(it, c); lowered = true; break; @@ -375,7 +376,10 @@ void Workspace::raiseClientWithinApplication(Client* c) // first try to put it above the top-most window of the application for (int i = unconstrained_stacking_order.size() - 1; i > -1 ; --i) { - Client *other = unconstrained_stacking_order.at(i); + Client *other = qobject_cast(unconstrained_stacking_order.at(i)); + if (!other) { + continue; + } if (other == c) // don't lower it just because it asked to be raised return; if (Client::belongToSameApplication(other, c)) { @@ -416,7 +420,7 @@ void Workspace::restack(Client* c, Client* under) // put in the stacking order below _all_ windows belonging to the active application Client *other = 0; for (int i = 0; i < unconstrained_stacking_order.size(); ++i) { // TODO ignore topmenus? - if (Client::belongToSameApplication(under, (other = unconstrained_stacking_order.at(i)))) { + if (Client::belongToSameApplication(under, (other = qobject_cast(unconstrained_stacking_order.at(i))))) { under = (c == other) ? 0 : other; break; } @@ -480,11 +484,14 @@ void Workspace::restoreSessionStackingOrder(Client* c) return; StackingUpdatesBlocker blocker(this); unconstrained_stacking_order.removeAll(c); - ClientList::Iterator best_pos = unconstrained_stacking_order.end(); - for (ClientList::Iterator it = unconstrained_stacking_order.begin(); // from bottom + for (ToplevelList::Iterator it = unconstrained_stacking_order.begin(); // from bottom it != unconstrained_stacking_order.end(); ++it) { - if ((*it)->sessionStackingOrder() > c->sessionStackingOrder()) { + Client *current = qobject_cast(*it); + if (!current) { + continue; + } + if (current->sessionStackingOrder() > c->sessionStackingOrder()) { unconstrained_stacking_order.insert(it, c); return; } @@ -522,12 +529,13 @@ ToplevelList Workspace::constrainedStackingOrder() #endif // build the order from layers QVector< QMap > minimum_layer(numScreens()); - for (ClientList::ConstIterator it = unconstrained_stacking_order.constBegin(), + for (ToplevelList::ConstIterator it = unconstrained_stacking_order.constBegin(), end = unconstrained_stacking_order.constEnd(); it != end; ++it) { Layer l = (*it)->layer(); const int screen = (*it)->screen(); - QMap< Group*, Layer >::iterator mLayer = minimum_layer[screen].find((*it)->group()); + Client *c = qobject_cast(*it); + QMap< Group*, Layer >::iterator mLayer = minimum_layer[screen].find(c ? c->group() : NULL); if (mLayer != minimum_layer[screen].end()) { // If a window is raised above some other window in the same window group // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays @@ -535,8 +543,8 @@ ToplevelList Workspace::constrainedStackingOrder() if (*mLayer == ActiveLayer && (l == NormalLayer || l == AboveLayer)) l = ActiveLayer; *mLayer = l; - } else { - minimum_layer[screen].insertMulti((*it)->group(), l); + } else if (c) { + minimum_layer[screen].insertMulti(c->group(), l); } layer[ l ].append(*it); } @@ -644,11 +652,16 @@ ClientList Workspace::ensureStackingOrder(const ClientList& list) const return list; // TODO is this worth optimizing? ClientList result = list; - for (ClientList::ConstIterator it = stacking_order.constBegin(); + for (ToplevelList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); - ++it) - if (result.removeAll(*it) != 0) - result.append(*it); + ++it) { + Client *c = qobject_cast(*it); + if (!c) { + continue; + } + if (result.removeAll(c) != 0) + result.append(c); + } return result; } @@ -684,7 +697,7 @@ ToplevelList Workspace::xStackingOrder() const unsigned int count = 0; XQueryTree(display(), rootWindow(), &dummy, &dummy, &windows, &count); // use our own stacking order, not the X one, as they may differ - foreach (Client * c, stacking_order) + foreach (Toplevel * c, stacking_order) x_stacking.append(c); for (unsigned int i = 0; i < count; @@ -692,6 +705,7 @@ ToplevelList Workspace::xStackingOrder() const if (Unmanaged* c = findUnmanaged(WindowMatchPredicate(windows[ i ]))) x_stacking.append(c); } + // TODO: remove after stacking_order contains Deleted foreach (Deleted * c, deleted) x_stacking.append(c); if (windows != NULL) @@ -713,7 +727,7 @@ void Client::restackWindow(Window above, int detail, NET::RequestSource src, Tim workspace()->raiseOrLowerClient(this); return; } - ClientList::const_iterator it = workspace()->stackingOrder().constBegin(), + ToplevelList::const_iterator it = workspace()->stackingOrder().constBegin(), end = workspace()->stackingOrder().constEnd(); while (it != end) { if (*it == this) { @@ -743,7 +757,7 @@ void Client::restackWindow(Window above, int detail, NET::RequestSource src, Tim other = workspace()->findClient(WindowMatchPredicate(above)); if (other && detail == Above) { - ClientList::const_iterator it = workspace()->stackingOrder().constEnd(), + ToplevelList::const_iterator it = workspace()->stackingOrder().constEnd(), begin = workspace()->stackingOrder().constBegin(); while (--it != begin) { if (*it == this) @@ -754,8 +768,9 @@ void Client::restackWindow(Window above, int detail, NET::RequestSource src, Tim src = NET::FromTool; // force break; } + Client *c = qobject_cast(*it); - if (!( (*it)->isNormalWindow() && (*it)->isShown(true) && + if (!( (*it)->isNormalWindow() && c->isShown(true) && (*it)->isOnCurrentDesktop() && (*it)->isOnCurrentActivity() && (*it)->isOnScreen(screen()) )) continue; // irrelevant clients @@ -764,7 +779,7 @@ void Client::restackWindow(Window above, int detail, NET::RequestSource src, Tim } if (it != begin && (*(it - 1) == other)) - other = const_cast(*it); + other = qobject_cast(*it); else other = 0; } diff --git a/placement.cpp b/placement.cpp index c9bee7838..0b9b2e59a 100644 --- a/placement.cpp +++ b/placement.cpp @@ -181,22 +181,26 @@ void Placement::placeSmart(Client* c, const QRect& area, Policy /*next*/) cxl = x; cxr = x + cw; cyt = y; cyb = y + ch; - ClientList::ConstIterator l; + ToplevelList::ConstIterator l; for (l = m_WorkspacePtr->stackingOrder().constBegin(); l != m_WorkspacePtr->stackingOrder().constEnd() ; ++l) { - if ((*l)->isOnDesktop(desktop) && - (*l)->isShown(false) && (*l) != c) { + Client *client = qobject_cast(*l); + if (!client) { + continue; + } + if (client->isOnDesktop(desktop) && + client->isShown(false) && client != c) { - xl = (*l)->x(); yt = (*l)->y(); - xr = xl + (*l)->width(); yb = yt + (*l)->height(); + xl = client->x(); yt = client->y(); + xr = xl + client->width(); yb = yt + client->height(); //if windows overlap, calc the overall overlapping if ((cxl < xr) && (cxr > xl) && (cyt < yb) && (cyb > yt)) { xl = qMax(cxl, xl); xr = qMin(cxr, xr); yt = qMax(cyt, yt); yb = qMin(cyb, yb); - if ((*l)->keepAbove()) + if (client->keepAbove()) overlap += 16 * (xr - xl) * (yb - yt); - else if ((*l)->keepBelow() && !(*l)->isDock()) // ignore KeepBelow windows + else if (client->keepBelow() && !client->isDock()) // ignore KeepBelow windows overlap += 0; // for placement (see Client::belongsToLayer() for Dock) else overlap += (xr - xl) * (yb - yt); @@ -230,14 +234,18 @@ void Placement::placeSmart(Client* c, const QRect& area, Policy /*next*/) if (possible - cw > x) possible -= cw; // compare to the position of each client on the same desk - ClientList::ConstIterator l; + ToplevelList::ConstIterator l; for (l = m_WorkspacePtr->stackingOrder().constBegin(); l != m_WorkspacePtr->stackingOrder().constEnd() ; ++l) { + Client *client = qobject_cast(*l); + if (!client) { + continue; + } - if ((*l)->isOnDesktop(desktop) && - (*l)->isShown(false) && (*l) != c) { + if (client->isOnDesktop(desktop) && + client->isShown(false) && client != c) { - xl = (*l)->x(); yt = (*l)->y(); - xr = xl + (*l)->width(); yb = yt + (*l)->height(); + xl = client->x(); yt = client->y(); + xr = xl + client->width(); yb = yt + client->height(); // if not enough room above or under the current tested client // determine the first non-overlapped x position @@ -261,13 +269,17 @@ void Placement::placeSmart(Client* c, const QRect& area, Policy /*next*/) if (possible - ch > y) possible -= ch; //test the position of each window on the desk - ClientList::ConstIterator l; + ToplevelList::ConstIterator l; for (l = m_WorkspacePtr->stackingOrder().constBegin(); l != m_WorkspacePtr->stackingOrder().constEnd() ; ++l) { - if ((*l)->isOnDesktop(desktop) && - (*l) != c && c->isShown(false)) { + Client *client = qobject_cast(*l); + if (!client) { + continue; + } + if (client->isOnDesktop(desktop) && + client != c && c->isShown(false)) { - xl = (*l)->x(); yt = (*l)->y(); - xr = xl + (*l)->width(); yb = yt + (*l)->height(); + xl = client->x(); yt = client->y(); + xr = xl + client->width(); yb = yt + client->height(); // if not enough room to the left or right of the current tested client // determine the first non-overlapped y position diff --git a/tabbox/tabbox.cpp b/tabbox/tabbox.cpp index 8eedefe88..a9c5cdadf 100644 --- a/tabbox/tabbox.cpp +++ b/tabbox/tabbox.cpp @@ -235,10 +235,12 @@ TabBoxClient* TabBoxHandlerImpl::clientToAddToList(TabBoxClient* client, int des TabBoxClientList TabBoxHandlerImpl::stackingOrder() const { - ClientList stacking = Workspace::self()->stackingOrder(); + ToplevelList stacking = Workspace::self()->stackingOrder(); TabBoxClientList ret; - foreach (const Client * client, stacking) { - ret.append(client->tabBoxClient()); + foreach (Toplevel *toplevel, stacking) { + if (Client *client = qobject_cast(toplevel)) { + ret.append(client->tabBoxClient()); + } } return ret; } @@ -266,8 +268,9 @@ void TabBoxHandlerImpl::elevateClient(TabBoxClient *c, bool b) const TabBoxClient* TabBoxHandlerImpl::desktopClient() const { - foreach (const Client * client, Workspace::self()->stackingOrder()) { - if (client->isDesktop() && client->isOnCurrentDesktop() && client->screen() == Workspace::self()->activeScreen()) { + foreach (Toplevel *toplevel, Workspace::self()->stackingOrder()) { + Client *client = qobject_cast(toplevel); + if (client && client->isDesktop() && client->isOnCurrentDesktop() && client->screen() == Workspace::self()->activeScreen()) { return client->tabBoxClient(); } } @@ -1110,8 +1113,8 @@ void TabBox::CDEWalkThroughWindows(bool forward) for (int i = Workspace::self()->stackingOrder().size() - 1; i >= 0 ; --i) { - Client* it = Workspace::self()->stackingOrder().at(i); - if (it->isOnCurrentActivity() && it->isOnCurrentDesktop() && !it->isSpecialWindow() + Client* it = qobject_cast(Workspace::self()->stackingOrder().at(i)); + if (it && it->isOnCurrentActivity() && it->isOnCurrentDesktop() && !it->isSpecialWindow() && it->isShown(false) && it->wantsTabFocus() && !it->keepAbove() && !it->keepBelow()) { c = it; diff --git a/tiling/tiling.cpp b/tiling/tiling.cpp index 72df511c1..7da6bd48f 100644 --- a/tiling/tiling.cpp +++ b/tiling/tiling.cpp @@ -96,8 +96,10 @@ void Tiling::setEnabled(bool tiling) connect(m_workspace, SIGNAL(clientRemoved(KWin::Client*)), this, SLOT(removeTile(KWin::Client*))); connect(m_workspace, SIGNAL(clientActivated(KWin::Client*)), this, SLOT(notifyTilingWindowActivated(KWin::Client*))); m_tilingLayouts.resize(Workspace::self()->numberOfDesktops() + 1); - foreach (Client * c, Workspace::self()->stackingOrder()) { - createTile(c); + foreach (Toplevel *t, Workspace::self()->stackingOrder()) { + if (Client *c = qobject_cast(t)) { + createTile(c); + } } } else { disconnect(m_workspace, SIGNAL(clientAdded(KWin::Client*))); diff --git a/tiling/tilinglayout.cpp b/tiling/tilinglayout.cpp index a42c38f12..c9d9bc696 100644 --- a/tiling/tilinglayout.cpp +++ b/tiling/tilinglayout.cpp @@ -195,9 +195,11 @@ void TilingLayout::reconfigureTiling() if (tiles().length() > 0) arrange(layoutArea(tiles().first())); - foreach (Client * c, workspace()->stackingOrder()) { - if (c->rules()->checkTilingOption(0) == 1) - workspace()->tiling()->createTile(c); + foreach (Toplevel * t, workspace()->stackingOrder()) { + if (Client *c = qobject_cast(t)) { + if (c->rules()->checkTilingOption(0) == 1) + workspace()->tiling()->createTile(c); + } } } diff --git a/useractions.cpp b/useractions.cpp index 27198f665..5737a9348 100644 --- a/useractions.cpp +++ b/useractions.cpp @@ -847,12 +847,13 @@ bool Client::performMouseCommand(Options::MouseCommand command, const QPoint &gl replay = isActive(); // for clickraise mode bool mustReplay = !rules()->checkAcceptFocus(input); if (mustReplay) { - ClientList::const_iterator it = workspace()->stackingOrder().constEnd(), + ToplevelList::const_iterator it = workspace()->stackingOrder().constEnd(), begin = workspace()->stackingOrder().constBegin(); while (mustReplay && --it != begin && *it != this) { - if (((*it)->keepAbove() && !keepAbove()) || (keepBelow() && !(*it)->keepBelow())) + Client *c = qobject_cast(*it); + if (!c || (c->keepAbove() && !keepAbove()) || (keepBelow() && !c->keepBelow())) continue; // can never raise above "it" - mustReplay = !((*it)->isOnCurrentDesktop() && (*it)->isOnCurrentActivity() && (*it)->geometry().intersects(geometry())); + mustReplay = !(c->isOnCurrentDesktop() && c->isOnCurrentActivity() && c->geometry().intersects(geometry())); } } workspace()->takeActivity(this, ActivityFocus | ActivityRaise, handled && replay); @@ -1467,13 +1468,17 @@ void Workspace::switchWindow(Direction direction) QPoint curPos(c->pos().x() + c->geometry().width() / 2, c->pos().y() + c->geometry().height() / 2); - QList clist = stackingOrder(); - for (QList::Iterator i = clist.begin(); i != clist.end(); ++i) { - if ((*i)->wantsTabFocus() && *i != c && - (*i)->desktop() == d && !(*i)->isMinimized() && (*i)->isOnCurrentActivity()) { + ToplevelList clist = stackingOrder(); + for (ToplevelList::Iterator i = clist.begin(); i != clist.end(); ++i) { + Client *client = qobject_cast(c); + if (!client) { + continue; + } + if (client->wantsTabFocus() && *i != c && + client->desktop() == d && !client->isMinimized() && (*i)->isOnCurrentActivity()) { // Centre of the other window - QPoint other((*i)->pos().x() + (*i)->geometry().width() / 2, - (*i)->pos().y() + (*i)->geometry().height() / 2); + QPoint other(client->pos().x() + client->geometry().width() / 2, + client->pos().y() + client->geometry().height() / 2); int distance; int offset; @@ -1503,7 +1508,7 @@ void Workspace::switchWindow(Direction direction) // Inverse score int score = distance + offset + ((offset * offset) / distance); if (score < bestScore || !switchTo) { - switchTo = *i; + switchTo = client; bestScore = score; } } diff --git a/workspace.cpp b/workspace.cpp index b5c801403..214aae975 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -490,14 +490,18 @@ Workspace::~Workspace() // TODO: grabXServer(); // Use stacking_order, so that kwin --replace keeps stacking order - for (ClientList::iterator it = stacking_order.begin(), end = stacking_order.end(); it != end; ++it) { + for (ToplevelList::iterator it = stacking_order.begin(), end = stacking_order.end(); it != end; ++it) { + Client *c = qobject_cast(*it); + if (!c) { + continue; + } // Only release the window - (*it)->releaseWindow(true); + c->releaseWindow(true); // No removeClient() is called, it does more than just removing. // However, remove from some lists to e.g. prevent performTransiencyCheck() // from crashing. - clients.removeAll(*it); - desktops.removeAll(*it); + clients.removeAll(c); + desktops.removeAll(c); } for (UnmanagedList::iterator it = unmanaged.begin(), end = unmanaged.end(); it != end; ++it) (*it)->release(); @@ -792,28 +796,32 @@ void Workspace::updateToolWindows(bool also_hide) // 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; - for (ClientList::ConstIterator it = stacking_order.constBegin(); + for (ToplevelList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) { - if ((*it)->isUtility() || (*it)->isMenu() || (*it)->isToolbar()) { + Client *c = qobject_cast(*it); + if (!c) { + continue; + } + if (c->isUtility() || c->isMenu() || c->isToolbar()) { bool show = true; - if (!(*it)->isTransient()) { - if ((*it)->group()->members().count() == 1) // Has its own group, keep always visible + if (!c->isTransient()) { + if (c->group()->members().count() == 1) // Has its own group, keep always visible show = true; - else if (client != NULL && (*it)->group() == client->group()) + else if (client != NULL && c->group() == client->group()) show = true; else show = false; } else { - if (group != NULL && (*it)->group() == group) + if (group != NULL && c->group() == group) show = true; - else if (client != NULL && client->hasTransient((*it), true)) + else if (client != NULL && client->hasTransient(c, true)) show = true; else show = false; } if (!show && also_hide) { - const ClientList mainclients = (*it)->mainClients(); + const ClientList mainclients = c->mainClients(); // Don't hide utility windows which are standalone(?) or // have e.g. kicker as mainwindow if (mainclients.isEmpty()) @@ -821,14 +829,14 @@ void Workspace::updateToolWindows(bool also_hide) for (ClientList::ConstIterator it2 = mainclients.constBegin(); it2 != mainclients.constEnd(); ++it2) { - if ((*it2)->isSpecialWindow()) + if (c->isSpecialWindow()) show = true; } if (!show) - to_hide.append(*it); + to_hide.append(c); } if (show) - to_show.append(*it); + to_show.append(c); } } // First show new ones, then hide for (int i = to_show.size() - 1; @@ -1254,14 +1262,19 @@ bool Workspace::setCurrentDesktop(int new_desktop) currentDesktop_ = new_desktop; // Change the desktop (so that Client::updateVisibility() works) - for (ClientList::ConstIterator it = stacking_order.constBegin(); + for (ToplevelList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); - ++it) - if (!(*it)->isOnDesktop(new_desktop) && (*it) != movingClient && (*it)->isOnCurrentActivity()) { - if ((*it)->isShown(true) && (*it)->isOnDesktop(old_desktop)) - obs_wins.create(*it); - (*it)->updateVisibility(); + ++it) { + Client *c = qobject_cast(*it); + if (!c) { + continue; } + if (!c->isOnDesktop(new_desktop) && c != movingClient && c->isOnCurrentActivity()) { + if (c->isShown(true) && c->isOnDesktop(old_desktop)) + obs_wins.create(c); + (c)->updateVisibility(); + } + } // Now propagate the change, after hiding, before showing rootInfo->setCurrentDesktop(currentDesktop()); @@ -1281,9 +1294,14 @@ bool Workspace::setCurrentDesktop(int new_desktop) #endif } - for (int i = stacking_order.size() - 1; i >= 0 ; --i) - if (stacking_order.at(i)->isOnDesktop(new_desktop) && stacking_order.at(i)->isOnCurrentActivity()) - stacking_order.at(i)->updateVisibility(); + for (int i = stacking_order.size() - 1; i >= 0 ; --i) { + Client *c = qobject_cast(stacking_order.at(i)); + if (!c) { + continue; + } + if (c->isOnDesktop(new_desktop) && c->isOnCurrentActivity()) + c->updateVisibility(); + } --block_showing_desktop; if (showingDesktop()) // Do this only after desktop change to avoid flicker @@ -1302,9 +1320,12 @@ bool Workspace::setCurrentDesktop(int new_desktop) c = active_client; // The requestFocus below will fail, as the client is already active // from actiavtion.cpp if (!c && options->isNextFocusPrefersMouse()) { - QList::const_iterator it = stackingOrder().constEnd(); + ToplevelList::const_iterator it = stackingOrder().constEnd(); while (it != stackingOrder().constBegin()) { - Client *client = *(--it); + Client *client = qobject_cast(*(--it)); + if (!client) { + continue; + } if (!(client->isShown(false) && client->isOnDesktop(new_desktop) && client->isOnCurrentActivity() && client->isOnScreen(activeScreen()))) @@ -1393,14 +1414,19 @@ void Workspace::updateCurrentActivity(const QString &new_activity) QString old_activity = activity_; activity_ = new_activity; - for (ClientList::ConstIterator it = stacking_order.constBegin(); + for (ToplevelList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); - ++it) - if (!(*it)->isOnActivity(new_activity) && (*it) != movingClient && (*it)->isOnCurrentDesktop()) { - if ((*it)->isShown(true) && (*it)->isOnActivity(old_activity)) - obs_wins.create(*it); - (*it)->updateVisibility(); + ++it) { + Client *c = qobject_cast(*it); + if (!c) { + continue; } + if (!c->isOnActivity(new_activity) && c != movingClient && c->isOnCurrentDesktop()) { + if (c->isShown(true) && c->isOnActivity(old_activity)) + obs_wins.create(c); + c->updateVisibility(); + } + } // Now propagate the change, after hiding, before showing //rootInfo->setCurrentDesktop( currentDesktop() ); @@ -1417,9 +1443,14 @@ void Workspace::updateCurrentActivity(const QString &new_activity) } */ - for (int i = stacking_order.size() - 1; i >= 0 ; --i) - if (stacking_order.at(i)->isOnActivity(new_activity)) - stacking_order.at(i)->updateVisibility(); + for (int i = stacking_order.size() - 1; i >= 0 ; --i) { + Client *c = qobject_cast(stacking_order.at(i)); + if (!c) { + continue; + } + if (c->isOnActivity(new_activity)) + c->updateVisibility(); + } --block_showing_desktop; //FIXME not sure if I should do this either @@ -1497,8 +1528,10 @@ void Workspace::updateCurrentActivity(const QString &new_activity) void Workspace::activityRemoved(const QString &activity) { allActivities_.removeOne(activity); - foreach (Client * client, stacking_order) { - client->setOnActivity(activity, false); + foreach (Toplevel * toplevel, stacking_order) { + if (Client *client = qobject_cast(toplevel)) { + client->setOnActivity(activity, false); + } } //toss out any session data for it KConfigGroup cg(KGlobal::config(), QString("SubSession: ") + activity); @@ -1892,14 +1925,19 @@ void Workspace::setShowingDesktop(bool showing) if (showing_desktop) { showing_desktop_clients.clear(); ++block_focus; - ClientList cls = stackingOrder(); + ToplevelList cls = stackingOrder(); // Find them first, then minimize, otherwise transients may get minimized with the window // they're transient for - for (ClientList::ConstIterator it = cls.constBegin(); + for (ToplevelList::ConstIterator it = cls.constBegin(); it != cls.constEnd(); - ++it) - if ((*it)->isOnCurrentActivity() && (*it)->isOnCurrentDesktop() && (*it)->isShown(true) && !(*it)->isSpecialWindow()) - showing_desktop_clients.prepend(*it); // Topmost first to reduce flicker + ++it) { + Client *c = qobject_cast(*it); + if (!c) { + continue; + } + if (c->isOnCurrentActivity() && c->isOnCurrentDesktop() && c->isShown(true) && !c->isSpecialWindow()) + showing_desktop_clients.prepend(c); // Topmost first to reduce flicker + } for (ClientList::ConstIterator it = showing_desktop_clients.constBegin(); it != showing_desktop_clients.constEnd(); ++it) diff --git a/workspace.h b/workspace.h index 1d72bce95..d2c3d8cd8 100644 --- a/workspace.h +++ b/workspace.h @@ -378,7 +378,7 @@ public: * Returns the list of clients sorted in stacking order, with topmost client * at the last position */ - const ClientList& stackingOrder() const; + const ToplevelList& stackingOrder() const; ToplevelList xStackingOrder() const; ClientList ensureStackingOrder(const ClientList& clients) const; @@ -790,8 +790,8 @@ private: UnmanagedList unmanaged; DeletedList deleted; - ClientList unconstrained_stacking_order; // Topmost last - ClientList stacking_order; // Topmost last + ToplevelList unconstrained_stacking_order; // Topmost last + ToplevelList stacking_order; // Topmost last bool force_restacking; mutable ToplevelList x_stacking; // From XQueryTree() mutable bool x_stacking_dirty; @@ -1025,7 +1025,7 @@ inline void Workspace::removeGroup(Group* group, allowed_t) groups.removeAll(group); } -inline const ClientList& Workspace::stackingOrder() const +inline const ToplevelList& Workspace::stackingOrder() const { // TODO: Q_ASSERT( block_stacking_updates == 0 ); return stacking_order;