Desktop Widget Settings
A dedicated configuration interface for their desktop widget. Unlike the general Settings UI which configures plugin-wide settings. Desktop Widget Settings operate on per-instance widget data, the position, scale, and custom properties stored for each individual widget on the desktop.
Basic Structure
Section titled “Basic Structure”A Desktop Widget Settings component is a QML file that receives a pluginApi and a widgetSettings object:
import QtQuickimport QtQuick.Layoutsimport qs.Commonsimport qs.Widgets
ColumnLayout { id: root spacing: Style.marginM
// Plugin API (injected by the settings dialog system) property var pluginApi: null
// Widget settings object (injected by the settings dialog system) property var widgetSettings: null
// Local state - initialize from widgetSettings.data with metadata fallback property bool valueShowBackground: widgetSettings?.data?.showBackground ?? widgetSettings?.metadata?.showBackground ?? true
// Your settings controls here
NToggle { Layout.fillWidth: true label: "Show Background" description: "Display the widget background container" checked: root.valueShowBackground onToggled: checked => { root.valueShowBackground = checked; saveSettings(); } }
function saveSettings() { if (!widgetSettings) return; widgetSettings.data.showBackground = root.valueShowBackground; widgetSettings.save(); }}How It Works
Section titled “How It Works”When a user right-clicks a desktop widget and selects Widget Settings (or clicks the gear icon in the Desktop Widgets settings tab), Noctalia loads your desktopWidgetSettings component inside a DesktopWidgetSettingsDialog. The dialog injects two properties into your component:
pluginApi
Section titled “pluginApi”The standard Plugin API object. Use it to access plugin-wide settings, translations, manifest data, and more.
property var pluginApi: nullwidgetSettings
Section titled “widgetSettings”An object that provides access to the current widget instance’s data:
property var widgetSettings: nullThe widgetSettings object contains two variables and one function:
- Type:
object - Read-only: no
- Description: The current widget instance’s stored settings (position, scale, and any custom keys you’ve added). Modify this object directly.
metadata
Section titled “metadata”- Type: object
- Read-only: yes
- Description: Read-only default metadata registered by the
DesktopWidgetRegistryfor your widget. Use as fallback values.
save()
Section titled “save()”- Type: function
- Signature:
function save(): void - Description: Call this to persist the current
widgetSettings.datato disk.
Manifest Entry
Section titled “Manifest Entry”Register the desktop widget settings in your plugin’s manifest.json:
{ "id": "my-plugin", "name": "My Plugin", "version": "1.0.0", "entryPoints": { "desktopWidget": "DesktopWidget.qml", "desktopWidgetSettings": "DesktopWidgetSettings.qml" }, "metadata": { "defaultSettings": { "message": "Hello World", "enabled": true, "count": 0 } }}Local State Pattern
Section titled “Local State Pattern”Follows the same local state pattern used in the Settings UI.
Initialize local properties from widgetSettings.data with fallbacks to widgetSettings.metadata, pluginApi.pluginSettings or pluginApi.manifest.metadata.defaultSettings:
ColumnLayout { id: root spacing: Style.marginM
property var pluginApi: null property var widgetSettings: null
// Local state with metadata fallback property bool valueShowBackground: widgetSettings?.data?.showBackground ?? widgetSettings?.metadata?.showBackground ?? true
property bool valueRoundedCorners: widgetSettings?.data?.roundedCorners ?? widgetSettings?.metadata?.roundedCorners ?? true
property string valueLayout: widgetSettings?.data?.layout ?? pluginApi?.manifest?.metadata?.defaultSettings?.layout ?? "side"
function save() { if (!widgetSettings) return; widgetSettings.data.showBackground = root.valueShowBackground; widgetSettings.data.roundedCorners = root.valueRoundedCorners; widgetSettings.data.layout = root.valueLayout; widgetSettings.save(); }}settingsChanged signal
Section titled “settingsChanged signal”As an alternative to calling widgetSettings.save(), your component can emit a settingsChanged signal. The settings dialog listens for this signal (debounced at 150ms) and handles persistence automatically. You can also emit settingsSaved for immediate (non-debounced) persistence:
ColumnLayout { id: root
property var pluginApi: null property var widgetSettings: null
signal settingsChanged(var settings)
property bool valueShowBackground: widgetSettings?.data?.showBackground ?? widgetSettings?.metadata?.showBackground ?? true
function save() { var settings = Object.assign({}, widgetSettings?.data || {}); settings.showBackground = root.valueShowBackground; settingsChanged(settings); }
NToggle { Layout.fillWidth: true label: "Show Background" checked: root.valueShowBackground onToggled: checked => { root.valueShowBackground = checked; root.save(); } }}Complete Example
Section titled “Complete Example”Here’s a complete desktop widget settings example:
import QtQuickimport QtQuick.Layoutsimport qs.Commonsimport qs.Widgets
ColumnLayout { id: root
property var pluginApi: null property var widgetSettings: null
// Local state property string editMessage: widgetSettings?.data?.message ?? pluginApi?.manifest?.metadata?.defaultSettings?.message ?? "Hello World"
property color editBgColor: widgetSettings?.data?.backgroundColor ?? pluginApi?.manifest?.metadata?.defaultSettings?.backgroundColor ?? "#A9AEFE"
property bool editShowIcon: widgetSettings?.data?.showIcon ?? pluginApi?.manifest?.metadata?.defaultSettings?.showIcon ?? true
property int editRefreshRate: widgetSettings?.data?.refreshRate ?? pluginApi?.manifest?.metadata?.defaultSettings?.refreshRate ?? 30
// Have a toggle for the built-in showBackground value as well property bool showBackground: widgetSettings?.data?.showBackground ?? widgetSettings?.metadata?.showBackground ?? true
spacing: Style.marginM
Component.onCompleted: { Logger.i("MyPlugin", "Desktop Widget Settings loaded") }
// Text input NTextInput { Layout.fillWidth: true label: "Display Message" description: "The message shown in the bar widget" placeholderText: "Enter a message..." text: root.editMessage onTextChanged: { root.editMessage = text; root.saveSettings(); } }
// Color picker ColumnLayout { Layout.fillWidth: true spacing: Style.marginS
NLabel { label: "Background Color" description: "Widget background color" }
NColorPicker { Layout.preferredWidth: Style.sliderWidth Layout.preferredHeight: Style.baseWidgetSize selectedColor: root.editBgColor onColorSelected: function(color) { root.editBgColor = color; root.saveSettings(); } } }
NDivider { Layout.fillWidth: true Layout.topMargin: Style.marginS Layout.bottomMargin: Style.marginS }
// Toggle NToggle { Layout.fillWidth: true label: "Show Icon" description: "Display an icon next to the message" checked: root.editShowIcon onToggled: checked => { root.editShowIcon = checked; root.saveSettings(); } }
// Slider with label ColumnLayout { Layout.fillWidth: true spacing: Style.marginS
NLabel { label: "Refresh Rate" description: "Update interval in seconds: " + root.editRefreshRate }
NSlider { Layout.fillWidth: true from: 5 to: 120 stepSize: 5 value: root.editRefreshRate onValueChanged: { root.editRefreshRate = value; root.saveSettings(); } } }
// Show background toggle NToggle { Layout.fillWidth: true label: "Show Background" description: "Show the background of the desktop widget" checked: root.showBackground onToggled: checked => { root.showBackground = checked; root.saveSettings(); } } // Preview section NDivider { Layout.fillWidth: true Layout.topMargin: Style.marginS Layout.bottomMargin: Style.marginS }
NLabel { label: "Preview" }
Rectangle { Layout.fillWidth: true Layout.preferredHeight: 50 color: root.editBgColor radius: Style.radiusM
RowLayout { anchors.centerIn: parent spacing: Style.marginS
NIcon { icon: "heart" visible: root.editShowIcon color: Color.mOnPrimary }
NText { text: root.editMessage color: Color.mOnPrimary pointSize: Style.fontSizeM } } }
// Save function - called by the dialog function saveSettings() { if (!widgetSettings || !widgetSettings.data) { Logger.e("MyPlugin", "Cannot save: widgetSettings is null") return }
widgetSettings.data.message = root.editMessage widgetSettings.data.backgroundColor = root.editBgColor.toString() widgetSettings.data.showIcon = root.editShowIcon widgetSettings.data.refreshRate = root.editRefreshRate widgetSettings.data.showBackground = root.showBackground;
widgetSettings.save();
Logger.i("MyPlugin", "Settings saved successfully") }}Best Practices
Section titled “Best Practices”- Use for per-instance options only: Desktop widget settings should control appearance and behavior of a specific widget instance (background, colors, layout). Plugin-wide settings (API keys, global toggles) belong in the general
settingsentry point. - Provide metadata fallbacks: Always fall back to
widgetSettings.metadatavalues so widgets have sensible defaults before the user configures them. - Save on change: Use the live-save pattern, call
widgetSettings.save()immediately when values change. The system debounces writes automatically. - Use Noctalia widgets: Use
NToggle,NDropdown,NTextInput, and other Noctalia components for a consistent look.
See Also
Section titled “See Also”- Getting Started - Create your first plugin
- Bar Widget Development - Create bar widgets
- Desktop Widget Development - Create desktop widgets
- Panel Development - Create overlay panels
- Plugin API - Full API reference
- Manifest Reference - Plugin configuration