mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-05 04:58:30 -04:00
frame: host bar and dock inside the frame surface in connected mode
Previously the bar-in-frame was rendered on the overlay layer always. Now they are rendered inside of the frames top-layer surface, which lets the compositor handle layer-shell layering natively.
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.DankBar
|
||||
import qs.Services
|
||||
|
||||
// Renders the bar(s) inside the frame surface in connected mode: one DankBarBody per
|
||||
// active bar edge, positioned in the frame's cutout band. Reuses the existing DankBar
|
||||
// item (per bar config) as rootWindow so colour-picker, overview loader and widget
|
||||
// models are shared with the standalone path.
|
||||
Item {
|
||||
id: host
|
||||
|
||||
required property var frameWindow
|
||||
required property var targetScreen
|
||||
|
||||
readonly property string screenName: targetScreen ? targetScreen.name : ""
|
||||
|
||||
readonly property var barSlots: {
|
||||
SettingsData.barConfigs;
|
||||
const out = [];
|
||||
const configs = SettingsData.barConfigs || [];
|
||||
for (let i = 0; i < configs.length; i++) {
|
||||
const bc = configs[i];
|
||||
if (!bc.enabled)
|
||||
continue;
|
||||
const prefs = bc.screenPreferences || ["all"];
|
||||
if (!prefs.includes("all") && !SettingsData.isScreenInPreferences(host.targetScreen, prefs))
|
||||
continue;
|
||||
let edge = "top";
|
||||
switch (bc.position ?? 0) {
|
||||
case SettingsData.Position.Bottom:
|
||||
edge = "bottom";
|
||||
break;
|
||||
case SettingsData.Position.Left:
|
||||
edge = "left";
|
||||
break;
|
||||
case SettingsData.Position.Right:
|
||||
edge = "right";
|
||||
break;
|
||||
}
|
||||
out.push({
|
||||
"barId": bc.id,
|
||||
"edge": edge
|
||||
});
|
||||
}
|
||||
// Horizontal bars own the corners, so render them last (on top) — their edge widget
|
||||
// must receive the corner click over the vertical bar's hover area beneath it.
|
||||
out.sort((a, b) => {
|
||||
const rank = e => (e === "left" || e === "right") ? 0 : 1;
|
||||
return rank(a.edge) - rank(b.edge);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: host.barSlots
|
||||
|
||||
delegate: Item {
|
||||
id: slot
|
||||
|
||||
required property var modelData
|
||||
|
||||
readonly property string edge: modelData.edge
|
||||
readonly property var dankBarItem: BarWidgetService.dankBarItems[modelData.barId] ?? null
|
||||
readonly property var slotBarConfig: dankBarItem?.barConfig ?? SettingsData.getBarConfig(modelData.barId)
|
||||
|
||||
// Each bar spans its full edge (matching the standalone window extent) so
|
||||
// DankBarContent's own adjacency margins inset it, rather than double-insetting
|
||||
// against a pre-carved strip.
|
||||
x: edge === "right" ? host.frameWindow._windowRegionWidth - host.frameWindow.cutoutRightInset : 0
|
||||
y: edge === "bottom" ? host.frameWindow._windowRegionHeight - host.frameWindow.cutoutBottomInset : 0
|
||||
width: {
|
||||
switch (edge) {
|
||||
case "left":
|
||||
return host.frameWindow.cutoutLeftInset;
|
||||
case "right":
|
||||
return host.frameWindow.cutoutRightInset;
|
||||
default:
|
||||
return host.frameWindow._windowRegionWidth;
|
||||
}
|
||||
}
|
||||
height: {
|
||||
switch (edge) {
|
||||
case "top":
|
||||
return host.frameWindow.cutoutTopInset;
|
||||
case "bottom":
|
||||
return host.frameWindow.cutoutBottomInset;
|
||||
default:
|
||||
return host.frameWindow._windowRegionHeight;
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
active: slot.dankBarItem !== null && slot.slotBarConfig !== null
|
||||
|
||||
sourceComponent: DankBarBody {
|
||||
hostWindow: host.frameWindow
|
||||
modelData: host.targetScreen
|
||||
rootWindow: slot.dankBarItem
|
||||
barConfig: slot.slotBarConfig
|
||||
leftWidgetsModel: slot.dankBarItem?.leftWidgetsModel ?? null
|
||||
centerWidgetsModel: slot.dankBarItem?.centerWidgetsModel ?? null
|
||||
rightWidgetsModel: slot.dankBarItem?.rightWidgetsModel ?? null
|
||||
|
||||
Component.onCompleted: BarWidgetService.registerFrameBar(host.screenName, this)
|
||||
Component.onDestruction: BarWidgetService.unregisterFrameBar(host.screenName, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.Dock
|
||||
import qs.Services
|
||||
|
||||
// Renders the dock inside the frame surface in connected mode: a single DockBody
|
||||
// positioned by SettingsData.dockPosition. It fills the frame and positions its own
|
||||
// content via its internal anchors/geometry using hostWindow.
|
||||
Item {
|
||||
id: host
|
||||
|
||||
required property var frameWindow
|
||||
required property var targetScreen
|
||||
|
||||
readonly property string screenName: targetScreen ? targetScreen.name : ""
|
||||
|
||||
// Exposed so FrameWindow can add the dock's hover strip to its input region.
|
||||
readonly property alias dockMaskItem: dockBody.inputMaskItem
|
||||
|
||||
DockBody {
|
||||
id: dockBody
|
||||
anchors.fill: parent
|
||||
hostWindow: host.frameWindow
|
||||
modelData: host.targetScreen
|
||||
contextMenu: BarWidgetService.dockContextMenu
|
||||
trashContextMenu: BarWidgetService.dockTrashContextMenu
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,23 @@ Scope {
|
||||
return SettingsData.getActiveBarEdgesForScreen(screen);
|
||||
}
|
||||
|
||||
// One thin invisible PanelWindow per edge.
|
||||
// Skips any edge where a bar already provides its own exclusiveZone.
|
||||
// One thin invisible PanelWindow per edge. A standalone bar reserves its own edge, so
|
||||
// that edge is skipped — unless the frame hosts the bar (connected mode), where no bar
|
||||
// window exists and the exclusion must reserve the full bar thickness itself.
|
||||
|
||||
readonly property bool screenEnabled: CompositorService.frameWindowVisibleForScreen(root.screen)
|
||||
readonly property bool hostsBar: CompositorService.frameHostsSurfacesForScreen(root.screen)
|
||||
|
||||
function exclusionSizeForEdge(edge) {
|
||||
return root.barEdges.includes(edge) ? SettingsData.frameBarSize : SettingsData.frameThickness;
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.screenEnabled && !root.barEdges.includes("top")
|
||||
readonly property bool isBarEdge: root.barEdges.includes("top")
|
||||
active: root.screenEnabled && (!isBarEdge || root.hostsBar)
|
||||
sourceComponent: EdgeExclusion {
|
||||
targetScreen: root.screen
|
||||
exclusionSize: root.exclusionSizeForEdge("top")
|
||||
anchorTop: true
|
||||
anchorLeft: true
|
||||
anchorRight: true
|
||||
@@ -32,9 +40,11 @@ Scope {
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.screenEnabled && !root.barEdges.includes("bottom")
|
||||
readonly property bool isBarEdge: root.barEdges.includes("bottom")
|
||||
active: root.screenEnabled && (!isBarEdge || root.hostsBar)
|
||||
sourceComponent: EdgeExclusion {
|
||||
targetScreen: root.screen
|
||||
exclusionSize: root.exclusionSizeForEdge("bottom")
|
||||
anchorBottom: true
|
||||
anchorLeft: true
|
||||
anchorRight: true
|
||||
@@ -42,9 +52,11 @@ Scope {
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.screenEnabled && !root.barEdges.includes("left")
|
||||
readonly property bool isBarEdge: root.barEdges.includes("left")
|
||||
active: root.screenEnabled && (!isBarEdge || root.hostsBar)
|
||||
sourceComponent: EdgeExclusion {
|
||||
targetScreen: root.screen
|
||||
exclusionSize: root.exclusionSizeForEdge("left")
|
||||
anchorLeft: true
|
||||
anchorTop: true
|
||||
anchorBottom: true
|
||||
@@ -52,9 +64,11 @@ Scope {
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.screenEnabled && !root.barEdges.includes("right")
|
||||
readonly property bool isBarEdge: root.barEdges.includes("right")
|
||||
active: root.screenEnabled && (!isBarEdge || root.hostsBar)
|
||||
sourceComponent: EdgeExclusion {
|
||||
targetScreen: root.screen
|
||||
exclusionSize: root.exclusionSizeForEdge("right")
|
||||
anchorRight: true
|
||||
anchorTop: true
|
||||
anchorBottom: true
|
||||
@@ -63,6 +77,7 @@ Scope {
|
||||
|
||||
component EdgeExclusion: PanelWindow {
|
||||
required property var targetScreen
|
||||
property real exclusionSize: SettingsData.frameThickness
|
||||
|
||||
screen: targetScreen
|
||||
property bool anchorTop: false
|
||||
@@ -72,7 +87,7 @@ Scope {
|
||||
|
||||
WlrLayershell.namespace: "dms:frame-exclusion"
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
exclusiveZone: SettingsData.frameThickness
|
||||
exclusiveZone: exclusionSize
|
||||
color: "transparent"
|
||||
mask: Region {}
|
||||
implicitWidth: 1
|
||||
|
||||
@@ -32,7 +32,41 @@ PanelWindow {
|
||||
}
|
||||
|
||||
color: "transparent"
|
||||
mask: Region {}
|
||||
// Click-through everywhere except the bar strips it hosts in connected mode.
|
||||
mask: Region {
|
||||
Region {
|
||||
readonly property bool present: win._connectedActive && win.barEdges.includes("top")
|
||||
x: 0
|
||||
y: 0
|
||||
width: present ? win._windowRegionWidth : 0
|
||||
height: present ? win.cutoutTopInset : 0
|
||||
}
|
||||
Region {
|
||||
readonly property bool present: win._connectedActive && win.barEdges.includes("bottom")
|
||||
x: 0
|
||||
y: present ? win._windowRegionHeight - win.cutoutBottomInset : 0
|
||||
width: present ? win._windowRegionWidth : 0
|
||||
height: present ? win.cutoutBottomInset : 0
|
||||
}
|
||||
Region {
|
||||
readonly property bool present: win._connectedActive && win.barEdges.includes("left")
|
||||
x: 0
|
||||
y: 0
|
||||
width: present ? win.cutoutLeftInset : 0
|
||||
height: present ? win._windowRegionHeight : 0
|
||||
}
|
||||
Region {
|
||||
readonly property bool present: win._connectedActive && win.barEdges.includes("right")
|
||||
x: present ? win._windowRegionWidth - win.cutoutRightInset : 0
|
||||
y: 0
|
||||
width: present ? win.cutoutRightInset : 0
|
||||
height: present ? win._windowRegionHeight : 0
|
||||
}
|
||||
// The frame-hosted dock's hover strip, so hover-reveal works through the frame surface.
|
||||
Region {
|
||||
item: frameDockHostLoader.item ? frameDockHostLoader.item.dockMaskItem : null
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var barEdges: {
|
||||
SettingsData.barConfigs;
|
||||
@@ -51,6 +85,16 @@ PanelWindow {
|
||||
readonly property var _modalDescriptor: ConnectedModeState.surfaceDescriptor(win._screenName, "modal")
|
||||
|
||||
readonly property bool _connectedActive: CompositorService.usesConnectedFrameChromeForScreen(win.targetScreen)
|
||||
readonly property bool _dockHostedHere: {
|
||||
if (!win._connectedActive || !SettingsData.showDock)
|
||||
return false;
|
||||
const screens = SettingsData.getFilteredScreens("dock");
|
||||
for (let i = 0; i < screens.length; i++) {
|
||||
if (screens[i] && screens[i].name === win._screenName)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
readonly property string _barSide: {
|
||||
const edges = win.barEdges;
|
||||
if (edges.includes("top"))
|
||||
@@ -1101,4 +1145,25 @@ PanelWindow {
|
||||
property vector4d chromeK3: win._sdfSlots[3].k
|
||||
property vector4d chromeParam3: win._sdfSlots[3].param
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
z: 1
|
||||
active: win._connectedActive
|
||||
sourceComponent: FrameBarHost {
|
||||
frameWindow: win
|
||||
targetScreen: win.targetScreen
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: frameDockHostLoader
|
||||
anchors.fill: parent
|
||||
z: 1
|
||||
active: win._dockHostedHere
|
||||
sourceComponent: FrameDockHost {
|
||||
frameWindow: win
|
||||
targetScreen: win.targetScreen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user