feat: add KDE Plasma customization scripts and docs

This commit is contained in:
droid
2026-03-23 16:40:14 +08:00
commit f0ced79af7
10 changed files with 4924 additions and 0 deletions

173
README.md Normal file
View File

@@ -0,0 +1,173 @@
# manjaro_kde_custom
我当前这台 Manjaro + KDE Plasma 6 机器的美化配置归档。
## 内容
- `scripts/recalc-plasma-bottom-docks.sh`
- 自动按当前显示器数量/尺寸重算底部 dock
- 确保每块启用中的屏幕都有一个底部 dock
- dock 统一保持:底部、居中、浮动、自动隐藏、长度随内容变化 (`fit`)
- `systemd/plasma-dock-autofit.service`
- 登录后执行一次自动重算
- `systemd/plasma-dock-autofit.path`
- 监听 `~/.config/kwinoutputconfig.json`,显示器布局变化时自动重算
- `presets/LogicDock/settings.json`
- 当前实际使用中的 Panel Colorizer 自定义预设
- 基于内置 Dock 预设修改而来,当前特点:
- 更圆的圆角
- 更大的 padding / spacing
- 更明显的阴影
- 更适合多屏下的底部自动隐藏 dock
- `docs/dock-launchers.txt`
- 当前主 dock 固定的启动器列表
- `install.sh`
- 一键安装脚本
- `uninstall.sh`
- 卸载自动重算脚本与 systemd 用户服务
## 这套美化当前依赖
- KDE Plasma 6
- [Panel Colorizer](https://github.com/luisbocanegra/plasma-panel-colorizer)
- 当前全局主题:`com.github.vinceliuice.Layan`
- 可选:`kvantum` / `kvantum-qt5`
> 当前机器使用的是 Layan 全局主题dock 的圆角和悬浮视觉主要由 Panel Colorizer 提供。
## 安装
### 1. 安装依赖
Manjaro / Arch:
```bash
sudo pacman -S spectacle python python-dbus python-gobject kvantum kvantum-qt5 papirus-icon-theme
```
Panel Colorizer
```bash
yay -S plasma6-applets-panel-colorizer
```
Layan 主题请通过 KDE Store 安装,或者使用你自己的 Plasma 6 主题。
### 2. 安装本仓库配置
在仓库根目录执行:
```bash
./install.sh
```
它会做这些事:
- 安装自动重算脚本到 `~/.local/bin/`
- 安装用户级 systemd 服务到 `~/.config/systemd/user/`
- 安装 `LogicDock` 预设到 `~/.config/panel-colorizer/presets/LogicDock`
- 启用并立即运行自动重算服务
### 3. 生效逻辑
- 登录后自动执行一次
- 当 KDE 显示器布局配置发生变化时自动执行
- 会自动为每块启用中的屏幕创建/修正底部 dock
## 当前 dock 行为
- 底部
- 居中
- 浮动
- 自动隐藏
- 长度按内容动态扩展,不固定留大空白
- 每块屏幕都各自有 dock
- 显示器变化后自动重算
## Panel Colorizer 预设说明
当前使用的是 `LogicDock` 预设,而不是单纯的内置 `Dock`
- 更大的圆角:更接近 mac 风格
- 更大的左右内边距:图标不会太挤
- 更大的 widget spacingdock 视觉更舒展
- 阴影稍加强:悬浮感更明显
如果你想手动应用这个预设:
1. 确保 bottom dock 里已经有 `Panel Colorizer`
2. 右键 `Panel Colorizer` → 配置
3. Presets → 选择 `LogicDock`
## Kvantum 说明
Kvantum 是 Qt 应用控件主题引擎,主要影响:
- 按钮
- 输入框
- 菜单
- 滚动条
它**不负责** Plasma 面板布局本身。
a. 安装:
```bash
sudo pacman -S kvantum kvantum-qt5
```
b. 打开:
```bash
kvantummanager
```
c. 在 KDE 中启用:
- 系统设置 → 应用程序样式 → Qt 程序样式 → 选择 `Kvantum`
## 恢复 / 卸载
```bash
./uninstall.sh
```
如果只想临时停用:
```bash
systemctl --user disable --now plasma-dock-autofit.path plasma-dock-autofit.service
```
## 额外推荐的小组件
### 官方最稳
- `System Monitor Memory`
- `System Monitor Net`
官方页:
- https://apps.kde.org/plasma-systemmonitor/
### 看上传/下载速度
- `Network Bandwidth Monitor - Qt6`
- KDE Store: https://store.kde.org/p/2280811
### 轻量看 RAM / 温度
- `KVitals`
- KDE Discuss: https://discuss.kde.org/t/kvitals-a-lightweight-plasma-6-panel-widget-for-system-vitals/44363
## 备注
这个仓库归档的是**我当前机器上实际跑通的一套配置**。
如果后面 Plasma / Panel Colorizer 升级后行为变化,建议:
1. 先执行 `./install.sh` 重新覆盖脚本和服务
2. 注销并重新登录一次
3. 再手动执行一次:
```bash
~/.local/bin/recalc-plasma-bottom-docks.sh
```

1
docs/dock-launchers.txt Normal file
View File

@@ -0,0 +1 @@
applications:systemsettings.desktop,preferred://filemanager,preferred://browser

1
docs/look-and-feel.txt Normal file
View File

@@ -0,0 +1 @@
LookAndFeelPackage=com.github.vinceliuice.Layan

19
docs/packages.txt Normal file
View File

@@ -0,0 +1,19 @@
# Required / recommended packages
# Install according to your preference.
# Required for the dock setup
spectacle
python
python-dbus
python-gobject
plasma6-applets-panel-colorizer
# Theme / style used on this machine
Layan KDE Global Theme (KDE Store)
# Optional Qt style engine
kvantum
kvantum-qt5
# Recommended icon themes
papirus-icon-theme

14
install.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
mkdir -p "$HOME/.local/bin" "$HOME/.config/systemd/user" "$HOME/.config/panel-colorizer/presets"
install -m 755 "$REPO_DIR/scripts/recalc-plasma-bottom-docks.sh" "$HOME/.local/bin/recalc-plasma-bottom-docks.sh"
install -m 644 "$REPO_DIR/systemd/plasma-dock-autofit.service" "$HOME/.config/systemd/user/plasma-dock-autofit.service"
install -m 644 "$REPO_DIR/systemd/plasma-dock-autofit.path" "$HOME/.config/systemd/user/plasma-dock-autofit.path"
rm -rf "$HOME/.config/panel-colorizer/presets/LogicDock"
cp -a "$REPO_DIR/presets/LogicDock" "$HOME/.config/panel-colorizer/presets/LogicDock"
systemctl --user daemon-reload
systemctl --user enable --now plasma-dock-autofit.service plasma-dock-autofit.path
"$HOME/.local/bin/recalc-plasma-bottom-docks.sh"
echo 'Installed. If Panel Colorizer was just updated, log out and back in once.'

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
#!/usr/bin/env bash
set -euo pipefail
CONFIG_FILE="$HOME/.config/plasma-org.kde.plasma.desktop-appletsrc"
CUSTOM_PRESET_DIR="$HOME/.config/panel-colorizer/presets/LogicDock"
USER_BUILTIN_PRESET_DIR="$HOME/.local/share/plasma/plasmoids/luisbocanegra.panel.colorizer/contents/ui/presets/Dock"
SYSTEM_BUILTIN_PRESET_DIR="/usr/share/plasma/plasmoids/luisbocanegra.panel.colorizer/contents/ui/presets/Dock"
PRESET_DIR="$CUSTOM_PRESET_DIR"
[[ -d "$PRESET_DIR" ]] || PRESET_DIR="$USER_BUILTIN_PRESET_DIR"
[[ -d "$PRESET_DIR" ]] || PRESET_DIR="$SYSTEM_BUILTIN_PRESET_DIR"
wait_for_plasma() {
for _ in $(seq 1 30); do
if qdbus6 org.kde.plasmashell /PlasmaShell org.freedesktop.DBus.Introspectable.Introspect >/dev/null 2>&1; then
return 0
fi
sleep 1
done
return 1
}
get_screen_count() {
python - <<'PY'
import re, subprocess
text = subprocess.check_output(["kscreen-doctor", "-o"], text=True, errors="ignore")
text = re.sub(r'\x1b\[[0-9;]*[A-Za-z]', '', text)
blocks = re.split(r'(?=Output: )', text)
count = 0
for block in blocks:
if not block.startswith('Output: '):
continue
if re.search(r'^\s*enabled\s*$', block, re.M):
count += 1
print(max(count, 1))
PY
}
get_bottom_colorizers() {
python - <<'PY'
import configparser, json, os, pathlib, re
cfg = pathlib.Path(os.path.expanduser('~/.config/plasma-org.kde.plasma.desktop-appletsrc'))
cp = configparser.RawConfigParser(interpolation=None)
cp.optionxform = str
cp.read(cfg)
items = []
for sec in cp.sections():
m = re.fullmatch(r'Containments\]\[(\d+)', sec)
if not m:
continue
cid = int(m.group(1))
if cp.get(sec, 'plugin', fallback='') != 'org.kde.panel':
continue
if cp.get(sec, 'location', fallback='') not in ('4', 'bottom'):
continue
for asec in cp.sections():
am = re.fullmatch(rf'Containments\]\[{cid}\]\[Applets\]\[(\d+)', asec)
if not am:
continue
if cp.get(asec, 'plugin', fallback='') != 'luisbocanegra.panel.colorizer':
continue
aid = int(am.group(1))
items.append({'containment': cid, 'applet': aid})
print(json.dumps(sorted(items, key=lambda x: (x['containment'], x['applet']))))
PY
}
ensure_bottom_panels() {
local screen_count="$1"
local targets
targets=$(python - <<PY
n = int(${screen_count})
print(','.join(str(i) for i in range(n)))
PY
)
qdbus6 org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "
function bottomPanelOnScreen(screenId) {
for (var i = 0; i < panelIds.length; ++i) {
var p = panelById(panelIds[i]);
if (p.location == 'bottom' && p.screen == screenId) return p;
}
return null;
}
function clamp(v, lo, hi) {
return Math.max(lo, Math.min(hi, v));
}
var targetScreens = [${targets}];
for (var i = 0; i < targetScreens.length; ++i) {
var sid = targetScreens[i];
var panel = bottomPanelOnScreen(sid);
if (!panel) {
panel = new Panel;
panel.screen = sid;
panel.location = 'bottom';
panel.addWidget('org.kde.plasma.icontasks');
panel.addWidget('luisbocanegra.panel.colorizer');
}
var g = screenGeometry(sid);
var h = Math.round(clamp(g.height * 0.048, 70, 76));
panel.thickness = h;
panel.height = h;
panel.lengthMode = 'fit';
panel.alignment = 'center';
panel.floating = true;
panel.hiding = 'autohide';
panel.opacity = 'adaptive';
}
"
}
apply_colorizer_preset() {
local json
json="$(get_bottom_colorizers)"
[[ -z "$json" || "$json" == "[]" ]] && return 0
python - <<'PY' "$json" "$PRESET_DIR" "$CONFIG_FILE"
import json, subprocess, sys, time
pairs = json.loads(sys.argv[1])
preset_dir = sys.argv[2]
config_file = sys.argv[3]
for item in pairs:
cid = item['containment']
aid = item['applet']
service = f'luisbocanegra.panel.colorizer.c{cid}.w{aid}'
for _ in range(12):
try:
subprocess.check_call(['qdbus6', service, '/preset', 'preset', preset_dir], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
break
except subprocess.CalledProcessError:
time.sleep(0.5)
subprocess.call([
'kwriteconfig6', '--file', config_file,
'--group', 'Containments', '--group', str(cid),
'--group', 'Applets', '--group', str(aid),
'--group', 'Configuration', '--group', 'General',
'--key', 'hideWidget', 'true'
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
PY
}
main() {
wait_for_plasma || exit 0
local screen_count
screen_count="$(get_screen_count)"
ensure_bottom_panels "$screen_count"
apply_colorizer_preset
}
main "$@"

View File

@@ -0,0 +1,10 @@
[Unit]
Description=Watch for KDE display layout changes and recalculate Plasma docks
[Path]
PathChanged=%h/.config/kwinoutputconfig.json
PathModified=%h/.config/kwinoutputconfig.json
Unit=plasma-dock-autofit.service
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,10 @@
[Unit]
Description=Recalculate Plasma bottom docks for current screens
After=plasma-plasmashell.service
[Service]
Type=oneshot
ExecStart=%h/.local/bin/recalc-plasma-bottom-docks.sh
[Install]
WantedBy=default.target

8
uninstall.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
systemctl --user disable --now plasma-dock-autofit.path plasma-dock-autofit.service || true
rm -f "$HOME/.config/systemd/user/plasma-dock-autofit.path" "$HOME/.config/systemd/user/plasma-dock-autofit.service"
rm -f "$HOME/.local/bin/recalc-plasma-bottom-docks.sh"
rm -rf "$HOME/.config/panel-colorizer/presets/LogicDock"
systemctl --user daemon-reload
echo 'Removed auto-fit service, script and custom preset.'