feat(quickshell): support x11 bar sessions

This commit is contained in:
2026-09-27 09:33:47 -04:00
parent 3f6473ce17
commit 5c13c8c3e7
10 changed files with 133 additions and 24 deletions
@@ -1,5 +1,23 @@
#!/bin/bash #!/bin/bash
# Start the systemd-managed Quickshell bar on the current Wayland session. # Start the systemd-managed Quickshell bar in the current graphical session.
systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE if ! command -v qs &> /dev/null; then
if [ "${XDG_SESSION_TYPE}" = "x11" ]; then
~/bin/desktop/polybar-start.sh
fi
exit 0
fi
if [ "${XDG_SESSION_TYPE}" = "x11" ]; then
systemctl --user unset-environment WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE
systemctl --user set-environment QT_QPA_PLATFORM=xcb
else
systemctl --user set-environment QT_QPA_PLATFORM=wayland
fi
systemctl --user import-environment DISPLAY XAUTHORITY WAYLAND_DISPLAY XDG_SESSION_TYPE XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE I3SOCK
if [ "$(hostname)" = "desktop" ]; then
systemctl --user set-environment QUICKSHELL_BAR_SCREEN=DP-2
else
systemctl --user unset-environment QUICKSHELL_BAR_SCREEN
fi
systemctl --user restart quickshell-bar.service systemctl --user restart quickshell-bar.service
+1 -5
View File
@@ -5,11 +5,7 @@ pass git pull
# Desktop # Desktop
~/bin/connect-nas.sh ~/bin/connect-nas.sh
if [ "${XDG_SESSION_TYPE}" = "wayland" ]; then ~/bin/desktop/quickshell-start.sh
~/bin/desktop/quickshell-start.sh
else
systemctl --user start polybar
fi
systemctl --user restart streamdeck systemctl --user restart streamdeck
/usr/libexec/polkit-gnome-authentication-agent-1 & /usr/libexec/polkit-gnome-authentication-agent-1 &
+8 -13
View File
@@ -1,6 +1,5 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import Quickshell.Services.UPower import Quickshell.Services.UPower
@@ -11,6 +10,7 @@ PanelWindow {
property var source: Pipewire.defaultAudioSource property var source: Pipewire.defaultAudioSource
property var battery: UPower.displayDevice property var battery: UPower.displayDevice
property var hardware property var hardware
property bool isWayland: Quickshell.env("XDG_SESSION_TYPE") === "wayland"
anchors { anchors {
top: true top: true
@@ -42,34 +42,29 @@ PanelWindow {
id: leftModules id: leftModules
anchors { anchors {
left: parent.left left: parent.left
top: parent.top verticalCenter: parent.verticalCenter
bottom: parent.bottom
} }
height: Theme.blockHeight
spacing: Theme.moduleSpacing spacing: Theme.moduleSpacing
Workspaces { Loader {
height: parent.height height: parent.height
source: bar.isWayland ? "Workspaces.qml" : "I3Workspaces.qml"
} }
} }
Text { Loader {
anchors.centerIn: parent anchors.centerIn: parent
width: Math.max(0, Math.min(implicitWidth, width: Math.max(0, Math.min(implicitWidth,
parent.width - leftModules.width - rightModules.width - Theme.blockHeight)) parent.width - leftModules.width - rightModules.width - Theme.blockHeight))
elide: Text.ElideRight source: bar.isWayland ? "HyprlandTitle.qml" : "I3Title.qml"
horizontalAlignment: Text.AlignHCenter
text: Hyprland.activeToplevel ? Hyprland.activeToplevel.title : ""
color: Theme.foreground
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
} }
Row { Row {
id: rightModules id: rightModules
anchors { anchors {
right: parent.right right: parent.right
top: parent.top verticalCenter: parent.verticalCenter
bottom: parent.bottom
rightMargin: Theme.moduleSpacing / 2 rightMargin: Theme.moduleSpacing / 2
} }
spacing: Theme.moduleSpacing spacing: Theme.moduleSpacing
@@ -4,10 +4,10 @@ Block {
id: root id: root
required property var battery required property var battery
property int percentage: Math.round(battery.percentage * 100) property int percentage: battery ? Math.round(battery.percentage * 100) : 0
signal detailsRequested(var anchorItem) signal detailsRequested(var anchorItem)
visible: battery.ready && battery.isLaptopBattery visible: battery && battery.ready && battery.isLaptopBattery
interactive: true interactive: true
blockColor: percentage <= 15 && UPower.onBattery blockColor: percentage <= 15 && UPower.onBattery
? Theme.urgent : UPower.onBattery ? Theme.foreground : Theme.secondary ? Theme.urgent : UPower.onBattery ? Theme.foreground : Theme.secondary
@@ -0,0 +1,11 @@
import QtQuick
import Quickshell.Hyprland
Text {
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: Hyprland.activeToplevel ? Hyprland.activeToplevel.title : ""
color: Theme.foreground
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
}
@@ -0,0 +1,40 @@
import QtQuick
import Quickshell.I3
import Quickshell.Io
Text {
id: root
function focusedTitle(node) {
for (const child of (node.nodes || []).concat(node.floating_nodes || [])) {
const title = focusedTitle(child);
if (title)
return title;
}
return node.focused && node.type === "con" ? node.name || "" : "";
}
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
color: Theme.foreground
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
Connections {
target: I3
function onRawEvent(event) {
if ((event.type === "window" || event.type === "workspace") && !treeQuery.running)
treeQuery.running = true;
}
}
Process {
id: treeQuery
command: ["i3-msg", "-t", "get_tree"]
running: true
stdout: StdioCollector {
onStreamFinished: root.text = root.focusedTitle(JSON.parse(text))
}
}
}
@@ -0,0 +1,48 @@
import QtQuick
import Quickshell.I3
Row {
spacing: 0
Repeater {
model: I3.workspaces
Rectangle {
id: workspaceButton
required property var modelData
property bool active: modelData.active
visible: modelData.number > 0
width: visible ? Theme.blockHeight + 2 : 0
height: parent.height
color: modelData.urgent ? Theme.urgent
: active ? Theme.primary : "transparent"
Rectangle {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: Theme.activeLineWidth
color: workspaceButton.active ? Theme.accent : "transparent"
}
Text {
anchors.centerIn: parent
text: modelData.number === 2 ? "\uf120"
: modelData.number === 13 ? "\uf001" : modelData.name
color: Theme.foreground
font.family: Theme.iconFontFamily
font.pixelSize: Theme.fontSize
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: workspaceButton.modelData.activate()
}
}
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ Singleton {
readonly property string fontFamily: "SF Pro Display, Helvetica, Arial, sans-serif" readonly property string fontFamily: "SF Pro Display, Helvetica, Arial, sans-serif"
readonly property string iconFontFamily: "SF Pro Display, Font Awesome 6 Free" readonly property string iconFontFamily: "SF Pro Display, Font Awesome 6 Free"
readonly property int barHeight: 38 readonly property int barHeight: 32
readonly property int blockHeight: 32 readonly property int blockHeight: 32
readonly property int fontSize: 18 readonly property int fontSize: 18
readonly property int fontTiny: 11 readonly property int fontTiny: 11
+2
View File
@@ -11,6 +11,8 @@ ShellRoot {
Bar { Bar {
required property var modelData required property var modelData
screen: modelData screen: modelData
visible: !Quickshell.env("QUICKSHELL_BAR_SCREEN")
|| modelData.name === Quickshell.env("QUICKSHELL_BAR_SCREEN")
hardware: hardwareService hardware: hardwareService
} }
} }
@@ -3,7 +3,6 @@ Description=Quickshell desktop bar
Documentation=https://quickshell.org/ Documentation=https://quickshell.org/
After=graphical-session.target After=graphical-session.target
PartOf=graphical-session.target PartOf=graphical-session.target
ConditionEnvironment=WAYLAND_DISPLAY
[Service] [Service]
Type=simple Type=simple