Merge Workspace::stackingOrder() and Workspace::xStackingOrder()

The Workspace has two stacks - one with managed windows and deleted
windows, the other includes windows from the first stack + override
redirect windows.

This change merges both stacks. It has several benefits - we will be
able to move window elevation stuff to Workspace and streamline the
scene stuff, for example it will be possible to have a root item.
Another advantage is that unmanaged windows will have
Window::stackingOrder() property set, which can be useful in the future
in qml effects or (qtquick scene if we push harder in that front).
Another advantage is that kwin will make less X11 calls when restacking
managed windows.
This commit is contained in:
Vlad Zahorodnii 2022-05-12 11:20:52 +03:00
parent fa0143fb97
commit 0489d4a2f6
11 changed files with 41 additions and 73 deletions

View file

@ -364,7 +364,6 @@ void Compositor::startupWithWorkspace()
this, &Compositor::cleanupX11, Qt::UniqueConnection);
initializeX11();
Workspace::self()->markXStackingOrderAsDirty();
Q_ASSERT(m_scene);
m_scene->initialize();
@ -891,7 +890,7 @@ void X11Compositor::composite(RenderLoop *renderLoop)
return;
}
QList<Window *> windows = Workspace::self()->xStackingOrder();
QList<Window *> windows = workspace()->stackingOrder();
QList<SurfaceItemX11 *> dirtyItems;
// Reset the damage state of each window and fetch the damage region

View file

@ -1110,7 +1110,7 @@ EffectWindow *EffectsHandlerImpl::findWindow(const QUuid &id) const
EffectWindowList EffectsHandlerImpl::stackingOrder() const
{
QList<Window *> list = Workspace::self()->xStackingOrder();
QList<Window *> list = workspace()->stackingOrder();
EffectWindowList ret;
for (Window *t : list) {
if (EffectWindow *w = t->effectWindow()) {

View file

@ -154,14 +154,12 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
return false; // let Qt process it, it'll be intercepted again in eventFilter()
}
// events that should be handled before windows can get them
switch (eventType) {
case XCB_CONFIGURE_NOTIFY:
if (reinterpret_cast<xcb_configure_notify_event_t *>(e)->event == kwinApp()->x11RootWindow()) {
markXStackingOrderAsDirty();
if (eventType == XCB_CONFIGURE_NOTIFY) {
const auto configureNotifyEvent = reinterpret_cast<xcb_configure_notify_event_t *>(e);
if (configureNotifyEvent->override_redirect && configureNotifyEvent->event == kwinApp()->x11RootWindow()) {
updateXStackingOrder();
}
break;
};
}
const xcb_window_t eventWindow = findEventWindow(e);
if (eventWindow != XCB_WINDOW_NONE) {

View file

@ -108,7 +108,6 @@ void Workspace::updateStackingOrder(bool propagate_new_windows)
stacking_order = new_stacking_order;
if (changed || propagate_new_windows) {
propagateWindows(propagate_new_windows);
markXStackingOrderAsDirty();
for (int i = 0; i < stacking_order.size(); ++i) {
stacking_order[i]->setStackingOrder(i);
@ -628,15 +627,6 @@ QList<Window *> Workspace::ensureStackingOrder(const QList<Window *> &list) cons
return ensureStackingOrderInList(stacking_order, list);
}
// Returns all windows in their stacking order on the root window.
QList<Window *> Workspace::xStackingOrder() const
{
if (m_xStackingDirty) {
const_cast<Workspace *>(this)->updateXStackingOrder();
}
return x_stacking;
}
QList<Window *> Workspace::unconstrainedStackingOrder() const
{
return unconstrained_stacking_order;
@ -644,30 +634,27 @@ QList<Window *> Workspace::unconstrainedStackingOrder() const
void Workspace::updateXStackingOrder()
{
// use our own stacking order, not the X one, as they may differ
x_stacking = stacking_order;
// we use our stacking order for managed windows, but X's for override-redirect windows
Xcb::Tree tree(kwinApp()->x11RootWindow());
xcb_window_t *windows = tree.children();
if (m_xStackingQueryTree && !m_xStackingQueryTree->isNull()) {
std::unique_ptr<Xcb::Tree> tree{std::move(m_xStackingQueryTree)};
xcb_window_t *windows = tree->children();
const auto count = tree->data()->children_len;
int foundUnmanagedCount = m_unmanaged.count();
for (unsigned int i = 0; i < count; ++i) {
for (auto it = m_unmanaged.constBegin(); it != m_unmanaged.constEnd(); ++it) {
Unmanaged *u = *it;
if (u->window() == windows[i]) {
x_stacking.append(u);
foundUnmanagedCount--;
break;
}
}
if (foundUnmanagedCount == 0) {
break;
}
const auto count = tree.data()->children_len;
int remainingCount = m_unmanaged.count();
for (unsigned int i = 0; i < count; ++i) {
auto window = findUnmanaged(windows[i]);
if (window) {
unconstrained_stacking_order.removeAll(window);
unconstrained_stacking_order.append(window);
remainingCount--;
}
if (remainingCount == 0) {
break;
}
}
m_xStackingDirty = false;
if (!m_unmanaged.isEmpty()) {
updateStackingOrder();
}
}
//*******************************

View file

@ -546,7 +546,7 @@ void Scene::paintSimpleScreen(int, const QRegion &region)
void Scene::createStackingOrder()
{
// Create a list of all windows in the stacking order
QList<Window *> windows = Workspace::self()->xStackingOrder();
QList<Window *> windows = workspace()->stackingOrder();
// Move elevated windows to the top of the stacking order
const QList<EffectWindow *> elevatedList = static_cast<EffectsHandlerImpl *>(effects)->elevatedWindows();

View file

@ -214,6 +214,11 @@ bool Unmanaged::isOutline() const
return m_outline;
}
bool Unmanaged::isUnmanaged() const
{
return true;
}
QWindow *Unmanaged::findInternalWindow() const
{
const QWindowList windows = kwinApp()->topLevelWindows();

View file

@ -30,12 +30,9 @@ public:
QStringList activities() const override;
QVector<VirtualDesktop *> desktops() const override;
QPoint clientPos() const override;
Layer layer() const override
{
return UnmanagedLayer;
}
NET::WindowType windowType(bool direct = false, int supported_types = 0) const override;
bool isOutline() const override;
bool isUnmanaged() const override;
QString captionNormal() const override { return {}; }
QString captionSuffix() const override { return {}; }

View file

@ -533,6 +533,11 @@ bool Window::isClient() const
return false;
}
bool Window::isUnmanaged() const
{
return false;
}
bool Window::isDeleted() const
{
return false;
@ -902,7 +907,7 @@ Layer Window::belongsToLayer() const
// and the docks move into the NotificationLayer (which is between Above- and
// ActiveLayer, so that active fullscreen windows will still cover everything)
// Since the desktop is also activated, nothing should be in the ActiveLayer, though
if (isInternal()) {
if (isUnmanaged() || isInternal()) {
return UnmanagedLayer;
}
if (isLockScreen()) {

View file

@ -640,6 +640,7 @@ public:
QRect visibleGeometry() const;
virtual bool isClient() const;
virtual bool isDeleted() const;
virtual bool isUnmanaged() const;
/**
* Maps the specified @a point from the global screen coordinates to the frame coordinates.

View file

@ -467,7 +467,6 @@ void Workspace::cleanupX11()
m_nullFocus.reset();
m_syncAlarmFilter.reset();
m_wasUserInteractionFilter.reset();
m_xStackingQueryTree.reset();
}
Workspace::~Workspace()
@ -698,7 +697,6 @@ void Workspace::addX11Window(X11Window *window)
m_x11Clients.append(window);
m_allClients.append(window);
addToStack(window);
markXStackingOrderAsDirty();
updateClientArea(); // This cannot be in manage(), because the window got added only now
window->updateLayer();
if (window->isDesktop()) {
@ -720,7 +718,7 @@ void Workspace::addX11Window(X11Window *window)
void Workspace::addUnmanaged(Unmanaged *window)
{
m_unmanaged.append(window);
markXStackingOrderAsDirty();
addToStack(window);
}
/**
@ -749,8 +747,8 @@ void Workspace::removeUnmanaged(Unmanaged *window)
{
Q_ASSERT(m_unmanaged.contains(window));
m_unmanaged.removeAll(window);
removeFromStack(window);
Q_EMIT unmanagedRemoved(window);
markXStackingOrderAsDirty();
}
void Workspace::addDeleted(Deleted *c, Window *orig)
@ -758,7 +756,6 @@ void Workspace::addDeleted(Deleted *c, Window *orig)
Q_ASSERT(!deleted.contains(c));
deleted.append(c);
replaceInStack(orig, c);
markXStackingOrderAsDirty();
}
void Workspace::removeDeleted(Deleted *c)
@ -767,7 +764,6 @@ void Workspace::removeDeleted(Deleted *c)
Q_EMIT deletedRemoved(c);
deleted.removeAll(c);
removeFromStack(c);
markXStackingOrderAsDirty();
if (!c->wasClient()) {
return;
}
@ -800,7 +796,6 @@ void Workspace::addWaylandWindow(Window *window)
m_allClients.append(window);
addToStack(window);
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();
if (window->wantsInput() && !window->isMinimized()) {
@ -809,7 +804,6 @@ void Workspace::addWaylandWindow(Window *window)
updateTabbox();
connect(window, &Window::windowShown, this, [this, window] {
window->updateLayer();
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();
if (window->wantsInput()) {
@ -818,7 +812,6 @@ void Workspace::addWaylandWindow(Window *window)
});
connect(window, &Window::windowHidden, this, [this] {
// TODO: update tabbox if it's displayed
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();
});
@ -854,7 +847,6 @@ void Workspace::removeAbstractClient(Window *window)
}
Q_EMIT windowRemoved(window);
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();
@ -1235,7 +1227,7 @@ void Workspace::slotOutputDisabled(Output *output)
disconnect(output, &Output::geometryChanged, this, &Workspace::desktopResized);
desktopResized();
const auto stack = xStackingOrder();
const auto stack = stackingOrder();
for (Window *window : stack) {
if (window->output() == output) {
window->setOutput(kwinApp()->platform()->outputAt(window->frameGeometry().center()));
@ -1884,14 +1876,6 @@ Window *Workspace::findInternal(QWindow *w) const
return nullptr;
}
void Workspace::markXStackingOrderAsDirty()
{
m_xStackingDirty = true;
if (kwinApp()->x11Connection() && !kwinApp()->isClosingX11Connection()) {
m_xStackingQueryTree.reset(new Xcb::Tree(kwinApp()->x11RootWindow()));
}
}
void Workspace::setWasUserInteraction()
{
if (was_user_interaction) {
@ -1928,7 +1912,6 @@ void Workspace::addInternalWindow(InternalWindow *window)
Placement::self()->place(window, area);
}
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();
@ -1939,7 +1922,6 @@ void Workspace::removeInternalWindow(InternalWindow *window)
{
m_internalWindows.removeOne(window);
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();

View file

@ -280,7 +280,6 @@ public:
* at the last position
*/
const QList<Window *> &stackingOrder() const;
QList<Window *> xStackingOrder() const;
QList<Window *> unconstrainedStackingOrder() const;
QList<X11Window *> ensureStackingOrder(const QList<X11Window *> &windows) const;
QList<Window *> ensureStackingOrder(const QList<Window *> &windows) const;
@ -388,8 +387,6 @@ public:
return m_moveResizeWindow;
}
void markXStackingOrderAsDirty();
void quickTileWindow(QuickTileMode mode);
enum Direction {
@ -630,9 +627,6 @@ private:
QList<Window *> stacking_order; // Topmost last
QVector<xcb_window_t> manual_overlays; // Topmost last
bool force_restacking;
QList<Window *> x_stacking; // From XQueryTree()
std::unique_ptr<Xcb::Tree> m_xStackingQueryTree;
bool m_xStackingDirty = false;
QList<Window *> should_get_focus; // Last is most recent
QList<Window *> attention_chain;