widgets: add a way to show cpu intensive ones

This commit is contained in:
Lemmy
2026-02-19 21:30:19 -05:00
parent a479984555
commit 3541ae9548
8 changed files with 122 additions and 65 deletions
+1
View File
@@ -965,6 +965,7 @@
"clock-style-label": "Clock style",
"clock-style-minimal": "Minimal",
"clock-width-description": "Width of the clock widget in pixels.",
"cpu-intensive-note": "Widgets marked with ! use more CPU and should be enabled mindfully.",
"edit-mode-button-label": "Enter edit mode",
"edit-mode-controls-explanation": "Left-click & drag: Move or resize the widget.\nRight-click: Open the context menu options.",
"edit-mode-description": "Enable edit mode to move and reposition desktop widgets. When enabled, widgets show a drag outline and can be repositioned.",
+1
View File
@@ -33,6 +33,7 @@ Singleton {
"media-next": "player-skip-forward-filled",
"download-speed": "download",
"upload-speed": "upload",
"cpu-intensive": "alert-octagon",
"cpu-usage": "brand-speedtest",
"cpu-temperature": "flame",
"gpu-temperature": "device-desktop",
@@ -117,6 +117,7 @@ NBox {
for (var i = 0; i < widgetIds.length; i++) {
var id = widgetIds[i];
var displayName = id;
const badges = [];
if (BarWidgetRegistry.isPluginWidget(id)) {
var pluginId = id.replace("plugin:", "");
var manifest = PluginRegistry.getPluginManifest(pluginId);
@@ -125,10 +126,21 @@ NBox {
} else {
displayName = pluginId;
}
badges.push({
"icon": "plugin",
"color": Color.mSecondary
});
}
if (BarWidgetRegistry.isCpuIntensive(id)) {
badges.push({
"icon": "cpu-intensive",
"color": Color.mSecondary
});
}
availableWidgetsModel.append({
"key": id,
"name": displayName
"name": displayName,
"badges": badges
});
}
}
@@ -36,29 +36,80 @@ ColumnLayout {
onToggled: checked => Settings.data.desktopWidgets.enabled = checked
}
NButton {
ColumnLayout {
enabled: Settings.data.desktopWidgets.enabled
Layout.fillWidth: true
text: DesktopWidgetRegistry.editMode ? I18n.tr("panels.desktop-widgets.edit-mode-exit-button") : I18n.tr("panels.desktop-widgets.edit-mode-button-label")
icon: "edit"
onClicked: {
DesktopWidgetRegistry.editMode = !DesktopWidgetRegistry.editMode;
if (DesktopWidgetRegistry.editMode && Settings.data.ui.settingsPanelMode !== "window") {
var item = root.parent;
while (item) {
if (item.closeRequested !== undefined) {
item.closeRequested();
break;
NLabel {
description: I18n.tr("panels.desktop-widgets.cpu-intensive-note")
}
NButton {
Layout.fillWidth: true
Layout.topMargin: Style.marginM
Layout.bottomMargin: Style.marginM
text: DesktopWidgetRegistry.editMode ? I18n.tr("panels.desktop-widgets.edit-mode-exit-button") : I18n.tr("panels.desktop-widgets.edit-mode-button-label")
icon: "edit"
onClicked: {
DesktopWidgetRegistry.editMode = !DesktopWidgetRegistry.editMode;
if (DesktopWidgetRegistry.editMode && Settings.data.ui.settingsPanelMode !== "window") {
var item = root.parent;
while (item) {
if (item.closeRequested !== undefined) {
item.closeRequested();
break;
}
item = item.parent;
}
item = item.parent;
}
}
}
// One NSectionEditor per monitor
Repeater {
model: Quickshell.screens
NSectionEditor {
required property var modelData
Layout.fillWidth: true
sectionName: modelData.name
sectionSubtitle: {
var compositorScale = CompositorService.getDisplayScale(modelData.name);
// Format scale to 2 decimal places to prevent overly long text
var formattedScale = compositorScale.toFixed(2);
return "(" + modelData.width + "x" + modelData.height + " @ " + formattedScale + "x)";
}
sectionId: modelData.name
screen: modelData
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/DesktopWidgets/DesktopWidgetSettingsDialog.qml")
widgetRegistry: DesktopWidgetRegistry
widgetModel: getWidgetsForMonitor(modelData.name)
availableWidgets: root.availableWidgetsModel
availableSections: root.getScreenNames()
sectionLabels: root.getScreenLabels()
sectionIcons: root.getScreenIcons()
draggable: false // Desktop widgets are positioned by X,Y, not list order
maxWidgets: -1
onAddWidget: (widgetId, section) => _addWidgetToMonitor(modelData.name, widgetId)
onRemoveWidget: (section, index) => _removeWidgetFromMonitor(modelData.name, index)
onMoveWidget: (fromSection, index, toSection) => _moveWidgetToMonitor(fromSection, index, toSection)
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsForMonitor(modelData.name, index, settings)
onOpenPluginSettingsRequested: manifest => pluginSettingsDialog.openPluginSettings(manifest)
}
}
}
NDivider {
visible: Settings.data.desktopWidgets.enabled
Layout.fillWidth: true
// Shared Plugin Settings Popup
NPluginSettingsPopup {
id: pluginSettingsDialog
parent: Overlay.overlay
showToastOnSave: false
}
Component.onCompleted: {
// Use Qt.callLater to ensure DesktopWidgetRegistry is ready
Qt.callLater(updateAvailableWidgetsModel);
}
// Helper to get screen names array
@@ -89,54 +140,6 @@ ColumnLayout {
return icons;
}
// One NSectionEditor per monitor
Repeater {
model: Quickshell.screens
NSectionEditor {
enabled: Settings.data.desktopWidgets.enabled
required property var modelData
Layout.fillWidth: true
sectionName: modelData.name
sectionSubtitle: {
var compositorScale = CompositorService.getDisplayScale(modelData.name);
// Format scale to 2 decimal places to prevent overly long text
var formattedScale = compositorScale.toFixed(2);
return "(" + modelData.width + "x" + modelData.height + " @ " + formattedScale + "x)";
}
sectionId: modelData.name
screen: modelData
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/DesktopWidgets/DesktopWidgetSettingsDialog.qml")
widgetRegistry: DesktopWidgetRegistry
widgetModel: getWidgetsForMonitor(modelData.name)
availableWidgets: root.availableWidgetsModel
availableSections: root.getScreenNames()
sectionLabels: root.getScreenLabels()
sectionIcons: root.getScreenIcons()
draggable: false // Desktop widgets are positioned by X,Y, not list order
maxWidgets: -1
onAddWidget: (widgetId, section) => _addWidgetToMonitor(modelData.name, widgetId)
onRemoveWidget: (section, index) => _removeWidgetFromMonitor(modelData.name, index)
onMoveWidget: (fromSection, index, toSection) => _moveWidgetToMonitor(fromSection, index, toSection)
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsForMonitor(modelData.name, index, settings)
onOpenPluginSettingsRequested: manifest => pluginSettingsDialog.openPluginSettings(manifest)
}
}
// Shared Plugin Settings Popup
NPluginSettingsPopup {
id: pluginSettingsDialog
parent: Overlay.overlay
showToastOnSave: false
}
Component.onCompleted: {
// Use Qt.callLater to ensure DesktopWidgetRegistry is ready
Qt.callLater(updateAvailableWidgetsModel);
}
function updateAvailableWidgetsModel() {
availableWidgets.clear();
try {
@@ -179,6 +182,12 @@ ColumnLayout {
"color": Color.mSecondary
});
}
if (DesktopWidgetRegistry.isCpuIntensive(widgetId)) {
badges.push({
"icon": "cpu-intensive",
"color": Color.mSecondary
});
}
availableWidgets.append({
"key": widgetId,
+8
View File
@@ -475,6 +475,14 @@ Singleton {
return id.startsWith("plugin:");
}
property var cpuIntensiveWidgets: ["AudioVisualizer"]
function isCpuIntensive(id) {
if (pluginWidgetMetadata[id]?.cpuIntensive)
return true;
return cpuIntensiveWidgets.indexOf(id) >= 0;
}
// Get list of plugin widget IDs
function getPluginWidgets() {
return Object.keys(pluginWidgets);
@@ -37,6 +37,8 @@ Singleton {
}
})
property var cpuIntensiveWidgets: ["SystemStat"]
// Component definitions - these are loaded once at startup
property Component airplaneModeComponent: Component {
AirplaneMode {}
@@ -152,4 +154,10 @@ Singleton {
function getPluginWidgets() {
return Object.keys(pluginWidgets);
}
function isCpuIntensive(id) {
if (pluginWidgetMetadata[id]?.cpuIntensive)
return true;
return cpuIntensiveWidgets.indexOf(id) >= 0;
}
}
+8
View File
@@ -81,6 +81,8 @@ Singleton {
}
})
property var cpuIntensiveWidgets: ["SystemStat"]
// Plugin widget storage (mirroring BarWidgetRegistry pattern)
property var pluginWidgets: ({})
property var pluginWidgetMetadata: ({})
@@ -111,6 +113,12 @@ Singleton {
return widgetMetadata[id] !== undefined;
}
function isCpuIntensive(id) {
if (pluginWidgetMetadata[id]?.cpuIntensive)
return true;
return cpuIntensiveWidgets.indexOf(id) >= 0;
}
// Check if a widget is a plugin widget
function isPluginWidget(id) {
return id.startsWith("plugin:");
+10
View File
@@ -494,6 +494,16 @@ NBox {
Layout.preferredHeight: Style.baseWidgetSize * 0.5
}
// CPU-intensive indicator icon
NIcon {
visible: root.widgetRegistry && root.widgetRegistry.isCpuIntensive(modelData.id)
icon: "cpu-intensive"
pointSize: Style.fontSizeXXS
color: root.getWidgetColor(modelData)[1]
Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.5 : 0
Layout.preferredHeight: Style.baseWidgetSize * 0.5
}
RowLayout {
spacing: 0
Layout.preferredWidth: buttonsCount * buttonsWidth * Style.uiScaleRatio