Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
IPlacementEngine.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
8
9#include <QJsonArray>
10#include <QJsonObject>
11#include <QPoint>
12#include <QRect>
13#include <QSet>
14#include <QString>
15#include <QStringList>
16#include <QVariantMap>
17
18#include <functional>
19
20class QObject;
21
22namespace PhosphorEngine {
23
56class PHOSPHORENGINE_EXPORT IPlacementEngine
57{
58public:
59 virtual ~IPlacementEngine() = default;
60
61 // ═══════════════════════════════════════════════════════════════════════════
62 // Screen ownership
63 // ═══════════════════════════════════════════════════════════════════════════
64
66 virtual bool isActiveOnScreen(const QString& screenId) const = 0;
67
68 // ═══════════════════════════════════════════════════════════════════════════
69 // Window lifecycle
70 // ═══════════════════════════════════════════════════════════════════════════
71
73 virtual void windowOpened(const QString& windowId, const QString& screenId, int minWidth = 0,
74 int minHeight = 0) = 0;
75
77 void windowOpened(const QString& windowId, const QString& screenId)
78 {
79 windowOpened(windowId, screenId, 0, 0);
80 }
81
83 virtual void windowClosed(const QString& windowId) = 0;
84
88 virtual void windowFocused(const QString& windowId, const QString& screenId) = 0;
89
90 // ═══════════════════════════════════════════════════════════════════════════
91 // Float management (explicit window ID)
92 //
93 // These take a concrete window ID — used by the D-Bus adaptor and
94 // engine-internal paths that already know which window to act on.
95 // toggleFocusedFloat() in the Navigation section is the user-intent
96 // entry point that resolves the focused window from NavigationContext.
97 // ═══════════════════════════════════════════════════════════════════════════
98
100 virtual void toggleWindowFloat(const QString& windowId, const QString& screenId) = 0;
101
103 virtual void setWindowFloat(const QString& windowId, bool shouldFloat) = 0;
104
105 // ═══════════════════════════════════════════════════════════════════════════
106 // Navigation (user intents)
107 // ═══════════════════════════════════════════════════════════════════════════
108
110 virtual void focusInDirection(const QString& direction, const NavigationContext& ctx) = 0;
111
113 virtual void moveFocusedInDirection(const QString& direction, const NavigationContext& ctx) = 0;
114
116 virtual void swapFocusedInDirection(const QString& direction, const NavigationContext& ctx) = 0;
117
119 virtual void moveFocusedToPosition(int position, const NavigationContext& ctx) = 0;
120
122 virtual void rotateWindows(bool clockwise, const NavigationContext& ctx) = 0;
123
125 virtual void reapplyLayout(const NavigationContext& ctx) = 0;
126
128 virtual void snapAllWindows(const NavigationContext& ctx) = 0;
129
131 virtual void cycleFocus(bool forward, const NavigationContext& ctx) = 0;
132
134 virtual void pushToEmptyZone(const NavigationContext& ctx) = 0;
135
137 virtual void restoreFocusedWindow(const NavigationContext& ctx) = 0;
138
140 virtual void toggleFocusedFloat(const NavigationContext& ctx) = 0;
141
142 // ═══════════════════════════════════════════════════════════════════════════
143 // OPTIONAL: Screen management (override if engine tracks multi-screen state)
144 // ═══════════════════════════════════════════════════════════════════════════
145
146 virtual QSet<QString> activeScreens() const
147 {
148 return {};
149 }
150 virtual void setActiveScreens(const QSet<QString>& screens)
151 {
152 Q_UNUSED(screens)
153 }
154
155 // ═══════════════════════════════════════════════════════════════════════════
156 // OPTIONAL: Window ordering (override if engine maintains stacking order)
157 // ═══════════════════════════════════════════════════════════════════════════
158
159 virtual QStringList managedWindowOrder(const QString& screenId) const
160 {
161 Q_UNUSED(screenId)
162 return {};
163 }
164 virtual void setInitialWindowOrder(const QString& screenId, const QStringList& windowIds)
165 {
166 Q_UNUSED(screenId)
167 Q_UNUSED(windowIds)
168 }
169
170 // ═══════════════════════════════════════════════════════════════════════════
171 // OPTIONAL: Per-screen config (override if engine supports per-screen overrides)
172 // ═══════════════════════════════════════════════════════════════════════════
173
174 virtual void applyPerScreenConfig(const QString& screenId, const QVariantMap& overrides)
175 {
176 Q_UNUSED(screenId)
177 Q_UNUSED(overrides)
178 }
179 virtual void clearPerScreenConfig(const QString& screenId)
180 {
181 Q_UNUSED(screenId)
182 }
183 virtual QVariantMap perScreenOverrides(const QString& screenId) const
184 {
185 Q_UNUSED(screenId)
186 return {};
187 }
188
189 // ═══════════════════════════════════════════════════════════════════════════
190 // OPTIONAL: Mode-specific float tracking (override if engine has mode-aware float)
191 // ═══════════════════════════════════════════════════════════════════════════
192
193 virtual bool isModeSpecificFloated(const QString& windowId) const
194 {
195 Q_UNUSED(windowId)
196 return false;
197 }
198 virtual void clearModeSpecificFloatMarker(const QString& windowId)
199 {
200 Q_UNUSED(windowId)
201 }
202 virtual bool restoreSavedModeFloat(const QString& windowId)
203 {
204 Q_UNUSED(windowId)
205 return false;
206 }
208 virtual void clearSavedFloatingForWindows(const QStringList& windowIds)
209 {
210 Q_UNUSED(windowIds)
211 }
212
213 // ═══════════════════════════════════════════════════════════════════════════
214 // OPTIONAL: Drag insert preview (override if engine supports drag-to-insert)
215 // ═══════════════════════════════════════════════════════════════════════════
216
217 virtual bool hasDragInsertPreview() const
218 {
219 return false;
220 }
221 virtual bool beginDragInsertPreview(const QString& windowId, const QString& screenId)
222 {
223 Q_UNUSED(windowId)
224 Q_UNUSED(screenId)
225 return false;
226 }
228 {
229 }
231 {
232 }
233 virtual QString dragInsertPreviewScreenId() const
234 {
235 return {};
236 }
237 virtual bool isWindowTracked(const QString& windowId) const
238 {
239 Q_UNUSED(windowId)
240 return false;
241 }
248 virtual bool isWindowManaged(const QString& windowId) const
249 {
250 Q_UNUSED(windowId)
251 return false;
252 }
253
256 virtual bool isWindowTiled(const QString& windowId) const
257 {
258 Q_UNUSED(windowId)
259 return false;
260 }
261
272 virtual QString screenForTrackedWindow(const QString& windowId) const
273 {
274 Q_UNUSED(windowId)
275 return {};
276 }
277
278 // ═══════════════════════════════════════════════════════════════════════════
279 // Cross-engine handoff
280 //
281 // When a window crosses screens whose owning engines differ (e.g. a snap
282 // screen → an autotile screen, via drag drop), ownership has to transfer
283 // between two engines. Without an explicit contract, each engine makes
284 // local guesses (autotile's "is this a floating window I should adopt?"
285 // branch, snap's "do I know this window?" early-return) and the daemon
286 // misroutes user intents during the transition window.
287 //
288 // The handoff is a two-step transaction the daemon orchestrates:
289 // 1. fromEngine->handoffRelease(windowId)
290 // 2. toEngine->handoffReceive(ctx)
291 //
292 // Each engine's release is a tracking-only clear (no geometry mutation —
293 // the receiving engine places the window). Each engine's receive applies
294 // its own placement policy (autotile picks an insert slot or floats;
295 // snap picks the nearest zone or floats) using the context fields.
296 //
297 // Engines that don't currently distinguish ownership across screens can
298 // leave both as no-ops; the defaults are safe.
299 //
300 // The verbs are prefixed `handoff*` to keep them distinct from
301 // PlacementEngineBase::releaseWindow (which is part of the base FSM
302 // lifecycle and means "this window is no longer engine-managed at all"
303 // — a different concept from "transferring ownership to another engine").
304 // ═══════════════════════════════════════════════════════════════════════════
305
310 {
311 QString windowId;
312 QString fromEngineId;
313 QString toScreenId;
314 QPoint dropPos;
316 QStringList sourceZoneIds;
317 bool wasFloating = false;
318 };
319
333 virtual void handoffReceive(const HandoffContext& ctx)
334 {
335 Q_UNUSED(ctx)
336 }
337
350 virtual void handoffRelease(const QString& windowId)
351 {
352 Q_UNUSED(windowId)
353 }
354
358 virtual QString engineId() const
359 {
360 return {};
361 }
362
365 virtual int computeDragInsertIndexAtPoint(const QString& screenId, const QPoint& cursorPos) const
366 {
367 Q_UNUSED(screenId)
368 Q_UNUSED(cursorPos)
369 return -1;
370 }
371
373 virtual void updateDragInsertPreview(int insertIndex)
374 {
375 Q_UNUSED(insertIndex)
376 }
377
378 // ═══════════════════════════════════════════════════════════════════════════
379 // OPTIONAL: Algorithm / mode identity (override if engine has switchable algorithms)
380 // ═══════════════════════════════════════════════════════════════════════════
381
382 virtual QString algorithmId() const
383 {
384 return {};
385 }
386 virtual void setAlgorithm(const QString& algorithmId)
387 {
388 Q_UNUSED(algorithmId)
389 }
390 virtual bool isEnabled() const noexcept
391 {
392 return false;
393 }
394 virtual QString activeScreen() const
395 {
396 return {};
397 }
398 virtual void setActiveScreenHint(const QString& screenId)
399 {
400 Q_UNUSED(screenId)
401 }
402
403 // ═══════════════════════════════════════════════════════════════════════════
404 // OPTIONAL: Desktop/activity context (override if engine is desktop-aware)
405 // ═══════════════════════════════════════════════════════════════════════════
406
407 virtual void setCurrentDesktop(int desktop)
408 {
409 Q_UNUSED(desktop)
410 }
411 virtual void setCurrentActivity(const QString& activity)
412 {
413 Q_UNUSED(activity)
414 }
415 virtual void updateStickyScreenPins(const std::function<bool(const QString&)>& isWindowSticky)
416 {
417 Q_UNUSED(isWindowSticky)
418 }
419 virtual QSet<int> desktopsWithActiveState() const
420 {
421 return {};
422 }
423 virtual void pruneStatesForDesktop(int removedDesktop)
424 {
425 Q_UNUSED(removedDesktop)
426 }
427 virtual void pruneStatesForActivities(const QStringList& validActivities)
428 {
429 Q_UNUSED(validActivities)
430 }
431
432 // ═══════════════════════════════════════════════════════════════════════════
433 // OPTIONAL: Settings synchronization (override if engine caches config)
434 // ═══════════════════════════════════════════════════════════════════════════
435
442 {
443 }
444 virtual qreal effectiveSplitRatioStep(const QString& screenId) const
445 {
446 Q_UNUSED(screenId)
447 return 0.05;
448 }
452 virtual int runtimeMaxWindows() const
453 {
454 return -1;
455 }
456
457 // ═══════════════════════════════════════════════════════════════════════════
458 // OPTIONAL: Retile / refresh (override if engine supports on-demand retile)
459 // ═══════════════════════════════════════════════════════════════════════════
460
461 virtual void retile(const QString& screenId = QString())
462 {
463 Q_UNUSED(screenId)
464 }
465 virtual void scheduleRetileForScreen(const QString& screenId)
466 {
467 Q_UNUSED(screenId)
468 }
469
470 // ═══════════════════════════════════════════════════════════════════════════
471 // OPTIONAL: Float origin (override if engine persists float state across mode switches)
472 // ═══════════════════════════════════════════════════════════════════════════
473
474 virtual void markModeSpecificFloated(const QString& windowId)
475 {
476 Q_UNUSED(windowId)
477 }
479 {
480 }
481 virtual void saveModeFloat(const QString& windowId)
482 {
483 Q_UNUSED(windowId)
484 }
486 {
487 }
488
489 // ═══════════════════════════════════════════════════════════════════════════
490 // OPTIONAL: Serialization (override if engine has persistent state)
491 // ═══════════════════════════════════════════════════════════════════════════
492
493 virtual QJsonArray serializeWindowOrders() const
494 {
495 return {};
496 }
497 virtual void deserializeWindowOrders(const QJsonArray& orders)
498 {
499 Q_UNUSED(orders)
500 }
501 virtual QJsonObject serializePendingRestores() const
502 {
503 return {};
504 }
505 virtual void deserializePendingRestores(const QJsonObject& obj)
506 {
507 Q_UNUSED(obj)
508 }
509
510 // ═══════════════════════════════════════════════════════════════════════════
511 // OPTIONAL: Init hooks (override to receive shared services)
512 // ═══════════════════════════════════════════════════════════════════════════
513
517 virtual void setWindowRegistry(QObject* registry)
518 {
519 Q_UNUSED(registry)
520 }
522 virtual void setIsWindowFloatingFn(std::function<bool(const QString&)> fn)
523 {
524 Q_UNUSED(fn)
525 }
526
527 // ═══════════════════════════════════════════════════════════════════════════
528 // OPTIONAL: Master operations (autotile-specific, no-op on snap engine)
529 // ═══════════════════════════════════════════════════════════════════════════
530
531 virtual void increaseMasterRatio(qreal delta = 0.05)
532 {
533 Q_UNUSED(delta)
534 }
535 virtual void decreaseMasterRatio(qreal delta = 0.05)
536 {
537 Q_UNUSED(delta)
538 }
539 virtual void increaseMasterCount()
540 {
541 }
542 virtual void decreaseMasterCount()
543 {
544 }
545 virtual void focusMaster()
546 {
547 }
549 {
550 }
551
552 // ═══════════════════════════════════════════════════════════════════════════
553 // Engine state serialization
554 // ═══════════════════════════════════════════════════════════════════════════
555
556 virtual QJsonObject serializeEngineState() const
557 {
558 return {};
559 }
560 virtual void deserializeEngineState(const QJsonObject& state)
561 {
562 Q_UNUSED(state)
563 }
564
565 // ═══════════════════════════════════════════════════════════════════════════
566 // Persistence
567 // ═══════════════════════════════════════════════════════════════════════════
568
569 virtual void saveState() = 0;
570 virtual void loadState() = 0;
571
572 // ═══════════════════════════════════════════════════════════════════════════
573 // State access
574 // ═══════════════════════════════════════════════════════════════════════════
575
581 virtual IPlacementState* stateForScreen(const QString& screenId) = 0;
582 virtual const IPlacementState* stateForScreen(const QString& screenId) const = 0;
583};
584
585} // namespace PhosphorEngine
Unified placement engine interface.
Definition IPlacementEngine.h:57
virtual QString activeScreen() const
Definition IPlacementEngine.h:394
virtual QString dragInsertPreviewScreenId() const
Definition IPlacementEngine.h:233
virtual void applyPerScreenConfig(const QString &screenId, const QVariantMap &overrides)
Definition IPlacementEngine.h:174
virtual void clearSavedFloatingForWindows(const QStringList &windowIds)
Remove saved floating state for the given windows (per-window, not bulk clear).
Definition IPlacementEngine.h:208
virtual void increaseMasterCount()
Definition IPlacementEngine.h:539
virtual QString engineId() const
Stable engine identity for HandoffContext.fromEngineId.
Definition IPlacementEngine.h:358
virtual void setAlgorithm(const QString &algorithmId)
Definition IPlacementEngine.h:386
void windowOpened(const QString &windowId, const QString &screenId)
Convenience overload — equivalent to windowOpened(id, screen, 0, 0).
Definition IPlacementEngine.h:77
virtual void setCurrentActivity(const QString &activity)
Definition IPlacementEngine.h:411
virtual int runtimeMaxWindows() const
Runtime max-windows limit.
Definition IPlacementEngine.h:452
virtual void setActiveScreenHint(const QString &screenId)
Definition IPlacementEngine.h:398
virtual void setWindowRegistry(QObject *registry)
Attach a window-class registry (QObject carrying WindowRegistry).
Definition IPlacementEngine.h:517
virtual void setActiveScreens(const QSet< QString > &screens)
Definition IPlacementEngine.h:150
virtual void windowFocused(const QString &windowId, const QString &screenId)=0
A window gained focus (called when the compositor reports activation).
virtual QString screenForTrackedWindow(const QString &windowId) const
Return the screen this engine considers the window to be on, or empty if the window isn't tracked by ...
Definition IPlacementEngine.h:272
virtual void increaseMasterRatio(qreal delta=0.05)
Definition IPlacementEngine.h:531
virtual bool isWindowTracked(const QString &windowId) const
Definition IPlacementEngine.h:237
virtual void commitDragInsertPreview()
Definition IPlacementEngine.h:227
virtual void moveFocusedInDirection(const QString &direction, const NavigationContext &ctx)=0
Move the focused window to the adjacent slot.
virtual void scheduleRetileForScreen(const QString &screenId)
Definition IPlacementEngine.h:465
virtual void swapFocusedWithMaster()
Definition IPlacementEngine.h:548
virtual void handoffRelease(const QString &windowId)
Release ownership of a window WITHOUT modifying its geometry.
Definition IPlacementEngine.h:350
virtual bool isWindowTiled(const QString &windowId) const
Whether the window is actively tiled (engine-owned, non-floating).
Definition IPlacementEngine.h:256
virtual ~IPlacementEngine()=default
virtual void setInitialWindowOrder(const QString &screenId, const QStringList &windowIds)
Definition IPlacementEngine.h:164
virtual void restoreFocusedWindow(const NavigationContext &ctx)=0
Restore the focused window out of its managed state.
virtual IPlacementState * stateForScreen(const QString &screenId)=0
Per-screen state object for the given screen.
virtual void handoffReceive(const HandoffContext &ctx)
Receive ownership of a window from another engine.
Definition IPlacementEngine.h:333
virtual void focusMaster()
Definition IPlacementEngine.h:545
virtual QString algorithmId() const
Definition IPlacementEngine.h:382
virtual void deserializeEngineState(const QJsonObject &state)
Definition IPlacementEngine.h:560
virtual QJsonObject serializePendingRestores() const
Definition IPlacementEngine.h:501
virtual bool hasDragInsertPreview() const
Definition IPlacementEngine.h:217
virtual void focusInDirection(const QString &direction, const NavigationContext &ctx)=0
Move keyboard focus to the adjacent window.
virtual void windowOpened(const QString &windowId, const QString &screenId, int minWidth=0, int minHeight=0)=0
A new window appeared on this engine's screen.
virtual void clearModeSpecificFloatMarker(const QString &windowId)
Definition IPlacementEngine.h:198
virtual void moveFocusedToPosition(int position, const NavigationContext &ctx)=0
Move the focused window to the Nth position.
virtual void refreshConfigFromSettings()
Re-read all tuning values from the engine's settings interface.
Definition IPlacementEngine.h:441
virtual QSet< QString > activeScreens() const
Definition IPlacementEngine.h:146
virtual bool isWindowManaged(const QString &windowId) const
Whether the engine considers the window "managed" (eligible for layout operations).
Definition IPlacementEngine.h:248
virtual void retile(const QString &screenId=QString())
Definition IPlacementEngine.h:461
virtual const IPlacementState * stateForScreen(const QString &screenId) const =0
virtual bool isEnabled() const noexcept
Definition IPlacementEngine.h:390
virtual qreal effectiveSplitRatioStep(const QString &screenId) const
Definition IPlacementEngine.h:444
virtual QJsonArray serializeWindowOrders() const
Definition IPlacementEngine.h:493
virtual void clearSavedModeFloating()
Definition IPlacementEngine.h:485
virtual bool isActiveOnScreen(const QString &screenId) const =0
Whether this engine is active on the given screen.
virtual void toggleWindowFloat(const QString &windowId, const QString &screenId)=0
Toggle between managed and floating.
virtual void swapFocusedInDirection(const QString &direction, const NavigationContext &ctx)=0
Swap the focused window with the adjacent window.
virtual void deserializeWindowOrders(const QJsonArray &orders)
Definition IPlacementEngine.h:497
virtual bool isModeSpecificFloated(const QString &windowId) const
Definition IPlacementEngine.h:193
virtual void rotateWindows(bool clockwise, const NavigationContext &ctx)=0
Rotate all managed windows on the screen.
virtual void saveModeFloat(const QString &windowId)
Definition IPlacementEngine.h:481
virtual bool beginDragInsertPreview(const QString &windowId, const QString &screenId)
Definition IPlacementEngine.h:221
virtual void snapAllWindows(const NavigationContext &ctx)=0
Snap every unmanaged window on the screen to the current layout.
virtual void setWindowFloat(const QString &windowId, bool shouldFloat)=0
Set floating state explicitly (directional, not toggle).
virtual QJsonObject serializeEngineState() const
Definition IPlacementEngine.h:556
virtual void cycleFocus(bool forward, const NavigationContext &ctx)=0
Cycle keyboard focus through managed windows.
virtual void toggleFocusedFloat(const NavigationContext &ctx)=0
Toggle the focused window between managed and floating.
virtual void windowClosed(const QString &windowId)=0
A window was closed.
virtual void clearPerScreenConfig(const QString &screenId)
Definition IPlacementEngine.h:179
virtual bool restoreSavedModeFloat(const QString &windowId)
Definition IPlacementEngine.h:202
virtual void reapplyLayout(const NavigationContext &ctx)=0
Re-apply the current layout to all managed windows.
virtual void updateStickyScreenPins(const std::function< bool(const QString &)> &isWindowSticky)
Definition IPlacementEngine.h:415
virtual void updateDragInsertPreview(int insertIndex)
Update the target insert index for an active drag-insert preview.
Definition IPlacementEngine.h:373
virtual void setCurrentDesktop(int desktop)
Definition IPlacementEngine.h:407
virtual void cancelDragInsertPreview()
Definition IPlacementEngine.h:230
virtual void decreaseMasterRatio(qreal delta=0.05)
Definition IPlacementEngine.h:535
virtual void deserializePendingRestores(const QJsonObject &obj)
Definition IPlacementEngine.h:505
virtual void setIsWindowFloatingFn(std::function< bool(const QString &)> fn)
Definition IPlacementEngine.h:522
virtual void pruneStatesForDesktop(int removedDesktop)
Definition IPlacementEngine.h:423
virtual void pushToEmptyZone(const NavigationContext &ctx)=0
Move the focused window to the first empty slot.
virtual void markModeSpecificFloated(const QString &windowId)
Definition IPlacementEngine.h:474
virtual void decreaseMasterCount()
Definition IPlacementEngine.h:542
virtual int computeDragInsertIndexAtPoint(const QString &screenId, const QPoint &cursorPos) const
Compute the insert index for a cursor position on a managed screen.
Definition IPlacementEngine.h:365
virtual QSet< int > desktopsWithActiveState() const
Definition IPlacementEngine.h:419
virtual void clearAllSavedFloating()
Definition IPlacementEngine.h:478
virtual QStringList managedWindowOrder(const QString &screenId) const
Definition IPlacementEngine.h:159
virtual QVariantMap perScreenOverrides(const QString &screenId) const
Definition IPlacementEngine.h:183
virtual void pruneStatesForActivities(const QStringList &validActivities)
Definition IPlacementEngine.h:427
Per-screen placement state contract.
Definition IPlacementState.h:26
Definition EngineTypes.h:13
Context for a cross-engine window handoff.
Definition IPlacementEngine.h:310
QString fromEngineId
source engine identity ("snap" / "autotile" / "")
Definition IPlacementEngine.h:312
QRect sourceGeometry
window's frame at handoff time (for size preservation)
Definition IPlacementEngine.h:315
QPoint dropPos
cursor position at drop, or invalid for non-drag handoffs
Definition IPlacementEngine.h:314
QString toScreenId
destination screen (must be owned by to engine)
Definition IPlacementEngine.h:313
QStringList sourceZoneIds
zones the window held at source (empty if not snapped)
Definition IPlacementEngine.h:316
QString windowId
Definition IPlacementEngine.h:311
Target window + screen for a navigation or lifecycle operation.
Definition NavigationContext.h:18