软件相关
建议必装
-
X11 相关: xorg-xset xorg-xhost xorg-xinit xorg-xev xclip xss-lock
-
功能性软件: lxqt-policykit-agent dunst copyq rog-control-center-x11(aur) i3lock-color(cachyos/aur)
-
美化: rofi qt5ct qt6ct picom nwg-look feh
-
设备控制: pipewire-pulse pavucontrol blueman nm-applet brightnessctl
自选软件
kitty thunar thunar-volman tumbler navi snipaste
锁屏相关
dwm 一般使用 i3lock 这里使用 i3lock-color, 为 i3lock 的增强版
创建锁屏脚本 lock.sh, 放到合适位置
#!/bin/sh
BLANK='#00000000'CLEAR='#00000000'DEFAULT='#ffffffff'TEXT='#ffffffff'WRONG='#fc5500ff'VERIFYING='#0089B6ff'BACKGROUND='#000000ff'
i3lock \--color=$BACKGROUND \--insidever-color=$CLEAR \--ringver-color=$VERIFYING \\--insidewrong-color=$CLEAR \--ringwrong-color=$WRONG \\--inside-color=$BLANK \--ring-color=$DEFAULT \--line-color=$BLANK \--separator-color=$BLANK \\--verif-color=$TEXT \--wrong-color=$TEXT \--time-color=$TEXT \--date-color=$TEXT \--layout-color=$TEXT \--keyhl-color=$VERIFYING \--bshl-color=$WRONG \--modifoutline-color=$TEXT \\--screen 1 \--clock \--indicator \--time-str="%H:%M:%S" \--date-str="%A, %Y-%m-%d" \--keylayout 1 \\--time-size=100 \--date-size=24 \\--radius 40 \--ring-width 10 \--ind-pos="x+w/2:y+h/2+300" \--time-pos="w/2:h/2-30" \--date-pos="w/2:h/2+30" \--verif-pos="w/2:h/2" \--wrong-pos="w/2:h/2" \--modif-pos="w/2:h-30" \--status-pos="w/2:h/2" \参考 https://github.com/Raymo111/i3lock-color/blob/master/examples/lock.sh
picom
picom 是一个第三方混成器, 可以给 dwm 提供窗口阴影, 半透明, 以及动画
创建 $HOME/.config/picom/picom.conf
vsync = true; # 垂直同步backend = "glx"; # 指定渲染后端
shadow = true;opacity-rule = [
"95:class_g = 'Code'", # VS Code 80% 透明 "90:class_g = 'kitty'", # VS Code 80% 透明
];触控板以及鼠标
-
开启触控板自然滚动,轻触点击
-
调整触摸板和鼠标的速度为 0.5 [0,1] 这样更快
Section "InputClass" Identifier "libinput pointer catchall" MatchIsPointer "on" Option "NaturalScrolling" "false" Option "AccelProfile" "flat" Option "AccelSpeed" "0.5"EndSection
Section "InputClass" Identifier "libinput touchpad catchall" MatchIsTouchpad "on" Option "NaturalScrolling" "true" Option "Tapping" "on" Option "TappingButtonMap" "lrm" Option "AccelSpeed" "0.5"EndSectiondwm
dwm 的设计理念为 suckless, 所有的自定义配置都需要修改头文件重新编译, 但是其具有极高的可拓展性, 可以通过应用 patch 进行扩展, 但是由于传统的手动应用 patch 需要解决过于复杂的合并工作, 以及需要遵守相当严格的合并顺序, 所以这里使用一个第三方的 dwm 改版: dwm-flexipatch, 这个版本将大部分常用补丁全部打入, 通过宏定义控制补丁的开启, 未开启的补丁在编译的时候会直接忽略以节省性能
克隆仓库
git clone https://github.com/bakkeby/dwm-flexipatch.git克隆完成后请立即执行 make
此时会生成两个文件:
-
config.h
-
patches.h
这两个文件为对应 .def.h 模板文件的副本, 用于用户自定义修改配置, 以防干扰默认配置, 如果需要使用 git 管理自定义修改需要将这两个文件从 .gitignore 中移除
执行 sudo make install 安装
启动 dwm
这里以 greetd 为例
在 $HOME 中添加一个 .xsession 文件, 里面编写启动脚本
#设置qt主题export QT_QPA_PLATFORMTHEME=qt6ct
#设置语言export LANG=zh_CN.UTF-8export LC_ALL=zh_CN.UTF-8
# 合并 Xresources 配置, 见后文xrdb -merge ~/.Xresources
# 设置壁纸feh --bg-fill ".../wallpaper.png" &
# 禁用自动休眠/黑屏xset -dpms && xset s off && xset s noblank
# 自动锁屏服务(注意:这里必须加 & 后台运行)xss-lock --transfer-sleep-lock -- .../lock.sh -n &
# dwm 的 bar, 见后文.../dwm_bar.sh &
picom -b & # 合成器, 见后文dunst & # 通知管理器fcitx5 & # 输入法nm-applet & # 网络托盘blueman-applet & # 蓝牙托盘flclash & # 飞机copyq & # 剪贴板Snipaste & # 截图软件lxqt-policykit-agent & # 应用授权后端rog-control-center & # 华硕面板
exec dwm修改 /etc/greetd/config.toml 中的 session 配置
command = "tuigreet --asterisks --time -r --cmd 'startx ~/.xsession'".Xresources 文件
其中包含了 xserver 的部分设置
Xft.dpi: 144 # 设置分数缩放 dpiXcursor.size: 32 # 设置鼠标指针大小patches 选择
编辑库中的 patches.h 文件中的宏定义, 标记为 1 开启 patch
-
BAR_AWESOMEBAR_PATCH: 类似awesomewm的任务栏, 显示当前虚拟桌面的所有窗口标题, 点击即可隐藏标签 -
BAR_STATUS_PATCH: 允许在状态栏中使用颜色和特殊格式 -
BAR_STATUS2D_PATCH: 许在状态栏中使用十六进制真彩色 -
BAR_SYSTRAY_PATCH: 启用系统托盘 -
BAR_TAGS_PATCH: 虚拟桌面指示器 -
BAR_WINTITLE_PATCH: 显示窗口标题, 是BAR_AWESOMEBAR_PATCH的依赖 -
CFACTS_PATCH: 允许调整单独平铺窗口大小 -
DRAGCFACT_PATCH: 允许通过按键拖拽调整平铺窗口高度 -
DRAGMFACT_PATCH: 允许通过按键拖拽调整平铺窗口宽度 -
FLOATPOS_PATCH: 允许设置浮动窗口创建时位置以及大小 -
FOCUSONCLICK_PATCH: 关闭鼠标哪窗口焦点就到哪 -
SELFRESTART_PATCH: 允许热重载 -
SHIFTVIEW_CLIENTS_PATCH: 可以前后切换虚拟桌面并且切换时候自动跳过空白虚拟桌面, 这里用于切换窗口 -
FOCUSADJACENTTAG_PATCH: 前后切换虚拟桌面但是不跳过空白虚拟桌面, 这里用于移动窗口到其他虚拟桌面 -
VANITYGAPS_PATCH: 设置窗口间隔 -
XRDB_PATCH: 允许读取.Xresources文件的颜色配置 -
TILE_LAYOUT: 默认的布局模式, 还有很多模式可以参考 -
FULLSCREEN_PATCH: 允许设置全屏 -
PLACEMOUSE_PATCH: 允许通过鼠标拖拽调换窗口位置
修改外观
修改 config.h
- 关闭标签指示器数字左上角的窗口指示器 (小方块)
...static int tagindicatortype = INDICATOR_NONE;static int floatindicatortype = INDICATOR_NONE;...- 调整字体和样式
...#if BAR_PANGO_PATCHstatic const char font[] = "monospace 10";#elsestatic const char *fonts[] = { "JetBrains Mono:style=Bold:size=10" };#endif // BAR_PANGO_PATCHstatic const char dmenufont[] = "JetBrains Mono:style=Bold:size=10";...- 加粗窗口边框
static const unsigned int borderpx = 4; /* border pixel of windows */- 关闭吸附
static const unsigned int snap = 0; /*- 调整非激活窗口边框颜色
static char normfloatcolor[] = "#444444";- 调整窗口间隔
static const unsigned int gappih = 5; /* horiz inner gap between windows */static const unsigned int gappiv = 5; /* vert inner gap between windows */static const unsigned int gappoh = 5; /* horiz outer gap between windows and screen edge */static const unsigned int gappov = 5; /* vert outer gap between windows and screen edge */- 调整 master 区域默认比例
static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */窗口规则
static const Rule rules[] = {
...
RULE(.class = "copyq", .isfloating = 1, .floatpos = "50% 50% 800W 600H") // 设置窗口打开就浮动, 位置位于屏幕中心, 大小是 800*600 RULE(.class = "Thunar", .isfloating = 1, .floatpos = "50% 50% 1400W 800H") RULE(.class = "kitty", .isfloating = 1, .floatpos = "50% 50% 1400W 800H") RULE(.class = "rog-control-center", .isfloating = 1, .floatpos = "50% 50% 1400W 800H")
// 设置微信主窗口平铺, 其余窗口浮动, QQ 同理 RULE(.class = "wechat", .isfloating = 1) RULE(.class = "wechat", .title = "微信", .isfloating = 0)
RULE(.class = "QQ", .isfloating = 1) RULE(.class = "QQ", .title = "QQ", .isfloating = 0)
...
};自定义任务
static const char *roficmd[] = { "rofi", "-show", "drun", NULL };static const char *kittycmd[] = { "kitty", NULL };static const char *thunarcmd[] = { "thunar", NULL };static const char *powerscript[] = { "bash", "/home/kinntaku/user_dotfiles/bin/power.sh", NULL }; // 电源菜单行为static const char *lockcmd[] = { "bash", "/home/kinntaku/user_dotfiles/bin/lock.sh", NULL }; // 锁屏行为static const char *navicmd[] = { "kitty", "-e", "navi", "--path", "/home/kinntaku/user_dotfiles/navi", NULL }; // 自定义路径 navistatic const char *powerprofilecmd[] = { "sh", "-c", "profile=$(powerprofilesctl get); case \"$profile\" in balanced) powerprofilesctl set power-saver ;; power-saver) powerprofilesctl set performance ;; performance) powerprofilesctl set balanced ;; esac", NULL }; // 电源模式调整按键绑定
如果使用 ipc 按键需要在 dwm.c 添加
#include <X11/XKBlib.h>更改 MODKEY 为 Windows 键, 修改 config.h
#define MODKEY Mod4Mask- 自定义快捷键
static const Key keys[] = { #if KEYMODES_PATCH
...
#endif // KEYMODES_PATCH
...
{ MODKEY, XK_x, spawn, {.v = powerscript } }, // 使用 rofi 实现电源菜单 { MODKEY, XK_grave, spawn, {.v = roficmd } }, // 打开 rofi { MODKEY, XK_t, spawn, {.v = kittycmd } }, // 打开 kitty { MODKEY, XK_e, spawn, {.v = thunarcmd } }, // 打开 thuanr { MODKEY, XK_l, spawn, {.v = lockcmd } }, // 锁屏 { Mod1Mask, XK_space, spawn, {.v = navicmd } }, // 打开 navi { MODKEY, XK_v, spawn, SHCMD("copyq show") }, // 呼出剪贴板 { 0, XF86XK_Launch3, spawn, SHCMD("rog-control-center") }, // 华硕面板 { 0, XF86XK_Launch4, spawn, {.v = powerprofilecmd } }, // 电源模式调整
// 音量调整 { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("pactl set-sink-volume @DEFAULT_SINK@ +5%") }, { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("pactl set-sink-volume @DEFAULT_SINK@ -5%") }, { 0, XF86XK_AudioMute, spawn, SHCMD("pactl set-sink-mute @DEFAULT_SINK@ toggle") }, { 0, XF86XK_AudioMicMute, spawn, SHCMD("pactl set-source-mute @DEFAULT_SOURCE@ toggle") },
// 亮度调整 { 0, XF86XK_MonBrightnessUp, spawn, SHCMD("brightnessctl set 5%+") }, { 0, XF86XK_MonBrightnessDown,spawn, SHCMD("brightnessctl set 5%-") },
// 媒体调整 { 0, XF86XK_AudioPlay, spawn, SHCMD("playerctl play-pause") }, { 0, XF86XK_AudioNext, spawn, SHCMD("playerctl next") }, { 0, XF86XK_AudioPrev, spawn, SHCMD("playerctl previous") }, { 0, XF86XK_AudioStop, spawn, SHCMD("playerctl stop") },
...
}- 窗口调整
切换左右虚拟桌面
{ MODKEY XK_a, shiftviewclients, { .i = -1 } },{ MODKEY, XK_d, shiftviewclients, { .i = +1 } },切换窗口
{ MODKEY, XK_s, focusstack, {.i = +1 } },{ MODKEY, XK_w, focusstack, {.i = -1 } },最小化窗口和解除全部最小化
{ MODKEY, XK_c, showhideclient, {0} },{ MODKEY|ShiftMask, XK_c, unhideall, {0} },增加/减少 master 区域的窗口数量
{ MODKEY, XK_F1, incnmaster, {.i = +1 } },{ MODKEY, XK_F2, incnmaster, {.i = -1 } },移动窗口到左右桌面 (不跳过空白虚拟桌面)
{ MODKEY|ShiftMask, XK_a, tagtoleft, {0} }, // note keybinding conflict with shifttag{ MODKEY|ShiftMask, XK_d, tagtoright, {0} }, // note keybinding conflict with shifttag调整窗口大小
#if FLEXTILE_DELUXE_LAYOUT
...
#endif // FLEXTILE_DELUXE_LAYOUT{ MODKEY, XK_g, setmfact, {.f = -0.05} },{ MODKEY, XK_h, setmfact, {.f = +0.05} },#if CFACTS_PATCH{ MODKEY|ShiftMask, XK_g, setcfact, {.f = +0.25} },{ MODKEY|ShiftMask, XK_h, setcfact, {.f = -0.25} },
...
#endif // CFACTS_PATCH#if ASPECTRESIZE_PATCH移动窗口位置
#if MOVESTACK_PATCH{ MODKEY|ShiftMask, XK_s, movestack, {.i = +1 } },{ MODKEY|ShiftMask, XK_w, movestack, {.i = -1 } },关闭窗口
{ Mod1Mask, XK_F4, killclient, {0} },退出桌面环境
{ MODKEY|ShiftMask, XK_F12, quit, {0} },如果你不需要调整布局
// { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },// { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },// { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },// { MODKEY, XK_space, setlayout, {0} },切换浮动窗口
{ MODKEY, XK_f, togglefloating, {0} },开启全屏
{ MODKEY|ShiftMask, XK_f, togglefullscreen, {0} },电源脚本编写, 使用rofi
MENU="rofi -dmenu -p Power"
options="Suspend\nSleep\nRestart\nShutdown\nExit"
chosen=$(echo -e "$options" | $MENU)
case "$chosen" in Suspend) systemctl suspend ;; Sleep) systemctl hibernate ;; Restart) reboot ;; Shutdown) poweroff ;; Exit) pkill dwm ;; *) exit 0 ;;esac状态栏脚本编写
编写 dwm_bar.sh 放到合适位置
#!/bin/bash
CLR_CPU="^c#BF616A^" # 红CLR_MEM="^c#D08770^" # 橙CLR_VOL="^c#A3BE8C^" # 绿CLR_MIC="^c#88C0D0^" # 青CLR_PWR="^c#81A1C1^" # 蓝CLR_BAT="^c#B48EAD^" # 紫CLR_DATE="^c#ECEFF4^" # 白CLR_WARN="^c#ECEFF4^^b#BF616A^" # 警告RESET="^d^"
update_status() { # --- CPU 使用率 --- CPU_VAL=$(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {printf("%.0f", usage)}') CPU_DIS="${CLR_CPU}CPU:${CPU_VAL:-0}%${RESET}"
# --- 内存使用率 --- MEM_TOTAL=$(awk '/MemTotal/ {print $2}' /proc/meminfo) MEM_AVAIL=$(awk '/MemAvailable/ {print $2}' /proc/meminfo) MEM_VAL=$(( (MEM_TOTAL - MEM_AVAIL) * 100 / MEM_TOTAL )) MEM_DIS="${CLR_MEM}MEM:${MEM_VAL}%${RESET}"
# --- 扬声器音量 --- V_NUM=$(pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null | grep -Po '\d+(?=%)' | head -n 1 || echo "0") if pactl get-sink-mute @DEFAULT_SINK@ 2>/dev/null | grep -q "yes"; then VOL_DIS="${CLR_WARN}VOL:M${RESET}" else VOL_DIS="${CLR_VOL}VOL:${V_NUM}%${RESET}" fi
# --- 麦克风音量 --- M_NUM=$(pactl get-source-volume @DEFAULT_SOURCE@ 2>/dev/null | grep -Po '\d+(?=%)' | head -n 1 || echo "0") if pactl get-source-mute @DEFAULT_SOURCE@ 2>/dev/null | grep -q "yes"; then MIC_DIS="${CLR_WARN}MIC:M${RESET}" else MIC_DIS="${CLR_MIC}MIC:${M_NUM}%${RESET}" fi
# --- 电源模式 (Power-Profiles-Daemon) --- PWR_MODE=$(powerprofilesctl get 2>/dev/null || echo "N/A") case "$PWR_MODE" in *performance*) PWR_STR="PERF" ;; *balanced*) PWR_STR="BAL" ;; *power-saver*) PWR_STR="SAVE" ;; *) PWR_STR="N/A" ;; esac PWR_DIS="${CLR_PWR}PWR:${PWR_STR}${RESET}"
# --- 亮度 --- BRIGHT_VAL=$(brightnessctl g 2>/dev/null | awk '{print int($1/255*100)}' || echo "0") BRT_DIS="${CLR_BRT}BRT:${BRIGHT_VAL}%${RESET}"
# --- 电池 --- BAT_PATH=$(ls /sys/class/power_supply/BAT* -d 2>/dev/null | head -n 1) if [ -n "$BAT_PATH" ]; then BAT_VAL=$(cat "$BAT_PATH/capacity" 2>/dev/null || echo "0") [ "$BAT_VAL" -lt 20 ] && BAT_DIS="${CLR_WARN}BAT:${BAT_VAL}%${RESET}" || BAT_DIS="${CLR_BAT}BAT:${BAT_VAL}%${RESET}" else BAT_DIS="" fi
# --- 时间 --- DATE_VAL=$(date +"%m.%d %H:%M") DATE_DIS="${CLR_DATE}${DATE_VAL}${RESET}"
STATUS=" ${CPU_DIS} ${MEM_DIS} ${VOL_DIS} ${MIC_DIS} ${PWR_DIS} ${BRT_DIS} ${BAT_DIS} ${DATE_DIS} "
xprop -root -f WM_NAME 8s -set WM_NAME "$STATUS"}
( while true; do update_status sleep 2 done) &
( pactl subscribe 2>/dev/null | grep --line-buffered -E "sink|source" | while read -r _; do update_status done) &
update_statuswhile true; do sleep 60; done