Files
omarchycn/default/quickshell/bar/widgets/lockKeys.qml
T
Ryan Hughes a901d4a71f Add 5 widgets inspired by Noctalia: activeWindow, nightLight, keyboardLayout, lockKeys, spacer
- activeWindow: shows the focused toplevel title from Quickshell.Wayland
  ToplevelManager. Left-click activates, middle-click closes, right-click
  killactive. Hidden in vertical bars to avoid title rotation noise.
- nightLight: toggles omarchy-toggle-nightlight; status detected via
  pgrep hyprsunset. Hides when hyprsunset isn't installed.
- keyboardLayout: shows current xkb layout short code, click cycles via
  hyprctl switchxkblayout. Refreshes on Hyprland activelayout events.
- lockKeys: caps/num/scroll lock indicators read from /sys/class/leds.
  Uses plain A/1/S letters; hides each indicator when off.
- spacer: configurable blank space (size) for layout tuning.

Defaults add activeWindow to the left section and nightLight to the
right section between audioPanel and brightness.
2026-05-14 02:21:47 -04:00

97 lines
2.8 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Io
import "../common" as Common
Item {
id: root
property QtObject bar: null
property string moduleName: "lockKeys"
property var settings: ({})
property bool capsOn: false
property bool numOn: false
property bool scrollOn: false
property bool hideWhenOff: true
function setting(name, fallback) {
var value = settings ? settings[name] : undefined
return value === undefined || value === null ? fallback : value
}
Component.onCompleted: {
hideWhenOff = setting("hideWhenOff", true) === true
refresh()
}
function refresh() {
if (!stateProc.running) stateProc.running = true
}
Process {
id: stateProc
command: ["bash", "-lc", "cat /sys/class/leds/input*::capslock/brightness 2>/dev/null | head -1; cat /sys/class/leds/input*::numlock/brightness 2>/dev/null | head -1; cat /sys/class/leds/input*::scrolllock/brightness 2>/dev/null | head -1"]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: {
var lines = String(text || "").split("\n")
root.capsOn = parseInt(lines[0], 10) > 0
root.numOn = parseInt(lines[1], 10) > 0
root.scrollOn = parseInt(lines[2], 10) > 0
}
}
}
Timer {
interval: 1000
running: true
repeat: true
onTriggered: root.refresh()
}
readonly property bool anyOn: capsOn || numOn || scrollOn
visible: hideWhenOff ? anyOn : true
readonly property bool vertical: bar ? bar.vertical : false
implicitWidth: vertical ? (bar ? bar.barSize : 28) : (lay.item ? lay.item.implicitWidth + 8 : 0)
implicitHeight: vertical ? (lay.item ? lay.item.implicitHeight + 8 : 0) : (bar ? bar.barSize : 26)
Loader {
id: lay
anchors.centerIn: parent
sourceComponent: root.vertical ? colLayout : rowLayout
}
Component {
id: rowLayout
Row {
spacing: 4
LockGlyph { glyph: "A"; active: root.capsOn; visible: !root.hideWhenOff || root.capsOn }
LockGlyph { glyph: "1"; active: root.numOn; visible: !root.hideWhenOff || root.numOn }
LockGlyph { glyph: "S"; active: root.scrollOn; visible: !root.hideWhenOff || root.scrollOn }
}
}
Component {
id: colLayout
Column {
spacing: 2
LockGlyph { glyph: "A"; active: root.capsOn; visible: !root.hideWhenOff || root.capsOn }
LockGlyph { glyph: "1"; active: root.numOn; visible: !root.hideWhenOff || root.numOn }
LockGlyph { glyph: "S"; active: root.scrollOn; visible: !root.hideWhenOff || root.scrollOn }
}
}
component LockGlyph: Text {
property string glyph: ""
property bool active: false
text: glyph
color: active ? (root.bar ? root.bar.foreground : "#cacccc") : Qt.rgba(0.7, 0.7, 0.7, 0.3)
font.family: root.bar ? root.bar.fontFamily : "JetBrainsMono Nerd Font"
font.pixelSize: 11
}
}