diff --git a/Modules/Bar/Widgets/CustomButton.qml b/Modules/Bar/Widgets/CustomButton.qml
index f80f8ba..9ab1b11 100644
--- a/Modules/Bar/Widgets/CustomButton.qml
+++ b/Modules/Bar/Widgets/CustomButton.qml
@@ -1,12 +1,13 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
+import Quickshell.Io
import qs.Commons
import qs.Services
import qs.Widgets
import qs.Modules.SettingsPanel
-NIconButton {
+Item {
id: root
// Widget properties passed from Bar.qml
@@ -35,33 +36,80 @@ NIconButton {
readonly property string leftClickExec: widgetSettings.leftClickExec || widgetMetadata.leftClickExec
readonly property string rightClickExec: widgetSettings.rightClickExec || widgetMetadata.rightClickExec
readonly property string middleClickExec: widgetSettings.middleClickExec || widgetMetadata.middleClickExec
+ readonly property string textCommand: widgetSettings.textCommand !== undefined ? widgetSettings.textCommand : (widgetMetadata.textCommand || "")
+ readonly property int textIntervalMs: widgetSettings.textIntervalMs !== undefined ? widgetSettings.textIntervalMs : (widgetMetadata.textIntervalMs || 3000)
readonly property bool hasExec: (leftClickExec || rightClickExec || middleClickExec)
- enabled: hasExec
- allowClickWhenDisabled: true // we want to be able to open config with left click when its not setup properly
- colorBorder: Color.transparent
- colorBorderHover: Color.transparent
- sizeRatio: 0.8
- icon: customIcon
- tooltipText: {
- if (!hasExec) {
- return "Custom Button - Configure in settings"
- } else {
- var lines = []
- if (leftClickExec !== "") {
- lines.push(`Left click: ${leftClickExec}.`)
+ implicitWidth: pill.width
+ implicitHeight: pill.height
+
+ NPill {
+ id: pill
+
+ rightOpen: BarWidgetRegistry.getNPillDirection(root)
+ icon: customIcon
+ text: _dynamicText
+ autoHide: false
+ forceOpen: _dynamicText !== ""
+ forceClose: false
+ disableOpen: true
+ tooltipText: {
+ if (!hasExec) {
+ return "Custom Button - Configure in settings"
+ } else {
+ var lines = []
+ if (leftClickExec !== "") {
+ lines.push(`Left click: ${leftClickExec}.`)
+ }
+ if (rightClickExec !== "") {
+ lines.push(`Right click: ${rightClickExec}.`)
+ }
+ if (middleClickExec !== "") {
+ lines.push(`Middle click: ${middleClickExec}.`)
+ }
+ return lines.join("\n")
}
- if (rightClickExec !== "") {
- lines.push(`Right click: ${rightClickExec}.`)
- }
- if (middleClickExec !== "") {
- lines.push(`Middle click: ${middleClickExec}.`)
- }
- return lines.join("
")
+ }
+
+ onClicked: root.onClicked()
+ onRightClicked: root.onRightClicked()
+ onMiddleClicked: root.onMiddleClicked()
+ }
+
+ // Internal state for dynamic text
+ property string _dynamicText: ""
+
+ // Periodically run the text command (if set)
+ Timer {
+ id: refreshTimer
+ interval: Math.max(250, textIntervalMs)
+ repeat: true
+ running: (textCommand && textCommand.length > 0)
+ triggeredOnStart: true
+ onTriggered: {
+ if (!textCommand || textCommand.length === 0)
+ return
+ if (textProc.running)
+ return
+ textProc.command = ["sh", "-lc", textCommand]
+ textProc.running = true
}
}
- onClicked: {
+ Process {
+ id: textProc
+ stdout: StdioCollector {}
+ stderr: StdioCollector {}
+ onExited: (exitCode, exitStatus) => {
+ var out = String(stdout.text || "").trim()
+ if (out.indexOf("\n") !== -1) {
+ out = out.split("\n")[0]
+ }
+ _dynamicText = out
+ }
+ }
+
+ function onClicked() {
if (leftClickExec) {
Quickshell.execDetached(["sh", "-c", leftClickExec])
Logger.log("CustomButton", `Executing command: ${leftClickExec}`)
@@ -73,14 +121,14 @@ NIconButton {
}
}
- onRightClicked: {
+ function onRightClicked() {
if (rightClickExec) {
Quickshell.execDetached(["sh", "-c", rightClickExec])
Logger.log("CustomButton", `Executing command: ${rightClickExec}`)
}
}
- onMiddleClicked: {
+ function onMiddleClicked() {
if (middleClickExec) {
Quickshell.execDetached(["sh", "-c", middleClickExec])
Logger.log("CustomButton", `Executing command: ${middleClickExec}`)
diff --git a/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml b/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml
index b6a5d32..371d845 100644
--- a/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml
+++ b/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml
@@ -19,6 +19,8 @@ ColumnLayout {
settings.leftClickExec = leftClickExecInput.text
settings.rightClickExec = rightClickExecInput.text
settings.middleClickExec = middleClickExecInput.text
+ settings.textCommand = textCommandInput.text
+ settings.textIntervalMs = parseInt(textIntervalInput.text || textIntervalInput.placeholderText, 10)
return settings
}
@@ -228,4 +230,33 @@ ColumnLayout {
placeholderText: "Enter command to execute (app or custom script)"
text: widgetData.middleClickExec || widgetMetadata.middleClickExec
}
+
+ NDivider {
+ Layout.fillWidth: true
+ }
+
+ NText {
+ text: "Dynamic Text"
+ font.pointSize: Style.fontSizeM * scaling
+ font.weight: Style.fontWeightBold
+ color: Color.mPrimary
+ }
+
+ NTextInput {
+ id: textCommandInput
+ Layout.fillWidth: true
+ label: "Text Command"
+ description: "Shell command to run periodically (first line becomes the text)."
+ placeholderText: "echo \"Hello World\""
+ text: widgetData?.textCommand || widgetMetadata.textCommand
+ }
+
+ NTextInput {
+ id: textIntervalInput
+ Layout.fillWidth: true
+ label: "Refresh Interval"
+ description: "Interval in milliseconds."
+ placeholderText: String(widgetMetadata.textIntervalMs || 3000)
+ text: widgetData && widgetData.textIntervalMs !== undefined ? String(widgetData.textIntervalMs) : ""
+ }
}
diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml
index 4fbcd22..392b570 100644
--- a/Services/BarWidgetRegistry.qml
+++ b/Services/BarWidgetRegistry.qml
@@ -61,7 +61,9 @@ Singleton {
"icon": "heart",
"leftClickExec": "",
"rightClickExec": "",
- "middleClickExec": ""
+ "middleClickExec": "",
+ "textCommand": "",
+ "textIntervalMs": 3000
},
"Microphone": {
"allowUserSettings": true,