scene: Rework window elevation

The order in which windows are painted is computed dynamically every
frame. On the other hand, with the introduction of items, it's desired
to avoid doing that so repaints can be scheduled as needed. The
unification also opens the possibilities for more rendering related
refactors to make the code nicer and more reusable.
This commit is contained in:
Vlad Zahorodnii 2023-02-28 14:57:25 +02:00
parent 1cbc9185fb
commit b4413f4b8b
5 changed files with 32 additions and 32 deletions

View file

@ -178,7 +178,6 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, WorkspaceScene *s
});
connect(ws, &Workspace::deletedRemoved, this, [this](KWin::Window *d) {
Q_EMIT windowDeleted(d->effectWindow());
elevated_windows.removeAll(d->effectWindow());
});
connect(ws->sessionManager(), &SessionManager::stateChanged, this, &KWin::EffectsHandler::sessionStateChanged);
connect(vds, &VirtualDesktopManager::countChanged, this, &EffectsHandler::numberDesktopsChanged);
@ -1097,11 +1096,13 @@ EffectWindowList EffectsHandlerImpl::stackingOrder() const
void EffectsHandlerImpl::setElevatedWindow(KWin::EffectWindow *w, bool set)
{
elevated_windows.removeAll(w);
WindowItem *item = static_cast<EffectWindowImpl *>(w)->windowItem();
if (set) {
elevated_windows.append(w);
item->elevate();
} else {
item->deelevate();
}
addRepaint(w->expandedGeometry());
}
void EffectsHandlerImpl::setTabBoxWindow(EffectWindow *w)

View file

@ -183,8 +183,6 @@ public:
QStringList loadedEffects() const;
QStringList listOfEffects() const;
void unloadAllEffects();
QList<EffectWindow *> elevatedWindows() const;
QStringList activeEffects() const;
/**
@ -313,7 +311,6 @@ protected:
Effect *keyboard_grab_effect;
Effect *fullscreen_effect;
QList<EffectWindow *> elevated_windows;
QMultiMap<int, EffectPair> effect_order;
QHash<long, int> registered_atoms;
@ -621,14 +618,6 @@ private:
QRect m_geometry;
};
inline QList<EffectWindow *> EffectsHandlerImpl::elevatedWindows() const
{
if (isScreenLocked()) {
return QList<EffectWindow *>();
}
return elevated_windows;
}
inline xcb_window_t EffectsHandlerImpl::x11RootWindow() const
{
return kwinApp()->x11RootWindow();

View file

@ -124,6 +124,24 @@ void WindowItem::unrefVisible(int reason)
updateVisibility();
}
void WindowItem::elevate()
{
// Not ideal, but it's also highly unlikely that there are more than 1000 windows. The
// elevation constantly increases so it's possible to force specific stacking order. It
// can potentially overflow, but it's unlikely to happen because windows are elevated
// rarely.
static int elevation = 1000;
m_elevation = elevation++;
updateStackingOrder();
}
void WindowItem::deelevate()
{
m_elevation.reset();
updateStackingOrder();
}
void WindowItem::handleWindowClosed(Window *original, Window *deleted)
{
m_window = deleted;
@ -262,7 +280,11 @@ void WindowItem::updateOpacity()
void WindowItem::updateStackingOrder()
{
setZ(m_window->stackingOrder());
if (m_elevation.has_value()) {
setZ(m_elevation.value());
} else {
setZ(m_window->stackingOrder());
}
}
void WindowItem::markDamaged()

View file

@ -51,6 +51,9 @@ public:
void refVisible(int reason);
void unrefVisible(int reason);
void elevate();
void deelevate();
protected:
explicit WindowItem(Window *window, Scene *scene, Item *parent = nullptr);
void updateSurfaceItem(SurfaceItem *surfaceItem);
@ -75,6 +78,7 @@ private:
std::unique_ptr<SurfaceItem> m_surfaceItem;
std::unique_ptr<DecorationItem> m_decorationItem;
std::unique_ptr<ShadowItem> m_shadowItem;
std::optional<int> m_elevation;
int m_forceVisibleByHiddenCount = 0;
int m_forceVisibleByDeleteCount = 0;
int m_forceVisibleByDesktopCount = 0;

View file

@ -427,23 +427,7 @@ void WorkspaceScene::paintSimpleScreen(const RenderTarget &renderTarget, const R
void WorkspaceScene::createStackingOrder()
{
// Create a list of all windows in the stacking order
QList<Item *> items = m_containerItem->sortedChildItems();
// Move elevated windows to the top of the stacking order
const QList<EffectWindow *> elevatedList = static_cast<EffectsHandlerImpl *>(effects)->elevatedWindows();
for (EffectWindow *c : elevatedList) {
WindowItem *item = static_cast<EffectWindowImpl *>(c)->windowItem();
items.removeAll(item);
items.append(item);
}
// Skip windows that are not yet ready for being painted and if screen is locked skip windows
// that are neither lockscreen nor inputmethod windows.
//
// TODO? This cannot be used so carelessly - needs protections against broken clients, the
// window should not get focus before it's displayed, handle unredirected windows properly and
// so on.
for (Item *item : std::as_const(items)) {
WindowItem *windowItem = static_cast<WindowItem *>(item);
if (windowItem->isVisible()) {