import QtQuick import QtQuick.Controls import QtQuick.Layouts import Quickshell import Quickshell.Bluetooth import Quickshell.Io import Quickshell.Networking import Quickshell.Services.Pipewire import Quickshell.Services.UPower import Quickshell.Wayland Scope { id: root property bool open: false property bool panelVisible: false property bool mediaOpen: false property bool notificationsOpen: false property bool osdOpen: false property string osdKind: "volume" property int brightness: 0 property var pendingNetwork: null property string wifiPassword: "" property var wifiDevice: Networking.devices.values.find(device => device.type === DeviceType.Wifi) property var bluetoothAdapter: Bluetooth.defaultAdapter property var audioSink: Pipewire.defaultAudioSink property var settings: statusSettings property alias cpuTemperature: statusBar.temperature property alias gpuTemperature: statusBar.gpuTemperature Settings { id: statusSettings } Bar { id: statusBar controlCenter: root settings: root.settings mediaPopup: mediaPopup toggleMedia: function() { root.mediaOpen = !root.mediaOpen } notificationCenter: notificationCenter } MediaPopup { id: mediaPopup open: root.mediaOpen onDismissed: root.mediaOpen = false } Notifications { id: notificationCenter open: root.notificationsOpen onDismissed: root.notificationsOpen = false } Osd { open: root.osdOpen kind: root.osdKind value: root.osdKind === "brightness" ? root.brightness / 100 : (root.audioSink && root.audioSink.audio ? root.audioSink.audio.volume : 0) muted: root.audioSink && root.audioSink.audio ? root.audioSink.audio.muted : false } function setBrightness(value) { const level = Math.max(0, Math.min(100, Math.round(value))); Quickshell.execDetached(["ddcutil", "setvcp", "10", String(level)]); root.brightness = level; } function connectWifi(network) { if (network.security === WifiSecurityType.Open) { network.connect(); return; } root.pendingNetwork = network; root.wifiPassword = ""; } function submitWifiPassword() { if (root.pendingNetwork && root.wifiPassword.length > 0) { root.pendingNetwork.connectWithPsk(root.wifiPassword); root.pendingNetwork = null; root.wifiPassword = ""; } } function showOsd(kind) { root.osdKind = kind; root.osdOpen = true; osdTimer.restart(); } function adjustBrightness(delta) { const current = root.brightness > 0 ? root.brightness : 50; root.setBrightness(current + delta); root.showOsd("brightness"); } function temperatureColor(value) { const match = String(value).match(/(\d+)C\s*$/); const temperature = match ? Number(match[1]) : -1; if (temperature < 0) return "#806d95"; if (temperature >= root.settings.temperatureCritical) return "#c94f6d"; if (temperature >= root.settings.temperatureWarning) return "#996315"; return "#4d7c38"; } function openPanel() { closePanelTimer.stop(); root.panelVisible = true; openPanelTimer.restart(); } function closePanel() { openPanelTimer.stop(); root.open = false; closePanelTimer.restart(); } function togglePanel() { if (root.open || root.panelVisible) root.closePanel(); else root.openPanel(); } Timer { id: openPanelTimer interval: 1 repeat: false onTriggered: root.open = true } Timer { id: closePanelTimer interval: 240 repeat: false onTriggered: root.panelVisible = false } IpcHandler { target: "controlcenter" function toggle() { root.togglePanel(); } function open() { root.openPanel(); } function close() { root.closePanel(); } } IpcHandler { target: "osd" function volume_up() { Quickshell.execDetached(["wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%+"]); root.showOsd("volume"); } function volume_down() { Quickshell.execDetached(["wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%-"]); root.showOsd("volume"); } function volume_mute() { Quickshell.execDetached(["wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle"]); root.showOsd("volume"); } function mic_mute() { Quickshell.execDetached(["wpctl", "set-mute", "@DEFAULT_AUDIO_SOURCE@", "toggle"]); root.showOsd("mic"); } function brightness_up() { root.adjustBrightness(5); } function brightness_down() { root.adjustBrightness(-5); } } Timer { id: osdTimer interval: 1400 repeat: false onTriggered: root.osdOpen = false } PwObjectTracker { objects: [root.audioSink] } Process { id: brightnessReader command: ["sh", "-c", "ddcutil getvcp 10 2>/dev/null | sed -n 's/.*current value = *\\([0-9]*\\).*/\\1/p'"] stdout: StdioCollector { onStreamFinished: { const value = parseInt(text.trim()); if (!isNaN(value)) root.brightness = value; } } } Timer { id: brightnessPoll interval: 3000 repeat: true running: root.open onTriggered: { if (!brightnessReader.running) brightnessReader.running = true; } } PanelWindow { visible: root.panelVisible color: "transparent" anchors { top: true bottom: true left: true right: true } exclusionMode: ExclusionMode.Ignore WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.keyboardFocus: root.panelVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None WlrLayershell.namespace: "quickshell-control-center" MouseArea { anchors.fill: parent onClicked: root.closePanel() } Rectangle { id: card width: Math.min(470, parent.width - 32) height: parent.height anchors.top: parent.top anchors.topMargin: 0 x: root.open ? parent.width - width - 16 : parent.width + 24 radius: 20 color: "#f5f2ea" border.color: "#d8d0c2" border.width: 1 z: 1 Behavior on x { NumberAnimation { duration: 220 easing.type: Easing.OutCubic } } MouseArea { anchors.fill: parent onClicked: mouse.accepted = true } ColumnLayout { id: content anchors.fill: parent anchors.margins: 18 spacing: 12 RowLayout { Layout.fillWidth: true ColumnLayout { Layout.fillWidth: true spacing: 0 Label { text: "Control center" color: "#252321" font.pixelSize: 22 font.bold: true } Label { text: "Niri / QuickShell" color: "#7c756c" font.pixelSize: 12 } } Button { text: "✕" ToolTip.visible: hovered ToolTip.text: "Close" onClicked: root.closePanel() } } ScrollView { Layout.fillWidth: true Layout.fillHeight: true clip: true ColumnLayout { width: parent.width spacing: 10 Rectangle { Layout.fillWidth: true implicitHeight: wifiColumn.implicitHeight + 24 radius: 14 color: "#e5f0ef" ColumnLayout { id: wifiColumn anchors.fill: parent anchors.margins: 12 spacing: 8 RowLayout { Layout.fillWidth: true Label { text: "Wi-Fi" color: "#1c666d" font.pixelSize: 16 font.bold: true Layout.fillWidth: true } Label { text: root.wifiDevice ? (root.wifiDevice.name || "Available") : "Unavailable" color: "#52777a" elide: Text.ElideRight } Switch { checked: Networking.wifiEnabled enabled: Networking.wifiHardwareEnabled onToggled: Networking.wifiEnabled = checked } } RowLayout { visible: root.wifiDevice !== null Layout.fillWidth: true Label { text: root.wifiDevice && root.wifiDevice.networks.values.find(network => network.connected) ? root.wifiDevice.networks.values.find(network => network.connected).name : "Not connected" color: "#252321" elide: Text.ElideRight Layout.fillWidth: true } Button { text: "Scan" onClicked: { if (root.wifiDevice) root.wifiDevice.scannerEnabled = true; } } } Repeater { model: root.wifiDevice ? root.wifiDevice.networks : null delegate: RowLayout { Layout.fillWidth: true spacing: 8 Label { text: modelData.name color: "#252321" elide: Text.ElideRight Layout.fillWidth: true } Label { text: modelData.connected ? "Connected" : Math.round(modelData.signalStrength) + "%" color: modelData.connected ? "#1c666d" : "#7c756c" } Button { text: modelData.connected ? "Disconnect" : "Connect" enabled: !modelData.stateChanging onClicked: modelData.connected ? modelData.disconnect() : root.connectWifi(modelData) } } } RowLayout { visible: root.pendingNetwork !== null Layout.fillWidth: true TextField { Layout.fillWidth: true placeholderText: "Password for " + (root.pendingNetwork ? root.pendingNetwork.name : "network") echoMode: TextInput.Password text: root.wifiPassword onTextChanged: root.wifiPassword = text onAccepted: root.submitWifiPassword() } Button { text: "Join" enabled: root.wifiPassword.length > 0 onClicked: root.submitWifiPassword() } } } } Rectangle { Layout.fillWidth: true implicitHeight: bluetoothColumn.implicitHeight + 24 radius: 14 color: "#eceafd" ColumnLayout { id: bluetoothColumn anchors.fill: parent anchors.margins: 12 spacing: 8 RowLayout { Layout.fillWidth: true Label { text: "Bluetooth" color: "#55499c" font.pixelSize: 16 font.bold: true Layout.fillWidth: true } Switch { checked: root.bluetoothAdapter ? root.bluetoothAdapter.enabled : false enabled: root.bluetoothAdapter !== null onToggled: { if (root.bluetoothAdapter) root.bluetoothAdapter.enabled = checked; } } Button { text: root.bluetoothAdapter && root.bluetoothAdapter.discovering ? "Stop scan" : "Scan" enabled: root.bluetoothAdapter && root.bluetoothAdapter.enabled onClicked: { if (root.bluetoothAdapter) root.bluetoothAdapter.discovering = !root.bluetoothAdapter.discovering; } } } Repeater { model: root.bluetoothAdapter ? root.bluetoothAdapter.devices : null delegate: RowLayout { Layout.fillWidth: true spacing: 8 ColumnLayout { Layout.fillWidth: true spacing: 0 Label { text: modelData.name || modelData.deviceName || "Unknown device" color: "#252321" elide: Text.ElideRight Layout.fillWidth: true } Label { text: modelData.connected ? "Connected" : (modelData.paired ? "Paired" : "Not paired") color: "#7c756c" font.pixelSize: 11 } } Label { visible: modelData.batteryAvailable text: Math.round(modelData.battery * 100) + "%" color: "#7c756c" } Button { text: modelData.connected ? "Disconnect" : (modelData.paired ? "Connect" : "Pair") onClicked: { if (modelData.connected) modelData.disconnect(); else if (modelData.paired) modelData.connect(); else modelData.pair(); } } } } } } Rectangle { Layout.fillWidth: true implicitHeight: audioColumn.implicitHeight + 24 radius: 14 color: "#fff1d7" ColumnLayout { id: audioColumn anchors.fill: parent anchors.margins: 12 spacing: 8 RowLayout { Layout.fillWidth: true Label { text: "Audio" color: "#996315" font.pixelSize: 16 font.bold: true Layout.fillWidth: true } Label { text: root.audioSink ? (root.audioSink.description || "Default output") : "Unavailable" color: "#806a48" elide: Text.ElideRight Layout.maximumWidth: 230 } } RowLayout { Layout.fillWidth: true Button { text: root.audioSink && root.audioSink.audio && root.audioSink.audio.muted ? "Unmute" : "Mute" enabled: root.audioSink && root.audioSink.audio onClicked: { if (root.audioSink && root.audioSink.audio) root.audioSink.audio.muted = !root.audioSink.audio.muted; } } Slider { Layout.fillWidth: true from: 0 to: 1 value: root.audioSink && root.audioSink.audio ? root.audioSink.audio.volume : 0 enabled: root.audioSink && root.audioSink.audio onMoved: { if (root.audioSink && root.audioSink.audio) root.audioSink.audio.volume = value; } } Label { text: root.audioSink && root.audioSink.audio ? Math.round(root.audioSink.audio.volume * 100) + "%" : "--" color: "#806a48" } } Repeater { model: Pipewire.nodes delegate: RowLayout { visible: modelData.isSink && !modelData.isStream Layout.fillWidth: true Label { text: modelData.description || modelData.name color: "#252321" elide: Text.ElideRight Layout.fillWidth: true } Button { text: modelData === root.audioSink ? "Default" : "Use" enabled: modelData !== root.audioSink onClicked: Pipewire.preferredDefaultAudioSink = modelData } } } } } Rectangle { Layout.fillWidth: true implicitHeight: displayColumn.implicitHeight + 24 radius: 14 color: "#f8e4dc" ColumnLayout { id: displayColumn anchors.fill: parent anchors.margins: 12 spacing: 8 RowLayout { Layout.fillWidth: true Label { text: "Display brightness" color: "#9e4d39" font.pixelSize: 16 font.bold: true Layout.fillWidth: true } Label { text: root.brightness > 0 ? root.brightness + "%" : "Unavailable" color: "#8b665b" } } Slider { Layout.fillWidth: true from: 1 to: 100 value: root.brightness enabled: root.brightness > 0 onPressedChanged: { if (!pressed) root.setBrightness(value); } } } } Rectangle { Layout.fillWidth: true implicitHeight: statusColumn.implicitHeight + 24 radius: 14 color: "#eee8f7" ColumnLayout { id: statusColumn anchors.fill: parent anchors.margins: 12 spacing: 8 RowLayout { Layout.fillWidth: true Label { text: "Status bar" color: "#684b8f" font.pixelSize: 16 font.bold: true Layout.fillWidth: true } Label { text: "Temperature" color: "#806d95" } } RowLayout { Layout.fillWidth: true Label { text: "CPU temperature" color: "#252321" Layout.fillWidth: true } Label { text: root.cpuTemperature color: root.temperatureColor(root.cpuTemperature) } } RowLayout { Layout.fillWidth: true Label { text: "GPU temperature" color: "#252321" Layout.fillWidth: true } Label { text: root.gpuTemperature color: root.temperatureColor(root.gpuTemperature) } } RowLayout { Layout.fillWidth: true Label { text: "Refresh interval" color: "#252321" Layout.fillWidth: true } ComboBox { model: ["1 second", "2 seconds", "5 seconds"] currentIndex: [1000, 2000, 5000].indexOf(root.settings.temperatureInterval) onActivated: root.settings.temperatureInterval = [1000, 2000, 5000][currentIndex] } } RowLayout { Layout.fillWidth: true Label { text: "Warning / critical" color: "#252321" Layout.fillWidth: true } SpinBox { from: 40 to: 99 value: root.settings.temperatureWarning editable: true onValueModified: root.settings.setTemperatureWarning(value) } Label { text: "/" color: "#7c756c" } SpinBox { from: 41 to: 110 value: root.settings.temperatureCritical editable: true onValueModified: root.settings.setTemperatureCritical(value) } Label { text: "°C" color: "#7c756c" } } } } Rectangle { Layout.fillWidth: true implicitHeight: powerColumn.implicitHeight + 24 radius: 14 color: "#e8f1df" ColumnLayout { id: powerColumn anchors.fill: parent anchors.margins: 12 spacing: 8 RowLayout { Layout.fillWidth: true Label { text: "Power profile" color: "#4d7c38" font.pixelSize: 16 font.bold: true Layout.fillWidth: true } Label { text: PowerProfile.toString(PowerProfiles.profile) color: "#66825a" } } RowLayout { Layout.fillWidth: true Button { text: "Saver" Layout.fillWidth: true onClicked: PowerProfiles.profile = PowerProfile.PowerSaver } Button { text: "Balanced" Layout.fillWidth: true onClicked: PowerProfiles.profile = PowerProfile.Balanced } Button { text: "Performance" enabled: PowerProfiles.hasPerformanceProfile Layout.fillWidth: true onClicked: PowerProfiles.profile = PowerProfile.Performance } } } } } } } } } }