Notification backend usable

This commit is contained in:
Amaro Lopes
2025-10-07 23:15:53 -03:00
parent d9406f2a90
commit 7c2c2f3a7c
13 changed files with 352 additions and 339 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
.qmlls.ini
.qmlls.ini
scripts/

View File

@@ -26,9 +26,6 @@ WrapperRectangle {
item.monitor = barArea.monitor;
}
}
}
}
}

View File

@@ -17,7 +17,7 @@ Item {
color: Theme.backgroudColor
implicitWidth: clockText.implicitWidth * 1.6
implicitHeight: Theme.heightGaps
implicitHeight: Theme.heightGaps
radius: 25
property string calendar: ""
@@ -36,9 +36,11 @@ Item {
Process {
id: cal
running: true
command: ["cal","-S3"]
command: ["cal", "-S3"]
stdout: StdioCollector {
onStreamFinished: {clock.calendar=this.text}
onStreamFinished: {
clock.calendar = this.text;
}
}
}
@@ -46,15 +48,12 @@ Item {
anchors.fill: parent
hoverEnabled: true
onEntered: {
cal.running = true
PopUpHover.start(clock,"time")
cal.running = true;
PopUpHover.start(clock, "time");
}
onExited: {
PopUpHover.exit()
PopUpHover.exit();
}
}
}
}

View File

@@ -7,7 +7,7 @@ import qs.Widgets
import Quickshell.Services.Notifications
Item {
id: root
id: root
property var monitor: ""
property bool createWindow: false
@@ -17,6 +17,12 @@ Item {
leftMargin: Theme.gaps
}
Binding {
target: root
property: "createWindow"
value: NotificationService.notificationsNumber > 0 && root.createWindow
}
Rectangle {
color: Theme.backgroudColor
implicitWidth: clockText.implicitWidth * 1.6
@@ -28,7 +34,7 @@ Item {
anchors.centerIn: parent
text: {
NotificationService.notificationsNumber > 0 ? "\udb80\udc9a "+NotificationService.notificationsNumber : "\ueaa2";
NotificationService.notificationsNumber > 0 ? "\udb80\udc9a " + NotificationService.notificationsNumber : "\ueaa2";
}
font.bold: true
font.pixelSize: Theme.pixelSize
@@ -39,18 +45,15 @@ Item {
MouseArea {
anchors.fill: parent
onClicked: {
console.log(NotificationService.currentNotification.image);
root.createWindow = true
root.createWindow = !root.createWindow;
}
}
}
LazyLoader {
id: windowLoader
active: root.createWindow
active: NotificationService.notificationsNumber ? createWindow : false
component: NotificationWindow {
anchor.item:root
}
component: NotificationWindow {}
}
}

View File

@@ -10,70 +10,68 @@ Singleton {
property var sortedTopLevels: {
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values) {
return []
return [];
}
const topLevels = Array.from(Hyprland.toplevels.values)
const topLevels = Array.from(Hyprland.toplevels.values);
const sortedHyprland = topLevels.sort((a, b) => {
if (a.monitor && b.monitor) {
const monitorCompare = a.monitor.name.localeCompare(b.monitor.name)
if (monitorCompare !== 0) {
return monitorCompare
}
}
if (a.monitor && b.monitor) {
const monitorCompare = a.monitor.name.localeCompare(b.monitor.name);
if (monitorCompare !== 0) {
return monitorCompare;
}
}
if (a.workspace && b.workspace) {
const workspaceCompare = a.workspace.id - b.workspace.id
if (workspaceCompare !== 0) {
return workspaceCompare
}
}
if (a.workspace && b.workspace) {
const workspaceCompare = a.workspace.id - b.workspace.id;
if (workspaceCompare !== 0) {
return workspaceCompare;
}
}
if (a.lastIpcObject && b.lastIpcObject && a.lastIpcObject.at && b.lastIpcObject.at) {
const aX = a.lastIpcObject.at[0]
const bX = b.lastIpcObject.at[0]
const aY = a.lastIpcObject.at[1]
const bY = b.lastIpcObject.at[1]
if (a.lastIpcObject && b.lastIpcObject && a.lastIpcObject.at && b.lastIpcObject.at) {
const aX = a.lastIpcObject.at[0];
const bX = b.lastIpcObject.at[0];
const aY = a.lastIpcObject.at[1];
const bY = b.lastIpcObject.at[1];
const xCompare = aX - bX
if (Math.abs(xCompare) > 10) {
return xCompare
}
return aY - bY
}
const xCompare = aX - bX;
if (Math.abs(xCompare) > 10) {
return xCompare;
}
return aY - bY;
}
if (a.lastIpcObject && !b.lastIpcObject) {
return -1
}
if (!a.lastIpcObject && b.lastIpcObject) {
return 1
}
if (a.lastIpcObject && !b.lastIpcObject) {
return -1;
}
if (!a.lastIpcObject && b.lastIpcObject) {
return 1;
}
if (a.title && b.title) {
return a.title.localeCompare(b.title)
}
return 0
})
return sortedHyprland.filter(tl => tl.wayland !== null)
if (a.title && b.title) {
return a.title.localeCompare(b.title);
}
return 0;
});
return sortedHyprland.filter(tl => tl.wayland !== null);
}
property var topLevelWorkspaces: {
return sortedTopLevels.map(topLevel => topLevel.workspace)
return sortedTopLevels.map(topLevel => topLevel.workspace);
}
property var sortedDesktopApplications: {
const sortedWayland = sortedTopLevels.map(topLevel => topLevel.wayland).filter(wayland=> wayland !== null)
const desktopEntries = sortedWayland.map( topLevel => {
return DesktopEntries.heuristicLookup(topLevel.appId)
})
const workspace = sortedTopLevels.map( topLevel => {
return topLevel.workspace.id
})
const workspaceDesktopEntries = new Map()
const sortedWayland = sortedTopLevels.map(topLevel => topLevel.wayland).filter(wayland => wayland !== null);
const desktopEntries = sortedWayland.map(topLevel => {
return DesktopEntries.heuristicLookup(topLevel.appId);
});
const workspace = sortedTopLevels.map(topLevel => {
return topLevel.workspace.id;
});
const workspaceDesktopEntries = new Map();
for (let i = 0; i < workspace.length; i++) {
const key = workspace[i];
@@ -85,8 +83,6 @@ Singleton {
workspaceDesktopEntries.set(key, [value]);
}
}
return workspaceDesktopEntries
return workspaceDesktopEntries;
}
}
}

View File

@@ -2,16 +2,13 @@ pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Notifications
import Quickshell.Widgets
import qs.Widgets
Singleton {
id: notificationRoot
readonly property var notificationServer: notificationServer
readonly property var trackedNotifications: notificationServer.trackedNotifications
readonly property var notificationsNumber: notificationServer.trackedNotifications.values.length
@@ -29,6 +26,9 @@ Singleton {
notif.dismiss();
return;
}
if (notif.traked) {
return;
}
notif.tracked = true;
notificationRoot.currentNotification = notif;
notificationRoot.shouldShowOsd = true;
@@ -47,19 +47,33 @@ Singleton {
LazyLoader {
id: popupLoader
active: currentNotification && shouldShowOsd
active: notificationRoot.currentNotification && notificationRoot.shouldShowOsd
component: NotificationPopup {
notification: currentNotification
// No signal handler here!
}
component: PanelWindow {
id: notificationWindow
onItemChanged: {
if (item) {
item.dismissed.connect(function() {
notificationRoot.shouldShowOsd = false
currentNotification.dismiss()
})
anchors.top: true
margins.top: screen.height / 100
exclusiveZone: 0
implicitWidth: 400
implicitHeight: 905
color: "transparent"
NotificationWrapper {
id: notificationWrapper
notification: notificationRoot.currentNotification
implicitWidth: notificationWindow.implicitWidth
Component.onCompleted: {
console.log(notificationWrapper.height);
popupLoader.implicitHeight = notificationWrapper.implicitHeight;
}
onDismissed: {
notificationRoot.shouldShowOsd = false;
notificationRoot.currentNotification.dismiss();
}
}
}
}

View File

@@ -8,33 +8,32 @@ import Quickshell.Widgets
import qs.Common
import qs.Services
Singleton {
function start(component, type) {
HoverMediator.component = component
HoverMediator.type = type
hoverPopUp.anchor.updateAnchor()
hoverTimer.start()
HoverMediator.component = component;
HoverMediator.type = type;
hoverPopUp.anchor.updateAnchor();
hoverTimer.start();
}
function exit() {
hoverTimer.stop()
hoverPopUp.visible = false
hoverTimer.stop();
hoverPopUp.visible = false;
}
PopupWindow {
id: hoverPopUp
id: hoverPopUp
anchor.item: HoverMediator.component
property bool initialized: false
anchor.rect.y: HoverMediator.y
anchor.rect.x: (HoverMediator.x - this.implicitWidth)/2
implicitHeight: wsPopUp.implicitHeight
implicitWidth: wsPopUp.implicitWidth
anchor.item: HoverMediator.component
property bool initialized: false
anchor.rect.y: HoverMediator.y
anchor.rect.x: (HoverMediator.x - this.implicitWidth) / 2
implicitHeight: wsPopUp.implicitHeight
implicitWidth: wsPopUp.implicitWidth
color: "transparent"
color:"transparent"
Component {
id: stub
Text {
@@ -45,15 +44,19 @@ Singleton {
color: Theme.textColor
}
}
Component {
id: systray
Text {
text: {
if (!HoverMediator.component.model) return ""
if (HoverMediator.component.model.tooltipTitle) return HoverMediator.component.model.tooltipTitle
if (HoverMediator.component.model.title) return HoverMediator.component.model.title
else return ""
if (!HoverMediator.component.model)
return "";
if (HoverMediator.component.model.tooltipTitle)
return HoverMediator.component.model.tooltipTitle;
if (HoverMediator.component.model.title)
return HoverMediator.component.model.title;
else
return "";
}
font.bold: true
font.pixelSize: Theme.pixelSize
@@ -65,7 +68,7 @@ Singleton {
Component {
id: time
Text {
property string calendar:(HoverMediator.component.calendar)? HoverMediator.component.calendar: ""
property string calendar: (HoverMediator.component.calendar) ? HoverMediator.component.calendar : ""
text: calendar
font.bold: true
@@ -78,7 +81,7 @@ Singleton {
Component {
id: audio
Text {
property string sinkDescription:(HoverMediator.component.sink)? HoverMediator.component.sink.description : ""
property string sinkDescription: (HoverMediator.component.sink) ? HoverMediator.component.sink.description : ""
text: sinkDescription
font.bold: true
font.pixelSize: Theme.pixelSize
@@ -97,14 +100,15 @@ Singleton {
Repeater {
property var modelo: HyprlandService.sortedDesktopApplications.get(parent.workspaceIndexAlign)
property var modelo: HyprlandService.sortedDesktopApplications.get(parent.workspaceIndexAlign)
model: modelo
delegate: IconImage {
required property var modelData
width:30; height:30
width: 30
height: 30
source: (modelData && modelData.icon) ? Quickshell.iconPath(modelData.icon, 1) : ""
}
}
@@ -122,21 +126,28 @@ Singleton {
radius: 25
opacity: 1
Behavior on opacity {
NumberAnimation { property: "opacity"; duration: Theme.animationDuration}
NumberAnimation {
property: "opacity"
duration: Theme.animationDuration
}
}
Loader {
id: hoverLoader
sourceComponent: {
if(!HoverMediator.type) return stub
if(HoverMediator.type === "workspace") return workspaceComponent
if(HoverMediator.type === "audio") return audio
if(HoverMediator.type === "time") return time
if(HoverMediator.type === "systray") return systray
if (!HoverMediator.type)
return stub;
if (HoverMediator.type === "workspace")
return workspaceComponent;
if (HoverMediator.type === "audio")
return audio;
if (HoverMediator.type === "time")
return time;
if (HoverMediator.type === "systray")
return systray;
}
}
}
}
Timer {
@@ -145,7 +156,7 @@ Singleton {
interval: 300
onTriggered: {
// wsPopUp.opacity = 1
hoverPopUp.visible = true
hoverPopUp.visible = true;
}
}
}
}

View File

@@ -14,5 +14,4 @@ Singleton {
precision: SystemClock.Seconds
}
}

View File

@@ -1,4 +1,3 @@
pragma ComponentBehavior: Bound
import QtQuick
@@ -52,12 +51,13 @@ WrapperRectangle {
implicitHeight: 30
implicitWidth: 30
color:"transparent"
color: "transparent"
IconImage {
anchors.verticalCenter:parent.verticalCenter
anchors.horizontalCenter:parent.horizontalCenter
width:25; height:25
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: 25
height: 25
source: systrayItem.iconSource
}
@@ -66,30 +66,23 @@ WrapperRectangle {
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
onEntered: {
PopUpHover.start(systrayItem,"systray")
PopUpHover.start(systrayItem, "systray");
}
onExited: {
PopUpHover.exit()
PopUpHover.exit();
}
onClicked: (mouse) => {
if (mouse.button === Qt.RightButton) {
onClicked: mouse => {
if (mouse.button === Qt.RightButton) {
menuAnchor.menu = systrayItem.model.menu;
menuAnchor.anchor.item = systrayItem;
menuAnchor.anchor.rect = Qt.rect(
0,
systrayItem.implicitHeight,
0,
0
);
menuAnchor.anchor.rect = Qt.rect(0, systrayItem.implicitHeight, 0, 0);
menuAnchor.open();
} else if (mouse.button === Qt.LeftButton) {
// systrayItem.model.activate()
}
} else if (mouse.button === Qt.LeftButton)
// systrayItem.model.activate()
{}
}
onDoubleClicked: {
systrayItem.model.activate()
systrayItem.model.activate();
}
}
}
@@ -98,6 +91,5 @@ WrapperRectangle {
QsMenuAnchor {
id: menuAnchor
}
}

View File

@@ -1,149 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Notifications
import Quickshell.Widgets
PanelWindow {
id: notificationRoot
// Since the panel's screen is unset, it will be picked by the compositor
// when the window is created. Most compositors pick the current active monitor.
property bool hasImage: notification?.image ? true : false
property string image: {
if (hasImage) {
return notification.image;
}
if (notification?.appIcon === "") {
return "";
}
return Quickshell.iconPath(notification?.appIcon);
}
property var notification: null
signal dismissed()
anchors.top: true
margins.top: screen.height / 100
exclusiveZone: 0
implicitWidth: 400
implicitHeight: 100
color: "transparent"
// An empty click mask prevents the window from blocking mouse events.
Rectangle {
anchors.fill: parent
topLeftRadius: 100
bottomLeftRadius: 100
topRightRadius: 20
bottomRightRadius: 20
color: "#80000000"
MouseArea{
anchors.fill: parent
onClicked: {
notificationRoot.dismissed()
}
}
RowLayout {
anchors {
fill: parent
}
ClippingRectangle {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
implicitWidth: 100
implicitHeight: 100
visible: image? true : false
color: "grey"
radius: 100
IconImage {
anchors.centerIn: parent
implicitSize: 100
source: notificationRoot.image
}
}
ColumnLayout {
Layout.leftMargin: 10
Layout.rightMargin: 10
Rectangle {
Layout.fillWidth: true
implicitHeight: 30
radius: 20
color: "#50ffffff"
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
implicitWidth: parent.width
radius: parent.radius
color: "white"
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
fontSizeMode: Text.Fit
text: notificationRoot.notification.summary
}
}
}
Rectangle {
Layout.fillWidth: true
implicitHeight: 55
radius: 20
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
implicitWidth: parent.width
radius: parent.radius
color: "white"
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 24
wrapMode: Text.WordWrap
fontSizeMode: Text.Fit
minimumPixelSize: 10
elide: Text.ElideRight
text: notificationRoot.notification.body
}
}
}
}
}
}
}

View File

@@ -1,42 +1,41 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Notifications
import Quickshell.Widgets
import qs.Services
import qs.Widgets
import QtQuick.Window
PopupWindow {
anchor.item:root
anchor.rect.y: parentWindow.height
implicitWidth: 400
implicitHeight: 1000
color: "white"
visible:true
id: notificationRoot
// Since the panel's screen is unset, it will be picked by the compositor
// when the window is created. Most compositors pick the current active monitor.
// An empty click mask prevents the window from blocking mouse events.
Component {
id: contactDelegate
NotificationPopup {
id: myItem
required property string notification
}
}
anchor.item: root
anchor.rect.y: parentWindow?.height
implicitWidth: 400
implicitHeight: Math.min(listView.contentHeight, 900)
color: "white"
visible: true
ListView {
id: listView
anchors.fill: parent
model: NotificationService.trackedNotifications.values
delegate: contactDelegate
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
orientation: ListView.Vertical
verticalLayoutDirection: ListView.BottomToTop
clip: true
spacing: 5
delegate: NotificationWrapper {
required property var modelData
notification: modelData
width: ListView.width
onDismissed: {
if (notification && typeof notification.dismiss === "function") {
notification.dismiss();
}
}
}
Component.onCompleted: positionViewAtEnd()
onModelChanged: positionViewAtEnd()
}
}

View File

@@ -0,0 +1,138 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
Rectangle {
id: notificationWrapper
signal dismissed
property bool hasImage: notification?.image ? true : false
property var notification: null
property string image: {
if (hasImage) {
return notification.image;
}
if (notification?.appIcon === "") {
return "";
}
return Quickshell.iconPath(notification?.appIcon);
}
implicitWidth: 400
implicitHeight: notifLayout.implicitHeight
topLeftRadius: image ? 100 : 20
bottomLeftRadius: image ? 100 : 20
topRightRadius: 20
bottomRightRadius: 20
color: "#80000000"
MouseArea {
anchors.fill: parent
onClicked: {
notificationWrapper.dismissed();
console.log("opa");
}
}
RowLayout {
id: notifLayout
anchors {
fill: parent
}
ClippingRectangle {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
implicitWidth: 100
implicitHeight: 100
visible: notificationWrapper.image ? true : false
color: "grey"
radius: 100
IconImage {
anchors.centerIn: parent
implicitSize: 100
source: notificationWrapper.image
}
}
ColumnLayout {
Layout.leftMargin: 10
Layout.rightMargin: 10
Rectangle {
Layout.fillWidth: true
implicitHeight: summaryText.implicitHeight + 10
radius: 20
color: "#50ffffff"
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
implicitWidth: parent.width
radius: parent.radius
color: "white"
Text {
id: summaryText
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 12
wrapMode: Text.WordWrap
textFormat: Text.MarkdownText
text: notificationWrapper.notification.summary
}
}
}
Rectangle {
Layout.fillWidth: true
implicitHeight: bodyText.implicitHeight + 10
radius: 20
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
implicitWidth: parent.width
radius: parent.radius
color: "white"
Text {
id: bodyText
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
wrapMode: Text.WordWrap
textFormat: Text.MarkdownText
text: notificationWrapper.notification.body
onLinkActivated: link => Qt.openUrlExternally(link)
}
}
}
}
}
}

View File

@@ -11,18 +11,18 @@ import qs.Services
WrapperMouseArea {
id: workspacesWidget
property var monitor: "black"
onWheel: (wheel) => {
onWheel: wheel => {
if (wheel.angleDelta.y > 0) {
if ((Hyprland.focusedWorkspace.id) % 5 === 0)
return ;
return;
Hyprland.dispatch("workspace " + (Hyprland.focusedWorkspace.id + 1));
} else if (wheel.angleDelta.y < 0) {
if (Hyprland.focusedWorkspace.id === 1 || Hyprland.focusedWorkspace.id === 6)
return ;
return;
Hyprland.dispatch("workspace " + (Hyprland.focusedWorkspace.id - 1));
}
@@ -35,7 +35,7 @@ WrapperMouseArea {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Repeater {
id:workspacesRepeater
id: workspacesRepeater
property var monitor: parent.monitor
@@ -49,11 +49,11 @@ WrapperMouseArea {
required property var modelData
property var index: modelData // Get the workspace data from the model
property int workspaceIndex: parent.monitor === "DP-2" ? modelData + 5 : modelData
property int workspaceIndexAlign: workspaceIndex+1
property int workspaceIndexAlign: workspaceIndex + 1
property var workspace: Hyprland.workspaces.values.length > workspaceIndex ? Hyprland.workspaces.values[workspaceIndex] : null
property bool workspaceActive: workspace === Hyprland.focusedWorkspace? true:false
property bool workspaceActive: workspace === Hyprland.focusedWorkspace ? true : false
property var topLevels: HyprlandService.topLevelWorkspaces
property var hasTopLevel: topLevels.filter(topLevelworkspace => topLevelworkspace.id === workspaceIndexAlign).length ? true:false
property var hasTopLevel: topLevels.filter(topLevelworkspace => topLevelworkspace.id === workspaceIndexAlign).length ? true : false
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
implicitHeight: Theme.heightGaps
@@ -63,17 +63,32 @@ WrapperMouseArea {
State {
name: "Active"
when: workspacesRectangle.workspaceActive
PropertyChanges { workspacesRectangle{ color: Theme.color6; implicitWidth: Theme.barSize*1.5}}
PropertyChanges {
workspacesRectangle {
color: Theme.color6
implicitWidth: Theme.barSize * 1.5
}
}
},
State {
name: "Filled"
when: !workspacesRectangle.workspaceActive && workspacesRectangle.hasTopLevel
PropertyChanges { workspacesRectangle{ color: Theme.backgroudColorBright; implicitWidth: Theme.barSize}}
PropertyChanges {
workspacesRectangle {
color: Theme.backgroudColorBright
implicitWidth: Theme.barSize
}
}
},
State {
name: "Empty"
when: !workspacesRectangle.workspaceActive && !workspacesRectangle.hasTopLevel
PropertyChanges { workspacesRectangle{ color: Theme.backgroudColor;implicitWidth: Theme.barSize}}
PropertyChanges {
workspacesRectangle {
color: Theme.backgroudColor
implicitWidth: Theme.barSize
}
}
}
]
@@ -91,7 +106,7 @@ WrapperMouseArea {
Text {
property int workspaceName: workspacesRectangle.workspaceIndexAlign > 5? workspacesRectangle.workspaceIndexAlign -5: workspacesRectangle.workspaceIndexAlign
property int workspaceName: workspacesRectangle.workspaceIndexAlign > 5 ? workspacesRectangle.workspaceIndexAlign - 5 : workspacesRectangle.workspaceIndexAlign
anchors.centerIn: parent
text: workspaceName
@@ -106,23 +121,21 @@ WrapperMouseArea {
hoverEnabled: true
onEntered: {
if (parent.hasTopLevel && !parent.workspaceActive) {
PopUpHover.start(workspacesRectangle, "workspace")
PopUpHover.start(workspacesRectangle, "workspace");
}
}
onExited: {
PopUpHover.exit()
PopUpHover.exit();
}
onClicked: {
if(workspacesRectangle.workspace.id === Hyprland.focusedWorkspace.id) {return} ;
if (workspacesRectangle.workspace.id === Hyprland.focusedWorkspace.id) {
return;
}
;
Hyprland.dispatch("workspace " + workspacesRectangle.workspace.id);
}
}
}
}
}
}