The hull moves to the top layer, with its transparent opening and empty input region, so windows sliding out of the opening during a workspace switch pass behind the frame like things behind a porthole rim rather than drawing over the bar. A layer rule keeps the bar and the rail above it on that layer. The animation tree is redone around that: workspaces drift 18% vertically and fade on a slow, jolt-free "drift" curve; the SUPER+S scratchpad slides in whole from under the bar, the same gesture as the dashboard and popouts; windows and layers keep their calm resolve and fade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
125 lines
3.9 KiB
QML
125 lines
3.9 KiB
QML
import QtQuick
|
|
import QtQuick.Shapes
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import "root:/config"
|
|
|
|
// The hull: one surface for the bar, the rail and the thin band down the left
|
|
// and along the bottom, with the desktop as a rounded opening cut out of it.
|
|
// The idea is caelestia's screen border; the reading is the wallpaper's — you
|
|
// are inside the ship, and the windows sit in the porthole.
|
|
//
|
|
// The hull lives on the top layer, over every window, and its opening is
|
|
// transparent with no input region, so it covers nothing inside the opening
|
|
// and catches no clicks. Being above the windows is the point: a workspace
|
|
// switch slides windows *behind* the frame, the way things pass behind the
|
|
// rim of a porthole, instead of drawing over the bar. A fullscreen window
|
|
// still covers it, since Hyprland draws fullscreen above the top layer.
|
|
// hypr/lua/rules/layers.lua orders it under the bar and the rail.
|
|
//
|
|
// The bar and the rail draw no surface of their own and ignore exclusive
|
|
// zones, so every piece is placed from the screen edge. The four zones are
|
|
// reserved here instead, by windows that draw nothing — that way the usable
|
|
// area is exactly the opening, whichever surface the compositor arranges
|
|
// first.
|
|
Scope {
|
|
id: root
|
|
|
|
required property var modelData
|
|
|
|
PanelWindow {
|
|
id: hull
|
|
|
|
screen: root.modelData
|
|
|
|
WlrLayershell.layer: WlrLayer.Top
|
|
WlrLayershell.namespace: "takemi-frame"
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
exclusionMode: ExclusionMode.Ignore
|
|
|
|
anchors {
|
|
top: true
|
|
bottom: true
|
|
left: true
|
|
right: true
|
|
}
|
|
|
|
color: "transparent"
|
|
mask: Region {}
|
|
|
|
// The opening, in window coordinates.
|
|
readonly property real x0: Theme.frame
|
|
readonly property real y0: Theme.barHeight
|
|
readonly property real x1: width - Theme.railWidth
|
|
readonly property real y1: height - Theme.frame
|
|
readonly property real r: Theme.frameRadius
|
|
|
|
readonly property string opening: {
|
|
const x0 = hull.x0, y0 = hull.y0, x1 = hull.x1, y1 = hull.y1, r = hull.r;
|
|
return `M ${x0 + r} ${y0} H ${x1 - r} A ${r} ${r} 0 0 1 ${x1} ${y0 + r}`
|
|
+ ` V ${y1 - r} A ${r} ${r} 0 0 1 ${x1 - r} ${y1}`
|
|
+ ` H ${x0 + r} A ${r} ${r} 0 0 1 ${x0} ${y1 - r}`
|
|
+ ` V ${y0 + r} A ${r} ${r} 0 0 1 ${x0 + r} ${y0} Z`;
|
|
}
|
|
|
|
Shape {
|
|
anchors.fill: parent
|
|
preferredRendererType: Shape.CurveRenderer
|
|
|
|
// The hull itself: the whole screen, minus the opening.
|
|
ShapePath {
|
|
fillColor: Theme.hull
|
|
fillRule: ShapePath.OddEvenFill
|
|
strokeColor: "transparent"
|
|
|
|
PathSvg {
|
|
path: `M 0 0 H ${hull.width} V ${hull.height} H 0 Z ` + hull.opening
|
|
}
|
|
}
|
|
|
|
// The rim — a hairline round the opening, the lit edge of the
|
|
// porthole in the wallpaper.
|
|
ShapePath {
|
|
fillColor: "transparent"
|
|
strokeColor: Theme.rim
|
|
strokeWidth: 1
|
|
|
|
PathSvg {
|
|
path: hull.opening
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExclusionZone {
|
|
anchors.top: true
|
|
exclusiveZone: Theme.barHeight
|
|
}
|
|
|
|
ExclusionZone {
|
|
anchors.right: true
|
|
exclusiveZone: Theme.railWidth
|
|
}
|
|
|
|
ExclusionZone {
|
|
anchors.bottom: true
|
|
exclusiveZone: Theme.frame
|
|
}
|
|
|
|
ExclusionZone {
|
|
anchors.left: true
|
|
exclusiveZone: Theme.frame
|
|
}
|
|
|
|
component ExclusionZone: PanelWindow {
|
|
screen: root.modelData
|
|
WlrLayershell.layer: WlrLayer.Bottom
|
|
WlrLayershell.namespace: "takemi-frame-zone"
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
color: "transparent"
|
|
mask: Region {}
|
|
implicitWidth: 1
|
|
implicitHeight: 1
|
|
}
|
|
}
|