mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-04 04:42:05 -04:00
170 lines
6.6 KiB
QML
170 lines
6.6 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import qs.Common
|
|
import qs.Services
|
|
|
|
PanelWindow {
|
|
id: win
|
|
|
|
required property var targetScreen
|
|
|
|
screen: targetScreen
|
|
visible: true
|
|
|
|
WlrLayershell.namespace: "dms:frame"
|
|
WlrLayershell.layer: WlrLayer.Top
|
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
|
|
|
anchors {
|
|
top: true
|
|
bottom: true
|
|
left: true
|
|
right: true
|
|
}
|
|
|
|
color: "transparent"
|
|
|
|
// No input — pass everything through to apps and bar
|
|
mask: Region {}
|
|
|
|
readonly property var barEdges: {
|
|
SettingsData.barConfigs;
|
|
return SettingsData.getActiveBarEdgesForScreen(win.screen);
|
|
}
|
|
|
|
readonly property real _dpr: CompositorService.getScreenScale(win.screen)
|
|
readonly property bool _frameActive: SettingsData.frameEnabled
|
|
&& SettingsData.isScreenInPreferences(win.screen, SettingsData.frameScreenPreferences)
|
|
readonly property int _windowRegionWidth: win._regionInt(win.width)
|
|
readonly property int _windowRegionHeight: win._regionInt(win.height)
|
|
|
|
function _regionInt(value) {
|
|
return Math.max(0, Math.round(Theme.px(value, win._dpr)));
|
|
}
|
|
|
|
readonly property int cutoutTopInset: win._regionInt(barEdges.includes("top") ? SettingsData.frameBarSize : SettingsData.frameThickness)
|
|
readonly property int cutoutBottomInset: win._regionInt(barEdges.includes("bottom") ? SettingsData.frameBarSize : SettingsData.frameThickness)
|
|
readonly property int cutoutLeftInset: win._regionInt(barEdges.includes("left") ? SettingsData.frameBarSize : SettingsData.frameThickness)
|
|
readonly property int cutoutRightInset: win._regionInt(barEdges.includes("right") ? SettingsData.frameBarSize : SettingsData.frameThickness)
|
|
readonly property int cutoutWidth: Math.max(0, win._windowRegionWidth - win.cutoutLeftInset - win.cutoutRightInset)
|
|
readonly property int cutoutHeight: Math.max(0, win._windowRegionHeight - win.cutoutTopInset - win.cutoutBottomInset)
|
|
readonly property int cutoutRadius: {
|
|
const requested = win._regionInt(SettingsData.frameRounding);
|
|
const maxRadius = Math.floor(Math.min(win.cutoutWidth, win.cutoutHeight) / 2);
|
|
return Math.max(0, Math.min(requested, maxRadius));
|
|
}
|
|
|
|
// Slightly expand the subtractive blur cutout at very low opacity levels
|
|
readonly property int _blurCutoutCompensation: SettingsData.frameOpacity <= 0.2 ? 1 : 0
|
|
readonly property int _blurCutoutLeft: Math.max(0, win.cutoutLeftInset - win._blurCutoutCompensation)
|
|
readonly property int _blurCutoutTop: Math.max(0, win.cutoutTopInset - win._blurCutoutCompensation)
|
|
readonly property int _blurCutoutRight: Math.min(win._windowRegionWidth, win._windowRegionWidth - win.cutoutRightInset + win._blurCutoutCompensation)
|
|
readonly property int _blurCutoutBottom: Math.min(win._windowRegionHeight, win._windowRegionHeight - win.cutoutBottomInset + win._blurCutoutCompensation)
|
|
readonly property int _blurCutoutRadius: {
|
|
const requested = win.cutoutRadius + win._blurCutoutCompensation;
|
|
const maxRadius = Math.floor(Math.min(_blurCutout.width, _blurCutout.height) / 2);
|
|
return Math.max(0, Math.min(requested, maxRadius));
|
|
}
|
|
|
|
// Must stay visible so Region.item can resolve scene coordinates.
|
|
Item {
|
|
id: _blurCutout
|
|
x: win._blurCutoutLeft
|
|
y: win._blurCutoutTop
|
|
width: Math.max(0, win._blurCutoutRight - win._blurCutoutLeft)
|
|
height: Math.max(0, win._blurCutoutBottom - win._blurCutoutTop)
|
|
}
|
|
|
|
property var _frameBlurRegion: null
|
|
|
|
function _buildBlur() {
|
|
_teardownBlur();
|
|
// Follow the global blur toggle
|
|
if (!BlurService.enabled || !SettingsData.frameBlurEnabled || !win._frameActive || !win.visible)
|
|
return;
|
|
try {
|
|
const region = Qt.createQmlObject(
|
|
'import QtQuick; import Quickshell; Region {' +
|
|
' property Item cutoutItem;' +
|
|
' property int cutoutRadius: 0;' +
|
|
' Region {' +
|
|
' item: cutoutItem;' +
|
|
' intersection: Intersection.Subtract;' +
|
|
' radius: cutoutRadius;' +
|
|
' }' +
|
|
'}',
|
|
win, "FrameBlurRegion");
|
|
|
|
region.x = Qt.binding(() => 0);
|
|
region.y = Qt.binding(() => 0);
|
|
region.width = Qt.binding(() => win._windowRegionWidth);
|
|
region.height = Qt.binding(() => win._windowRegionHeight);
|
|
region.cutoutItem = _blurCutout;
|
|
region.cutoutRadius = Qt.binding(() => win._blurCutoutRadius);
|
|
|
|
win.BackgroundEffect.blurRegion = region;
|
|
win._frameBlurRegion = region;
|
|
} catch (e) {
|
|
console.warn("FrameWindow: Failed to create blur region:", e);
|
|
}
|
|
}
|
|
|
|
function _teardownBlur() {
|
|
if (!win._frameBlurRegion)
|
|
return;
|
|
try {
|
|
win.BackgroundEffect.blurRegion = null;
|
|
} catch (e) {}
|
|
win._frameBlurRegion.destroy();
|
|
win._frameBlurRegion = null;
|
|
}
|
|
|
|
Timer {
|
|
id: _blurRebuildTimer
|
|
interval: 1
|
|
onTriggered: win._buildBlur()
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onFrameBlurEnabledChanged() { _blurRebuildTimer.restart(); }
|
|
function onFrameEnabledChanged() { _blurRebuildTimer.restart(); }
|
|
function onFrameThicknessChanged() { _blurRebuildTimer.restart(); }
|
|
function onFrameBarSizeChanged() { _blurRebuildTimer.restart(); }
|
|
function onFrameOpacityChanged() { _blurRebuildTimer.restart(); }
|
|
function onFrameRoundingChanged() { _blurRebuildTimer.restart(); }
|
|
function onFrameScreenPreferencesChanged() { _blurRebuildTimer.restart(); }
|
|
function onBarConfigsChanged() { _blurRebuildTimer.restart(); }
|
|
}
|
|
|
|
Connections {
|
|
target: BlurService
|
|
function onEnabledChanged() { _blurRebuildTimer.restart(); }
|
|
}
|
|
|
|
onVisibleChanged: {
|
|
if (visible) {
|
|
win._frameBlurRegion = null;
|
|
_blurRebuildTimer.restart();
|
|
} else {
|
|
_teardownBlur();
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: Qt.callLater(() => win._buildBlur())
|
|
Component.onDestruction: win._teardownBlur()
|
|
|
|
FrameBorder {
|
|
anchors.fill: parent
|
|
visible: win._frameActive
|
|
cutoutTopInset: win.cutoutTopInset
|
|
cutoutBottomInset: win.cutoutBottomInset
|
|
cutoutLeftInset: win.cutoutLeftInset
|
|
cutoutRightInset: win.cutoutRightInset
|
|
cutoutRadius: win.cutoutRadius
|
|
}
|
|
}
|