From 2e466abf719d64cbc2d134dfcdcc43d19ec7afbb Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 10 Apr 2025 00:16:42 +0200
Subject: [PATCH 001/795] empty bar
---
.config/quickshell/modules/bar/Bar.qml | 54 ++++++++++
.../quickshell/modules/bar/ClockWidget.qml | 6 ++
.../quickshell/modules/common/Appearance.qml | 101 ++++++++++++++++++
.../quickshell/modules/common/DateTime.qml | 19 ++++
.config/quickshell/shell.qml | 11 ++
5 files changed, 191 insertions(+)
create mode 100644 .config/quickshell/modules/bar/Bar.qml
create mode 100644 .config/quickshell/modules/bar/ClockWidget.qml
create mode 100644 .config/quickshell/modules/common/Appearance.qml
create mode 100644 .config/quickshell/modules/common/DateTime.qml
create mode 100644 .config/quickshell/shell.qml
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
new file mode 100644
index 000000000..21c97db90
--- /dev/null
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -0,0 +1,54 @@
+import "../common"
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+
+Scope {
+ Variants {
+ model: Quickshell.screens
+
+ PanelWindow {
+ property var modelData
+
+ screen: modelData
+ height: 40
+ color: Appearance.colors.colLayer0
+
+ // Left section
+ RowLayout {
+ anchors.left: parent.left
+ }
+
+ // Middle section
+ RowLayout {
+ anchors.top: parent.top
+ anchors.bottom: parent.top
+ anchors.centerIn: parent
+
+ // Rectangle {
+
+ // }
+
+ // ClockWidget {
+ // Layout.fillHeight: true
+ // }
+
+ }
+
+ // Right section
+ RowLayout {
+ anchors.right: parent.right
+ }
+
+ anchors {
+ top: true
+ left: true
+ right: true
+ }
+
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/bar/ClockWidget.qml b/.config/quickshell/modules/bar/ClockWidget.qml
new file mode 100644
index 000000000..2ab37f1bc
--- /dev/null
+++ b/.config/quickshell/modules/bar/ClockWidget.qml
@@ -0,0 +1,6 @@
+import QtQuick
+import "../common"
+
+Text {
+ text: DateTime.time
+}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
new file mode 100644
index 000000000..dafe130dc
--- /dev/null
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -0,0 +1,101 @@
+import QtQuick
+import Quickshell
+pragma Singleton
+
+Singleton {
+ property QtObject m3colors
+ property QtObject colors
+
+ function mix(color1, color2, percentage) {
+ var c1 = Qt.color(color1);
+ var c2 = Qt.color(color2);
+ return Qt.rgba((1 - percentage) * c1.r + percentage * c2.r, (1 - percentage) * c1.g + percentage * c2.g, (1 - percentage) * c1.b + percentage * c2.b, (1 - percentage) * c1.a + percentage * c2.a);
+ }
+
+ m3colors: QtObject {
+ property bool darkmode: false
+ property bool transparent: false
+ property color m3primary_paletteKeyColor: "#8A7175"
+ property color m3secondary_paletteKeyColor: "#847376"
+ property color m3tertiary_paletteKeyColor: "#8F6E74"
+ property color m3neutral_paletteKeyColor: "#7B7676"
+ property color m3neutral_variant_paletteKeyColor: "#7B7676"
+ property color m3background: "#FFF8F7"
+ property color m3onBackground: "#1E1B1B"
+ property color m3surface: "#FFF8F7"
+ property color m3surfaceDim: "#E0D8D8"
+ property color m3surfaceBright: "#FFF8F7"
+ property color m3surfaceContainerLowest: "#FFFFFF"
+ property color m3surfaceContainerLow: "#FAF2F2"
+ property color m3surfaceContainer: "#F4ECEC"
+ property color m3surfaceContainerHigh: "#EEE6E6"
+ property color m3surfaceContainerHighest: "#E8E1E1"
+ property color m3onSurface: "#1E1B1B"
+ property color m3surfaceVariant: "#E8E1E1"
+ property color m3onSurfaceVariant: "#4A4646"
+ property color m3inverseSurface: "#332F30"
+ property color m3inverseOnSurface: "#F7EFEF"
+ property color m3outline: "#797373"
+ property color m3outlineVariant: "#CCC5C5"
+ property color m3shadow: "#000000"
+ property color m3scrim: "#000000"
+ property color m3surfaceTint: "#70585D"
+ property color m3primary: "#70585D"
+ property color m3onPrimary: "#FFFFFF"
+ property color m3primaryContainer: "#FADBE0"
+ property color m3onPrimaryContainer: "#564145"
+ property color m3inversePrimary: "#DDBFC4"
+ property color m3secondary: "#6A5A5D"
+ property color m3onSecondary: "#FFFFFF"
+ property color m3secondaryContainer: "#F3DDE0"
+ property color m3onSecondaryContainer: "#524346"
+ property color m3tertiary: "#8D6C72"
+ property color m3onTertiary: "#FFFFFF"
+ property color m3tertiaryContainer: "#8D6C72"
+ property color m3onTertiaryContainer: "#FFFFFF"
+ property color m3error: "#BA1A1A"
+ property color m3onError: "#FFFFFF"
+ property color m3errorContainer: "#FFDAD6"
+ property color m3onErrorContainer: "#93000A"
+ property color m3primaryFixed: "#FADBE0"
+ property color m3primaryFixedDim: "#DDBFC4"
+ property color m3onPrimaryFixed: "#28171A"
+ property color m3onPrimaryFixedVariant: "#564145"
+ property color m3secondaryFixed: "#F3DDE0"
+ property color m3secondaryFixedDim: "#D6C2C4"
+ property color m3onSecondaryFixed: "#24191B"
+ property color m3onSecondaryFixedVariant: "#524346"
+ property color m3tertiaryFixed: "#FFD9DF"
+ property color m3tertiaryFixedDim: "#E4BDC3"
+ property color m3onTertiaryFixed: "#2B151A"
+ property color m3onTertiaryFixedVariant: "#5B3F45"
+ property color m3success: "#4F6354"
+ property color m3onSuccess: "#FFFFFF"
+ property color m3successContainer: "#D1E8D5"
+ property color m3onSuccessContainer: "#0C1F13"
+ property color term0: "#EDE4E4"
+ property color term1: "#B52755"
+ property color term2: "#A97363"
+ property color term3: "#AF535D"
+ property color term4: "#A67F7C"
+ property color term5: "#B2416B"
+ property color term6: "#8D76AD"
+ property color term7: "#272022"
+ property color term8: "#0E0D0D"
+ property color term9: "#B52755"
+ property color term10: "#A97363"
+ property color term11: "#AF535D"
+ property color term12: "#A67F7C"
+ property color term13: "#B2416B"
+ property color term14: "#8D76AD"
+ property color term15: "#221A1A"
+ }
+
+ colors: QtObject {
+ property color colLayer0: m3colors.m3background
+ property color colOnLayer0: m3colors.m3onBackground
+ property color colLayer0Hover: mix(colLayer0, colOnLayer0, 0.85)
+ property color colLayer0Active: m3colors.m3surfaceContainerHigh
+ }
+
+}
diff --git a/.config/quickshell/modules/common/DateTime.qml b/.config/quickshell/modules/common/DateTime.qml
new file mode 100644
index 000000000..a217b1ac9
--- /dev/null
+++ b/.config/quickshell/modules/common/DateTime.qml
@@ -0,0 +1,19 @@
+import QtQuick
+import Quickshell
+import Quickshell.Io
+// with this line our type becomes a singleton
+pragma Singleton
+
+// your singletons should always have Singleton as the type
+Singleton {
+ property string time: Qt.formatDateTime(clock.date, "hh:mm")
+ // something like Wednesday, 09/04
+ property string date: Qt.formatDateTime(clock.date, "dddd, dd/MM")
+
+ SystemClock {
+ id: clock
+
+ precision: SystemClock.Minutes
+ }
+
+}
diff --git a/.config/quickshell/shell.qml b/.config/quickshell/shell.qml
new file mode 100644
index 000000000..aeb4b2ba1
--- /dev/null
+++ b/.config/quickshell/shell.qml
@@ -0,0 +1,11 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import "./modules/bar"
+
+ShellRoot {
+ Bar {
+ }
+
+}
From 179be02e0d79cb3ede42af319aa9b31990177a65 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 10 Apr 2025 00:19:17 +0200
Subject: [PATCH 002/795] Update README.md
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 39213c596..af4a74e69 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+# QUICKSHELL, WIP, DO NOT USE
+
+i hope ill actually properly learn quickshell this time
+
【 end_4's Hyprland dotfiles 】
From 91cef5700a14c0198fd3ee0cd8ef01cd5f36e5f8 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 10 Apr 2025 02:06:15 +0200
Subject: [PATCH 003/795] clock
---
.config/quickshell/modules/bar/Bar.qml | 30 +++++++++----
.../quickshell/modules/bar/ClockWidget.qml | 44 +++++++++++++++++--
.../quickshell/modules/bar/UtilButtons.qml | 19 ++++++++
.../quickshell/modules/common/Appearance.qml | 38 +++++++++++++++-
.../quickshell/modules/common/DateTime.qml | 1 -
5 files changed, 119 insertions(+), 13 deletions(-)
create mode 100644 .config/quickshell/modules/bar/UtilButtons.qml
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index 21c97db90..f8d92db9b 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -22,17 +22,31 @@ Scope {
// Middle section
RowLayout {
- anchors.top: parent.top
- anchors.bottom: parent.top
anchors.centerIn: parent
+ implicitWidth: 500
- // Rectangle {
-
- // }
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
- // ClockWidget {
- // Layout.fillHeight: true
- // }
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ ClockWidget {
+ Layout.alignment: Qt.AlignVCenter
+ }
+ UtilButtons {
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ }
}
diff --git a/.config/quickshell/modules/bar/ClockWidget.qml b/.config/quickshell/modules/bar/ClockWidget.qml
index 2ab37f1bc..6e8785eff 100644
--- a/.config/quickshell/modules/bar/ClockWidget.qml
+++ b/.config/quickshell/modules/bar/ClockWidget.qml
@@ -1,6 +1,44 @@
-import QtQuick
import "../common"
+import QtQuick
+import QtQuick.Layouts
+
+Rectangle {
+ implicitWidth: 200
+ implicitHeight: 32
+ color: Appearance.colors.colLayer1
+ radius: Appearance.rounding.small
+
+ RowLayout {
+ spacing: 4
+ anchors.centerIn: parent
+
+ Text {
+ renderType: Text.NativeRendering
+ verticalAlignment: Text.AlignVCenter
+ font.family: Appearance.font.family.title
+ font.pointSize: Appearance.font.pointSize.large
+ text: DateTime.time
+ color: Appearance.colors.colOnLayer1
+ }
+
+ Text {
+ renderType: Text.NativeRendering
+ verticalAlignment: Text.AlignVCenter
+ font.family: Appearance.font.family.main
+ font.pointSize: Appearance.font.pointSize.small
+ text: "•"
+ color: Appearance.colors.colOnLayer1
+ }
+
+ Text {
+ renderType: Text.NativeRendering
+ verticalAlignment: Text.AlignVCenter
+ font.family: Appearance.font.family.main
+ font.pointSize: Appearance.font.pointSize.small
+ text: DateTime.date
+ color: Appearance.colors.colOnLayer1
+ }
+
+ }
-Text {
- text: DateTime.time
}
diff --git a/.config/quickshell/modules/bar/UtilButtons.qml b/.config/quickshell/modules/bar/UtilButtons.qml
new file mode 100644
index 000000000..def2bb629
--- /dev/null
+++ b/.config/quickshell/modules/bar/UtilButtons.qml
@@ -0,0 +1,19 @@
+import "../common"
+import QtQuick
+import QtQuick.Layouts
+
+Rectangle {
+ implicitWidth: 200
+ implicitHeight: 32
+ color: Appearance.colors.colLayer1
+ radius: Appearance.rounding.small
+
+ RowLayout {
+ spacing: 4
+ anchors.centerIn: parent
+
+
+
+ }
+
+}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index dafe130dc..ce9a01be3 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -5,11 +5,13 @@ pragma Singleton
Singleton {
property QtObject m3colors
property QtObject colors
+ property QtObject rounding
+ property QtObject font
function mix(color1, color2, percentage) {
var c1 = Qt.color(color1);
var c2 = Qt.color(color2);
- return Qt.rgba((1 - percentage) * c1.r + percentage * c2.r, (1 - percentage) * c1.g + percentage * c2.g, (1 - percentage) * c1.b + percentage * c2.b, (1 - percentage) * c1.a + percentage * c2.a);
+ return Qt.rgba(percentage * c1.r + (1 - percentage) * c2.r, percentage * c1.g + (1 - percentage) * c2.g, percentage * c1.b + (1 - percentage) * c2.b, percentage * c1.a + (1 - percentage) * c2.a);
}
m3colors: QtObject {
@@ -96,6 +98,40 @@ Singleton {
property color colOnLayer0: m3colors.m3onBackground
property color colLayer0Hover: mix(colLayer0, colOnLayer0, 0.85)
property color colLayer0Active: m3colors.m3surfaceContainerHigh
+ property color colLayer1: m3colors.m3surfaceContainerLow;
+ property color colOnLayer1: m3colors.m3onSurfaceVariant;
+ property color colOnLayer1Inactive: mix(colOnLayer1, colLayer1, 0.45);
+ property color colLayer2: mix(m3colors.m3surfaceContainer, m3colors.m3surfaceContainerHigh, 0.55);
+ property color colOnLayer2: m3colors.m3onSurface;
+ property color colLayer3: mix(m3colors.m3surfaceContainerHigh, m3colors.m3onSurface, 0.96);
+ property color colOnLayer3: m3colors.m3onSurface;
+ }
+
+ rounding: QtObject {
+ property int unsharpen: 2
+ property int verysmall: 8
+ property int small: 12
+ property int normal: 17
+ property int large: 25
+ property int full: 9999
+ }
+
+ font: QtObject {
+ property QtObject family: QtObject {
+ property string main: "Rubik"
+ property string title: "Gabarito"
+ property string iconMaterial: "Material Symbols Rounded"
+ property string iconNerd: "SpaceMono NF"
+ property string monospace: "JetBrains Mono NF"
+ property string reading: "Readex Pro"
+ }
+ property QtObject pointSize: QtObject {
+ property int smaller: 10
+ property int small: 11
+ property int normal: 12
+ property int large: 13
+ property int larger: 16
+ }
}
}
diff --git a/.config/quickshell/modules/common/DateTime.qml b/.config/quickshell/modules/common/DateTime.qml
index a217b1ac9..6e29ec968 100644
--- a/.config/quickshell/modules/common/DateTime.qml
+++ b/.config/quickshell/modules/common/DateTime.qml
@@ -7,7 +7,6 @@ pragma Singleton
// your singletons should always have Singleton as the type
Singleton {
property string time: Qt.formatDateTime(clock.date, "hh:mm")
- // something like Wednesday, 09/04
property string date: Qt.formatDateTime(clock.date, "dddd, dd/MM")
SystemClock {
From 15990bf8d1b3ca8754e183e78065e28fa84a841c Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 10 Apr 2025 12:55:26 +0200
Subject: [PATCH 004/795] utilbuttons
---
.../quickshell/modules/bar/ClockWidget.qml | 25 ++++------
.../quickshell/modules/bar/UtilButtons.qml | 46 ++++++++++++++++++-
.../quickshell/modules/common/Appearance.qml | 6 ++-
.../modules/common/widgets/MaterialSymbol.qml | 11 +++++
.../common/widgets/SmallCircleButton.qml | 25 ++++++++++
.../modules/common/widgets/StyledText.qml | 11 +++++
6 files changed, 106 insertions(+), 18 deletions(-)
create mode 100644 .config/quickshell/modules/common/widgets/MaterialSymbol.qml
create mode 100644 .config/quickshell/modules/common/widgets/SmallCircleButton.qml
create mode 100644 .config/quickshell/modules/common/widgets/StyledText.qml
diff --git a/.config/quickshell/modules/bar/ClockWidget.qml b/.config/quickshell/modules/bar/ClockWidget.qml
index 6e8785eff..d001f1db7 100644
--- a/.config/quickshell/modules/bar/ClockWidget.qml
+++ b/.config/quickshell/modules/bar/ClockWidget.qml
@@ -1,42 +1,37 @@
import "../common"
+import "../common/widgets"
import QtQuick
import QtQuick.Layouts
Rectangle {
- implicitWidth: 200
+ implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 6 // idk, text seems nicer w/ more padding
implicitHeight: 32
color: Appearance.colors.colLayer1
radius: Appearance.rounding.small
RowLayout {
+ id: rowLayout
+
spacing: 4
anchors.centerIn: parent
- Text {
- renderType: Text.NativeRendering
- verticalAlignment: Text.AlignVCenter
+ StyledText {
font.family: Appearance.font.family.title
font.pointSize: Appearance.font.pointSize.large
+ color: Appearance.colors.colOnLayer1
text: DateTime.time
- color: Appearance.colors.colOnLayer1
}
- Text {
- renderType: Text.NativeRendering
- verticalAlignment: Text.AlignVCenter
- font.family: Appearance.font.family.main
+ StyledText {
font.pointSize: Appearance.font.pointSize.small
+ color: Appearance.colors.colOnLayer1
text: "•"
- color: Appearance.colors.colOnLayer1
}
- Text {
- renderType: Text.NativeRendering
- verticalAlignment: Text.AlignVCenter
- font.family: Appearance.font.family.main
+ StyledText {
font.pointSize: Appearance.font.pointSize.small
- text: DateTime.date
color: Appearance.colors.colOnLayer1
+ text: DateTime.date
}
}
diff --git a/.config/quickshell/modules/bar/UtilButtons.qml b/.config/quickshell/modules/bar/UtilButtons.qml
index def2bb629..eb0af110f 100644
--- a/.config/quickshell/modules/bar/UtilButtons.qml
+++ b/.config/quickshell/modules/bar/UtilButtons.qml
@@ -1,18 +1,60 @@
import "../common"
+import "../common/widgets"
import QtQuick
import QtQuick.Layouts
+import Quickshell
+import Quickshell.Io
Rectangle {
- implicitWidth: 200
+ Layout.alignment: Qt.AlignVCenter
+ implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: 32
color: Appearance.colors.colLayer1
radius: Appearance.rounding.small
+ Process {
+ id: screenSnip
+
+ command: ["grimblast", "copy", "area"]
+ }
+
+ Process {
+ id: pickColor
+
+ command: ["hyprpicker", "-a"]
+ }
+
RowLayout {
+ id: rowLayout
+
spacing: 4
anchors.centerIn: parent
-
+ SmallCircleButton {
+ Layout.alignment: Qt.AlignVCenter
+ onClicked: screenSnip.running = true
+
+ MaterialSymbol {
+ anchors.centerIn: parent
+ text: "screenshot_region"
+ font.pointSize: Appearance.font.pointSize.normal
+ color: Appearance.colors.colOnLayer2
+ }
+
+ }
+
+ SmallCircleButton {
+ Layout.alignment: Qt.AlignVCenter
+ onClicked: pickColor.running = true
+
+ MaterialSymbol {
+ anchors.centerIn: parent
+ text: "colorize"
+ font.pointSize: Appearance.font.pointSize.normal
+ color: Appearance.colors.colOnLayer2
+ }
+
+ }
}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index ce9a01be3..44f79a4a1 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -105,6 +105,10 @@ Singleton {
property color colOnLayer2: m3colors.m3onSurface;
property color colLayer3: mix(m3colors.m3surfaceContainerHigh, m3colors.m3onSurface, 0.96);
property color colOnLayer3: m3colors.m3onSurface;
+ property color colLayer2Hover: mix(colLayer2, colOnLayer2, 0.90);
+ property color colLayer2Active: mix(colLayer2, colOnLayer2, 0.80);
+ property color colLayer3Hover: mix(colLayer3, colOnLayer3, 0.90);
+ property color colLayer3Active: mix(colLayer3, colOnLayer3, 0.80);
}
rounding: QtObject {
@@ -119,7 +123,7 @@ Singleton {
font: QtObject {
property QtObject family: QtObject {
property string main: "Rubik"
- property string title: "Gabarito"
+ property string title: "Rubik"
property string iconMaterial: "Material Symbols Rounded"
property string iconNerd: "SpaceMono NF"
property string monospace: "JetBrains Mono NF"
diff --git a/.config/quickshell/modules/common/widgets/MaterialSymbol.qml b/.config/quickshell/modules/common/widgets/MaterialSymbol.qml
new file mode 100644
index 000000000..4f0f6a0d4
--- /dev/null
+++ b/.config/quickshell/modules/common/widgets/MaterialSymbol.qml
@@ -0,0 +1,11 @@
+import "../"
+import QtQuick
+import QtQuick.Layouts
+
+Text {
+ renderType: Text.NativeRendering
+ verticalAlignment: Text.AlignVCenter
+ font.family: Appearance.font.family.iconMaterial
+ font.pointSize: Appearance.font.pointSize.small
+ color: Appearance.colors.colOnBackground
+}
diff --git a/.config/quickshell/modules/common/widgets/SmallCircleButton.qml b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
new file mode 100644
index 000000000..c1df4855f
--- /dev/null
+++ b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
@@ -0,0 +1,25 @@
+import "../"
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Io
+import Quickshell.Wayland
+
+Button {
+ id: button
+ implicitWidth: 26
+ implicitHeight: 26
+
+ required default property Item content
+ property bool extraActiveCondition: false
+
+ contentItem: content
+
+ background: Rectangle {
+ anchors.fill: parent
+ radius: Appearance.rounding.full
+ color: (button.down || extraActiveCondition) ? Appearance.colors.colLayer2Active : (button.hovered ? Appearance.colors.colLayer2Hover : Appearance.colors.colLayer2)
+ }
+
+}
diff --git a/.config/quickshell/modules/common/widgets/StyledText.qml b/.config/quickshell/modules/common/widgets/StyledText.qml
new file mode 100644
index 000000000..190e0b1cf
--- /dev/null
+++ b/.config/quickshell/modules/common/widgets/StyledText.qml
@@ -0,0 +1,11 @@
+import "../"
+import QtQuick
+import QtQuick.Layouts
+
+Text {
+ renderType: Text.NativeRendering
+ verticalAlignment: Text.AlignVCenter
+ font.family: Appearance.font.family.main
+ font.pointSize: Appearance.font.pointSize.small
+ color: Appearance.colors.colOnBackground
+}
From 5c88c6a5a6746fa27146215fea4c21384a771351 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 10 Apr 2025 13:09:49 +0200
Subject: [PATCH 005/795] button color anims
---
.config/quickshell/modules/common/Appearance.qml | 9 +++++++++
.../modules/common/widgets/SmallCircleButton.qml | 14 ++++++++++++--
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index 44f79a4a1..155f80dc3 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -4,6 +4,7 @@ pragma Singleton
Singleton {
property QtObject m3colors
+ property QtObject animation
property QtObject colors
property QtObject rounding
property QtObject font
@@ -138,4 +139,12 @@ Singleton {
}
}
+ animation: QtObject {
+ property QtObject elementDecel: QtObject {
+ property int duration: 100
+ property int type: Easing.BezierSpline
+ property list
bezierCurve: [0, 0.55, 0.45, 1]
+ }
+ }
+
}
diff --git a/.config/quickshell/modules/common/widgets/SmallCircleButton.qml b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
index c1df4855f..545887bfa 100644
--- a/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
+++ b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
@@ -8,18 +8,28 @@ import Quickshell.Wayland
Button {
id: button
- implicitWidth: 26
- implicitHeight: 26
required default property Item content
property bool extraActiveCondition: false
+ implicitWidth: 26
+ implicitHeight: 26
contentItem: content
background: Rectangle {
anchors.fill: parent
radius: Appearance.rounding.full
color: (button.down || extraActiveCondition) ? Appearance.colors.colLayer2Active : (button.hovered ? Appearance.colors.colLayer2Hover : Appearance.colors.colLayer2)
+
+ Behavior on color {
+ ColorAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
+ }
+
+ }
+
}
}
From ff93725b28f57b9c9df20e5decb2a4f685789dad Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 10 Apr 2025 17:03:57 +0200
Subject: [PATCH 006/795] the perfect workspace indicator
---
.config/quickshell/modules/bar/Bar.qml | 11 +
.config/quickshell/modules/bar/Workspaces.qml | 198 ++++++++++++++++++
.../quickshell/modules/common/Appearance.qml | 4 +
.../modules/common/ConfigOptions.qml | 10 +
.../common/widgets/SmallCircleButton.qml | 1 -
5 files changed, 223 insertions(+), 1 deletion(-)
create mode 100644 .config/quickshell/modules/bar/Workspaces.qml
create mode 100644 .config/quickshell/modules/common/ConfigOptions.qml
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index f8d92db9b..acbc8a0b3 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -9,6 +9,7 @@ Scope {
model: Quickshell.screens
PanelWindow {
+ id: barRoot
property var modelData
screen: modelData
@@ -24,8 +25,10 @@ Scope {
RowLayout {
anchors.centerIn: parent
implicitWidth: 500
+ spacing: 8 // TODO: Why is this halved when rendered??
RowLayout {
+ spacing: 4
Layout.fillWidth: true
Layout.fillHeight: true
}
@@ -33,15 +36,23 @@ Scope {
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
+ spacing: 4
+
+ Workspaces {
+ bar: barRoot
+ }
+
}
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
+ spacing: 4
ClockWidget {
Layout.alignment: Qt.AlignVCenter
}
+
UtilButtons {
Layout.alignment: Qt.AlignVCenter
}
diff --git a/.config/quickshell/modules/bar/Workspaces.qml b/.config/quickshell/modules/bar/Workspaces.qml
new file mode 100644
index 000000000..1f7c0dab3
--- /dev/null
+++ b/.config/quickshell/modules/bar/Workspaces.qml
@@ -0,0 +1,198 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Hyprland
+import Quickshell.Io
+
+Rectangle {
+ required property var bar
+ readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
+ readonly property list workspaceOccupied: []
+ readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / ConfigOptions.bar.workspacesShown)
+ property int widgetPadding: 4
+ property int workspaceButtonWidth: 26
+ property int activeWorkspaceMargin: 1
+ property double animatedActiveWorkspaceIndex: (monitor.activeWorkspace?.id - 1) % ConfigOptions.bar.workspacesShown
+
+ Behavior on animatedActiveWorkspaceIndex {
+ NumberAnimation {
+ duration: Appearance.animation.menuDecel.duration
+ easing.type: Appearance.animation.menuDecel.type
+ }
+
+ }
+
+ // Function to update workspaceOccupied
+ function updateWorkspaceOccupied() {
+ workspaceOccupied = Array.from({ length: ConfigOptions.bar.workspacesShown }, (_, i) => {
+ return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * ConfigOptions.bar.workspacesShown + i + 1);
+ });
+ }
+
+ // Initialize workspaceOccupied when the component is created
+ Component.onCompleted: updateWorkspaceOccupied()
+
+ // Listen for changes in Hyprland.workspaces.values
+ Connections {
+ target: Hyprland.workspaces
+ function onValuesChanged() {
+ updateWorkspaceOccupied();
+ }
+ }
+
+
+ Layout.fillHeight: true
+ implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
+ implicitHeight: 40
+ color: "transparent"
+
+ // Background
+ Rectangle {
+ z: 0
+ anchors.centerIn: parent
+ implicitHeight: 32
+ implicitWidth: rowLayout.implicitWidth + widgetPadding * 2
+ radius: Appearance.rounding.small
+ color: Appearance.colors.colLayer1
+ }
+
+ // Scroll to switch workspaces
+ WheelHandler {
+ onWheel: (event) => {
+ if (event.angleDelta.y < 0)
+ Hyprland.dispatch(`workspace r+1`);
+ else if (event.angleDelta.y > 0)
+ Hyprland.dispatch(`workspace r-1`);
+ }
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
+ }
+
+ // Workspaces - background
+ RowLayout {
+ id: rowLayout
+ z: 1
+
+ spacing: 0
+ anchors.fill: parent
+ implicitHeight: 40
+
+ Repeater {
+ model: ConfigOptions.bar.workspacesShown
+
+ Rectangle {
+ z: 1
+ implicitWidth: workspaceButtonWidth
+ implicitHeight: workspaceButtonWidth
+ radius: Appearance.rounding.full
+ property var radiusLeft: workspaceOccupied[index-1] ? 0 : Appearance.rounding.full
+ property var radiusRight: workspaceOccupied[index+1] ? 0 : Appearance.rounding.full
+
+ topLeftRadius: radiusLeft
+ bottomLeftRadius: radiusLeft
+ topRightRadius: radiusRight
+ bottomRightRadius: radiusRight
+
+ color: Appearance.colors.colLayer2
+ opacity: workspaceOccupied[index] ? 1 : 0
+ // color: workspaceOccupied[index] ? Appearance.colors.colLayer2 : "transparent"
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
+ }
+ }
+ Behavior on radiusLeft {
+ NumberAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
+ }
+ }
+
+ Behavior on radiusRight {
+ NumberAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+ // Active workspace
+ Rectangle {
+ z: 2
+ implicitWidth: workspaceButtonWidth - activeWorkspaceMargin * 2
+ implicitHeight: workspaceButtonWidth - activeWorkspaceMargin * 2
+ radius: Appearance.rounding.full
+ color: Appearance.m3colors.m3primary
+ anchors.verticalCenter: parent.verticalCenter
+ x: animatedActiveWorkspaceIndex * workspaceButtonWidth + activeWorkspaceMargin
+ }
+
+ // Workspaces - numbers
+ RowLayout {
+ id: rowLayoutNumbers
+ z: 3
+
+ spacing: 0
+ anchors.fill: parent
+ implicitHeight: 40
+
+ Repeater {
+ model: ConfigOptions.bar.workspacesShown
+
+ Button {
+ id: button
+ Layout.fillHeight: true
+ topInset: 7
+ bottomInset: 7
+ onPressed: Hyprland.dispath(`workspace ${index+1}`)
+ width: workspaceButtonWidth
+
+ contentItem: StyledText {
+ z: 3
+ property int workspaceValue: workspaceGroup * ConfigOptions.bar.workspacesShown + index + 1
+
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pointSize: Appearance.font.pointSize.small
+ text: `${workspaceValue}`
+ elide: Text.ElideRight
+ color: (monitor.activeWorkspace?.id == workspaceValue) ? Appearance.m3colors.m3onPrimary : (workspaceOccupied[index] ? Appearance.colors.colOnLayer1 : Appearance.colors.colOnLayer1Inactive)
+
+ Behavior on color {
+ ColorAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
+ }
+
+ }
+
+ }
+
+ background: Rectangle {
+ color: "transparent" // Transparent background
+ implicitWidth: workspaceButtonWidth
+ implicitHeight: workspaceButtonWidth
+ }
+
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index 155f80dc3..00783c13c 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -145,6 +145,10 @@ Singleton {
property int type: Easing.BezierSpline
property list bezierCurve: [0, 0.55, 0.45, 1]
}
+ property QtObject menuDecel: QtObject {
+ property int duration: 250
+ property int type: Easing.OutCubic
+ }
}
}
diff --git a/.config/quickshell/modules/common/ConfigOptions.qml b/.config/quickshell/modules/common/ConfigOptions.qml
new file mode 100644
index 000000000..1ff2f2cba
--- /dev/null
+++ b/.config/quickshell/modules/common/ConfigOptions.qml
@@ -0,0 +1,10 @@
+import QtQuick
+import Quickshell
+pragma Singleton
+
+Singleton {
+ property QtObject bar: QtObject {
+ property int workspacesShown: 10
+ }
+
+}
diff --git a/.config/quickshell/modules/common/widgets/SmallCircleButton.qml b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
index 545887bfa..cd881f38b 100644
--- a/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
+++ b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
@@ -4,7 +4,6 @@ import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
-import Quickshell.Wayland
Button {
id: button
From ad63ae699f41bf22e40b0806bb47f9dda7afb2b4 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 00:05:34 +0200
Subject: [PATCH 007/795] battery
---
.config/quickshell/modules/bar/Bar.qml | 6 +-
.config/quickshell/modules/bar/Battery.qml | 98 +++++++++++
.config/quickshell/modules/bar/Workspaces.qml | 5 +-
.../modules/common/ConfigOptions.qml | 1 +
.../common/widgets/CircularProgress.qml | 69 ++++++++
licenses/LGPL-3.0.txt | 165 ++++++++++++++++++
6 files changed, 339 insertions(+), 5 deletions(-)
create mode 100644 .config/quickshell/modules/bar/Battery.qml
create mode 100644 .config/quickshell/modules/common/widgets/CircularProgress.qml
create mode 100644 licenses/LGPL-3.0.txt
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index acbc8a0b3..6785cb729 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -25,7 +25,7 @@ Scope {
RowLayout {
anchors.centerIn: parent
implicitWidth: 500
- spacing: 8 // TODO: Why is this halved when rendered??
+ spacing: 8
RowLayout {
spacing: 4
@@ -57,6 +57,10 @@ Scope {
Layout.alignment: Qt.AlignVCenter
}
+ Battery {
+ Layout.alignment: Qt.AlignVCenter
+ }
+
}
}
diff --git a/.config/quickshell/modules/bar/Battery.qml b/.config/quickshell/modules/bar/Battery.qml
new file mode 100644
index 000000000..c9c482003
--- /dev/null
+++ b/.config/quickshell/modules/bar/Battery.qml
@@ -0,0 +1,98 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Io
+import Quickshell.Services.UPower
+
+Rectangle {
+ readonly property var chargeState: UPower.displayDevice.state
+ readonly property bool isCharging: chargeState == UPowerDeviceState.Charging
+ readonly property bool isPluggedIn: isCharging || chargeState == UPowerDeviceState.PendingCharge
+ readonly property real percentage: UPower.displayDevice.percentage
+ readonly property bool isLow: percentage <= ConfigOptions.bar.batteryLowThreshold / 100
+ readonly property int batterySlideDistance: 10
+ readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer
+ readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error
+
+ implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
+ implicitHeight: 32
+ color: Appearance.colors.colLayer1
+ radius: Appearance.rounding.small
+
+ Process {
+ id: screenSnip
+
+ command: ["grimblast", "copy", "area"]
+ }
+
+ RowLayout {
+ id: rowLayout
+
+ spacing: 4
+ anchors.centerIn: parent
+
+ Rectangle {
+ implicitWidth: (isCharging ? boltIcon.width : 0) - rowLayout.spacing
+
+ Behavior on implicitWidth {
+ NumberAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
+ }
+
+ }
+
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignVCenter
+ color: Appearance.colors.colOnLayer1
+ text: `${percentage * 100}%`
+ }
+
+ CircularProgress {
+ Layout.alignment: Qt.AlignVCenter
+ lineWidth: 2
+ value: percentage
+ size: 26
+ secondaryColor: (isLow && !isCharging) ? batteryLowBackground : Appearance.m3colors.m3secondaryContainer
+ primaryColor: (isLow && !isCharging) ? batteryLowOnBackground : Appearance.m3colors.m3onSecondaryContainer
+ fill: (isLow && !isCharging)
+
+ MaterialSymbol {
+ anchors.centerIn: parent
+ text: "battery_full"
+ font.pointSize: Appearance.font.pointSize.normal
+ color: (isLow && !isCharging) ? batteryLowOnBackground : Appearance.m3colors.m3onSecondaryContainer
+ }
+
+ }
+
+ }
+
+ MaterialSymbol {
+ id: boltIcon
+
+ anchors.left: rowLayout.left
+ anchors.verticalCenter: rowLayout.verticalCenter
+ text: "bolt"
+ font.pointSize: Appearance.font.pointSize.large
+ color: Appearance.m3colors.m3onSecondaryContainer
+ visible: opacity !== 0 // Only show when charging
+ opacity: isCharging ? 1 : 0 // Keep opacity for visibility
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
+ }
+
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/bar/Workspaces.qml b/.config/quickshell/modules/bar/Workspaces.qml
index 1f7c0dab3..0eaf706a4 100644
--- a/.config/quickshell/modules/bar/Workspaces.qml
+++ b/.config/quickshell/modules/bar/Workspaces.qml
@@ -97,7 +97,6 @@ Rectangle {
color: Appearance.colors.colLayer2
opacity: workspaceOccupied[index] ? 1 : 0
- // color: workspaceOccupied[index] ? Appearance.colors.colLayer2 : "transparent"
Behavior on opacity {
NumberAnimation {
@@ -154,9 +153,7 @@ Rectangle {
Button {
id: button
Layout.fillHeight: true
- topInset: 7
- bottomInset: 7
- onPressed: Hyprland.dispath(`workspace ${index+1}`)
+ onPressed: Hyprland.dispatch(`workspace ${index+1}`)
width: workspaceButtonWidth
contentItem: StyledText {
diff --git a/.config/quickshell/modules/common/ConfigOptions.qml b/.config/quickshell/modules/common/ConfigOptions.qml
index 1ff2f2cba..4ba8f8a6b 100644
--- a/.config/quickshell/modules/common/ConfigOptions.qml
+++ b/.config/quickshell/modules/common/ConfigOptions.qml
@@ -5,6 +5,7 @@ pragma Singleton
Singleton {
property QtObject bar: QtObject {
property int workspacesShown: 10
+ property int batteryLowThreshold: 20
}
}
diff --git a/.config/quickshell/modules/common/widgets/CircularProgress.qml b/.config/quickshell/modules/common/widgets/CircularProgress.qml
new file mode 100644
index 000000000..d72760126
--- /dev/null
+++ b/.config/quickshell/modules/common/widgets/CircularProgress.qml
@@ -0,0 +1,69 @@
+// From https://github.com/rafzby/circular-progressbar
+// License: LGPL-3.0 - A copy can be found in `licenses` folder of repo
+import QtQuick 2.9
+
+Item {
+ id: root
+
+ property int size: 30
+ property int lineWidth: 2
+ property real value: 0
+ property color primaryColor: "#29b6f6"
+ property color secondaryColor: "#e0e0e0"
+ property bool fill: false
+ property int fillOverflow: 2
+ property int animationDuration: 1000
+
+ width: size
+ height: size
+ onValueChanged: {
+ canvas.degree = value * 360;
+ }
+
+ Canvas {
+ id: canvas
+
+ property real degree: 0
+
+ anchors.fill: parent
+ antialiasing: true
+ onDegreeChanged: {
+ requestPaint();
+ }
+ onPaint: {
+ var ctx = getContext("2d");
+ var x = root.width / 2;
+ var y = root.height / 2;
+ var radius = root.size / 2 - root.lineWidth;
+ var startAngle = (Math.PI / 180) * 270;
+ var fullAngle = (Math.PI / 180) * (270 + 360);
+ var progressAngle = (Math.PI / 180) * (270 + degree);
+ ctx.reset();
+ if (root.fill) {
+ ctx.fillStyle = root.secondaryColor;
+ ctx.beginPath();
+ ctx.arc(x, y, radius + fillOverflow, startAngle, fullAngle);
+ ctx.fill();
+ }
+ ctx.lineCap = 'round';
+ ctx.lineWidth = root.lineWidth;
+ ctx.beginPath();
+ ctx.arc(x, y, radius, startAngle, fullAngle);
+ ctx.strokeStyle = root.secondaryColor;
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(x, y, radius, startAngle, progressAngle);
+ ctx.strokeStyle = root.primaryColor;
+ ctx.stroke();
+ }
+
+ Behavior on degree {
+ NumberAnimation {
+ duration: root.animationDuration
+ }
+
+ }
+
+ }
+
+}
diff --git a/licenses/LGPL-3.0.txt b/licenses/LGPL-3.0.txt
new file mode 100644
index 000000000..0a041280b
--- /dev/null
+++ b/licenses/LGPL-3.0.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
From 742ec413f378574117214c9984d51252518b0ebf Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 01:16:55 +0200
Subject: [PATCH 008/795] bar resource usage indicator
---
.config/quickshell/modules/bar/Bar.qml | 5 ++
.config/quickshell/modules/bar/Battery.qml | 9 +--
.config/quickshell/modules/bar/Resource.qml | 36 ++++++++++++
.config/quickshell/modules/bar/Resources.qml | 35 ++++++++++++
.../modules/common/ConfigOptions.qml | 3 +
.../quickshell/modules/common/DateTime.qml | 4 +-
.../modules/common/ResourceUsage.qml | 56 +++++++++++++++++++
.../common/widgets/CircularProgress.qml | 5 +-
8 files changed, 140 insertions(+), 13 deletions(-)
create mode 100644 .config/quickshell/modules/bar/Resource.qml
create mode 100644 .config/quickshell/modules/bar/Resources.qml
create mode 100644 .config/quickshell/modules/common/ResourceUsage.qml
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index 6785cb729..6871a964f 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -10,6 +10,7 @@ Scope {
PanelWindow {
id: barRoot
+
property var modelData
screen: modelData
@@ -31,6 +32,10 @@ Scope {
spacing: 4
Layout.fillWidth: true
Layout.fillHeight: true
+
+ Resources {
+ }
+
}
RowLayout {
diff --git a/.config/quickshell/modules/bar/Battery.qml b/.config/quickshell/modules/bar/Battery.qml
index c9c482003..215458ec6 100644
--- a/.config/quickshell/modules/bar/Battery.qml
+++ b/.config/quickshell/modules/bar/Battery.qml
@@ -12,7 +12,6 @@ Rectangle {
readonly property bool isPluggedIn: isCharging || chargeState == UPowerDeviceState.PendingCharge
readonly property real percentage: UPower.displayDevice.percentage
readonly property bool isLow: percentage <= ConfigOptions.bar.batteryLowThreshold / 100
- readonly property int batterySlideDistance: 10
readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer
readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error
@@ -21,12 +20,6 @@ Rectangle {
color: Appearance.colors.colLayer1
radius: Appearance.rounding.small
- Process {
- id: screenSnip
-
- command: ["grimblast", "copy", "area"]
- }
-
RowLayout {
id: rowLayout
@@ -50,7 +43,7 @@ Rectangle {
StyledText {
Layout.alignment: Qt.AlignVCenter
color: Appearance.colors.colOnLayer1
- text: `${percentage * 100}%`
+ text: `${Math.round(percentage * 100)}%`
}
CircularProgress {
diff --git a/.config/quickshell/modules/bar/Resource.qml b/.config/quickshell/modules/bar/Resource.qml
new file mode 100644
index 000000000..4f231835e
--- /dev/null
+++ b/.config/quickshell/modules/bar/Resource.qml
@@ -0,0 +1,36 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Io
+
+RowLayout {
+ required property string iconName
+ required property double percentage
+ spacing: 4
+
+ CircularProgress {
+ Layout.alignment: Qt.AlignVCenter
+ lineWidth: 2
+ value: percentage
+ size: 26
+ secondaryColor: Appearance.m3colors.m3secondaryContainer
+ primaryColor: Appearance.m3colors.m3onSecondaryContainer
+
+ MaterialSymbol {
+ anchors.centerIn: parent
+ text: iconName
+ font.pointSize: Appearance.font.pointSize.normal
+ color: Appearance.m3colors.m3onSecondaryContainer
+ }
+
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignVCenter
+ color: Appearance.colors.colOnLayer1
+ text: `${Math.round(percentage * 100)}%`
+ }
+
+}
diff --git a/.config/quickshell/modules/bar/Resources.qml b/.config/quickshell/modules/bar/Resources.qml
new file mode 100644
index 000000000..ea64c8ce6
--- /dev/null
+++ b/.config/quickshell/modules/bar/Resources.qml
@@ -0,0 +1,35 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Io
+
+Rectangle {
+ implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
+ implicitHeight: 32
+ color: Appearance.colors.colLayer1
+ radius: Appearance.rounding.small
+
+ RowLayout {
+ id: rowLayout
+
+ spacing: 4
+ anchors.centerIn: parent
+
+ Resource {
+ iconName: "memory"
+ percentage: ResourceUsage.memoryUsedPercentage
+ }
+ Resource {
+ iconName: "swap_horiz"
+ percentage: ResourceUsage.swapUsedPercentage
+ }
+ Resource {
+ iconName: "settings_slow_motion"
+ percentage: ResourceUsage.cpuUsage
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/common/ConfigOptions.qml b/.config/quickshell/modules/common/ConfigOptions.qml
index 4ba8f8a6b..df7f5e154 100644
--- a/.config/quickshell/modules/common/ConfigOptions.qml
+++ b/.config/quickshell/modules/common/ConfigOptions.qml
@@ -7,5 +7,8 @@ Singleton {
property int workspacesShown: 10
property int batteryLowThreshold: 20
}
+ property QtObject resources: QtObject {
+ property int updateInterval: 3000
+ }
}
diff --git a/.config/quickshell/modules/common/DateTime.qml b/.config/quickshell/modules/common/DateTime.qml
index 6e29ec968..ddeec093e 100644
--- a/.config/quickshell/modules/common/DateTime.qml
+++ b/.config/quickshell/modules/common/DateTime.qml
@@ -1,13 +1,11 @@
import QtQuick
import Quickshell
import Quickshell.Io
-// with this line our type becomes a singleton
pragma Singleton
-// your singletons should always have Singleton as the type
Singleton {
property string time: Qt.formatDateTime(clock.date, "hh:mm")
- property string date: Qt.formatDateTime(clock.date, "dddd, dd/MM")
+ property string date: Qt.formatDateTime(clock.date, "dddd, dd/MM")
SystemClock {
id: clock
diff --git a/.config/quickshell/modules/common/ResourceUsage.qml b/.config/quickshell/modules/common/ResourceUsage.qml
new file mode 100644
index 000000000..898abbb34
--- /dev/null
+++ b/.config/quickshell/modules/common/ResourceUsage.qml
@@ -0,0 +1,56 @@
+pragma Singleton
+import QtQuick
+import Quickshell
+import Quickshell.Io
+
+Singleton {
+ property double memoryTotal: 1
+ property double memoryFree: 1
+ property double memoryUsed: memoryTotal - memoryFree
+ property double memoryUsedPercentage: memoryUsed / memoryTotal
+ property double swapTotal: 1
+ property double swapFree: 1
+ property double swapUsed: swapTotal - swapFree
+ property double swapUsedPercentage: swapUsed / swapTotal
+ property double cpuUsage: 0
+ property var previousCpuStats
+
+ Timer {
+ interval: 50
+ running: true
+ repeat: true
+ onTriggered: {
+ // Reload files
+ fileMeminfo.reload()
+ fileStat.reload()
+
+ // Parse memory and swap usage
+ const textMeminfo = fileMeminfo.text()
+ memoryTotal = Number(textMeminfo.match(/MemTotal: *(\d+)/)?.[1] ?? 1)
+ memoryFree = Number(textMeminfo.match(/MemAvailable: *(\d+)/)?.[1] ?? 0)
+ swapTotal = Number(textMeminfo.match(/SwapTotal: *(\d+)/)?.[1] ?? 1)
+ swapFree = Number(textMeminfo.match(/SwapFree: *(\d+)/)?.[1] ?? 0)
+
+ // Parse CPU usage
+ const textStat = fileStat.text()
+ const cpuLine = textStat.match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/)
+ if (cpuLine) {
+ const stats = cpuLine.slice(1).map(Number)
+ const total = stats.reduce((a, b) => a + b, 0)
+ const idle = stats[3]
+
+ if (previousCpuStats) {
+ const totalDiff = total - previousCpuStats.total
+ const idleDiff = idle - previousCpuStats.idle
+ cpuUsage = totalDiff > 0 ? (1 - idleDiff / totalDiff) : 0
+ }
+
+ previousCpuStats = { total, idle }
+ }
+ interval = ConfigOptions.resources.updateInterval
+ }
+ }
+
+ FileView { id: fileMeminfo; path: "/proc/meminfo" }
+ FileView { id: fileStat; path: "/proc/stat" }
+}
\ No newline at end of file
diff --git a/.config/quickshell/modules/common/widgets/CircularProgress.qml b/.config/quickshell/modules/common/widgets/CircularProgress.qml
index d72760126..62970f797 100644
--- a/.config/quickshell/modules/common/widgets/CircularProgress.qml
+++ b/.config/quickshell/modules/common/widgets/CircularProgress.qml
@@ -8,8 +8,8 @@ Item {
property int size: 30
property int lineWidth: 2
property real value: 0
- property color primaryColor: "#29b6f6"
- property color secondaryColor: "#e0e0e0"
+ property color primaryColor: "#70585D"
+ property color secondaryColor: "#FFF8F7"
property bool fill: false
property int fillOverflow: 2
property int animationDuration: 1000
@@ -60,6 +60,7 @@ Item {
Behavior on degree {
NumberAnimation {
duration: root.animationDuration
+ easing.type: Easing.OutCubic
}
}
From 3bb67a9a4f55203f1aea12cd714a9b100e53857f Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 01:39:31 +0200
Subject: [PATCH 009/795] bar: workspaces: better occupied state
---
.config/quickshell/modules/bar/Workspaces.qml | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/.config/quickshell/modules/bar/Workspaces.qml b/.config/quickshell/modules/bar/Workspaces.qml
index 0eaf706a4..6730a6515 100644
--- a/.config/quickshell/modules/bar/Workspaces.qml
+++ b/.config/quickshell/modules/bar/Workspaces.qml
@@ -4,14 +4,16 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
+import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Io
Rectangle {
required property var bar
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
- readonly property list workspaceOccupied: []
+ readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / ConfigOptions.bar.workspacesShown)
+ property list workspaceOccupied: []
property int widgetPadding: 4
property int workspaceButtonWidth: 26
property int activeWorkspaceMargin: 1
@@ -29,7 +31,10 @@ Rectangle {
function updateWorkspaceOccupied() {
workspaceOccupied = Array.from({ length: ConfigOptions.bar.workspacesShown }, (_, i) => {
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * ConfigOptions.bar.workspacesShown + i + 1);
- });
+ })
+ if(!activeWindow?.activated) {
+ workspaceOccupied[(monitor.activeWorkspace?.id - 1) % ConfigOptions.bar.workspacesShown] = false;
+ }
}
// Initialize workspaceOccupied when the component is created
From d9ed5434ac78ac68d1efccec3aa20113c0973883 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 14:54:22 +0200
Subject: [PATCH 010/795] bar: media indicator
---
.config/quickshell/modules/bar/Bar.qml | 17 +-
.config/quickshell/modules/bar/Battery.qml | 3 +-
.config/quickshell/modules/bar/Media.qml | 85 ++++++++++
.config/quickshell/modules/bar/Workspaces.qml | 4 -
.../quickshell/modules/common/Appearance.qml | 9 +-
.../modules/common/MprisController.qml | 159 ++++++++++++++++++
.../common/widgets/SmallCircleButton.qml | 1 -
7 files changed, 262 insertions(+), 16 deletions(-)
create mode 100644 .config/quickshell/modules/bar/Media.qml
create mode 100644 .config/quickshell/modules/common/MprisController.qml
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index 6871a964f..0e7bcabd5 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -5,6 +5,10 @@ import QtQuick.Layouts
import Quickshell
Scope {
+ id: bar
+ readonly property int barHeight: 40
+ readonly property int sideCenterModuleWidth: 360
+
Variants {
model: Quickshell.screens
@@ -14,7 +18,7 @@ Scope {
property var modelData
screen: modelData
- height: 40
+ height: barHeight
color: Appearance.colors.colLayer0
// Left section
@@ -25,17 +29,21 @@ Scope {
// Middle section
RowLayout {
anchors.centerIn: parent
- implicitWidth: 500
spacing: 8
RowLayout {
+ Layout.preferredWidth: sideCenterModuleWidth
spacing: 4
- Layout.fillWidth: true
Layout.fillHeight: true
+ implicitWidth: 350
Resources {
}
+ Media {
+ Layout.fillWidth: true
+ }
+
}
RowLayout {
@@ -50,12 +58,13 @@ Scope {
}
RowLayout {
- Layout.fillWidth: true
+ Layout.preferredWidth: sideCenterModuleWidth
Layout.fillHeight: true
spacing: 4
ClockWidget {
Layout.alignment: Qt.AlignVCenter
+ Layout.fillWidth: true
}
UtilButtons {
diff --git a/.config/quickshell/modules/bar/Battery.qml b/.config/quickshell/modules/bar/Battery.qml
index 215458ec6..b4cbea1f3 100644
--- a/.config/quickshell/modules/bar/Battery.qml
+++ b/.config/quickshell/modules/bar/Battery.qml
@@ -27,13 +27,12 @@ Rectangle {
anchors.centerIn: parent
Rectangle {
- implicitWidth: (isCharging ? boltIcon.width : 0) - rowLayout.spacing
+ implicitWidth: (isCharging ? boltIcon.width : 0)
Behavior on implicitWidth {
NumberAnimation {
duration: Appearance.animation.elementDecel.duration
easing.type: Appearance.animation.elementDecel.type
- easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
}
}
diff --git a/.config/quickshell/modules/bar/Media.qml b/.config/quickshell/modules/bar/Media.qml
new file mode 100644
index 000000000..44431f016
--- /dev/null
+++ b/.config/quickshell/modules/bar/Media.qml
@@ -0,0 +1,85 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Io
+import Quickshell.Services.Mpris
+
+Rectangle {
+ readonly property MprisPlayer activePlayer: MprisController.activePlayer
+ readonly property string cleanedTitle: activePlayer?.trackTitle.replace(/【[^】]*】/, "") || "No media"
+
+ Layout.fillHeight: true
+ implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
+ implicitHeight: 40
+ color: "transparent"
+
+ // Background
+ Rectangle {
+ anchors.centerIn: parent
+ width: parent.width
+ implicitHeight: 32
+ color: Appearance.colors.colLayer1
+ radius: Appearance.rounding.small
+ }
+
+ Timer {
+ running: activePlayer?.playbackState == MprisPlaybackState.Playing
+ interval: 1000
+ repeat: true
+ onTriggered: activePlayer.positionChanged()
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.MiddleButton | Qt.BackButton | Qt.ForwardButton | Qt.RightButton
+ onPressed: (event) => {
+ if (event.button === Qt.MiddleButton) {
+ activePlayer.togglePlaying();
+ } else if (event.button === Qt.BackButton) {
+ activePlayer.previous();
+ } else if (event.button === Qt.ForwardButton || event.button === Qt.RightButton) {
+ activePlayer.next();
+ }
+ }
+ }
+
+ RowLayout {
+ id: rowLayout
+
+ spacing: 4
+ anchors.fill: parent
+
+ CircularProgress {
+ Layout.alignment: Qt.AlignVCenter
+ Layout.leftMargin: rowLayout.spacing
+ lineWidth: 2
+ value: activePlayer?.position / activePlayer?.length
+ size: 26
+ secondaryColor: Appearance.m3colors.m3secondaryContainer
+ primaryColor: Appearance.m3colors.m3onSecondaryContainer
+
+ MaterialSymbol {
+ anchors.centerIn: parent
+ text: activePlayer?.isPlaying ? "pause" : "play_arrow"
+ font.pointSize: Appearance.font.pointSize.normal
+ color: Appearance.m3colors.m3onSecondaryContainer
+ }
+
+ }
+
+ StyledText {
+ width: rowLayout.width - (CircularProgress.size + rowLayout.spacing * 2) // TODO ADJUST THIS
+ Layout.alignment: Qt.AlignVCenter
+ Layout.fillWidth: true // Ensures the text takes up available space
+ Layout.rightMargin: rowLayout.spacing
+ horizontalAlignment: Text.AlignHCenter
+ elide: Text.ElideRight // Truncates the text on the right
+ color: Appearance.colors.colOnLayer1
+ text: `${cleanedTitle} • ${activePlayer?.trackArtist}`
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/bar/Workspaces.qml b/.config/quickshell/modules/bar/Workspaces.qml
index 6730a6515..26274d4a3 100644
--- a/.config/quickshell/modules/bar/Workspaces.qml
+++ b/.config/quickshell/modules/bar/Workspaces.qml
@@ -107,14 +107,12 @@ Rectangle {
NumberAnimation {
duration: Appearance.animation.elementDecel.duration
easing.type: Appearance.animation.elementDecel.type
- easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
}
}
Behavior on radiusLeft {
NumberAnimation {
duration: Appearance.animation.elementDecel.duration
easing.type: Appearance.animation.elementDecel.type
- easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
}
}
@@ -122,7 +120,6 @@ Rectangle {
NumberAnimation {
duration: Appearance.animation.elementDecel.duration
easing.type: Appearance.animation.elementDecel.type
- easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
}
}
@@ -177,7 +174,6 @@ Rectangle {
ColorAnimation {
duration: Appearance.animation.elementDecel.duration
easing.type: Appearance.animation.elementDecel.type
- easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
}
}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index 00783c13c..d0b62f3a4 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -141,13 +141,12 @@ Singleton {
animation: QtObject {
property QtObject elementDecel: QtObject {
- property int duration: 100
- property int type: Easing.BezierSpline
- property list bezierCurve: [0, 0.55, 0.45, 1]
+ property int duration: 180
+ property int type: Easing.OutCirc
}
property QtObject menuDecel: QtObject {
- property int duration: 250
- property int type: Easing.OutCubic
+ property int duration: 350
+ property int type: Easing.OutQuint
}
}
diff --git a/.config/quickshell/modules/common/MprisController.qml b/.config/quickshell/modules/common/MprisController.qml
new file mode 100644
index 000000000..24977f749
--- /dev/null
+++ b/.config/quickshell/modules/common/MprisController.qml
@@ -0,0 +1,159 @@
+pragma Singleton
+pragma ComponentBehavior: Bound
+
+import QtQml.Models
+import QtQuick
+import Quickshell
+import Quickshell.Io
+import Quickshell.Services.Mpris
+import "../.."
+
+Singleton {
+ id: root;
+ property MprisPlayer trackedPlayer: null;
+ property MprisPlayer activePlayer: trackedPlayer ?? Mpris.players.values[0] ?? null;
+ signal trackChanged(reverse: bool);
+
+ property bool __reverse: false;
+
+ property var activeTrack;
+
+ Instantiator {
+ model: Mpris.players;
+
+ Connections {
+ required property MprisPlayer modelData;
+ target: modelData;
+
+ Component.onCompleted: {
+ if (root.trackedPlayer == null || modelData.isPlaying) {
+ root.trackedPlayer = modelData;
+ }
+ }
+
+ Component.onDestruction: {
+ if (root.trackedPlayer == null || !root.trackedPlayer.isPlaying) {
+ for (const player of Mpris.players.values) {
+ if (player.playbackState.isPlaying) {
+ root.trackedPlayer = player;
+ break;
+ }
+ }
+
+ if (trackedPlayer == null && Mpris.players.values.length != 0) {
+ trackedPlayer = Mpris.players.values[0];
+ }
+ }
+ }
+
+ function onPlaybackStateChanged() {
+ if (root.trackedPlayer !== modelData) root.trackedPlayer = modelData;
+ }
+ }
+ }
+
+ Connections {
+ target: activePlayer
+
+ function onPostTrackChanged() {
+ root.updateTrack();
+ }
+
+ function onTrackArtUrlChanged() {
+ console.log("arturl:", activePlayer.trackArtUrl)
+ //root.updateTrack();
+ if (root.activePlayer.uniqueId == root.activeTrack.uniqueId && root.activePlayer.trackArtUrl != root.activeTrack.artUrl) {
+ // cantata likes to send cover updates *BEFORE* updating the track info.
+ // as such, art url changes shouldn't be able to break the reverse animation
+ const r = root.__reverse;
+ root.updateTrack();
+ root.__reverse = r;
+
+ }
+ }
+ }
+
+ onActivePlayerChanged: this.updateTrack();
+
+ function updateTrack() {
+ //console.log(`update: ${this.activePlayer?.trackTitle ?? ""} : ${this.activePlayer?.trackArtists}`)
+ this.activeTrack = {
+ uniqueId: this.activePlayer?.uniqueId ?? 0,
+ artUrl: this.activePlayer?.trackArtUrl ?? "",
+ title: this.activePlayer?.trackTitle || "Unknown Title",
+ artist: this.activePlayer?.trackArtist || "Unknown Artist",
+ album: this.activePlayer?.trackAlbum || "Unknown Album",
+ };
+
+ this.trackChanged(__reverse);
+ this.__reverse = false;
+ }
+
+ property bool isPlaying: this.activePlayer && this.activePlayer.isPlaying;
+ property bool canTogglePlaying: this.activePlayer?.canTogglePlaying ?? false;
+ function togglePlaying() {
+ if (this.canTogglePlaying) this.activePlayer.togglePlaying();
+ }
+
+ property bool canGoPrevious: this.activePlayer?.canGoPrevious ?? false;
+ function previous() {
+ if (this.canGoPrevious) {
+ this.__reverse = true;
+ this.activePlayer.previous();
+ }
+ }
+
+ property bool canGoNext: this.activePlayer?.canGoNext ?? false;
+ function next() {
+ if (this.canGoNext) {
+ this.__reverse = false;
+ this.activePlayer.next();
+ }
+ }
+
+ property bool canChangeVolume: this.activePlayer && this.activePlayer.volumeSupported && this.activePlayer.canControl;
+
+ property bool loopSupported: this.activePlayer && this.activePlayer.loopSupported && this.activePlayer.canControl;
+ property var loopState: this.activePlayer?.loopState ?? MprisLoopState.None;
+ function setLoopState(loopState: var) {
+ if (this.loopSupported) {
+ this.activePlayer.loopState = loopState;
+ }
+ }
+
+ property bool shuffleSupported: this.activePlayer && this.activePlayer.shuffleSupported && this.activePlayer.canControl;
+ property bool hasShuffle: this.activePlayer?.shuffle ?? false;
+ function setShuffle(shuffle: bool) {
+ if (this.shuffleSupported) {
+ this.activePlayer.shuffle = shuffle;
+ }
+ }
+
+ function setActivePlayer(player: MprisPlayer) {
+ const targetPlayer = player ?? Mpris.players[0];
+ console.log(`setactive: ${targetPlayer} from ${activePlayer}`)
+
+ if (targetPlayer && this.activePlayer) {
+ this.__reverse = Mpris.players.indexOf(targetPlayer) < Mpris.players.indexOf(this.activePlayer);
+ } else {
+ // always animate forward if going to null
+ this.__reverse = false;
+ }
+
+ this.trackedPlayer = targetPlayer;
+ }
+
+ IpcHandler {
+ target: "mpris"
+
+ function pauseAll(): void {
+ for (const player of Mpris.players.values) {
+ if (player.canPause) player.pause();
+ }
+ }
+
+ function playPause(): void { root.togglePlaying(); }
+ function previous(): void { root.previous(); }
+ function next(): void { root.next(); }
+ }
+}
diff --git a/.config/quickshell/modules/common/widgets/SmallCircleButton.qml b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
index cd881f38b..4cb2e9e61 100644
--- a/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
+++ b/.config/quickshell/modules/common/widgets/SmallCircleButton.qml
@@ -24,7 +24,6 @@ Button {
ColorAnimation {
duration: Appearance.animation.elementDecel.duration
easing.type: Appearance.animation.elementDecel.type
- easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
}
}
From c29041aa9e15eaa298cc5ad5863791cb239816f3 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 16:03:54 +0200
Subject: [PATCH 011/795] bar: resources/music: dynamic show/hide
---
.config/quickshell/modules/bar/Battery.qml | 1 -
.config/quickshell/modules/bar/Media.qml | 2 +-
.config/quickshell/modules/bar/Resource.qml | 64 +++++++++++++------
.config/quickshell/modules/bar/Resources.qml | 15 ++++-
.../quickshell/modules/common/Appearance.qml | 2 +-
.../modules/common/ConfigOptions.qml | 4 ++
.config/quickshell/shell.qml | 3 +
7 files changed, 65 insertions(+), 26 deletions(-)
diff --git a/.config/quickshell/modules/bar/Battery.qml b/.config/quickshell/modules/bar/Battery.qml
index b4cbea1f3..dc3b0d057 100644
--- a/.config/quickshell/modules/bar/Battery.qml
+++ b/.config/quickshell/modules/bar/Battery.qml
@@ -80,7 +80,6 @@ Rectangle {
NumberAnimation {
duration: Appearance.animation.elementDecel.duration
easing.type: Appearance.animation.elementDecel.type
- easing.bezierCurve: Appearance.animation.elementDecel.bezierCurve
}
}
diff --git a/.config/quickshell/modules/bar/Media.qml b/.config/quickshell/modules/bar/Media.qml
index 44431f016..e681140ad 100644
--- a/.config/quickshell/modules/bar/Media.qml
+++ b/.config/quickshell/modules/bar/Media.qml
@@ -77,7 +77,7 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight // Truncates the text on the right
color: Appearance.colors.colOnLayer1
- text: `${cleanedTitle} • ${activePlayer?.trackArtist}`
+ text: `${cleanedTitle}${activePlayer?.trackArtist ? ' • ' + activePlayer.trackArtist : ''}`
}
}
diff --git a/.config/quickshell/modules/bar/Resource.qml b/.config/quickshell/modules/bar/Resource.qml
index 4f231835e..3b7f83bfc 100644
--- a/.config/quickshell/modules/bar/Resource.qml
+++ b/.config/quickshell/modules/bar/Resource.qml
@@ -5,32 +5,56 @@ import QtQuick.Layouts
import Quickshell
import Quickshell.Io
-RowLayout {
+Rectangle {
required property string iconName
required property double percentage
- spacing: 4
+ property bool shown: true
+ clip: true
+ implicitWidth: resourceRowLayout.x < 0 ? 0 : childrenRect.width
+ implicitHeight: childrenRect.height
+ color: "transparent"
- CircularProgress {
- Layout.alignment: Qt.AlignVCenter
- lineWidth: 2
- value: percentage
- size: 26
- secondaryColor: Appearance.m3colors.m3secondaryContainer
- primaryColor: Appearance.m3colors.m3onSecondaryContainer
+ RowLayout {
+ spacing: 4
+ id: resourceRowLayout
+ x: shown ? 0 : -resourceRowLayout.width
- MaterialSymbol {
- anchors.centerIn: parent
- text: iconName
- font.pointSize: Appearance.font.pointSize.normal
- color: Appearance.m3colors.m3onSecondaryContainer
+ CircularProgress {
+ Layout.alignment: Qt.AlignVCenter
+ lineWidth: 2
+ value: percentage
+ size: 26
+ secondaryColor: Appearance.m3colors.m3secondaryContainer
+ primaryColor: Appearance.m3colors.m3onSecondaryContainer
+
+ MaterialSymbol {
+ anchors.centerIn: parent
+ text: iconName
+ font.pointSize: Appearance.font.pointSize.normal
+ color: Appearance.m3colors.m3onSecondaryContainer
+ }
+
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignVCenter
+ color: Appearance.colors.colOnLayer1
+ text: `${Math.round(percentage * 100)}%`
+ }
+
+ Behavior on x {
+ NumberAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ }
}
}
- StyledText {
- Layout.alignment: Qt.AlignVCenter
- color: Appearance.colors.colOnLayer1
- text: `${Math.round(percentage * 100)}%`
+ Behavior on implicitWidth {
+ NumberAnimation {
+ duration: Appearance.animation.elementDecel.duration
+ easing.type: Appearance.animation.elementDecel.type
+ }
}
-
-}
+}
\ No newline at end of file
diff --git a/.config/quickshell/modules/bar/Resources.qml b/.config/quickshell/modules/bar/Resources.qml
index ea64c8ce6..4528f8b48 100644
--- a/.config/quickshell/modules/bar/Resources.qml
+++ b/.config/quickshell/modules/bar/Resources.qml
@@ -4,9 +4,10 @@ import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
+import Quickshell.Services.Mpris
Rectangle {
- implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
+ implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin
implicitHeight: 32
color: Appearance.colors.colLayer1
radius: Appearance.rounding.small
@@ -14,20 +15,28 @@ Rectangle {
RowLayout {
id: rowLayout
- spacing: 4
- anchors.centerIn: parent
+ spacing: 0
+ anchors.fill: parent
+ anchors.leftMargin: 4
+ anchors.rightMargin: 4
Resource {
iconName: "memory"
percentage: ResourceUsage.memoryUsedPercentage
}
+
Resource {
iconName: "swap_horiz"
percentage: ResourceUsage.swapUsedPercentage
+ shown: ConfigOptions.bar.resources.alwaysShowSwap || (MprisController.activePlayer == null)
+ Layout.leftMargin: shown ? 4 : 0
}
+
Resource {
iconName: "settings_slow_motion"
percentage: ResourceUsage.cpuUsage
+ shown: ConfigOptions.bar.resources.alwaysShowCpu || (MprisController.activePlayer == null)
+ Layout.leftMargin: shown ? 4 : 0
}
}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index d0b62f3a4..404656565 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -146,7 +146,7 @@ Singleton {
}
property QtObject menuDecel: QtObject {
property int duration: 350
- property int type: Easing.OutQuint
+ property int type: Easing.OutExpo
}
}
diff --git a/.config/quickshell/modules/common/ConfigOptions.qml b/.config/quickshell/modules/common/ConfigOptions.qml
index df7f5e154..d86fb96a8 100644
--- a/.config/quickshell/modules/common/ConfigOptions.qml
+++ b/.config/quickshell/modules/common/ConfigOptions.qml
@@ -6,6 +6,10 @@ Singleton {
property QtObject bar: QtObject {
property int workspacesShown: 10
property int batteryLowThreshold: 20
+ property QtObject resources: QtObject {
+ property bool alwaysShowSwap: true
+ property bool alwaysShowCpu: false
+ }
}
property QtObject resources: QtObject {
property int updateInterval: 3000
diff --git a/.config/quickshell/shell.qml b/.config/quickshell/shell.qml
index aeb4b2ba1..ceec43fd5 100644
--- a/.config/quickshell/shell.qml
+++ b/.config/quickshell/shell.qml
@@ -4,8 +4,11 @@ import QtQuick.Layouts
import Quickshell
import "./modules/bar"
+import QtQuick.Window
+
ShellRoot {
Bar {
}
+
}
From 06fc4baf4e90164a27dda2e5b0603ad6ab96e5a2 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 17:10:19 +0200
Subject: [PATCH 012/795] active window title + workspace fix
---
.../quickshell/modules/bar/ActiveWindow.qml | 39 +++++++++++++++++++
.config/quickshell/modules/bar/Bar.qml | 7 ++++
.../quickshell/modules/bar/ClockWidget.qml | 1 -
.config/quickshell/modules/bar/Workspaces.qml | 10 ++---
.../quickshell/modules/common/Appearance.qml | 2 +
.../modules/common/MprisController.qml | 4 +-
.../common/widgets/CircularProgress.qml | 8 ++++
7 files changed, 61 insertions(+), 10 deletions(-)
create mode 100644 .config/quickshell/modules/bar/ActiveWindow.qml
diff --git a/.config/quickshell/modules/bar/ActiveWindow.qml b/.config/quickshell/modules/bar/ActiveWindow.qml
new file mode 100644
index 000000000..d51381580
--- /dev/null
+++ b/.config/quickshell/modules/bar/ActiveWindow.qml
@@ -0,0 +1,39 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Layouts
+import Quickshell.Wayland
+import Quickshell.Hyprland
+
+Rectangle {
+ required property var bar
+ readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
+ readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
+
+ height: parent.height
+ width: colLayout.width
+ color: "transparent"
+ Layout.leftMargin: Appearance.rounding.screenRounding
+
+
+ ColumnLayout {
+ id: colLayout
+
+ anchors.centerIn: parent
+ spacing: -4
+
+ StyledText {
+ font.pointSize: Appearance.font.pointSize.smaller
+ color: Appearance.colors.colSubtext
+ text: activeWindow.activated ? activeWindow?.appId : "Desktop"
+ }
+
+ StyledText {
+ font.pointSize: Appearance.font.pointSize.small
+ color: Appearance.colors.colOnLayer0
+ text: activeWindow.activated ? activeWindow?.title : `Workspace ${monitor.activeWorkspace?.id}`
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index 0e7bcabd5..5289f42c8 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -6,6 +6,7 @@ import Quickshell
Scope {
id: bar
+
readonly property int barHeight: 40
readonly property int sideCenterModuleWidth: 360
@@ -24,6 +25,12 @@ Scope {
// Left section
RowLayout {
anchors.left: parent.left
+ implicitHeight: barHeight
+
+ ActiveWindow {
+ bar: barRoot
+ }
+
}
// Middle section
diff --git a/.config/quickshell/modules/bar/ClockWidget.qml b/.config/quickshell/modules/bar/ClockWidget.qml
index d001f1db7..4568bbdcd 100644
--- a/.config/quickshell/modules/bar/ClockWidget.qml
+++ b/.config/quickshell/modules/bar/ClockWidget.qml
@@ -16,7 +16,6 @@ Rectangle {
anchors.centerIn: parent
StyledText {
- font.family: Appearance.font.family.title
font.pointSize: Appearance.font.pointSize.large
color: Appearance.colors.colOnLayer1
text: DateTime.time
diff --git a/.config/quickshell/modules/bar/Workspaces.qml b/.config/quickshell/modules/bar/Workspaces.qml
index 26274d4a3..1fd13c42c 100644
--- a/.config/quickshell/modules/bar/Workspaces.qml
+++ b/.config/quickshell/modules/bar/Workspaces.qml
@@ -32,9 +32,6 @@ Rectangle {
workspaceOccupied = Array.from({ length: ConfigOptions.bar.workspacesShown }, (_, i) => {
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * ConfigOptions.bar.workspacesShown + i + 1);
})
- if(!activeWindow?.activated) {
- workspaceOccupied[(monitor.activeWorkspace?.id - 1) % ConfigOptions.bar.workspacesShown] = false;
- }
}
// Initialize workspaceOccupied when the component is created
@@ -48,7 +45,6 @@ Rectangle {
}
}
-
Layout.fillHeight: true
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: 40
@@ -92,8 +88,8 @@ Rectangle {
implicitWidth: workspaceButtonWidth
implicitHeight: workspaceButtonWidth
radius: Appearance.rounding.full
- property var radiusLeft: workspaceOccupied[index-1] ? 0 : Appearance.rounding.full
- property var radiusRight: workspaceOccupied[index+1] ? 0 : Appearance.rounding.full
+ property var radiusLeft: (workspaceOccupied[index-1] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index)) ? 0 : Appearance.rounding.full
+ property var radiusRight: (workspaceOccupied[index+1] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index+2)) ? 0 : Appearance.rounding.full
topLeftRadius: radiusLeft
bottomLeftRadius: radiusLeft
@@ -101,7 +97,7 @@ Rectangle {
bottomRightRadius: radiusRight
color: Appearance.colors.colLayer2
- opacity: workspaceOccupied[index] ? 1 : 0
+ opacity: (workspaceOccupied[index] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index+1)) ? 1 : 0
Behavior on opacity {
NumberAnimation {
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index 404656565..bfff14963 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -95,6 +95,7 @@ Singleton {
}
colors: QtObject {
+ property color colSubtext: m3colors.m3outline
property color colLayer0: m3colors.m3background
property color colOnLayer0: m3colors.m3onBackground
property color colLayer0Hover: mix(colLayer0, colOnLayer0, 0.85)
@@ -119,6 +120,7 @@ Singleton {
property int normal: 17
property int large: 25
property int full: 9999
+ property int screenRounding: large
}
font: QtObject {
diff --git a/.config/quickshell/modules/common/MprisController.qml b/.config/quickshell/modules/common/MprisController.qml
index 24977f749..590dcd86c 100644
--- a/.config/quickshell/modules/common/MprisController.qml
+++ b/.config/quickshell/modules/common/MprisController.qml
@@ -60,8 +60,8 @@ Singleton {
}
function onTrackArtUrlChanged() {
- console.log("arturl:", activePlayer.trackArtUrl)
- //root.updateTrack();
+ // console.log("arturl:", activePlayer.trackArtUrl)
+ // root.updateTrack();
if (root.activePlayer.uniqueId == root.activeTrack.uniqueId && root.activePlayer.trackArtUrl != root.activeTrack.artUrl) {
// cantata likes to send cover updates *BEFORE* updating the track info.
// as such, art url changes shouldn't be able to break the reverse animation
diff --git a/.config/quickshell/modules/common/widgets/CircularProgress.qml b/.config/quickshell/modules/common/widgets/CircularProgress.qml
index 62970f797..73ab50f4b 100644
--- a/.config/quickshell/modules/common/widgets/CircularProgress.qml
+++ b/.config/quickshell/modules/common/widgets/CircularProgress.qml
@@ -19,6 +19,12 @@ Item {
onValueChanged: {
canvas.degree = value * 360;
}
+ onPrimaryColorChanged: {
+ canvas.requestPaint();
+ }
+ onSecondaryColorChanged: {
+ canvas.requestPaint();
+ }
Canvas {
id: canvas
@@ -27,9 +33,11 @@ Item {
anchors.fill: parent
antialiasing: true
+
onDegreeChanged: {
requestPaint();
}
+
onPaint: {
var ctx = getContext("2d");
var x = root.width / 2;
From d77e4f14bf43f98f53b4195e998c836b63b2803d Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 20:43:18 +0200
Subject: [PATCH 013/795] bar brightness scroll
---
.../quickshell/modules/bar/ActiveWindow.qml | 9 ++-
.config/quickshell/modules/bar/Bar.qml | 11 ++++
.../quickshell/modules/common/Brightness.qml | 63 +++++++++++++++++++
3 files changed, 81 insertions(+), 2 deletions(-)
create mode 100644 .config/quickshell/modules/common/Brightness.qml
diff --git a/.config/quickshell/modules/bar/ActiveWindow.qml b/.config/quickshell/modules/bar/ActiveWindow.qml
index d51381580..3a23182ac 100644
--- a/.config/quickshell/modules/bar/ActiveWindow.qml
+++ b/.config/quickshell/modules/bar/ActiveWindow.qml
@@ -9,6 +9,7 @@ Rectangle {
required property var bar
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
+ property int preferredWidth: 400
height: parent.height
width: colLayout.width
@@ -25,13 +26,17 @@ Rectangle {
StyledText {
font.pointSize: Appearance.font.pointSize.smaller
color: Appearance.colors.colSubtext
- text: activeWindow.activated ? activeWindow?.appId : "Desktop"
+ Layout.preferredWidth: preferredWidth
+ elide: Text.ElideRight
+ text: activeWindow?.activated ? activeWindow?.appId : "Desktop"
}
StyledText {
font.pointSize: Appearance.font.pointSize.small
color: Appearance.colors.colOnLayer0
- text: activeWindow.activated ? activeWindow?.title : `Workspace ${monitor.activeWorkspace?.id}`
+ Layout.preferredWidth: preferredWidth
+ elide: Text.ElideRight
+ text: activeWindow?.activated ? activeWindow?.title : `Workspace ${monitor.activeWorkspace?.id}`
}
}
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index 5289f42c8..3cb2ce7c8 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -30,6 +30,17 @@ Scope {
ActiveWindow {
bar: barRoot
}
+ // Scroll to switch workspaces
+
+ WheelHandler {
+ onWheel: (event) => {
+ if (event.angleDelta.y < 0)
+ Brightness.value = -1;
+ else if (event.angleDelta.y > 0)
+ Brightness.value = 1;
+ }
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
+ }
}
diff --git a/.config/quickshell/modules/common/Brightness.qml b/.config/quickshell/modules/common/Brightness.qml
new file mode 100644
index 000000000..57ad389d3
--- /dev/null
+++ b/.config/quickshell/modules/common/Brightness.qml
@@ -0,0 +1,63 @@
+import Quickshell
+import Quickshell.Io
+pragma Singleton
+
+Singleton {
+ id: root
+
+ property string brightness
+ property int value: 0
+
+ function refresh() {
+ getBrightness.running = true;
+ }
+
+ onValueChanged: () => {
+ if (value > 0) {
+ increaseBrightness.running = true;
+ root.value = 0;
+ } else if (value < 0) {
+ decreaseBrightness.running = true;
+ root.value = 0;
+ }
+ getBrightness.running = true;
+ }
+
+ Process {
+ id: getBrightness
+
+ command: ["sh", "-c", "brightnessctl -m i | cut -d, -f4"]
+ running: true
+ onExited: {
+ running = false;
+ }
+
+ stdout: SplitParser {
+ onRead: (data) => {
+ root.brightness = data;
+ }
+ }
+
+ }
+
+ Process {
+ id: decreaseBrightness
+
+ command: ["brightnessctl", "set", "5%-"]
+ running: false
+ onExited: {
+ running = false;
+ }
+ }
+
+ Process {
+ id: increaseBrightness
+
+ command: ["brightnessctl", "set", "5%+"]
+ running: false
+ onExited: {
+ running = false;
+ }
+ }
+
+}
From dae28573919afa3c2693cf782777ad2c468b3ae3 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Fri, 11 Apr 2025 23:35:05 +0200
Subject: [PATCH 014/795] system tray
---
.../quickshell/modules/bar/ActiveWindow.qml | 3 +-
.config/quickshell/modules/bar/Bar.qml | 27 +++++++++-
.config/quickshell/modules/bar/Media.qml | 3 +-
.config/quickshell/modules/bar/Resource.qml | 3 +-
.config/quickshell/modules/bar/SysTray.qml | 39 +++++++++++++++
.../quickshell/modules/bar/SysTrayItem.qml | 49 +++++++++++++++++++
.config/quickshell/modules/bar/Workspaces.qml | 6 +--
.config/quickshell/modules/common/Audio.qml | 16 ++++++
.config/quickshell/shell.qml | 2 +
9 files changed, 137 insertions(+), 11 deletions(-)
create mode 100644 .config/quickshell/modules/bar/SysTray.qml
create mode 100644 .config/quickshell/modules/bar/SysTrayItem.qml
create mode 100644 .config/quickshell/modules/common/Audio.qml
diff --git a/.config/quickshell/modules/bar/ActiveWindow.qml b/.config/quickshell/modules/bar/ActiveWindow.qml
index 3a23182ac..e2ab07c91 100644
--- a/.config/quickshell/modules/bar/ActiveWindow.qml
+++ b/.config/quickshell/modules/bar/ActiveWindow.qml
@@ -5,7 +5,7 @@ import QtQuick.Layouts
import Quickshell.Wayland
import Quickshell.Hyprland
-Rectangle {
+Item {
required property var bar
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
@@ -13,7 +13,6 @@ Rectangle {
height: parent.height
width: colLayout.width
- color: "transparent"
Layout.leftMargin: Appearance.rounding.screenRounding
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index 3cb2ce7c8..a6d3b1ebb 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -1,4 +1,5 @@
import "../common"
+import "../common/widgets"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
@@ -30,8 +31,8 @@ Scope {
ActiveWindow {
bar: barRoot
}
- // Scroll to switch workspaces
+ // Scroll to change brightness
WheelHandler {
onWheel: (event) => {
if (event.angleDelta.y < 0)
@@ -100,6 +101,30 @@ Scope {
// Right section
RowLayout {
anchors.right: parent.right
+ implicitHeight: barHeight
+ spacing: 20
+
+ SysTray {
+ bar: barRoot
+ }
+
+ Item { // TODO make this wifi & bluetooth
+ Layout.leftMargin: Appearance.rounding.screenRounding
+ }
+
+ // Scroll to change volume
+ WheelHandler {
+ onWheel: (event) => {
+ const currentVolume = Audio.sink?.audio.volume;
+ const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
+ if (event.angleDelta.y < 0)
+ Audio.sink.audio.volume -= step;
+ else if (event.angleDelta.y > 0)
+ Audio.sink.audio.volume += step;
+ }
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
+ }
+
}
anchors {
diff --git a/.config/quickshell/modules/bar/Media.qml b/.config/quickshell/modules/bar/Media.qml
index e681140ad..268ea1042 100644
--- a/.config/quickshell/modules/bar/Media.qml
+++ b/.config/quickshell/modules/bar/Media.qml
@@ -6,14 +6,13 @@ import Quickshell
import Quickshell.Io
import Quickshell.Services.Mpris
-Rectangle {
+Item {
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property string cleanedTitle: activePlayer?.trackTitle.replace(/【[^】]*】/, "") || "No media"
Layout.fillHeight: true
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: 40
- color: "transparent"
// Background
Rectangle {
diff --git a/.config/quickshell/modules/bar/Resource.qml b/.config/quickshell/modules/bar/Resource.qml
index 3b7f83bfc..fd9a0b87a 100644
--- a/.config/quickshell/modules/bar/Resource.qml
+++ b/.config/quickshell/modules/bar/Resource.qml
@@ -5,14 +5,13 @@ import QtQuick.Layouts
import Quickshell
import Quickshell.Io
-Rectangle {
+Item {
required property string iconName
required property double percentage
property bool shown: true
clip: true
implicitWidth: resourceRowLayout.x < 0 ? 0 : childrenRect.width
implicitHeight: childrenRect.height
- color: "transparent"
RowLayout {
spacing: 4
diff --git a/.config/quickshell/modules/bar/SysTray.qml b/.config/quickshell/modules/bar/SysTray.qml
new file mode 100644
index 000000000..27d4e456e
--- /dev/null
+++ b/.config/quickshell/modules/bar/SysTray.qml
@@ -0,0 +1,39 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Layouts
+import Quickshell.Hyprland
+import Quickshell.Services.SystemTray
+import Quickshell.Wayland
+import Quickshell.Widgets
+
+Item {
+ id: root
+
+ required property var bar
+
+ height: parent.height
+ implicitWidth: rowLayout.implicitWidth
+ Layout.leftMargin: Appearance.rounding.screenRounding
+
+ RowLayout {
+ id: rowLayout
+
+ anchors.fill: parent
+ spacing: 15
+
+ Repeater {
+ model: SystemTray.items
+
+ SysTrayItem {
+ required property SystemTrayItem modelData
+
+ bar: root.bar
+ item: modelData
+ }
+
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/bar/SysTrayItem.qml b/.config/quickshell/modules/bar/SysTrayItem.qml
new file mode 100644
index 000000000..83eb267a5
--- /dev/null
+++ b/.config/quickshell/modules/bar/SysTrayItem.qml
@@ -0,0 +1,49 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Services.SystemTray
+import Quickshell.Widgets
+
+MouseArea {
+ id: root
+
+ required property var bar
+ required property SystemTrayItem item
+ property bool targetMenuOpen: false
+ property int trayItemWidth: 16
+
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ Layout.fillHeight: true
+ implicitWidth: trayItemWidth
+ onClicked: (event) => {
+ switch (event.button) {
+ case Qt.LeftButton:
+ item.activate();
+ break;
+ case Qt.RightButton:
+ item.hasMenu && menu.open();
+ break;
+ default:
+ console.log("Buttonevent unhandled");
+ }
+ }
+
+ QsMenuAnchor {
+ id: menu
+
+ menu: root.item.menu
+ anchor.window: bar
+ anchor.rect.x: root.x + bar.width
+ anchor.rect.y: root.y
+ anchor.rect.height: root.height * 3
+ anchor.edges: Edges.Left | Edges.Bottom
+ }
+
+ IconImage {
+ source: root.item.icon
+ anchors.centerIn: parent
+ width: parent.width
+ height: parent.height
+ }
+
+}
diff --git a/.config/quickshell/modules/bar/Workspaces.qml b/.config/quickshell/modules/bar/Workspaces.qml
index 1fd13c42c..1df21c8be 100644
--- a/.config/quickshell/modules/bar/Workspaces.qml
+++ b/.config/quickshell/modules/bar/Workspaces.qml
@@ -8,7 +8,7 @@ import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Io
-Rectangle {
+Item {
required property var bar
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
@@ -48,7 +48,6 @@ Rectangle {
Layout.fillHeight: true
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: 40
- color: "transparent"
// Background
Rectangle {
@@ -176,8 +175,7 @@ Rectangle {
}
- background: Rectangle {
- color: "transparent" // Transparent background
+ background: Item {
implicitWidth: workspaceButtonWidth
implicitHeight: workspaceButtonWidth
}
diff --git a/.config/quickshell/modules/common/Audio.qml b/.config/quickshell/modules/common/Audio.qml
new file mode 100644
index 000000000..292efbf43
--- /dev/null
+++ b/.config/quickshell/modules/common/Audio.qml
@@ -0,0 +1,16 @@
+import QtQuick
+import Quickshell
+import Quickshell.Services.Pipewire
+pragma Singleton
+
+Singleton {
+ id: root
+
+ property var sink: Pipewire.defaultAudioSink
+ property var source: Pipewire.defaultAudioSource
+
+ PwObjectTracker {
+ objects: [Pipewire.defaultAudioSink, Pipewire.defaultAudioSource]
+ }
+
+}
diff --git a/.config/quickshell/shell.qml b/.config/quickshell/shell.qml
index ceec43fd5..211e56d8d 100644
--- a/.config/quickshell/shell.qml
+++ b/.config/quickshell/shell.qml
@@ -1,3 +1,5 @@
+//@ pragma UseQApplication
+//@ pragma IconTheme OneUI
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
From eff8d1e4c389f33cd73998378ca721a458712bf9 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sat, 12 Apr 2025 15:40:40 +0200
Subject: [PATCH 015/795] no more pragma needed
---
.config/quickshell/shell.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/quickshell/shell.qml b/.config/quickshell/shell.qml
index 211e56d8d..9859b8db3 100644
--- a/.config/quickshell/shell.qml
+++ b/.config/quickshell/shell.qml
@@ -1,5 +1,5 @@
//@ pragma UseQApplication
-//@ pragma IconTheme OneUI
+
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
From 7b8582124deb8ba7fd1110ee7935c4c72f63df65 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 13 Apr 2025 02:27:58 +0200
Subject: [PATCH 016/795] fix stupid tooltip corner
---
.config/Kvantum/Colloid/Colloid.kvconfig | 2 +-
.config/Kvantum/Colloid/ColloidDark.kvconfig | 2 +-
.config/Kvantum/MaterialAdw/MaterialAdw.kvconfig | 2 +-
.config/quickshell/modules/bar/SysTrayItem.qml | 9 +++++----
4 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/.config/Kvantum/Colloid/Colloid.kvconfig b/.config/Kvantum/Colloid/Colloid.kvconfig
index 1294ba409..65470510c 100644
--- a/.config/Kvantum/Colloid/Colloid.kvconfig
+++ b/.config/Kvantum/Colloid/Colloid.kvconfig
@@ -10,7 +10,7 @@ group_toolbar_buttons=false
toolbar_item_spacing=0
toolbar_interior_spacing=2
spread_progressbar=true
-composite=false
+composite=true
menu_shadow_depth=6
spread_menuitems=false
tooltip_shadow_depth=7
diff --git a/.config/Kvantum/Colloid/ColloidDark.kvconfig b/.config/Kvantum/Colloid/ColloidDark.kvconfig
index 61493df5a..d2406c143 100644
--- a/.config/Kvantum/Colloid/ColloidDark.kvconfig
+++ b/.config/Kvantum/Colloid/ColloidDark.kvconfig
@@ -10,7 +10,7 @@ group_toolbar_buttons=false
toolbar_item_spacing=0
toolbar_interior_spacing=2
spread_progressbar=true
-composite=false
+composite=true
menu_shadow_depth=6
spread_menuitems=false
tooltip_shadow_depth=7
diff --git a/.config/Kvantum/MaterialAdw/MaterialAdw.kvconfig b/.config/Kvantum/MaterialAdw/MaterialAdw.kvconfig
index 85264e0d2..62faf0b55 100644
--- a/.config/Kvantum/MaterialAdw/MaterialAdw.kvconfig
+++ b/.config/Kvantum/MaterialAdw/MaterialAdw.kvconfig
@@ -10,7 +10,7 @@ group_toolbar_buttons=false
toolbar_item_spacing=0
toolbar_interior_spacing=2
spread_progressbar=true
-composite=false
+composite=true
menu_shadow_depth=6
spread_menuitems=false
tooltip_shadow_depth=7
diff --git a/.config/quickshell/modules/bar/SysTrayItem.qml b/.config/quickshell/modules/bar/SysTrayItem.qml
index 83eb267a5..d40ce778b 100644
--- a/.config/quickshell/modules/bar/SysTrayItem.qml
+++ b/.config/quickshell/modules/bar/SysTrayItem.qml
@@ -21,8 +21,9 @@ MouseArea {
item.activate();
break;
case Qt.RightButton:
- item.hasMenu && menu.open();
- break;
+ if (item.hasMenu) {
+ menu.open();
+ }
default:
console.log("Buttonevent unhandled");
}
@@ -35,8 +36,8 @@ MouseArea {
anchor.window: bar
anchor.rect.x: root.x + bar.width
anchor.rect.y: root.y
- anchor.rect.height: root.height * 3
- anchor.edges: Edges.Left | Edges.Bottom
+ anchor.rect.height: root.height
+ anchor.edges: Edges.Bottom
}
IconImage {
From 28bd79234d52704fbdcde02a0923bfcabb294f47 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 13 Apr 2025 16:37:30 +0200
Subject: [PATCH 017/795] rounding decorations
---
.config/hypr/hyprland/rules.conf | 6 +-
.config/quickshell/modules/bar/Bar.qml | 249 ++++++++++--------
.config/quickshell/modules/bar/Resources.qml | 4 +-
.../quickshell/modules/bar/SysTrayItem.qml | 6 +-
.../quickshell/modules/common/Appearance.qml | 9 +
.../modules/common/widgets/RoundCorner.qml | 64 +++++
.../modules/screenCorners/ScreenCorners.qml | 66 +++++
.../modules/sidebarRight/SidebarRight.qml | 46 ++++
.config/quickshell/shell.qml | 12 +-
9 files changed, 343 insertions(+), 119 deletions(-)
create mode 100644 .config/quickshell/modules/common/widgets/RoundCorner.qml
create mode 100644 .config/quickshell/modules/screenCorners/ScreenCorners.qml
create mode 100644 .config/quickshell/modules/sidebarRight/SidebarRight.qml
diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf
index d67554148..701d5ebd6 100644
--- a/.config/hypr/hyprland/rules.conf
+++ b/.config/hypr/hyprland/rules.conf
@@ -69,8 +69,6 @@ layerrule = noanim, anyrun
layerrule = noanim, indicator.*
layerrule = noanim, osk
layerrule = noanim, hyprpicker
-layerrule = blur, shell:*
-layerrule = ignorealpha 0.6, shell:*
layerrule = noanim, noanim
layerrule = blur, gtk-layer-shell
@@ -105,3 +103,7 @@ layerrule = blur, indicator.*
layerrule = ignorealpha 0.6, indicator.*
layerrule = blur, osk[0-9]*
layerrule = ignorealpha 0.6, osk[0-9]*
+
+# Quickshell
+layerrule = animation fade, quickshell:screenCorners
+
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index a6d3b1ebb..e84697e6e 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -8,8 +8,8 @@ import Quickshell
Scope {
id: bar
- readonly property int barHeight: 40
- readonly property int sideCenterModuleWidth: 360
+ readonly property int barHeight: Appearance.sizes.barHeight
+ readonly property int barCenterSideModuleWidth: Appearance.sizes.barCenterSideModuleWidth
Variants {
model: Quickshell.screens
@@ -20,112 +20,12 @@ Scope {
property var modelData
screen: modelData
- height: barHeight
- color: Appearance.colors.colLayer0
-
- // Left section
- RowLayout {
- anchors.left: parent.left
- implicitHeight: barHeight
-
- ActiveWindow {
- bar: barRoot
- }
-
- // Scroll to change brightness
- WheelHandler {
- onWheel: (event) => {
- if (event.angleDelta.y < 0)
- Brightness.value = -1;
- else if (event.angleDelta.y > 0)
- Brightness.value = 1;
- }
- acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
- }
-
- }
-
- // Middle section
- RowLayout {
- anchors.centerIn: parent
- spacing: 8
-
- RowLayout {
- Layout.preferredWidth: sideCenterModuleWidth
- spacing: 4
- Layout.fillHeight: true
- implicitWidth: 350
-
- Resources {
- }
-
- Media {
- Layout.fillWidth: true
- }
-
- }
-
- RowLayout {
- Layout.fillWidth: true
- Layout.fillHeight: true
- spacing: 4
-
- Workspaces {
- bar: barRoot
- }
-
- }
-
- RowLayout {
- Layout.preferredWidth: sideCenterModuleWidth
- Layout.fillHeight: true
- spacing: 4
-
- ClockWidget {
- Layout.alignment: Qt.AlignVCenter
- Layout.fillWidth: true
- }
-
- UtilButtons {
- Layout.alignment: Qt.AlignVCenter
- }
-
- Battery {
- Layout.alignment: Qt.AlignVCenter
- }
-
- }
-
- }
-
- // Right section
- RowLayout {
- anchors.right: parent.right
- implicitHeight: barHeight
- spacing: 20
-
- SysTray {
- bar: barRoot
- }
-
- Item { // TODO make this wifi & bluetooth
- Layout.leftMargin: Appearance.rounding.screenRounding
- }
-
- // Scroll to change volume
- WheelHandler {
- onWheel: (event) => {
- const currentVolume = Audio.sink?.audio.volume;
- const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
- if (event.angleDelta.y < 0)
- Audio.sink.audio.volume -= step;
- else if (event.angleDelta.y > 0)
- Audio.sink.audio.volume += step;
- }
- acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
- }
-
+ height: barHeight + Appearance.rounding.screenRounding
+ exclusiveZone: barHeight
+ mask: Region {
+ item: barContent
}
+ color: "transparent"
anchors {
top: true
@@ -133,6 +33,141 @@ Scope {
right: true
}
+ Rectangle {
+ id: barContent
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.top: parent.top
+ color: Appearance.colors.colLayer0
+ height: barHeight
+ // Left section
+ RowLayout {
+ anchors.left: parent.left
+ implicitHeight: barHeight
+
+ ActiveWindow {
+ bar: barRoot
+ }
+
+ // Scroll to change brightness
+ WheelHandler {
+ onWheel: (event) => {
+ if (event.angleDelta.y < 0)
+ Brightness.value = -1;
+ else if (event.angleDelta.y > 0)
+ Brightness.value = 1;
+ }
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
+ }
+
+ }
+
+ // Middle section
+ RowLayout {
+ anchors.centerIn: parent
+ spacing: 8
+
+ RowLayout {
+ Layout.preferredWidth: barCenterSideModuleWidth
+ spacing: 4
+ Layout.fillHeight: true
+ implicitWidth: 350
+
+ Resources {
+ }
+
+ Media {
+ Layout.fillWidth: true
+ }
+
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ spacing: 4
+
+ Workspaces {
+ bar: barRoot
+ }
+
+ }
+
+ RowLayout {
+ Layout.preferredWidth: barCenterSideModuleWidth
+ Layout.fillHeight: true
+ spacing: 4
+
+ ClockWidget {
+ Layout.alignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ }
+
+ UtilButtons {
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ Battery {
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ }
+
+ }
+
+ // Right section
+ RowLayout {
+ anchors.right: parent.right
+ implicitHeight: barHeight
+ spacing: 20
+
+ SysTray {
+ bar: barRoot
+ }
+
+ Item { // TODO make this wifi & bluetooth
+ Layout.leftMargin: Appearance.rounding.screenRounding
+ }
+
+ // Scroll to change volume
+ WheelHandler {
+ onWheel: (event) => {
+ const currentVolume = Audio.sink?.audio.volume;
+ const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
+ if (event.angleDelta.y < 0)
+ Audio.sink.audio.volume -= step;
+ else if (event.angleDelta.y > 0)
+ Audio.sink.audio.volume += step;
+ }
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
+ }
+
+ }
+ }
+
+ // Round decorators
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: Appearance.rounding.screenRounding
+
+ RoundCorner {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ size: Appearance.rounding.screenRounding
+ corner: cornerEnum.topLeft
+ color: Appearance.colors.colLayer0
+ }
+ RoundCorner {
+ anchors.top: parent.top
+ anchors.right: parent.right
+ size: Appearance.rounding.screenRounding
+ corner: cornerEnum.topRight
+ color: Appearance.colors.colLayer0
+ }
+ }
+
}
}
diff --git a/.config/quickshell/modules/bar/Resources.qml b/.config/quickshell/modules/bar/Resources.qml
index 4528f8b48..0a7f28f6e 100644
--- a/.config/quickshell/modules/bar/Resources.qml
+++ b/.config/quickshell/modules/bar/Resources.qml
@@ -28,14 +28,14 @@ Rectangle {
Resource {
iconName: "swap_horiz"
percentage: ResourceUsage.swapUsedPercentage
- shown: ConfigOptions.bar.resources.alwaysShowSwap || (MprisController.activePlayer == null)
+ shown: ConfigOptions.bar.resources.alwaysShowSwap || (MprisController.activePlayer?.trackTitle == null)
Layout.leftMargin: shown ? 4 : 0
}
Resource {
iconName: "settings_slow_motion"
percentage: ResourceUsage.cpuUsage
- shown: ConfigOptions.bar.resources.alwaysShowCpu || (MprisController.activePlayer == null)
+ shown: ConfigOptions.bar.resources.alwaysShowCpu || !(MprisController.activePlayer?.trackTitle?.length > 0)
Layout.leftMargin: shown ? 4 : 0
}
diff --git a/.config/quickshell/modules/bar/SysTrayItem.qml b/.config/quickshell/modules/bar/SysTrayItem.qml
index d40ce778b..c0c2e6bad 100644
--- a/.config/quickshell/modules/bar/SysTrayItem.qml
+++ b/.config/quickshell/modules/bar/SysTrayItem.qml
@@ -21,11 +21,9 @@ MouseArea {
item.activate();
break;
case Qt.RightButton:
- if (item.hasMenu) {
+ if (item.hasMenu)
menu.open();
- }
- default:
- console.log("Buttonevent unhandled");
+
}
}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index bfff14963..e65a54193 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -8,6 +8,7 @@ Singleton {
property QtObject colors
property QtObject rounding
property QtObject font
+ property QtObject sizes
function mix(color1, color2, percentage) {
var c1 = Qt.color(color1);
@@ -152,4 +153,12 @@ Singleton {
}
}
+ sizes: QtObject {
+ property int barHeight: 40
+ property int barCenterSideModuleWidth: 360
+ property int sidebarWidth: 450
+ property int hyprlandGapsOut: 5
+ property int elevationMargin: 7
+ }
+
}
diff --git a/.config/quickshell/modules/common/widgets/RoundCorner.qml b/.config/quickshell/modules/common/widgets/RoundCorner.qml
new file mode 100644
index 000000000..6a9020bc0
--- /dev/null
+++ b/.config/quickshell/modules/common/widgets/RoundCorner.qml
@@ -0,0 +1,64 @@
+import QtQuick 2.9
+
+Item {
+ id: root
+
+ property int size: 25
+ property color color: "#000000"
+
+ property QtObject cornerEnum: QtObject {
+ property int topLeft: 0
+ property int topRight: 1
+ property int bottomLeft: 2
+ property int bottomRight: 3
+ }
+
+ property int corner: cornerEnum.topLeft // Default to TopLeft
+
+ width: size
+ height: size
+
+ Canvas {
+ id: canvas
+
+ anchors.fill: parent
+ antialiasing: true
+
+ onPaint: {
+ var ctx = getContext("2d");
+ var r = root.size;
+
+ ctx.beginPath();
+ switch (root.corner) {
+ case cornerEnum.topLeft:
+ ctx.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
+ ctx.lineTo(0, 0);
+ break;
+ case cornerEnum.topRight:
+ ctx.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI);
+ ctx.lineTo(r, 0);
+ break;
+ case cornerEnum.bottomLeft:
+ ctx.arc(r, 0, r, Math.PI / 2, Math.PI);
+ ctx.lineTo(0, r);
+ break;
+ case cornerEnum.bottomRight:
+ ctx.arc(0, 0, r, 0, Math.PI / 2);
+ ctx.lineTo(r, r);
+ break;
+ }
+ ctx.closePath();
+ ctx.fillStyle = root.color;
+ ctx.fill();
+ }
+ }
+
+ Behavior on size {
+ NumberAnimation {
+ duration: root.animationDuration
+ easing.type: Easing.OutCubic
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/screenCorners/ScreenCorners.qml b/.config/quickshell/modules/screenCorners/ScreenCorners.qml
new file mode 100644
index 000000000..49b2560ef
--- /dev/null
+++ b/.config/quickshell/modules/screenCorners/ScreenCorners.qml
@@ -0,0 +1,66 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Wayland
+
+Scope {
+ id: screenCorners
+ readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
+
+ Variants {
+ model: Quickshell.screens
+
+ PanelWindow {
+ id: barRoot
+ visible: !activeWindow?.fullscreen
+
+ property var modelData
+
+ screen: modelData
+ exclusionMode: ExclusionMode.Ignore
+ mask: Region {
+ item: null
+ }
+ WlrLayershell.namespace: "quickshell:screenCorners"
+ color: "transparent"
+
+ anchors {
+ top: true
+ left: true
+ right: true
+ bottom: true
+ }
+
+ RoundCorner {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ size: Appearance.rounding.screenRounding
+ corner: cornerEnum.topLeft
+ }
+ RoundCorner {
+ anchors.top: parent.top
+ anchors.right: parent.right
+ size: Appearance.rounding.screenRounding
+ corner: cornerEnum.topRight
+ }
+ RoundCorner {
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ size: Appearance.rounding.screenRounding
+ corner: cornerEnum.bottomLeft
+ }
+ RoundCorner {
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ size: Appearance.rounding.screenRounding
+ corner: cornerEnum.bottomRight
+ }
+
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/modules/sidebarRight/SidebarRight.qml b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
new file mode 100644
index 000000000..fcb296431
--- /dev/null
+++ b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
@@ -0,0 +1,46 @@
+import "../common"
+import "../common/widgets"
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+
+Scope {
+ id: bar
+
+ readonly property int sidebarWidth: Appearance.sizes.sidebarWidth
+
+ Variants {
+ model: Quickshell.screens
+
+ PanelWindow {
+ id: barRoot
+
+ property var modelData
+
+ screen: modelData
+ exclusiveZone: 0
+ width: sidebarWidth
+ color: "transparent"
+
+ anchors {
+ top: true
+ right: true
+ bottom: true
+ }
+
+ // Background
+ Rectangle {
+ id: sidebarRightBackground
+ anchors.centerIn: parent
+ width: parent.width - Appearance.sizes.hyprlandGapsOut * 2
+ height: parent.height - Appearance.sizes.hyprlandGapsOut * 2
+ color: Appearance.colors.colLayer0
+ radius: Appearance.rounding.screenRounding - Appearance.sizes.elevationMargin + 1
+ }
+
+ }
+
+ }
+
+}
diff --git a/.config/quickshell/shell.qml b/.config/quickshell/shell.qml
index 9859b8db3..869923f3a 100644
--- a/.config/quickshell/shell.qml
+++ b/.config/quickshell/shell.qml
@@ -1,16 +1,20 @@
//@ pragma UseQApplication
+import "./modules/bar/"
+import "./modules/sidebarRight/"
+import "./modules/screenCorners/"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
-import Quickshell
-import "./modules/bar"
-
import QtQuick.Window
+import Quickshell
ShellRoot {
Bar {
}
-
+ // SidebarRight {
+ // }
+ ScreenCorners {
+ }
}
From 248ff831abd123dec419f676860d85ea523fd9a6 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 13 Apr 2025 16:42:55 +0200
Subject: [PATCH 018/795] make screen corner configurable
---
.config/quickshell/modules/common/ConfigOptions.qml | 5 +++++
.config/quickshell/modules/screenCorners/ScreenCorners.qml | 3 ++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/.config/quickshell/modules/common/ConfigOptions.qml b/.config/quickshell/modules/common/ConfigOptions.qml
index d86fb96a8..93fa413a9 100644
--- a/.config/quickshell/modules/common/ConfigOptions.qml
+++ b/.config/quickshell/modules/common/ConfigOptions.qml
@@ -3,6 +3,10 @@ import Quickshell
pragma Singleton
Singleton {
+ property QtObject appearance: QtObject {
+ property int fakeScreenRounding: 1 // 0: None | 1: Always | 2: When not fullscreen
+ }
+
property QtObject bar: QtObject {
property int workspacesShown: 10
property int batteryLowThreshold: 20
@@ -11,6 +15,7 @@ Singleton {
property bool alwaysShowCpu: false
}
}
+
property QtObject resources: QtObject {
property int updateInterval: 3000
}
diff --git a/.config/quickshell/modules/screenCorners/ScreenCorners.qml b/.config/quickshell/modules/screenCorners/ScreenCorners.qml
index 49b2560ef..95764848a 100644
--- a/.config/quickshell/modules/screenCorners/ScreenCorners.qml
+++ b/.config/quickshell/modules/screenCorners/ScreenCorners.qml
@@ -15,7 +15,7 @@ Scope {
PanelWindow {
id: barRoot
- visible: !activeWindow?.fullscreen
+ visible: (ConfigOptions.appearance.fakeScreenRounding === 1 || (ConfigOptions.appearance.fakeScreenRounding === 2 && !activeWindow?.fullscreen))
property var modelData
@@ -25,6 +25,7 @@ Scope {
item: null
}
WlrLayershell.namespace: "quickshell:screenCorners"
+ WlrLayershell.layer: WlrLayer.Overlay
color: "transparent"
anchors {
From a139c29a2be0cd2f425114a3e53bbf53e76d602c Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 13 Apr 2025 17:07:32 +0200
Subject: [PATCH 019/795] toggleable sidebar
---
.config/hypr/hyprland/keybinds.conf | 7 ++---
.../modules/sidebarRight/SidebarRight.qml | 26 ++++++++++++++++++-
.config/quickshell/shell.qml | 5 ++--
3 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf
index 5d3b89ece..bfa6578b6 100644
--- a/.config/hypr/hyprland/keybinds.conf
+++ b/.config/hypr/hyprland/keybinds.conf
@@ -59,6 +59,7 @@ bind = Super, Down, movefocus, d # [hidden]
bind = Super, BracketLeft, movefocus, l # [hidden]
bind = Super, BracketRight, movefocus, r # [hidden]
bindm = Super, mouse:272, movewindow
+bindm = Super, mouse:274, movewindow
bindm = Super, mouse:273, resizewindow
bind = Super, Q, killactive,
bind = Super+Shift+Alt, Q, exec, hyprctl kill # Pick and kill a window
@@ -163,9 +164,9 @@ bindir = Super, Super_L, exec, agsv1 -t 'overview' # Toggle overview/launcher
bind = Super, Tab, exec, agsv1 -t 'overview' # [hidden]
bind = Super, Slash, exec, for ((i=0; i<$(hyprctl monitors -j | jq length); i++)); do agsv1 -t "cheatsheet""$i"; done # Show cheatsheet
bind = Super, B, exec, agsv1 -t 'sideleft' # Toggle left sidebar
-bind = Super, A, exec, agsv1 -t 'sideleft' # [hidden]
-bind = Super, O, exec, agsv1 -t 'sideleft' # [hidden]
-bind = Super, N, exec, agsv1 -t 'sideright' # Toggle right sidebar
+bind = Super, A, exec, qs ipc call sidebarLeft toggle || agsv1 -t 'sideleft' # [hidden]
+bind = Super, O, exec, qs ipc call sidebarLeft toggle || agsv1 -t 'sideleft' # [hidden]
+bind = Super, N, exec, qs ipc call sidebarRight toggle || agsv1 -t 'sideright' # Toggle right sidebar
bind = Super, M, exec, agsv1 run-js 'openMusicControls.value = (!mpris.getPlayer() ? false : !openMusicControls.value);' # Toggle music controls
bind = Super, Comma, exec, agsv1 run-js 'openColorScheme.value = true; Utils.timeout(2000, () => openColorScheme.value = false);' # View color scheme and options
bind = Super, K, exec, for ((i=0; i<$(hyprctl monitors -j | jq length); i++)); do agsv1 -t "osk""$i"; done # Toggle on-screen keyboard
diff --git a/.config/quickshell/modules/sidebarRight/SidebarRight.qml b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
index fcb296431..8b6b6494e 100644
--- a/.config/quickshell/modules/sidebarRight/SidebarRight.qml
+++ b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
@@ -3,7 +3,9 @@ import "../common/widgets"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
+import Quickshell.Io
import Quickshell
+import Quickshell.Wayland
Scope {
id: bar
@@ -14,13 +16,15 @@ Scope {
model: Quickshell.screens
PanelWindow {
- id: barRoot
+ id: sidebarRoot
+ visible: false
property var modelData
screen: modelData
exclusiveZone: 0
width: sidebarWidth
+ WlrLayershell.namespace: "quickshell:sidebarRight"
color: "transparent"
anchors {
@@ -32,6 +36,7 @@ Scope {
// Background
Rectangle {
id: sidebarRightBackground
+
anchors.centerIn: parent
width: parent.width - Appearance.sizes.hyprlandGapsOut * 2
height: parent.height - Appearance.sizes.hyprlandGapsOut * 2
@@ -39,6 +44,25 @@ Scope {
radius: Appearance.rounding.screenRounding - Appearance.sizes.elevationMargin + 1
}
+ // Shadow
+ // DropShadow {
+ // anchors.fill: sideRightBackground
+ // horizontalOffset: 0
+ // verticalOffset: 2
+ // radius: 3
+ // samples: 17
+ // color: Appearance.m3colors.m3shadow
+ // source: sideRightBackground
+ // }
+
+ IpcHandler {
+ target: "sidebarRight"
+
+ function toggle(): void {
+ sidebarRoot.visible = !sidebarRoot.visible
+ }
+ }
+
}
}
diff --git a/.config/quickshell/shell.qml b/.config/quickshell/shell.qml
index 869923f3a..5f822082e 100644
--- a/.config/quickshell/shell.qml
+++ b/.config/quickshell/shell.qml
@@ -13,8 +13,9 @@ ShellRoot {
Bar {
}
- // SidebarRight {
- // }
+ SidebarRight {
+ }
+
ScreenCorners {
}
}
From 9f0deefec4a6e5cc28b63cd49d66e611ffca849d Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Mon, 14 Apr 2025 12:18:33 +0200
Subject: [PATCH 020/795] per-monitor handling of sidebar opening
---
.../quickshell/modules/common/Appearance.qml | 6 +++
.../quickshell/modules/common/DateTime.qml | 31 +++++++++++
.../modules/common/ResourceUsage.qml | 2 +-
.../quickshell/modules/common/SystemInfo.qml | 51 +++++++++++++++++++
.../modules/sidebarRight/SidebarRight.qml | 40 +++++++++------
5 files changed, 113 insertions(+), 17 deletions(-)
create mode 100644 .config/quickshell/modules/common/SystemInfo.qml
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index e65a54193..6190a3ac8 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -16,6 +16,12 @@ Singleton {
return Qt.rgba(percentage * c1.r + (1 - percentage) * c2.r, percentage * c1.g + (1 - percentage) * c2.g, percentage * c1.b + (1 - percentage) * c2.b, percentage * c1.a + (1 - percentage) * c2.a);
}
+ // Transparentize
+ function transparentize(color, percentage) {
+ var c = Qt.color(color);
+ return Qt.rgba(c.r, c.g, c.b, c.a * (1 - percentage));
+ }
+
m3colors: QtObject {
property bool darkmode: false
property bool transparent: false
diff --git a/.config/quickshell/modules/common/DateTime.qml b/.config/quickshell/modules/common/DateTime.qml
index ddeec093e..bbcedfb52 100644
--- a/.config/quickshell/modules/common/DateTime.qml
+++ b/.config/quickshell/modules/common/DateTime.qml
@@ -6,6 +6,7 @@ pragma Singleton
Singleton {
property string time: Qt.formatDateTime(clock.date, "hh:mm")
property string date: Qt.formatDateTime(clock.date, "dddd, dd/MM")
+ property string uptime: "0h, 0m"
SystemClock {
id: clock
@@ -13,4 +14,34 @@ Singleton {
precision: SystemClock.Minutes
}
+ Timer {
+ interval: 10
+ running: true
+ repeat: true
+ onTriggered: {
+ fileUptime.reload()
+ const textUptime = fileUptime.text()
+ const uptimeSeconds = Number(textUptime.split(" ")[0] ?? 0)
+
+ // Convert seconds to days, hours, and minutes
+ const days = Math.floor(uptimeSeconds / 86400)
+ const hours = Math.floor((uptimeSeconds % 86400) / 3600)
+ const minutes = Math.floor((uptimeSeconds % 3600) / 60)
+
+ // Build the formatted uptime string
+ let formatted = ""
+ if (days > 0) formatted += `${days}d`
+ if (hours > 0) formatted += `${formatted ? ", " : ""}${hours}h`
+ if (minutes > 0 || !formatted) formatted += `${formatted ? ", " : ""}${minutes}m`
+ uptime = formatted
+ interval = ConfigOptions.resources.updateInterval;
+ }
+ }
+
+ FileView {
+ id: fileUptime
+
+ path: "/proc/uptime"
+ }
+
}
diff --git a/.config/quickshell/modules/common/ResourceUsage.qml b/.config/quickshell/modules/common/ResourceUsage.qml
index 898abbb34..6326baceb 100644
--- a/.config/quickshell/modules/common/ResourceUsage.qml
+++ b/.config/quickshell/modules/common/ResourceUsage.qml
@@ -16,7 +16,7 @@ Singleton {
property var previousCpuStats
Timer {
- interval: 50
+ interval: 10
running: true
repeat: true
onTriggered: {
diff --git a/.config/quickshell/modules/common/SystemInfo.qml b/.config/quickshell/modules/common/SystemInfo.qml
new file mode 100644
index 000000000..3db1237c8
--- /dev/null
+++ b/.config/quickshell/modules/common/SystemInfo.qml
@@ -0,0 +1,51 @@
+import QtQuick
+import Quickshell
+import Quickshell.Io
+pragma Singleton
+
+Singleton {
+ property string distroName: "Unknown"
+ property string distroId: "unknown"
+ property string distroIcon: "linux-symbolic"
+
+ Timer {
+ interval: 1
+ running: true
+ repeat: false
+ onTriggered: {
+ fileOsRelease.reload()
+ const textOsRelease = fileOsRelease.text()
+
+ // Extract the friendly name (PRETTY_NAME field, fallback to NAME)
+ const prettyNameMatch = textOsRelease.match(/^PRETTY_NAME="(.+?)"/m)
+ const nameMatch = textOsRelease.match(/^NAME="(.+?)"/m)
+ distroName = prettyNameMatch ? prettyNameMatch[1] : (nameMatch ? nameMatch[1].replace(/Linux/i, "").trim() : "Unknown")
+
+ // Extract the ID (LOGO field, fallback to "unknown")
+ const logoMatch = textOsRelease.match(/^LOGO=(.+)$/m)
+ distroId = logoMatch ? logoMatch[1].replace(/"/g, "") : "unknown"
+
+ // Update the distroIcon property based on distroId
+ switch (distroId) {
+ case "arch": distroIcon = "arch-symbolic"; break;
+ case "endeavouros": distroIcon = "endeavouros-symbolic"; break;
+ case "cachyos": distroIcon = "cachyos-symbolic"; break;
+ case "nixos": distroIcon = "nixos-symbolic"; break;
+ case "fedora": distroIcon = "fedora-symbolic"; break;
+ case "linuxmint":
+ case "ubuntu":
+ case "zorin":
+ case "popos": distroIcon = "ubuntu-symbolic"; break;
+ case "debian":
+ case "raspbian":
+ case "kali": distroIcon = "debian-symbolic"; break;
+ default: distroIcon = "linux-symbolic"; break;
+ }
+ }
+ }
+
+ FileView {
+ id: fileOsRelease
+ path: "/etc/os-release"
+ }
+}
\ No newline at end of file
diff --git a/.config/quickshell/modules/sidebarRight/SidebarRight.qml b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
index 8b6b6494e..f6643c893 100644
--- a/.config/quickshell/modules/sidebarRight/SidebarRight.qml
+++ b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
@@ -6,6 +6,8 @@ import QtQuick.Layouts
import Quickshell.Io
import Quickshell
import Quickshell.Wayland
+import Quickshell.Hyprland
+import Qt5Compat.GraphicalEffects
Scope {
id: bar
@@ -13,6 +15,7 @@ Scope {
readonly property int sidebarWidth: Appearance.sizes.sidebarWidth
Variants {
+ id: sidebarVariants
model: Quickshell.screens
PanelWindow {
@@ -45,26 +48,31 @@ Scope {
}
// Shadow
- // DropShadow {
- // anchors.fill: sideRightBackground
- // horizontalOffset: 0
- // verticalOffset: 2
- // radius: 3
- // samples: 17
- // color: Appearance.m3colors.m3shadow
- // source: sideRightBackground
- // }
-
- IpcHandler {
- target: "sidebarRight"
-
- function toggle(): void {
- sidebarRoot.visible = !sidebarRoot.visible
- }
+ DropShadow {
+ anchors.fill: sidebarRightBackground
+ horizontalOffset: 0
+ verticalOffset: 2
+ radius: Appearance.sizes.elevationMargin
+ samples: Appearance.sizes.elevationMargin * 2 + 1 // Ideally should be 2 * radius + 1, see qt docs
+ color: Appearance.transparentize(Appearance.m3colors.m3shadow, 0.55)
+ source: sidebarRightBackground
}
}
}
+ IpcHandler {
+ target: "sidebarRight"
+
+ function toggle(): void {
+ for (let i = 0; i < sidebarVariants.instances.length; i++) {
+ let panelWindow = sidebarVariants.instances[i];
+ if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) {
+ panelWindow.visible = !panelWindow.visible;
+ }
+ }
+ }
+ }
+
}
From ab04d1e10d2e89f4566fb7577c6afcc4f889ca76 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Mon, 14 Apr 2025 12:19:02 +0200
Subject: [PATCH 021/795] add reload popup
---
.config/quickshell/ReloadPopup.qml | 142 +++++++++++++++++++++++++++++
.config/quickshell/shell.qml | 6 +-
2 files changed, 147 insertions(+), 1 deletion(-)
create mode 100644 .config/quickshell/ReloadPopup.qml
diff --git a/.config/quickshell/ReloadPopup.qml b/.config/quickshell/ReloadPopup.qml
new file mode 100644
index 000000000..ec0a91538
--- /dev/null
+++ b/.config/quickshell/ReloadPopup.qml
@@ -0,0 +1,142 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import Qt5Compat.GraphicalEffects
+
+Scope {
+ id: root
+ property bool failed;
+ property string errorString;
+
+ // Connect to the Quickshell global to listen for the reload signals.
+ Connections {
+ target: Quickshell
+
+ function onReloadCompleted() {
+ root.failed = false;
+ popupLoader.loading = true;
+ }
+
+ function onReloadFailed(error: string) {
+ // Close any existing popup before making a new one.
+ popupLoader.active = false;
+
+ root.failed = true;
+ root.errorString = error;
+ popupLoader.loading = true;
+ }
+ }
+
+ // Keep the popup in a loader because it isn't needed most of the timeand will take up
+ // memory that could be used for something else.
+ LazyLoader {
+ id: popupLoader
+
+ PanelWindow {
+ id: popup
+
+ anchors.top: true
+ margins.top: 0
+
+ width: rect.width + shadow.radius * 2
+ height: rect.height + shadow.radius * 2
+
+ // color blending is a bit odd as detailed in the type reference.
+ color: "transparent"
+
+ Rectangle {
+ id: rect
+ anchors.centerIn: parent
+ color: failed ? "#ffe99195" : "#ffD1E8D5"
+
+ implicitHeight: layout.implicitHeight + 30
+ implicitWidth: layout.implicitWidth + 30
+ radius: 12
+
+ // Fills the whole area of the rectangle, making any clicks go to it,
+ // which dismiss the popup.
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ onClicked: popupLoader.active = false
+
+ // makes the mouse area track mouse hovering, so the hide animation
+ // can be paused when hovering.
+ hoverEnabled: true
+ }
+
+ ColumnLayout {
+ id: layout
+ anchors {
+ top: parent.top
+ topMargin: 10
+ horizontalCenter: parent.horizontalCenter
+ }
+
+ Text {
+ renderType: Text.NativeRendering
+ font.family: "Rubik"
+ font.pointSize: 14
+ // color: Appearance.colors.colOnBackground
+ text: root.failed ? "Reload failed" : "Reload completed"
+ color: failed ? "#ff93000A" : "#ff0C1F13"
+ }
+
+ Text {
+ renderType: Text.NativeRendering
+ font.family: "JetBrains Mono NF"
+ font.pointSize: 11
+ text: root.errorString
+ color: failed ? "#ff93000A" : "#ff0C1F13"
+ // When visible is false, it also takes up no space.
+ visible: root.errorString != ""
+ }
+ }
+
+ // A progress bar on the bottom of the screen, showing how long until the
+ // popup is removed.
+ Rectangle {
+ id: bar
+ color: failed ? "#ff93000A" : "#ff0C1F13"
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.margins: 10
+ height: 5
+ radius: 9999
+
+ PropertyAnimation {
+ id: anim
+ target: bar
+ property: "width"
+ from: rect.width
+ to: 0
+ duration: failed ? 10000 : 800
+ onFinished: popupLoader.active = false
+
+ // Pause the animation when the mouse is hovering over the popup,
+ // so it stays onscreen while reading. This updates reactively
+ // when the mouse moves on and off the popup.
+ paused: mouseArea.containsMouse
+ }
+ }
+
+ // We could set `running: true` inside the animation, but the width of the
+ // rectangle might not be calculated yet, due to the layout.
+ // In the `Component.onCompleted` event handler, all of the component's
+ // properties and children have been initialized.
+ Component.onCompleted: anim.start()
+ }
+
+ DropShadow {
+ id: shadow
+ anchors.fill: rect
+ horizontalOffset: 0
+ verticalOffset: 2
+ radius: 6
+ samples: radius * 2 + 1 // Ideally should be 2 * radius + 1, see qt docs
+ color: "#44000000"
+ source: rect
+ }
+ }
+ }
+}
diff --git a/.config/quickshell/shell.qml b/.config/quickshell/shell.qml
index 5f822082e..d253053d6 100644
--- a/.config/quickshell/shell.qml
+++ b/.config/quickshell/shell.qml
@@ -1,8 +1,8 @@
//@ pragma UseQApplication
import "./modules/bar/"
-import "./modules/sidebarRight/"
import "./modules/screenCorners/"
+import "./modules/sidebarRight/"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
@@ -18,4 +18,8 @@ ShellRoot {
ScreenCorners {
}
+
+ ReloadPopup {
+ }
+
}
From ab81e79eece2f95941776c34b9322962f5e53187 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Mon, 14 Apr 2025 12:59:52 +0200
Subject: [PATCH 022/795] sidebar esc to close
---
.config/quickshell/ReloadPopup.qml | 3 +-
.../quickshell/modules/bar/ActiveWindow.qml | 2 +-
.config/quickshell/modules/bar/Bar.qml | 40 ++++++++++++++++---
.../quickshell/modules/common/Appearance.qml | 1 +
.../modules/sidebarRight/SidebarRight.qml | 15 +++++++
5 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/.config/quickshell/ReloadPopup.qml b/.config/quickshell/ReloadPopup.qml
index ec0a91538..c3f0aab95 100644
--- a/.config/quickshell/ReloadPopup.qml
+++ b/.config/quickshell/ReloadPopup.qml
@@ -67,6 +67,7 @@ Scope {
ColumnLayout {
id: layout
+ spacing: 10
anchors {
top: parent.top
topMargin: 10
@@ -78,7 +79,7 @@ Scope {
font.family: "Rubik"
font.pointSize: 14
// color: Appearance.colors.colOnBackground
- text: root.failed ? "Reload failed" : "Reload completed"
+ text: root.failed ? "Quickshell: Reload failed" : "Quickshell reloaded"
color: failed ? "#ff93000A" : "#ff0C1F13"
}
diff --git a/.config/quickshell/modules/bar/ActiveWindow.qml b/.config/quickshell/modules/bar/ActiveWindow.qml
index e2ab07c91..39b34fa15 100644
--- a/.config/quickshell/modules/bar/ActiveWindow.qml
+++ b/.config/quickshell/modules/bar/ActiveWindow.qml
@@ -9,7 +9,7 @@ Item {
required property var bar
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
- property int preferredWidth: 400
+ property int preferredWidth: Appearance.sizes.barPreferredSideSectionWidth
height: parent.height
width: colLayout.width
diff --git a/.config/quickshell/modules/bar/Bar.qml b/.config/quickshell/modules/bar/Bar.qml
index e84697e6e..b31ac371a 100644
--- a/.config/quickshell/modules/bar/Bar.qml
+++ b/.config/quickshell/modules/bar/Bar.qml
@@ -4,6 +4,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
+import Quickshell.Io
Scope {
id: bar
@@ -11,6 +12,15 @@ Scope {
readonly property int barHeight: Appearance.sizes.barHeight
readonly property int barCenterSideModuleWidth: Appearance.sizes.barCenterSideModuleWidth
+ Process {
+ id: toggleSidebarRight
+ command: ["qs", "ipc", "call", "sidebarRight", "toggle"]
+ }
+ Process {
+ id: toggleSidebarLeft
+ command: ["qs", "ipc", "call", "sidebarLeft", "toggle"]
+ }
+
Variants {
model: Quickshell.screens
@@ -42,6 +52,7 @@ Scope {
height: barHeight
// Left section
RowLayout {
+ id: leftSection
anchors.left: parent.left
implicitHeight: barHeight
@@ -64,6 +75,7 @@ Scope {
// Middle section
RowLayout {
+ id: middleSection
anchors.centerIn: parent
spacing: 8
@@ -117,18 +129,37 @@ Scope {
// Right section
RowLayout {
+ id: rightSection
anchors.right: parent.right
implicitHeight: barHeight
+ width: Appearance.sizes.barPreferredSideSectionWidth
spacing: 20
-
- SysTray {
- bar: barRoot
- }
+ layoutDirection: Qt.RightToLeft
Item { // TODO make this wifi & bluetooth
Layout.leftMargin: Appearance.rounding.screenRounding
+ Layout.fillWidth: false
}
+ SysTray {
+ bar: barRoot
+ Layout.fillWidth: false
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+
+ }
+ MouseArea {
+ anchors.fill: rightSection
+ acceptedButtons: Qt.LeftButton
+ onPressed: (event) => {
+ if (event.button === Qt.LeftButton) {
+ toggleSidebarRight.running = true
+ }
+ }
// Scroll to change volume
WheelHandler {
onWheel: (event) => {
@@ -141,7 +172,6 @@ Scope {
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
-
}
}
diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml
index 6190a3ac8..b290c2a95 100644
--- a/.config/quickshell/modules/common/Appearance.qml
+++ b/.config/quickshell/modules/common/Appearance.qml
@@ -162,6 +162,7 @@ Singleton {
sizes: QtObject {
property int barHeight: 40
property int barCenterSideModuleWidth: 360
+ property int barPreferredSideSectionWidth: 400
property int sidebarWidth: 450
property int hyprlandGapsOut: 5
property int elevationMargin: 7
diff --git a/.config/quickshell/modules/sidebarRight/SidebarRight.qml b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
index f6643c893..b26d59eed 100644
--- a/.config/quickshell/modules/sidebarRight/SidebarRight.qml
+++ b/.config/quickshell/modules/sidebarRight/SidebarRight.qml
@@ -21,6 +21,7 @@ Scope {
PanelWindow {
id: sidebarRoot
visible: false
+ focusable: true
property var modelData
@@ -36,6 +37,12 @@ Scope {
bottom: true
}
+ HyprlandFocusGrab {
+ active: sidebarRoot.visible
+ id: grab
+ windows: [ sidebarRoot ]
+ }
+
// Background
Rectangle {
id: sidebarRightBackground
@@ -45,6 +52,14 @@ Scope {
height: parent.height - Appearance.sizes.hyprlandGapsOut * 2
color: Appearance.colors.colLayer0
radius: Appearance.rounding.screenRounding - Appearance.sizes.elevationMargin + 1
+
+ focus: true
+ Keys.onPressed: {
+ if (event.key === Qt.Key_Escape) {
+ sidebarRoot.visible = false;
+ event.accepted = true; // Prevent further propagation of the event
+ }
+ }
}
// Shadow
From c27366900389886df50f79b40a645ca126adf11c Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Mon, 14 Apr 2025 23:35:40 +0200
Subject: [PATCH 023/795] sidebar progress
---
.config/quickshell/ReloadPopup.qml | 17 +-
.../assets/icons/ai-openai-symbolic.svg | 1 +
.../quickshell/assets/icons/arch-symbolic.svg | 113 +++++++
.../assets/icons/cachyos-symbolic.svg | 318 ++++++++++++++++++
.../assets/icons/cloudflare-dns-symbolic.svg | 10 +
.../assets/icons/crosshair-symbolic.svg | 65 ++++
.../assets/icons/debian-symbolic.svg | 91 +++++
.../assets/icons/deepseek-symbolic.svg | 47 +++
.../assets/icons/desktop-symbolic.svg | 4 +
.../assets/icons/endeavouros-symbolic.svg | 96 ++++++
.../assets/icons/fedora-symbolic.svg | 38 +++
.../assets/icons/flatpak-symbolic.svg | 52 +++
.../assets/icons/github-symbolic.svg | 40 +++
.../assets/icons/google-gemini-symbolic.svg | 56 +++
.../assets/icons/linux-symbolic.svg | 113 +++++++
.../assets/icons/microsoft-symbolic.svg | 54 +++
.../assets/icons/nixos-symbolic.svg | 77 +++++
.../assets/icons/ollama-symbolic.svg | 60 ++++
.../assets/icons/openai-symbolic.svg | 38 +++
.../assets/icons/openrouter-symbolic.svg | 39 +++
.../assets/icons/ubuntu-symbolic.svg | 85 +++++
.../assets/images/default_wallpaper.png | Bin 0 -> 67685 bytes
.../quickshell/modules/common/Appearance.qml | 4 +
.../modules/common/ConfigOptions.qml | 4 +
.../modules/common/widgets/CustomIcon.qml | 24 ++
.../sidebarRight/QuickToggleButton.qml | 33 ++
.../modules/sidebarRight/SidebarRight.qml | 93 ++++-
.../scripts/wayland-idle-inhibitor.py | 86 +++++
28 files changed, 1652 insertions(+), 6 deletions(-)
create mode 120000 .config/quickshell/assets/icons/ai-openai-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/arch-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/cachyos-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/cloudflare-dns-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/crosshair-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/debian-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/deepseek-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/desktop-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/endeavouros-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/fedora-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/flatpak-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/github-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/google-gemini-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/linux-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/microsoft-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/nixos-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/ollama-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/openai-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/openrouter-symbolic.svg
create mode 100644 .config/quickshell/assets/icons/ubuntu-symbolic.svg
create mode 100644 .config/quickshell/assets/images/default_wallpaper.png
create mode 100644 .config/quickshell/modules/common/widgets/CustomIcon.qml
create mode 100644 .config/quickshell/modules/sidebarRight/QuickToggleButton.qml
create mode 100755 .config/quickshell/scripts/wayland-idle-inhibitor.py
diff --git a/.config/quickshell/ReloadPopup.qml b/.config/quickshell/ReloadPopup.qml
index c3f0aab95..eb19cbd91 100644
--- a/.config/quickshell/ReloadPopup.qml
+++ b/.config/quickshell/ReloadPopup.qml
@@ -97,6 +97,7 @@ Scope {
// A progress bar on the bottom of the screen, showing how long until the
// popup is removed.
Rectangle {
+ z: 2
id: bar
color: failed ? "#ff93000A" : "#ff0C1F13"
anchors.bottom: parent.bottom
@@ -109,9 +110,9 @@ Scope {
id: anim
target: bar
property: "width"
- from: rect.width
+ from: rect.width - bar.anchors.margins * 2
to: 0
- duration: failed ? 10000 : 800
+ duration: failed ? 10000 : 1000
onFinished: popupLoader.active = false
// Pause the animation when the mouse is hovering over the popup,
@@ -120,6 +121,18 @@ Scope {
paused: mouseArea.containsMouse
}
}
+ // Its bg
+ Rectangle {
+ z: 1
+ id: bar_bg
+ color: failed ? "#30af1b25" : "#4027643e"
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.margins: 10
+ height: 5
+ radius: 9999
+ width: rect.width - bar.anchors.margins * 2
+ }
// We could set `running: true` inside the animation, but the width of the
// rectangle might not be calculated yet, due to the layout.
diff --git a/.config/quickshell/assets/icons/ai-openai-symbolic.svg b/.config/quickshell/assets/icons/ai-openai-symbolic.svg
new file mode 120000
index 000000000..c9ee0b32f
--- /dev/null
+++ b/.config/quickshell/assets/icons/ai-openai-symbolic.svg
@@ -0,0 +1 @@
+openai-symbolic.svg
\ No newline at end of file
diff --git a/.config/quickshell/assets/icons/arch-symbolic.svg b/.config/quickshell/assets/icons/arch-symbolic.svg
new file mode 100644
index 000000000..7de9094e0
--- /dev/null
+++ b/.config/quickshell/assets/icons/arch-symbolic.svg
@@ -0,0 +1,113 @@
+
+
+
+
diff --git a/.config/quickshell/assets/icons/cachyos-symbolic.svg b/.config/quickshell/assets/icons/cachyos-symbolic.svg
new file mode 100644
index 000000000..4a9db19ab
--- /dev/null
+++ b/.config/quickshell/assets/icons/cachyos-symbolic.svg
@@ -0,0 +1,318 @@
+
+
diff --git a/.config/quickshell/assets/icons/cloudflare-dns-symbolic.svg b/.config/quickshell/assets/icons/cloudflare-dns-symbolic.svg
new file mode 100644
index 000000000..bd48d3c93
--- /dev/null
+++ b/.config/quickshell/assets/icons/cloudflare-dns-symbolic.svg
@@ -0,0 +1,10 @@
+
diff --git a/.config/quickshell/assets/icons/crosshair-symbolic.svg b/.config/quickshell/assets/icons/crosshair-symbolic.svg
new file mode 100644
index 000000000..22967493d
--- /dev/null
+++ b/.config/quickshell/assets/icons/crosshair-symbolic.svg
@@ -0,0 +1,65 @@
+
+
+
+
diff --git a/.config/quickshell/assets/icons/debian-symbolic.svg b/.config/quickshell/assets/icons/debian-symbolic.svg
new file mode 100644
index 000000000..252f85334
--- /dev/null
+++ b/.config/quickshell/assets/icons/debian-symbolic.svg
@@ -0,0 +1,91 @@
+
+
+
+
diff --git a/.config/quickshell/assets/icons/deepseek-symbolic.svg b/.config/quickshell/assets/icons/deepseek-symbolic.svg
new file mode 100644
index 000000000..029e12663
--- /dev/null
+++ b/.config/quickshell/assets/icons/deepseek-symbolic.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/.config/quickshell/assets/icons/desktop-symbolic.svg b/.config/quickshell/assets/icons/desktop-symbolic.svg
new file mode 100644
index 000000000..04f7a3b5e
--- /dev/null
+++ b/.config/quickshell/assets/icons/desktop-symbolic.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/.config/quickshell/assets/icons/endeavouros-symbolic.svg b/.config/quickshell/assets/icons/endeavouros-symbolic.svg
new file mode 100644
index 000000000..3be4cc406
--- /dev/null
+++ b/.config/quickshell/assets/icons/endeavouros-symbolic.svg
@@ -0,0 +1,96 @@
+
+
diff --git a/.config/quickshell/assets/icons/fedora-symbolic.svg b/.config/quickshell/assets/icons/fedora-symbolic.svg
new file mode 100644
index 000000000..1a4e8c873
--- /dev/null
+++ b/.config/quickshell/assets/icons/fedora-symbolic.svg
@@ -0,0 +1,38 @@
+
+
diff --git a/.config/quickshell/assets/icons/flatpak-symbolic.svg b/.config/quickshell/assets/icons/flatpak-symbolic.svg
new file mode 100644
index 000000000..0c2bf6280
--- /dev/null
+++ b/.config/quickshell/assets/icons/flatpak-symbolic.svg
@@ -0,0 +1,52 @@
+
+
diff --git a/.config/quickshell/assets/icons/github-symbolic.svg b/.config/quickshell/assets/icons/github-symbolic.svg
new file mode 100644
index 000000000..c1c9f19c4
--- /dev/null
+++ b/.config/quickshell/assets/icons/github-symbolic.svg
@@ -0,0 +1,40 @@
+
+
diff --git a/.config/quickshell/assets/icons/google-gemini-symbolic.svg b/.config/quickshell/assets/icons/google-gemini-symbolic.svg
new file mode 100644
index 000000000..9de741be6
--- /dev/null
+++ b/.config/quickshell/assets/icons/google-gemini-symbolic.svg
@@ -0,0 +1,56 @@
+
+
+
+
diff --git a/.config/quickshell/assets/icons/linux-symbolic.svg b/.config/quickshell/assets/icons/linux-symbolic.svg
new file mode 100644
index 000000000..63f9c7e58
--- /dev/null
+++ b/.config/quickshell/assets/icons/linux-symbolic.svg
@@ -0,0 +1,113 @@
+
+
+
+
diff --git a/.config/quickshell/assets/icons/microsoft-symbolic.svg b/.config/quickshell/assets/icons/microsoft-symbolic.svg
new file mode 100644
index 000000000..b90cfc637
--- /dev/null
+++ b/.config/quickshell/assets/icons/microsoft-symbolic.svg
@@ -0,0 +1,54 @@
+
+
diff --git a/.config/quickshell/assets/icons/nixos-symbolic.svg b/.config/quickshell/assets/icons/nixos-symbolic.svg
new file mode 100644
index 000000000..b697b0d1a
--- /dev/null
+++ b/.config/quickshell/assets/icons/nixos-symbolic.svg
@@ -0,0 +1,77 @@
+
+
diff --git a/.config/quickshell/assets/icons/ollama-symbolic.svg b/.config/quickshell/assets/icons/ollama-symbolic.svg
new file mode 100644
index 000000000..014548151
--- /dev/null
+++ b/.config/quickshell/assets/icons/ollama-symbolic.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/.config/quickshell/assets/icons/openai-symbolic.svg b/.config/quickshell/assets/icons/openai-symbolic.svg
new file mode 100644
index 000000000..8ffc912ae
--- /dev/null
+++ b/.config/quickshell/assets/icons/openai-symbolic.svg
@@ -0,0 +1,38 @@
+
+
diff --git a/.config/quickshell/assets/icons/openrouter-symbolic.svg b/.config/quickshell/assets/icons/openrouter-symbolic.svg
new file mode 100644
index 000000000..32aaaf50b
--- /dev/null
+++ b/.config/quickshell/assets/icons/openrouter-symbolic.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/.config/quickshell/assets/icons/ubuntu-symbolic.svg b/.config/quickshell/assets/icons/ubuntu-symbolic.svg
new file mode 100644
index 000000000..07746c9f6
--- /dev/null
+++ b/.config/quickshell/assets/icons/ubuntu-symbolic.svg
@@ -0,0 +1,85 @@
+
+
+
+
diff --git a/.config/quickshell/assets/images/default_wallpaper.png b/.config/quickshell/assets/images/default_wallpaper.png
new file mode 100644
index 0000000000000000000000000000000000000000..77d890c21b201652214d41195a15bb586beac1be
GIT binary patch
literal 67685
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