Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
phosphor-overlay

‍Per-screen layer-shell shell hosts, slot vocabulary, and animator-config wiring for multi-slot overlays.

Responsibility

Helper layer on top of `phosphor-layer`, `phosphor-surfaces`, and `phosphor-animation`. Given a consumer-provided surface factory, ShellHost owns the per-screen layer-shell shell lifecycle (create / destroy / rekey), the slot map keyed by consumer-chosen slot names, animator-driven slot hides, and per-role animator-config registration. The library knows nothing about zones, layouts, or specific content. Consumers wire their slot vocabulary through callbacks.

Key types

Type Purpose
PhosphorOverlay::ShellHost Owns the per-screen ShellState map, lifecycle methods, animator wiring.
PhosphorOverlay::ShellState Per-screen mechanism state: layer-shell surface, QQuickWindow, physical screen, slot map.
PhosphorOverlay::SlotEntry One slot entry: QPointer<QQuickItem> item + PhosphorLayer::Role role.
PhosphorOverlay::makePerInstanceRole() Build a per-instance Role by appending -{screenId}-{generation} to a base scope prefix.

Typical use

using namespace PhosphorOverlay;

ShellHost host;
host.setSurfaceAnimator(&animator);                          // from phosphor-animation

host.setSurfaceFactory([&](const QString& sid, QScreen* s) {
    const auto role = makePerInstanceRole(MyShellBaseRole, sid, mgr.nextScopeGeneration());
    return mgr.createSurface(/* role, qml url, screen, ... */);
});

host.setPostCreateCallback([&](const QString& sid, ShellState& state) {
    // Look up content slot Items by their QML object names, wire QML
    // signals, prime the RHI pipeline. Insert one SlotEntry per slot:
    auto* item = qvariant_cast<QQuickItem*>(state.shellWindow()->property("osdSlotItem"));
    state.slots.insert(QStringLiteral("osd"), SlotEntry{item, MyOsdRole});
});

host.setPreDestroyCallback([&](const QString& sid) {
    // Drop any parallel consumer-side per-screen state so a stale signal
    // firing during teardown doesn't dereference a dangling pointer.
});

// Lifecycle:
host.registerConfigForRole(MyOsdRole, buildOsdConfig());
host.ensureShell(screenId, physScreen);
host.syncSurfaceState(screenId, /*anyVisible=*/true, /*anyInputGrabbing=*/false);
host.hideSlot(screenId, QStringLiteral("osd"), [&]{ /* on hide-leg settle */ });
host.destroyShell(screenId);

Design notes

  • Stable pointers via raw owning pointers. ShellState entries are heap-allocated, and the host stores QHash<QString, ShellState*>. Consumers cache the ShellState* returned by ensureShell / stateFor in parallel per-screen state and rely on the pointer staying valid across rehashes. QHash<QString, std::unique_ptr<ShellState>> would move the pointee but still rehash the bucket array, so consumer-cached references are stable only by the indirection. std::shared_ptr would add refcount overhead the lib does not need (there is one owner, the host, plus any number of borrowed observers). ShellState is non-copyable / non-movable to prevent accidental auto copy = host.stateFor(id) (note the missing &) from shallow-cloning the mechanism pointers and slot map.
  • Callback-driven content boundary. Three function-object hooks (SurfaceFactory, PostCreateCallback, PreDestroyCallback) carry every consumer-specific decision: which role / qmlSource the surface uses, which slot QML object names to look up, which signal handlers to wire, which parallel content state to clear at teardown. The library owns surface lifecycle, and the consumer owns content.
  • Slot role pinned at wire time. Each SlotEntry carries the PhosphorLayer::Role the slot animates as, so hideSlot can drive SurfaceAnimator::beginHide without the caller re-specifying the role at every dismiss / cancel call site.
  • **syncSurfaceState is mechanism-only.** Consumers compute anyVisible and anyInputGrabbing from their content slot visibility (e.g. modal vs non-modal classification), and the library decides surface mapping + Qt::WindowTransparentForInput toggling.
  • Sticky per-screen creation failure. When the surface factory returns nullptr for a screen, the host flags it. Subsequent ensureShell calls short-circuit until clearFailure(screenId) is called, typically on hot-plug. failureScreenIds() exposes the current set so consumers with their own id grammar (e.g. virtual- screen prefixes) can clear by prefix without the library learning the grammar.

Dependencies

See also