Initial Ubuntu 24.04 Niri installer

This commit is contained in:
wuyang
2026-07-27 13:39:29 +08:00
commit 1b0af7b3ff
12 changed files with 900 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
.cache/
.build/
*.log
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 wuyang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+105
View File
@@ -0,0 +1,105 @@
# Niri Beyond Glass
面向 **Ubuntu 24.04 LTS** 的可移植 Niri 桌面配置。一条命令安装 Niri
26.04、Xwayland 支持和一套克制的半透明桌面组件,同时保留原有 GNOME 与
GDM,可在登录界面随时切换会话。
## 效果与范围
- Niri 滚动平铺、窗口圆角、阴影、流畅动画
- 支持 Niri 26.04 的背景模糊、`xray` 和轻微噪点效果
- Waybar 顶栏,时间位于最右侧区域,图标风格统一
- Fuzzel 启动器、Mako 通知、Swaylock 锁屏和自动息屏
- 中文快捷键说明
- 浏览器、视频播放器、Steam 保持完全不透明
- 自动备份已有配置,可卸载恢复
本项目**不包含**动态壁纸、DMS、登录界面或 GRUB 主题,也不重新分发
Wallpaper Engine 创意工坊图片。默认使用 Ubuntu 自带静态壁纸;安装时可指定
自己的图片。
## 一键安装
```bash
curl -fsSL https://git.k1412.top/wuyang/niri-beyond-glass/raw/branch/main/install.sh | bash
```
首次安装需要编译 Niri,耗时取决于 CPU 和网络。脚本会调用 `sudo` 安装依赖,
但必须以普通用户运行。完成后注销,在 GDM 左下角的会话菜单选择 **Niri**
使用自己的静态壁纸:
```bash
curl -fsSL https://git.k1412.top/wuyang/niri-beyond-glass/raw/branch/main/install.sh \
-o /tmp/install-niri.sh
bash /tmp/install-niri.sh --wallpaper "$HOME/Pictures/wallpaper.jpg"
```
只更新配置,不编译和安装软件:
```bash
bash /tmp/install-niri.sh --config-only
```
## 常用快捷键
| 快捷键 | 功能 |
|---|---|
| `Super + Enter` | 终端 |
| `Super + D` | 应用启动器 |
| `Super + B` | 默认浏览器 |
| `Super + E` | 文件管理器 |
| `Super + O` | 总览 |
| `Super + Q` | 关闭窗口 |
| `Super + V` | 切换浮动 |
| `Super + L` | 锁屏 |
| `Super + Shift + /` | 中文快捷键总览 |
| `Super + PageUp/PageDown` | 切换工作区 |
| `Super + Shift + E` | 退出 Niri |
`Super` 就是键盘上的 Windows 徽标键或 Mac 键盘上的 Command 键。
## 安全设计
- 仅支持 Ubuntu 24.04,检测到其他版本会停止
- 不替换显示管理器,不修改 GDM,不移除 GNOME
- 安装前备份 `niri``waybar``fuzzel``mako``swaylock`
- Niri 和 Xwayland Satellite 固定到明确版本
- Rust 工具链隔离在 `~/.local/share/niri-beyond-glass`
- 配置安装后使用 `niri validate` 校验
备份位于:
```text
~/.local/state/niri-beyond-glass/backups/
```
## 卸载
```bash
curl -fsSL https://git.k1412.top/wuyang/niri-beyond-glass/raw/branch/main/uninstall.sh | bash
```
卸载器恢复最近一次配置备份,并保留已安装的系统软件和 Niri 二进制,避免破坏
其他会话。若要删除系统依赖,请按实际用途手动处理,不建议执行盲目的
`apt autoremove`
## 已知限制
- Niri 26.04 比 Ubuntu 24.04 更新,因此脚本采用源码编译,而不是跨版本安装
PPA 二进制包。
- Ubuntu 24.04 自带的 `libdisplay-info` 版本不足时,脚本会在
`/usr/local` 编译安装 0.3.0。
- 这是一套 Niri 配置,不复刻 DMS 的控制中心、登录页和动态壁纸。
- NVIDIA 用户应先确保 Ubuntu 官方驱动在 GNOME Wayland 下工作正常。
## 上游项目
- [Niri](https://github.com/niri-wm/niri)
- [Xwayland Satellite](https://github.com/Supreeeme/xwayland-satellite)
- [Waybar](https://github.com/Alexays/Waybar)
- [Fuzzel](https://codeberg.org/dnkl/fuzzel)
## License
[MIT](LICENSE)。Niri、Xwayland Satellite 及各依赖遵循其各自许可证。
+29
View File
@@ -0,0 +1,29 @@
[main]
font=Noto Sans CJK SC:size=13
terminal=alacritty
prompt="搜索 "
icon-theme=Yaru
icons-enabled=yes
width=46
lines=10
horizontal-pad=20
vertical-pad=14
inner-pad=8
image-size-ratio=0.45
layer=overlay
[colors]
background=181a1de8
text=f0eee8ff
match=d4c5a5ff
selection=3b3e44ff
selection-text=ffffffff
selection-match=e7d8b8ff
border=ffffff20
[border]
width=1
radius=10
[dmenu]
exit-immediately-if-empty=yes
+16
View File
@@ -0,0 +1,16 @@
font=Noto Sans CJK SC 12
background-color=#181a1de8
text-color=#f0eee8
border-color=#ffffff20
progress-color=over #d4c5a5
border-size=1
border-radius=8
padding=14
margin=12
width=360
height=120
max-visible=5
default-timeout=5000
icons=1
layer=overlay
anchor=top-right
+223
View File
@@ -0,0 +1,223 @@
// Niri Beyond Glass
// Portable profile for Ubuntu 24.04 and Niri 26.04.
input {
keyboard {
numlock
}
touchpad {
tap
natural-scroll
dwt
}
mouse {
accel-profile "flat"
}
}
environment {
"XDG_CURRENT_DESKTOP" "niri"
"XDG_SESSION_DESKTOP" "niri"
"QT_QPA_PLATFORM" "wayland;xcb"
"NIXOS_OZONE_WL" "1"
"_JAVA_AWT_WM_NONREPARENTING" "1"
}
spawn-at-startup "xwayland-satellite"
spawn-at-startup "sh" "-lc" "$HOME/.local/bin/niri-beyond-wallpaper"
spawn-at-startup "waybar"
spawn-at-startup "mako"
spawn-at-startup "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1"
spawn-at-startup "swayidle" "-w" "timeout" "600" "swaylock -f" "timeout" "660" "niri msg action power-off-monitors" "resume" "niri msg action power-on-monitors" "before-sleep" "swaylock -f"
hotkey-overlay {
skip-at-startup
}
prefer-no-csd
screenshot-path "~/Pictures/Screenshots/niri-%Y-%m-%d-%H-%M-%S.png"
cursor {
xcursor-theme "Yaru"
xcursor-size 24
}
layer-rule {
match namespace="swaybg"
place-within-backdrop true
}
layer-rule {
match namespace="waybar"
geometry-corner-radius 10
background-effect {
blur true
xray true
noise 0.018
saturation 0.94
}
}
animations {
slowdown 0.85
}
layout {
gaps 8
center-focused-column "never"
background-color "#15171a"
preset-column-widths {
proportion 0.33333
proportion 0.5
proportion 0.66667
}
default-column-width {
proportion 0.5
}
focus-ring {
width 2
active-color "#d4c5a5"
inactive-color "#4d5056"
urgent-color "#dc7a78"
}
border {
off
}
shadow {
on
softness 30
spread -5
offset x=0 y=8
color "#00000070"
}
tab-indicator {
active-color "#d4c5a5"
inactive-color "#4d5056"
urgent-color "#dc7a78"
}
insert-hint {
color "#d4c5a580"
}
}
window-rule {
match app-id=".*"
geometry-corner-radius 12
clip-to-geometry true
tiled-state true
draw-border-with-background false
}
window-rule {
match app-id=r#"(?i)^alacritty$"#
opacity 0.88
default-column-width {
proportion 0.5
}
background-effect {
blur true
xray true
noise 0.025
saturation 0.95
}
}
window-rule {
match app-id=r#"(?i)^(firefox|org\.mozilla\.firefox|google-chrome|chromium|brave-browser|zen-browser)$"#
opacity 1.0
default-column-width {
proportion 0.62
}
}
window-rule {
match app-id=r#"(?i)^(mpv|vlc|io\.github\.celluloid_player\.Celluloid|org\.gnome\.Totem|steam)$"#
opacity 1.0
default-column-width {
proportion 0.70
}
}
window-rule {
match app-id=r#"^org\.gnome\.(Calculator|Settings|Loupe)$"#
open-floating true
default-column-width {
proportion 0.36
}
}
binds {
Mod+Return hotkey-overlay-title="打开终端" { spawn "alacritty"; }
Mod+D hotkey-overlay-title="应用启动器" { spawn "fuzzel"; }
Mod+B hotkey-overlay-title="打开默认浏览器" { spawn "sh" "-lc" "xdg-open https://www.google.com"; }
Mod+E hotkey-overlay-title="文件管理器" { spawn "nautilus"; }
Mod+L hotkey-overlay-title="锁定屏幕" { spawn "swaylock" "-f"; }
Mod+Shift+Slash hotkey-overlay-title="显示快捷键说明" { show-hotkey-overlay; }
Mod+Q hotkey-overlay-title="关闭窗口" { close-window; }
Mod+O repeat=false hotkey-overlay-title="总览" { toggle-overview; }
Mod+F hotkey-overlay-title="最大化当前列" { maximize-column; }
Mod+Shift+F hotkey-overlay-title="窗口全屏" { fullscreen-window; }
Mod+V hotkey-overlay-title="切换浮动窗口" { toggle-window-floating; }
Mod+W hotkey-overlay-title="切换标签页模式" { toggle-column-tabbed-display; }
Mod+Left hotkey-overlay-title="焦点向左" { focus-column-left; }
Mod+Down hotkey-overlay-title="焦点向下" { focus-window-down; }
Mod+Up hotkey-overlay-title="焦点向上" { focus-window-up; }
Mod+Right hotkey-overlay-title="焦点向右" { focus-column-right; }
Mod+H { focus-column-left; }
Mod+J { focus-window-down; }
Mod+K { focus-window-up; }
Mod+Semicolon { focus-column-right; }
Mod+Shift+Left hotkey-overlay-title="窗口向左移动" { move-column-left; }
Mod+Shift+Down hotkey-overlay-title="窗口向下移动" { move-window-down; }
Mod+Shift+Up hotkey-overlay-title="窗口向上移动" { move-window-up; }
Mod+Shift+Right hotkey-overlay-title="窗口向右移动" { move-column-right; }
Mod+Page_Down hotkey-overlay-title="下一个工作区" { focus-workspace-down; }
Mod+Page_Up hotkey-overlay-title="上一个工作区" { focus-workspace-up; }
Mod+Shift+Page_Down hotkey-overlay-title="窗口移到下一个工作区" { move-column-to-workspace-down; }
Mod+Shift+Page_Up hotkey-overlay-title="窗口移到上一个工作区" { move-column-to-workspace-up; }
Mod+1 { focus-workspace 1; }
Mod+2 { focus-workspace 2; }
Mod+3 { focus-workspace 3; }
Mod+4 { focus-workspace 4; }
Mod+5 { focus-workspace 5; }
Mod+Shift+1 { move-column-to-workspace 1; }
Mod+Shift+2 { move-column-to-workspace 2; }
Mod+Shift+3 { move-column-to-workspace 3; }
Mod+Shift+4 { move-column-to-workspace 4; }
Mod+Shift+5 { move-column-to-workspace 5; }
Mod+R hotkey-overlay-title="切换列宽" { switch-preset-column-width; }
Mod+Shift+R hotkey-overlay-title="切换窗口高度" { switch-preset-window-height; }
Mod+Minus { set-column-width "-10%"; }
Mod+Equal { set-column-width "+10%"; }
Print hotkey-overlay-title="截图" { screenshot; }
Ctrl+Print hotkey-overlay-title="截取屏幕" { screenshot-screen; }
Alt+Print hotkey-overlay-title="截取窗口" { screenshot-window; }
XF86AudioRaiseVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05+"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05-"; }
XF86AudioMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
XF86AudioPlay allow-when-locked=true { spawn "playerctl" "play-pause"; }
XF86AudioNext allow-when-locked=true { spawn "playerctl" "next"; }
XF86AudioPrev allow-when-locked=true { spawn "playerctl" "previous"; }
XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "set" "+5%"; }
XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "set" "5%-"; }
Mod+Shift+E hotkey-overlay-title="退出 Niri" { quit; }
Mod+Shift+P hotkey-overlay-title="关闭显示器" { power-off-monitors; }
}
+21
View File
@@ -0,0 +1,21 @@
daemonize
show-failed-attempts
ignore-empty-password
font=Noto Sans CJK SC
font-size=24
indicator-radius=82
indicator-thickness=8
inside-color=181a1dcc
inside-clear-color=d4c5a5cc
inside-ver-color=5d83aacc
inside-wrong-color=dc7a78cc
ring-color=ffffff30
ring-clear-color=d4c5a5ff
ring-ver-color=7aa2c8ff
ring-wrong-color=dc7a78ff
key-hl-color=d4c5a5ff
text-color=f0eee8ff
text-clear-color=181a1dff
text-ver-color=f0eee8ff
text-wrong-color=f0eee8ff
separator-color=00000000
+56
View File
@@ -0,0 +1,56 @@
{
"layer": "top",
"position": "top",
"height": 36,
"spacing": 6,
"margin-top": 6,
"margin-left": 8,
"margin-right": 8,
"modules-left": ["custom/launcher"],
"modules-center": [],
"modules-right": ["tray", "network", "pulseaudio", "battery", "clock", "custom/lock", "custom/power"],
"custom/launcher": {
"format": " \uf141 ",
"tooltip": false,
"on-click": "fuzzel"
},
"tray": {
"icon-size": 17,
"spacing": 8
},
"network": {
"format-wifi": "\uf1eb {signalStrength}%",
"format-ethernet": "\uf1e6",
"format-disconnected": "\uf071",
"tooltip-format": "{ifname}: {ipaddr}/{cidr}"
},
"pulseaudio": {
"format": "{icon} {volume}%",
"format-muted": "\uf026",
"format-icons": ["\uf026", "\uf027", "\uf028"],
"on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
"tooltip": false
},
"battery": {
"states": {"warning": 30, "critical": 15},
"format": "{icon} {capacity}%",
"format-charging": "\uf0e7 {capacity}%",
"format-icons": ["\uf244", "\uf243", "\uf242", "\uf241", "\uf240"],
"tooltip": false
},
"clock": {
"interval": 1,
"format": "{:%m月%d日 %H:%M}",
"tooltip-format": "<tt>{calendar}</tt>"
},
"custom/lock": {
"format": "\uf023",
"tooltip": false,
"on-click": "swaylock -f"
},
"custom/power": {
"format": "\uf011",
"tooltip": false,
"on-click": "wlogout"
}
}
+59
View File
@@ -0,0 +1,59 @@
@define-color panel rgba(24, 26, 29, 0.76);
@define-color text #f0eee8;
@define-color muted #a8abb2;
@define-color accent #d4c5a5;
@define-color red #dc7a78;
* {
border: none;
border-radius: 0;
min-height: 0;
font-family: "Noto Sans CJK SC", "Noto Sans", "FontAwesome";
font-size: 13px;
font-weight: 500;
}
window#waybar {
background: @panel;
color: @text;
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 10px;
}
#custom-launcher,
#tray,
#network,
#pulseaudio,
#battery,
#clock,
#custom-lock,
#custom-power {
padding: 0 10px;
color: @text;
}
#custom-launcher {
color: @accent;
font-size: 16px;
}
#network.disconnected,
#battery.critical {
color: @red;
}
#custom-lock,
#custom-power {
padding: 0 12px;
}
#custom-power {
color: @red;
}
tooltip {
background: #202226;
color: @text;
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 6px;
}
Executable
+323
View File
@@ -0,0 +1,323 @@
#!/usr/bin/env bash
set -Eeuo pipefail
readonly PROJECT="niri-beyond-glass"
readonly NIRI_TAG="v26.04"
readonly XWS_TAG="v0.8.2"
readonly RUST_TOOLCHAIN="1.85.1"
readonly ARCHIVE_URL="https://git.k1412.top/wuyang/niri-beyond-glass/archive/main.tar.gz"
wallpaper=""
config_only=0
dry_run=0
rebuild=0
source_dir="${NBG_SOURCE_DIR:-}"
tmp_dir=""
usage() {
cat <<'EOF'
用法:install.sh [选项]
--wallpaper PATH 使用指定的静态壁纸
--config-only 只更新配置,不安装/编译软件
--rebuild 强制重新编译 Niri 和 Xwayland Satellite
--dry-run 显示将执行的主要步骤,不修改系统
-h, --help 显示帮助
EOF
}
log() {
printf '\033[1;36m[Niri]\033[0m %s\n' "$*"
}
die() {
printf '\033[1;31m错误:\033[0m %s\n' "$*" >&2
exit 1
}
run() {
if (( dry_run )); then
printf '+'
printf ' %q' "$@"
printf '\n'
else
"$@"
fi
}
cleanup() {
[[ -n "$tmp_dir" && -d "$tmp_dir" ]] && rm -rf "$tmp_dir"
}
trap cleanup EXIT
while (($#)); do
case "$1" in
--wallpaper)
(($# >= 2)) || die "--wallpaper 缺少路径"
wallpaper="$2"
shift 2
;;
--config-only)
config_only=1
shift
;;
--rebuild)
rebuild=1
shift
;;
--dry-run)
dry_run=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
die "未知参数:$1"
;;
esac
done
[[ ${EUID:-$(id -u)} -ne 0 ]] || die "请用普通用户运行,脚本会在需要时调用 sudo。"
[[ -z "$wallpaper" || -f "$wallpaper" ]] || die "壁纸不存在:$wallpaper"
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
else
die "无法识别操作系统。"
fi
if [[ "${ID:-}" != "ubuntu" || "${VERSION_ID:-}" != "24.04" ]]; then
die "只支持 Ubuntu 24.04;当前是 ${PRETTY_NAME:-未知系统}"
fi
case "$(uname -m)" in
x86_64|aarch64) ;;
*) die "目前只支持 x86_64 和 aarch64。" ;;
esac
fetch_source() {
if [[ -n "$source_dir" ]]; then
[[ -f "$source_dir/config/niri/config.kdl" ]] || die "NBG_SOURCE_DIR 不是有效源码目录。"
return
fi
tmp_dir="$(mktemp -d)"
log "下载配置仓库"
curl -fL --retry 3 "$ARCHIVE_URL" -o "$tmp_dir/source.tar.gz"
mkdir -p "$tmp_dir/source"
tar -xzf "$tmp_dir/source.tar.gz" -C "$tmp_dir/source" --strip-components=1
source_dir="$tmp_dir/source"
}
install_packages() {
log "安装 Ubuntu 24.04 依赖"
run sudo apt-get update
run sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential clang git curl ca-certificates pkg-config \
meson ninja-build cmake \
libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev \
libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev \
libseat-dev libpipewire-0.3-dev libpango1.0-dev \
libdisplay-info-dev libcairo2-dev libglib2.0-dev \
libxcb1-dev libxcb-composite0-dev libxcb-randr0-dev \
libxcb-res0-dev libxcb-xfixes0-dev libxcb-cursor-dev \
xwayland xdg-desktop-portal-gnome xdg-desktop-portal-gtk \
alacritty fuzzel waybar swaybg swaylock swayidle mako-notifier \
nautilus policykit-1-gnome pipewire-pulse wireplumber \
brightnessctl playerctl grim slurp wl-clipboard wlogout \
fonts-noto-core fonts-noto-cjk fonts-noto-color-emoji fonts-font-awesome
}
install_rust() {
export RUSTUP_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/$PROJECT/rustup"
export CARGO_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/$PROJECT/cargo"
export PATH="$CARGO_HOME/bin:$PATH"
if [[ ! -x "$CARGO_HOME/bin/rustup" ]]; then
log "安装隔离的 Rust $RUST_TOOLCHAIN 工具链"
if (( dry_run )); then
printf '+ curl https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain %q\n' "$RUST_TOOLCHAIN"
return
fi
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs |
sh -s -- -y --no-modify-path --profile minimal --default-toolchain "$RUST_TOOLCHAIN"
else
run "$CARGO_HOME/bin/rustup" toolchain install "$RUST_TOOLCHAIN" --profile minimal
run "$CARGO_HOME/bin/rustup" default "$RUST_TOOLCHAIN"
fi
}
version_ge() {
[[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -n1)" == "$2" ]]
}
install_libdisplay_info() {
local installed=""
installed="$(pkg-config --modversion libdisplay-info 2>/dev/null || true)"
if [[ -n "$installed" ]] && version_ge "$installed" "0.3.0"; then
return
fi
log "编译 libdisplay-info 0.3.0Ubuntu 24.04 自带版本较旧)"
local build_root="${XDG_CACHE_HOME:-$HOME/.cache}/$PROJECT/build"
local src="$build_root/libdisplay-info"
run mkdir -p "$build_root"
if [[ ! -d "$src/.git" ]]; then
run git clone --depth 1 --branch 0.3.0 \
https://gitlab.freedesktop.org/emersion/libdisplay-info.git "$src"
fi
run meson setup "$src/build" "$src" --prefix=/usr/local --buildtype=release --wipe
run ninja -C "$src/build"
run sudo ninja -C "$src/build" install
run sudo ldconfig
}
install_niri() {
local current=""
current="$(niri --version 2>/dev/null || true)"
if (( ! rebuild )) && [[ "$current" == *"26.4"* || "$current" == *"26.04"* ]]; then
log "已安装兼容的 $current,跳过编译"
return
fi
log "编译 Niri $NIRI_TAG"
local build_root="${XDG_CACHE_HOME:-$HOME/.cache}/$PROJECT/build"
local src="$build_root/niri"
run mkdir -p "$build_root"
if [[ ! -d "$src/.git" ]]; then
run git clone --depth 1 --branch "$NIRI_TAG" https://github.com/niri-wm/niri.git "$src"
else
run git -C "$src" fetch --depth 1 origin "refs/tags/$NIRI_TAG:refs/tags/$NIRI_TAG"
run git -C "$src" checkout -f "$NIRI_TAG"
fi
run cargo build --manifest-path "$src/Cargo.toml" --release --locked
run sudo install -Dm755 "$src/target/release/niri" /usr/local/bin/niri
run sudo install -Dm755 "$src/resources/niri-session" /usr/local/bin/niri-session
run sudo install -Dm644 "$src/resources/niri.service" /usr/local/lib/systemd/user/niri.service
run sudo install -Dm644 "$src/resources/niri-shutdown.target" /usr/local/lib/systemd/user/niri-shutdown.target
run sudo install -Dm644 "$src/resources/niri.desktop" /usr/local/share/wayland-sessions/niri.desktop
run sudo install -Dm644 "$src/resources/niri-portals.conf" /usr/local/share/xdg-desktop-portal/niri-portals.conf
}
install_xwayland_satellite() {
if (( ! rebuild )) && command -v xwayland-satellite >/dev/null 2>&1; then
return
fi
log "编译 Xwayland Satellite $XWS_TAG"
local build_root="${XDG_CACHE_HOME:-$HOME/.cache}/$PROJECT/build"
local src="$build_root/xwayland-satellite"
run mkdir -p "$build_root"
if [[ ! -d "$src/.git" ]]; then
run git clone --depth 1 --branch "$XWS_TAG" \
https://github.com/Supreeeme/xwayland-satellite.git "$src"
else
run git -C "$src" fetch --depth 1 origin "refs/tags/$XWS_TAG:refs/tags/$XWS_TAG"
run git -C "$src" checkout -f "$XWS_TAG"
fi
run cargo build --manifest-path "$src/Cargo.toml" --release --locked
run sudo install -Dm755 "$src/target/release/xwayland-satellite" /usr/local/bin/xwayland-satellite
}
backup_and_install_config() {
local config_home="${XDG_CONFIG_HOME:-$HOME/.config}"
local state_home="${XDG_STATE_HOME:-$HOME/.local/state}"
local stamp
stamp="$(date +%Y%m%d-%H%M%S)"
local backup="$state_home/$PROJECT/backups/$stamp/config"
local names=(niri waybar fuzzel mako swaylock niri-beyond-glass)
log "备份并安装用户配置"
run mkdir -p "$backup"
local name
for name in "${names[@]}"; do
if [[ -e "$config_home/$name" ]]; then
run cp -a "$config_home/$name" "$backup/$name"
fi
done
run mkdir -p \
"$config_home/niri" \
"$config_home/waybar" \
"$config_home/fuzzel" \
"$config_home/mako" \
"$config_home/swaylock" \
"$config_home/niri-beyond-glass" \
"$HOME/.local/bin" \
"$HOME/Pictures/Screenshots"
run install -m644 "$source_dir/config/niri/config.kdl" "$config_home/niri/config.kdl"
run install -m644 "$source_dir/config/waybar/config.jsonc" "$config_home/waybar/config.jsonc"
run install -m644 "$source_dir/config/waybar/style.css" "$config_home/waybar/style.css"
run install -m644 "$source_dir/config/fuzzel/fuzzel.ini" "$config_home/fuzzel/fuzzel.ini"
run install -m644 "$source_dir/config/mako/config" "$config_home/mako/config"
run install -m644 "$source_dir/config/swaylock/config" "$config_home/swaylock/config"
run install -m755 "$source_dir/scripts/niri-beyond-wallpaper" "$HOME/.local/bin/niri-beyond-wallpaper"
select_wallpaper "$config_home/niri-beyond-glass/wallpaper"
}
select_wallpaper() {
local state_file="$1"
local selected="$wallpaper"
if [[ -z "$selected" ]]; then
local candidates=(
/usr/share/backgrounds/warty-final-ubuntu.png
/usr/share/backgrounds/ubuntu-default-greyscale-wallpaper.png
)
local candidate
for candidate in "${candidates[@]}"; do
if [[ -f "$candidate" ]]; then
selected="$candidate"
break
fi
done
fi
if [[ -z "$selected" ]]; then
selected="$(find /usr/share/backgrounds -maxdepth 2 -type f \
\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \) \
-print -quit 2>/dev/null || true)"
fi
if (( dry_run )); then
printf '+ write wallpaper path %q to %q\n' "$selected" "$state_file"
else
printf '%s\n' "$selected" > "$state_file"
fi
}
validate_config() {
if (( dry_run )); then
printf '+ niri validate -c %q\n' "${XDG_CONFIG_HOME:-$HOME/.config}/niri/config.kdl"
return
fi
command -v niri >/dev/null 2>&1 || die "找不到 niri,无法验证配置。"
niri validate -c "${XDG_CONFIG_HOME:-$HOME/.config}/niri/config.kdl"
}
main() {
fetch_source
if (( ! config_only )); then
install_packages
install_rust
install_libdisplay_info
install_niri
install_xwayland_satellite
fi
backup_and_install_config
validate_config
log "安装完成"
printf '\n请注销,在 GDM 会话菜单中选择“Niri”后登录。\n'
printf 'GNOME 和 GDM 均未被修改;快捷键说明:Super+Shift+/。\n'
}
main
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
state="${XDG_CONFIG_HOME:-$HOME/.config}/niri-beyond-glass/wallpaper"
wallpaper=""
if [[ -s "$state" ]]; then
IFS= read -r wallpaper < "$state"
fi
if [[ -n "$wallpaper" && -f "$wallpaper" ]]; then
exec swaybg -m fill -i "$wallpaper"
fi
exec swaybg -c '#15171a'
Executable
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
config_home="${XDG_CONFIG_HOME:-$HOME/.config}"
state_home="${XDG_STATE_HOME:-$HOME/.local/state}"
backup_root="$state_home/niri-beyond-glass/backups"
latest=""
if [[ -d "$backup_root" ]]; then
latest="$(find "$backup_root" -mindepth 1 -maxdepth 1 -type d -printf '%p\n' | sort | tail -n 1)"
fi
rm -rf \
"$config_home/niri" \
"$config_home/waybar" \
"$config_home/fuzzel" \
"$config_home/mako" \
"$config_home/swaylock" \
"$config_home/niri-beyond-glass"
rm -f "$HOME/.local/bin/niri-beyond-wallpaper"
if [[ -n "$latest" && -d "$latest/config" ]]; then
cp -a "$latest/config/." "$config_home/"
printf '已恢复备份:%s\n' "$latest"
else
printf '配置已移除;没有找到可恢复的备份。\n'
fi
printf 'Niri 和系统软件包被保留。GNOME/GDM 未修改。\n'