Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
WindowPlacement.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
7
8#include <QHash>
9#include <QJsonArray>
10#include <QJsonObject>
11#include <QLatin1String>
12#include <QRect>
13#include <QString>
14#include <QStringList>
15
16namespace PhosphorEngine {
17
30{
31 QString state;
32 QStringList zoneIds;
33 int order = -1;
34
35 bool operator==(const EngineSlot& o) const
36 {
37 return state == o.state && zoneIds == o.zoneIds && order == o.order;
38 }
39 bool operator!=(const EngineSlot& o) const
40 {
41 return !(*this == o);
42 }
43 bool isEmpty() const
44 {
45 return state.isEmpty();
46 }
47};
48
66{
67 // ── Identity (the two store keys) ──
68 QString windowId;
69 QString appId;
70
71 // ── Context (the universal restore + disabled-context gate) ──
72 QString screenId;
74 QString activity;
76
77 // ── Per-engine managed state, keyed by engineId() ──
78 QHash<QString, EngineSlot> engines;
79
80 // ── Shared free/float geometry, keyed by screenId ──
81 QHash<QString, QRect> freeGeometryByScreen;
82
83 // ── Recency (most-recent-wins ordering; stamped by the store) ──
84 quint64 sequence = 0;
85
86 bool isValid() const
87 {
88 return !windowId.isEmpty() && !appId.isEmpty();
89 }
90
93 EngineSlot slotFor(const QString& engineId) const
94 {
95 return engines.value(engineId);
96 }
97
100 QRect freeGeometryFor(const QString& screenId) const
101 {
102 return freeGeometryByScreen.value(screenId);
103 }
104
109 QRect anyFreeGeometry() const
110 {
111 for (auto it = freeGeometryByScreen.constBegin(); it != freeGeometryByScreen.constEnd(); ++it) {
112 if (it.value().isValid()) {
113 return it.value();
114 }
115 }
116 return QRect();
117 }
118
133 {
134 if (anyFreeGeometry().isValid()) {
135 return true;
136 }
137 for (auto it = engines.constBegin(); it != engines.constEnd(); ++it) {
138 const EngineSlot& s = it.value();
139 if (s.state == stateSnapped() || s.state == stateTiled()) {
140 return true;
141 }
142 if (!s.zoneIds.isEmpty() || s.order >= 0) {
143 return true;
144 }
145 }
146 return false;
147 }
148
155 bool sameContentAs(const WindowPlacement& o) const
156 {
157 return windowId == o.windowId && appId == o.appId && screenId == o.screenId
158 && virtualDesktop == o.virtualDesktop && activity == o.activity && kind == o.kind && engines == o.engines
160 }
161
167 static QLatin1String snapEngineId()
168 {
169 return QLatin1String("snap");
170 }
171 static QLatin1String autotileEngineId()
172 {
173 return QLatin1String("autotile");
174 }
175
183 static QLatin1String stateFree()
184 {
185 return QLatin1String("free");
186 }
187 static QLatin1String stateFloating()
188 {
189 return QLatin1String("floating");
190 }
191 static QLatin1String stateSnapped()
192 {
193 return QLatin1String("snapped");
194 }
195 static QLatin1String stateTiled()
196 {
197 return QLatin1String("tiled");
198 }
199
200 QJsonObject toJson() const
201 {
202 QJsonObject obj;
203 obj[QLatin1String("windowId")] = windowId;
204 obj[QLatin1String("screen")] = screenId;
205 obj[QLatin1String("desktop")] = virtualDesktop;
206 if (!activity.isEmpty()) {
207 obj[QLatin1String("activity")] = activity;
208 }
209 obj[QLatin1String("kind")] = static_cast<int>(kind);
210
211 QJsonObject eng;
212 for (auto it = engines.constBegin(); it != engines.constEnd(); ++it) {
213 const EngineSlot& s = it.value();
214 if (s.isEmpty()) {
215 continue;
216 }
217 QJsonObject so;
218 so[QLatin1String("state")] = s.state;
219 if (!s.zoneIds.isEmpty()) {
220 QJsonArray z;
221 for (const QString& id : s.zoneIds) {
222 z.append(id);
223 }
224 so[QLatin1String("zoneIds")] = z;
225 }
226 if (s.order >= 0) {
227 so[QLatin1String("order")] = s.order;
228 }
229 eng[it.key()] = so;
230 }
231 if (!eng.isEmpty()) {
232 obj[QLatin1String("engines")] = eng;
233 }
234
235 QJsonObject fg;
236 for (auto it = freeGeometryByScreen.constBegin(); it != freeGeometryByScreen.constEnd(); ++it) {
237 const QRect& g = it.value();
238 if (!g.isValid()) {
239 continue;
240 }
241 QJsonObject go;
242 go[QLatin1String("x")] = g.x();
243 go[QLatin1String("y")] = g.y();
244 go[QLatin1String("w")] = g.width();
245 go[QLatin1String("h")] = g.height();
246 fg[it.key()] = go;
247 }
248 if (!fg.isEmpty()) {
249 obj[QLatin1String("freeGeo")] = fg;
250 }
251
252 obj[QLatin1String("seq")] = static_cast<double>(sequence);
253 return obj;
254 }
255
256 static WindowPlacement fromJson(const QString& appId, const QJsonObject& obj)
257 {
259 p.appId = appId;
260 p.windowId = obj.value(QLatin1String("windowId")).toString();
261 p.screenId = obj.value(QLatin1String("screen")).toString();
262 p.virtualDesktop = obj.value(QLatin1String("desktop")).toInt();
263 p.activity = obj.value(QLatin1String("activity")).toString();
264 p.kind = clampWindowKindFromWire(obj.value(QLatin1String("kind")).toInt());
265
266 const QJsonObject eng = obj.value(QLatin1String("engines")).toObject();
267 for (auto it = eng.constBegin(); it != eng.constEnd(); ++it) {
268 const QJsonObject so = it.value().toObject();
269 EngineSlot s;
270 s.state = so.value(QLatin1String("state")).toString();
271 for (const QJsonValue& v : so.value(QLatin1String("zoneIds")).toArray()) {
272 const QString z = v.toString();
273 if (!z.isEmpty()) {
274 s.zoneIds.append(z);
275 }
276 }
277 s.order = so.value(QLatin1String("order")).toInt(-1);
278 if (!s.isEmpty()) {
279 p.engines.insert(it.key(), s);
280 }
281 }
282
283 const QJsonObject fg = obj.value(QLatin1String("freeGeo")).toObject();
284 for (auto it = fg.constBegin(); it != fg.constEnd(); ++it) {
285 const QJsonObject go = it.value().toObject();
286 const QRect g(go.value(QLatin1String("x")).toInt(), go.value(QLatin1String("y")).toInt(),
287 go.value(QLatin1String("w")).toInt(), go.value(QLatin1String("h")).toInt());
288 if (g.isValid()) {
289 p.freeGeometryByScreen.insert(it.key(), g);
290 }
291 }
292
293 p.sequence = static_cast<quint64>(obj.value(QLatin1String("seq")).toDouble());
294 return p;
295 }
296};
297
298} // namespace PhosphorEngine
Definition EngineTypes.h:13
WindowKind clampWindowKindFromWire(int wire)
Clamp an integer wire value to a valid WindowKind.
Definition EngineTypes.h:52
WindowKind
Coarse structural classification for the snap-restore consume gate.
Definition EngineTypes.h:39
One engine's view of a window: which managed slot it occupies (or that it is floating / unmanaged) in...
Definition WindowPlacement.h:30
bool isEmpty() const
Definition WindowPlacement.h:43
int order
autotile slot — tile index within the screen; -1 for snap
Definition WindowPlacement.h:33
bool operator==(const EngineSlot &o) const
Definition WindowPlacement.h:35
bool operator!=(const EngineSlot &o) const
Definition WindowPlacement.h:39
QStringList zoneIds
snap slot — zone UUIDs (first is primary); empty for autotile
Definition WindowPlacement.h:32
QString state
engine-defined token: snap "snapped"/"floating"; autotile "tiled"/"floating" ("free" retired)
Definition WindowPlacement.h:31
One window's single, authoritative placement record — the unit of the unified, engine-agnostic restor...
Definition WindowPlacement.h:66
EngineSlot slotFor(const QString &engineId) const
The slot for engineId, or a default (empty) slot if this engine has no recorded state for the window.
Definition WindowPlacement.h:93
static QLatin1String snapEngineId()
Built-in engine-slot ids.
Definition WindowPlacement.h:167
static QLatin1String stateFree()
Common state-token vocabulary.
Definition WindowPlacement.h:183
QRect freeGeometryFor(const QString &screenId) const
The shared free/float geometry for screenId, or an invalid rect if none has been captured on that scr...
Definition WindowPlacement.h:100
static QLatin1String autotileEngineId()
Definition WindowPlacement.h:171
WindowKind kind
Definition WindowPlacement.h:75
bool isValid() const
Definition WindowPlacement.h:86
static QLatin1String stateTiled()
Definition WindowPlacement.h:195
bool sameContentAs(const WindowPlacement &o) const
Content equality IGNORING sequence (the store stamps a fresh sequence on every record(),...
Definition WindowPlacement.h:155
int virtualDesktop
0 = all-desktops / sticky / unknown
Definition WindowPlacement.h:73
QString activity
empty = all-activities / unknown
Definition WindowPlacement.h:74
static QLatin1String stateFloating()
Definition WindowPlacement.h:187
QRect anyFreeGeometry() const
Any captured free/float geometry (the first valid rect in unspecified hash order — there is no per-sc...
Definition WindowPlacement.h:109
QJsonObject toJson() const
Definition WindowPlacement.h:200
static QLatin1String stateSnapped()
Definition WindowPlacement.h:191
static WindowPlacement fromJson(const QString &appId, const QJsonObject &obj)
Definition WindowPlacement.h:256
QString screenId
last managed-context screen
Definition WindowPlacement.h:72
quint64 sequence
Definition WindowPlacement.h:84
QHash< QString, EngineSlot > engines
Definition WindowPlacement.h:78
QString appId
window class; FIFO key for close/reopen (uuid changes)
Definition WindowPlacement.h:69
QHash< QString, QRect > freeGeometryByScreen
Definition WindowPlacement.h:81
QString windowId
full appId|uuid; exact key for daemon-restart (uuid stable)
Definition WindowPlacement.h:68
bool hasRestorableContent() const
Whether this record carries anything worth restoring.
Definition WindowPlacement.h:132