Fix Warnings and implements Systray

This commit is contained in:
Amaro Lopes
2025-09-22 23:03:42 -03:00
parent 690a244bad
commit 99f7e41ff4
8 changed files with 156 additions and 114 deletions

View File

@@ -1,8 +1,6 @@
import QtQuick import QtQuick
import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import Quickshell.Widgets
import qs.Common import qs.Common
Rectangle { Rectangle {
@@ -10,7 +8,8 @@ Rectangle {
property string monitor: "" property string monitor: ""
property string icon: " " property string icon: " "
property int volume: Math.round(Pipewire.defaultAudioSink.audio.volume * 100) property bool audioPipewireActive: Pipewire.defaultAudioSink? true:false
property int volume: audioPipewireActive? Math.round(Pipewire.defaultAudioSink.audio.volume * 100): 30
implicitWidth: audioText.implicitWidth * 1.6 implicitWidth: audioText.implicitWidth * 1.6
implicitHeight: Theme.heightGaps implicitHeight: Theme.heightGaps
@@ -55,17 +54,19 @@ Rectangle {
audioWidget.volume = Math.round(Pipewire.defaultAudioSink.audio.volume * 100); audioWidget.volume = Math.round(Pipewire.defaultAudioSink.audio.volume * 100);
} }
target: Pipewire.defaultAudioSink.audio target: audioWidget.audioPipewireActive? Pipewire.defaultAudioSink.audio: null
} }
Text { Text {
id: audioText id: audioText
property string audioTextText: audioWidget.audioPipewireActive? audioWidget.icon + " " + Math.round(Pipewire.defaultAudioSink.audio.volume * 100).toString() + "%" : ""
anchors.centerIn: parent anchors.centerIn: parent
text: audioWidget.icon + " " + Math.round(Pipewire.defaultAudioSink.audio.volume * 100).toString() + "%" text: audioTextText
font.bold: true font.bold: true
font.pixelSize: 14 font.pixelSize: 14
font.family: root.fontFamily font.family: Theme.fontFamily
color: Theme.textColor color: Theme.textColor
} }
@@ -76,61 +77,8 @@ Rectangle {
command: ["pavucontrol"] command: ["pavucontrol"]
} }
Timer {
id: audioTimer
interval: 1000
onTriggered: {
audioPopUp.visible = true;
}
}
PopupWindow {
id: audioPopUp
anchor.window: root
anchor.rect.x: barArea.x
anchor.rect.y: root.implicitHeight
implicitWidth: 500
implicitHeight: 500
color: "transparent"
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "teal"
radius: 25
}
Text {
anchors.centerIn: parent
text: "opa"
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onExited: {
audioPopUp.visible = false;
}
}
}
Behavior on visible {
NumberAnimation {
duration: 1000 // Matches your original duration
}
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
onClicked: { onClicked: {
audioWidgetProcess.startDetached(); audioWidgetProcess.startDetached();
} }
@@ -147,13 +95,6 @@ Rectangle {
Pipewire.defaultAudioSink.audio.volume = (audioWidget.volume - 5) / 100; Pipewire.defaultAudioSink.audio.volume = (audioWidget.volume - 5) / 100;
} }
} }
onEntered: {
audioTimer.start();
}
onExited: {
audioPopUp.visible = false;
audioTimer.stop();
}
} }
} }

View File

@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell.Widgets import Quickshell.Widgets
import qs.Common
WrapperRectangle { WrapperRectangle {
id: barArea id: barArea
@@ -10,7 +11,8 @@ WrapperRectangle {
property var components: [] // Add this new property property var components: [] // Add this new property
color: "transparent" color: "transparent"
margin: 0 rightMargin: Theme.gaps
leftMargin: Theme.gaps
RowLayout { RowLayout {
Repeater { Repeater {

View File

@@ -7,7 +7,8 @@ Item {
property var monitor: "" property var monitor: ""
MarginWrapperManager { MarginWrapperManager {
rightMargin: 10 rightMargin: Theme.gaps
leftMargin: Theme.gaps
} }
Rectangle { Rectangle {

View File

@@ -9,6 +9,8 @@ Singleton {
readonly property int barSize: 35 readonly property int barSize: 35
readonly property double heightGaps: barSize * 0.8 readonly property double heightGaps: barSize * 0.8
readonly property string fontFamily: "Source Code Pro"
readonly property int gaps: 5
// Colors // Colors
FileView { FileView {
@@ -38,7 +40,7 @@ Singleton {
property color color7Bright: walColorsText[14] property color color7Bright: walColorsText[14]
property color foregroundColorBright: walColorsText[15] property color foregroundColorBright: walColorsText[15]
readonly property string textColor: foregroundColor readonly property color textColor: foregroundColor
// background "#0e1721" // background "#0e1721"
// color2 "#463e44" // color2 "#463e44"
// color3 "#7b4834" // color3 "#7b4834"

View File

@@ -2,12 +2,17 @@ pragma Singleton
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Wayland
Singleton { Singleton {
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE") readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
property var sortedTopLevels: { property var sortedTopLevels: {
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values) {
return []
}
const topLevels = Array.from(Hyprland.toplevels.values) const topLevels = Array.from(Hyprland.toplevels.values)
const sortedHyprland = topLevels.sort((a, b) => { const sortedHyprland = topLevels.sort((a, b) => {
if (a.monitor && b.monitor) { if (a.monitor && b.monitor) {
@@ -50,7 +55,7 @@ Singleton {
return 0 return 0
}) })
return sortedHyprland return sortedHyprland.filter(tl => tl.wayland !== null)
} }
@@ -59,8 +64,10 @@ Singleton {
} }
property var sortedDesktopApplications: { property var sortedDesktopApplications: {
const desktopEntries = sortedTopLevels.map( topLevel => { const sortedWayland = sortedTopLevels.map(topLevel => topLevel.wayland).filter(wayland=> wayland !== null)
return DesktopEntries.heuristicLookup(topLevel.wayland.appId)
const desktopEntries = sortedWayland.map( topLevel => {
return DesktopEntries.heuristicLookup(topLevel.appId)
}) })
const workspace = sortedTopLevels.map( topLevel => { const workspace = sortedTopLevels.map( topLevel => {
return topLevel.workspace.id return topLevel.workspace.id

View File

@@ -6,38 +6,92 @@ import Quickshell.Widgets
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import qs.Common import qs.Common
Item { WrapperRectangle {
id: systrayRoot
property var monitor: "" property var monitor: ""
rightMargin: Theme.gaps
leftMargin: Theme.gaps
radius: 25
MarginWrapperManager { color: Theme.backgroudColor
leftMargin: 5
}
Rectangle { // color: Theme.backgroudColor
color:"blue" RowLayout {
implicitHeight: 50 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
implicitWidth: 50 Repeater {
// color: Theme.backgroudColor model: SystemTray.items.values
radius: 25 delegate: Rectangle {
RowLayout { id: systrayItem
anchors{
horizontalCenter:parent.horizontalCenter required property var modelData
verticalCenter:parent.verticalCenter property var model: modelData
} property string iconSource: {
Repeater { let icon = systrayItem.model && systrayItem.model.icon;
model: SystemTray.items.values if (typeof icon === 'string' || icon instanceof String) {
delegate: IconImage { if (icon.includes("?path=")) {
required property var modelData const split = icon.split("?path=");
width:30; height:30 if (split.length !== 2) {
source: modelData.icon return icon;
}
const name = split[0];
const path = split[1];
const fileName = name.substring(name.lastIndexOf("/") + 1);
return `file://${path}/${fileName}`;
}
return icon;
}
return "";
}
implicitHeight: 30
implicitWidth: 30
color:"transparent"
IconImage {
anchors.verticalCenter:parent.verticalCenter
anchors.horizontalCenter:parent.horizontalCenter
width:25; height:25
source: iconSource
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: (mouse) => {
if (mouse.button === Qt.RightButton) {
const globalPos = mapToGlobal(0, 0);
const currentScreen = systrayRoot.monitor
const screenX = currentScreen.x || 0;
console.log(screenX)
const relativeX = globalPos.x - screenX;
menuAnchor.menu = systrayItem.model.menu;
menuAnchor.anchor.window = root;
menuAnchor.anchor.rect = Qt.rect(
globalPos.x,
globalPos.y+10,
1,
1
);
menuAnchor.open();
} else if (mouse.button === Qt.LeftButton) {
// systrayItem.model.activate()
}
}
onDoubleClicked: {
systrayItem.model.activate()
}
} }
} }
} }
MouseArea { }
anchors.fill: parent
onClicked: { QsMenuAnchor {
console.log(SystemTray.items.values[0].icon) id: menuAnchor
}
}
} }
} }

View File

@@ -8,7 +8,8 @@ import qs.Common
import qs.Services import qs.Services
WrapperMouseArea { WrapperMouseArea {
id: workspacesRoot id: workspacesWidget
property var monitor: "black" property var monitor: "black"
onWheel: (wheel) => { onWheel: (wheel) => {
@@ -26,28 +27,39 @@ WrapperMouseArea {
} }
RowLayout { RowLayout {
property var monitor: workspacesWidget.monitor
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Repeater { Repeater {
property var monitor: parent.monitor
model: 5 model: 5
delegate: Rectangle { delegate: Rectangle {
id: workspacesRectangle id: workspacesRectangle
required property var modelData required property var modelData
property var index: modelData // Get the workspace data from the model property var index: modelData // Get the workspace data from the model
property var workspace: { property int workspaceIndex: parent.monitor === "DP-2" ? modelData + 5 : modelData
workspacesRoot.monitor === "DP-2" ? Hyprland.workspaces.values[index + 5] : Hyprland.workspaces.values[index]; property int workspaceIndexAlign: workspaceIndex+1
} property var workspace: Hyprland.workspaces.values.length > workspaceIndex ? Hyprland.workspaces.values[workspaceIndex] : null
property var topLevels: HyprlandService.topLevelWorkspaces
property bool workspaceActive: workspace === Hyprland.focusedWorkspace? true:false
property var hasTopLevel: topLevels.filter(topLevelworkspace => topLevelworkspace.id === workspaceIndexAlign).length ? true:false
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
implicitHeight: Theme.heightGaps implicitHeight: Theme.heightGaps
implicitWidth: workspace.id === Hyprland.focusedWorkspace.id ? Theme.barSize* 1.5 : Theme.barSize implicitWidth: workspaceActive? Theme.barSize* 1.5 : Theme.barSize
radius: 25 radius: 25
color: { color: {
if (workspace.id === Hyprland.focusedWorkspace.id) { if (workspaceActive) {
return Theme.color6 return Theme.color6
} }
if (HyprlandService.topLevelWorkspaces.filter(topLevelworkspace => topLevelworkspace.id === workspace.id).length) { if (hasTopLevel) {
return Theme.backgroudColorBright return Theme.backgroudColorBright
} }
return Theme.backgroudColor return Theme.backgroudColor
@@ -55,27 +67,45 @@ WrapperMouseArea {
PopupWindow { PopupWindow {
id: workspacesPopUp id: workspacesPopUp
property int workspaceIndexAlign: workspacesRectangle.workspaceIndexAlign
anchor.item: workspacesRectangle anchor.item: workspacesRectangle
anchor.rect.y: workspacesRectangle.implicitHeight+5 anchor.rect.y: workspacesRectangle.implicitHeight+5
anchor.rect.x: -implicitWidth/2 + workspacesRectangle.implicitWidth/2 anchor.rect.x: -implicitWidth/2 + workspacesRectangle.implicitWidth/2
implicitWidth: wsPopUpRow.implicitWidth*1.6 implicitWidth: wsPopUp.implicitWidth
implicitHeight: 35 implicitHeight: wsPopUp.implicitHeight
color:"transparent" color:"transparent"
WrapperRectangle {
id: wsPopUp
Rectangle { property int workspaceIndexAlign: workspacesPopUp.workspaceIndexAlign
anchors.fill: parent
leftMargin: Theme.gaps*2
rightMargin: Theme.gaps*2
topMargin: Theme.gaps
bottomMargin: Theme.gaps
color: Theme.backgroudColor color: Theme.backgroudColor
radius: 25 radius: 25
RowLayout { RowLayout {
id: wsPopUpRow
property int workspaceIndexAlign: parent.workspaceIndexAlign
anchors{ anchors{
horizontalCenter:parent.horizontalCenter horizontalCenter:parent.horizontalCenter
verticalCenter:parent.verticalCenter verticalCenter:parent.verticalCenter
} }
id: wsPopUpRow
Repeater { Repeater {
model: HyprlandService.sortedDesktopApplications.get(workspacesRectangle.workspace.id)
property var modelo: HyprlandService.sortedDesktopApplications.get(parent.workspaceIndexAlign)
model: modelo
delegate: IconImage { delegate: IconImage {
required property var modelData required property var modelData
width:30; height:30 width:30; height:30
source: (modelData && modelData.icon) ? Quickshell.iconPath(modelData.icon, 1) : "" source: (modelData && modelData.icon) ? Quickshell.iconPath(modelData.icon, 1) : ""
} }
@@ -85,12 +115,16 @@ WrapperMouseArea {
} }
Timer { Timer {
id: workspacesTimer id: workspacesTimer
interval: 300 interval: 300
onTriggered: { workspacesPopUp.visible = true } onTriggered: { workspacesPopUp.visible = true }
} }
Text { Text {
property int workspaceName: workspacesRectangle.workspaceIndexAlign > 5? workspacesRectangle.workspaceIndexAlign -5: workspacesRectangle.workspaceIndexAlign
anchors.centerIn: parent anchors.centerIn: parent
text: workspacesRoot.monitor === "DP-2" ? workspacesRectangle.workspace.id - 5 : workspacesRectangle.workspace.id text: workspaceName
font.bold: true font.bold: true
font.pixelSize: 14 font.pixelSize: 14
font.family: Theme.fontFamily font.family: Theme.fontFamily
@@ -100,7 +134,7 @@ WrapperMouseArea {
MouseArea { MouseArea {
hoverEnabled: true hoverEnabled: true
onEntered: { onEntered: {
if (HyprlandService.sortedDesktopApplications.get(workspacesRectangle.workspace.id)){ if (parent.hasTopLevel) {
workspacesTimer.start() workspacesTimer.start()
} }
} }

View File

@@ -1,3 +1,4 @@
//@ pragma UseQApplication
import Quickshell import Quickshell
ShellRoot { ShellRoot {