Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
TilingState.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 fuddlesworth
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include <QColor>
7#include <QHash>
8#include <QPair>
9#include <QRect>
10#include <QRectF>
11#include <QSet>
12#include <QString>
13#include <QVector>
14
15namespace PhosphorCompositor {
16
29{
35 QHash<QString, QSet<QString>> tiledWindowsByScreen;
36};
37
44namespace TilingStateHelpers {
45
46// ═══════════════════════════════════════════════════════════════════════════════
47// Border state accessors (pure data queries)
48// ═══════════════════════════════════════════════════════════════════════════════
49
59inline QString screenForTiledWindow(const BorderState& border, const QString& windowId)
60{
61 for (auto it = border.tiledWindowsByScreen.constBegin(); it != border.tiledWindowsByScreen.constEnd(); ++it) {
62 if (it.value().contains(windowId)) {
63 return it.key();
64 }
65 }
66 return QString();
67}
68
69// Deliberately its OWN loop rather than screenForTiledWindow(...).isEmpty():
70// membership must stay a pure "is it in any bucket" test. Routing it through
71// the screen lookup would make a window held under an empty screen key read as
72// untiled, and this predicate has far more callers than that refactor is worth.
73inline bool isTiledWindow(const BorderState& border, const QString& windowId)
74{
75 for (auto it = border.tiledWindowsByScreen.constBegin(); it != border.tiledWindowsByScreen.constEnd(); ++it) {
76 if (it.value().contains(windowId)) {
77 return true;
78 }
79 }
80 return false;
81}
82
83// ═══════════════════════════════════════════════════════════════════════════════
84// Window closed cleanup (pure state bookkeeping)
85// ═══════════════════════════════════════════════════════════════════════════════
86
94{
95 QSet<QString>& notifiedWindows;
96 QHash<QString, QString>& notifiedWindowScreens;
97 QSet<QString>& minimizeFloatedWindows;
98 QHash<QString, QRect>& tileTargetZones;
99 QHash<QString, QRect>& centeredWaylandZones;
101 QHash<QString, QHash<QString, QRectF>>& preTileGeometries;
102};
103
110inline void cleanupClosedWindowState(const QString& windowId, BorderState& border, TilingWindowState& state)
111{
112 state.notifiedWindows.remove(windowId);
113 state.notifiedWindowScreens.remove(windowId);
114 state.minimizeFloatedWindows.remove(windowId);
115 state.tileTargetZones.remove(windowId);
116 state.centeredWaylandZones.remove(windowId);
117 state.monocleMaximizedWindows.remove(windowId);
118 // Closed windows must be removed from every screen bucket — the effect
119 // may have stale entries if the window crossed screens before closing.
120 for (auto it = border.tiledWindowsByScreen.begin(); it != border.tiledWindowsByScreen.end();) {
121 it.value().remove(windowId);
122 if (it.value().isEmpty()) {
123 it = border.tiledWindowsByScreen.erase(it);
124 } else {
125 ++it;
126 }
127 }
128
129 // Sweep the pre-tile geometry out of EVERY screen bucket — the same
130 // cross-screen-stale scenario the tiled sweep above defends against
131 // (the window crossed screens before closing) would otherwise leak a
132 // geometry entry in the old screen's bucket forever.
133 for (auto it = state.preTileGeometries.begin(); it != state.preTileGeometries.end();) {
134 it->remove(windowId);
135 if (it->isEmpty()) {
136 it = state.preTileGeometries.erase(it);
137 } else {
138 ++it;
139 }
140 }
141}
142
143// ═══════════════════════════════════════════════════════════════════════════════
144// Per-screen BorderState mutators
145// ═══════════════════════════════════════════════════════════════════════════════
146
148inline void addTiledOnScreen(BorderState& border, const QString& screenId, const QString& windowId)
149{
150 border.tiledWindowsByScreen[screenId].insert(windowId);
151}
152
155inline bool removeTiledOnScreen(BorderState& border, const QString& screenId, const QString& windowId)
156{
157 auto it = border.tiledWindowsByScreen.find(screenId);
158 if (it == border.tiledWindowsByScreen.end()) {
159 return false;
160 }
161 const bool removed = it.value().remove(windowId);
162 if (it.value().isEmpty()) {
163 border.tiledWindowsByScreen.erase(it);
164 }
165 return removed;
166}
167
171inline void removeFromOtherScreens(BorderState& border, const QString& windowId, const QString& keepScreenId)
172{
173 for (auto it = border.tiledWindowsByScreen.begin(); it != border.tiledWindowsByScreen.end();) {
174 if (it.key() != keepScreenId) {
175 it.value().remove(windowId);
176 }
177 // The keep-bucket exclusion below is defensive symmetry only: this
178 // function never mutates the keep bucket, so an empty keep bucket
179 // could only pre-exist (and every other mutator erases empty
180 // buckets on the way out).
181 if (it.value().isEmpty() && it.key() != keepScreenId) {
182 it = border.tiledWindowsByScreen.erase(it);
183 } else {
184 ++it;
185 }
186 }
187}
188
191inline bool removeFromAllScreens(BorderState& border, const QString& windowId)
192{
193 bool any = false;
194 for (auto it = border.tiledWindowsByScreen.begin(); it != border.tiledWindowsByScreen.end();) {
195 if (it.value().remove(windowId)) {
196 any = true;
197 }
198 if (it.value().isEmpty()) {
199 it = border.tiledWindowsByScreen.erase(it);
200 } else {
201 ++it;
202 }
203 }
204 return any;
205}
206
209inline QSet<QString> tiledOnScreen(const BorderState& border, const QString& screenId)
210{
211 return border.tiledWindowsByScreen.value(screenId);
212}
213
214} // namespace TilingStateHelpers
215} // namespace PhosphorCompositor
QString screenForTiledWindow(const BorderState &border, const QString &windowId)
The screen a tiled window is tracked on, or empty if it is not tiled.
Definition TilingState.h:59
void removeFromOtherScreens(BorderState &border, const QString &windowId, const QString &keepScreenId)
Remove a window from every screen's tiled bucket EXCEPT keepScreenId (cross-screen transfer: a window...
Definition TilingState.h:171
bool removeFromAllScreens(BorderState &border, const QString &windowId)
Remove a window from every screen's tiled bucket.
Definition TilingState.h:191
QSet< QString > tiledOnScreen(const BorderState &border, const QString &screenId)
Detached copy of the set of tiled windows on a given screen (QHash::value copy, not a reference).
Definition TilingState.h:209
void cleanupClosedWindowState(const QString &windowId, BorderState &border, TilingWindowState &state)
Clean up all state tracking for a closed window.
Definition TilingState.h:110
bool isTiledWindow(const BorderState &border, const QString &windowId)
Definition TilingState.h:73
bool removeTiledOnScreen(BorderState &border, const QString &screenId, const QString &windowId)
Remove a window from a specific screen's tiled bucket.
Definition TilingState.h:155
void addTiledOnScreen(BorderState &border, const QString &screenId, const QString &windowId)
Add a window to a screen's tiled bucket. Idempotent.
Definition TilingState.h:148
Definition DaemonClient.h:22
Compositor-agnostic engine-managed (tiling-family) border state.
Definition TilingState.h:29
QHash< QString, QSet< QString > > tiledWindowsByScreen
windowId → screen bucket of tile-managed windows (drives border RENDERING).
Definition TilingState.h:35
Bundles per-window state maps for cleanup operations.
Definition TilingState.h:94
QHash< QString, QString > & notifiedWindowScreens
Definition TilingState.h:96
QSet< QString > & notifiedWindows
Definition TilingState.h:95
QHash< QString, QHash< QString, QRectF > > & preTileGeometries
Definition TilingState.h:101
QSet< QString > & minimizeFloatedWindows
Definition TilingState.h:97
QHash< QString, QRect > & centeredWaylandZones
Definition TilingState.h:99
QHash< QString, QRect > & tileTargetZones
Definition TilingState.h:98
QSet< QString > & monocleMaximizedWindows
Definition TilingState.h:100