mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2025-12-06 06:36:15 +00:00
MainScreen: Bar content is in its own PanelWindow
This commit is contained in:
@@ -226,7 +226,7 @@
|
||||
"audio": {
|
||||
"volumeStep": 5,
|
||||
"volumeOverdrive": false,
|
||||
"cavaFrameRate": 60,
|
||||
"cavaFrameRate": 30,
|
||||
"visualizerType": "linear",
|
||||
"visualizerQuality": "high",
|
||||
"mprisBlacklist": [],
|
||||
|
||||
@@ -30,9 +30,6 @@ Item {
|
||||
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
|
||||
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
|
||||
|
||||
// Attachment overlap to fix hairline gap with fractional scaling
|
||||
readonly property real attachmentOverlap: 1
|
||||
|
||||
// Fill the parent (the Loader)
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -68,29 +65,28 @@ Item {
|
||||
id: bar
|
||||
|
||||
// Position and size the bar based on orientation and floating margins
|
||||
// Extend the bar by attachmentOverlap to eliminate hairline gap
|
||||
x: {
|
||||
var baseX = (root.barPosition === "right") ? (parent.width - Style.barHeight - root.barMarginH) : root.barMarginH
|
||||
if (root.barPosition === "right")
|
||||
return baseX - root.attachmentOverlap // Extend left towards panels
|
||||
return baseX // Extend left towards panels
|
||||
return baseX
|
||||
}
|
||||
y: {
|
||||
var baseY = (root.barPosition === "bottom") ? (parent.height - Style.barHeight - root.barMarginV) : root.barMarginV
|
||||
if (root.barPosition === "bottom")
|
||||
return baseY - root.attachmentOverlap // Extend up towards panels
|
||||
return baseY // Extend up towards panels
|
||||
return baseY
|
||||
}
|
||||
width: {
|
||||
var baseWidth = root.barIsVertical ? Style.barHeight : (parent.width - root.barMarginH * 2)
|
||||
if (!root.barIsVertical)
|
||||
return baseWidth // Horizontal bars extend via height, not width
|
||||
return baseWidth + root.attachmentOverlap + 1
|
||||
return baseWidth + 1
|
||||
}
|
||||
height: {
|
||||
var baseHeight = root.barIsVertical ? (parent.height - root.barMarginV * 2) : Style.barHeight
|
||||
if (!root.barIsVertical)
|
||||
return baseHeight + root.attachmentOverlap
|
||||
return baseHeight
|
||||
return baseHeight // Vertical bars extend via width, not height
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,25 @@ Variants {
|
||||
}
|
||||
}
|
||||
|
||||
// Bar content in separate windows to prevent fullscreen redraws
|
||||
Loader {
|
||||
active: {
|
||||
if (!parent.windowLoaded || !parent.shouldBeActive || !BarService.isVisible)
|
||||
return false
|
||||
|
||||
// Check if bar is configured for this screen
|
||||
var monitors = Settings.data.bar.monitors || []
|
||||
return monitors.length === 0 || monitors.includes(modelData?.name)
|
||||
}
|
||||
asynchronous: false
|
||||
|
||||
sourceComponent: BarContentWindow {}
|
||||
|
||||
onLoaded: {
|
||||
Logger.d("Shell", "BarContentWindow created for", modelData?.name)
|
||||
}
|
||||
}
|
||||
|
||||
// BarExclusionZone - created after MainScreen has fully loaded
|
||||
// Disabled when bar is hidden or not configured for this screen
|
||||
Loader {
|
||||
|
||||
@@ -56,6 +56,7 @@ Item {
|
||||
BarBackground {
|
||||
bar: root.bar
|
||||
shapeContainer: backgroundsShape
|
||||
windowRoot: root.windowRoot
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import qs.Commons
|
||||
import qs.Services.UI
|
||||
import qs.Modules.MainScreen.Backgrounds
|
||||
|
||||
|
||||
@@ -25,6 +26,24 @@ ShapePath {
|
||||
// Required reference to AllBackgrounds shapeContainer
|
||||
required property var shapeContainer
|
||||
|
||||
// Required reference to windowRoot for screen access
|
||||
required property var windowRoot
|
||||
|
||||
// Check if bar should be visible on this screen
|
||||
readonly property bool shouldShowBar: {
|
||||
// Check global bar visibility
|
||||
if (!BarService.isVisible)
|
||||
return false
|
||||
|
||||
// Check screen-specific configuration
|
||||
var monitors = Settings.data.bar.monitors || []
|
||||
var screenName = windowRoot?.screen?.name || ""
|
||||
|
||||
// If no monitors specified, show on all screens
|
||||
// If monitors specified, only show if this screen is in the list
|
||||
return monitors.length === 0 || monitors.includes(screenName)
|
||||
}
|
||||
|
||||
// Corner radius (from Style)
|
||||
readonly property real radius: Style.radiusL
|
||||
|
||||
@@ -64,7 +83,7 @@ ShapePath {
|
||||
|
||||
// ShapePath configuration
|
||||
strokeWidth: -1 // No stroke, fill only
|
||||
fillColor: Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity)
|
||||
fillColor: shouldShowBar ? Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity) : Color.transparent
|
||||
|
||||
// Starting position (top-left corner, after the arc)
|
||||
// Use mapped coordinates relative to the Shape container
|
||||
|
||||
72
Modules/MainScreen/BarContentWindow.qml
Normal file
72
Modules/MainScreen/BarContentWindow.qml
Normal file
@@ -0,0 +1,72 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Commons
|
||||
import qs.Services.UI
|
||||
import qs.Modules.Bar
|
||||
|
||||
|
||||
/**
|
||||
* BarContentWindow - Separate transparent PanelWindow for bar content
|
||||
*
|
||||
* This window contains only the bar widgets (content), while the background
|
||||
* is rendered in MainScreen's unified Shape system. This separation prevents
|
||||
* fullscreen redraws when bar widgets redraw.
|
||||
*/
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
delegate: Loader {
|
||||
id: barWindowLoader
|
||||
|
||||
required property ShellScreen modelData
|
||||
|
||||
// Only create window if bar should be visible on this screen
|
||||
active: {
|
||||
if (!modelData || !modelData.name)
|
||||
return false
|
||||
var monitors = Settings.data.bar.monitors || []
|
||||
return BarService.isVisible && (monitors.length === 0 || monitors.includes(modelData.name))
|
||||
}
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
id: barWindow
|
||||
screen: modelData
|
||||
|
||||
color: Color.transparent // Transparent - background is in MainScreen below
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.d("BarContentWindow", "Bar content window created for screen:", screen?.name)
|
||||
}
|
||||
|
||||
// Wayland layer configuration
|
||||
WlrLayershell.namespace: "noctalia-bar-content-" + (screen?.name || "unknown")
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore // Don't reserve space - BarExclusionZone in MainScreen handles that
|
||||
|
||||
// Position and size to match bar location
|
||||
readonly property string barPosition: Settings.data.bar.position || "top"
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property bool barFloating: Settings.data.bar.floating || false
|
||||
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
|
||||
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
|
||||
|
||||
// Anchor to the bar's edge
|
||||
anchors {
|
||||
top: barPosition === "top" || barIsVertical
|
||||
bottom: barPosition === "bottom" || barIsVertical
|
||||
left: barPosition === "left" || !barIsVertical
|
||||
right: barPosition === "right" || !barIsVertical
|
||||
}
|
||||
// Set to FULL screen dimensions - margins will reduce the actual window size
|
||||
implicitWidth: (barIsVertical ? (Style.barHeight + 1) : screen.width) + barMarginH
|
||||
implicitHeight: (barIsVertical ? screen.height : Style.barHeight) + barMarginV
|
||||
|
||||
// Bar content - just the widgets, no background
|
||||
Bar {
|
||||
anchors.fill: parent
|
||||
screen: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,12 +101,11 @@ PanelWindow {
|
||||
// Bar region - subtract bar area from mask
|
||||
Region {
|
||||
id: barMaskRegion
|
||||
property var barRegion: barLoader.item?.barRegion
|
||||
|
||||
x: barRegion?.x ?? 0
|
||||
y: barRegion?.y ?? 0
|
||||
width: barRegion?.width ?? 0
|
||||
height: barRegion?.height ?? 0
|
||||
x: barPlaceholder.x
|
||||
y: barPlaceholder.y
|
||||
width: barPlaceholder.width
|
||||
height: barPlaceholder.height
|
||||
intersection: Intersection.Subtract
|
||||
}
|
||||
|
||||
@@ -133,7 +132,7 @@ PanelWindow {
|
||||
Backgrounds.AllBackgrounds {
|
||||
id: unifiedBackgrounds
|
||||
anchors.fill: parent
|
||||
bar: barLoader.item?.barItem || null
|
||||
bar: barPlaceholder.barItem || null
|
||||
windowRoot: root
|
||||
z: 0 // Behind all content
|
||||
}
|
||||
@@ -309,28 +308,108 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// Bar (always on top - rendered last in tree, so naturally on top)
|
||||
Loader {
|
||||
id: barLoader
|
||||
asynchronous: false
|
||||
sourceComponent: Bar {}
|
||||
// Keep bar loaded but hide it when BarService.isVisible is false
|
||||
// This allows panels to remain accessible via IPC
|
||||
visible: BarService.isVisible
|
||||
// Bar placeholder - just for background positioning (actual bar content is in BarContentWindow)
|
||||
Item {
|
||||
id: barPlaceholder
|
||||
|
||||
// Fill parent to provide dimensions for Bar to reference
|
||||
anchors.fill: parent
|
||||
// Expose self as barItem for AllBackgrounds compatibility
|
||||
readonly property var barItem: barPlaceholder
|
||||
|
||||
// Screen reference
|
||||
property ShellScreen screen: root.screen
|
||||
|
||||
onLoaded: {
|
||||
if (item) {
|
||||
Logger.d("MainScreen", "Bar loaded with screen", item.screen?.name)
|
||||
// Bind screen to bar component (use binding for reactivity)
|
||||
item.screen = Qt.binding(function () {
|
||||
return barLoader.screen
|
||||
})
|
||||
// Bar positioning properties (match Bar.qml logic)
|
||||
readonly property string barPosition: Settings.data.bar.position || "top"
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property bool barFloating: Settings.data.bar.floating || false
|
||||
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
|
||||
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
|
||||
|
||||
// Expose bar dimensions directly on this Item for BarBackground
|
||||
// Use screen dimensions directly
|
||||
x: {
|
||||
if (barPosition === "right")
|
||||
return screen.width - Style.barHeight - barMarginH
|
||||
return barMarginH
|
||||
}
|
||||
y: {
|
||||
if (barPosition === "bottom")
|
||||
return screen.height - Style.barHeight - barMarginV
|
||||
return barMarginV
|
||||
}
|
||||
width: {
|
||||
if (barIsVertical) {
|
||||
return Style.barHeight + 1
|
||||
}
|
||||
return screen.width - barMarginH * 2
|
||||
}
|
||||
height: {
|
||||
if (barIsVertical) {
|
||||
return screen.height - barMarginV * 2
|
||||
}
|
||||
return Style.barHeight
|
||||
}
|
||||
|
||||
// Corner states (same as Bar.qml)
|
||||
readonly property int topLeftCornerState: {
|
||||
if (barFloating)
|
||||
return 0
|
||||
if (barPosition === "top")
|
||||
return -1
|
||||
if (barPosition === "left")
|
||||
return -1
|
||||
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "right")) {
|
||||
return barIsVertical ? 1 : 2
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
readonly property int topRightCornerState: {
|
||||
if (barFloating)
|
||||
return 0
|
||||
if (barPosition === "top")
|
||||
return -1
|
||||
if (barPosition === "right")
|
||||
return -1
|
||||
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "left")) {
|
||||
return barIsVertical ? 1 : 2
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
readonly property int bottomLeftCornerState: {
|
||||
if (barFloating)
|
||||
return 0
|
||||
if (barPosition === "bottom")
|
||||
return -1
|
||||
if (barPosition === "left")
|
||||
return -1
|
||||
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "right")) {
|
||||
return barIsVertical ? 1 : 2
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
readonly property int bottomRightCornerState: {
|
||||
if (barFloating)
|
||||
return 0
|
||||
if (barPosition === "bottom")
|
||||
return -1
|
||||
if (barPosition === "right")
|
||||
return -1
|
||||
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "left")) {
|
||||
return barIsVertical ? 1 : 2
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.d("MainScreen", "===== Bar placeholder loaded =====")
|
||||
Logger.d("MainScreen", " Screen:", screen?.name, "Size:", screen?.width, "x", screen?.height)
|
||||
Logger.d("MainScreen", " Bar position:", barPosition, "| isVertical:", barIsVertical)
|
||||
Logger.d("MainScreen", " Bar dimensions: x=" + x, "y=" + y, "width=" + width, "height=" + height)
|
||||
Logger.d("MainScreen", " Style.barHeight =", Style.barHeight)
|
||||
Logger.d("MainScreen", " Margins: H=" + barMarginH, "V=" + barMarginV, "| Floating:", barFloating)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import qs.Services.UI
|
||||
|
||||
// Modules
|
||||
import qs.Modules.Background
|
||||
import qs.Modules.Bar
|
||||
import qs.Modules.Dock
|
||||
import qs.Modules.MainScreen
|
||||
import qs.Modules.LockScreen
|
||||
@@ -106,7 +107,7 @@ ShellRoot {
|
||||
// Item that needs to exists in the shell.
|
||||
IPCService {}
|
||||
|
||||
// MainScreen for each screen (manages bar + all panels)
|
||||
// MainScreen for each screen
|
||||
AllScreens {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user