From 532497f6bd1c668dab241cb75cb78180111ecf5a Mon Sep 17 00:00:00 2001 From: cupcat121 <75441895+cupcat121@users.noreply.github.com> Date: Sat, 6 Sep 2025 11:40:24 +0800 Subject: [PATCH 01/38] fix out of index error in OverviewWindow monitorData --- .config/quickshell/ii/modules/overview/OverviewWidget.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/overview/OverviewWidget.qml b/.config/quickshell/ii/modules/overview/OverviewWidget.qml index 2510a5642..367565d30 100644 --- a/.config/quickshell/ii/modules/overview/OverviewWidget.qml +++ b/.config/quickshell/ii/modules/overview/OverviewWidget.qml @@ -153,15 +153,17 @@ Item { }) } } + // TODO: Fix various issues in multiple monitors + // 1. Indicator for workspace ID is wrong when workspaces in overview are included from multiple monitors delegate: OverviewWindow { id: window required property var modelData property int monitorId: windowData?.monitor - property var monitor: HyprlandData.monitors[monitorId] + property var monitor: HyprlandData.monitors.find(m => m.id == Hyprland.focusedMonitor?.id) property var address: `0x${modelData.HyprlandToplevel.address}` windowData: windowByAddress[address] toplevel: modelData - monitorData: HyprlandData.monitors[monitorId] + monitorData: root.monitorData scale: root.scale availableWorkspaceWidth: root.workspaceImplicitWidth availableWorkspaceHeight: root.workspaceImplicitHeight From cd851afc8d1bf691404aa1bfa064cdb3813e8094 Mon Sep 17 00:00:00 2001 From: cupcat121 <75441895+cupcat121@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:08:29 +0800 Subject: [PATCH 02/38] remove TODO --- .config/quickshell/ii/modules/overview/OverviewWidget.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.config/quickshell/ii/modules/overview/OverviewWidget.qml b/.config/quickshell/ii/modules/overview/OverviewWidget.qml index 367565d30..dc64d3f58 100644 --- a/.config/quickshell/ii/modules/overview/OverviewWidget.qml +++ b/.config/quickshell/ii/modules/overview/OverviewWidget.qml @@ -153,8 +153,6 @@ Item { }) } } - // TODO: Fix various issues in multiple monitors - // 1. Indicator for workspace ID is wrong when workspaces in overview are included from multiple monitors delegate: OverviewWindow { id: window required property var modelData From f1ba087bff12be659ef327f7d6b8ec5fa5615db8 Mon Sep 17 00:00:00 2001 From: cupcat121 <75441895+cupcat121@users.noreply.github.com> Date: Thu, 11 Sep 2025 00:29:44 +0800 Subject: [PATCH 03/38] fix wrong monitor data being passed to OverviewWindow --- .config/quickshell/ii/modules/overview/OverviewWidget.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.config/quickshell/ii/modules/overview/OverviewWidget.qml b/.config/quickshell/ii/modules/overview/OverviewWidget.qml index dc64d3f58..5d965585a 100644 --- a/.config/quickshell/ii/modules/overview/OverviewWidget.qml +++ b/.config/quickshell/ii/modules/overview/OverviewWidget.qml @@ -155,13 +155,13 @@ Item { } delegate: OverviewWindow { id: window + windowData: windowByAddress[address] required property var modelData property int monitorId: windowData?.monitor - property var monitor: HyprlandData.monitors.find(m => m.id == Hyprland.focusedMonitor?.id) + property var monitor: HyprlandData.monitors.find(m => m.id == monitorId) property var address: `0x${modelData.HyprlandToplevel.address}` - windowData: windowByAddress[address] toplevel: modelData - monitorData: root.monitorData + monitorData: this.monitor scale: root.scale availableWorkspaceWidth: root.workspaceImplicitWidth availableWorkspaceHeight: root.workspaceImplicitHeight From a238c33fd06358af414c0f7a35a4d682242f79c1 Mon Sep 17 00:00:00 2001 From: dodaars Date: Sun, 21 Sep 2025 23:54:12 +0200 Subject: [PATCH 04/38] A simple function to slice keyboard variants to avoid overflow of text when using vertical bars I added a function that slices keyboard variants to be at most 4 characters long to avoid text overflow, especially when you set the bar to be vertical. --- .../quickshell/ii/modules/bar/HyprlandXkbIndicator.qml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml b/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml index 3e85b829b..ed00cd532 100644 --- a/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml +++ b/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml @@ -6,10 +6,16 @@ import qs.modules.common.widgets Loader { id: root property bool vertical: false - active: HyprlandXkb.layoutCodes.length > 1 visible: active + function abbreviateLayoutCode(fullCode) { + return fullCode.split(':').map(layout => { + const baseLayout = layout.split('-')[0]; + return baseLayout.length > 4 ? baseLayout.slice(0, 4) : baseLayout; + }).join('\n'); + } + sourceComponent: Item { implicitWidth: root.vertical ? null : layoutCodeText.implicitWidth implicitHeight: root.vertical ? layoutCodeText.implicitHeight : null @@ -18,7 +24,7 @@ Loader { id: layoutCodeText anchors.centerIn: parent horizontalAlignment: Text.AlignHCenter - text: HyprlandXkb.currentLayoutCode.split(":").join("\n") + text: abbreviateLayoutCode(HyprlandXkb.currentLayoutCode) font.pixelSize: text.includes("\n") ? Appearance.font.pixelSize.smallie : Appearance.font.pixelSize.small color: rightSidebarButton.colText animateChange: true From 44cbd025f4aadf5e7f56c1aa426952be4de927e3 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 08:25:48 +0200 Subject: [PATCH 05/38] correct indentation, remove unnecessary check --- .../quickshell/ii/modules/bar/HyprlandXkbIndicator.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml b/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml index ed00cd532..c4dc11083 100644 --- a/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml +++ b/.config/quickshell/ii/modules/bar/HyprlandXkbIndicator.qml @@ -10,11 +10,11 @@ Loader { visible: active function abbreviateLayoutCode(fullCode) { - return fullCode.split(':').map(layout => { - const baseLayout = layout.split('-')[0]; - return baseLayout.length > 4 ? baseLayout.slice(0, 4) : baseLayout; - }).join('\n'); - } + return fullCode.split(':').map(layout => { + const baseLayout = layout.split('-')[0]; + return baseLayout.slice(0, 4); + }).join('\n'); + } sourceComponent: Item { implicitWidth: root.vertical ? null : layoutCodeText.implicitWidth From cf4505635b5560f4e36824836803c4a71ede4411 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 08:39:59 +0200 Subject: [PATCH 06/38] toolbar: add make radius configurable --- .config/quickshell/ii/modules/common/widgets/Toolbar.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/common/widgets/Toolbar.qml b/.config/quickshell/ii/modules/common/widgets/Toolbar.qml index aa07f8230..7c7e5f922 100644 --- a/.config/quickshell/ii/modules/common/widgets/Toolbar.qml +++ b/.config/quickshell/ii/modules/common/widgets/Toolbar.qml @@ -16,6 +16,7 @@ Item { default property alias data: toolbarLayout.data implicitWidth: background.implicitWidth implicitHeight: background.implicitHeight + property alias radius: background.radius StyledRectangularShadow { target: background @@ -23,11 +24,11 @@ Item { Rectangle { id: background - anchors.centerIn: parent + anchors.fill: parent color: Appearance.m3colors.m3surfaceContainer // Needs to be opaque implicitHeight: Math.max(toolbarLayout.implicitHeight + root.padding * 2, 56) implicitWidth: toolbarLayout.implicitWidth + root.padding * 2 - radius: Appearance.rounding.full + radius: height / 2 RowLayout { id: toolbarLayout From f430b22884f2bb1beae83d65ca3fa72da7b29dde Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:39:56 +0200 Subject: [PATCH 07/38] fix shadow radius --- .../ii/modules/common/widgets/StyledRectangularShadow.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/common/widgets/StyledRectangularShadow.qml b/.config/quickshell/ii/modules/common/widgets/StyledRectangularShadow.qml index a0c9f7ba3..a3c842c4b 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledRectangularShadow.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledRectangularShadow.qml @@ -5,7 +5,7 @@ import qs.modules.common RectangularShadow { required property var target anchors.fill: target - radius: 20 + radius: target.radius blur: 0.9 * Appearance.sizes.elevationMargin offset: Qt.vector2d(0.0, 1.0) spread: 1 From 28c37c08d2bc24dac474dd37def2a668dd2dbb7d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:45:16 +0200 Subject: [PATCH 08/38] make media control seekable (closes #1615) --- .../widgets/LightDarkPreferenceButton.qml | 4 +- .../common/widgets/StyledProgressBar.qml | 95 +++++++++---------- .../modules/common/widgets/StyledSlider.qml | 65 ++++++++++--- .../ii/modules/common/widgets/WavyLine.qml | 34 +++++++ .../modules/mediaControls/PlayerControl.qml | 40 ++++++-- .../volumeMixer/VolumeMixerEntry.qml | 2 +- 6 files changed, 166 insertions(+), 74 deletions(-) create mode 100644 .config/quickshell/ii/modules/common/widgets/WavyLine.qml diff --git a/.config/quickshell/ii/modules/common/widgets/LightDarkPreferenceButton.qml b/.config/quickshell/ii/modules/common/widgets/LightDarkPreferenceButton.qml index 5ad1316b9..efef4c1af 100644 --- a/.config/quickshell/ii/modules/common/widgets/LightDarkPreferenceButton.qml +++ b/.config/quickshell/ii/modules/common/widgets/LightDarkPreferenceButton.qml @@ -72,8 +72,8 @@ RippleButton { Layout.bottomMargin: 5 Layout.fillWidth: true value: 0.7 - sperm: true - animateSperm: lightDarkButtonRoot.toggled + wavy: true + animateWave: lightDarkButtonRoot.toggled highlightColor: lightDarkButtonRoot.toggled ? Appearance.m3colors.m3primary : lightDarkButtonRoot.previewFg trackColor: ColorUtils.mix(lightDarkButtonRoot.previewBg, lightDarkButtonRoot.previewFg, 0.5) } diff --git a/.config/quickshell/ii/modules/common/widgets/StyledProgressBar.qml b/.config/quickshell/ii/modules/common/widgets/StyledProgressBar.qml index 8197b29f9..62b8dcf74 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledProgressBar.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledProgressBar.qml @@ -1,12 +1,9 @@ -import qs.services +pragma ComponentBehavior: Bound import qs.modules.common import qs.modules.common.widgets import QtQuick import QtQuick.Controls -import QtQuick.Layouts -import Quickshell -import Quickshell.Widgets -import Qt5Compat.GraphicalEffects + /** * Material 3 progress bar. See https://m3.material.io/components/progress-indicators/overview @@ -18,13 +15,13 @@ ProgressBar { property real valueBarGap: 4 property color highlightColor: Appearance?.colors.colPrimary ?? "#685496" property color trackColor: Appearance?.m3colors.m3secondaryContainer ?? "#F1D3F9" - property bool sperm: false // If true, the progress bar will have a wavy fill effect - property bool animateSperm: true - property real spermAmplitudeMultiplier: sperm ? 0.5 : 0 - property real spermFrequency: 6 - property real spermFps: 60 + property bool wavy: false // If true, the progress bar will have a wavy fill effect + property bool animateWave: true + property real waveAmplitudeMultiplier: wavy ? 0.5 : 0 + property real waveFrequency: 6 + property real waveFps: 60 - Behavior on spermAmplitudeMultiplier { + Behavior on waveAmplitudeMultiplier { animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this) } @@ -38,64 +35,62 @@ ProgressBar { } contentItem: Item { + id: contentItem anchors.fill: parent - Canvas { - id: wavyFill + Loader { anchors { left: parent.left - right: parent.right verticalCenter: parent.verticalCenter } - height: parent.height * 6 - onPaint: { - var ctx = getContext("2d"); - ctx.clearRect(0, 0, width, height); - - var progress = root.visualPosition; - var fillWidth = progress * width; - var amplitude = parent.height * root.spermAmplitudeMultiplier; - var frequency = root.spermFrequency; - var phase = Date.now() / 400.0; - var centerY = height / 2; - - ctx.strokeStyle = root.highlightColor; - ctx.lineWidth = parent.height; - ctx.lineCap = "round"; - ctx.beginPath(); - for (var x = ctx.lineWidth / 2; x <= fillWidth; x += 1) { - var waveY = centerY + amplitude * Math.sin(frequency * 2 * Math.PI * x / width + phase); - if (x === 0) - ctx.moveTo(x, waveY); - else - ctx.lineTo(x, waveY); + active: root.wavy + sourceComponent: WavyLine { + id: wavyFill + frequency: root.waveFrequency + color: root.highlightColor + amplitudeMultiplier: root.wavy ? 0.5 : 0 + height: contentItem.height * 6 + width: contentItem.width * root.visualPosition + lineWidth: contentItem.height + fullLength: root.width + Connections { + target: root + function onValueChanged() { wavyFill.requestPaint(); } + function onHighlightColorChanged() { wavyFill.requestPaint(); } + } + FrameAnimation { + running: root.animateWave + onTriggered: { + wavyFill.requestPaint() + } } - ctx.stroke(); - } - Connections { - target: root - function onValueChanged() { wavyFill.requestPaint(); } - function onHighlightColorChanged() { wavyFill.requestPaint(); } - } - Timer { - interval: 1000 / root.spermFps - running: root.animateSperm - repeat: root.sperm - onTriggered: wavyFill.requestPaint() } } + + Loader { + active: !root.wavy + sourceComponent: Rectangle { + anchors.left: parent.left + width: contentItem.width * root.visualPosition + height: contentItem.height + radius: height / 2 + color: root.highlightColor + } + } + Rectangle { // Right remaining part fill anchors.right: parent.right width: (1 - root.visualPosition) * parent.width - valueBarGap height: parent.height - radius: Appearance?.rounding.full ?? 9999 + radius: height / 2 color: root.trackColor } + Rectangle { // Stop point anchors.right: parent.right width: valueBarGap height: valueBarGap - radius: Appearance?.rounding.full ?? 9999 + radius: height / 2 color: root.highlightColor } } diff --git a/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml b/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml index 6f2fc2314..99e7b8d6b 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import qs.modules.common import qs.modules.common.widgets import qs.services @@ -17,6 +18,7 @@ Slider { property list stopIndicatorValues: [1] enum Configuration { + Wavy = 4, XS = 12, S = 18, M = 30, @@ -28,10 +30,9 @@ Slider { property real handleDefaultWidth: 3 property real handlePressedWidth: 1.5 - property color highlightColor: Appearance.colors.colPrimary property color trackColor: Appearance.colors.colSecondaryContainer - property color handleColor: Appearance.m3colors.m3onSecondaryContainer + property color handleColor: Appearance.colors.colPrimary property color dotColor: Appearance.m3colors.m3onSecondaryContainer property color dotColorHighlighted: Appearance.m3colors.m3onPrimary property real unsharpenRadius: Appearance.rounding.unsharpen @@ -39,15 +40,18 @@ Slider { property real trackRadius: trackWidth >= StyledSlider.Configuration.XL ? 21 : trackWidth >= StyledSlider.Configuration.L ? 12 : trackWidth >= StyledSlider.Configuration.M ? 9 - : 6 - property real handleHeight: Math.max(33, trackWidth + 9) + : trackWidth >= StyledSlider.Configuration.S ? 6 + : height / 2 + property real handleHeight: (configuration === StyledSlider.Configuration.Wavy) ? 24 : Math.max(33, trackWidth + 9) property real handleWidth: root.pressed ? handlePressedWidth : handleDefaultWidth property real handleMargins: 4 - onHandleMarginsChanged: { - console.log("Handle margins changed to", handleMargins); - } property real trackDotSize: 3 property string tooltipContent: `${Math.round(value * 100)}%` + property bool wavy: configuration === StyledSlider.Configuration.Wavy // If true, the progress bar will have a wavy fill effect + property bool animateWave: true + property real waveAmplitudeMultiplier: wavy ? 0.5 : 0 + property real waveFrequency: 6 + property real waveFps: 60 leftPadding: handleMargins rightPadding: handleMargins @@ -93,18 +97,51 @@ Slider { implicitHeight: trackWidth // Fill left - Rectangle { + Loader { anchors { verticalCenter: parent.verticalCenter left: parent.left } width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins) - height: trackWidth - color: root.highlightColor - topLeftRadius: root.trackRadius - bottomLeftRadius: root.trackRadius - topRightRadius: root.unsharpenRadius - bottomRightRadius: root.unsharpenRadius + height: root.trackWidth + active: !root.wavy + sourceComponent: Rectangle { + color: root.highlightColor + topLeftRadius: root.trackRadius + bottomLeftRadius: root.trackRadius + topRightRadius: root.unsharpenRadius + bottomRightRadius: root.unsharpenRadius + } + } + + Loader { + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + } + width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins) + height: root.height + active: root.wavy + sourceComponent: WavyLine { + id: wavyFill + frequency: root.waveFrequency + fullLength: root.width + color: root.highlightColor + amplitudeMultiplier: root.wavy ? 0.5 : 0 + width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins) + height: root.trackWidth + Connections { + target: root + function onValueChanged() { wavyFill.requestPaint(); } + function onHighlightColorChanged() { wavyFill.requestPaint(); } + } + FrameAnimation { + running: root.animateWave + onTriggered: { + wavyFill.requestPaint() + } + } + } } // Fill right diff --git a/.config/quickshell/ii/modules/common/widgets/WavyLine.qml b/.config/quickshell/ii/modules/common/widgets/WavyLine.qml new file mode 100644 index 000000000..7c3ff528a --- /dev/null +++ b/.config/quickshell/ii/modules/common/widgets/WavyLine.qml @@ -0,0 +1,34 @@ +import qs.modules.common +import QtQuick + +Canvas { + id: root + property real amplitudeMultiplier: 0.5 + property real frequency: 6 + property color color: Appearance?.colors.colPrimary ?? "#685496" + property real lineWidth: 4 + property real fullLength: width + + onPaint: { + var ctx = getContext("2d"); + ctx.clearRect(0, 0, width, height); + + var amplitude = root.lineWidth * root.amplitudeMultiplier; + var frequency = root.frequency; + var phase = Date.now() / 400.0; + var centerY = height / 2; + + ctx.strokeStyle = root.color; + ctx.lineWidth = root.lineWidth; + ctx.lineCap = "round"; + ctx.beginPath(); + for (var x = ctx.lineWidth / 2; x <= root.width - ctx.lineWidth / 2; x += 1) { + var waveY = centerY + amplitude * Math.sin(frequency * 2 * Math.PI * x / root.fullLength + phase); + if (x === 0) + ctx.moveTo(x, waveY); + else + ctx.lineTo(x, waveY); + } + ctx.stroke(); + } +} diff --git a/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml b/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml index 5be82f09e..8cef6a861 100644 --- a/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml +++ b/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import qs.modules.common import qs.modules.common.models import qs.modules.common.widgets @@ -233,16 +234,41 @@ Item { // Player instance Item { id: progressBarContainer Layout.fillWidth: true - implicitHeight: progressBar.implicitHeight + implicitHeight: Math.max(sliderLoader.implicitHeight, progressBarLoader.implicitHeight) - StyledProgressBar { - id: progressBar + Loader { + id: sliderLoader anchors.fill: parent - highlightColor: blendedColors.colPrimary - trackColor: blendedColors.colSecondaryContainer - value: playerController.player?.position / playerController.player?.length - sperm: playerController.player?.isPlaying + active: playerController.player?.canSeek ?? false + sourceComponent: StyledSlider { + configuration: StyledSlider.Configuration.Wavy + highlightColor: blendedColors.colPrimary + trackColor: blendedColors.colSecondaryContainer + handleColor: blendedColors.colPrimary + value: playerController.player?.position / playerController.player?.length + onMoved: { + playerController.player.position = value * playerController.player.length; + } + } } + + Loader { + id: progressBarLoader + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + right: parent.right + } + active: !(playerController.player?.canSeek ?? false) + sourceComponent: StyledProgressBar { + wavy: playerController.player?.isPlaying + highlightColor: blendedColors.colPrimary + trackColor: blendedColors.colSecondaryContainer + value: playerController.player?.position / playerController.player?.length + } + } + + } TrackChangeButton { iconName: "skip_next" diff --git a/.config/quickshell/ii/modules/sidebarRight/volumeMixer/VolumeMixerEntry.qml b/.config/quickshell/ii/modules/sidebarRight/volumeMixer/VolumeMixerEntry.qml index 5ee398015..2f605fafe 100644 --- a/.config/quickshell/ii/modules/sidebarRight/volumeMixer/VolumeMixerEntry.qml +++ b/.config/quickshell/ii/modules/sidebarRight/volumeMixer/VolumeMixerEntry.qml @@ -56,7 +56,7 @@ Item { StyledSlider { id: slider value: root.node.audio.volume - onValueChanged: root.node.audio.volume = value + onMoved: root.node.audio.volume = value } } } From e97f819a5cb249667aeb191366ec56a32b4d00ee Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 11:33:58 +0200 Subject: [PATCH 09/38] make night light auto still function after manual toggle (#2030) --- .config/quickshell/ii/services/Hyprsunset.qml | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/.config/quickshell/ii/services/Hyprsunset.qml b/.config/quickshell/ii/services/Hyprsunset.qml index 3f33aa549..2f7b3569f 100644 --- a/.config/quickshell/ii/services/Hyprsunset.qml +++ b/.config/quickshell/ii/services/Hyprsunset.qml @@ -12,7 +12,6 @@ import Quickshell.Io */ Singleton { id: root - property var manualActive property string from: Config.options?.light?.night?.from ?? "19:00" property string to: Config.options?.light?.night?.to ?? "06:30" property bool automatic: Config.options?.light?.night?.automatic && (Config?.ready ?? true) @@ -29,6 +28,9 @@ Singleton { property int clockHour: DateTime.clock.hours property int clockMinute: DateTime.clock.minutes + property var manualActive + property int manualActiveHour + property int manualActiveMinute onClockMinuteChanged: reEvaluate() onAutomaticChanged: { @@ -36,17 +38,26 @@ Singleton { root.firstEvaluation = true; reEvaluate(); } + + function inBetween(t, from, to) { + if (from < to) { + return (t >= from && t <= to); + } else { + // Wrapped around midnight + return (t >= from || t <= to); + } + } + function reEvaluate() { const t = clockHour * 60 + clockMinute; const from = fromHour * 60 + fromMinute; const to = toHour * 60 + toMinute; + const manualActive = manualActiveHour * 60 + manualActiveMinute; - if (from < to) { - root.shouldBeOn = t >= from && t <= to; - } else { - // Wrapped around midnight - root.shouldBeOn = t >= from || t <= to; + if (root.manualActive !== undefined && (inBetween(from, manualActive, t) || inBetween(to, manualActive, t))) { + root.manualActive = undefined; } + root.shouldBeOn = inBetween(t, from, to); if (firstEvaluation) { firstEvaluation = false; root.ensureState(); @@ -94,15 +105,18 @@ Singleton { if (output.length == 0 || output.startsWith("Couldn't")) root.active = false; else - root.active = (output != "6500"); + root.active = (output != "6500"); // 6500 is the default when off // console.log("[Hyprsunset] Fetched state:", output, "->", root.active); } } } function toggle() { - if (root.manualActive === undefined) + if (root.manualActive === undefined) { root.manualActive = root.active; + root.manualActiveHour = root.clockHour; + root.manualActiveMinute = root.clockMinute; + } root.manualActive = !root.manualActive; if (root.manualActive) { From 05dc53b3962292225cf21e04e27ac4b6d92cad0a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 11:52:35 +0200 Subject: [PATCH 10/38] use StyledImage in more places --- .config/quickshell/ii/modules/background/Background.qml | 8 +------- .../ii/modules/common/widgets/CliphistImage.qml | 2 +- .../quickshell/ii/modules/mediaControls/PlayerControl.qml | 3 +-- .../modules/sidebarLeft/aiChat/AttachedFileIndicator.qml | 3 +-- .../ii/modules/sidebarLeft/anime/BooruImage.qml | 8 +------- 5 files changed, 5 insertions(+), 19 deletions(-) diff --git a/.config/quickshell/ii/modules/background/Background.qml b/.config/quickshell/ii/modules/background/Background.qml index 4ed1055d7..81193ff3a 100644 --- a/.config/quickshell/ii/modules/background/Background.qml +++ b/.config/quickshell/ii/modules/background/Background.qml @@ -175,16 +175,10 @@ Variants { anchors.fill: parent clip: true - Image { + StyledImage { id: wallpaper visible: opacity > 0 && !blurLoader.active - opacity: (status === Image.Ready && !bgRoot.wallpaperIsVideo) ? 1 : 0 - Behavior on opacity { - animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) - } cache: false - asynchronous: true - retainWhileLoading: true smooth: false // Range = groups that workspaces span on property int chunkSize: Config?.options.bar.workspaces.shown ?? 10 diff --git a/.config/quickshell/ii/modules/common/widgets/CliphistImage.qml b/.config/quickshell/ii/modules/common/widgets/CliphistImage.qml index 339cd4e6c..7aa1e6f12 100644 --- a/.config/quickshell/ii/modules/common/widgets/CliphistImage.qml +++ b/.config/quickshell/ii/modules/common/widgets/CliphistImage.qml @@ -77,7 +77,7 @@ Rectangle { } } - Image { + StyledImage { id: image anchors.fill: parent diff --git a/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml b/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml index 8cef6a861..0e318e0f3 100644 --- a/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml +++ b/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml @@ -161,7 +161,7 @@ Item { // Player instance } } - Image { // Art image + StyledImage { // Art image id: mediaArt property int size: parent.height anchors.fill: parent @@ -170,7 +170,6 @@ Item { // Player instance fillMode: Image.PreserveAspectCrop cache: false antialiasing: true - asynchronous: true width: size height: size diff --git a/.config/quickshell/ii/modules/sidebarLeft/aiChat/AttachedFileIndicator.qml b/.config/quickshell/ii/modules/sidebarLeft/aiChat/AttachedFileIndicator.qml index a0a3e14e2..2df576505 100644 --- a/.config/quickshell/ii/modules/sidebarLeft/aiChat/AttachedFileIndicator.qml +++ b/.config/quickshell/ii/modules/sidebarLeft/aiChat/AttachedFileIndicator.qml @@ -125,13 +125,12 @@ Rectangle { sourceComponent: Item { implicitHeight: root.imageHeight * root.scale implicitWidth: imagePreview.implicitWidth - Image { + StyledImage { id: imagePreview anchors.fill: parent source: Qt.resolvedUrl(root.filePath) fillMode: Image.PreserveAspectFit antialiasing: true - asynchronous: true width: root.imageWidth * root.scale height: root.imageHeight * root.scale sourceSize.width: root.imageWidth * root.scale diff --git a/.config/quickshell/ii/modules/sidebarLeft/anime/BooruImage.qml b/.config/quickshell/ii/modules/sidebarLeft/anime/BooruImage.qml index 8df196d9a..1fd18394a 100644 --- a/.config/quickshell/ii/modules/sidebarLeft/anime/BooruImage.qml +++ b/.config/quickshell/ii/modules/sidebarLeft/anime/BooruImage.qml @@ -58,7 +58,7 @@ Button { contentItem: Item { anchors.fill: parent - Image { + StyledImage { id: imageObject anchors.fill: parent width: root.rowHeight * modelData.aspect_ratio @@ -68,12 +68,6 @@ Button { sourceSize.width: root.rowHeight * modelData.aspect_ratio sourceSize.height: root.rowHeight - visible: opacity > 0 - opacity: status === Image.Ready ? 1 : 0 - Behavior on opacity { - animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) - } - layer.enabled: true layer.effect: OpacityMask { maskSource: Rectangle { From 6031bb49537e2681fc1c525c143d0a90a7aa8f83 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 12:05:42 +0200 Subject: [PATCH 11/38] left sidebar: consider closed when floating window is closed --- .config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml b/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml index 0aed7b75d..8d0a43a05 100644 --- a/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml +++ b/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml @@ -127,8 +127,12 @@ Scope { // Scope sourceComponent: FloatingWindow { id: detachedSidebarRoot - visible: GlobalStates.sidebarLeftOpen property var contentParent: detachedSidebarBackground + + visible: GlobalStates.sidebarLeftOpen + onVisibleChanged: { + if (!visible) GlobalStates.sidebarLeftOpen = false; + } Rectangle { id: detachedSidebarBackground From b57e678dc99facdce898287f93480d8813794f9f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 13:15:23 +0200 Subject: [PATCH 12/38] notifications: fix ultra laggy expansion --- .../quickshell/ii/modules/common/widgets/NotificationItem.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml b/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml index 3aafdc400..0c0fa40a4 100644 --- a/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml +++ b/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml @@ -173,7 +173,7 @@ Item { // Notification item area implicitHeight: summaryText.implicitHeight StyledText { id: summaryText - Layout.fillWidth: summaryTextMetrics.width >= summaryRow.width * root.summaryElideRatio + Layout.fillWidth: summaryTextMetrics.width >= summaryRow.implicitWidth * root.summaryElideRatio visible: !root.onlyNotification font.pixelSize: root.fontSize color: Appearance.colors.colOnLayer3 From 0f6c076dda53414922b542b4e042016d941619cb Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 13:42:44 +0200 Subject: [PATCH 13/38] use more non-Layouts --- .../quickshell/ii/modules/bar/BarContent.qml | 8 ++-- .../modules/cheatsheet/CheatsheetKeybinds.qml | 41 +++++++++++-------- .../cheatsheet/CheatsheetPeriodicTable.qml | 6 +-- .../modules/mediaControls/MediaControls.qml | 5 ++- .../verticalBar/VerticalBarContent.qml | 4 +- .config/quickshell/ii/screenshot.qml | 24 +++++------ 6 files changed, 46 insertions(+), 42 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BarContent.qml b/.config/quickshell/ii/modules/bar/BarContent.qml index c0c5e31b8..677801882 100644 --- a/.config/quickshell/ii/modules/bar/BarContent.qml +++ b/.config/quickshell/ii/modules/bar/BarContent.qml @@ -97,7 +97,7 @@ Item { // Bar content region } } - RowLayout { // Middle section + Row { // Middle section id: middleSection anchors { top: parent.top @@ -108,8 +108,7 @@ Item { // Bar content region BarGroup { id: leftCenterGroup - Layout.preferredWidth: root.centerSideModuleWidth - Layout.fillHeight: false + implicitWidth: root.centerSideModuleWidth Resources { alwaysShowAllResources: root.useShortenedForm === 2 @@ -153,9 +152,8 @@ Item { // Bar content region MouseArea { id: rightCenterGroup - implicitWidth: rightCenterGroupContent.implicitWidth + implicitWidth: root.centerSideModuleWidth implicitHeight: rightCenterGroupContent.implicitHeight - Layout.preferredWidth: root.centerSideModuleWidth onPressed: { GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; diff --git a/.config/quickshell/ii/modules/cheatsheet/CheatsheetKeybinds.qml b/.config/quickshell/ii/modules/cheatsheet/CheatsheetKeybinds.qml index e0e8ce6cd..8c21d3426 100644 --- a/.config/quickshell/ii/modules/cheatsheet/CheatsheetKeybinds.qml +++ b/.config/quickshell/ii/modules/cheatsheet/CheatsheetKeybinds.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import qs import qs.services import qs.modules.common @@ -11,8 +12,9 @@ Item { readonly property var keybinds: HyprlandKeybinds.keybinds property real spacing: 20 property real titleSpacing: 7 - implicitWidth: rowLayout.implicitWidth - implicitHeight: rowLayout.implicitHeight + property real padding: 4 + implicitWidth: row.implicitWidth + padding * 2 + implicitHeight: row.implicitHeight + padding * 2 property var keyBlacklist: ["Super_L"] property var keySubstitutions: ({ @@ -28,43 +30,51 @@ Item { // "Shift": "", }) - RowLayout { // Keybind columns - id: rowLayout + Row { // Keybind columns + id: row spacing: root.spacing + Repeater { model: keybinds.children - delegate: ColumnLayout { // Keybind sections + delegate: Column { // Keybind sections spacing: root.spacing required property var modelData - Layout.alignment: Qt.AlignTop + anchors.top: row.top + Repeater { model: modelData.children delegate: Item { // Section with real keybinds + id: keybindSection required property var modelData - implicitWidth: sectionColumnLayout.implicitWidth - implicitHeight: sectionColumnLayout.implicitHeight - ColumnLayout { - id: sectionColumnLayout + implicitWidth: sectionColumn.implicitWidth + implicitHeight: sectionColumn.implicitHeight + + Column { + id: sectionColumn anchors.centerIn: parent spacing: root.titleSpacing + StyledText { id: sectionTitle font.family: Appearance.font.family.title font.pixelSize: Appearance.font.pixelSize.huge color: Appearance.colors.colOnLayer0 - text: modelData.name + text: keybindSection.modelData.name } - GridLayout { + Grid { id: keybindGrid columns: 2 + columnSpacing: 4 + rowSpacing: 4 + Repeater { model: { var result = []; - for (var i = 0; i < modelData.keybinds.length; i++) { - const keybind = modelData.keybinds[i]; + for (var i = 0; i < keybindSection.modelData.keybinds.length; i++) { + const keybind = keybindSection.modelData.keybinds[i]; result.push({ "type": "keys", "mods": keybind.mods, @@ -89,7 +99,7 @@ Item { Component { id: keysComponent - RowLayout { + Row { spacing: 4 Repeater { model: modelData.mods @@ -101,7 +111,6 @@ Item { StyledText { id: keybindPlus visible: !keyBlacklist.includes(modelData.key) && modelData.mods.length > 0 - Layout.alignment: Qt.AlignVCenter text: "+" } KeyboardKey { diff --git a/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml b/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml index a0a8ecf3f..c21ddc825 100644 --- a/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml +++ b/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml @@ -15,14 +15,14 @@ Item { implicitWidth: mainLayout.implicitWidth implicitHeight: mainLayout.implicitHeight - ColumnLayout { + Column { id: mainLayout spacing: root.spacing Repeater { // Main table rows model: root.elements - delegate: RowLayout { // Table cells + delegate: Row { // Table cells id: tableRow spacing: root.spacing required property var modelData @@ -47,7 +47,7 @@ Item { Repeater { // Main table rows model: root.series - delegate: RowLayout { // Table cells + delegate: Row { // Table cells id: seriesTableRow spacing: root.spacing required property var modelData diff --git a/.config/quickshell/ii/modules/mediaControls/MediaControls.qml b/.config/quickshell/ii/modules/mediaControls/MediaControls.qml index b5742075a..5f8154a76 100644 --- a/.config/quickshell/ii/modules/mediaControls/MediaControls.qml +++ b/.config/quickshell/ii/modules/mediaControls/MediaControls.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import qs.modules.common import qs.modules.common.widgets import qs.services @@ -153,8 +154,8 @@ Scope { required property MprisPlayer modelData player: modelData visualizerPoints: root.visualizerPoints - implicitWidth: widgetWidth - implicitHeight: widgetHeight + implicitWidth: root.widgetWidth + implicitHeight: root.widgetHeight radius: root.popupRounding } } diff --git a/.config/quickshell/ii/modules/verticalBar/VerticalBarContent.qml b/.config/quickshell/ii/modules/verticalBar/VerticalBarContent.qml index 612510720..8635bc969 100644 --- a/.config/quickshell/ii/modules/verticalBar/VerticalBarContent.qml +++ b/.config/quickshell/ii/modules/verticalBar/VerticalBarContent.qml @@ -80,7 +80,7 @@ Item { // Bar content region } } - ColumnLayout { // Middle section + Column { // Middle section id: middleSection anchors.centerIn: parent spacing: 4 @@ -156,8 +156,6 @@ Item { // Bar content region Layout.fillWidth: true Layout.fillHeight: false } - - } } diff --git a/.config/quickshell/ii/screenshot.qml b/.config/quickshell/ii/screenshot.qml index a8e102048..ec52aaa33 100644 --- a/.config/quickshell/ii/screenshot.qml +++ b/.config/quickshell/ii/screenshot.qml @@ -74,10 +74,10 @@ ShellRoot { } implicitWidth: regionInfoRow.implicitWidth + horizontalPadding * 2 implicitHeight: regionInfoRow.implicitHeight + verticalPadding * 2 - RowLayout { + Row { id: regionInfoRow anchors.centerIn: parent - spacing: 8 + spacing: 4 Loader { id: regionIconLoader @@ -430,21 +430,19 @@ ShellRoot { implicitWidth: instructionsRow.implicitWidth + 10 * 2 implicitHeight: instructionsRow.implicitHeight + 5 * 2 - RowLayout { + Row { id: instructionsRow anchors.centerIn: parent - Item { - Layout.fillHeight: true - implicitWidth: screenshotRegionIcon.implicitWidth - MaterialSymbol { - id: screenshotRegionIcon - anchors.centerIn: parent - iconSize: Appearance.font.pixelSize.larger - text: "screenshot_region" - color: root.genericContentForeground - } + spacing: 4 + MaterialSymbol { + id: screenshotRegionIcon + // anchors.centerIn: parent + iconSize: Appearance.font.pixelSize.larger + text: "screenshot_region" + color: root.genericContentForeground } StyledText { + anchors.verticalCenter: parent.verticalCenter text: Translation.tr("Drag or click a region • LMB: Copy • RMB: Edit") color: root.genericContentForeground } From 7237dd053dd898298c20a446f7ecc2bedf0692a0 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 13:47:40 +0200 Subject: [PATCH 14/38] lock: use Rows instead of RowLayouts --- .../ii/modules/lock/LockSurface.qml | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.config/quickshell/ii/modules/lock/LockSurface.qml b/.config/quickshell/ii/modules/lock/LockSurface.qml index c917e3a66..62137adfa 100644 --- a/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -155,21 +155,21 @@ MouseArea { opacity: root.toolbarOpacity // Username - RowLayout { + Row { spacing: 6 Layout.leftMargin: 8 Layout.fillHeight: true MaterialSymbol { id: userIcon - Layout.alignment: Qt.AlignVCenter + anchors.verticalCenter: parent.verticalCenter fill: 1 text: "account_circle" iconSize: Appearance.font.pixelSize.huge color: Appearance.colors.colOnSurfaceVariant } StyledText { - Layout.alignment: Qt.AlignVCenter + anchors.verticalCenter: parent.verticalCenter text: SystemInfo.username color: Appearance.colors.colOnSurfaceVariant } @@ -184,18 +184,19 @@ MouseArea { active: true visible: active - sourceComponent: RowLayout { + sourceComponent: Row { spacing: 8 MaterialSymbol { id: keyboardIcon - Layout.alignment: Qt.AlignVCenter + anchors.verticalCenter: parent.verticalCenter fill: 1 text: "keyboard_alt" iconSize: Appearance.font.pixelSize.huge color: Appearance.colors.colOnSurfaceVariant } Loader { + anchors.verticalCenter: parent.verticalCenter sourceComponent: StyledText { text: HyprlandXkb.currentLayoutCode color: Appearance.colors.colOnSurfaceVariant @@ -229,18 +230,18 @@ MouseArea { scale: root.toolbarScale opacity: root.toolbarOpacity - RowLayout { + Row { visible: UPower.displayDevice.isLaptopBattery - spacing: 6 + spacing: 4 Layout.fillHeight: true Layout.leftMargin: 10 Layout.rightMargin: 10 MaterialSymbol { id: boltIcon - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: -2 - Layout.rightMargin: -2 + anchors { + verticalCenter: parent.verticalCenter + } fill: 1 text: Battery.isCharging ? "bolt" : "battery_android_full" iconSize: Appearance.font.pixelSize.huge @@ -248,7 +249,7 @@ MouseArea { color: (Battery.isLow && !Battery.isCharging) ? Appearance.colors.colError : Appearance.colors.colOnSurfaceVariant } StyledText { - Layout.alignment: Qt.AlignVCenter + anchors.verticalCenter: parent.verticalCenter text: Math.round(Battery.percentage * 100) color: (Battery.isLow && !Battery.isCharging) ? Appearance.colors.colError : Appearance.colors.colOnSurfaceVariant } From 0ce4260134721bb240acea79322fc22ecbf93d6f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 13:53:27 +0200 Subject: [PATCH 15/38] background: fewer Layouts --- .../quickshell/ii/modules/background/Background.qml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.config/quickshell/ii/modules/background/Background.qml b/.config/quickshell/ii/modules/background/Background.qml index 81193ff3a..28f8028de 100644 --- a/.config/quickshell/ii/modules/background/Background.qml +++ b/.config/quickshell/ii/modules/background/Background.qml @@ -294,9 +294,7 @@ Variants { easing.bezierCurve: Appearance.animation.elementMove.bezierCurve } } - sourceComponent: ColumnLayout { - spacing: 8 - + sourceComponent: Column { Loader { id: digitalClockLoader visible: root.clockStyle === "digital" @@ -334,7 +332,6 @@ Variants { Loader { id: cookieClockLoader - Layout.alignment: Qt.AlignHCenter visible: root.clockStyle === "cookie" active: visible sourceComponent: CookieClock {} @@ -426,7 +423,7 @@ Variants { styleColor: Appearance.colors.colShadow animateChange: true } - component ClockStatusText: RowLayout { + component ClockStatusText: Row { id: statusTextRow property alias statusIcon: statusIconWidget.text property alias statusText: statusTextWidget.text @@ -437,10 +434,10 @@ Variants { Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } - Layout.fillWidth: false + spacing: 4 MaterialSymbol { id: statusIconWidget - Layout.fillWidth: false + anchors.verticalCenter: statusTextRow.verticalCenter iconSize: Appearance.font.pixelSize.huge color: statusTextRow.textColor style: Text.Raised @@ -448,8 +445,8 @@ Variants { } ClockText { id: statusTextWidget - Layout.fillWidth: false color: statusTextRow.textColor + anchors.verticalCenter: statusTextRow.verticalCenter font { family: Appearance.font.family.main pixelSize: Appearance.font.pixelSize.large From de6969f561570d93c9bf161613a833ef860784a6 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:03:18 +0200 Subject: [PATCH 16/38] bar: fix tooltip shadow cutoff, use fewer Layouts --- .../ii/modules/bar/BatteryPopup.qml | 4 ++- .../ii/modules/bar/ClockWidgetTooltip.qml | 12 ++++---- .../ii/modules/bar/ResourcesPopup.qml | 28 +++++++++++-------- .../quickshell/ii/modules/bar/StyledPopup.qml | 12 ++++---- .../ii/modules/verticalBar/VerticalMedia.qml | 10 +++++-- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml index c697bfbda..1f96155e0 100644 --- a/.config/quickshell/ii/modules/bar/BatteryPopup.qml +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -14,11 +14,12 @@ StyledPopup { spacing: 4 // Header - RowLayout { + Row { id: header spacing: 5 MaterialSymbol { + anchors.verticalCenter: parent.verticalCenter fill: 0 font.weight: Font.Medium text: "battery_android_full" @@ -27,6 +28,7 @@ StyledPopup { } StyledText { + anchors.verticalCenter: parent.verticalCenter text: "Battery" font { weight: Font.Medium diff --git a/.config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml b/.config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml index b2e0165ac..de6ad0935 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml @@ -39,10 +39,11 @@ StyledPopup { spacing: 4 // Date + Time row - RowLayout { + Row { spacing: 5 MaterialSymbol { + anchors.verticalCenter: parent.verticalCenter fill: 0 font.weight: Font.Medium text: "calendar_month" @@ -50,6 +51,7 @@ StyledPopup { color: Appearance.colors.colOnSurfaceVariant } StyledText { + anchors.verticalCenter: parent.verticalCenter horizontalAlignment: Text.AlignLeft color: Appearance.colors.colOnSurfaceVariant text: `${root.formattedDate}` @@ -79,26 +81,26 @@ StyledPopup { } // Tasks - ColumnLayout { + Column { spacing: 0 Layout.fillWidth: true - RowLayout { + Row { spacing: 4 - Layout.fillWidth: true MaterialSymbol { + anchors.verticalCenter: parent.verticalCenter text: "checklist" color: Appearance.colors.colOnSurfaceVariant font.pixelSize: Appearance.font.pixelSize.large } StyledText { + anchors.verticalCenter: parent.verticalCenter text: Translation.tr("To Do:") color: Appearance.colors.colOnSurfaceVariant } } StyledText { - Layout.fillWidth: true horizontalAlignment: Text.AlignLeft wrapMode: Text.Wrap color: Appearance.colors.colOnSurfaceVariant diff --git a/.config/quickshell/ii/modules/bar/ResourcesPopup.qml b/.config/quickshell/ii/modules/bar/ResourcesPopup.qml index 2c694de1e..6aeedf76a 100644 --- a/.config/quickshell/ii/modules/bar/ResourcesPopup.qml +++ b/.config/quickshell/ii/modules/bar/ResourcesPopup.qml @@ -20,7 +20,6 @@ StyledPopup { required property string label required property string value spacing: 4 - Layout.fillWidth: true MaterialSymbol { text: resourceItem.icon @@ -40,13 +39,14 @@ StyledPopup { } } - component ResourceHeaderItem: RowLayout { + component ResourceHeaderItem: Row { id: headerItem required property var icon required property var label spacing: 5 MaterialSymbol { + anchors.verticalCenter: parent.verticalCenter fill: 0 font.weight: Font.Medium text: headerItem.icon @@ -55,6 +55,7 @@ StyledPopup { } StyledText { + anchors.verticalCenter: parent.verticalCenter text: headerItem.label font { weight: Font.Medium @@ -64,19 +65,20 @@ StyledPopup { } } - RowLayout { + Row { anchors.centerIn: parent spacing: 12 - ColumnLayout { - Layout.alignment: Qt.AlignTop + Column { + anchors.top: parent.top spacing: 8 ResourceHeaderItem { icon: "memory" label: "RAM" } - ColumnLayout { + Column { + spacing: 4 ResourceItem { icon: "clock_loader_60" label: Translation.tr("Used:") @@ -95,16 +97,17 @@ StyledPopup { } } - ColumnLayout { + Column { visible: ResourceUsage.swapTotal > 0 - Layout.alignment: Qt.AlignTop + anchors.top: parent.top spacing: 8 ResourceHeaderItem { icon: "swap_horiz" label: "Swap" } - ColumnLayout { + Column { + spacing: 4 ResourceItem { icon: "clock_loader_60" label: Translation.tr("Used:") @@ -123,15 +126,16 @@ StyledPopup { } } - ColumnLayout { - Layout.alignment: Qt.AlignTop + Column { + anchors.top: parent.top spacing: 8 ResourceHeaderItem { icon: "planner_review" label: "CPU" } - ColumnLayout { + Column { + spacing: 4 ResourceItem { icon: "bolt" label: Translation.tr("Load:") diff --git a/.config/quickshell/ii/modules/bar/StyledPopup.qml b/.config/quickshell/ii/modules/bar/StyledPopup.qml index 68ba609e2..9b030685f 100644 --- a/.config/quickshell/ii/modules/bar/StyledPopup.qml +++ b/.config/quickshell/ii/modules/bar/StyledPopup.qml @@ -24,8 +24,8 @@ LazyLoader { anchors.top: Config.options.bar.vertical || (!Config.options.bar.vertical && !Config.options.bar.bottom) anchors.bottom: !Config.options.bar.vertical && Config.options.bar.bottom - implicitWidth: popupBackground.implicitWidth + Appearance.sizes.hyprlandGapsOut * 2 + root.popupBackgroundMargin - implicitHeight: popupBackground.implicitHeight + Appearance.sizes.hyprlandGapsOut * 2 + root.popupBackgroundMargin + implicitWidth: popupBackground.implicitWidth + Appearance.sizes.elevationMargin * 2 + root.popupBackgroundMargin + implicitHeight: popupBackground.implicitHeight + Appearance.sizes.elevationMargin * 2 + root.popupBackgroundMargin mask: Region { item: popupBackground @@ -63,10 +63,10 @@ LazyLoader { readonly property real margin: 10 anchors { fill: parent - leftMargin: Appearance.sizes.hyprlandGapsOut + root.popupBackgroundMargin * (!popupWindow.anchors.left) - rightMargin: Appearance.sizes.hyprlandGapsOut + root.popupBackgroundMargin * (!popupWindow.anchors.right) - topMargin: Appearance.sizes.hyprlandGapsOut + root.popupBackgroundMargin * (!popupWindow.anchors.top) - bottomMargin: Appearance.sizes.hyprlandGapsOut + root.popupBackgroundMargin * (!popupWindow.anchors.bottom) + leftMargin: Appearance.sizes.elevationMargin + root.popupBackgroundMargin * (!popupWindow.anchors.left) + rightMargin: Appearance.sizes.elevationMargin + root.popupBackgroundMargin * (!popupWindow.anchors.right) + topMargin: Appearance.sizes.elevationMargin + root.popupBackgroundMargin * (!popupWindow.anchors.top) + bottomMargin: Appearance.sizes.elevationMargin + root.popupBackgroundMargin * (!popupWindow.anchors.bottom) } implicitWidth: root.contentItem.implicitWidth + margin * 2 implicitHeight: root.contentItem.implicitHeight + margin * 2 diff --git a/.config/quickshell/ii/modules/verticalBar/VerticalMedia.qml b/.config/quickshell/ii/modules/verticalBar/VerticalMedia.qml index 1be93d4a7..24eed8b4f 100644 --- a/.config/quickshell/ii/modules/verticalBar/VerticalMedia.qml +++ b/.config/quickshell/ii/modules/verticalBar/VerticalMedia.qml @@ -70,12 +70,15 @@ MouseArea { hoverTarget: root active: GlobalStates.mediaControlsOpen ? false : root.containsMouse - ColumnLayout { + Column { anchors.centerIn: parent - RowLayout { - spacing: 5 + spacing: 4 + + Row { + spacing: 4 MaterialSymbol { + anchors.verticalCenter: parent.verticalCenter fill: 0 font.weight: Font.Medium text: "music_note" @@ -84,6 +87,7 @@ MouseArea { } StyledText { + anchors.verticalCenter: parent.verticalCenter text: "Media" font { weight: Font.Medium From b497c22d6b8d8df89c776ad322501c8dd588b008 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:07:50 +0200 Subject: [PATCH 17/38] overview: fewer Layouts --- .../ii/modules/overview/OverviewWidget.qml | 4 +- .../ii/modules/overview/OverviewWindow.qml | 50 ++++++++----------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/.config/quickshell/ii/modules/overview/OverviewWidget.qml b/.config/quickshell/ii/modules/overview/OverviewWidget.qml index a7255415c..51b1acbe3 100644 --- a/.config/quickshell/ii/modules/overview/OverviewWidget.qml +++ b/.config/quickshell/ii/modules/overview/OverviewWidget.qml @@ -63,7 +63,7 @@ Item { border.width: 1 border.color: Appearance.colors.colLayer0Border - ColumnLayout { // Workspaces + Column { // Workspaces id: workspaceColumnLayout z: root.workspaceZ @@ -71,7 +71,7 @@ Item { spacing: workspaceSpacing Repeater { model: Config.options.overview.rows - delegate: RowLayout { + delegate: Row { id: row property int rowIndex: index spacing: workspaceSpacing diff --git a/.config/quickshell/ii/modules/overview/OverviewWindow.qml b/.config/quickshell/ii/modules/overview/OverviewWindow.qml index 856096f38..b2d39cfea 100644 --- a/.config/quickshell/ii/modules/overview/OverviewWindow.qml +++ b/.config/quickshell/ii/modules/overview/OverviewWindow.qml @@ -81,35 +81,29 @@ Item { // Window border.width : 1 } - ColumnLayout { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - spacing: Appearance.font.pixelSize.smaller * 0.5 + Image { + id: windowIcon + anchors.centerIn: parent + property var iconSize: { + // console.log("-=-=-", root.toplevel.title, "-=-=-") + // console.log("Target window size:", targetWindowWidth, targetWindowHeight) + // console.log("Icon ratio:", root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) + // console.log("Scale:", root.monitorData.scale) + // console.log("Final:", Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / root.monitorData.scale) + return Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / root.monitorData.scale; + } + // mipmap: true + Layout.alignment: Qt.AlignHCenter + source: root.iconPath + width: iconSize + height: iconSize + sourceSize: Qt.size(iconSize, iconSize) - Image { - id: windowIcon - property var iconSize: { - // console.log("-=-=-", root.toplevel.title, "-=-=-") - // console.log("Target window size:", targetWindowWidth, targetWindowHeight) - // console.log("Icon ratio:", root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) - // console.log("Scale:", root.monitorData.scale) - // console.log("Final:", Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / root.monitorData.scale) - return Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / root.monitorData.scale; - } - // mipmap: true - Layout.alignment: Qt.AlignHCenter - source: root.iconPath - width: iconSize - height: iconSize - sourceSize: Qt.size(iconSize, iconSize) - - Behavior on width { - animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) - } - Behavior on height { - animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) - } + Behavior on width { + animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) + } + Behavior on height { + animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) } } } From 410971a228f4718eab880639abd79b87fac78660 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:14:43 +0200 Subject: [PATCH 18/38] scroll hint: no more Layout, add tooltip --- .../quickshell/ii/modules/bar/ScrollHint.qml | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/ScrollHint.qml b/.config/quickshell/ii/modules/bar/ScrollHint.qml index 9a338df48..37b6a4886 100644 --- a/.config/quickshell/ii/modules/bar/ScrollHint.qml +++ b/.config/quickshell/ii/modules/bar/ScrollHint.qml @@ -2,7 +2,6 @@ import qs import qs.modules.common import qs.modules.common.widgets import QtQuick -import QtQuick.Layouts Revealer { // Scroll hint id: root @@ -11,10 +10,11 @@ Revealer { // Scroll hint property string tooltipText: "" MouseArea { + id: mouseArea anchors.right: root.side === "left" ? parent.right : undefined anchors.left: root.side === "right" ? parent.left : undefined - implicitWidth: contentColumnLayout.implicitWidth - implicitHeight: contentColumnLayout.implicitHeight + implicitWidth: contentColumn.implicitWidth + implicitHeight: contentColumn.implicitHeight property bool hovered: false hoverEnabled: true @@ -22,32 +22,36 @@ Revealer { // Scroll hint onExited: hovered = false acceptedButtons: Qt.NoButton - // StyledToolTip { - // extraVisibleCondition: tooltipText.length > 0 - // text: tooltipText - // } + property bool showHintTimedOut: false + onHoveredChanged: showHintTimedOut = false + Timer { + running: mouseArea.hovered + interval: 500 + onTriggered: mouseArea.showHintTimedOut = true + } - ColumnLayout { - id: contentColumnLayout - anchors.centerIn: parent + PopupToolTip { + extraVisibleCondition: (tooltipText.length > 0 && mouseArea.showHintTimedOut) + text: tooltipText + } + + Column { + id: contentColumn + anchors { + fill: parent + } spacing: -5 MaterialSymbol { - Layout.leftMargin: 5 - Layout.rightMargin: 5 text: "keyboard_arrow_up" iconSize: 14 color: Appearance.colors.colSubtext } MaterialSymbol { - Layout.leftMargin: 5 - Layout.rightMargin: 5 text: root.icon iconSize: 14 color: Appearance.colors.colSubtext } MaterialSymbol { - Layout.leftMargin: 5 - Layout.rightMargin: 5 text: "keyboard_arrow_down" iconSize: 14 color: Appearance.colors.colSubtext From d24555a4d7f5baa9bdb4d7f13d3f68de8d847eab Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 14:25:52 +0200 Subject: [PATCH 19/38] bar: workspaces: no more Layout --- .../quickshell/ii/modules/bar/Workspaces.qml | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/Workspaces.qml b/.config/quickshell/ii/modules/bar/Workspaces.qml index 5d0c9f62b..118be89d1 100644 --- a/.config/quickshell/ii/modules/bar/Workspaces.qml +++ b/.config/quickshell/ii/modules/bar/Workspaces.qml @@ -5,7 +5,6 @@ import qs.modules.common.widgets import qs.modules.common.functions import QtQuick import QtQuick.Controls -import QtQuick.Layouts import Quickshell import Quickshell.Wayland import Quickshell.Hyprland @@ -19,7 +18,8 @@ Item { readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.QsWindow.window?.screen) readonly property Toplevel activeWindow: ToplevelManager.activeToplevel - readonly property int workspaceGroup: Math.floor((monitor?.activeWorkspace?.id - 1) / Config.options.bar.workspaces.shown) + readonly property int workspacesShown: Config.options.bar.workspaces.shown + readonly property int workspaceGroup: Math.floor((monitor?.activeWorkspace?.id - 1) / root.workspacesShown) property list workspaceOccupied: [] property int widgetPadding: 4 property int workspaceButtonWidth: 26 @@ -28,7 +28,7 @@ Item { property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55 property real workspaceIconOpacityShrinked: 1 property real workspaceIconMarginShrinked: -4 - property int workspaceIndexInGroup: (monitor?.activeWorkspace?.id - 1) % Config.options.bar.workspaces.shown + property int workspaceIndexInGroup: (monitor?.activeWorkspace?.id - 1) % root.workspacesShown property bool showNumbers: false Timer { @@ -56,8 +56,8 @@ Item { // Function to update workspaceOccupied function updateWorkspaceOccupied() { - workspaceOccupied = Array.from({ length: Config.options.bar.workspaces.shown }, (_, i) => { - return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * Config.options.bar.workspaces.shown + i + 1); + workspaceOccupied = Array.from({ length: root.workspacesShown }, (_, i) => { + return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * root.workspacesShown + i + 1); }) } @@ -79,8 +79,8 @@ Item { updateWorkspaceOccupied(); } - implicitWidth: root.vertical ? Appearance.sizes.verticalBarWidth : backgroundLayout.implicitWidth - implicitHeight: root.vertical ? backgroundLayout.implicitHeight : Appearance.sizes.barHeight + implicitWidth: root.vertical ? Appearance.sizes.verticalBarWidth : (root.workspaceButtonWidth * root.workspacesShown) + implicitHeight: root.vertical ? (root.workspaceButtonWidth * root.workspacesShown) : Appearance.sizes.barHeight // Scroll to switch workspaces WheelHandler { @@ -104,24 +104,20 @@ Item { } // Workspaces - background - GridLayout { - id: backgroundLayout + Grid { z: 1 - anchors.fill: parent - implicitHeight: root.vertical ? root.workspaceButtonWidth : Appearance.sizes.barHeight - implicitWidth: root.vertical ? Appearance.sizes.verticalBarWidth : root.workspaceButtonWidth + anchors.centerIn: parent rowSpacing: 0 columnSpacing: 0 - columns: root.vertical ? 1 : -1 + columns: root.vertical ? 1 : root.workspacesShown + rows: root.vertical ? root.workspacesShown : 1 Repeater { - model: Config.options.bar.workspaces.shown + model: root.workspacesShown Rectangle { z: 1 - Layout.alignment: root.vertical ? Qt.AlignHCenter : Qt.AlignVCenter - implicitWidth: workspaceButtonWidth implicitHeight: workspaceButtonWidth radius: (width / 2) @@ -195,26 +191,24 @@ Item { } // Workspaces - numbers - GridLayout { - id: rowLayoutNumbers + Grid { z: 3 - columns: vertical ? 1 : -1 + columns: root.vertical ? 1 : root.workspacesShown + rows: root.vertical ? root.workspacesShown : 1 columnSpacing: 0 rowSpacing: 0 anchors.fill: parent - implicitHeight: vertical ? Appearance.sizes.verticalBarWidth : Appearance.sizes.barHeight - implicitWidth: vertical ? Appearance.sizes.verticalBarWidth : Appearance.sizes.verticalBarWidth Repeater { - model: Config.options.bar.workspaces.shown + model: root.workspacesShown Button { id: button - property int workspaceValue: workspaceGroup * Config.options.bar.workspaces.shown + index + 1 - Layout.fillHeight: !root.vertical - Layout.fillWidth: root.vertical + property int workspaceValue: workspaceGroup * root.workspacesShown + index + 1 + implicitHeight: vertical ? Appearance.sizes.verticalBarWidth : Appearance.sizes.barHeight + implicitWidth: vertical ? Appearance.sizes.verticalBarWidth : Appearance.sizes.verticalBarWidth onPressed: Hyprland.dispatch(`workspace ${workspaceValue}`) width: vertical ? undefined : workspaceButtonWidth height: vertical ? workspaceButtonWidth : undefined From 667afa6d64c570703e56cc47cd78af508147565d Mon Sep 17 00:00:00 2001 From: nrand Date: Sun, 28 Sep 2025 15:25:59 +0300 Subject: [PATCH 20/38] cheatsheet: added element weight to periodic table --- .../ii/modules/cheatsheet/ElementTile.qml | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml b/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml index 70e7b4d69..4d9e33923 100644 --- a/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml +++ b/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml @@ -26,13 +26,35 @@ RippleButton { StyledText { id: elementNumber - anchors.centerIn: parent + anchors.left: parent.left color: Appearance.colors.colOnLayer2 text: root.element.number font.pixelSize: Appearance.font.pixelSize.smallest } } + Rectangle { + anchors { + top: parent.top + right: parent.right + topMargin: 4 + rightMargin: 4 + } + color: Appearance.colors.colLayer2 + radius: Appearance.rounding.full + implicitWidth: Math.max(20, elementWeight.implicitWidth) + implicitHeight: Math.max(20, elementWeight.implicitHeight) + width: height + + StyledText { + id: elementWeight + anchors.right: parent.right + color: Appearance.colors.colOnLayer2 + text: root.element.weight + font.pixelSize: Appearance.font.pixelSize.smallest + } + } + StyledText { id: elementSymbol anchors.centerIn: parent From 3dd5e78b35e00e765f1b778e34400873b3021968 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 16:43:43 +0200 Subject: [PATCH 21/38] overview: force floating windows to be on top of tiling ones (#2068) --- .config/quickshell/ii/modules/overview/OverviewWidget.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/quickshell/ii/modules/overview/OverviewWidget.qml b/.config/quickshell/ii/modules/overview/OverviewWidget.qml index 51b1acbe3..27a095ac6 100644 --- a/.config/quickshell/ii/modules/overview/OverviewWidget.qml +++ b/.config/quickshell/ii/modules/overview/OverviewWidget.qml @@ -148,17 +148,16 @@ Item { model: ScriptModel { values: { // console.log(JSON.stringify(ToplevelManager.toplevels.values.map(t => t), null, 2)) - return ToplevelManager.toplevels.values.filter((toplevel) => { + return [...ToplevelManager.toplevels.values.filter((toplevel) => { const address = `0x${toplevel.HyprlandToplevel?.address}` var win = windowByAddress[address] const inWorkspaceGroup = (root.workspaceGroup * root.workspacesShown < win?.workspace?.id && win?.workspace?.id <= (root.workspaceGroup + 1) * root.workspacesShown) return inWorkspaceGroup; - }) + })].reverse() } } delegate: OverviewWindow { id: window - windowData: windowByAddress[address] required property var modelData property int monitorId: windowData?.monitor property var monitor: HyprlandData.monitors.find(m => m.id == monitorId) @@ -169,6 +168,7 @@ Item { availableWorkspaceWidth: root.workspaceImplicitWidth availableWorkspaceHeight: root.workspaceImplicitHeight widgetMonitorId: root.monitor.id + windowData: windowByAddress[address] property bool atInitPosition: (initX == x && initY == y) @@ -188,7 +188,7 @@ Item { } } - z: atInitPosition ? root.windowZ : root.windowDraggingZ + z: atInitPosition ? (root.windowZ + windowData?.floating) : root.windowDraggingZ Drag.hotSpot.x: targetWindowWidth / 2 Drag.hotSpot.y: targetWindowHeight / 2 MouseArea { From 01ab0f5ab99d8b4d5532451b74603fe7ac5ea6a6 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 16:57:32 +0200 Subject: [PATCH 22/38] cheatsheet: ptable: make elements not look weird when hovered --- .config/quickshell/ii/modules/cheatsheet/ElementTile.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml b/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml index 4d9e33923..d84abedfd 100644 --- a/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml +++ b/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml @@ -1,4 +1,5 @@ import qs.modules.common +import qs.modules.common.functions import qs.modules.common.widgets import QtQuick @@ -18,7 +19,7 @@ RippleButton { topMargin: 4 leftMargin: 4 } - color: Appearance.colors.colLayer2 + color: ColorUtils.transparentize(Appearance.colors.colLayer2) radius: Appearance.rounding.full implicitWidth: Math.max(20, elementNumber.implicitWidth) implicitHeight: Math.max(20, elementNumber.implicitHeight) @@ -40,7 +41,7 @@ RippleButton { topMargin: 4 rightMargin: 4 } - color: Appearance.colors.colLayer2 + color: ColorUtils.transparentize(Appearance.colors.colLayer2) radius: Appearance.rounding.full implicitWidth: Math.max(20, elementWeight.implicitWidth) implicitHeight: Math.max(20, elementWeight.implicitHeight) From bd8e004795434309df8f6f1c53d26092f67fa24c Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 18:04:57 +0200 Subject: [PATCH 23/38] osd: unify brightness and volume --- .../ii/modules/common/Appearance.qml | 2 +- ...nDisplayVolume.qml => OnScreenDisplay.qml} | 82 +++++---- .../OnScreenDisplayBrightness.qml | 157 ------------------ .../onScreenDisplay/OsdValueIndicator.qml | 22 +-- .../indicators/BrightnessIndicator.qml | 18 ++ .../indicators/VolumeIndicator.qml | 11 ++ .config/quickshell/ii/shell.qml | 6 +- 7 files changed, 92 insertions(+), 206 deletions(-) rename .config/quickshell/ii/modules/onScreenDisplay/{OnScreenDisplayVolume.qml => OnScreenDisplay.qml} (77%) delete mode 100644 .config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplayBrightness.qml create mode 100644 .config/quickshell/ii/modules/onScreenDisplay/indicators/BrightnessIndicator.qml create mode 100644 .config/quickshell/ii/modules/onScreenDisplay/indicators/VolumeIndicator.qml diff --git a/.config/quickshell/ii/modules/common/Appearance.qml b/.config/quickshell/ii/modules/common/Appearance.qml index d63d04800..d6822785a 100644 --- a/.config/quickshell/ii/modules/common/Appearance.qml +++ b/.config/quickshell/ii/modules/common/Appearance.qml @@ -356,7 +356,7 @@ Singleton { property real mediaControlsWidth: 440 property real mediaControlsHeight: 160 property real notificationPopupWidth: 410 - property real osdWidth: 200 + property real osdWidth: 180 property real searchWidthCollapsed: 260 property real searchWidth: 450 property real sidebarWidth: 460 diff --git a/.config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplayVolume.qml b/.config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplay.qml similarity index 77% rename from .config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplayVolume.qml rename to .config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplay.qml index 51207d6df..21b9c4320 100644 --- a/.config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplayVolume.qml +++ b/.config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplay.qml @@ -15,9 +15,21 @@ Scope { property string protectionMessage: "" property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) + property string currentIndicator: "volume" + property var indicators: [ + { + id: "volume", + sourceUrl: "indicators/VolumeIndicator.qml" + }, + { + id: "brightness", + sourceUrl: "indicators/BrightnessIndicator.qml" + }, + ] + function triggerOsd() { - GlobalStates.osdVolumeOpen = true - osdTimeout.restart() + GlobalStates.osdVolumeOpen = true; + osdTimeout.restart(); } Timer { @@ -26,35 +38,44 @@ Scope { repeat: false running: false onTriggered: { - GlobalStates.osdVolumeOpen = false - root.protectionMessage = "" + GlobalStates.osdVolumeOpen = false; + root.protectionMessage = ""; } } Connections { target: Brightness function onBrightnessChanged() { - GlobalStates.osdVolumeOpen = false + root.protectionMessage = ""; + root.currentIndicator = "brightness"; + root.triggerOsd(); } } - Connections { // Listen to volume changes + Connections { + // Listen to volume changes target: Audio.sink?.audio ?? null function onVolumeChanged() { - if (!Audio.ready) return - root.triggerOsd() + if (!Audio.ready) + return; + root.currentIndicator = "volume"; + root.triggerOsd(); } function onMutedChanged() { - if (!Audio.ready) return - root.triggerOsd() + if (!Audio.ready) + return; + root.currentIndicator = "volume"; + root.triggerOsd(); } } - Connections { // Listen to protection triggers + Connections { + // Listen to protection triggers target: Audio function onSinkProtectionTriggered(reason) { root.protectionMessage = reason; - root.triggerOsd() + root.currentIndicator = "volume"; + root.triggerOsd(); } } @@ -69,7 +90,7 @@ Scope { Connections { target: root function onFocusedScreenChanged() { - osdRoot.screen = root.focusedScreen + osdRoot.screen = root.focusedScreen; } } @@ -97,10 +118,11 @@ Scope { ColumnLayout { id: columnLayout anchors.horizontalCenter: parent.horizontalCenter + Item { id: osdValuesWrapper // Extra space for shadow - implicitHeight: contentColumnLayout.implicitHeight + Appearance.sizes.elevationMargin * 2 + implicitHeight: contentColumnLayout.implicitHeight implicitWidth: contentColumnLayout.implicitWidth clip: true @@ -110,30 +132,25 @@ Scope { onEntered: GlobalStates.osdVolumeOpen = false } - ColumnLayout { + Column { id: contentColumnLayout anchors { top: parent.top left: parent.left right: parent.right - leftMargin: Appearance.sizes.elevationMargin - rightMargin: Appearance.sizes.elevationMargin } spacing: 0 - OsdValueIndicator { - id: osdValues - Layout.fillWidth: true - value: Audio.sink?.audio.volume ?? 0 - icon: Audio.sink?.audio.muted ? "volume_off" : "volume_up" - name: Translation.tr("Volume") + Loader { + id: osdIndicatorLoader + source: root.indicators.find(i => i.id === root.currentIndicator)?.sourceUrl } Item { id: protectionMessageWrapper + anchors.horizontalCenter: parent.horizontalCenter implicitHeight: protectionMessageBackground.implicitHeight implicitWidth: protectionMessageBackground.implicitWidth - Layout.alignment: Qt.AlignHCenter opacity: root.protectionMessage !== "" ? 1 : 0 StyledRectangularShadow { @@ -174,26 +191,26 @@ Scope { } IpcHandler { - target: "osdVolume" + target: "osdVolume" - function trigger() { - root.triggerOsd() + function trigger() { + root.triggerOsd(); } function hide() { - GlobalStates.osdVolumeOpen = false + GlobalStates.osdVolumeOpen = false; } function toggle() { - GlobalStates.osdVolumeOpen = !GlobalStates.osdVolumeOpen + GlobalStates.osdVolumeOpen = !GlobalStates.osdVolumeOpen; } - } + } GlobalShortcut { name: "osdVolumeTrigger" description: "Triggers volume OSD on press" onPressed: { - root.triggerOsd() + root.triggerOsd(); } } GlobalShortcut { @@ -201,8 +218,7 @@ Scope { description: "Hides volume OSD on press" onPressed: { - GlobalStates.osdVolumeOpen = false + GlobalStates.osdVolumeOpen = false; } } - } diff --git a/.config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplayBrightness.qml b/.config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplayBrightness.qml deleted file mode 100644 index 13f78b68c..000000000 --- a/.config/quickshell/ii/modules/onScreenDisplay/OnScreenDisplayBrightness.qml +++ /dev/null @@ -1,157 +0,0 @@ -import qs -import qs.services -import qs.modules.common -import qs.modules.common.widgets -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell -import Quickshell.Io -import Quickshell.Hyprland -import Quickshell.Wayland - -Scope { - id: root - property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) - property var brightnessMonitor: Brightness.getMonitorForScreen(focusedScreen) - - function triggerOsd() { - GlobalStates.osdBrightnessOpen = true - osdTimeout.restart() - } - - Timer { - id: osdTimeout - interval: Config.options.osd.timeout - repeat: false - running: false - onTriggered: { - GlobalStates.osdBrightnessOpen = false - } - } - - Connections { - target: Audio.sink?.audio ?? null - function onVolumeChanged() { - if (!Audio.ready) return - GlobalStates.osdBrightnessOpen = false - } - } - - Connections { - target: Brightness - function onBrightnessChanged() { - if (!root.brightnessMonitor.ready) return - root.triggerOsd() - } - } - - Loader { - id: osdLoader - active: GlobalStates.osdBrightnessOpen - - sourceComponent: PanelWindow { - id: osdRoot - color: "transparent" - - Connections { - target: root - function onFocusedScreenChanged() { - osdRoot.screen = root.focusedScreen - } - } - - WlrLayershell.namespace: "quickshell:onScreenDisplay" - WlrLayershell.layer: WlrLayer.Overlay - anchors { - top: !Config.options.bar.bottom - bottom: Config.options.bar.bottom - } - mask: Region { - item: osdValuesWrapper - } - - exclusionMode: ExclusionMode.Ignore - exclusiveZone: 0 - margins { - top: Appearance.sizes.barHeight - bottom: Appearance.sizes.barHeight - } - - implicitWidth: columnLayout.implicitWidth - implicitHeight: columnLayout.implicitHeight - visible: osdLoader.active - - ColumnLayout { - id: columnLayout - anchors.horizontalCenter: parent.horizontalCenter - Item { - id: osdValuesWrapper - // Extra space for shadow - implicitHeight: osdValues.implicitHeight + Appearance.sizes.elevationMargin * 2 - implicitWidth: osdValues.implicitWidth - clip: true - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: GlobalStates.osdBrightnessOpen = false - } - - Behavior on implicitHeight { - NumberAnimation { - duration: Appearance.animation.menuDecel.duration - easing.type: Appearance.animation.menuDecel.type - } - } - - OsdValueIndicator { - id: osdValues - anchors.fill: parent - anchors.margins: Appearance.sizes.elevationMargin - value: root.brightnessMonitor?.brightness ?? 50 - icon: "light_mode" - rotateIcon: true - scaleIcon: true - name: Translation.tr("Brightness") - } - } - } - - } - } - - IpcHandler { - target: "osdBrightness" - - function trigger() { - root.triggerOsd() - } - - function hide() { - GlobalStates.osdBrightnessOpen = false - } - - function toggle() { - GlobalStates.osdBrightnessOpen = !GlobalStates.osdBrightnessOpen - } - } - - GlobalShortcut { - name: "osdBrightnessTrigger" - description: "Triggers brightness OSD on press" - - onPressed: { - root.triggerOsd() - } - } - GlobalShortcut { - name: "osdBrightnessHide" - description: "Hides brightness OSD on press" - - onPressed: { - GlobalStates.osdBrightnessOpen = false - } - } - -} diff --git a/.config/quickshell/ii/modules/onScreenDisplay/OsdValueIndicator.qml b/.config/quickshell/ii/modules/onScreenDisplay/OsdValueIndicator.qml index 6edd24a49..fc10c8a2a 100644 --- a/.config/quickshell/ii/modules/onScreenDisplay/OsdValueIndicator.qml +++ b/.config/quickshell/ii/modules/onScreenDisplay/OsdValueIndicator.qml @@ -1,13 +1,8 @@ -import qs.services import qs.modules.common import qs.modules.common.widgets import QtQuick -import QtQuick.Controls -import QtQuick.Effects import QtQuick.Layouts -import Quickshell import Quickshell.Widgets -// import Qt5Compat.GraphicalEffects Item { id: root @@ -21,19 +16,23 @@ Item { property real valueIndicatorLeftPadding: 10 property real valueIndicatorRightPadding: 20 // An icon is circle ish, a column isn't, hence the extra padding - Layout.margins: Appearance.sizes.elevationMargin - implicitWidth: Appearance.sizes.osdWidth - implicitHeight: valueIndicator.implicitHeight + implicitWidth: Appearance.sizes.osdWidth + 2 * Appearance.sizes.elevationMargin + implicitHeight: valueIndicator.implicitHeight + 2 * Appearance.sizes.elevationMargin StyledRectangularShadow { target: valueIndicator } - WrapperRectangle { + Rectangle { id: valueIndicator - anchors.fill: parent + anchors { + fill: parent + margins: Appearance.sizes.elevationMargin + } radius: Appearance.rounding.full color: Appearance.colors.colLayer0 + implicitWidth: valueRow.implicitWidth + implicitHeight: valueRow.implicitHeight RowLayout { // Icon on the left, stuff on the right id: valueRow @@ -48,6 +47,7 @@ Item { Layout.leftMargin: valueIndicatorLeftPadding Layout.topMargin: valueIndicatorVerticalPadding Layout.bottomMargin: valueIndicatorVerticalPadding + MaterialSymbol { // Icon anchors { centerIn: parent @@ -101,4 +101,4 @@ Item { } } } -} \ No newline at end of file +} diff --git a/.config/quickshell/ii/modules/onScreenDisplay/indicators/BrightnessIndicator.qml b/.config/quickshell/ii/modules/onScreenDisplay/indicators/BrightnessIndicator.qml new file mode 100644 index 000000000..da4ad575c --- /dev/null +++ b/.config/quickshell/ii/modules/onScreenDisplay/indicators/BrightnessIndicator.qml @@ -0,0 +1,18 @@ +import qs +import qs.services +import QtQuick +import Quickshell +import Quickshell.Hyprland +import "../" + +OsdValueIndicator { + id: root + property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) + property var brightnessMonitor: Brightness.getMonitorForScreen(focusedScreen) + + value: root.brightnessMonitor?.brightness ?? 50 + icon: "light_mode" + rotateIcon: true + scaleIcon: true + name: Translation.tr("Brightness") +} diff --git a/.config/quickshell/ii/modules/onScreenDisplay/indicators/VolumeIndicator.qml b/.config/quickshell/ii/modules/onScreenDisplay/indicators/VolumeIndicator.qml new file mode 100644 index 000000000..675410355 --- /dev/null +++ b/.config/quickshell/ii/modules/onScreenDisplay/indicators/VolumeIndicator.qml @@ -0,0 +1,11 @@ +import qs +import qs.services +import QtQuick +import "../" + +OsdValueIndicator { + id: osdValues + value: Audio.sink?.audio.volume ?? 0 + icon: Audio.sink?.audio.muted ? "volume_off" : "volume_up" + name: Translation.tr("Volume") +} diff --git a/.config/quickshell/ii/shell.qml b/.config/quickshell/ii/shell.qml index 1088669ed..942bb282e 100644 --- a/.config/quickshell/ii/shell.qml +++ b/.config/quickshell/ii/shell.qml @@ -42,8 +42,7 @@ ShellRoot { property bool enableLock: true property bool enableMediaControls: true property bool enableNotificationPopup: true - property bool enableOnScreenDisplayBrightness: true - property bool enableOnScreenDisplayVolume: true + property bool enableOnScreenDisplay: true property bool enableOnScreenKeyboard: true property bool enableOverview: true property bool enableReloadPopup: true @@ -72,8 +71,7 @@ ShellRoot { LazyLoader { active: enableLock; component: Lock {} } LazyLoader { active: enableMediaControls; component: MediaControls {} } LazyLoader { active: enableNotificationPopup; component: NotificationPopup {} } - LazyLoader { active: enableOnScreenDisplayBrightness; component: OnScreenDisplayBrightness {} } - LazyLoader { active: enableOnScreenDisplayVolume; component: OnScreenDisplayVolume {} } + LazyLoader { active: enableOnScreenDisplay; component: OnScreenDisplay {} } LazyLoader { active: enableOnScreenKeyboard; component: OnScreenKeyboard {} } LazyLoader { active: enableOverview; component: Overview {} } LazyLoader { active: enableReloadPopup; component: ReloadPopup {} } From 7876ab993a989686898d552bb9182fdb16c2eef9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 18:05:31 +0200 Subject: [PATCH 24/38] settings: remove unnecessary page check for anim --- .config/quickshell/ii/settings.qml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.config/quickshell/ii/settings.qml b/.config/quickshell/ii/settings.qml index 3f3df0703..64728412c 100644 --- a/.config/quickshell/ii/settings.qml +++ b/.config/quickshell/ii/settings.qml @@ -224,10 +224,8 @@ ApplicationWindow { Connections { target: root function onCurrentPageChanged() { - if (pageLoader.sourceComponent !== root.pages[root.currentPage].component) { - switchAnim.complete(); - switchAnim.start(); - } + switchAnim.complete(); + switchAnim.start(); } } From ccab724db23de40d50f80dd8818a08bd6131ed5e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 18:16:14 +0200 Subject: [PATCH 25/38] screenshot tool: fix interactivity of floating windows being behind tiled --- .config/quickshell/ii/screenshot.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.config/quickshell/ii/screenshot.qml b/.config/quickshell/ii/screenshot.qml index ec52aaa33..5c930f0c6 100644 --- a/.config/quickshell/ii/screenshot.qml +++ b/.config/quickshell/ii/screenshot.qml @@ -35,7 +35,11 @@ ShellRoot { property color imageFillColor: "#33f1d1ff" property color onBorderColor: "#ff000000" property real standardRounding: 4 - readonly property var windows: HyprlandData.windowList + readonly property var windows: [...HyprlandData.windowList].sort((a, b) => { + // Sort floating=true windows before others + if (a.floating === b.floating) return 0; + return a.floating ? -1 : 1; + }) readonly property var layers: HyprlandData.layers readonly property real falsePositivePreventionRatio: 0.5 From 8713e9442827b0438213864955f7eab003e14cef Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 18:44:05 +0200 Subject: [PATCH 26/38] screenshot tool: make dark overlay clipped by selection, add selection size indicator --- .config/quickshell/ii/screenshot.qml | 38 ++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/.config/quickshell/ii/screenshot.qml b/.config/quickshell/ii/screenshot.qml index 5c930f0c6..13e07bb5e 100644 --- a/.config/quickshell/ii/screenshot.qml +++ b/.config/quickshell/ii/screenshot.qml @@ -15,6 +15,7 @@ import qs.modules.common.functions import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Qt5Compat.GraphicalEffects import Quickshell import Quickshell.Io import Quickshell.Widgets @@ -137,7 +138,8 @@ ShellRoot { }) readonly property list layerRegions: { const layersOfThisMonitor = root.layers[panelWindow.hyprlandMonitor.name] - const topLayers = layersOfThisMonitor.levels["2"] + const topLayers = layersOfThisMonitor?.levels["2"] + if (!topLayers) return []; const nonBarTopLayers = topLayers .filter(layer => !(layer.namespace.includes(":bar") || layer.namespace.includes(":verticalBar") || layer.namespace.includes(":dock"))) .map(layer => { @@ -390,14 +392,24 @@ ShellRoot { // Overlay to darken screen Rectangle { // Base - id: overlayRect - z: 0 - anchors.fill: parent - color: root.overlayColor - layer.enabled: true + id: darkenOverlay + z: 1 + anchors { + left: parent.left + top: parent.top + leftMargin: panelWindow.regionX - darkenOverlay.border.width + topMargin: panelWindow.regionY - darkenOverlay.border.width + } + width: panelWindow.regionWidth + darkenOverlay.border.width * 2 + height: panelWindow.regionHeight + darkenOverlay.border.width * 2 + color: "transparent" + // border.color: root.selectionBorderColor + border.color: root.overlayColor + border.width: Math.max(panelWindow.width, panelWindow.height) + radius: root.standardRounding } Rectangle { - // TODO: Make this mask the base instead of just overlaying a border + id: selectionBorder z: 1 anchors { left: parent.left @@ -410,11 +422,21 @@ ShellRoot { color: "transparent" border.color: root.selectionBorderColor border.width: 2 - radius: root.standardRounding + // radius: root.standardRounding + radius: 0 // TODO: figure out how to make the overlay thing work with rounding + } + StyledText { + anchors { + bottom: selectionBorder.bottom + right: selectionBorder.right + margins: 8 + } + text: `${Math.round(panelWindow.regionWidth)} x ${Math.round(panelWindow.regionHeight)}` } // Instructions Rectangle { + z: 9999 anchors { top: parent.top horizontalCenter: parent.horizontalCenter From 0491bd993eeb87b9a46e297ce338b988c794dada Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 20:48:59 +0200 Subject: [PATCH 27/38] overview: floating window position move --- .../quickshell/ii/modules/overview/OverviewWidget.qml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/overview/OverviewWidget.qml b/.config/quickshell/ii/modules/overview/OverviewWidget.qml index 27a095ac6..0487c6025 100644 --- a/.config/quickshell/ii/modules/overview/OverviewWidget.qml +++ b/.config/quickshell/ii/modules/overview/OverviewWidget.qml @@ -218,8 +218,13 @@ Item { updateWindowPosition.restart() } else { - window.x = window.initX - window.y = window.initY + if (!window.windowData.floating) { + updateWindowPosition.restart() + return + } + const percentageX = Math.round((window.x - xOffset) / root.workspaceImplicitWidth * 100) + const percentageY = Math.round((window.y - yOffset) / root.workspaceImplicitHeight * 100) + Hyprland.dispatch(`movewindowpixel exact ${percentageX}% ${percentageY}%, address:${window.windowData?.address}`) } } onClicked: (event) => { From 83be5822b1e8db8bba1fc76cfd9b93eddde60943 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 28 Sep 2025 20:50:21 +0200 Subject: [PATCH 28/38] add random osu seasonal wallpaper button --- .../ii/modules/overview/SearchWidget.qml | 2 +- .../ii/modules/settings/QuickConfig.qml | 51 ++++++++++++------- .../{ => random}/random_konachan_wall.sh | 6 +-- .../scripts/colors/random/random_osu_wall.sh | 44 ++++++++++++++++ .config/quickshell/ii/welcome.qml | 2 +- 5 files changed, 83 insertions(+), 22 deletions(-) rename .config/quickshell/ii/scripts/colors/{ => random}/random_konachan_wall.sh (87%) create mode 100755 .config/quickshell/ii/scripts/colors/random/random_osu_wall.sh diff --git a/.config/quickshell/ii/modules/overview/SearchWidget.qml b/.config/quickshell/ii/modules/overview/SearchWidget.qml index c857c0676..53df4b75b 100644 --- a/.config/quickshell/ii/modules/overview/SearchWidget.qml +++ b/.config/quickshell/ii/modules/overview/SearchWidget.qml @@ -42,7 +42,7 @@ Item { // Wrapper { action: "konachanwallpaper", execute: () => { - Quickshell.execDetached([Quickshell.shellPath("scripts/colors/random_konachan_wall.sh")]); + Quickshell.execDetached([Quickshell.shellPath("scripts/colors/random/random_konachan_wall.sh")]); } }, { diff --git a/.config/quickshell/ii/modules/settings/QuickConfig.qml b/.config/quickshell/ii/modules/settings/QuickConfig.qml index ca8a0f73d..b14cb085a 100644 --- a/.config/quickshell/ii/modules/settings/QuickConfig.qml +++ b/.config/quickshell/ii/modules/settings/QuickConfig.qml @@ -14,12 +14,13 @@ ContentPage { forceWidth: true Process { - id: konachanWallProc + id: randomWallProc property string status: "" - command: ["bash", "-c", FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/random_konachan_wall.sh`)] + property string scriptPath: `${Directories.scriptPath}/colors/random/random_konachan_wall.sh` + command: ["bash", "-c", FileUtils.trimFileProtocol(randomWallProc.scriptPath)] stdout: SplitParser { onRead: data => { - konachanWallProc.status = data.trim(); + randomWallProc.status = data.trim(); } } } @@ -90,19 +91,35 @@ ContentPage { ColumnLayout { RippleButtonWithIcon { - id: rndWallBtn + enabled: !randomWallProc.running visible: Config.options.policies.weeb === 1 Layout.fillWidth: true buttonRadius: Appearance.rounding.small materialIcon: "ifl" - mainText: konachanWallProc.running ? Translation.tr("Be patient...") : Translation.tr("Random: Konachan") + mainText: randomWallProc.running ? Translation.tr("Be patient...") : Translation.tr("Random: Konachan") onClicked: { - konachanWallProc.running = true; + randomWallProc.scriptPath = `${Directories.scriptPath}/colors/random/random_konachan_wall.sh`; + randomWallProc.running = true; } StyledToolTip { text: Translation.tr("Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers") } } + RippleButtonWithIcon { + enabled: !randomWallProc.running + visible: Config.options.policies.weeb === 1 + Layout.fillWidth: true + buttonRadius: Appearance.rounding.small + materialIcon: "ifl" + mainText: randomWallProc.running ? Translation.tr("Be patient...") : Translation.tr("Random: osu! seasonal") + onClicked: { + randomWallProc.scriptPath = `${Directories.scriptPath}/colors/random/random_osu_wall.sh`; + randomWallProc.running = true; + } + StyledToolTip { + text: Translation.tr("Random osu! seasonal background\nImage is saved to ~/Pictures/Wallpapers") + } + } RippleButtonWithIcon { Layout.fillWidth: true materialIcon: "wallpaper" @@ -154,17 +171,6 @@ ContentPage { dark: true } } - - ConfigSwitch { - text: Translation.tr("Transparency") - checked: Config.options.appearance.transparency.enable - onCheckedChanged: { - Config.options.appearance.transparency.enable = checked; - } - StyledToolTip { - text: Translation.tr("Might look ass. Unsupported.") - } - } } } @@ -213,6 +219,17 @@ ContentPage { } ] } + + ConfigSwitch { + text: Translation.tr("Transparency") + checked: Config.options.appearance.transparency.enable + onCheckedChanged: { + Config.options.appearance.transparency.enable = checked; + } + StyledToolTip { + text: Translation.tr("Might look ass. Unsupported.") + } + } } ContentSection { diff --git a/.config/quickshell/ii/scripts/colors/random_konachan_wall.sh b/.config/quickshell/ii/scripts/colors/random/random_konachan_wall.sh similarity index 87% rename from .config/quickshell/ii/scripts/colors/random_konachan_wall.sh rename to .config/quickshell/ii/scripts/colors/random/random_konachan_wall.sh index a4685da95..a1f922121 100755 --- a/.config/quickshell/ii/scripts/colors/random_konachan_wall.sh +++ b/.config/quickshell/ii/scripts/colors/random/random_konachan_wall.sh @@ -32,11 +32,11 @@ page=$((1 + RANDOM % 1000)); response=$(curl "https://konachan.net/post.json?tags=rating%3Asafe&limit=1&page=$page") link=$(echo "$response" | jq '.[0].file_url' -r); ext=$(echo "$link" | awk -F. '{print $NF}') -downloadPath="$PICTURES_DIR/Wallpapers/konachan_random_image.$ext" +downloadPath="$PICTURES_DIR/Wallpapers/random_wallpaper.$ext" illogicalImpulseConfigPath="$HOME/.config/illogical-impulse/config.json" currentWallpaperPath=$(jq -r '.background.wallpaperPath' $illogicalImpulseConfigPath) if [ "$downloadPath" == "$currentWallpaperPath" ]; then - downloadPath="$PICTURES_DIR/Wallpapers/konachan_random_image-1.$ext" + downloadPath="$PICTURES_DIR/Wallpapers/random_wallpaper-1.$ext" fi curl "$link" -o "$downloadPath" -"$SCRIPT_DIR/switchwall.sh" --image "$downloadPath" +"$SCRIPT_DIR/../switchwall.sh" --image "$downloadPath" diff --git a/.config/quickshell/ii/scripts/colors/random/random_osu_wall.sh b/.config/quickshell/ii/scripts/colors/random/random_osu_wall.sh new file mode 100755 index 000000000..54b3af6a0 --- /dev/null +++ b/.config/quickshell/ii/scripts/colors/random/random_osu_wall.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +get_pictures_dir() { + if command -v xdg-user-dir &> /dev/null; then + xdg-user-dir PICTURES + return + fi + + local config_file="${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" + if [ -f "$config_file" ]; then + local pictures_path + pictures_path=$(source "$config_file" >/dev/null 2>&1; echo "$XDG_PICTURES_DIR") + echo "${pictures_path/#\$HOME/$HOME}" + return + fi + + echo "$HOME/Pictures" +} + +QUICKSHELL_CONFIG_NAME="ii" +XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" +XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" +XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}" +PICTURES_DIR=$(get_pictures_dir) +CONFIG_DIR="$XDG_CONFIG_HOME/quickshell/$QUICKSHELL_CONFIG_NAME" +CACHE_DIR="$XDG_CACHE_HOME/quickshell" +STATE_DIR="$XDG_STATE_HOME/quickshell" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +mkdir -p "$PICTURES_DIR/Wallpapers" + +response=$(curl "https://osu.ppy.sh/api/v2/seasonal-backgrounds") +images=$(echo "$response" | jq '.backgrounds | length' -r); +randomIndex=$((RANDOM % images)); +link=$(echo "$response" | jq ".backgrounds[$randomIndex].url" -r) +ext=$(echo "$link" | awk -F. '{print $NF}') +downloadPath="$PICTURES_DIR/Wallpapers/random_wallpaper.$ext" +illogicalImpulseConfigPath="$HOME/.config/illogical-impulse/config.json" +currentWallpaperPath=$(jq -r '.background.wallpaperPath' $illogicalImpulseConfigPath) +if [ "$downloadPath" == "$currentWallpaperPath" ]; then + downloadPath="$PICTURES_DIR/Wallpapers/random_wallpaper-1.$ext" +fi +curl "$link" -o "$downloadPath" +"$SCRIPT_DIR/../switchwall.sh" --image "$downloadPath" diff --git a/.config/quickshell/ii/welcome.qml b/.config/quickshell/ii/welcome.qml index 1f7e0dc22..4acd2c80b 100644 --- a/.config/quickshell/ii/welcome.qml +++ b/.config/quickshell/ii/welcome.qml @@ -44,7 +44,7 @@ ApplicationWindow { Process { id: konachanWallProc property string status: "" - command: ["bash", "-c", Quickshell.shellPath("scripts/colors/random_konachan_wall.sh")] + command: ["bash", "-c", Quickshell.shellPath("scripts/colors/random/random_konachan_wall.sh")] stdout: SplitParser { onRead: data => { console.log(`Konachan wall proc output: ${data}`); From ec3c09607dabf4d41c619cb4b898548f9feadfc4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:20:15 +0200 Subject: [PATCH 29/38] bar: fix misaligned items for horizontal floating mode (#2075) --- .config/quickshell/ii/modules/bar/BarContent.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.config/quickshell/ii/modules/bar/BarContent.qml b/.config/quickshell/ii/modules/bar/BarContent.qml index 677801882..7b0a090dc 100644 --- a/.config/quickshell/ii/modules/bar/BarContent.qml +++ b/.config/quickshell/ii/modules/bar/BarContent.qml @@ -108,6 +108,7 @@ Item { // Bar content region BarGroup { id: leftCenterGroup + anchors.verticalCenter: parent.verticalCenter implicitWidth: root.centerSideModuleWidth Resources { @@ -127,6 +128,7 @@ Item { // Bar content region BarGroup { id: middleCenterGroup + anchors.verticalCenter: parent.verticalCenter padding: workspacesWidget.widgetPadding Workspaces { @@ -152,6 +154,7 @@ Item { // Bar content region MouseArea { id: rightCenterGroup + anchors.verticalCenter: parent.verticalCenter implicitWidth: root.centerSideModuleWidth implicitHeight: rightCenterGroupContent.implicitHeight From 6201798ef57ebf205c9732bd160aeebe555e3e47 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 29 Sep 2025 10:28:54 +0200 Subject: [PATCH 30/38] ai: ctrl+shift+o to clear --- .config/quickshell/ii/modules/sidebarLeft/AiChat.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml b/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml index b746e9482..16d7baee8 100644 --- a/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml +++ b/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml @@ -36,6 +36,9 @@ Item { event.accepted = true } } + if ((event.modifiers & Qt.ControlModifier) && (event.modifiers & Qt.ShiftModifier) && event.key === Qt.Key_O) { + Ai.clearMessages(); + } } property var allCommands: [ From 6e126dc08d4d53d1d37159b17a33dde1f88e5228 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 29 Sep 2025 22:21:09 +0200 Subject: [PATCH 31/38] lock: option to launch on startup (#2076) --- .config/quickshell/ii/GlobalStates.qml | 9 +++++++++ .config/quickshell/ii/modules/common/Config.qml | 1 + .../quickshell/ii/modules/settings/InterfaceConfig.qml | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/.config/quickshell/ii/GlobalStates.qml b/.config/quickshell/ii/GlobalStates.qml index 207b23fe3..c9cd602d6 100644 --- a/.config/quickshell/ii/GlobalStates.qml +++ b/.config/quickshell/ii/GlobalStates.qml @@ -27,6 +27,15 @@ Singleton { property bool superReleaseMightTrigger: true property bool workspaceShowNumbers: false + Connections { + target: Config + function onReadyChanged() { + if (Config.ready && Config.options.lock.launchOnStartup) { + GlobalStates.screenLocked = true; + } + } + } + property real screenZoom: 1 onScreenZoomChanged: { Quickshell.execDetached(["hyprctl", "keyword", "cursor:zoom_factor", root.screenZoom.toString()]); diff --git a/.config/quickshell/ii/modules/common/Config.qml b/.config/quickshell/ii/modules/common/Config.qml index e7b595d44..b59cc31dc 100644 --- a/.config/quickshell/ii/modules/common/Config.qml +++ b/.config/quickshell/ii/modules/common/Config.qml @@ -260,6 +260,7 @@ Singleton { } property JsonObject lock: JsonObject { + property bool launchOnStartup: false property JsonObject blur: JsonObject { property bool enable: false property real radius: 100 diff --git a/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index e79a40779..76bd43b93 100644 --- a/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -167,6 +167,14 @@ ContentPage { icon: "lock" title: Translation.tr("Lock screen") + ConfigSwitch { + text: Translation.tr('Launch on startup') + checked: Config.options.lock.launchOnStartup + onCheckedChanged: { + Config.options.lock.launchOnStartup = checked; + } + } + ContentSubsection { title: Translation.tr("Blurred style") From 4a40ce5646e0c64a02d5de68c841b74b919d4eec Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 29 Sep 2025 22:47:57 +0200 Subject: [PATCH 32/38] idle inhibitor: only remember toggled state within same session --- .../quickshell/ii/modules/common/Persistent.qml | 13 +++++++++++++ .config/quickshell/ii/services/Idle.qml | 16 ++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/common/Persistent.qml b/.config/quickshell/ii/modules/common/Persistent.qml index e7dc68d7d..a705de098 100644 --- a/.config/quickshell/ii/modules/common/Persistent.qml +++ b/.config/quickshell/ii/modules/common/Persistent.qml @@ -11,6 +11,15 @@ Singleton { property string fileName: "states.json" property string filePath: `${root.fileDir}/${root.fileName}` + property bool ready: false + property string previousHyprlandInstanceSignature: "" + property bool isNewHyprlandInstance: previousHyprlandInstanceSignature !== states.hyprlandInstanceSignature + + onReadyChanged: { + root.previousHyprlandInstanceSignature = root.states.hyprlandInstanceSignature + root.states.hyprlandInstanceSignature = Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE") || "" + } + Timer { id: fileReloadTimer interval: 100 @@ -36,6 +45,7 @@ Singleton { watchChanges: true onFileChanged: fileReloadTimer.restart() onAdapterUpdated: fileWriteTimer.restart() + onLoaded: root.ready = true onLoadFailed: error => { console.log("Failed to load persistent states file:", error); if (error == FileViewError.FileNotFound) { @@ -45,6 +55,9 @@ Singleton { adapter: JsonAdapter { id: persistentStatesJsonAdapter + + property string hyprlandInstanceSignature: "" + property JsonObject ai: JsonObject { property string model property real temperature: 0.5 diff --git a/.config/quickshell/ii/services/Idle.qml b/.config/quickshell/ii/services/Idle.qml index d45e4ed0d..db63b5bb0 100644 --- a/.config/quickshell/ii/services/Idle.qml +++ b/.config/quickshell/ii/services/Idle.qml @@ -12,10 +12,22 @@ Singleton { id: root property alias inhibit: idleInhibitor.enabled - inhibit: Persistent.states.idle.inhibit + inhibit: false + + Connections { + target: Persistent + function onReadyChanged() { + if (!Persistent.isNewHyprlandInstance) { + root.inhibit = Persistent.states.idle.inhibit + } else { + Persistent.states.idle.inhibit = root.inhibit + } + } + } function toggleInhibit() { - Persistent.states.idle.inhibit = !Persistent.states.idle.inhibit + root.inhibit = !root.inhibit + Persistent.states.idle.inhibit = root.inhibit } IdleInhibitor { From 1aa0e3fb47b8d4cdb0bdc7cbc585bc2c813a7235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Pi=C5=82syk?= Date: Mon, 29 Sep 2025 23:27:28 +0200 Subject: [PATCH 33/38] fix(brightness): prevent bus number collision for identical monitor models --- .config/quickshell/ii/services/Brightness.qml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/services/Brightness.qml b/.config/quickshell/ii/services/Brightness.qml index 42becc766..d38bfdcf4 100644 --- a/.config/quickshell/ii/services/Brightness.qml +++ b/.config/quickshell/ii/services/Brightness.qml @@ -74,8 +74,14 @@ Singleton { id: monitor required property ShellScreen screen - readonly property bool isDdc: root.ddcMonitors.some(m => m.model === screen.model) - readonly property string busNum: root.ddcMonitors.find(m => m.model === screen.model)?.busNum ?? "" + readonly property bool isDdc: { + const match = root.ddcMonitors.find(m => m.model === screen.model && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum)); + return !!match; + } + readonly property string busNum: { + const match = root.ddcMonitors.find(m => m.model === screen.model && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum)); + return match?.busNum ?? ""; + } property int rawMaxBrightness: 100 property real brightness property bool ready: false From 0b36e2a8333b95f6af9a7375288c80ce30c25b50 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 30 Sep 2025 07:45:10 +0200 Subject: [PATCH 34/38] lock: do not autostart after crash --- .config/quickshell/ii/GlobalStates.qml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.config/quickshell/ii/GlobalStates.qml b/.config/quickshell/ii/GlobalStates.qml index c9cd602d6..077a810bc 100644 --- a/.config/quickshell/ii/GlobalStates.qml +++ b/.config/quickshell/ii/GlobalStates.qml @@ -30,7 +30,15 @@ Singleton { Connections { target: Config function onReadyChanged() { - if (Config.ready && Config.options.lock.launchOnStartup) { + if (Config.options.lock.launchOnStartup && Config.ready && Persistent.ready && Persistent.isNewHyprlandInstance) { + GlobalStates.screenLocked = true; + } + } + } + Connections { + target: Persistent + function onReadyChanged() { + if (Config.options.lock.launchOnStartup && Config.ready && Persistent.ready && Persistent.isNewHyprlandInstance) { GlobalStates.screenLocked = true; } } From 27626ee59aeb561fe56c557968147384f5ce853f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 30 Sep 2025 07:58:54 +0200 Subject: [PATCH 35/38] ai: simplify auto scroll (#2080) --- .config/quickshell/ii/modules/sidebarLeft/AiChat.qml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml b/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml index 16d7baee8..814077787 100644 --- a/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml +++ b/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml @@ -335,14 +335,11 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\) mouseScrollFactor: Config.options.interactions.scrolling.mouseScrollFactor * 1.4 property int lastResponseLength: 0 - property bool shouldAutoScroll: true - - onContentYChanged: shouldAutoScroll = atYEnd onContentHeightChanged: { - if (shouldAutoScroll) positionViewAtEnd(); + if (atYEnd) positionViewAtEnd(); } onCountChanged: { // Auto-scroll when new messages are added - if (shouldAutoScroll) positionViewAtEnd(); + if (atYEnd) positionViewAtEnd(); } add: null // Prevent function calls from being janky From 82fa754497683f5083cc4b7445e48309eebf20ed Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 30 Sep 2025 20:47:10 +0200 Subject: [PATCH 36/38] ai: ctrl+v to attach file note: only convenient with dolphin --- .../quickshell/ii/modules/sidebarLeft/AiChat.qml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml b/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml index 814077787..29411b7ae 100644 --- a/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml +++ b/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml @@ -647,13 +647,24 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\) root.handleInput(inputText) event.accepted = true } - } else if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_V) { // Intercept Ctrl+V to handle image pasting + } else if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_V) { // Intercept Ctrl+V to handle image/file pasting + if (event.modifiers & Qt.ShiftModifier) { // Let Shift+Ctrl+V = plain paste + messageInputField.text += Quickshell.clipboardText + event.accepted = true; + return; + } // Try image paste first const currentClipboardEntry = Cliphist.entries[0] + const cleanCliphistEntry = StringUtils.cleanCliphistEntry(currentClipboardEntry) if (/^\d+\t\[\[.*binary data.*\d+x\d+.*\]\]$/.test(currentClipboardEntry)) { // First entry = currently copied entry = image? decodeImageAndAttachProc.handleEntry(currentClipboardEntry) event.accepted = true; return; + } else if (cleanCliphistEntry.startsWith("file://")) { // First entry = currently copied entry = image? + const fileName = decodeURIComponent(cleanCliphistEntry) + Ai.attachFile(fileName); + event.accepted = true; + return; } event.accepted = false; // No image, let text pasting proceed } else if (event.key === Qt.Key_Escape) { // Esc to detach file From 599055b49f95e0b31f4b9b1f0af767d875d1599a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 30 Sep 2025 20:47:44 +0200 Subject: [PATCH 37/38] search: add /wipeclipboard action --- .../quickshell/ii/modules/overview/SearchWidget.qml | 6 ++++++ .config/quickshell/ii/services/Cliphist.qml | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/.config/quickshell/ii/modules/overview/SearchWidget.qml b/.config/quickshell/ii/modules/overview/SearchWidget.qml index 53df4b75b..e58a300d0 100644 --- a/.config/quickshell/ii/modules/overview/SearchWidget.qml +++ b/.config/quickshell/ii/modules/overview/SearchWidget.qml @@ -81,6 +81,12 @@ Item { // Wrapper GlobalStates.wallpaperSelectorOpen = true; } }, + { + action: "wipeclipboard", + execute: () => { + Cliphist.wipe(); + } + }, ] function focusFirstItem() { diff --git a/.config/quickshell/ii/services/Cliphist.qml b/.config/quickshell/ii/services/Cliphist.qml index 32b2a0203..568526c12 100644 --- a/.config/quickshell/ii/services/Cliphist.qml +++ b/.config/quickshell/ii/services/Cliphist.qml @@ -95,6 +95,18 @@ Singleton { deleteProc.deleteEntry(entry); } + Process { + id: wipeProc + command: [root.cliphistBinary, "wipe"] + onExited: (exitCode, exitStatus) => { + root.refresh(); + } + } + + function wipe() { + wipeProc.running = true; + } + Connections { target: Quickshell function onClipboardTextChanged() { From 3c008057632d86102dc6411971cb5bd3c915343e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 30 Sep 2025 23:07:04 +0200 Subject: [PATCH 38/38] lock: also unlock keyring on unlock --- .../quickshell/ii/modules/common/Config.qml | 1 + .../ii/modules/lock/LockContext.qml | 11 ++++++++ .../quickshell/ii/scripts/keyring/unlock.sh | 25 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100755 .config/quickshell/ii/scripts/keyring/unlock.sh diff --git a/.config/quickshell/ii/modules/common/Config.qml b/.config/quickshell/ii/modules/common/Config.qml index b59cc31dc..00e0afd2a 100644 --- a/.config/quickshell/ii/modules/common/Config.qml +++ b/.config/quickshell/ii/modules/common/Config.qml @@ -268,6 +268,7 @@ Singleton { } property bool centerClock: true property bool showLockedText: true + property bool unlockKeyring: true } property JsonObject media: JsonObject { diff --git a/.config/quickshell/ii/modules/lock/LockContext.qml b/.config/quickshell/ii/modules/lock/LockContext.qml index 976aa9c6a..f48b84057 100644 --- a/.config/quickshell/ii/modules/lock/LockContext.qml +++ b/.config/quickshell/ii/modules/lock/LockContext.qml @@ -1,4 +1,5 @@ import qs +import qs.modules.common import QtQuick import Quickshell import Quickshell.Services.Pam @@ -55,6 +56,7 @@ Scope { onCompleted: result => { if (result == PamResult.Success) { root.unlocked(); + if (Config.options.lock.unlockKeyring) root.unlockKeyring(); } else { root.showFailure = true; GlobalStates.screenUnlockFailed = true; @@ -64,4 +66,13 @@ Scope { root.unlockInProgress = false; } } + + function unlockKeyring() { + Quickshell.execDetached({ + environment: ({ + UNLOCK_PASSWORD: root.currentText + }), + command: ["bash", "-c", Quickshell.shellPath("scripts/keyring/unlock.sh")] + }) + } } diff --git a/.config/quickshell/ii/scripts/keyring/unlock.sh b/.config/quickshell/ii/scripts/keyring/unlock.sh new file mode 100755 index 000000000..b255f8e0f --- /dev/null +++ b/.config/quickshell/ii/scripts/keyring/unlock.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Based on https://unix.stackexchange.com/a/602935 + +# Skip if already unlocked +locked_state=$(busctl --user get-property org.freedesktop.secrets \ + /org/freedesktop/secrets/collection/login \ + org.freedesktop.Secret.Collection Locked) +if [[ "${locked_state}" == "b false" ]]; then + echo 'Keyring is already unlocked.' >&2 + exit 1 +fi + +# Prompt for password if not provided +if [[ -z "${UNLOCK_PASSWORD}" ]]; then + echo -n 'Login password: ' >&2 + read -s UNLOCK_PASSWORD || return +fi + +# Unlock +killall -q -u "$(whoami)" gnome-keyring-daemon +eval $(echo -n "${UNLOCK_PASSWORD}" \ + | gnome-keyring-daemon --daemonize --login \ + | sed -e 's/^/export /') +unset UNLOCK_PASSWORD +echo '' >&2