Manual zone-layout registry + per-context assignment store. More...
#include <phosphor-zones/include/PhosphorZones/LayoutRegistry.h>
Signals | |
| void | layoutsChanged () |
| void | layoutDirectoryChanged () |
| void | layoutsLoaded () |
| void | layoutsSaved () |
Signals inherited from PhosphorZones::IZoneLayoutRegistry | |
| void | layoutAdded (Layout *layout) |
| void | layoutRemoved (Layout *layout) |
| void | activeLayoutChanged (Layout *layout) |
| void | layoutAssigned (const QString &screenId, int virtualDesktop, Layout *layout) |
Signals inherited from PhosphorLayout::ILayoutSourceRegistry | |
| void | contentsChanged () |
| Emitted when the set of layouts this registry produces changes in any way that invalidates cached previews — entries added, removed, renamed, or re-parameterised. | |
Public Member Functions | |
| LayoutRegistry (PhosphorRules::RuleStore *ruleStore, QString layoutSubdirectory, QObject *parent=nullptr) | |
| ~LayoutRegistry () override | |
| int | layoutCount () const override |
| QVector< Layout * > | layouts () const override |
| Enumerate every known layout. | |
| Layout * | layout (int index) const override |
| Layout * | layoutById (const QUuid &id) const override |
| Resolve a layout by its stable UUID. | |
| Layout * | layoutByName (const QString &name) const override |
| void | addLayout (Layout *layout) override |
| bool | removeLayout (Layout *layout) override |
| bool | removeLayoutById (const QUuid &id) override |
| Layout * | duplicateLayout (Layout *source) override |
| Layout * | activeLayout () const override |
| void | setActiveLayout (Layout *layout) override |
| void | setActiveLayoutById (const QUuid &id) override |
| QString | layoutDirectory () const |
| void | setLayoutDirectory (const QString &directory) |
| void | loadLayouts () |
| void | saveLayouts () |
| void | saveLayout (Layout *layout) |
| Layout * | importLayout (const QString &filePath) |
Load a layout from filePath and add it to the registry. | |
| bool | exportLayout (Layout *layout, const QString &filePath) |
Write layout to filePath as a standalone layout document. | |
| void | loadAssignments () |
| void | saveAssignments () |
| Layout * | defaultLayout () const override |
| Resolve the effective default layout. | |
| void | setDefaultLayoutIdProvider (std::function< QString()> provider) |
| Inject a callback that returns the user-configured default layout id (or empty if unset). | |
| void | setDefaultAutotileAlgorithmProvider (std::function< QString()> provider) |
| Inject a callback that returns the user-configured default autotile algorithm id (or empty if autotile is not the user's active default). | |
| void | setTiledWindowCountProvider (std::function< std::optional< int >(const QString &screenId, int virtualDesktop, const QString &activity)> provider) |
| Inject a callback that returns the tiled-window count for a screen, or std::nullopt when the screen is not actively tiling (so a count predicate stays inert there). | |
| void | setScreenOrientationProvider (std::function< std::optional< QString >(const QString &screenId)> provider) |
| Inject a callback that returns a screen's orientation token ("portrait" / "landscape"), or std::nullopt when the geometry is unknown (so an orientation predicate stays inert there). | |
| void | setColorSchemeProvider (std::function< std::optional< QString >()> provider) |
| Inject a callback that reports the system colour scheme ("light" / "dark"), or std::nullopt when it is unknown (so a colour-scheme predicate stays inert). | |
| void | setSnappingPreferredProvider (std::function< bool()> provider) |
| Inject a callback that returns true when Snapping is the user's preferred default mode (regardless of whether a default snapping layout id is configured). | |
| void | setDefaultAssignmentSuppressedProvider (std::function< bool()> provider) |
| Inject a callback that returns true when the user has opted to suppress the synthesized level-1 default layout assignment globally. | |
| bool | snappingPreferred () const |
| True when the snapping-preferred provider is wired AND reports true — i.e. | |
| Layout * | previousLayout () const |
| Get the previous active layout (before the most recent setActiveLayout). | |
| void | assignLayout (const QString &screenId, int virtualDesktop, const QString &activity, Layout *layout) |
| void | assignLayoutById (const QString &screenId, int virtualDesktop, const QString &activity, const QString &layoutId) |
| void | setAssignmentEntryDirect (const QString &screenId, int virtualDesktop, const QString &activity, const AssignmentEntry &entry) |
| Store a full entry directly (from KCM via D-Bus). | |
| void | assignScrollingTemplate (const QString &screenId, int virtualDesktop, const QString &activity, const QString &templateId) |
Assign templateId as the context's scrolling TEMPLATE (the native ScrollingTemplate whose vocabularies and blueprint the engine consumes) and flip the mode to Scrolling. | |
| ScrollingTemplate | scrollingTemplateForContext (const QString &screenId, int virtualDesktop, const QString &activity) const override |
| The resolved ScrollingTemplate for a scrolling context, by value — invalid when the cascade has no Scrolling entry, the entry names no template and the default-template provider answers nothing, or the named template no longer exists in the store (deleted-template fallback: "no template"). | |
| void | setScrollingTemplateStore (ScrollingTemplateStore *store) |
| Wire the native template store (borrowed, post-construction like the other injected collaborators; pass nullptr on teardown). | |
| ScrollingTemplateStore * | scrollingTemplateStore () const override |
| The native scrolling-template store wired into this registry, or null when none is (lightweight stubs, roots with no template feature). | |
| void | setDefaultScrollingTemplateProvider (std::function< QString()> provider) |
| Provider for the DEFAULT scrolling template id (a config setting the daemon owns): consulted when a Scrolling context's cascade entry names no template. | |
| QString | rulesVisibleActiveLayoutId (const QString &screenId, int virtualDesktop, const QString &activity) const |
| The RULES-VISIBLE ActiveLayout value the context resolvers stamp onto their windowless queries: the assignment id, except that a Scrolling context with a resolved template substitutes the PREFIXED "scrolling:<templateUuid>" (LayoutId::makeScrollingId) — parity with autotile's "autotile:<algorithmId>" stamp, so a rule can target one template. | |
| Layout * | layoutForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const override |
Cascade-resolve the manual layout for screenId. | |
| Layout * | resolveLayoutForScreen (const QString &screenId) const override |
Resolve layout for screenId using the current desktop/activity context. | |
| ContextGapOverride | resolveContextGaps (const QString &screenId, int virtualDesktop, const QString &activity, const QString &mode=QString()) const override |
| Resolve the per-context gap override for (screen, desktop, activity) by evaluating a windowless WindowQuery through the RuleEvaluator and reading the gap action slots (InnerGap / OuterGap / UsePerSideOuterGap / per-side). | |
| bool | resolveContextLocked (const QString &screenId, int virtualDesktop, const QString &activity) const override |
Resolve whether a context rule locks the active layout for the (screen, desktop, activity) context by evaluating a windowless WindowQuery through the RuleEvaluator and reading the ActionSlot::Locked slot. | |
| std::optional< bool > | resolveContextDefaultAssignment (const QString &screenId, int virtualDesktop, const QString &activity) const |
Resolve a per-context override of the global default-layout-assignment baseline for the (screen, desktop, activity) context by evaluating a windowless WindowQuery and reading the ActionSlot::DefaultAssignment slot. | |
| std::optional< bool > | resolveContextOsdEnabled (const QString &screenId, int virtualDesktop, const QString &activity) const |
Resolve a per-context override of the OSD toggles for the (screen, desktop, activity) context by evaluating a windowless WindowQuery and reading the ActionSlot::OsdEnabled slot. | |
| std::optional< bool > | resolveContextDragSelectorEnabled (const QString &screenId, int virtualDesktop, const QString &activity) const override |
Resolve a per-context override of the drag selector popup — the edge-triggered zone / strip picker offered during a window drag — for the (screen, desktop, activity) context by evaluating a windowless WindowQuery and reading the ActionSlot::DragSelectorEnabled slot. | |
| ContextOverlayOverride | resolveContextOverlay (const QString &screenId, int virtualDesktop, const QString &activity) const override |
| Resolve the per-context overlay-property override (shader / style) for (screen, desktop, activity) by evaluating a windowless WindowQuery and reading the OverlayShader / OverlayStyle slots. | |
| ContextTilingParams | resolveContextTilingParams (const QString &screenId, int virtualDesktop, const QString &activity) const |
| Resolve the per-context autotile parameter overrides (max windows / split ratio / master count) for (screen, desktop, activity) — a per-slot read like resolveContextGaps. | |
| ContextScrollingParams | resolveContextScrollingParams (const QString &screenId, int virtualDesktop, const QString &activity) const |
| Resolve the per-context scrolling parameter overrides (default column width / focused-column centering / default column display) for (screen, desktop, activity) — a per-slot read like resolveContextTilingParams, and uncached for the same reason (screen / layout changes, not the hot per-cursor path). | |
| QString | screenOrientationToken (const QString &screenId) const |
| The screen-orientation token from m_screenOrientationProvider ("portrait" / "landscape"), or an empty string when the provider is unset or returns nullopt. | |
| void | stampScreenOrientation (PhosphorRules::WindowQuery &query, const QString &screenId) const |
Stamp the screen-orientation token onto query from m_screenOrientationProvider (a no-op when the provider is unset or returns nullopt). | |
| QString | colorSchemeToken () const |
| The colour-scheme token from m_colorSchemeProvider ("light" / "dark"), or an empty string when the provider is unset or returns nullopt. | |
| void | stampColorScheme (PhosphorRules::WindowQuery &query) const |
Stamp the colour-scheme token onto query from m_colorSchemeProvider (a no-op when unset). | |
| void | clearAssignment (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) |
| bool | hasExplicitAssignment (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const |
True iff a context-assignment rule whose match is exactly this (screen, desktop, activity) tuple's shape exists in the rule set — regardless of the rule's enabled state. | |
| AssignmentEntry | exactContextEntry (const QString &screenId, int virtualDesktop, const QString &activity) const |
| The EXPLICIT assignment entry pinned by this exact context tuple's rule, or a default entry when none exists. | |
| bool | exactContextDeclaresEngineMode (const QString &screenId, int virtualDesktop, const QString &activity) const |
| Whether the exact-context rule for this tuple DECLARES an engine mode, rather than merely being defaulted into one. | |
| QString | assignmentIdForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const override |
| Raw assignment id for a (screen, desktop, activity) context. | |
| QString | storedAssignmentIdForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const |
| Like assignmentIdForScreen, but WITHOUT the level-1 global default fallback: resolves the same per-context cascade (including the connector-name / virtual-screen retries) and returns empty on a cascade miss instead of synthesizing an id from the default providers. | |
| AssignmentEntry | assignmentEntryForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const |
| Full entry for a (screen, desktop, activity) context. | |
| AssignmentEntry::Mode | modeForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const |
| bool | isContextActiveLayoutSuppressed (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const override |
True iff the context has NO active layout specifically because the default assignment is suppressed — globally (see setDefaultAssignmentSuppressedProvider) or by a per-context DefaultLayoutAssignment rule. | |
| bool | isDefaultAssignmentSuppressedForContext (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const |
True iff the SYNTHESIZED default (the level-1 provider layout / autotile algorithm) is suppressed for this context — a per-context DefaultLayoutAssignment override decides locally (suppress → true, allow → false), otherwise the global suppress setting. | |
| QString | snappingLayoutForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const |
| Per-field cascade readers — return the named field from the first entry in the cascade where it is non-empty. | |
| QString | tilingAlgorithmForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const override |
Raw id of the tiling algorithm active for the (screenId, virtualDesktop, activity) context, or empty when none resolves. | |
| QString | scrollingTemplateLayoutForScreen (const QString &screenId, int virtualDesktop=0, const QString &activity=QString()) const |
| Raw template-field sibling of the two getters above: NOT mode-gated, so a dormant template preserved on a non-Scrolling context (the lossless-toggle contract) reads back. | |
| bool | scrollingTemplateExplicitlyNone (const QString &screenId, int virtualDesktop, const QString &activity) const override |
| Mode-gated like scrollingTemplateForContext rather than like the raw getter above: a token preserved on a context that has since been switched to another engine is dormant data, and highlighting the picker's None card for it would describe a choice the screen is not currently making. | |
| void | clearAutotileAssignments () |
Flip mode to Snapping for every entry currently in Autotile (preserves snappingLayout + tilingAlgorithm + scrollingTemplateLayout) and CLEAR the autotile quick-layout slots. | |
| int | restoreAutotileAssignments () |
Reverse direction of clearAutotileAssignments FOR THE ASSIGNMENT RULES ONLY (the wiped quick-layout slots are NOT restored): flip mode back to Autotile for every context-assignment entry sitting in Snapping while still carrying a tilingAlgorithm; preserves snappingLayout, advisory null-layout layoutAssigned per affected screen, one save at end. | |
| void | setAllScreenAssignments (const QHash< QString, QString > &assignments) |
| Batch setters - clear existing, set new, save once at end. | |
| void | setAllDesktopAssignments (const QHash< QPair< QString, int >, QString > &assignments) |
| void | setAllActivityAssignments (const QHash< QPair< QString, QString >, QString > &assignments) |
| void | setAllCombinedAssignments (const QHash< CombinedAssignmentKey, QString > &assignments) |
| Combined-context (screen + desktop + activity) batch setter — the triple-axis sibling of the Activity / Desktop batches. | |
| QHash< QPair< QString, int >, AssignmentEntry > | desktopAssignments () const |
| The three projection readers return the FULL AssignmentEntry per context (mode + all three payload fields), so consumers see the scrolling template beside the activeLayoutId() the batch setters round-trip on. | |
| QHash< QPair< QString, QString >, AssignmentEntry > | activityAssignments () const |
| QHash< CombinedAssignmentKey, AssignmentEntry > | combinedAssignments () const |
| Strict Combined-context reader. | |
| Layout * | layoutForShortcut (AssignmentEntry::Mode mode, int number) const |
| void | applyQuickLayout (AssignmentEntry::Mode mode, int number, const QString &screenId) |
| void | setQuickLayoutSlot (AssignmentEntry::Mode mode, int number, const QString &layoutId) |
| void | setAllQuickLayoutSlots (AssignmentEntry::Mode mode, const QHash< int, QString > &slots) |
| QHash< int, QString > | quickLayoutSlots (AssignmentEntry::Mode mode) const |
| void | cycleToPreviousLayout (const QString &screenId) |
| void | cycleToNextLayout (const QString &screenId) |
| bool | applyScrollingTemplateToScreen (const QString &screenId, const QString &templateId) |
Commit templateId as screenId's scrolling template on the screen's OWN desktop (the template twin of applyLayoutToScreen's per-screen commit; quick slots and the picker route here). | |
| bool | purgeLayoutIdFromAssignments (const QString &layoutId) |
Drop id from every assignment rule's SetSnappingLayout and SetScrollingTemplate actions, and from every quick-slot array — the id-keyed scrub BOTH deletion flows drive: layout deletion (removeLayout calls it) and native template deletion (the D-Bus delete verb calls it; the two id namespaces are disjoint UUID sets, so one walk is exact for both). | |
| void | createBuiltInLayouts () |
| QVector< Layout * > | builtInLayouts () const |
| int | currentVirtualDesktop () const override |
| QString | currentActivity () const override |
| void | setCurrentVirtualDesktop (int desktop) |
| int | currentVirtualDesktopForScreen (const QString &screenId) const override |
| This screen's current virtual desktop, resolved through the injected provider (the daemon wires it to the VirtualDesktopManager — ONE authority, no push-updated mirror to lag) and falling back to the global m_currentVirtualDesktop when no provider is installed (KCM/editor-hosted registries) or the provider has no answer (#648). | |
| void | setCurrentVirtualDesktopProvider (std::function< std::optional< int >(const QString &screenId)> provider) |
| Inject the per-screen desktop resolver above. | |
| void | setCurrentActivity (const QString &activity) |
| void | saveAutotileOverrides (const QString &algorithmId, const QJsonObject &overrides) |
| QJsonObject | loadAutotileOverrides (const QString &algorithmId) const override |
| Per-algorithm autotile settings (gaps, shader, hiddenFromSelector, …) stored in the unified layout-settings.json sidecar, keyed by raw algorithm id. | |
| void | seedDefaultLayoutSettingsIfFresh (const QJsonObject &defaults) |
| Seed curated default picker visibility into the sidecar, but ONLY on a fresh install — when neither layout-settings.json nor the legacy autotile-overrides.json exists. | |
| int | contextResolveCacheSize () const |
| Current entry count in the resolveAssignmentEntry hot-path cache. | |
Public Member Functions inherited from PhosphorZones::IZoneLayoutRegistry | |
| IZoneLayoutRegistry (QObject *parent=nullptr) | |
| ~IZoneLayoutRegistry () override | |
| QString | scrollingDisplayIdForContext (const QString &screenId, int virtualDesktop, const QString &activity) const |
| The id the layout PICKER highlights for a scrolling context: the resolved template's bare UUID, the reserved no-template word when the context opted out explicitly, or the "scrolling:" sentinel (matches no card) when no template resolves for any other reason. | |
Public Member Functions inherited from PhosphorLayout::ILayoutSourceRegistry | |
| ILayoutSourceRegistry (QObject *parent=nullptr) | |
| ~ILayoutSourceRegistry () override | |
Static Public Member Functions | |
| static QString | duplicateNameSuffix () |
| The literal suffix duplicateLayout appends to the source layout's name. | |
| static bool | isLayoutJsonValid (const QJsonObject &json, const QString &context) |
Validate json against the bundled layout schema — the single gate every untrusted layout document passes before it reaches Layout::fromJson. | |
| static QString | contextCacheKeyToken (const QString &modeToken, const QString &activeLayoutId, const QString &orientationToken, const QString &colorSchemeToken) |
Compose the extra cache-key token a daemon-facing context resolver (gap / lock / overlay / default-assignment / osd / drag-selector) passes to resolveCachedContext, folding in the placement modeToken (empty for every resolver but the gap one), the activeLayoutId, the orientationToken and the colorSchemeToken. | |
| static QString | assignmentCacheKeyToken (const std::optional< int > &tiledCount, const QString &orientationToken, const QString &colorSchemeToken) |
| The resolveAssignmentEntry cache's own extra token. | |
| static QString | escapeKeyComponent (const QString &component) |
| Make a cache-key component unambiguous under concatenation. | |
Static Public Attributes | |
| static constexpr QLatin1String | QuickSlotsSnappingKey {"snapping"} |
| quicklayouts.json top-level keys: one nested slot object per slot ARRAY ("snapping", "autotile", "scrolling"). | |
| static constexpr QLatin1String | QuickSlotsAutotileKey {"autotile"} |
| static constexpr QLatin1String | QuickSlotsScrollingKey {"scrolling"} |
Manual zone-layout registry + per-context assignment store.
Concrete counterpart to IZoneLayoutRegistry - mirrors the PhosphorTiles AlgorithmRegistry shape (interface for the provider contract, one concrete class for everything else). Composition roots construct one instance per process and inject it into every consumer; there is no process-global singleton.
Responsibilities:
Rule and the cascade is the evaluator's descending-priority walk.quicklayouts.json sidecar beside the rule store's file.| PhosphorZones::LayoutRegistry::LayoutRegistry | ( | PhosphorRules::RuleStore * | ruleStore, |
| QString | layoutSubdirectory, | ||
| QObject * | parent = nullptr |
||
| ) |
| ruleStore | Borrowed unified Rule store. Required - asserted non-null. The store's PhosphorRules::RuleSet is the single source of truth for every per-context assignment; the registry resolves layoutForScreen / assignmentEntryForScreen and the per-mode/snapping/ tiling derivatives by building a windowless PhosphorRules::WindowQuery and evaluating it through PhosphorRules::RuleEvaluator. Mutators (assignLayout etc.) translate to context-rule upserts via ContextRuleBridge and persist through the store. The caller owns the store and must outlive the registry. |
| layoutSubdirectory | XDG-relative path used for layout JSON discovery (e.g. "plasmazones/layouts"). The registry writes to QStandardPaths::writableLocation(GenericDataLocation)/<subdir> and reads the union of every GenericDataLocation entry containing that subdirectory, so system copies (in /usr/share/ <subdir>) provide built-ins while the user-writable copy overrides them. Required - asserted non-empty. Quick-layout slots do NOT live here: they persist to a quicklayouts.json sibling of the rule store's file, so their location survives a later setLayoutDirectory call. |
| parent | Qt parent. |
ruleStore loads its rule set in its own constructor, so assignment resolution is live immediately. loadAssignments additionally re-reads the shared rule store from disk, so composition roots also call it to pick up cross-process rule edits. The daemon composition root calls loadLayouts then loadAssignments; the editor / settings roots, which drive quick slots over D-Bus rather than locally, deliberately skip it.
|
override |
|
inlineoverridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
| QHash< QPair< QString, QString >, AssignmentEntry > PhosphorZones::LayoutRegistry::activityAssignments | ( | ) | const |
|
overridevirtual |
| layout | Ownership transferred - the registry adopts layout and is responsible for its lifetime from this call on. |
Implements PhosphorZones::IZoneLayoutRegistry.
| void PhosphorZones::LayoutRegistry::applyQuickLayout | ( | AssignmentEntry::Mode | mode, |
| int | number, | ||
| const QString & | screenId | ||
| ) |
| bool PhosphorZones::LayoutRegistry::applyScrollingTemplateToScreen | ( | const QString & | screenId, |
| const QString & | templateId | ||
| ) |
Commit templateId as screenId's scrolling template on the screen's OWN desktop (the template twin of applyLayoutToScreen's per-screen commit; quick slots and the picker route here).
Refuses an empty screen, a malformed id, or an id the wired store does not know. Impl beside applyLayoutToScreen.
| void PhosphorZones::LayoutRegistry::assignLayout | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity, | ||
| Layout * | layout | ||
| ) |
| void PhosphorZones::LayoutRegistry::assignLayoutById | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity, | ||
| const QString & | layoutId | ||
| ) |
|
inlinestatic |
The resolveAssignmentEntry cache's own extra token.
The assignment resolver stamps the tiled-window count but NOT the active layout (reading it there would recurse), so its key carries a "twc:" component the daemon-facing resolvers have no use for and no "al:" component — a different shape, composed here rather than open-coded at the call site so both key formats live next to each other and share escapeKeyComponent. tiledCount contributes nothing when disengaged, which is the "count unknown" key.
| AssignmentEntry PhosphorZones::LayoutRegistry::assignmentEntryForScreen | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) | const |
Full entry for a (screen, desktop, activity) context.
Shares the per-context cascade with layoutForScreen up through level-2 (per-screen base entry), but the two diverge at level-1 (global defaults): on cascade-miss this method synthesizes from BOTH providers - snap provider first, then autotile provider - using the same precedence as assignmentIdForScreen, while layoutForScreen consults only the snap provider via defaultLayout. This means a caller mixing both APIs may see entry.mode == Autotile with layoutForScreen returning a snap Layout* (the historical pre-368 fallback shape, preserved so the autotile engine's assignmentIdForScreen-driven activation path remains mode-aware while the snap engine's layoutForScreen-driven path stays Layout*-typed). Returns a default-constructed entry when neither provider returns a value. Callers that need raw stored state without the synth fallback must gate with hasExplicitAssignment.
|
overridevirtual |
Raw assignment id for a (screen, desktop, activity) context.
Returns the stored string (manual-layout UUID, "autotile:<algorithmId>", or the bare "scrolling:" sentinel) without resolving to a Layout*. An explicit mode-only Snapping pin settles as an EMPTY id (no layout identity exists for it). On cascade-miss, falls through to the level-1 global defaults (snap provider first, then autotile provider; see setDefaultLayoutIdProvider / setDefaultAutotileAlgorithmProvider). Empty when every cascade level misses AND both providers return empty. Callers that need to distinguish "stored" from "synthesized fallback" should use storedAssignmentIdForScreen, which walks the same cascade but reports a miss as empty instead of synthesizing.
Implements PhosphorZones::IZoneLayoutRegistry.
| void PhosphorZones::LayoutRegistry::assignScrollingTemplate | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity, | ||
| const QString & | templateId | ||
| ) |
Assign templateId as the context's scrolling TEMPLATE (the native ScrollingTemplate whose vocabularies and blueprint the engine consumes) and flip the mode to Scrolling.
The sibling fields survive per the lossless-toggle contract, and activeLayoutId() stays the bare "scrolling:" sentinel. An id unknown to the wired store is stored as "no template" (empty), matching the resolver's deleted-template degrade. Impl in layoutregistry_assignments.cpp.
| QVector< Layout * > PhosphorZones::LayoutRegistry::builtInLayouts | ( | ) | const |
| void PhosphorZones::LayoutRegistry::clearAssignment | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) |
| void PhosphorZones::LayoutRegistry::clearAutotileAssignments | ( | ) |
Flip mode to Snapping for every entry currently in Autotile (preserves snappingLayout + tilingAlgorithm + scrollingTemplateLayout) and CLEAR the autotile quick-layout slots.
Emits layoutAssigned per affected screen; one save at end. The quick-slot wipe is intentional and one-way: it is persisted with the save and restoreAutotileAssignments cannot bring it back.
|
inline |
The colour-scheme token from m_colorSchemeProvider ("light" / "dark"), or an empty string when the provider is unset or returns nullopt.
Shared by the query stamp and the cache-key fold, the same one-read discipline as screenOrientationToken.
PROVIDER-DEPENDENT, and only the daemon wires one: in the settings and editor processes this reads back EMPTY, so a ColorScheme Equals "dark" leaf never matches there while a negated none{ColorScheme Equals "dark"} matches everything. A preview rendered in those processes can therefore disagree with what the daemon resolves. Wire a provider in any process that must agree with the daemon's verdict.
| QHash< CombinedAssignmentKey, AssignmentEntry > PhosphorZones::LayoutRegistry::combinedAssignments | ( | ) | const |
Strict Combined-context reader.
See setAllCombinedAssignments for the round-trip contract. Returns ONLY rules with all three dimensions pinned (screen + desktop + activity).
|
inlinestatic |
Compose the extra cache-key token a daemon-facing context resolver (gap / lock / overlay / default-assignment / osd / drag-selector) passes to resolveCachedContext, folding in the placement modeToken (empty for every resolver but the gap one), the activeLayoutId, the orientationToken and the colorSchemeToken.
All three of the active layout, the screen orientation and the colour scheme are NON-rule-set inputs — each can change without a rule-set revision bump (the layout via the external global-default provider, the orientation via a live monitor rotation, the scheme via a palette switch) — so, exactly like the tiledWindowCount "twc:" token, they must ride the cache KEY rather than the value, or the change would return a stale hit. See resolveCachedContext.
|
inline |
Current entry count in the resolveAssignmentEntry hot-path cache.
Used by tests to verify the cache populates and invalidates against rule-set revision bumps. Not for production callers — the value drifts as cursor-move resolves come in. Return type is int because the cache is bounded at 256 entries (kMaxEntries in the shared resolveCachedContext template below), well within int range — keeps test assertions free of the qsizetype int widening dance.
| void PhosphorZones::LayoutRegistry::createBuiltInLayouts | ( | ) |
|
inlineoverridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
|
inlineoverridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
|
inlineoverridevirtual |
This screen's current virtual desktop, resolved through the injected provider (the daemon wires it to the VirtualDesktopManager — ONE authority, no push-updated mirror to lag) and falling back to the global m_currentVirtualDesktop when no provider is installed (KCM/editor-hosted registries) or the provider has no answer (#648).
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
| void PhosphorZones::LayoutRegistry::cycleToNextLayout | ( | const QString & | screenId | ) |
| void PhosphorZones::LayoutRegistry::cycleToPreviousLayout | ( | const QString & | screenId | ) |
|
overridevirtual |
Resolve the effective default layout.
Returns, in order:
defaultOrder)."autotile:<algo>" id from the level-1 cascade. Implements PhosphorZones::IZoneLayoutRegistry.
| QHash< QPair< QString, int >, AssignmentEntry > PhosphorZones::LayoutRegistry::desktopAssignments | ( | ) | const |
The three projection readers return the FULL AssignmentEntry per context (mode + all three payload fields), so consumers see the scrolling template beside the activeLayoutId() the batch setters round-trip on.
The setters stay id-string-keyed: the template travels through assignScrollingTemplate / setScrollingTemplateLayout, and the batch rebuild preserves it from the stored entry.
| source | Borrowed - caller retains ownership. |
addLayout semantics). Returns nullptr if source is unknown. Implements PhosphorZones::IZoneLayoutRegistry.
|
inlinestatic |
The literal suffix duplicateLayout appends to the source layout's name.
Public so callers that post-process a duplicate's name (e.g. a boundary clamp that must trim the base while keeping the suffix intact) reference the same string instead of duplicating the literal.
|
inlinestatic |
Make a cache-key component unambiguous under concatenation.
The key formats above join their parts with a literal '|', so a component that itself contains one would let two different (layout, orientation, scheme) tuples compose the SAME key and share a cached verdict. Layout ids are normally braced UUIDs and orientation / scheme tokens are fixed words, so this is latent rather than live — but the "scrolling:<uuid>" and "autotile:<algorithmId>" prefixed forms carry an algorithm id that is only as constrained as the algorithm that supplied it. Escaping '' first, then '|', keeps the mapping injective.
| bool PhosphorZones::LayoutRegistry::exactContextDeclaresEngineMode | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity | ||
| ) | const |
Whether the exact-context rule for this tuple DECLARES an engine mode, rather than merely being defaulted into one.
Needed because exactContextEntry cannot express "no mode stated": it decodes through entryFromRuleMatchActions, which starts every entry at Snapping, so a layout-only pin (a SetSnappingLayout or SetScrollingTemplate with no SetEngineMode — a shape the exact-context lookup deliberately admits) is indistinguishable from one that chose Snapping. A readback that publishes the entry's mode as stored state must ask this first, or it asserts a choice the user never made. Enabled-blind, like its two siblings.
| AssignmentEntry PhosphorZones::LayoutRegistry::exactContextEntry | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity | ||
| ) | const |
The EXPLICIT assignment entry pinned by this exact context tuple's rule, or a default entry when none exists.
Unlike the cascade resolvers this never falls back to wider scopes or defaults — it is the UI's explicit-vs-resolved discriminator (the Monitors page must not re-pin a cascade default as explicit when carrying sibling-mode fields through a mode toggle). Like hasExplicitAssignment it is blind to the rule's enabled flag; see its definition comment.
| bool PhosphorZones::LayoutRegistry::exportLayout | ( | Layout * | layout, |
| const QString & | filePath | ||
| ) |
Write layout to filePath as a standalone layout document.
Returns false when the destination cannot be opened, written or committed. Failures report through the return value for the same file-picker reason as importLayout(). The write is atomic, so a failure leaves whatever was already at the destination untouched.
| bool PhosphorZones::LayoutRegistry::hasExplicitAssignment | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) | const |
True iff a context-assignment rule whose match is exactly this (screen, desktop, activity) tuple's shape exists in the rule set — regardless of the rule's enabled state.
A DISABLED explicit assignment is still an explicit assignment: this reports stored intent, not the effective cascade result. It therefore intentionally diverges from assignmentEntryForScreen / the resolvers, which skip disabled rules and fall through to the gated default for a context whose only rule is disabled.
| Layout * PhosphorZones::LayoutRegistry::importLayout | ( | const QString & | filePath | ) |
Load a layout from filePath and add it to the registry.
Returns the imported layout, so callers can name what was imported without guessing at registry order. Returns nullptr when the file is missing, unreadable, empty, not JSON, fails schema validation, or does not parse into a layout. The reason is logged. Failures report through the return value rather than a signal because the D-Bus caller answers a user who is waiting on the result of a file picker, and every one of these branches used to be a silent early return.
|
overridevirtual |
True iff the context has NO active layout specifically because the default assignment is suppressed — globally (see setDefaultAssignmentSuppressedProvider) or by a per-context DefaultLayoutAssignment rule.
Returns false when an active layout exists (an explicit assignment, or a default forced through by an "allow" rule), AND false for OTHER empty-assignment states (e.g. snapping enabled with no global default layout id, where callers still fall back to defaultLayout). This lets daemon overlay / display paths — which otherwise fall back to defaultLayout on a missing assignment — treat a suppressed context as "no layout, engine inactive" without regressing the no-global-default case. Mode-agnostic: a suppressed context has no layout for either engine.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
| bool PhosphorZones::LayoutRegistry::isDefaultAssignmentSuppressedForContext | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) | const |
True iff the SYNTHESIZED default (the level-1 provider layout / autotile algorithm) is suppressed for this context — a per-context DefaultLayoutAssignment override decides locally (suppress → true, allow → false), otherwise the global suppress setting.
Unlike isContextActiveLayoutSuppressed this does NOT consider whether a mode-only assignment rule covers the context: such a rule sets the mode but still draws its layout / algorithm from the default. The autotile activation path uses this to refuse to tile a bare "autotile:" context (mode set, no concrete algorithm) with the global default algorithm when the default is suppressed — a concrete assigned algorithm is explicit and always tiles.
|
static |
Validate json against the bundled layout schema — the single gate every untrusted layout document passes before it reaches Layout::fromJson.
Returns false when the document is not a well-formed layout, logging context (a file path, or a name for the ingress) followed by a per-error diagnostic.
Static, and public so ingresses outside this library — the D-Bus layout surface — apply the identical gate the file ingresses do. Without it an out-of-range value (a zero-width zone, say) is accepted and persisted, then refused by this same schema on the next startup, and the layout disappears with no user-visible cause. The schema is compiled once process-wide and validation reads only it, so this holds no registry state and is safe to call from anywhere.
|
overridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
|
overridevirtual |
Resolve a layout by its stable UUID.
Returns nullptr when no layout with that id is known to the registry.
Implements PhosphorZones::IZoneLayoutRegistry.
|
overridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
|
inlineoverridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
|
inline |
|
signal |
|
overridevirtual |
Cascade-resolve the manual layout for screenId.
Returns defaultLayout() when no explicit assignment matches.
Implements PhosphorZones::IZoneLayoutRegistry.
| Layout * PhosphorZones::LayoutRegistry::layoutForShortcut | ( | AssignmentEntry::Mode | mode, |
| int | number | ||
| ) | const |
|
inlineoverridevirtual |
Enumerate every known layout.
Borrowed pointers - owned by the concrete registry (typically LayoutManager). Order is the registry's natural iteration order.
Implements PhosphorZones::IZoneLayoutRegistry.
|
signal |
|
signal |
|
signal |
| void PhosphorZones::LayoutRegistry::loadAssignments | ( | ) |
|
overridevirtual |
Per-algorithm autotile settings (gaps, shader, hiddenFromSelector, …) stored in the unified layout-settings.json sidecar, keyed by raw algorithm id.
Default returns empty so non-persisting implementers and the unified-list builder degrade to "no overrides". Concrete registries (LayoutRegistry) read the sidecar.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
| void PhosphorZones::LayoutRegistry::loadLayouts | ( | ) |
| AssignmentEntry::Mode PhosphorZones::LayoutRegistry::modeForScreen | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) | const |
|
inline |
Get the previous active layout (before the most recent setActiveLayout).
On first call, equals activeLayout. Used by resnap-to-new-layout.
| bool PhosphorZones::LayoutRegistry::purgeLayoutIdFromAssignments | ( | const QString & | layoutId | ) |
Drop id from every assignment rule's SetSnappingLayout and SetScrollingTemplate actions, and from every quick-slot array — the id-keyed scrub BOTH deletion flows drive: layout deletion (removeLayout calls it) and native template deletion (the D-Bus delete verb calls it; the two id namespaces are disjoint UUID sets, so one walk is exact for both).
A rule that still carries meaningful intent (an Autotile engine-mode, a preserved tilingAlgorithm, or the other surviving layout slot) is rebuilt with only the referencing slots cleared — the mode + remaining intent survives, preserving mode-toggle losslessness. A rule left with nothing but a default (Snapping) engine-mode and no payload is dropped entirely. The quick-slot sweep spans all three mode arrays (disjoint id namespaces again) and rewrites quicklayouts.json when it removes anything. Returns true if the rule set or any quick slot changed.
|
inline |
|
overridevirtual |
| layout | Borrowed - caller hands the pointer in; the registry un-registers it and schedules deletion via deleteLater (matching how the registry adopted it in addLayout). Callers must drop any other references before this call returns. |
true when the layout was removed. false when the removal was REFUSED and the layout is still registered: the implementation keeps the layout, its file and its settings sidecar mutually consistent rather than deleting a half of them, so a caller that announces the deletion (a layoutRemoved-style signal, an eviction of per-layout state) must gate that announcement on this result. Implements PhosphorZones::IZoneLayoutRegistry.
|
overridevirtual |
| layout | Borrowed - caller hands the pointer in; the registry un-registers it and schedules deletion via deleteLater (matching how the registry adopted it in addLayout). Callers must drop any other references before this call returns. |
true when the layout was removed. false when the removal was REFUSED and the layout is still registered: the implementation keeps the layout, its file and its settings sidecar mutually consistent rather than deleting a half of them, so a caller that announces the deletion (a layoutRemoved-style signal, an eviction of per-layout state) must gate that announcement on this result. Also returns false when no layout carries id. Implements PhosphorZones::IZoneLayoutRegistry.
| std::optional< bool > PhosphorZones::LayoutRegistry::resolveContextDefaultAssignment | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity | ||
| ) | const |
Resolve a per-context override of the global default-layout-assignment baseline for the (screen, desktop, activity) context by evaluating a windowless WindowQuery and reading the ActionSlot::DefaultAssignment slot.
Per-slot read (mirrors resolveContextLocked): returns the winning DefaultLayoutAssignment action's boolean value (true = allow / force the default through, false = suppress), or std::nullopt when no matching rule fills the slot (the context then follows the global setting). Same owner-thread affinity as the rest of the registry.
|
overridevirtual |
Resolve a per-context override of the drag selector popup — the edge-triggered zone / strip picker offered during a window drag — for the (screen, desktop, activity) context by evaluating a windowless WindowQuery and reading the ActionSlot::DragSelectorEnabled slot.
Per-slot read, the exact twin of resolveContextOsdEnabled (including the activeLayout + orientation stamping, and the same absence of a recursion hazard). One deliberate asymmetry: this one is an IZoneLayoutRegistry virtual (its consumer, the drag adaptor via OverlayService, holds the interface) while the OSD twin is concrete-only (its sole consumer holds the concrete registry) — so a stub registry can suppress the drag selector but not OSDs. Returns the winning SetDragSelectorEnabled action's boolean value (true = force the popup on past the global selector toggle, false = suppress it), or std::nullopt when no matching rule fills the slot (the context then follows the global toggle). Same owner-thread affinity as the rest of the registry.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
|
overridevirtual |
Resolve the per-context gap override for (screen, desktop, activity) by evaluating a windowless WindowQuery through the RuleEvaluator and reading the gap action slots (InnerGap / OuterGap / UsePerSideOuterGap / per-side).
Unlike resolveAssignmentEntry this is a PER-SLOT read across all matching context rules (not a single winning rule), so independent gap rules compose and there is no engine-mode gate. Returns an all-unset ContextGapOverride when no matching rule fills a gap slot. Same owner-thread affinity as the rest of the registry. An EMPTY mode is a supported caller shape meaning "mode-agnostic". It is not the same as a mode that happens to be empty: the resolver structurally excludes Field::Mode in that case, so neither a positive Mode Equals x nor a negated None{Mode Equals x} rule participates. Without that exclusion the negated form would match every context.
The exclusion is a WHOLE-TREE test, so it also drops a rule that merely mentions Mode in an unrelated branch — Any{Mode Equals "tiling", ScreenId Equals "DP-1"} is invisible to a mode-agnostic call even though its ScreenId branch would legitimately match. Deliberate: it fails safe (a rule goes unapplied) rather than open (a negated rule fires everywhere), and a per-branch test cannot be done without evaluating the tree, which is the thing being avoided. The same applies to the assignment / lock / overlay / default-assignment / osd / drag-selector resolvers, which are unconditionally mode-agnostic.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
|
overridevirtual |
Resolve whether a context rule locks the active layout for the (screen, desktop, activity) context by evaluating a windowless WindowQuery through the RuleEvaluator and reading the ActionSlot::Locked slot.
Mode-agnostic per-slot read (mirrors resolveContextGaps); returns true iff the winning Locked-slot action's value is true. Same owner-thread affinity as the rest of the registry.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
| std::optional< bool > PhosphorZones::LayoutRegistry::resolveContextOsdEnabled | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity | ||
| ) | const |
Resolve a per-context override of the OSD toggles for the (screen, desktop, activity) context by evaluating a windowless WindowQuery and reading the ActionSlot::OsdEnabled slot.
Per-slot read (mirrors resolveContextLocked, including the activeLayout + orientation stamping — OSD resolution never runs inside the assignment cascade, so there is no recursion hazard): returns the winning SetOsdEnabled action's boolean value (true = force OSDs on past the per-trigger toggles, false = suppress them), or std::nullopt when no matching rule fills the slot (the context then follows the global toggles). Same owner-thread affinity as the rest of the registry.
|
overridevirtual |
Resolve the per-context overlay-property override (shader / style) for (screen, desktop, activity) by evaluating a windowless WindowQuery and reading the OverlayShader / OverlayStyle slots.
Per-slot read (mirrors resolveContextGaps), so independent overlay rules compose; returns an all-unset ContextOverlayOverride when no matching rule fills an overlay slot. Same owner-thread affinity as the rest of the registry.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
| ContextScrollingParams PhosphorZones::LayoutRegistry::resolveContextScrollingParams | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity | ||
| ) | const |
Resolve the per-context scrolling parameter overrides (default column width / focused-column centering / default column display) for (screen, desktop, activity) — a per-slot read like resolveContextTilingParams, and uncached for the same reason (screen / layout changes, not the hot per-cursor path).
The daemon layers the returned values onto the scrolling engine's per-screen parameters, with config as the base. Concrete (not on the interface): the daemon holds a concrete LayoutRegistry.
| ContextTilingParams PhosphorZones::LayoutRegistry::resolveContextTilingParams | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity | ||
| ) | const |
Resolve the per-context autotile parameter overrides (max windows / split ratio / master count) for (screen, desktop, activity) — a per-slot read like resolveContextGaps.
The daemon layers the returned values onto the per-screen autotile override map (config stays the base; the rule wins where present). NOT cached: called on screen / layout changes, not the hot per-cursor path — which also lets it stamp the active layout onto the query without a cache-key fold (there is no cache entry to go stale). Concrete (not on the interface): the daemon holds a concrete LayoutRegistry.
|
inlineoverridevirtual |
Resolve layout for screenId using the current desktop/activity context.
layoutForScreen already falls back to defaultLayout internally when no explicit assignment matches, so this helper is a thin context-filling forwarder.
Implements PhosphorZones::IZoneLayoutRegistry.
| int PhosphorZones::LayoutRegistry::restoreAutotileAssignments | ( | ) |
Reverse direction of clearAutotileAssignments FOR THE ASSIGNMENT RULES ONLY (the wiped quick-layout slots are NOT restored): flip mode back to Autotile for every context-assignment entry sitting in Snapping while still carrying a tilingAlgorithm; preserves snappingLayout, advisory null-layout layoutAssigned per affected screen, one save at end.
Needed because the disable is global across every desktop/activity while the daemon's re-enable writes only the current desktop per screen. The carried tilingAlgorithm is the only discriminator and survives a manual switch back to Snapping just as it survives the disable, so this revives every context that has ever run autotile, hand-switched ones included (see layoutregistry_batch.cpp).
| QString PhosphorZones::LayoutRegistry::rulesVisibleActiveLayoutId | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity | ||
| ) | const |
The RULES-VISIBLE ActiveLayout value the context resolvers stamp onto their windowless queries: the assignment id, except that a Scrolling context with a resolved template substitutes the PREFIXED "scrolling:<templateUuid>" (LayoutId::makeScrollingId) — parity with autotile's "autotile:<algorithmId>" stamp, so a rule can target one template.
Assignment ids on every other surface stay the bare sentinel. Public so the daemon can push the same value to the effect for window-domain (appearance/animation) rule queries — both rule pipelines must see one ActiveLayout vocabulary. Impl in layoutregistry_contextresolve.cpp.
| void PhosphorZones::LayoutRegistry::saveAssignments | ( | ) |
| void PhosphorZones::LayoutRegistry::saveAutotileOverrides | ( | const QString & | algorithmId, |
| const QJsonObject & | overrides | ||
| ) |
| void PhosphorZones::LayoutRegistry::saveLayout | ( | Layout * | layout | ) |
| void PhosphorZones::LayoutRegistry::saveLayouts | ( | ) |
|
inline |
The screen-orientation token from m_screenOrientationProvider ("portrait" / "landscape"), or an empty string when the provider is unset or returns nullopt.
Shared by stampScreenOrientation (the query value) and the cache-key fold (see contextCacheKeyToken) so both read the same source.
|
overridevirtual |
Mode-gated like scrollingTemplateForContext rather than like the raw getter above: a token preserved on a context that has since been switched to another engine is dormant data, and highlighting the picker's None card for it would describe a choice the screen is not currently making.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
|
overridevirtual |
The resolved ScrollingTemplate for a scrolling context, by value — invalid when the cascade has no Scrolling entry, the entry names no template and the default-template provider answers nothing, or the named template no longer exists in the store (deleted-template fallback: "no template").
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
| QString PhosphorZones::LayoutRegistry::scrollingTemplateLayoutForScreen | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) | const |
Raw template-field sibling of the two getters above: NOT mode-gated, so a dormant template preserved on a non-Scrolling context (the lossless-toggle contract) reads back.
The mode-gated scrollingTemplateForContext is the resolver the engine push and picker use; this is the field-inspection twin, parity with snappingLayoutForScreen returning a preserved layout in autotile mode.
|
inlineoverridevirtual |
The native scrolling-template store wired into this registry, or null when none is (lightweight stubs, roots with no template feature).
Consumers use it for template enumeration (picker lists); context RESOLUTION goes through scrollingTemplateForContext below.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
| void PhosphorZones::LayoutRegistry::seedDefaultLayoutSettingsIfFresh | ( | const QJsonObject & | defaults | ) |
Seed curated default picker visibility into the sidecar, but ONLY on a fresh install — when neither layout-settings.json nor the legacy autotile-overrides.json exists.
defaults is keyed exactly as the sidecar (manual layouts by UUID, algorithms by "autotile:<id>"). Existing installs are never reseeded. Call before loadLayouts so the merge picks up the seeded entries.
|
overridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
|
overridevirtual |
Implements PhosphorZones::IZoneLayoutRegistry.
| void PhosphorZones::LayoutRegistry::setAllActivityAssignments | ( | const QHash< QPair< QString, QString >, QString > & | assignments | ) |
| void PhosphorZones::LayoutRegistry::setAllCombinedAssignments | ( | const QHash< CombinedAssignmentKey, QString > & | assignments | ) |
Combined-context (screen + desktop + activity) batch setter — the triple-axis sibling of the Activity / Desktop batches.
Combined rules cannot round-trip through setAllActivityAssignments (the (screen, activity) key drops the desktop dimension); this API keeps them as first-class. Pure-Activity, pure-Desktop, and Monitor-only rules are NOT touched — they remain in their own batches.
| void PhosphorZones::LayoutRegistry::setAllDesktopAssignments | ( | const QHash< QPair< QString, int >, QString > & | assignments | ) |
| void PhosphorZones::LayoutRegistry::setAllQuickLayoutSlots | ( | AssignmentEntry::Mode | mode, |
| const QHash< int, QString > & | slots | ||
| ) |
| void PhosphorZones::LayoutRegistry::setAllScreenAssignments | ( | const QHash< QString, QString > & | assignments | ) |
Batch setters - clear existing, set new, save once at end.
| void PhosphorZones::LayoutRegistry::setAssignmentEntryDirect | ( | const QString & | screenId, |
| int | virtualDesktop, | ||
| const QString & | activity, | ||
| const AssignmentEntry & | entry | ||
| ) |
Store a full entry directly (from KCM via D-Bus).
Stores regardless of isValid() - mode-only entries are valid when explicitly set.
| void PhosphorZones::LayoutRegistry::setColorSchemeProvider | ( | std::function< std::optional< QString >()> | provider | ) |
Inject a callback that reports the system colour scheme ("light" / "dark"), or std::nullopt when it is unknown (so a colour-scheme predicate stays inert).
Session-wide, not per-screen — the scheme is one value for the whole desktop, so the provider takes no arguments. The token is stamped onto every windowless context WindowQuery this registry builds AND folded into every cached resolver's key (see contextCacheKeyToken): a scheme flip is a non-rule-set input, exactly like a monitor rotation, so key-based invalidation is what keeps cached verdicts honest across it. Scheme derives from the application palette alone, independent of the resolved layout, so it carries no recursion risk and is stamped in the assignment cascade too. The daemon wires this to a palette read. Same threading contract as setScreenOrientationProvider.
|
inline |
|
inline |
|
inline |
Inject the per-screen desktop resolver above.
Same pattern and main-thread contract as setScreenOrientationProvider; the daemon installs it at service init and clears it before teardown.
| void PhosphorZones::LayoutRegistry::setDefaultAssignmentSuppressedProvider | ( | std::function< bool()> | provider | ) |
Inject a callback that returns true when the user has opted to suppress the synthesized level-1 default layout assignment globally.
When the callback returns true, resolveDefaultAssignmentEntry yields a default-constructed (invalid) entry on cascade-miss instead of synthesizing one from the snap / autotile / snapping-preferred providers — i.e. a context with no explicit assignment gets NO active layout and no engine activates until the user assigns one. This is the same effective state as a system with every provider returning empty, so the daemon's existing "empty entry ⇒ no default" handling covers it unchanged.
The global baseline is overridable PER CONTEXT by a DefaultLayoutAssignment rule (see resolveContextDefaultAssignment): a false rule suppresses a single context even when this provider is off, a true rule forces the default through even when this provider is on.
Optional. When unset, the resolver behaves as before (never suppresses). Same threading rules as the other providers.
| void PhosphorZones::LayoutRegistry::setDefaultAutotileAlgorithmProvider | ( | std::function< QString()> | provider | ) |
Inject a callback that returns the user-configured default autotile algorithm id (or empty if autotile is not the user's active default).
Symmetric to setDefaultLayoutIdProvider, completing the level-1 (global) tier of the assignment hierarchy:
On cascade-miss, assignmentIdForScreen and assignmentEntryForScreen consult the snap provider first, then the autotile provider; the first non-empty return wins. Providers are pass-throughs from the composition root's settings layer - each is expected to return empty when its mode is disabled in settings, which means "autotile-only" users see autotile as the natural cascade fallback (snap provider returns empty → autotile wins) without any mode-priority logic in the composition root. layoutForScreen ignores the autotile provider (it returns a snap Layout*, which has no autotile counterpart) and falls back to defaultLayout as before.
Invoked on every cascade-miss with no caching, so providers can re-read settings cheaply per call. Pass an empty function to disable.
Thread-safety: the provider is read on every cascade query and swapped via this setter without synchronization; both must run on the same thread (the LayoutRegistry's owner thread, typically the main Qt thread). The same applies to setDefaultLayoutIdProvider.
| void PhosphorZones::LayoutRegistry::setDefaultLayoutIdProvider | ( | std::function< QString()> | provider | ) |
Inject a callback that returns the user-configured default layout id (or empty if unset).
Used by composition roots that own a settings object the lib doesn't know about. The registry invokes the callback on every defaultLayout call (no caching) so the callback can re-read settings on each call. Pass an empty function to disable.
|
inline |
Provider for the DEFAULT scrolling template id (a config setting the daemon owns): consulted when a Scrolling context's cascade entry names no template.
Same injected-provider pattern as the screen orientation provider; registries without one (settings/KCM local views) simply resolve no default.
| void PhosphorZones::LayoutRegistry::setLayoutDirectory | ( | const QString & | directory | ) |
| void PhosphorZones::LayoutRegistry::setQuickLayoutSlot | ( | AssignmentEntry::Mode | mode, |
| int | number, | ||
| const QString & | layoutId | ||
| ) |
| void PhosphorZones::LayoutRegistry::setScreenOrientationProvider | ( | std::function< std::optional< QString >(const QString &screenId)> | provider | ) |
Inject a callback that returns a screen's orientation token ("portrait" / "landscape"), or std::nullopt when the geometry is unknown (so an orientation predicate stays inert there).
The token is stamped onto every windowless context WindowQuery this registry builds (assignment, gap, lock, overlay, default-assignment, osd, drag-selector, tiling-params, scrolling-params), so an orientation rule can drive any context slot — for example a different tiling algorithm on a rotated (portrait) monitor. Orientation derives from screen geometry alone, independent of the resolved layout, so it carries no recursion risk (unlike an active-layout query). The daemon wires this to ScreenManager::screenGeometry. Same threading contract as setTiledWindowCountProvider.
|
inline |
Wire the native template store (borrowed, post-construction like the other injected collaborators; pass nullptr on teardown).
Without a store every template resolve answers "no template".
| void PhosphorZones::LayoutRegistry::setSnappingPreferredProvider | ( | std::function< bool()> | provider | ) |
Inject a callback that returns true when Snapping is the user's preferred default mode (regardless of whether a default snapping layout id is configured).
Without this provider, resolveDefaultAssignmentEntry can only tell whether snap has a non-empty default layout id. When a user has snapping enabled but never configured a global default layout (a common, valid state - the user expects per-screen assignments to drive everything), the m_defaultLayoutIdProvider returns empty and the cascade silently falls through to the autotile branch - surfacing autotile content (e.g. "Tiling: Binary Split") to a user who never wanted autotile.
This provider lets the composition root express "snap mode is
preferred" independently of "snap has a default layout". When it returns true, the resolver returns a Snapping entry with the (possibly empty) snappingLayout from m_defaultLayoutIdProvider - activeLayoutId() then yields empty, callers see "no assignment", and the OSD path correctly suppresses rather than falling back to autotile.
Optional. When unset, the resolver behaves as before (snap-id-non-empty → snap; else autotile if available; else empty). Same threading rules as the other two providers.
| void PhosphorZones::LayoutRegistry::setTiledWindowCountProvider | ( | std::function< std::optional< int >(const QString &screenId, int virtualDesktop, const QString &activity)> | provider | ) |
Inject a callback that returns the tiled-window count for a screen, or std::nullopt when the screen is not actively tiling (so a count predicate stays inert there).
The count is fed into the windowless WindowQuery built during resolveAssignmentEntry, letting a SetTilingAlgorithm rule match on Field::TiledWindowCount, for example to switch algorithm once a second window opens. The value also participates in that resolver's cache key, so a count change yields a distinct entry rather than a stale hit; the caller (the daemon) re-resolves and re-applies the per-screen algorithm when the count changes (on the engine's placementChanged).
The (virtualDesktop, activity) parameters identify the resolution context, but a provider may return the screen's CURRENT-context count when its backing engine only tracks the visible desktop. That is sound because the tiling-algorithm slot is only ever resolved for the screen's current context; a count predicate on a non-current (desktop, activity) is not a supported configuration. Returning nullopt for an unknown context is also valid (the predicate then stays inert).
Same threading contract as setDefaultAutotileAlgorithmProvider.
| QString PhosphorZones::LayoutRegistry::snappingLayoutForScreen | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) | const |
Per-field cascade readers — return the named field from the first entry in the cascade where it is non-empty.
Crucially, these do NOT route through the activeLayoutId-based reject filter that assignmentEntryForScreen uses, so a "stored-but-inactive" preference (e.g. an entry shaped like {mode=Snapping, snap="", tile="cluster"} that the partial-update path can produce) IS visible to the field-getter that targets the populated field. On total cascade miss they synthesize from the global default (snap provider for snap, autotile provider for tile) and may still return empty if no provider has a value.
| bool PhosphorZones::LayoutRegistry::snappingPreferred | ( | ) | const |
True when the snapping-preferred provider is wired AND reports true — i.e.
snapping is globally enabled (the consumer wires the provider to its global snapping-enabled setting). Mirrors the internal default-assignment branch's m_snappingPreferredProvider && m_snappingPreferredProvider() test, exposed so other engines can gate cross-engine coordination on the global snap toggle. When unset, returns false (no provider ⇒ not preferred).
|
inline |
Stamp the colour-scheme token onto query from m_colorSchemeProvider (a no-op when unset).
Used by the two UNCACHED param resolvers; the cached resolvers assign colorSchemeToken directly for the same key-vs-query consistency reason stampScreenOrientation documents. Palette-derived and layout-independent, so safe from the assignment cascade.
|
inline |
Stamp the screen-orientation token onto query from m_screenOrientationProvider (a no-op when the provider is unset or returns nullopt).
Used by the two UNCACHED param resolvers (tiling-params, scrolling-params); the seven cached resolvers (assignment, gap, lock, default-assignment, osd, drag-selector, overlay) assign screenOrientationToken directly, because they must fold the very same token into their cache key and re-reading the provider could hand the query a token the key does not describe. Either way every windowless-context query carries the token, so a Field::ScreenOrientation predicate matches regardless of which context slot is being resolved. Orientation is geometry-derived and layout-independent, so this is safe to call from the assignment cascade (no recursion, unlike an active-layout read).
| QString PhosphorZones::LayoutRegistry::storedAssignmentIdForScreen | ( | const QString & | screenId, |
| int | virtualDesktop = 0, |
||
| const QString & | activity = QString() |
||
| ) | const |
Like assignmentIdForScreen, but WITHOUT the level-1 global default fallback: resolves the same per-context cascade (including the connector-name / virtual-screen retries) and returns empty on a cascade miss instead of synthesizing an id from the default providers.
Answers "does this context have a layout of its OWN" — a rule-based assignment counts, the registry-wide default does not. The editor's screen switcher uses this to offer a fresh layout for a screen that has never been assigned one, rather than opening the default layout for in-place editing (discussion #858).
|
overridevirtual |
Raw id of the tiling algorithm active for the (screenId, virtualDesktop, activity) context, or empty when none resolves.
Used by the unified-list builder to keep the active algorithm visible in the picker even when it's been hidden (mirrors the active-layout exemption for manual layouts). Default empty for non-resolving implementers.
Reimplemented from PhosphorZones::IZoneLayoutRegistry.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
quicklayouts.json top-level keys: one nested slot object per slot ARRAY ("snapping", "autotile", "scrolling").
This is the ONLY on-disk shape — there is no flat legacy variant. Shared with a consumer's v3→v4 schema migration, which writes the same nested format, so reader and migration cannot drift.