feat(screencorners): no longer reside in MainScreen, tiny PanelWindow. Will also serve for hotcorners detection

This commit is contained in:
Lemmy
2026-03-19 22:46:13 -04:00
parent b1f8a24da4
commit 1f0ea41c35
4 changed files with 101 additions and 234 deletions
+14
View File
@@ -103,6 +103,20 @@ Variants {
}
}
// Screen corners - 4 small PanelWindows, one per corner
Repeater {
model: ["topLeft", "topRight", "bottomLeft", "bottomRight"]
delegate: Loader {
active: windowItem.windowLoaded && windowItem.shouldBeActive
asynchronous: false
sourceComponent: ScreenCornerWindow {
screen: windowItem.modelData
corner: modelData
}
}
}
// BarExclusionZone - created after MainScreen has fully loaded
// Note: Exclusion zone should NOT be affected by hideOnOverview setting.
// When bar is hidden during overview, the exclusion zone should remain to prevent
-3
View File
@@ -572,9 +572,6 @@ PanelWindow {
}
}
// Screen Corners
ScreenCorners {}
// Blur behind the bar and open panels
// Helper object holding computed properties for blur regions
QtObject {
+87
View File
@@ -0,0 +1,87 @@
import QtQuick
import QtQuick.Shapes
import Quickshell
import Quickshell.Wayland
import qs.Commons
/**
* ScreenCornerWindow - Small PanelWindow that renders a single concave screen corner.
*/
PanelWindow {
id: root
required property string corner // "topLeft", "topRight", "bottomLeft", "bottomRight"
readonly property real s: Style.screenRadius
readonly property bool shouldShow: Settings.data.general.showScreenCorners && s > 0
visible: shouldShow
color: "transparent"
// Click-through
mask: Region {}
WlrLayershell.namespace: "noctalia-corner-" + corner + "-" + (screen?.name || "unknown")
WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
anchors {
top: corner === "topLeft" || corner === "topRight"
bottom: corner === "bottomLeft" || corner === "bottomRight"
left: corner === "topLeft" || corner === "bottomLeft"
right: corner === "topRight" || corner === "bottomRight"
}
implicitWidth: Math.ceil(s)
implicitHeight: Math.ceil(s)
// Cache to texture to avoid continuous re-tessellation
Item {
anchors.fill: parent
layer.enabled: true
Shape {
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
asynchronous: true
enabled: false
visible: root.s > 0 && width > 0 && height > 0
ShapePath {
id: cornerPath
readonly property color cornerColor: Settings.data.general.forceBlackScreenCorners ? "black" : Color.mSurface
strokeWidth: -1
fillColor: root.shouldShow ? cornerColor : "transparent"
Behavior on fillColor {
enabled: !Color.isTransitioning
ColorAnimation {
duration: Style.animationFast
}
}
PathSvg {
path: {
var s = root.s;
if (s <= 0)
return "M -1 -1 L -1 0 L 0 0 Z";
switch (root.corner) {
case "topLeft":
return "M 0 0 L " + s + " 0 A " + s + " " + s + " 0 0 0 0 " + s + " Z";
case "topRight":
return "M 0 0 L " + s + " 0 L " + s + " " + s + " A " + s + " " + s + " 0 0 0 0 0 Z";
case "bottomLeft":
return "M 0 0 A " + s + " " + s + " 0 0 0 " + s + " " + s + " L 0 " + s + " Z";
case "bottomRight":
return "M " + s + " " + s + " L 0 " + s + " A " + s + " " + s + " 0 0 0 " + s + " 0 Z";
default:
return "M -1 -1 L -1 0 L 0 0 Z";
}
}
}
}
}
}
}
-231
View File
@@ -1,231 +0,0 @@
import QtQuick
import QtQuick.Shapes
import qs.Commons
/**
* ScreenCorners - Shape component for rendering screen corners
*
* Renders concave corners at the screen edges to create a rounded screen effect.
* Self-contained Shape component (no shadows).
*/
Item {
id: root
anchors.fill: parent
// Wrapper with layer caching to reduce GPU tessellation overhead
Item {
anchors.fill: parent
// Cache the Shape to a texture to prevent continuous re-tessellation
layer.enabled: true
Shape {
id: cornersShape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
asynchronous: true
enabled: false // Disable mouse input
visible: cornersPath.cornerRadius > 0 && width > 0 && height > 0
ShapePath {
id: cornersPath
// Corner configuration
readonly property color cornerColor: Settings.data.general.forceBlackScreenCorners ? "black" : Color.mSurface
readonly property real cornerRadius: Style.screenRadius
readonly property real cornerSize: Style.screenRadius
// Determine margins based on bar position
readonly property real topMargin: 0
readonly property real bottomMargin: 0
readonly property real leftMargin: 0
readonly property real rightMargin: 0
// Screen dimensions
readonly property real screenWidth: cornersShape.width
readonly property real screenHeight: cornersShape.height
// Only show screen corners if enabled and appropriate conditions are met
readonly property bool shouldShow: Settings.data.general.showScreenCorners
// ShapePath configuration
strokeWidth: -1 // No stroke, fill only
fillColor: shouldShow ? cornerColor : "transparent"
// Smooth color animation (disabled during theme transitions to sync with Color.qml)
Behavior on fillColor {
enabled: !Color.isTransitioning
ColorAnimation {
duration: Style.animationFast
}
}
// ========== PATH DEFINITION ==========
// Draws 4 separate corner squares at screen edges
// Each corner square has a concave arc on the inner diagonal
// ========== TOP-LEFT CORNER ==========
// Arc is at the bottom-right of this square (inner diagonal)
// Start at top-left screen corner
startX: leftMargin
startY: topMargin
// Top edge (moving right)
PathLine {
relativeX: cornersPath.cornerSize
relativeY: 0
}
// Right edge (moving down toward arc)
PathLine {
relativeX: 0
relativeY: cornersPath.cornerSize - cornersPath.cornerRadius
}
// Concave arc (bottom-right corner of square, curving inward toward screen center)
PathArc {
relativeX: -cornersPath.cornerRadius
relativeY: cornersPath.cornerRadius
radiusX: cornersPath.cornerRadius
radiusY: cornersPath.cornerRadius
direction: PathArc.Counterclockwise
}
// Bottom edge (moving left)
PathLine {
relativeX: -(cornersPath.cornerSize - cornersPath.cornerRadius)
relativeY: 0
}
// Left edge (moving up) - closes back to start
PathLine {
relativeX: 0
relativeY: -cornersPath.cornerSize
}
// ========== TOP-RIGHT CORNER ==========
// Arc is at the bottom-left of this square (inner diagonal)
PathMove {
x: cornersPath.screenWidth - cornersPath.rightMargin - cornersPath.cornerSize
y: cornersPath.topMargin
}
// Top edge (moving right)
PathLine {
relativeX: cornersPath.cornerSize
relativeY: 0
}
// Right edge (moving down)
PathLine {
relativeX: 0
relativeY: cornersPath.cornerSize
}
// Bottom edge (moving left toward arc)
PathLine {
relativeX: -(cornersPath.cornerSize - cornersPath.cornerRadius)
relativeY: 0
}
// Concave arc (bottom-left corner of square, curving inward toward screen center)
PathArc {
relativeX: -cornersPath.cornerRadius
relativeY: -cornersPath.cornerRadius
radiusX: cornersPath.cornerRadius
radiusY: cornersPath.cornerRadius
direction: PathArc.Counterclockwise
}
// Left edge (moving up) - closes back to start
PathLine {
relativeX: 0
relativeY: -(cornersPath.cornerSize - cornersPath.cornerRadius)
}
// ========== BOTTOM-LEFT CORNER ==========
// Arc is at the top-right of this square (inner diagonal)
PathMove {
x: cornersPath.leftMargin
y: cornersPath.screenHeight - cornersPath.bottomMargin - cornersPath.cornerSize
}
// Top edge (moving right toward arc)
PathLine {
relativeX: cornersPath.cornerSize - cornersPath.cornerRadius
relativeY: 0
}
// Concave arc (top-right corner of square, curving inward toward screen center)
PathArc {
relativeX: cornersPath.cornerRadius
relativeY: cornersPath.cornerRadius
radiusX: cornersPath.cornerRadius
radiusY: cornersPath.cornerRadius
direction: PathArc.Counterclockwise
}
// Right edge (moving down)
PathLine {
relativeX: 0
relativeY: cornersPath.cornerSize - cornersPath.cornerRadius
}
// Bottom edge (moving left)
PathLine {
relativeX: -cornersPath.cornerSize
relativeY: 0
}
// Left edge (moving up) - closes back to start
PathLine {
relativeX: 0
relativeY: -cornersPath.cornerSize
}
// ========== BOTTOM-RIGHT CORNER ==========
// Arc is at the top-left of this square (inner diagonal)
// Start at bottom-right of square (different from other corners!)
PathMove {
x: cornersPath.screenWidth - cornersPath.rightMargin
y: cornersPath.screenHeight - cornersPath.bottomMargin
}
// Bottom edge (moving left)
PathLine {
relativeX: -cornersPath.cornerSize
relativeY: 0
}
// Left edge (moving up toward arc)
PathLine {
relativeX: 0
relativeY: -(cornersPath.cornerSize - cornersPath.cornerRadius)
}
// Concave arc (top-left corner of square, curving inward toward screen center)
PathArc {
relativeX: cornersPath.cornerRadius
relativeY: -cornersPath.cornerRadius
radiusX: cornersPath.cornerRadius
radiusY: cornersPath.cornerRadius
direction: PathArc.Counterclockwise
}
// Top edge (moving right)
PathLine {
relativeX: cornersPath.cornerSize - cornersPath.cornerRadius
relativeY: 0
}
// Right edge (moving down) - closes back to start
PathLine {
relativeX: 0
relativeY: cornersPath.cornerSize
}
}
}
}
}