github fuddlesworth/PlasmaZones v3.0.0
PlasmaZones v3.0.0

latest release: v3.0.1
5 hours ago

PlasmaZones v3.0.0

Added

  • Virtual screens for ultrawide monitors: physical monitors can be subdivided into independent logical screens, each with its own layouts, autotile state, snap-assist, OSDs, shortcuts, and per-desktop or per-activity assignments. A new VirtualScreenSwapper exposes swap and rotate D-Bus methods plus global shortcuts, and a monitor-level OSD acknowledges the action so the user sees which regions moved. The layout editor and settings app are virtual-screen aware throughout, and the configuration UI moved from the editor into the settings app.
  • Animation App Rules: a new Animations → App Rules page assigns motion curves, shader overrides, and per-event timings to specific window classes. The resolver cascades through global, app-rule, and window-filter layers inside the kwin-effect, and the editor supports curve picking, shader-parameter overrides, lock and randomize controls, and window-class filtering with a Disable animations short-circuit. A two-layer resolver with leaf seeds gives widgets distinctive tunings even when they share a parent rule.
  • Unified PassiveOverlayShell: OSDs, snap-assist, the layout picker, the zone selector, and the main zone overlay now run inside one shell surface instead of five separate layer-shell windows. The shell is click-through except when a modal popup is up, hides itself when no slot is visible so clicks pass through, releases its input region after every slot show, and enforces explicit z-order. Slots animate independently, so a snap-assist show no longer cancels an in-flight OSD. Replaces the legacy NotificationOverlay.qml lifecycle.
  • Krohnkite-style autotile reorder and unlimited stack: dragging a tiled window onto another inserts or swaps it into the target slot live via a new Reorder drag behavior. A new Unlimited overflow lets the stack grow past the algorithm's natural cap instead of evicting windows. Drag-insert has always-active and toggle modes matching the snap trigger, and the dropdowns are exposed in Settings → Tiling → Behavior.
  • Animation engine and 47 ported shader transitions: window transitions run through a new OffscreenEffect redirect path with vertex-shader plumbing, parent-FBO bounds extent, live-texture sampling of the rendered surface, and direction-aware leg signals. The release ships compatibility shims that port 28 niri animation shaders via niri_compat and 9 Burn-My-Windows shaders via bmw_compat, plus 10 new BMW-inspired transitions, an audio-reactive neon-city cityscape, a Matrix rain port, a 3D chrome-protocol rewrite, and user-texture support for image-driven effects. OSDs use surface sampling for morph, slide, slidefade, and popin.
  • Animations settings UI overhaul: an eight-phase rework adds an AnimationsPageController and drill-down sub-pages for OSDs, overlays, shaders, motion sets, app rules, widgets, windows, and side panels. The Shaders page hosts a per-event shader picker backed by a generic shader browser. Motion sets bundle themed overrides users can switch between. A timing-mode toggle on the General page and change detection on save round it out. A separate Snapping → Shaders page exposes the same browser for snap-assist, zone-selector, and layout-picker effects.
  • Layout ordering for cycling: the cycle shortcut and zone-selector cycling follow a user-configurable order set under Settings → Snapping → Ordering and Settings → Tiling → Ordering, instead of the implicit save-time order.
  • Per-mode disable lists: snapping and autotiling each have their own exclusion lists for monitors, virtual desktops, and activities, replacing the single global disable. The disabled-context OSD explains which exclusion is active so the user can find the toggle.
  • Native-feeling wheel scroll in settings (#405): every Flickable settings page uses Kirigami.WheelHandler so scroll speed matches the rest of Plasma System Settings, while preserving the Flickable drag-to-flick path.
  • Hold/Toggle controls now work in always-active mode (#249): "Hold to activate" and "Toggle mode" stay enabled when "Activate on every drag" is on, with inverted semantics. The configured trigger deactivates the overlay instead of activating it, so a binding like Right Mouse Button activates when always-active is off and deactivates when on. Esc continues to cancel the drag entirely.
  • Global "auto-assign new windows for all layouts" toggle (#370): a master switch in Snapping Behavior → Window Handling that forces auto-assign on for every manual layout, regardless of the per-layout icon. Effective behavior is globalToggle OR layout.autoAssign, and the default is off so existing semantics are preserved on upgrade. While the global is on, the per-layout toggle is disabled and the Auto/Manual badge in the Layouts grid, layout combo, zone selector, layout picker, and layout OSD shows the effective on state.
  • Separate "Desktop switch OSD" toggle (#372, #373): the layout-preview OSD that fires on virtual-desktop change, activity change, and daemon startup is now governed by its own setting, Snapping.Effects/OsdOnDesktopSwitch, independent of OsdOnLayoutSwitch. Manual layout switches continue to gate on the existing layout-switch toggle. Default is true to preserve current behavior. Upgrade note: users who previously set OsdOnLayoutSwitch=false to silence the startup or VD-switch flash will see those OSDs return on first launch under the new schema. Toggle "Desktop switch OSD" off in Settings → On-Screen Display to restore the old quiet behavior.
  • New D-Bus methods: setPerScreenSettings accepts a batched per-screen settings map so the editor and KCM can apply screen-scoped changes in one round-trip. requestRunningWindows and the runningWindowsAvailable signal give the App Rules editor an async window picker that doesn't block while the daemon enumerates KWin clients.
  • Phosphor SDK foundation libraries: core services are extracted into reusable LGPL libraries, each with its own export macro, headers, and minimal Qt dependencies. The set covers phosphor-engine (renamed from phosphor-engine-api), phosphor-layout-api, phosphor-animation, phosphor-shaders (extracted from phosphor-shell), phosphor-workspaces (VirtualDesktopManager and ActivityManager), phosphor-placement (WindowTrackingService and WindowRegistry), phosphor-tiles, phosphor-zones for manual zone-layout primitives, phosphor-screens, phosphor-snap-engine and phosphor-tile-engine for the physically moved SnapEngine and AutotileEngine, phosphor-config, phosphor-fsloader (renamed from phosphor-jsonloader, with the WatchedDirectorySet base extracted), phosphor-shell-patterns, phosphor-wayland (renamed from phosphor-shell), and phosphor-layer. Geometry primitives use domain-neutral identifiers so the libraries are reusable outside PlasmaZones. SnapState is now the single source of truth for snap window state, owned by SnapEngine. Forwarding headers were removed in favor of direct library includes.
  • Phosphor compositor SDK: a new phosphor-compositor library exposes DaemonClient plus handler interfaces, extracted from the old compositor-common, so third-party Wayland compositors such as river can host the placement, tiling, and overlay services without depending on KWin.

Changed

  • KCM Apply now respects the layout-switch OSD toggle: the per-screen preview OSDs emitted after a System Settings → Apply previously fired unconditionally, ignoring the user's OsdOnLayoutSwitch setting. They now gate on the same flag as cycle, quick-layout, and zone-selector drop. The locked-context OSD remains unconditional so it can explain why a requested change had no visible effect on a locked screen.
  • Drag protocol refactor (#310): the kwin-effect is now a dumb relay for drag events. The daemon owns all drag routing decisions through a new beginDrag, updateDragCursor, and endDrag protocol with typed DragPolicy and DragOutcome structs. The previous effect-side distributed state (m_dragBypassedForAutotile, m_cachedZoneSelectorEnabled, m_autotileScreens local cache) went stale during the asynchronous settings-reload window and produced ~40 seconds of dead drags in the reporter's log on #310. The new protocol makes the daemon the single source of truth at drag start, drag cursor update (30Hz fire-and-forget), and drag end. Cross-VS mid-drag flips are emitted by the daemon via dragPolicyChanged and applied locally by the plugin, replacing the effect-side flip loop that walked KWin::effects->screens() against a local autotile-screen cache. Pinned against drift by a new 8-state truth table test.
  • Meta-F float toggle now runs daemon-local (#310): the keyboard shortcut previously made 4 D-Bus hops across 3 processes (KWin → daemon → effect → daemon → engine → effect), stalling under any D-Bus backpressure and producing the "pressed Meta-F, nothing happened, seconds later it toggled" symptom. It now reads the active window from WindowTrackingAdaptor::m_lastActiveWindowId, fresh frame geometry from a 50ms-debounced shadow (setFrameGeometry), and dispatches to the engine in-process. One D-Bus hop remains for the daemon → effect applyGeometryRequested paint, targeting sub-50ms latency from keypress to visible toggle. The 100ms debounce on handleFloat has been dropped since the in-process path has no D-Bus latency to coalesce.
  • Settings nesting made compile-time: ISettings gains isZoneSelectorActive() and isSnapAssistActive() composite accessors that return snappingEnabled() && <child>Enabled(). Consumers can no longer forget the parent-gate check when reading a nested Snapping.* flag. Raw child accessors remain for KCM settings UI code that genuinely needs the unaffected value.

Fixed

  • No default layout assignment on brand-new virtual desktops (#368): a fresh virtual desktop had no stored entry in the per-context assignment table, so the cascade fell through to a snap-only defaultLayout() that had no concept of mode. Users with autotile configured globally saw new desktops behave as if no mode were set at all: autotile never activated, snapping was disabled, drag overlays did not appear, and windows just floated. The cascade now consults a settings-derived AssignmentEntry provider as the final step, applying the user's intended mode and default to fresh desktops.
  • Autotile shortcut-adjusted ratio and master count did not persist (#271): shortcut adjustments to the autotile master ratio and master count updated runtime state but not the config, the per-algorithm saved settings, or Settings, so the change reverted on the next reload. Shortcut-driven adjustments now propagate through all three with signal-blocking so the values survive every propagation path.
  • Snap-assist showed occupied windows from other virtual desktops (#323): the drag-path occupancy filter walked the live window list without scoping to the current virtual desktop, so a zone that was empty on the user's desktop showed as occupied because a window from another desktop matched it. Now filtered to the current desktop before the occupancy check.
  • Per-activity layout assignments could be overridden by per-monitor defaults (#413): in the layout registry, the fallback chain resolved monitor defaults before per-activity overrides, so a user-set activity-scoped layout could lose to a monitor default that predated it. Activity assignments now win in the precedence order, matching what the assignments UI implies.
  • Layouts context menu eventually stopped opening (#406): in the Layouts page, the right-click context menu would silently fail to open after enough show and hide cycles because separator visibility was imperatively flipped on each show, eventually leaving a dead null-context binding. Separator visibility is now declarative and the dead null-context guard was removed.
  • Cycle-triggered resnap affected windows on other virtual desktops: the daemon's resnap pass after a cycle shortcut walked every tracked window instead of scoping to the active virtual desktop, so cycling on one VD could nudge windows on another VD that happened to share a layout. Now scoped to the active VD.

Installation

Arch Linux (AUR):

yay -S plasmazones  # or plasmazones-bin

Arch Linux (manual):

sudo pacman -U plasmazones-3.0.0-*-x86_64.pkg.tar.zst

KDE Neon / Debian-based:

sudo dpkg -i plasmazones_3.0.0-*_amd64.deb
sudo apt-get install -f  # Install dependencies if needed

Fedora (COPR):

sudo dnf copr enable fuddlesworth/PlasmaZones
sudo dnf install plasmazones

Fedora (manual RPM):

# Fedora 43
sudo dnf install plasmazones-3.0.0-*.fc43.x86_64.rpm
# Fedora 44
sudo dnf install plasmazones-3.0.0-*.fc44.x86_64.rpm

openSUSE Tumbleweed (manual RPM):

sudo zypper install plasmazones-3.0.0-*.x86_64.rpm

openSUSE Tumbleweed (OBS):

sudo zypper addrepo https://download.opensuse.org/repositories/home:ilFrance/openSUSE_Tumbleweed/home:ilFrance.repo
sudo zypper refresh
sudo zypper install plasmazones

Community-maintained package by ilFrance

Universal Linux (AppDir):
For Fedora Atomic, Steam Deck, or non-root user installation:

tar xzf plasmazones-3.0.0-linux-x86_64.tar.gz
cd plasmazones-linux-x86_64
./install.sh

NixOS (flake):

# flake.nix inputs
plasmazones.url = "github:fuddlesworth/PlasmaZones";

# configuration.nix
programs.plasmazones.enable = true;

NixOS (standalone):
Download plasmazones.nix from the release assets, then:

# configuration.nix
environment.systemPackages = [
  (pkgs.callPackage ./plasmazones.nix {})
];

Post-Installation

systemctl --user enable --now plasmazones.service
systemsettings kcm_plasmazones

Don't miss a new PlasmaZones release

NewReleases is sending notifications on new releases.