Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
SnapEngine.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 fuddlesworth
2// SPDX-License-Identifier: LGPL-2.1-or-later
3//
4// FILE-SIZE EXCEPTION (sanctioned): SnapEngine is one class — the snap
5// engine's whole public and internal surface — and C++ cannot split a class
6// declaration across headers. The implementation is partitioned by concern
7// under src/; shrinking this header means extracting collaborator classes,
8// a deliberate refactor rather than a mechanical file split. Same rationale
9// as AutotileEngine.h / daemon.h / windowtrackingadaptor.h.
10
11#pragma once
12
13#include <phosphorsnapengine_export.h>
26#include <PhosphorRules/RuleEvaluator.h>
27#include <QObject>
28#include <QPointer>
29#include <QRect>
30#include <QSet>
31#include <QString>
32#include <QStringList>
33#include <functional>
34#include <optional>
35#include <memory>
36
37namespace PhosphorZones {
38class IZoneDetector;
39class LayoutRegistry;
40}
41
42namespace PhosphorEngine {
43class IWindowRegistry;
44}
45
46// PhosphorRules::RuleEvaluator is included as a member type of
47// std::optional below (needs a complete type at declaration); RuleSet
48// is referenced only by pointer / reference, so a forward declaration would
49// suffice — but including RuleEvaluator.h pulls in RuleSet.h
50// transitively anyway, so leave the explicit forward decls out and let
51// RuleEvaluator.h provide both.
52
53namespace PhosphorSnapEngine {
54
55class INavigationStateProvider;
56class IZoneAdjacencyResolver;
57class SnapNavigationTargetResolver;
58
73class PHOSPHORSNAPENGINE_EXPORT SnapEngine : public PhosphorEngine::PlacementEngineBase
74{
75 Q_OBJECT
76
77public:
81 QObject* parent = nullptr);
82 ~SnapEngine() override;
83
104 int currentVirtualDesktopForScreen(const QString& screenId) const;
105 QString currentActivity() const;
106
113 std::pair<QString, QRect> resolveCrossDesktopZone(const QString& currentZoneId, const QString& screenId,
114 int targetDesktop) const;
115
121 QString entryZoneForCrossing(const QString& direction, const QString& neighbourScreen) const;
122
127 QString windowInZoneOnScreen(const QString& zoneId, const QString& screenId) const;
128
129 // ═══════════════════════════════════════════════════════════════════════════
130 // IPlacementEngine — lifecycle
131 // ═══════════════════════════════════════════════════════════════════════════
132
133 bool isActiveOnScreen(const QString& screenId) const override;
139 bool isEnabled() const noexcept override;
140 using IPlacementEngine::windowOpened;
141 void windowOpened(const QString& windowId, const QString& screenId, int minWidth, int minHeight) override;
142
168 using ShouldRestorePredicate = std::function<bool(const QString& screenId)>;
169
177 void setShouldRestorePredicate(ShouldRestorePredicate predicate)
178 {
179 m_shouldRestorePredicate = std::move(predicate);
180 }
181
212 using RestorePositionPredicate = std::function<bool(const QString& windowId)>;
213
221 {
222 m_restorePositionPredicate = std::move(predicate);
223 }
224
242 using ManagedRestorePredicate = std::function<bool(const QString& windowId)>;
243
251 {
252 m_managedRestorePredicate = std::move(predicate);
253 }
254
263 using LiveModeResolver = std::function<PhosphorZones::AssignmentEntry::Mode(const QString& screenId)>;
265 {
266 m_liveModeResolver = std::move(resolver);
267 }
268
280 std::function<bool(PhosphorZones::AssignmentEntry::Mode mode, const QString& screenId)>;
282 {
283 m_tilingEngineLiveResolver = std::move(resolver);
284 }
285
298 using FloatPredicate = std::function<bool(const QString& windowId, const QString& screenId)>;
299
301 {
302 m_floatPredicate = std::move(predicate);
303 }
304
320 using UnfloatFallbackPredicate = std::function<bool(const QString& windowId, const QString& screenId)>;
321
323 {
324 m_unfloatFallbackPredicate = std::move(predicate);
325 }
326
343 using PlacementZonesResolver = std::function<PlacementDirective(const QString& windowId, const QString& screenId)>;
344
346 {
347 m_placementZonesResolver = std::move(resolver);
348 }
349
350 void windowClosed(const QString& windowId) override;
351 void windowFocused(const QString& windowId, const QString& screenId) override;
352 void toggleWindowFloat(const QString& windowId, const QString& screenId) override;
353 void setWindowFloat(const QString& windowId, bool shouldFloat, const QString& screenId = QString()) override;
354 void saveState() override;
355 void loadState() override;
356
357 // Layout capability (see IPlacementEngine's Layout capability section)
360 {
361 return LayoutSupport::Placement;
362 }
363
364 // Cross-engine handoff
365 QString engineId() const override
366 {
367 return QStringLiteral("snap");
368 }
369 void handoffReceive(const HandoffContext& ctx) override;
370 void handoffRelease(const QString& windowId) override;
371 QString screenForTrackedWindow(const QString& windowId) const override;
376 bool isWindowTracked(const QString& windowId) const override;
377
385
390 void resnapCurrentAssignments(const QString& screenFilter = QString());
391
398 void resnapFromAutotileOrder(const QStringList& autotileWindowOrder, const QString& screenId);
399
416 QVector<PhosphorEngine::ZoneAssignmentEntry>
417 calculateResnapEntriesFromAutotileOrder(const QStringList& autotileWindowOrder, const QString& screenId,
418 const QStringList& preClaimedZoneIds = {});
419
426 PhosphorProtocol::SnapAllResultList calculateSnapAllWindows(const QStringList& windowIds, const QString& screenId);
427
437 void emitBatchedResnap(const QVector<PhosphorEngine::ZoneAssignmentEntry>& entries);
438
443 void snapAllWindows(const QString& screenId);
444
445 // ═══════════════════════════════════════════════════════════════════════════
446 // Window restore (auto-snap on window open)
447 // ═══════════════════════════════════════════════════════════════════════════
448
473 resolveWindowRestore(const QString& windowId, const QString& screenId, bool sticky,
475
476 // ═══════════════════════════════════════════════════════════════════════════
477 // Autotile engine reference (for isActiveOnScreen routing)
478 // ═══════════════════════════════════════════════════════════════════════════
479
489
497 void setWindowRegistry(QObject* registry) override;
498
499 // ═══════════════════════════════════════════════════════════════════════════
500 // Per-screen state resolution
501 //
502 // The engine owns one SnapState per (screen, desktop, activity)
503 // PlacementStateKey (via PerScreenStates) plus a single global-scalar holder
504 // (m_globals, keyed under the empty-screen sentinel). Each per-key store now
505 // tracks its OWN last-used zone; m_globals keeps the user-snapped classes (a
506 // per-app preference, not a placement) and the single representative last-used
507 // restored from disk. A window is placed
508 // under the key derived from its screen on first snap/float and stays there
509 // for its lifetime (the reverse map is authoritative); its screen is recorded
510 // as a per-window value, updated in place, exactly as the former single store.
511 // ═══════════════════════════════════════════════════════════════════════════
512
520 SnapState* stateForWindow(const QString& windowId);
521 const SnapState* stateForWindow(const QString& windowId) const;
522
526 {
527 return m_globals;
528 }
529
534 {
535 return m_globals;
536 }
537
540 QList<SnapState*> allSnapStates() const;
541
549 SnapState* stateForWindowOnScreen(const QString& windowId, const QString& screenId);
550
553 void forgetWindow(const QString& windowId);
554
568 bool migrateWindowToScreen(const QString& windowId, const QString& newScreenId);
569
570 // ═══════════════════════════════════════════════════════════════════════════
571 // Current-context feed (ScreenContextTracker)
572 //
573 // The daemon pushes the current virtual desktop / per-output desktop (#648) /
574 // activity here so currentKeyForScreen resolves a window's owning
575 // (screen, desktop, activity) key, mirroring the pushes it already makes into
576 // AutotileEngine. Snap keys are per-monitor first (the load-bearing #724 fix);
577 // the desktop/activity dimensions match autotile's per-context semantics.
578 // ═══════════════════════════════════════════════════════════════════════════
579
580 void setCurrentDesktop(int desktop) override;
581 void setCurrentDesktopForScreen(const QString& screenId, int desktop) override;
582 void setCurrentActivity(const QString& activity) override;
583
584 // Reclaim per-(screen,desktop,activity) stores whose context no longer exists.
585 // Without these the per-monitor stores accumulate across desktop/activity/output
586 // removal (the global holder has an empty screenId, so it is never a prune
587 // target). The daemon drives them from its desktop-count / activities-changed /
588 // screenRemoved signals, mirroring AutotileEngine.
589 QSet<int> desktopsWithActiveState() const override;
590 void pruneStatesForDesktop(int removedDesktop) override;
591 void pruneStatesForActivities(const QStringList& validActivities) override;
592 void pruneStatesForRemovedScreen(const QString& physicalScreenId) override;
593
594 // Float facade over the per-screen stores (the daemon's engine float
595 // resolver/writer/lister route here instead of a single SnapState).
596 bool isFloating(const QString& windowId) const;
597 void setFloating(const QString& windowId, bool floating);
598 QStringList floatingWindows() const;
599
606 void applyNoMatchFloatDefault(const QString& windowId, const QString& screenId);
607
610 QString zoneForWindow(const QString& windowId) const;
611
612 // ═══════════════════════════════════════════════════════════════════════════
613 // Zone adjacency resolver (for daemon-driven navigation)
614 // ═══════════════════════════════════════════════════════════════════════════
615
626
631
632 // ═══════════════════════════════════════════════════════════════════════════
633 // Navigation state provider
634 // ═══════════════════════════════════════════════════════════════════════════
635
648
649 // ═══════════════════════════════════════════════════════════════════════════
650 // Navigation (moved out of WindowTrackingAdaptor)
651 //
652 // Every method takes a PhosphorEngine::NavigationContext populated by the daemon's
653 // shortcut handler. The engine uses ctx.windowId directly rather than
654 // re-reading it from the WTA shadow, which is a step toward retiring
655 // the SnapEngine -> WTA back-reference entirely. When ctx.windowId is
656 // empty, the engine may consult m_navState->lastActiveWindowId() as a
657 // best-effort fallback -- but in the normal path the daemon always
658 // provides a resolved target.
659 // ═══════════════════════════════════════════════════════════════════════════
660
661 // ═══════════════════════════════════════════════════════════════════════════
662 // IPlacementEngine — navigation overrides
663 // ═══════════════════════════════════════════════════════════════════════════
664
667 void focusInDirection(const QString& direction, const PhosphorEngine::NavigationContext& ctx) override;
668
671 void moveFocusedInDirection(const QString& direction, const PhosphorEngine::NavigationContext& ctx) override;
672
677 void spanFocusedInDirection(const QString& direction, const PhosphorEngine::NavigationContext& ctx) override;
678
681 void swapFocusedInDirection(const QString& direction, const PhosphorEngine::NavigationContext& ctx) override;
682
685 void moveFocusedToPosition(int zoneNumber, const PhosphorEngine::NavigationContext& ctx) override;
686
689 void rotateWindows(bool clockwise, const PhosphorEngine::NavigationContext& ctx) override;
690
694
700
703 std::optional<PhosphorEngine::WindowPlacement> capturePlacement(const QString& windowId) const override;
704
715 std::optional<PhosphorEngine::WindowPlacement> capturePlacementAtDesktop(const QString& windowId,
716 int gateDesktop) const;
717
722
725
728
731
741 void switchFocusBetweenFloatingAndTiling(const QString& screenId) override;
742
746 void cycleFocus(bool forward, const PhosphorEngine::NavigationContext& ctx) override;
747
748 // ═══════════════════════════════════════════════════════════════════════════
749 // Snap commit orchestration
750 //
751 // Full snap lifecycle: clear floating, assign to zone, update tracking,
752 // emit state-changed signals. Owns the orchestration that was previously
753 // on WindowTrackingService.
754 // ═══════════════════════════════════════════════════════════════════════════
755
761 void commitSnap(const QString& windowId, const QString& zoneId, const QString& screenId,
763 int virtualDesktop = 0);
764
765 void commitMultiZoneSnap(const QString& windowId, const QStringList& zoneIds, const QString& screenId,
767 int virtualDesktop = 0);
768
769 void uncommitSnap(const QString& windowId);
770
773 PhosphorEngine::UnfloatResult resolveUnfloatGeometry(const QString& windowId, const QString& fallbackScreen) const;
784 PhosphorEngine::UnfloatResult resolveUnfloatGeometry(const QString& windowId, const QString& fallbackScreen,
785 bool confineToFallbackScreen) const;
786
799 const QString& fallbackScreen) const;
800
802 applyBatchAssignments(const QVector<PhosphorEngine::ZoneAssignmentEntry>& entries,
804 std::function<QString()> fallbackScreenResolver = {});
805
806 // ═══════════════════════════════════════════════════════════════════════════
807 // Auto-snap calculations (moved from WTS)
808 // ═══════════════════════════════════════════════════════════════════════════
809
810 PhosphorEngine::SnapResult calculateSnapToPlacementRule(const QString& windowId, const QString& windowScreenName,
811 bool isSticky) const;
812 PhosphorEngine::SnapResult calculateSnapToLastZone(const QString& windowId, const QString& windowScreenId,
813 bool isSticky) const;
814 PhosphorEngine::SnapResult calculateSnapToEmptyZone(const QString& windowId, const QString& windowScreenId,
815 bool isSticky) const;
816
817 // ═══════════════════════════════════════════════════════════════════════════
818 // Resnap / rotation calculations (moved from WTS)
819 // ═══════════════════════════════════════════════════════════════════════════
820
821 QVector<PhosphorEngine::ZoneAssignmentEntry> calculateResnapFromPreviousLayout();
822 QVector<PhosphorEngine::ZoneAssignmentEntry>
823 calculateResnapFromCurrentAssignments(const QString& screenFilter = QString()) const;
824 QVector<PhosphorEngine::ZoneAssignmentEntry>
825 calculateResnapFromAutotileOrder(const QStringList& autotileWindowOrder, const QString& screenId,
826 const QStringList& preClaimedZoneIds = {}) const;
827 QVector<PhosphorEngine::ZoneAssignmentEntry> calculateSnapAllWindowEntries(const QStringList& windowIds,
828 const QString& screenId) const;
829 QVector<PhosphorEngine::ZoneAssignmentEntry> calculateRotation(bool clockwise,
830 const QString& screenFilter = QString()) const;
831
832 // ═══════════════════════════════════════════════════════════════════════════
833 // Effect-reported windows (runtime flag — not persisted)
834 // ═══════════════════════════════════════════════════════════════════════════
835
836 void markWindowReported(const QString& windowId);
837 const QSet<QString>& effectReportedWindows() const
838 {
839 return m_effectReportedWindows;
840 }
841
842 int pruneStaleWindows(const QSet<QString>& aliveWindowIds) override;
843
844 // ═══════════════════════════════════════════════════════════════════════════
845 // IPlacementEngine — state access
846 //
847 // Resolves the per-(screen,desktop,activity) SnapState for a screen via the
848 // shared ScreenContextTracker + PerScreenStates. The non-const overload lazily
849 // creates the store; an empty screenId resolves to the global-scalar holder.
850 // ═══════════════════════════════════════════════════════════════════════════
851
852 PhosphorEngine::IPlacementState* stateForScreen(const QString& screenId) override;
853 const PhosphorEngine::IPlacementState* stateForScreen(const QString& screenId) const override;
854
855 // ═══════════════════════════════════════════════════════════════════════════
856 // Internal navigation helpers (concrete SnapEngine methods that the
857 // IPlacementEngine overrides delegate to)
858 // ═══════════════════════════════════════════════════════════════════════════
859
863
865 void rotateWindowsInLayout(bool clockwise, const QString& screenId);
866
867 // ═══════════════════════════════════════════════════════════════════════════
868 // Persistence delegate
869 // ═══════════════════════════════════════════════════════════════════════════
870
881 void setPersistenceDelegate(std::function<void()> saveFn, std::function<void()> loadFn)
882 {
883 m_saveFn = std::move(saveFn);
884 m_loadFn = std::move(loadFn);
885 }
886
891 QString lastActiveScreenId() const
892 {
893 return m_lastActiveScreenId;
894 }
895
918 void setExcludeRuleSet(const PhosphorRules::RuleSet* ruleSet);
919
940 std::function<std::optional<PhosphorRules::WindowQuery>(const QString& windowId, const QString& screenHint)>;
941
946 {
947 m_exclusionQueryProvider = std::move(provider);
948 }
949
961 bool isAppIdExcluded(const QString& appId) const;
962
973 bool isWindowExcluded(const QString& windowId, const QString& screenHint = QString()) const;
974
975Q_SIGNALS:
976 // ═══════════════════════════════════════════════════════════════════════════
977 // Signals (relayed via SnapAdaptor -> WTA -> D-Bus -> effect)
978 // ═══════════════════════════════════════════════════════════════════════════
979
981 void windowSnapStateChanged(const QString& windowId, const PhosphorProtocol::WindowStateEntry& entry);
982
984 void windowFloatingClearedForSnap(const QString& windowId, const QString& screenId);
985
987 void applyGeometryRequested(const QString& windowId, int x, int y, int width, int height, const QString& zoneId,
988 const QString& screenId, bool sizeOnly);
989
991 void resnapToNewLayoutRequested(const QString& resnapData);
992
994 void snapAllWindowsRequested(const QString& screenId);
995
1002 void applyGeometriesBatch(const PhosphorProtocol::WindowGeometryList& geometries, const QString& action);
1003
1004private:
1005 PhosphorEngine::ISnapSettings* snapSettings() const;
1006
1011 QString canonicalWindowId(const QString& rawWindowId) const;
1012
1015 PhosphorEngine::PlacementStateKey currentKeyForScreen(const QString& screenId) const
1016 {
1017 return m_context.currentKeyForScreen(screenId);
1018 }
1019
1023 SnapState* ensureStateForKey(const PhosphorEngine::PlacementStateKey& key);
1024
1032 void forEachSnapAssignment(const std::function<void(const QString& windowId, const QStringList& zoneIds,
1033 const QString& screenId, int desktop)>& fn) const;
1034
1039 void syncGlobalLastUsedForRemovedZones(const QStringList& removedZones);
1040
1046 const SnapState* lastUsedStateForScreen(const QString& screenId) const;
1047
1048 void commitSnapImpl(const QString& windowId, const QStringList& zoneIds, const QString& screenId,
1049 PhosphorEngine::SnapIntent intent, int virtualDesktop = 0);
1050
1064 QString resolveUnfloatScreen(const QString& primaryScreen, const QString& fallbackScreen) const;
1065
1066 PhosphorZones::LayoutRegistry* m_layoutManager = nullptr;
1067 PhosphorEngine::IWindowTrackingService* m_windowTracker = nullptr;
1068 // Per-(screen,desktop,activity) snap stores + the current-context tracker that
1069 // resolves a screen to its owning key. The daemon feeds the tracker the current
1070 // desktop / per-output desktop (#648) / activity, so each screen resolves to a
1071 // real {screenId, desktop, activity} key and gets its own SnapState (created
1072 // lazily on first placement). m_globals holds the global user-snapped classes
1073 // (and the representative last-used restored from disk, plus any screenless
1074 // float) under the empty-screen key so whole-store iterations pick it up
1075 // transparently; live last-used now lives in each per-screen store.
1078 SnapState* m_globals = nullptr;
1079 PhosphorEngine::IWindowRegistry* m_windowRegistry = nullptr;
1080 PhosphorZones::IZoneDetector* m_zoneDetector = nullptr;
1081 PhosphorEngine::IVirtualDesktopManager* m_virtualDesktopManager = nullptr;
1082 QPointer<QObject> m_autotileEngineObj;
1083 PhosphorEngine::IPlacementEngine* m_autotileEngineTyped = nullptr;
1084 IZoneAdjacencyResolver* m_zoneAdjacencyResolver = nullptr;
1085 // QObject identity of m_zoneAdjacencyResolver, kept so a replacement can
1086 // disconnect the previous resolver's destroyed guard (a stale guard firing
1087 // later would null the LIVE replacement). Mirrors m_autotileEngineObj.
1088 QPointer<QObject> m_zoneAdjacencyResolverObj;
1089 PhosphorEngine::ICrossSurfaceResolver* m_crossSurfaceResolver = nullptr;
1090 // Typed navigation-state provider — replaces the opaque QObject* m_wta
1091 // back-reference. Provides read-only access to compositor-layer shadows
1092 // (last-active window, last-active screen, last-cursor screen, frame
1093 // geometry). Not owned; must outlive SnapEngine.
1094 INavigationStateProvider* m_navState = nullptr;
1095 // QObject identity of m_navState — same stale-destroyed-guard rationale
1096 // as m_zoneAdjacencyResolverObj.
1097 QPointer<QObject> m_navStateObj;
1098 // Snap-mode navigation target resolver. Owned by SnapEngine — moved
1099 // here in Phase 5E from WindowTrackingAdaptor. Constructed lazily on
1100 // first navigation call (so the construction order isn't constrained
1101 // by the fact that SnapEngine has to exist before a resolver that
1102 // takes WTS + PhosphorZones::LayoutRegistry can be built).
1103 std::unique_ptr<SnapNavigationTargetResolver> m_targetResolver;
1104 QSet<QString> m_effectReportedWindows;
1105
1106 // ═══════════════════════════════════════════════════════════════════════════
1107 // Float helpers (snapengine/float.cpp)
1108 //
1109 // The historical clearFloatingStateForSnap / assignToZones pair was
1110 // removed — all snap commits now route through commitSnapImpl.
1111 // ═══════════════════════════════════════════════════════════════════════════
1112
1115 enum class UnfloatCause {
1121 UserToggle,
1125 Suspension,
1126 };
1127 bool unfloatToZone(const QString& windowId, const QString& screenId, UnfloatCause cause);
1128 bool applyGeometryForFloat(const QString& windowId, const QString& screenId);
1133 void applyFloatGeometryUnlessMinimized(const QString& windowId, const QString& screenId);
1134
1144 SnapNavigationTargetResolver* ensureTargetResolver(const QString& action = QString());
1145
1156 bool tryCrossDesktopMove(const QString& windowId, const QString& direction, const QString& screenId);
1157
1166 bool tryCrossModeOutput(const QString& windowId, const QString& direction, const QString& screenId, bool swap);
1167
1175 bool tryCrossDesktopFocus(const QString& focusedWindowId, const QString& direction, const QString& screenId);
1176
1182 bool isWindowExcludedForAction(const QString& windowId, const QString& action, const QString& screenId);
1183
1184 // `isAppIdExcluded` and `isWindowExcluded` are declared in the public
1185 // section above (so the unit tests can drive the wiring directly); full
1186 // docstrings live with those declarations.
1187
1191 bool evaluateExcludeRules(const PhosphorRules::WindowQuery& query) const;
1192
1206 const PhosphorRules::RuleSet* m_excludeRuleSet = nullptr;
1215 mutable std::optional<PhosphorRules::RuleEvaluator> m_excludeEvaluator;
1216
1220 ExclusionQueryProvider m_exclusionQueryProvider{};
1221
1222 // Persistence delegates (KConfig stays in adaptor layer)
1223 std::function<void()> m_saveFn;
1224 std::function<void()> m_loadFn;
1225
1226 // Last-focused screen (updated by windowFocused)
1227 QString m_lastActiveScreenId;
1228
1229 // Auto-snap entry gate. Empty until the daemon wires it; while empty
1230 // the engine treats every screen as active — preserving the
1231 // historical default that unit tests rely on. (The predicate's
1232 // signature is `bool(const QString& screenId)` — the desktop and
1233 // activity dimensions are resolved by the daemon-side closure at
1234 // call time, not passed in here; see ShouldRestorePredicate doc
1235 // above and discussion #461 item 7.)
1236 ShouldRestorePredicate m_shouldRestorePredicate{};
1237
1238 // Unsnapped-position-restore gate. Empty until the daemon wires it; while
1239 // empty the engine marks floated windows floating but restores their position
1240 // only on the reopening screen — the historical behaviour unit tests rely on.
1241 // See RestorePositionPredicate doc above.
1242 RestorePositionPredicate m_restorePositionPredicate{};
1243
1244 // Managed (snapped-to-zone) restore gate. Empty until the daemon wires it;
1245 // while empty the engine restores snapped records unconditionally — the
1246 // historical behaviour unit tests rely on. See ManagedRestorePredicate.
1247 ManagedRestorePredicate m_managedRestorePredicate{};
1248
1249 // Live placement-mode resolver. Empty until the daemon wires it; while empty
1250 // the engine falls back to the layout registry's cascade. See LiveModeResolver
1251 // doc above.
1252 LiveModeResolver m_liveModeResolver{};
1254 TilingEngineLiveResolver m_tilingEngineLiveResolver{};
1255
1256 // Rule-driven open-floating gate. Empty until the daemon wires it; while
1257 // empty no window is rule-floated. See FloatPredicate doc above.
1258 FloatPredicate m_floatPredicate{};
1259
1260 // Rule-driven unfloat-fallback gate. Empty until the daemon wires it;
1261 // while empty the ISnapSettings bool decides alone. See
1262 // UnfloatFallbackPredicate doc above.
1263 UnfloatFallbackPredicate m_unfloatFallbackPredicate{};
1264
1265 // Rule-driven open-placement resolver (SnapToZone). Empty until the daemon
1266 // wires it; while empty no window is rule-snapped. See PlacementZonesResolver
1267 // doc above.
1268 PlacementZonesResolver m_placementZonesResolver{};
1269};
1270
1271} // namespace PhosphorSnapEngine
Resolves the neighbouring surface — output or virtual desktop — in a direction, for cross-surface win...
Definition ICrossSurfaceResolver.h:21
Unified placement engine interface.
Definition IPlacementEngine.h:72
LayoutSupport
How this engine relates to user-selectable layouts — the entries the layout picker,...
Definition IPlacementEngine.h:964
Per-screen placement state contract.
Definition IPlacementState.h:28
Definition ISnapSettings.h:12
Definition IVirtualDesktopManager.h:13
Definition IWindowRegistry.h:14
Definition IWindowTrackingService.h:34
The two cooperating maps a per-monitor placement engine keeps: a forward map from PlacementStateKey t...
Definition PerScreenStates.h:35
Abstract base class for placement engines.
Definition PlacementEngineBase.h:32
Tracks the "current context" of each screen for a placement engine: the global current virtual deskto...
Definition ScreenContextTracker.h:46
Narrow read-only interface for compositor-layer state queries.
Definition INavigationStateProvider.h:32
Narrow interface for zone-adjacency queries used by snap navigation.
Definition IZoneAdjacencyResolver.h:28
Engine for manual zone-based window snapping.
Definition SnapEngine.h:74
void setWindowFloat(const QString &windowId, bool shouldFloat, const QString &screenId=QString()) override
Set floating state explicitly (directional, not toggle).
void windowSnapStateChanged(const QString &windowId, const PhosphorProtocol::WindowStateEntry &entry)
Snap state changed (commit / uncommit). WTA relays to D-Bus windowStateChanged.
void snapAllWindowsRequested(const QString &screenId)
Request KWin effect to collect unsnapped windows and snap them all.
void focusInDirection(const QString &direction, const PhosphorEngine::NavigationContext &ctx) override
Walk to the adjacent window in direction and transfer keyboard focus.
QString entryZoneForCrossing(const QString &direction, const QString &neighbourScreen) const
The zone a window ENTERS when it crosses onto neighbourScreen moving in direction: the first zone on ...
PhosphorEngine::SnapResult calculateSnapToPlacementRule(const QString &windowId, const QString &windowScreenName, bool isSticky) const
void markWindowReported(const QString &windowId)
void setPersistenceDelegate(std::function< void()> saveFn, std::function< void()> loadFn)
Set persistence callbacks for save/load.
Definition SnapEngine.h:881
std::function< bool(const QString &windowId)> ManagedRestorePredicate
Predicate consulted in resolveWindowRestore to decide whether a window that was SNAPPED at logout sho...
Definition SnapEngine.h:242
QVector< PhosphorEngine::ZoneAssignmentEntry > calculateRotation(bool clockwise, const QString &screenFilter=QString()) const
void setRestorePositionPredicate(RestorePositionPredicate predicate)
Inject the unsnapped-position-restore gate.
Definition SnapEngine.h:220
void setExclusionQueryProvider(ExclusionQueryProvider provider)
Inject the exclusion query provider.
Definition SnapEngine.h:945
bool isFloating(const QString &windowId) const
void setManagedRestorePredicate(ManagedRestorePredicate predicate)
Inject the managed (snapped-to-zone) restore gate.
Definition SnapEngine.h:250
void emitBatchedResnap(const QVector< PhosphorEngine::ZoneAssignmentEntry > &entries)
Emit a single batched resnapToNewLayoutRequested signal.
void setUnfloatFallbackPredicate(UnfloatFallbackPredicate predicate)
Definition SnapEngine.h:322
void setCurrentDesktop(int desktop) override
QSet< int > desktopsWithActiveState() const override
const QSet< QString > & effectReportedWindows() const
Definition SnapEngine.h:837
PhosphorEngine::SnapResult calculateSnapToLastZone(const QString &windowId, const QString &windowScreenId, bool isSticky) const
int pruneStaleWindows(const QSet< QString > &aliveWindowIds) override
Drop any per-engine bookkeeping for windows not in aliveWindowIds.
bool isAppIdExcluded(const QString &appId) const
True if appId matches an enabled rule in the borrowed placement-exclusion set (Exclude or ExcludePlac...
void reapplyManagedWindowAppearance() override
Re-emit the snap geometry for every currently-snapped (non-floating) window so the compositor re-appl...
void rotateWindowsInLayout(bool clockwise, const QString &screenId)
Rotate snapped windows through the layout's zone order on screenId.
void toggleFocusedFloat(const PhosphorEngine::NavigationContext &ctx) override
Toggle the focused window between snapped and floating.
void setExcludeRuleSet(const PhosphorRules::RuleSet *ruleSet)
Wire the daemon's filtered placement-exclusion rule set (rules carrying an Exclude or ExcludePlacemen...
SnapState * snapState() const
The global-scalar holder (alias of globalState).
Definition SnapEngine.h:533
std::optional< PhosphorEngine::WindowPlacement > capturePlacementAtDesktop(const QString &windowId, int gateDesktop) const
capturePlacement with the mode gate resolved at an EXPLICIT desktop.
PhosphorEngine::SnapResult calculateSnapToEmptyZone(const QString &windowId, const QString &windowScreenId, bool isSticky) const
QString screenForTrackedWindow(const QString &windowId) const override
Return the screen this engine considers the window to be on, or empty if the window isn't tracked by ...
void setLiveModeResolver(LiveModeResolver resolver)
Definition SnapEngine.h:264
void setPlacementZonesResolver(PlacementZonesResolver resolver)
Definition SnapEngine.h:345
bool isWindowExcluded(const QString &windowId, const QString &screenHint=QString()) const
Resolve exclusion for a live windowId using the FULL window attributes when the exclusion query provi...
void reapplyLayout(const PhosphorEngine::NavigationContext &ctx) override
Re-apply the current layout to all managed windows.
bool isActiveOnScreen(const QString &screenId) const override
Whether this engine is active on the given screen.
void pushToEmptyZone(const PhosphorEngine::NavigationContext &ctx) override
Move the focused window to the first empty zone on ctx.screenId.
void restoreFocusedWindow(const PhosphorEngine::NavigationContext &ctx) override
Restore the focused window to its captured pre-snap size and unsnap.
std::function< bool(const QString &screenId)> ShouldRestorePredicate
Predicate consulted on the auto-snap entry path to suppress zone restores onto a context the user dis...
Definition SnapEngine.h:168
std::function< bool(const QString &windowId, const QString &screenId)> UnfloatFallbackPredicate
Predicate deciding whether an unfloat with NO remembered pre-float zone falls back to a zone anyway (...
Definition SnapEngine.h:320
void windowFloatingClearedForSnap(const QString &windowId, const QString &screenId)
Floating state cleared as part of a commit. WTA relays as windowFloatingChanged(id,...
LayoutSupport layoutSupport() const override
Snap placement is driven by user-selectable zone layouts.
Definition SnapEngine.h:359
void resnapFromAutotileOrder(const QStringList &autotileWindowOrder, const QString &screenId)
Resnap windows using autotile window order as assignment source.
PhosphorEngine::IPlacementState * stateForScreen(const QString &screenId) override
Per-screen state object for the given screen.
std::pair< QString, QRect > resolveCrossDesktopZone(const QString &currentZoneId, const QString &screenId, int targetDesktop) const
Resolve the zone on screenId's targetDesktop layout that is positionally equivalent to currentZoneId ...
void handoffReceive(const HandoffContext &ctx) override
Receive ownership of a window from another engine.
void setFloating(const QString &windowId, bool floating)
void setCurrentActivity(const QString &activity) override
void snapAllWindows(const QString &screenId)
Request the KWin effect to collect and snap all unsnapped windows.
void switchFocusBetweenFloatingAndTiling(const QString &screenId) override
Jump focus between the float layer and the snapped layout (niri's switch-focus-between-floating-and-t...
PhosphorEngine::UnfloatResult resolveFallbackUnfloatGeometry(const QString &windowId, const QString &fallbackScreen) const
Fallback unfloat target for a window with NO pre-float zone (a never-snapped window that defaulted to...
void setFloatPredicate(FloatPredicate predicate)
Definition SnapEngine.h:300
void moveFocusedToPosition(int zoneNumber, const PhosphorEngine::NavigationContext &ctx) override
Move the focused window to the layout zone with zoneNumber (1-based) on ctx.screenId.
QVector< PhosphorEngine::ZoneAssignmentEntry > calculateResnapFromPreviousLayout()
int currentVirtualDesktopForScreen(const QString &screenId) const
This screen's current virtual desktop (Plasma 6.7 per-output virtual desktops, #648).
void handoffRelease(const QString &windowId) override
Release ownership of a window WITHOUT modifying its geometry.
void moveFocusedInDirection(const QString &direction, const PhosphorEngine::NavigationContext &ctx) override
Move the focused window into the adjacent zone in direction (displacing or filling the target).
int currentVirtualDesktop() const
Current virtual desktop (1-based; 0 when no virtual-desktop manager is wired) and activity,...
std::function< PlacementDirective(const QString &windowId, const QString &screenId)> PlacementZonesResolver
Resolver yielding the open-placement directive — SnapToZone ordinals and/or zone names,...
Definition SnapEngine.h:343
bool isEnabled() const noexcept override
True when snapping is globally enabled.
std::function< bool(const QString &windowId)> RestorePositionPredicate
Predicate consulted in resolveWindowRestore to decide whether a FLOATED window should have its previo...
Definition SnapEngine.h:212
QString windowInZoneOnScreen(const QString &zoneId, const QString &screenId) const
The window snapped to zoneId on screenId (the daemon's stored assignment pins it to that output),...
QString engineId() const override
Stable engine identity for HandoffContext.fromEngineId.
Definition SnapEngine.h:365
SnapState * stateForWindow(const QString &windowId)
The SnapState that owns windowId (via the reverse map), or the global holder when the window is untra...
void spanFocusedInDirection(const QString &direction, const PhosphorEngine::NavigationContext &ctx) override
Grow the focused window's zone span into the adjacent zone(s) in direction, or retract the opposite e...
PhosphorEngine::UnfloatResult resolveUnfloatGeometry(const QString &windowId, const QString &fallbackScreen) const
Unconfined (user-toggle) form.
void applyGeometriesBatch(const PhosphorProtocol::WindowGeometryList &geometries, const QString &action)
Batch of window-geometry updates, applied by the KWin effect in a single operation.
void setCurrentDesktopForScreen(const QString &screenId, int desktop) override
Set a single screen's current virtual desktop (Plasma 6.7 "switch desktops independently for each scr...
void pruneStatesForActivities(const QStringList &validActivities) override
void setWindowRegistry(QObject *registry) override
Attach the daemon's shared window registry.
void resnapToNewLayoutRequested(const QString &resnapData)
Batched resnap data (routed through WTA::handleBatchedResnap for bookkeeping)
std::function< bool(PhosphorZones::AssignmentEntry::Mode mode, const QString &screenId)> TilingEngineLiveResolver
Whether the tiling engine owning mode is actually LIVE on screenId — the liveness half of resolveWind...
Definition SnapEngine.h:280
std::optional< PhosphorEngine::WindowPlacement > capturePlacement(const QString &windowId) const override
Unified placement model — report this window's current snap state (snapped or floated) for persistenc...
void pushFocusedToEmptyZone(const PhosphorEngine::NavigationContext &ctx)
Move the focused window to the first empty zone on ctx.screenId.
void commitMultiZoneSnap(const QString &windowId, const QStringList &zoneIds, const QString &screenId, PhosphorEngine::SnapIntent intent=PhosphorEngine::SnapIntent::UserInitiated, int virtualDesktop=0)
void setTilingEngineLiveResolver(TilingEngineLiveResolver resolver)
Definition SnapEngine.h:281
std::function< PhosphorZones::AssignmentEntry::Mode(const QString &screenId)> LiveModeResolver
Live placement-mode resolver injected by the daemon (its ScreenModeRouter): engine-live-set-first wit...
Definition SnapEngine.h:263
PhosphorEngine::UnfloatResult resolveUnfloatGeometry(const QString &windowId, const QString &fallbackScreen, bool confineToFallbackScreen) const
confineToFallbackScreen refuses (returns not-found) when the RECORDED (raw, unresolved) home screen n...
QVector< PhosphorEngine::ZoneAssignmentEntry > calculateSnapAllWindowEntries(const QStringList &windowIds, const QString &screenId) const
void windowClosed(const QString &windowId) override
A window was closed.
void snapAllWindows(const PhosphorEngine::NavigationContext &ctx) override
Snap every unmanaged window on the screen.
bool migrateWindowToScreen(const QString &windowId, const QString &newScreenId)
Re-home a tracked window's snap state onto newScreenId's per-key store when it crosses monitors.
void rotateWindows(bool clockwise, const PhosphorEngine::NavigationContext &ctx) override
Rotate snapped windows through the layout's zone order, dispatched via IPlacementEngine.
QVector< PhosphorEngine::ZoneAssignmentEntry > calculateResnapFromCurrentAssignments(const QString &screenFilter=QString()) const
void applyNoMatchFloatDefault(const QString &windowId, const QString &screenId)
The no-match float-default terminal of resolveWindowRestore, callable by the SnapAdaptor when a SnapR...
const PhosphorEngine::IPlacementState * stateForScreen(const QString &screenId) const override
void applyGeometryRequested(const QString &windowId, int x, int y, int width, int height, const QString &zoneId, const QString &screenId, bool sizeOnly)
Daemon-driven geometry application (used by autotile float restore)
QString lastActiveScreenId() const
Last screen the engine saw via windowFocused.
Definition SnapEngine.h:891
QStringList floatingWindows() const
void resnapToNewLayout()
Resnap windows from previous layout to current layout after layout switch.
bool isWindowTracked(const QString &windowId) const override
Whether this engine considers the window owned (snapped, snap-floated, or otherwise carried in SnapSt...
void windowFocused(const QString &windowId, const QString &screenId) override
A window gained focus (called when the compositor reports activation).
SnapState * stateForWindowOnScreen(const QString &windowId, const QString &screenId)
Resolve-or-register the owning state for windowId placed/acting on screenId, and return it.
PhosphorProtocol::SnapAllResultList calculateSnapAllWindows(const QStringList &windowIds, const QString &screenId)
Calculate snap-all-windows assignments without applying them.
void cycleFocus(bool forward, const PhosphorEngine::NavigationContext &ctx) override
Cycle keyboard focus forward/backward through managed windows in the active zone (or the layout cycle...
void uncommitSnap(const QString &windowId)
PhosphorEngine::SnapResult resolveWindowRestore(const QString &windowId, const QString &screenId, bool sticky, PhosphorEngine::WindowKind kind=PhosphorEngine::WindowKind::Unknown)
Resolve auto-snap for a newly opened window.
QVector< PhosphorEngine::ZoneAssignmentEntry > calculateResnapEntriesFromAutotileOrder(const QStringList &autotileWindowOrder, const QString &screenId, const QStringList &preClaimedZoneIds={})
Calculate resnap entries from autotile order WITHOUT emitting signal.
void commitSnap(const QString &windowId, const QString &zoneId, const QString &screenId, PhosphorEngine::SnapIntent intent=PhosphorEngine::SnapIntent::UserInitiated, int virtualDesktop=0)
virtualDesktop pins the assignment to a specific 1-based desktop; 0 (default) records it on the windo...
QString zoneForWindow(const QString &windowId) const
Primary zone of windowId across the per-screen stores (empty if none).
std::function< bool(const QString &windowId, const QString &screenId)> FloatPredicate
Predicate deciding whether an opening window should start FLOATING because a "Float this app" rule ma...
Definition SnapEngine.h:298
SnapState * globalState() const
The global-scalar holder (last-used-zone + user-snapped classes).
Definition SnapEngine.h:525
QVector< PhosphorEngine::ZoneAssignmentEntry > calculateResnapFromAutotileOrder(const QStringList &autotileWindowOrder, const QString &screenId, const QStringList &preClaimedZoneIds={}) const
void toggleWindowFloat(const QString &windowId, const QString &screenId) override
Toggle between managed and floating.
void pruneStatesForDesktop(int removedDesktop) override
void setAutotileEngine(PhosphorEngine::IPlacementEngine *engine)
Set the autotile engine for screen ownership checks.
PhosphorProtocol::WindowGeometryList applyBatchAssignments(const QVector< PhosphorEngine::ZoneAssignmentEntry > &entries, PhosphorEngine::SnapIntent intent=PhosphorEngine::SnapIntent::UserInitiated, std::function< QString()> fallbackScreenResolver={})
void setNavigationStateProvider(INavigationStateProvider *provider)
Wire the typed navigation-state provider.
QList< SnapState * > allSnapStates() const
Every SnapState the engine owns, including the global holder, for whole-store enumerations (occupied ...
std::function< std::optional< PhosphorRules::WindowQuery >(const QString &windowId, const QString &screenHint)> ExclusionQueryProvider
Provider that builds the full WindowQuery (window class / title / role / frame size / flags) for a li...
Definition SnapEngine.h:940
void forgetWindow(const QString &windowId)
Drop the reverse-map entry for windowId (window closed / fully removed).
void pruneStatesForRemovedScreen(const QString &physicalScreenId) override
Prune per-(screen, desktop, activity) state for a PHYSICALLY REMOVED output (monitor hot-unplug),...
void setZoneAdjacencyResolver(IZoneAdjacencyResolver *resolver)
Set typed zone-adjacency resolver for directional navigation.
const SnapState * stateForWindow(const QString &windowId) const
void setCrossSurfaceResolver(PhosphorEngine::ICrossSurfaceResolver *resolver) override
Inject the cross-surface resolver (neighbour output / desktop lookup), threaded into the navigation t...
void swapFocusedInDirection(const QString &direction, const PhosphorEngine::NavigationContext &ctx) override
Swap the focused window with whatever's in the adjacent zone in direction.
void resnapCurrentAssignments(const QString &screenFilter=QString())
Resnap windows to their current zone assignments (re-apply geometries)
SnapEngine(PhosphorZones::LayoutRegistry *layoutManager, PhosphorEngine::IWindowTrackingService *windowTracker, PhosphorZones::IZoneDetector *zoneDetector, PhosphorEngine::IVirtualDesktopManager *vdm, QObject *parent=nullptr)
Per-screen snap placement state.
Definition SnapState.h:32
Abstract interface for zone detection + highlight lifecycle.
Definition IZoneDetector.h:84
Manual zone-layout registry + per-context assignment store.
Definition LayoutRegistry.h:89
Definition EngineTypes.h:14
SnapIntent
Definition EngineTypes.h:59
WindowKind
Coarse structural classification for the snap-restore consume gate.
Definition EngineTypes.h:66
constexpr QLatin1String LayoutRegistry("org.plasmazones.LayoutRegistry")
QList< SnapAllResultEntry > SnapAllResultList
Definition NavigationTypes.h:38
QList< WindowGeometryEntry > WindowGeometryList
Definition WindowTypes.h:51
Definition SnapStateResolver.h:11
Definition IWindowTrackingService.h:23
Context for a cross-engine window handoff.
Definition IPlacementEngine.h:872
Target window + screen for a navigation or lifecycle operation.
Definition NavigationContext.h:18
Identity of a per-screen placement state: a window's placement is scoped to the (screen,...
Definition EngineTypes.h:22
Definition EngineTypes.h:114
Definition EngineTypes.h:150
D-Bus struct for window state: (sssbsasb)
Definition WindowTypes.h:77
What a matched open-placement rule directs for an opening window.
Definition PlacementDirective.h:39
Mode
Per-context engine selection.
Definition AssignmentEntry.h:212