Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
PhosphorCompositor::DecorationManager Class Reference

The single owner of server-side decoration (title-bar) state. More...

#include <phosphor-compositor/include/PhosphorCompositor/DecorationManager.h>

Inheritance diagram for PhosphorCompositor::DecorationManager:
[legend]

Classes

struct  Owner
 An owner is a (kind, screen) pair. More...
 

Public Types

enum class  OwnerKind { Autotile , Snap , Rule }
 
enum class  Placement { CallerWillPlace , AlreadyPlaced }
 How the physical hide coordinates with geometry application. More...
 
enum class  Restore { Immediate , Deferred }
 

Signals

void windowDecorationRestored (const QString &windowId)
 Emitted after a physical decoration restore (the effect refreshes border overlays for the window).
 
void drainFinished ()
 Emitted when a drain chain completes having processed at least one restore (the effect rebuilds all borders).
 

Public Member Functions

 DecorationManager (ICompositorBridge &bridge, QObject *parent=nullptr)
 bridge must outlive the manager (the KWin effect owns both, with the bridge destroyed after the manager).
 
 ~DecorationManager () override
 Breaks any in-flight drain chains' self-reference cycles — a chain interrupted by manager destruction would otherwise leak its heap closure (the queued QTimer continuations die with the QObject, so the chain's own cycle-break never runs).
 
void acquire (const QString &windowId, const Owner &owner, Placement placement=Placement::AlreadyPlaced)
 
void release (const QString &windowId, const Owner &owner, Restore restore=Restore::Immediate)
 
void releaseKind (const QString &windowId, OwnerKind kind, Restore restore=Restore::Immediate)
 Release every owner of kind regardless of screen (float, fullscreen, window leaving the mode entirely).
 
void releaseOthersOfKind (const QString &windowId, OwnerKind kind, const QString &keepScreenId)
 Cross-screen transfer: drop kind owners on every screen EXCEPT keepScreenId.
 
void releaseAllOfKind (OwnerKind kind, Restore restore=Restore::Immediate)
 Per-mode hide-title-bars toggle OFF / whole-mode teardown.
 
void restoreAll ()
 Daemon loss / effect teardown: synchronously restore every window we hid to its prior state, then drop all tracking, timers, and any in-flight drain chains.
 
void forgetWindow (const QString &windowId)
 Window destroyed: drop all state for it.
 
void setRuleOverride (const QString &windowId, std::optional< bool > ruleValue)
 nullopt: rule has no opinion — clear Rule owner and veto.
 
void clearAllRuleOverrides ()
 Rules went away wholesale (rule set emptied / teardown): clear every Rule owner and veto, restoring where no mode owner remains.
 
void drainPendingRestores ()
 Drain queued restores, one decoration toggle per event-loop tick.
 
void setFallbackIntervalForTesting (int ms)
 Test seam: shrink the fallback-retry interval (default 500 ms) so timer-interplay tests run in milliseconds.
 
void setRestoreVeto (std::function< bool(const QString &windowId)> veto)
 Extra authoritative re-check evaluated per window at drain-step time (in addition to the built-in "window has owners again" check).
 
void resyncWindow (const QString &windowId)
 The compositor can silently reset noBorder (KWin does on desktop switches).
 
bool isBorderless (const QString &windowId) const
 True when we physically suppressed the window's decoration.
 
bool isOwned (const QString &windowId) const
 
bool isOwnedBy (const QString &windowId, const Owner &owner) const
 
bool isVetoed (const QString &windowId) const
 

Static Public Member Functions

static Owner autotile (const QString &screenId)
 
static Owner snap (const QString &screenId)
 
static Owner rule ()
 

Detailed Description

The single owner of server-side decoration (title-bar) state.

Every component that wants a window's title bar hidden — autotile retiles, snap commits, window rules — registers as an OWNER here instead of calling setNoBorder() itself. The decoration is hidden while at least one owner holds the window (and no veto pins it visible) and restored to its prior state when the last owner releases. This replaces the per-mode borderless sets and the web of cross-mode "is the other mode still using it?" guards that historically caused title-bar oscillation.

Invariants this class centralizes (previously duplicated and divergent):

  • Capability gate: userCanSetNoBorder() — true for an SSD window even while it is CURRENTLY borderless (survives the autotile→snap handoff); false for CSD apps (GTK/Electron) and other non-toggleable windows, which are tracked as owned but never physically touched.
  • Prior-state capture: a window that was already borderless when first acquired (user's own compositor rule) is restored to borderless, never force-decorated.
  • Geometry preservation: the compositor holds the CLIENT size constant across a decoration change, so toggling the decoration on a placed window changes the frame height by the title-bar height. Hiding a placed window therefore captures moveResizeGeometry() — NOT frameGeometry(), which lags on Wayland until the client acks the configure — toggles, and re-asserts the target.
  • Deferred restore: decoration restores are synchronous Wayland round-trips (30–120 ms each); bulk restores (mode toggles) are queued and drained one per event-loop tick so concurrent animations stay smooth, with a fallback timer in case the drain trigger never fires. A window re-acquired while queued keeps its decoration hidden.

Member Enumeration Documentation

◆ OwnerKind

Enumerator
Autotile 
Snap 
Rule 

◆ Placement

How the physical hide coordinates with geometry application.

Enumerator
CallerWillPlace 

The caller applies the zone geometry immediately after acquire (autotile tile path: hide first, applyWindowGeometry supplies the frame).

The manager only toggles the decoration.

AlreadyPlaced 

The window is already at (or moving toward) its target: capture moveResizeGeometry() → setNoBorder(true) → re-assert the target so the content grows to fill the zone (snap path, settings toggles, rule changes).

◆ Restore

Enumerator
Immediate 

restore synchronously when the last owner releases

Deferred 

queue for drainPendingRestores() / the fallback timer

Constructor & Destructor Documentation

◆ DecorationManager()

PhosphorCompositor::DecorationManager::DecorationManager ( ICompositorBridge bridge,
QObject *  parent = nullptr 
)
explicit

bridge must outlive the manager (the KWin effect owns both, with the bridge destroyed after the manager).

Taken by reference so a null bridge is unrepresentable — no runtime guard needed on any call path.

◆ ~DecorationManager()

PhosphorCompositor::DecorationManager::~DecorationManager ( )
override

Breaks any in-flight drain chains' self-reference cycles — a chain interrupted by manager destruction would otherwise leak its heap closure (the queued QTimer continuations die with the QObject, so the chain's own cycle-break never runs).

Member Function Documentation

◆ acquire()

void PhosphorCompositor::DecorationManager::acquire ( const QString &  windowId,
const Owner owner,
Placement  placement = Placement::AlreadyPlaced 
)

◆ autotile()

static Owner PhosphorCompositor::DecorationManager::autotile ( const QString &  screenId)
inlinestatic

◆ clearAllRuleOverrides()

void PhosphorCompositor::DecorationManager::clearAllRuleOverrides ( )

Rules went away wholesale (rule set emptied / teardown): clear every Rule owner and veto, restoring where no mode owner remains.

◆ drainFinished

void PhosphorCompositor::DecorationManager::drainFinished ( )
signal

Emitted when a drain chain completes having processed at least one restore (the effect rebuilds all borders).

An all-vetoed chain — every queued restore re-queued for the fallback retry — emits nothing: zero decorations changed, so a rebuild would be pure churn.

◆ drainPendingRestores()

void PhosphorCompositor::DecorationManager::drainPendingRestores ( )

Drain queued restores, one decoration toggle per event-loop tick.

Cancels the fallback timer. Re-entrant safe (snapshot-and-clear).

◆ forgetWindow()

void PhosphorCompositor::DecorationManager::forgetWindow ( const QString &  windowId)

Window destroyed: drop all state for it.

Zero compositor calls — the decoration dies with the window.

◆ isBorderless()

bool PhosphorCompositor::DecorationManager::isBorderless ( const QString &  windowId) const

True when we physically suppressed the window's decoration.

◆ isOwned()

bool PhosphorCompositor::DecorationManager::isOwned ( const QString &  windowId) const

◆ isOwnedBy()

bool PhosphorCompositor::DecorationManager::isOwnedBy ( const QString &  windowId,
const Owner owner 
) const

◆ isVetoed()

bool PhosphorCompositor::DecorationManager::isVetoed ( const QString &  windowId) const

◆ release()

void PhosphorCompositor::DecorationManager::release ( const QString &  windowId,
const Owner owner,
Restore  restore = Restore::Immediate 
)

◆ releaseAllOfKind()

void PhosphorCompositor::DecorationManager::releaseAllOfKind ( OwnerKind  kind,
Restore  restore = Restore::Immediate 
)

Per-mode hide-title-bars toggle OFF / whole-mode teardown.

NOTE: there is deliberately no per-screen bulk release. Owners are per-screen but NOT per-desktop, and the mode-toggle path must apply desktop policy (sticky-window guards, current-desktop filters) per window before releasing — see AutotileHandler::slotScreensChanged.

◆ releaseKind()

void PhosphorCompositor::DecorationManager::releaseKind ( const QString &  windowId,
OwnerKind  kind,
Restore  restore = Restore::Immediate 
)

Release every owner of kind regardless of screen (float, fullscreen, window leaving the mode entirely).

◆ releaseOthersOfKind()

void PhosphorCompositor::DecorationManager::releaseOthersOfKind ( const QString &  windowId,
OwnerKind  kind,
const QString &  keepScreenId 
)

Cross-screen transfer: drop kind owners on every screen EXCEPT keepScreenId.

Never produces a physical toggle — even when the kept screen's owner is not registered yet (the caller acquires it next); the decoration deliberately stays hidden across the hop.

◆ restoreAll()

void PhosphorCompositor::DecorationManager::restoreAll ( )

Daemon loss / effect teardown: synchronously restore every window we hid to its prior state, then drop all tracking, timers, and any in-flight drain chains.

The installed restore veto deliberately survives: it is wired once at effect construction and stays valid for the next daemon session (the post-restoreAll queue is empty, so it is not consulted until new deferred releases arrive).

◆ resyncWindow()

void PhosphorCompositor::DecorationManager::resyncWindow ( const QString &  windowId)

The compositor can silently reset noBorder (KWin does on desktop switches).

If windowId should be hidden but the decoration came back, re-hide via the AlreadyPlaced sequence. No-op otherwise.

◆ rule()

static Owner PhosphorCompositor::DecorationManager::rule ( )
inlinestatic

◆ setFallbackIntervalForTesting()

void PhosphorCompositor::DecorationManager::setFallbackIntervalForTesting ( int  ms)

Test seam: shrink the fallback-retry interval (default 500 ms) so timer-interplay tests run in milliseconds.

Production never calls it. Negative values clamp to 0 (QTimer::start would warn on them). Restarts an already-running countdown with the new interval — the arm path deliberately never restarts an active timer (see armFallbackTimer), so ordering this call after a defer must apply the shrunk interval here.

◆ setRestoreVeto()

void PhosphorCompositor::DecorationManager::setRestoreVeto ( std::function< bool(const QString &windowId)>  veto)

Extra authoritative re-check evaluated per window at drain-step time (in addition to the built-in "window has owners again" check).

Returning true keeps the restore QUEUED (re-armed via the fallback timer) so a re-acquire that never lands still restores eventually — it must therefore only return true while a re-acquire is genuinely expected. The KWin effect installs "window's screen is autotiled, hide-title-bars is on, and the window is not floating". The predicate MUST NOT call back into the manager (it runs between an entry lookup and writes through that entry; a re-entrant mutation could rehash the table under the held iterator).

◆ setRuleOverride()

void PhosphorCompositor::DecorationManager::setRuleOverride ( const QString &  windowId,
std::optional< bool >  ruleValue 
)

nullopt: rule has no opinion — clear Rule owner and veto.

true: rule hides — acquire a Rule owner (clears any veto). false: rule force-shows — VETO. The veto wins over every owner and pins the decoration visible; owners re-assert when it lifts. Geometry is re-asserted across veto-driven toggles while the window has mode owners (it is zone-placed).

◆ snap()

static Owner PhosphorCompositor::DecorationManager::snap ( const QString &  screenId)
inlinestatic

◆ windowDecorationRestored

void PhosphorCompositor::DecorationManager::windowDecorationRestored ( const QString &  windowId)
signal

Emitted after a physical decoration restore (the effect refreshes border overlays for the window).

Slots may synchronously re-enter the manager — including destroying it or calling restoreAll() — every emit site guards its epilogue accordingly.


The documentation for this class was generated from the following file: