feat: bar workspaces show windows

Better hyprland clients (update existing instead of resetting every time)
Option for ws trail
Custom label for occupied ws as well
This commit is contained in:
2 * r + 2 * t 2025-04-30 13:49:05 +10:00
parent 65c54e12c2
commit e8fe4ef673
4 changed files with 117 additions and 15 deletions

View file

@ -26,7 +26,10 @@ Singleton {
readonly property int shown: 10 readonly property int shown: 10
readonly property string style: "" readonly property string style: ""
readonly property bool occupiedBg: true readonly property bool occupiedBg: true
readonly property string label: " " readonly property bool showWindows: true
readonly property bool activeTrail: !showWindows // Doesn't work well with variable sized workspaces
readonly property string label: " "
readonly property string occupiedLabel: "󰮯 "
readonly property string activeLabel: "󰮯 " readonly property string activeLabel: "󰮯 "
} }

View file

@ -71,16 +71,34 @@ Rectangle {
} }
Behavior on leading { Behavior on leading {
enabled: BarConfig.workspaces.activeTrail
Anim {} Anim {}
} }
Behavior on trailing { Behavior on trailing {
enabled: BarConfig.workspaces.activeTrail
Anim { Anim {
duration: Appearance.anim.durations.normal * 2 duration: Appearance.anim.durations.normal * 2
} }
} }
Behavior on currentSize { Behavior on currentSize {
enabled: BarConfig.workspaces.activeTrail
Anim {}
}
Behavior on offset {
enabled: !BarConfig.workspaces.activeTrail
Anim {}
}
Behavior on size {
enabled: !BarConfig.workspaces.activeTrail
Anim {} Anim {}
} }

View file

@ -1,9 +1,14 @@
import "root:/widgets" import "root:/widgets"
import "root:/services" import "root:/services"
import "root:/utils"
import "root:/config" import "root:/config"
import Quickshell
import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
StyledText { Item {
id: root
required property int index required property int index
required property bool vertical required property bool vertical
required property var occupied required property var occupied
@ -12,15 +17,73 @@ StyledText {
readonly property bool isWorkspace: true // Flag for finding workspace children readonly property bool isWorkspace: true // Flag for finding workspace children
readonly property int ws: groupOffset + index + 1 readonly property int ws: groupOffset + index + 1
readonly property string label: BarConfig.workspaces.label || ws readonly property bool isOccupied: occupied[ws] ?? false
readonly property string activeLabel: BarConfig.workspaces.activeLabel || label
animate: true Layout.preferredWidth: childrenRect.width + (isOccupied && !vertical ? Appearance.padding.normal : 0)
animateProp: "scale" Layout.preferredHeight: childrenRect.height + (isOccupied && vertical ? Appearance.padding.normal : 0)
text: (Hyprland.activeWorkspace?.id ?? 1) === ws ? activeLabel : label
color: BarConfig.workspaces.occupiedBg || occupied[ws] ? Appearance.colours.text : Appearance.colours.subtext0
horizontalAlignment: StyledText.AlignHCenter
Layout.minimumWidth: vertical ? -1 : BarConfig.sizes.innerHeight StyledText {
Layout.minimumHeight: vertical ? BarConfig.sizes.innerHeight : -1 id: indicator
readonly property string label: BarConfig.workspaces.label || root.ws
readonly property string occupiedLabel: BarConfig.workspaces.occupiedLabel || label
readonly property string activeLabel: BarConfig.workspaces.activeLabel || (root.isOccupied ? occupiedLabel : label)
animate: true
animateProp: "scale"
text: Hyprland.activeWsId === root.ws ? activeLabel : root.isOccupied ? occupiedLabel : label
color: BarConfig.workspaces.occupiedBg || root.isOccupied ? Appearance.colours.text : Appearance.colours.subtext0
horizontalAlignment: StyledText.AlignHCenter
verticalAlignment: StyledText.AlignVCenter
width: BarConfig.sizes.innerHeight
height: BarConfig.sizes.innerHeight
}
Grid {
flow: root.vertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: root.vertical ? -1 : 1
columns: root.vertical ? 1 : -1
spacing: Appearance.padding.small
anchors.left: vertical ? undefined : indicator.right
anchors.top: vertical ? indicator.bottom : undefined
anchors.verticalCenter: vertical ? undefined : indicator.verticalCenter
anchors.horizontalCenter: vertical ? indicator.horizontalCenter : undefined
add: Transition {
Anim {
properties: "scale"
from: 0
to: 1
duration: Appearance.anim.durations.small
}
}
Repeater {
model: ScriptModel {
values: Hyprland.clients.filter(c => c.workspace.id === root.ws)
}
MaterialIcon {
required property Hyprland.Client modelData
text: Icons.getAppCategoryIcon(modelData.wmClass, "terminal")
}
}
}
Behavior on Layout.preferredWidth {
Anim {}
}
Behavior on Layout.preferredHeight {
Anim {}
}
component Anim: NumberAnimation {
duration: Appearance.anim.durations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
} }

View file

@ -8,12 +8,13 @@ import QtQuick
Singleton { Singleton {
id: root id: root
property list<Client> clients: [] readonly property list<Client> clients: []
readonly property var workspaces: Hyprland.workspaces readonly property var workspaces: Hyprland.workspaces
readonly property var monitors: Hyprland.monitors readonly property var monitors: Hyprland.monitors
property Client activeClient: null property Client activeClient: null
readonly property HyprlandWorkspace activeWorkspace: focusedMonitor?.activeWorkspace ?? null readonly property HyprlandWorkspace activeWorkspace: focusedMonitor?.activeWorkspace ?? null
readonly property HyprlandMonitor focusedMonitor: Hyprland.monitors.values.find(m => m.lastIpcObject.focused) ?? null readonly property HyprlandMonitor focusedMonitor: Hyprland.monitors.values.find(m => m.lastIpcObject.focused) ?? null
readonly property int activeWsId: activeWorkspace?.id ?? 1
function reload() { function reload() {
Hyprland.refreshWorkspaces(); Hyprland.refreshWorkspaces();
@ -43,9 +44,25 @@ Singleton {
stdout: SplitParser { stdout: SplitParser {
onRead: data => { onRead: data => {
const clients = JSON.parse(data); const clients = JSON.parse(data);
root.clients = clients.map(c => clientComp.createObject(root, { const rClients = root.clients;
lastIpcObject: c
})).filter(c => c); const len = rClients.length;
for (let i = 0; i < len; i++) {
const client = rClients[i];
if (!clients.find(c => c.address === client.address))
rClients.splice(i, 1);
}
for (const client of clients) {
const match = rClients.find(c => c.address === client.address);
if (match) {
match.lastIpcObject = client;
} else {
rClients.push(clientComp.createObject(root, {
lastIpcObject: client
}));
}
}
} }
} }
} }
@ -78,6 +95,7 @@ Singleton {
property bool floating: lastIpcObject.floating property bool floating: lastIpcObject.floating
property bool fullscreen: lastIpcObject.fullscreen property bool fullscreen: lastIpcObject.fullscreen
property int pid: lastIpcObject.pid property int pid: lastIpcObject.pid
property int focusHistoryId: lastIpcObject.focusHistoryID
} }
Component { Component {