From 0d13a02e29fab16c90485d0472e99546665addca Mon Sep 17 00:00:00 2001 From: Uyanide Date: Sun, 8 Mar 2026 03:30:05 +0100 Subject: [PATCH] qs: update --- config/niri/.config/niri/config/binds.kdl | 3 +- .../.config/quickshell/Modules/Bar/Bar.qml | 159 ++++++++++++------ .../Modules/Bar/Modules/LyricsBar.qml | 6 - .../Sidebar/Modules/ConnectionCard.qml | 32 +--- .../Modules/Sidebar/Modules/LyricsCard.qml | 4 +- .../quickshell/Services/IPCService.qml | 12 ++ .../quickshell/Services/LyricsService.qml | 65 ++++--- .../quickshell/Services/NotesService.qml | 20 ++- config/scripts/.local/scripts/fzfclip-wrap | 15 +- config/wallpaper/.config/wallreel/config.json | 2 +- memo/lfs.md | 19 +-- 11 files changed, 196 insertions(+), 141 deletions(-) diff --git a/config/niri/.config/niri/config/binds.kdl b/config/niri/.config/niri/config/binds.kdl index 4c7105c..7b3c90e 100644 --- a/config/niri/.config/niri/config/binds.kdl +++ b/config/niri/.config/niri/config/binds.kdl @@ -13,7 +13,8 @@ binds { Mod+C { spawn "code"; } Mod+E { spawn "dolphin" "--new-window"; } Mod+W { spawn-sh "zen || zen-browser"; } - Mod+X { spawn "gnome-text-editor" "--new-window"; } + Mod+X { spawn "qs" "ipc" "call" "notes" "openRecent"; } + Mod+Shift+X { spawn "qs" "ipc" "call" "notes" "createNote"; } Mod+B { spawn-sh "pkill -x -n btop || wezterm -e btop"; } Mod+Shift+T { spawn "wezterm"; } Mod+Shift+Return { spawn "wezterm"; } diff --git a/config/quickshell/.config/quickshell/Modules/Bar/Bar.qml b/config/quickshell/.config/quickshell/Modules/Bar/Bar.qml index 125674e..08fec9e 100644 --- a/config/quickshell/.config/quickshell/Modules/Bar/Bar.qml +++ b/config/quickshell/.config/quickshell/Modules/Bar/Bar.qml @@ -72,18 +72,18 @@ Variants { RowLayout { id: leftLayout - height: parent.height - 10 + height: parent.height - Style.marginXS * 2 anchors { left: parent.left verticalCenter: parent.verticalCenter - leftMargin: 5 + leftMargin: Style.marginXS } UIconButton { textOverride: "󰣇" fontFamily: Fonts.nerd - baseSize: parent.height - Style.marginXXS * 2 + baseSize: parent.height - Style.marginXS * 2 iconSize: Style.fontNerd colorFg: Colors.distro onClicked: () => { @@ -121,7 +121,7 @@ Variants { RowLayout { id: middleLayout - height: parent.height - 10 + height: parent.height - Style.marginXS * 2 anchors { horizontalCenter: parent.horizontalCenter @@ -136,68 +136,127 @@ Variants { RowLayout { id: rightLayout - height: parent.height - 10 + height: parent.height - Style.marginXS * 2 anchors { right: parent.right verticalCenter: parent.verticalCenter - rightMargin: 5 + rightMargin: Style.marginXS } - Loader { - sourceComponent: LyricsService.showLyricsBar ? lyricsComponent : monitorsComponent + Connections { + target: LyricsService + onShowLyricsBarChanged: { + if (LyricsService.showLyricsBar) { + LyricsService.registerComponent("LyricsBar"); + SystemStatService.unregisterComponent("BarMonitors"); + } else { + LyricsService.unregisterComponent("LyricsBar"); + SystemStatService.registerComponent("BarMonitors"); + } + } + } - Component { - id: monitorsComponent + Item { + Layout.fillHeight: true + Layout.fillWidth: true - RowLayout { - id: monitorsLayout + RowLayout { + id: monitorsLayout - height: rightLayout.height - spacing: Style.marginM - Component.onCompleted: { + anchors.right: parent.right + height: parent.height + y: LyricsService.showLyricsBar ? Style.barHeight : 0 + opacity: LyricsService.showLyricsBar ? 0 : 1 + spacing: Style.marginM + Component.onCompleted: { + if (!LyricsService.showLyricsBar) SystemStatService.registerComponent("BarMonitors"); + + } + Component.onDestruction: { + SystemStatService.unregisterComponent("BarMonitors"); + } + + NetworkSpeed { + } + + Separator { + } + + RecordIndicator { + } + + Ip { + } + + CpuTemp { + } + + MemUsage { + } + + CpuUsage { + } + + Battery { + } + + Brightness { + screen: modelData + } + + Volume { + } + + Behavior on y { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic } - NetworkSpeed { - } + } - Separator { - } - - RecordIndicator { - } - - Ip { - } - - CpuTemp { - } - - MemUsage { - } - - CpuUsage { - } - - Battery { - } - - Brightness { - screen: modelData - } - - Volume { + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic } } } - Component { - id: lyricsComponent + LyricsBar { + id: lyricsBar + + anchors.right: parent.right + height: parent.height + y: LyricsService.showLyricsBar ? 0 : -Style.barHeight + opacity: LyricsService.showLyricsBar ? 1 : 0 + Component.onCompleted: { + if (LyricsService.showLyricsBar) + LyricsService.registerComponent("LyricsBar"); + + } + Component.onDestruction: { + LyricsService.unregisterComponent("LyricsBar"); + } + + Behavior on y { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } - LyricsBar { } } @@ -208,18 +267,18 @@ Variants { } RowLayout { - height: rightLayout.height + Layout.fillHeight: true spacing: Style.marginS TrayExpander { screen: modelData - baseSize: rightLayout.height - Style.marginXXS * 2 + baseSize: rightLayout.height - Style.marginXS * 2 } UIconButton { iconName: Caffeine.isInhibited ? "mug-off" : "mug" colorFg: Caffeine.isInhibited ? Colors.mOrange : Colors.mYellow - baseSize: rightLayout.height - Style.marginXXS * 2 + baseSize: rightLayout.height - Style.marginXS * 2 alwaysHover: Caffeine.isInhibited onClicked: () => { Caffeine.manualToggle(); @@ -229,7 +288,7 @@ Variants { UIconButton { iconName: "power" colorFg: Colors.mRed - baseSize: rightLayout.height - Style.marginXXS * 2 + baseSize: rightLayout.height - Style.marginXS * 2 onClicked: () => { BarService.toggleRight(); } diff --git a/config/quickshell/.config/quickshell/Modules/Bar/Modules/LyricsBar.qml b/config/quickshell/.config/quickshell/Modules/Bar/Modules/LyricsBar.qml index 3893de6..66756fe 100644 --- a/config/quickshell/.config/quickshell/Modules/Bar/Modules/LyricsBar.qml +++ b/config/quickshell/.config/quickshell/Modules/Bar/Modules/LyricsBar.qml @@ -10,12 +10,6 @@ Rectangle { color: Colors.mSurface border.color: Colors.mPrimary border.width: Style.borderS - Component.onCompleted: { - LyricsService.startSyncing(); - } - Component.onDestruction: { - LyricsService.stopSyncing(); - } implicitHeight: Style.barHeight - Style.marginXS * 2 implicitWidth: 600 diff --git a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml index 75e7711..730531b 100644 --- a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml +++ b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml @@ -148,14 +148,12 @@ UBox { Layout.fillHeight: true clip: true - Loader { - id: btContentLoader - + BluetoothCard { width: parent.width height: parent.height x: root.currentPanel === "bluetooth" ? 0 : -width opacity: root.currentPanel === "bluetooth" ? 1 : 0 - sourceComponent: bluetoothComponent + anchors.margins: Style.marginS Behavior on x { NumberAnimation { @@ -175,14 +173,12 @@ UBox { } - Loader { - id: wifiContentLoader - + WifiCard { width: parent.width height: parent.height x: root.currentPanel === "wifi" ? 0 : width opacity: root.currentPanel === "wifi" ? 1 : 0 - sourceComponent: wifiComponent + anchors.margins: Style.marginS Behavior on x { NumberAnimation { @@ -202,26 +198,6 @@ UBox { } - Component { - id: bluetoothComponent - - BluetoothCard { - anchors.fill: parent - anchors.margins: Style.marginS - } - - } - - Component { - id: wifiComponent - - WifiCard { - anchors.fill: parent - anchors.margins: Style.marginS - } - - } - } } diff --git a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/LyricsCard.qml b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/LyricsCard.qml index 5e7a11b..ef10500 100644 --- a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/LyricsCard.qml +++ b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/LyricsCard.qml @@ -10,10 +10,10 @@ UBox { id: lyricsBox Component.onCompleted: { - LyricsService.startSyncing(); + LyricsService.registerComponent("LyricsCard"); } Component.onDestruction: { - LyricsService.stopSyncing(); + LyricsService.unregisterComponent("LyricsCard"); } ColumnLayout { diff --git a/config/quickshell/.config/quickshell/Services/IPCService.qml b/config/quickshell/.config/quickshell/Services/IPCService.qml index 4392b22..dbbdc16 100644 --- a/config/quickshell/.config/quickshell/Services/IPCService.qml +++ b/config/quickshell/.config/quickshell/Services/IPCService.qml @@ -129,4 +129,16 @@ Item { target: "brightness" } + IpcHandler { + function openRecent() { + NotesService.openRecent(); + } + + function createNote() { + NotesService.createNote(); + } + + target: "notes" + } + } diff --git a/config/quickshell/.config/quickshell/Services/LyricsService.qml b/config/quickshell/.config/quickshell/Services/LyricsService.qml index 542c06d..fecf325 100644 --- a/config/quickshell/.config/quickshell/Services/LyricsService.qml +++ b/config/quickshell/.config/quickshell/Services/LyricsService.qml @@ -15,7 +15,10 @@ Singleton { readonly property string offsetFile: Paths.cacheDir + "/spotify-lyrics-offset.txt" property int offset: 0 // in ms readonly property int offsetStep: 500 // in ms - property int referenceCount: 0 + property var _registered: ({ + }) + readonly property int _registeredCount: Object.keys(_registered).length + readonly property bool shouldRun: _registeredCount > 0 // with linesCount=3 and linesAhead=1, lyrics will be like: // line 1 // line 2 <- current line @@ -30,29 +33,35 @@ Singleton { } function startSyncing() { - referenceCount++; - Logger.d("LyricsService", "Reference count:", referenceCount); - if (referenceCount === 1) { - Logger.d("LyricsService", "Starting lyrics syncing"); - // fill lyrics with empty lines - lyrics = Array(linesCount).fill(" "); - listenProcess.exec(["sh", "-c", `pkill -x spotify-lyrics -u $USER; spotify-lyrics listen -l ${linesCount} -a ${linesAhead} -f ${offsetFile}`]); - } + Logger.d("Lyrics", "Starting lyrics syncing"); + // fill lyrics with empty lines + lyrics = Array(linesCount).fill(" "); + listenProcess.exec(["sh", "-c", `pkill -x spotify-lyrics -u $USER; spotify-lyrics listen -l ${linesCount} -a ${linesAhead} -f ${offsetFile}`]); } function stopSyncing() { - referenceCount--; - Logger.d("LyricsService", "Reference count:", referenceCount); - if (referenceCount <= 0) { - Logger.d("LyricsService", "Stopping lyrics syncing"); - // kinda ugly but works, meanwhile: - // listenProcess.signal(9) - // listenProcess.signal(15) - // listenProcess.running = false - // counting on exec() to terminate previous exec() - // all don't work - listenProcess.exec(["sh", "-c", `pkill -x spotify-lyrics -u $USER`]); - } + Logger.d("Lyrics", "Stopping lyrics syncing"); + // kinda ugly but works, meanwhile: + // listenProcess.signal(9) + // listenProcess.signal(15) + // listenProcess.running = false + // counting on exec() to terminate previous exec() + // all don't work + Quickshell.execDetached(["sh", "-c", `pkill -x spotify-lyrics -u $USER`]); + } + + function registerComponent(componentId) { + root._registered[componentId] = true; + root._registered = Object.assign({ + }, root._registered); + Logger.d("Lyrics", "Component registered:", componentId, "- total:", root._registeredCount); + } + + function unregisterComponent(componentId) { + delete root._registered[componentId]; + root._registered = Object.assign({ + }, root._registered); + Logger.d("Lyrics", "Component unregistered:", componentId, "- total:", root._registeredCount); } function writeOffset() { @@ -90,6 +99,12 @@ Singleton { writeOffset(); } + onShouldRunChanged: { + if (shouldRun) + startSyncing(); + else + stopSyncing(); + } Process { id: listenProcess @@ -129,7 +144,7 @@ Singleton { const val = parseInt(fileContents); if (!isNaN(val)) { offset = val; - Logger.d("LyricsService", "Loaded offset:", offset); + Logger.d("Lyrics", "Loaded offset:", offset); } else { offset = 0; writeOffset(); @@ -139,14 +154,14 @@ Singleton { writeOffset(); } } catch (e) { - Logger.e("LyricsService", "Error reading offset file:", e); + Logger.e("Lyrics", "Error reading offset file:", e); } } onLoadFailed: { - Logger.e("LyricsService", "Error loading offset file."); + Logger.e("Lyrics", "Error loading offset file."); } onSaveFailed: { - Logger.e("LyricsService", "Error saving offset file."); + Logger.e("Lyrics", "Error saving offset file."); } } diff --git a/config/quickshell/.config/quickshell/Services/NotesService.qml b/config/quickshell/.config/quickshell/Services/NotesService.qml index decb40a..f2e7245 100644 --- a/config/quickshell/.config/quickshell/Services/NotesService.qml +++ b/config/quickshell/.config/quickshell/Services/NotesService.qml @@ -9,6 +9,7 @@ Singleton { id: root property ListModel notesModel + property string recentNotePath: "" function createNote() { if (createProcess.running) { @@ -36,9 +37,17 @@ Singleton { } function openNote(path) { + recentNotePath = path; Quickshell.execDetached(["wezterm", "start", "--", "sh", "-c", `exec nvim "${path}"`]); } + function openRecent() { + if (recentNotePath) + openNote(recentNotePath); + else + createNote(); + } + function strToColor(str) { let hash = 5381; for (let i = 0; i < str.length; i++) { @@ -86,6 +95,12 @@ Singleton { break; } } + if (recentNotePath === currentPath) + if (notesModel.count > 0) + recentNotePath = notesModel.get(0).notePath; + else + recentNotePath = "";; + currentPath = ""; } } @@ -94,7 +109,7 @@ Singleton { id: initProcess running: true - command: ["sh", "-c", "ls -p -tr " + Paths.notesDir] + command: ["sh", "-c", "ls -p -t " + Paths.notesDir] stdout: StdioCollector { id: listCollector @@ -113,6 +128,9 @@ Singleton { }); Logger.d("Notes", "Loaded note: " + fileName); } + if (notesModel.count > 0) + recentNotePath = notesModel.get(0).notePath; + } } diff --git a/config/scripts/.local/scripts/fzfclip-wrap b/config/scripts/.local/scripts/fzfclip-wrap index 8ddf77f..47f1823 100755 --- a/config/scripts/.local/scripts/fzfclip-wrap +++ b/config/scripts/.local/scripts/fzfclip-wrap @@ -1,14 +1,3 @@ -#!/usr/bin/env bash +#!/bin/sh -# Description: -# Wrapper for fzfclip to ensure only one instance is -# running and to launch it in terminal. - -exec {LOCK_FD}>/tmp/"$(basename "$0")".lock - -flock -n "$LOCK_FD" || { - echo "Another instance is running. Exiting." >&2 - exit 1 -} - -wezterm start -- fzfclip "$@" {LOCK_FD}>&- +wezterm start -- fzfclip "$@" diff --git a/config/wallpaper/.config/wallreel/config.json b/config/wallpaper/.config/wallreel/config.json index b8d160d..f122301 100644 --- a/config/wallpaper/.config/wallreel/config.json +++ b/config/wallpaper/.config/wallreel/config.json @@ -17,7 +17,7 @@ }, "action": { "onSelected": "qs ipc call background setWallpaper '{{ path }}'; change-colortheme -c '{{ colorHex }}'", - "onPreview": "qs ipc call background previewWallpaper '{{ path }}'; change-colortheme -c '{{ colorHex }}' quickshell niri", + "onPreview": "qs ipc call background previewWallpaper '{{ path }}'; touch '{{ path }}'; change-colortheme -c '{{ colorHex }}' quickshell niri", "quitOnSelected": true, "saveState": [ { diff --git a/memo/lfs.md b/memo/lfs.md index 5c90f3d..62c4407 100644 --- a/memo/lfs.md +++ b/memo/lfs.md @@ -145,20 +145,7 @@ - [7.4. Entering the Chroot Environment](https://www.linuxfromscratch.org/lfs/view/stable/chapter07/chroot.html) - 如果想要使用 `arch-install-scripts` 提供的 `arch-chroot` 脚本偷懒,则必须确保环境变量的清洗与重新设置,至少应确保 `PATH`, `MAKEFLAGS` 和 `TESTSUITEFLAGS` 被正确设置: - - ```bash - arch-chroot "$LFS" /usr/bin/env -i \ - HOME=/root \ - TERM="$TERM" \ - PS1='(lfs chroot) \u:\w\$ ' \ - PATH=/usr/local/bin:/usr/bin:/usr/sbin \ - MAKEFLAGS="-j$(nproc)" \ - TESTSUITEFLAGS="-j$(nproc)" \ - /bin/bash --login - ``` - - 或者完全按照 LFS 书中的 chroot 步骤编写一个小脚本: + 完全按照 LFS 书中的 chroot 步骤编写一个小脚本: ```bash #!/bin/bash @@ -206,6 +193,10 @@ 它的作用是自动挂载一系列虚拟文件系统,同时在退出 chroot 时自动清理。 +> [!IMPORTANT] +> +> 不建议使用 `arch-install-scripts` 提供的 `arch-chroot` 脚本偷懒, 即使用的话也需要做一些修改, 如对 `/dev` 不同的处理方式与默认缺失的环境变量. + - [8.64. GRUB-2.12](https://www.linuxfromscratch.org/lfs/view/stable/chapter08/grub.html) 对于 UEFI 引导的系统,此时需要跳转 BLFS 安装 GRUB。为避免过早地陷入依赖地狱,建议仅按照顺序安装以下包: