From 328dfa17860bf7a1f6130d5136361e6a949b3640 Mon Sep 17 00:00:00 2001 From: Sem Date: Tue, 7 Apr 2026 22:10:33 +0200 Subject: [PATCH] Add bluetooth icon --- hypr/environment.conf | 3 +- hypr/keybindings.conf | 1 + qt6ct/qt6ct.conf | 33 +++++++++++++- quickshell/services/BluetoothService.qml | 56 ++++++++++++++++++++++++ quickshell/services/SystemStats.qml | 1 - quickshell/shell.qml | 2 - quickshell/ui/BluetoothIcon.qml | 49 +++++++++++++++++++++ quickshell/ui/MixerEntry.qml | 51 +++++++++++++++++++++ quickshell/ui/TopBar.qml | 8 ++++ 9 files changed, 198 insertions(+), 6 deletions(-) create mode 100644 quickshell/services/BluetoothService.qml create mode 100644 quickshell/ui/BluetoothIcon.qml create mode 100644 quickshell/ui/MixerEntry.qml diff --git a/hypr/environment.conf b/hypr/environment.conf index 396c252..62d80c4 100644 --- a/hypr/environment.conf +++ b/hypr/environment.conf @@ -1,4 +1,5 @@ # See https://wiki.hypr.land/Configuring/Environment-variables/ env = XCURSOR_SIZE,24 -env = HYPRCURSOR_SIZE,24 \ No newline at end of file +env = HYPRCURSOR_SIZE,24 +env = QT_QPA_PLATFORMTHEME,qt6ct \ No newline at end of file diff --git a/hypr/keybindings.conf b/hypr/keybindings.conf index 0bfdfe8..e167944 100644 --- a/hypr/keybindings.conf +++ b/hypr/keybindings.conf @@ -26,6 +26,7 @@ bind = $mainMod SHIFT, o, movefocus, d bind = $mainMod SHIFT, J, swapnext bind = $mainMod SHIFT, K, swapnext, prev +bind = $mainMod, F, fullscreen, toggle # Switch workspaces with mainMod + [0-9] bind = $mainMod, 1, workspace, 1 diff --git a/qt6ct/qt6ct.conf b/qt6ct/qt6ct.conf index c43bbb9..a692234 100644 --- a/qt6ct/qt6ct.conf +++ b/qt6ct/qt6ct.conf @@ -1,3 +1,32 @@ [Appearance] -color_scheme_path=/home/sem/linux-dotfiles/qt6ct/colors/matugen.conf -custom_palette=true \ No newline at end of file +color_scheme_path=/home/sem/.config/qt6ct/colors/matugen.conf +custom_palette=true +icon_theme=breeze-dark +standard_dialogs=default +style=Breeze + +[Fonts] +fixed="Sans Serif,9,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0,0" +general="Sans Serif,9,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0,0" + +[Interface] +activate_item_on_single_click=1 +buttonbox_layout=0 +cursor_flash_time=1000 +dialog_buttons_have_icons=1 +double_click_interval=400 +gui_effects=@Invalid() +keyboard_scheme=2 +menus_have_icons=true +show_shortcuts_in_context_menus=true +stylesheets=@Invalid() +toolbutton_style=4 +underline_shortcut=1 +wheel_scroll_lines=3 + +[SettingsWindow] +geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x4\xe2\0\0\x2\xa6\0\0\0\0\0\0\0\0\0\0\x4\xe2\0\0\x2\xa6\0\0\0\x1\x2\0\0\0\n\0\0\0\0\0\0\0\0\0\0\0\x4\xe2\0\0\x2\xa6) + +[Troubleshooting] +force_raster_widgets=1 +ignored_applications=@Invalid() diff --git a/quickshell/services/BluetoothService.qml b/quickshell/services/BluetoothService.qml new file mode 100644 index 0000000..91ba6e7 --- /dev/null +++ b/quickshell/services/BluetoothService.qml @@ -0,0 +1,56 @@ +import QtQuick +import Quickshell.Io + +Item { + id: root + signal devicesFound(var devices) + property var connectedDevices: [] + + function deviceListChanged(newList) { + if (newList.length !== root.connectedDevices.length) { + return true; + } + for (let i = 0; i < newList.length; i++) { + if (newList[i].mac !== root.connectedDevices[i].mac || + newList[i].name !== root.connectedDevices[i].name) { + return true; + } + } + return false; + } + + Process { + id: bluetoothConnectedDevicesProcess + command: ["bluetoothctl", "devices", "Connected"] + stdout: StdioCollector { + onStreamFinished: { + if (!this.text) { + root.connectedDevices = []; + root.devicesFound([]); + return; + } + var devices = this.text.trim().split("\n").map(line => { + var parts = line.split(" "); + return { + mac: parts[1], + name: parts.slice(2).join(" ") + }; + }); + + if (root.deviceListChanged(devices)) { + root.connectedDevices = devices; + root.devicesFound(devices); + } + } + } + } + + Timer { + interval: 2000 + running: true + repeat: true + onTriggered: bluetoothConnectedDevicesProcess.running = true + } + + Component.onCompleted: bluetoothConnectedDevicesProcess.running = true +} \ No newline at end of file diff --git a/quickshell/services/SystemStats.qml b/quickshell/services/SystemStats.qml index 1152b9a..c8b205e 100644 --- a/quickshell/services/SystemStats.qml +++ b/quickshell/services/SystemStats.qml @@ -68,7 +68,6 @@ Item { stdout: StdioCollector { onStreamFinished: { - console.log("GPU usage data:", this.text); if (!this.text) { return; } diff --git a/quickshell/shell.qml b/quickshell/shell.qml index 7cd5056..ee07192 100644 --- a/quickshell/shell.qml +++ b/quickshell/shell.qml @@ -51,7 +51,6 @@ ShellRoot { gpuUsage: stats.gpuUsage } } - } Variants { @@ -66,4 +65,3 @@ ShellRoot { } } } - diff --git a/quickshell/ui/BluetoothIcon.qml b/quickshell/ui/BluetoothIcon.qml new file mode 100644 index 0000000..aa88e72 --- /dev/null +++ b/quickshell/ui/BluetoothIcon.qml @@ -0,0 +1,49 @@ +import Quickshell.Io +import QtQuick + +import "../constants" +import "../services" + +Text { + id: root + + // Nerd Font Bluetooth icon (nf-fa-bluetooth) + property string iconGlyph: "\udb80\udcaf" + property string connectedIconGlyph: "\udb80\udcb1" + property string disconnectedIconGlyph: "\udb80\udcaf" + + property BluetoothService bluetoothService: BluetoothService { + onDevicesFound: function(devices) { + if (devices.length > 0) { + root.iconGlyph = root.connectedIconGlyph; + root.color = Colors.md3.on_primary_fixed; + } else { + root.iconGlyph = root.disconnectedIconGlyph; + root.color = Colors.md3.primary; + } + } + } + + text: iconGlyph + color: Colors.md3.on_primary_fixed + + font { + family: Constants.fontFamily + pixelSize: Constants.fontSize + bold: true + } + + Process { + id: bluemanManagerProcess + command: ["blueman-manager"] + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onClicked: { + bluemanManagerProcess.running = true; + } + } +} diff --git a/quickshell/ui/MixerEntry.qml b/quickshell/ui/MixerEntry.qml new file mode 100644 index 0000000..56f1e7e --- /dev/null +++ b/quickshell/ui/MixerEntry.qml @@ -0,0 +1,51 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Quickshell.Services.Pipewire + +ColumnLayout { + required property PwNode node; + + // bind the node so we can read its properties + PwObjectTracker { objects: [ node ] } + + RowLayout { + Image { + visible: source != "" + source: { + const icon = node.properties["application.icon-name"] ?? "audio-volume-high-symbolic"; + return `image://icon/${icon}`; + } + + sourceSize.width: 20 + sourceSize.height: 20 + } + + Label { + text: { + // application.name -> description -> name + const app = node.properties["application.name"] ?? (node.description != "" ? node.description : node.name); + const media = node.properties["media.name"]; + return media != undefined ? `${app} - ${media}` : app; + } + } + + Button { + text: node.audio.muted ? "unmute" : "mute" + onClicked: node.audio.muted = !node.audio.muted + } + } + + RowLayout { + Label { + Layout.preferredWidth: 50 + text: `${Math.floor(node.audio.volume * 100)}%` + } + + Slider { + Layout.fillWidth: true + value: node.audio.volume + onValueChanged: node.audio.volume = value + } + } +} \ No newline at end of file diff --git a/quickshell/ui/TopBar.qml b/quickshell/ui/TopBar.qml index f1c5ca5..22216ea 100644 --- a/quickshell/ui/TopBar.qml +++ b/quickshell/ui/TopBar.qml @@ -66,12 +66,17 @@ Item { Layout.fillWidth: true } + // ===================== // RIGHT: System info // ===================== RowLayout { spacing: 10 + LineSeparator {} + + BluetoothIcon {} + LineSeparator {} BarText { @@ -93,6 +98,9 @@ Item { value: gpuUsage } + LineSeparator {} + + LineSeparator {} Clock {}