mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Merge branch 'main' of https://github.com/noctalia-dev/noctalia-shell
This commit is contained in:
@@ -433,6 +433,10 @@
|
||||
"description": "Choose how workspace labels are displayed.",
|
||||
"label": "Label mode"
|
||||
},
|
||||
"unfocused-icons-opacity": {
|
||||
"description": "Set the opacity level for unfocused app icons",
|
||||
"label": "Unfocused icons opacity"
|
||||
},
|
||||
"show-applications": {
|
||||
"description": "Display application icons inside each workspace.",
|
||||
"label": "Show applications"
|
||||
@@ -1077,9 +1081,13 @@
|
||||
"description": "Displays a visible border around every widget.",
|
||||
"label": "Show widget outlines"
|
||||
},
|
||||
"transparent": {
|
||||
"description": "This will prevent the panels from attaching to the bar.",
|
||||
"label": "Transparent background"
|
||||
"use-separate-opacity": {
|
||||
"description": "Enable to use a separate opacity value for the bar background.",
|
||||
"label": "Use separate bar opacity"
|
||||
},
|
||||
"background-opacity": {
|
||||
"description": "Set the background opacity specifically for the bar.",
|
||||
"label": "Bar background opacity"
|
||||
}
|
||||
},
|
||||
"monitors": {
|
||||
|
||||
@@ -1077,9 +1077,13 @@
|
||||
"description": "在每个小部件周围显示可见边框。",
|
||||
"label": "显示小部件轮廓"
|
||||
},
|
||||
"transparent": {
|
||||
"description": "这将阻止面板附加到工具栏。",
|
||||
"label": "透明背景"
|
||||
"use-separate-opacity": {
|
||||
"description": "启用后为任务栏背景使用单独的不透明度值。",
|
||||
"label": "使用单独的任务栏不透明度"
|
||||
},
|
||||
"background-opacity": {
|
||||
"description": "为任务栏设置背景不透明度。",
|
||||
"label": "任务栏背景不透明度"
|
||||
}
|
||||
},
|
||||
"monitors": {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"position": "top",
|
||||
"monitors": [],
|
||||
"density": "default",
|
||||
"transparent": false,
|
||||
"barBackgroundOpacity": 0.93,
|
||||
"useSeparateBarOpacity": false,
|
||||
"showOutline": false,
|
||||
"showCapsule": true,
|
||||
"capsuleOpacity": 1,
|
||||
@@ -354,12 +355,7 @@
|
||||
"autoHideMs": 2000,
|
||||
"overlayLayer": true,
|
||||
"backgroundOpacity": 1,
|
||||
"enabledTypes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4
|
||||
],
|
||||
"enabledTypes": [0, 1, 2, 4],
|
||||
"monitors": []
|
||||
},
|
||||
"audio": {
|
||||
@@ -436,4 +432,4 @@
|
||||
"gridSnap": false,
|
||||
"monitorWidgets": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,11 +189,14 @@ Singleton {
|
||||
property string position: "top" // "top", "bottom", "left", or "right"
|
||||
property list<string> monitors: [] // holds bar visibility per monitor
|
||||
property string density: "default" // "compact", "default", "comfortable"
|
||||
property bool transparent: false
|
||||
property bool showOutline: false
|
||||
property bool showCapsule: true
|
||||
property real capsuleOpacity: 1.0
|
||||
|
||||
// Bar background opacity settings
|
||||
property real backgroundOpacity: 0.93
|
||||
property bool useSeparateOpacity: false
|
||||
|
||||
// Floating bar settings
|
||||
property bool floating: false
|
||||
property real marginVertical: 0.25
|
||||
|
||||
@@ -54,6 +54,7 @@ Item {
|
||||
readonly property bool showApplications: (widgetSettings.showApplications !== undefined) ? widgetSettings.showApplications : widgetMetadata.showApplications
|
||||
readonly property bool showLabelsOnlyWhenOccupied: (widgetSettings.showLabelsOnlyWhenOccupied !== undefined) ? widgetSettings.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied
|
||||
readonly property bool colorizeIcons: (widgetSettings.colorizeIcons !== undefined) ? widgetSettings.colorizeIcons : widgetMetadata.colorizeIcons
|
||||
readonly property real unfocusedIconsOpacity: (widgetSettings.unfocusedIconsOpacity !== undefined) ? widgetSettings.unfocusedIconsOpacity : widgetMetadata.unfocusedIconsOpacity
|
||||
readonly property bool enableScrollWheel: (widgetSettings.enableScrollWheel !== undefined) ? widgetSettings.enableScrollWheel : widgetMetadata.enableScrollWheel
|
||||
|
||||
readonly property int itemSize: Math.round(Style.capsuleHeight * 0.8)
|
||||
@@ -833,6 +834,7 @@ Item {
|
||||
source: ThemeIcons.iconForAppId(model.appId)
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
opacity: model.isFocused ? Style.opacityFull : unfocusedIconsOpacity
|
||||
layer.enabled: root.colorizeIcons && !model.isFocused
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -27,73 +27,153 @@ Item {
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
// Wrapper with layer caching for better shadow performance
|
||||
// Unified background container
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
// Enable layer caching to prevent continuous re-rendering
|
||||
// This caches the Shape to a GPU texture, reducing GPU tessellation overhead
|
||||
layer.enabled: true
|
||||
|
||||
// Apply opacity to all backgrounds
|
||||
opacity: Settings.data.ui.panelBackgroundOpacity
|
||||
|
||||
// The unified Shape container
|
||||
Shape {
|
||||
id: backgroundsShape
|
||||
// When not using separate bar opacity, use unified approach (original behavior)
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
visible: !Settings.data.bar.useSeparateOpacity
|
||||
|
||||
// Use curve renderer for smooth corners (GPU-accelerated)
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
// Enable layer caching to prevent continuous re-rendering
|
||||
layer.enabled: true
|
||||
opacity: Settings.data.ui.panelBackgroundOpacity
|
||||
|
||||
enabled: false // Disable mouse input on the Shape itself
|
||||
Shape {
|
||||
id: unifiedBackgroundsShape
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
enabled: false
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.d("AllBackgrounds", "AllBackgrounds initialized");
|
||||
}
|
||||
|
||||
/**
|
||||
* Bar
|
||||
*/
|
||||
BarBackground {
|
||||
bar: root.bar
|
||||
shapeContainer: backgroundsShape
|
||||
windowRoot: root.windowRoot
|
||||
backgroundColor: Settings.data.bar.transparent ? Color.transparent : panelBackgroundColor
|
||||
}
|
||||
|
||||
/**
|
||||
* Panel Background Slots
|
||||
* Only 2 slots needed: one for currently open/opening panel, one for closing panel
|
||||
*/
|
||||
|
||||
// Slot 0: Currently open/opening panel
|
||||
PanelBackground {
|
||||
assignedPanel: {
|
||||
var p = PanelService.backgroundSlotAssignments[0];
|
||||
// Only render if this panel belongs to this screen
|
||||
return (p && p.screen === root.windowRoot.screen) ? p : null;
|
||||
Component.onCompleted: {
|
||||
Logger.d("AllBackgrounds", "AllBackgrounds initialized");
|
||||
}
|
||||
|
||||
/**
|
||||
* Bar
|
||||
*/
|
||||
BarBackground {
|
||||
bar: root.bar
|
||||
shapeContainer: unifiedBackgroundsShape
|
||||
windowRoot: root.windowRoot
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
/**
|
||||
* Panel Background Slots
|
||||
* Only 2 slots needed: one for currently open/opening panel, one for closing panel
|
||||
*/
|
||||
|
||||
// Slot 0: Currently open/opening panel
|
||||
PanelBackground {
|
||||
assignedPanel: {
|
||||
var p = PanelService.backgroundSlotAssignments[0];
|
||||
// Only render if this panel belongs to this screen
|
||||
return (p && p.screen === root.windowRoot.screen) ? p : null;
|
||||
}
|
||||
shapeContainer: unifiedBackgroundsShape
|
||||
defaultBackgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Slot 1: Closing panel (during transitions)
|
||||
PanelBackground {
|
||||
assignedPanel: {
|
||||
var p = PanelService.backgroundSlotAssignments[1];
|
||||
// Only render if this panel belongs to this screen
|
||||
return (p && p.screen === root.windowRoot.screen) ? p : null;
|
||||
}
|
||||
shapeContainer: unifiedBackgroundsShape
|
||||
defaultBackgroundColor: panelBackgroundColor
|
||||
}
|
||||
shapeContainer: backgroundsShape
|
||||
defaultBackgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Slot 1: Closing panel (during transitions)
|
||||
PanelBackground {
|
||||
assignedPanel: {
|
||||
var p = PanelService.backgroundSlotAssignments[1];
|
||||
// Only render if this panel belongs to this screen
|
||||
return (p && p.screen === root.windowRoot.screen) ? p : null;
|
||||
}
|
||||
shapeContainer: backgroundsShape
|
||||
defaultBackgroundColor: panelBackgroundColor
|
||||
// Apply shadow to the unified backgrounds
|
||||
NDropShadow {
|
||||
anchors.fill: parent
|
||||
source: unifiedBackgroundsShape
|
||||
}
|
||||
}
|
||||
|
||||
// Apply shadow to the cached layer
|
||||
NDropShadow {
|
||||
// When using separate bar opacity, separate the rendering
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
source: backgroundsShape
|
||||
visible: Settings.data.bar.useSeparateOpacity
|
||||
|
||||
// Panel backgrounds with panel opacity
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
layer.enabled: true
|
||||
opacity: Settings.data.ui.panelBackgroundOpacity
|
||||
|
||||
Shape {
|
||||
id: panelBackgroundsShape
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
enabled: false
|
||||
|
||||
/**
|
||||
* Panel Background Slots
|
||||
* Only 2 slots needed: one for currently open/opening panel, one for closing panel
|
||||
*/
|
||||
|
||||
// Slot 0: Currently open/opening panel
|
||||
PanelBackground {
|
||||
assignedPanel: {
|
||||
var p = PanelService.backgroundSlotAssignments[0];
|
||||
// Only render if this panel belongs to this screen
|
||||
return (p && p.screen === root.windowRoot.screen) ? p : null;
|
||||
}
|
||||
shapeContainer: panelBackgroundsShape
|
||||
defaultBackgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Slot 1: Closing panel (during transitions)
|
||||
PanelBackground {
|
||||
assignedPanel: {
|
||||
var p = PanelService.backgroundSlotAssignments[1];
|
||||
// Only render if this panel belongs to this screen
|
||||
return (p && p.screen === root.windowRoot.screen) ? p : null;
|
||||
}
|
||||
shapeContainer: panelBackgroundsShape
|
||||
defaultBackgroundColor: panelBackgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
// Apply shadow to the panel backgrounds
|
||||
NDropShadow {
|
||||
anchors.fill: parent
|
||||
source: panelBackgroundsShape
|
||||
}
|
||||
}
|
||||
|
||||
// Bar background with separate opacity
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
layer.enabled: true
|
||||
opacity: Settings.data.bar.backgroundOpacity
|
||||
|
||||
Shape {
|
||||
id: barBackgroundShape
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
enabled: false
|
||||
|
||||
BarBackground {
|
||||
bar: root.bar
|
||||
shapeContainer: barBackgroundShape
|
||||
windowRoot: root.windowRoot
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
NDropShadow {
|
||||
anchors.fill: parent
|
||||
source: barBackgroundShape
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,38 +149,45 @@ Item {
|
||||
buttonItem = BarService.lookupWidget(buttonName, screen.name);
|
||||
}
|
||||
|
||||
if (buttonItem) {
|
||||
root.buttonItem = buttonItem;
|
||||
// Map button position within its window
|
||||
var buttonLocal = buttonItem.mapToItem(null, 0, 0);
|
||||
// Validate buttonItem is a valid QML Item with mapToItem function
|
||||
if (buttonItem && typeof buttonItem.mapToItem === "function") {
|
||||
try {
|
||||
root.buttonItem = buttonItem;
|
||||
// Map button position within its window
|
||||
var buttonLocal = buttonItem.mapToItem(null, 0, 0);
|
||||
|
||||
// Calculate the bar window's position on screen based on bar settings
|
||||
// The BarContentWindow uses anchors, so we need to compute its position
|
||||
var barWindowX = 0;
|
||||
var barWindowY = 0;
|
||||
var screenWidth = root.screen?.width || 0;
|
||||
var screenHeight = root.screen?.height || 0;
|
||||
// Calculate the bar window's position on screen based on bar settings
|
||||
// The BarContentWindow uses anchors, so we need to compute its position
|
||||
var barWindowX = 0;
|
||||
var barWindowY = 0;
|
||||
var screenWidth = root.screen?.width || 0;
|
||||
var screenHeight = root.screen?.height || 0;
|
||||
|
||||
if (root.barPosition === "right") {
|
||||
barWindowX = screenWidth - root.barMarginH - Style.barHeight;
|
||||
} else if (root.barPosition === "left") {
|
||||
barWindowX = root.barMarginH;
|
||||
if (root.barPosition === "right") {
|
||||
barWindowX = screenWidth - root.barMarginH - Style.barHeight;
|
||||
} else if (root.barPosition === "left") {
|
||||
barWindowX = root.barMarginH;
|
||||
}
|
||||
// For top/bottom bars, barWindowX stays 0 (full width window)
|
||||
|
||||
if (root.barPosition === "bottom") {
|
||||
barWindowY = screenHeight - root.barMarginV - Style.barHeight;
|
||||
} else if (root.barPosition === "top") {
|
||||
barWindowY = root.barMarginV;
|
||||
}
|
||||
// For left/right bars, barWindowY stays 0 (full height window)
|
||||
|
||||
root.buttonPosition = Qt.point(barWindowX + buttonLocal.x, barWindowY + buttonLocal.y);
|
||||
root.buttonWidth = buttonItem.width;
|
||||
root.buttonHeight = buttonItem.height;
|
||||
root.useButtonPosition = true;
|
||||
} catch (e) {
|
||||
Logger.w("SmartPanel", "Failed to get button position, using default positioning:", e);
|
||||
root.buttonItem = null;
|
||||
root.useButtonPosition = false;
|
||||
}
|
||||
// For top/bottom bars, barWindowX stays 0 (full width window)
|
||||
|
||||
if (root.barPosition === "bottom") {
|
||||
barWindowY = screenHeight - root.barMarginV - Style.barHeight;
|
||||
} else if (root.barPosition === "top") {
|
||||
barWindowY = root.barMarginV;
|
||||
}
|
||||
// For left/right bars, barWindowY stays 0 (full height window)
|
||||
|
||||
root.buttonPosition = Qt.point(barWindowX + buttonLocal.x, barWindowY + buttonLocal.y);
|
||||
root.buttonWidth = buttonItem.width;
|
||||
root.buttonHeight = buttonItem.height;
|
||||
root.useButtonPosition = true;
|
||||
} else {
|
||||
// No button provided: reset button position mode
|
||||
// No valid button provided: reset button position mode
|
||||
root.buttonItem = null;
|
||||
root.useButtonPosition = false;
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ SmartPanel {
|
||||
}
|
||||
|
||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||
return dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0);
|
||||
return dev && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0);
|
||||
}).length;
|
||||
return (availableCount === 0);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ ColumnLayout {
|
||||
property bool valueShowApplications: widgetData.showApplications !== undefined ? widgetData.showApplications : widgetMetadata.showApplications
|
||||
property bool valueShowLabelsOnlyWhenOccupied: widgetData.showLabelsOnlyWhenOccupied !== undefined ? widgetData.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied
|
||||
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons
|
||||
property real valueUnfocusedIconsOpacity: widgetData.unfocusedIconsOpacity !== undefined ? widgetData.unfocusedIconsOpacity : widgetMetadata.unfocusedIconsOpacity
|
||||
property bool valueEnableScrollWheel: widgetData.enableScrollWheel !== undefined ? widgetData.enableScrollWheel : widgetMetadata.enableScrollWheel
|
||||
|
||||
function saveSettings() {
|
||||
@@ -32,6 +33,7 @@ ColumnLayout {
|
||||
settings.showApplications = valueShowApplications;
|
||||
settings.showLabelsOnlyWhenOccupied = valueShowLabelsOnlyWhenOccupied;
|
||||
settings.colorizeIcons = valueColorizeIcons;
|
||||
settings.unfocusedIconsOpacity = valueUnfocusedIconsOpacity;
|
||||
settings.enableScrollWheel = valueEnableScrollWheel;
|
||||
return settings;
|
||||
}
|
||||
@@ -115,4 +117,22 @@ ColumnLayout {
|
||||
onToggled: checked => valueColorizeIcons = checked
|
||||
visible: valueShowApplications
|
||||
}
|
||||
RowLayout {
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
NLabel {
|
||||
label: I18n.tr("bar.widget-settings.workspace.unfocused-icons-opacity.label")
|
||||
description: I18n.tr("bar.widget-settings.workspace.unfocused-icons-opacity.description")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: 1
|
||||
stepSize: 0.01
|
||||
value: valueUnfocusedIconsOpacity
|
||||
visible: valueShowApplications
|
||||
onMoved: value => valueUnfocusedIconsOpacity = value
|
||||
text: Math.floor(valueUnfocusedIconsOpacity * 100) + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,14 +86,30 @@ ColumnLayout {
|
||||
onSelected: key => Settings.data.bar.density = key
|
||||
}
|
||||
|
||||
// Use Separate Bar Opacity Toggle
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.bar.appearance.transparent.label")
|
||||
description: I18n.tr("settings.bar.appearance.transparent.description")
|
||||
checked: Settings.data.bar.transparent
|
||||
label: I18n.tr("settings.bar.appearance.use-separate-opacity.label")
|
||||
description: I18n.tr("settings.bar.appearance.use-separate-opacity.description")
|
||||
checked: Settings.data.bar.useSeparateOpacity
|
||||
isSettings: true
|
||||
defaultValue: Settings.getDefaultValue("bar.transparent")
|
||||
onToggled: checked => Settings.data.bar.transparent = checked
|
||||
defaultValue: Settings.getDefaultValue("bar.useSeparateOpacity")
|
||||
onToggled: checked => Settings.data.bar.useSeparateOpacity = checked
|
||||
}
|
||||
|
||||
// Bar Background Opacity (only visible when separate opacity is enabled)
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
visible: Settings.data.bar.useSeparateOpacity
|
||||
label: I18n.tr("settings.bar.appearance.background-opacity.label")
|
||||
description: I18n.tr("settings.bar.appearance.background-opacity.description")
|
||||
from: 0
|
||||
to: 1
|
||||
stepSize: 0.01
|
||||
value: Settings.data.bar.backgroundOpacity
|
||||
isSettings: true
|
||||
defaultValue: Settings.getDefaultValue("bar.backgroundOpacity")
|
||||
onMoved: value => Settings.data.bar.backgroundOpacity = value
|
||||
text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%"
|
||||
}
|
||||
|
||||
NToggle {
|
||||
|
||||
@@ -60,7 +60,7 @@ Item {
|
||||
Timer {
|
||||
id: screenDetectorDebounce
|
||||
running: false
|
||||
interval: 20
|
||||
interval: 40
|
||||
onTriggered: {
|
||||
Logger.d("CurrentScreenDetector", "Screen debounced to:", root.detectedScreen?.name || "null");
|
||||
|
||||
@@ -77,8 +77,15 @@ Item {
|
||||
}
|
||||
|
||||
Logger.d("CurrentScreenDetector", "Executing callback on screen:", root.detectedScreen.name);
|
||||
root.pendingCallback(root.detectedScreen);
|
||||
// Store callback locally and clear pendingCallback first to prevent deadlock
|
||||
// if the callback throws an error
|
||||
var callback = root.pendingCallback;
|
||||
root.pendingCallback = null;
|
||||
try {
|
||||
callback(root.detectedScreen);
|
||||
} catch (e) {
|
||||
Logger.e("CurrentScreenDetector", "Callback failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
|
||||
@@ -222,6 +222,7 @@ Singleton {
|
||||
"showApplications": false,
|
||||
"showLabelsOnlyWhenOccupied": true,
|
||||
"colorizeIcons": false,
|
||||
"unfocusedIconsOpacity": 1.0,
|
||||
"enableScrollWheel": true
|
||||
},
|
||||
"Volume": {
|
||||
|
||||
Reference in New Issue
Block a user