dwm

出自 ArchWiki

dwm 是一个用于 Xorg 的动态窗口管理器。它可以管理平铺、堆叠和全屏布局的窗口,以及许多其他通过可选补丁实现的布局。布局可以动态应用,从而优化使用中的应用程序和正在执行的任务的环境。dwm 非常轻巧快速,用 C 语言编写,并声明设计目标是保持在 2000 行源代码以下。它为 xrandr 和 Xinerama 提供 多显示器 支持。

安装

dwm 可以通过软件包 dwmAURdwm-gitAUR 安装。在构建和安装之前进行任何必需的 配置 更改,请参阅 makepkg

提示: 也可以遵循 上游说明,但这将安装文件,而 pacman 不会跟踪这些文件。

配置

dwm 在编译时通过编辑其一些源文件(特别是 config.h)进行配置。有关这些设置的详细信息,请参阅包含在内且注释良好的 config.def.h 以及 dwm 网站上的自定义部分

官方网站有许多 补丁,可以为 dwm 添加额外的功能。这些补丁主要修改 dwm.c 文件,但也适当地修改 config.h 文件。有关应用补丁的信息,请参阅 Patching packages 文章。

启动

从所选显示管理器的菜单中选择Dwm。或者,要使用 startx 启动 dwm,请将 exec dwm 附加到 ~/.xinitrc,并将其他程序放在前面以同时执行它们,例如

redshift -O3500; xset r rate 300 50; exec dwm

用法

有关 dwm 基本用法的信息,请参阅 dwm 教程

技巧与提示

状态栏配置

有关状态栏的更多示例,请参阅 [1]

注意: 以下内容需要安装 xorg-xsetroot 软件包。

dwm 读取根窗口的名称并将其重定向到状态栏。根窗口是所有其他窗口在其中绘制并由窗口管理器排列的窗口。像任何其他窗口一样,根窗口也有标题/名称,但它通常是未定义的,因为根窗口始终在后台运行。

您希望 dwm 在状态栏中显示的信息应使用 xsetroot -name "" 命令在 ~/.xinitrc~/.xprofile(如果您正在使用显示管理器)中定义。例如

xsetroot -name "Thanks for all the fish!"

动态更新的信息应放在一个循环中,该循环被 fork 到后台 - 请参见下面的示例

# Statusbar loop
while true; do
   xsetroot -name "$( date +"%F %R" )"
   sleep 1m    # Update time every minute
done &

# Autostart section
pcmanfm & 

exec dwm

在这种情况下,日期以 RFC:3339 格式显示,并且在启动时启动 PCManFM

注意: 不建议将更新间隔设置为零或完全删除 "sleep" 行,因为这将导致 CPU 使用率大幅上升(您可以使用 toppowertop 评估效果)。

Conky 状态栏

Conky 可以使用 xsetroot -name 打印到状态栏

(conky | while read LINE; do xsetroot -name "$LINE"; done) &
exec dwm

如果您不想通过 'xsetroot' 命令生成过多的 PID,您可以编译这个 C 程序

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>

int main(int argc, char * argv[])
{
        Display * dpy = NULL;
        Window win = 0;
        size_t length = 0;
        ssize_t bytes_read = 0;
        char * input = NULL;

        dpy = XOpenDisplay(getenv("DISPLAY"));
        if (dpy == NULL)
        {
                fprintf(stderr, "Can't open display, exiting.\n");
                exit(1);
        }
        win = DefaultRootWindow(dpy);

        while ((bytes_read = getline(&input, &length, stdin)) != EOF)
        {
                input[strlen(input) - 1] = '\0';
                XStoreName(dpy, win, input);
                XFlush(dpy);
                fprintf(stderr, "Input: %s", input);
                fprintf(stderr, "\nbytes read: %ld\n", bytes_read);
        }
        free(input);
        return 0;
}

将此代码保存到文件 dwm-setstatus.c,编译

$ gcc dwm-setstatus.c -lX11 -o dwm-setstatus

将 'dwm-setstatus' 移动到您的 $PATH 中(例如 /usr/local/bin

# mv dwm-setstatus /usr/local/bin

并运行

$ conky | dwm-setstatus

为此,需要告诉 conky 仅将文本输出到控制台。以下是双核 CPU 的示例 conkyrc,显示了几个使用统计信息

conky.config = {
out_to_console = true,
out_to_x = false,
background = false,
update_interval = 2,
total_run_times = 0,
use_spacer = 'none',
};
conky.text = [[
$mpd_smart :: ${cpu cpu1}% / ${cpu cpu2}%  ${loadavg 1} ${loadavg 2 3} :: ${acpitemp}c :: $memperc% ($mem) :: ${downspeed eth0}K/s ${upspeed eth0}K/s :: ${time %a %b %d %I:%M%P}
]];

有关图标和颜色选项,请参阅 dzen

重启 dwm

要在不注销或关闭应用程序的情况下重启 dwm,请更改或添加启动脚本,使其在 while 循环中加载 dwm,例如

while true; do
    # Log stderror to a file 
    dwm 2> ~/.dwm.log
    # No error logging
    #dwm >/dev/null 2>&1
done

现在可以通过按通常的 Mod-Shift-Q 组合键来重启 dwm,而不会破坏其他 X 窗口。

最好将上述启动脚本放在一个单独的文件中,例如 ~/bin/startdwm,并通过 ~/.xinitrc 执行它。考虑使用 exec 运行脚本,以避免在 X 服务器终止后仍然登录的安全隐患;有关更多信息,请参阅 Xinit#Autostart X at login。从那时起,当您希望结束 X 会话时,只需执行 pkill dwm,或将其绑定到一个方便的快捷键。或者,您可以设置您的 dwm 会话脚本,以便仅在二进制文件更改时才重新启动 dwm。如果您更改设置或更新 dwm 代码库,这将非常有用。

# relaunch DWM if the binary changes, otherwise bail
csum=""
new_csum=$(sha1sum $(which dwm))
while true
do
    if [ "$csum" != "$new_csum" ]
    then
        csum=$new_csum
        dwm
    else
        exit 0
    fi
    new_csum=$(sha1sum $(which dwm))
    sleep 0.5
done

将右 Alt 键绑定到 Mod4

当使用 Mod4(Super/Windows 键)作为 MODKEY 时,将右 Alt 键 (Alt_R) 用作 Mod4 可能同样方便。这将允许您单手执行原本笨拙的击键,例如使用 Alt_R+Enter 进行缩放。

首先,找出分配给 Alt_R 的键码

$ xmodmap -pke | grep Alt_R

然后只需将以下内容添加到启动脚本(例如 ~/.xinitrc),如果需要,将键码 113 更改为先前 xmodmap 命令收集的结果

Alt_R 重新分配给 Super_L

xmodmap -e "keycode 113 = Super_L"

确保 X 将其排除在 "mod1" 组之外

xmodmap -e "remove mod1 = Super_L"

这样做之后,由 Super_L 键按触发的任何功能也将由 Alt_R 键按触发。

注意: config.h 中有一个 #define 选项,也允许您切换 Mod 键。

在 DWM 中将两个 Alt 键都用作 Meta 键

使用 xmodmap 将 Alt_L 分配为 DWM 中的辅助 meta 键(前提是已在使用 Mod1Mask (Alt_R))

~/.xinitrc
/usr/bin/xmodmap -e "clear mod5"
/usr/bin/xmodmap -e "keycode 108 = Alt_L"

dwm 栏中字体周围的空间

默认情况下,dwm 的栏在字体大小周围添加 2px 的空间。要更改此设置,请修改以下行

dwm.c
bh = dc.h = dc.font.height + 2;

禁用焦点跟随鼠标

要禁用焦点跟随鼠标的行为,请注释掉 struct handler 定义中的以下行

dwm.c
[EnterNotify] = enternotify,

请注意,此更改可能会导致一些困难;首次单击非活动窗口只会将焦点移至该窗口。要与窗口内容(按钮、字段等)交互,您需要再次单击。此外,如果您有多个显示器,您可能会注意到键盘焦点不会切换到通过单击激活的另一个显示器。

某些窗口的浮动布局

对于某些窗口,例如首选项对话框,这些窗口不应平铺,而应自由浮动。例如,要使 Firefox 的首选项对话框浮动,请将以下内容添加到 config.h 中的 rules 数组

{ "Firefox",     NULL,       "Firefox Preferences",        1 << 8,         True,     -1 },


要获取其他窗口的属性,可以使用程序 xprop。


xprop | awk '
/^WM_CLASS/{sub(/.* =/, "instance:"); sub(/,/, "\nclass:"); print}
/^WM_NAME/{sub(/.* =/, "title:"); print}'

更多信息可以在 dwm 网站上找到。

将 Tilda 与 dwm 一起使用

当添加到所有标签并配置为浮动时,Tilda 效果最佳。为此,请将以下内容添加到 config.h 中的 rules 数组

{ "Tilda",        NULL,       NULL,                         0,              True,       -1 },

使用 -C 选项启动 tilda

$ tilda -C

现在您可以配置 Tilda,以下选项作为建议提供

Font: Clean 9
Appearance: Height: 50%, Width: 70%, Centered Horizontally
Extras: Enable Transparency Level 15
Animated Pulldown: 1500 usec, Orientation: Top
Colors: Built-in Scheme "Green on Black"
Scrolling: Scrollbar is on the left, 2000 lines scrollback
Key Binding: F9

启用下拉动画非常重要,否则每次取消隐藏 Tilda 时,Tilda 都会不断向下跳动,这一定是 dwm 的问题。

截图

安装 scrot 软件包。接下来创建两个脚本

/path/to/scripts/screenshot.sh
#!/bin/sh
mkdir -p /path/to/pics && scrot /path/to/pics/%m-%d-%Y-%H%M%S.png

用于制作截图和

/path/to/scripts/screenshotsel.sh
#!/bin/sh
mkdir -p /path/to/pics && scrot /path/to/pics/%m-%d-%Y-%H%M%S.png --select --line mode=edge

用于制作带有选择框的截图。赋予它们可执行权限。在 config.h 中添加以下内容

static const Key keys[] = {
       ...
       
       { 0,         XK_Print, spawn, SHCMD("/path/to/scripts/screenshot.sh") },
       { ShiftMask, XK_Print, spawn, SHCMD("/path/to/scripts/screenshotsel.sh") },
       
       ...
};

这将截图映射到 Print 键,并将带有选择框的截图映射到 Shift + Print 键。

映射多媒体键

添加到 config.h 的顶部,

#include <X11/XF86keysym.h>

使用多媒体键。现在我们可以将常用任务映射到这些键。

调节音量

安装 pipewire 软件包。现在在 config.h 中,我们可以添加用于静音和音量增大/减小的命令。

static const char *up_vol[]   = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "+10%",   NULL };
static const char *down_vol[] = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "-10%",   NULL };
static const char *mute_vol[] = { "pactl", "set-sink-mute",   "@DEFAULT_SINK@", "toggle", NULL };
...

static const Key keys[] = {
       ...
       
       { 0, XF86XK_AudioMute,        spawn, {.v = mute_vol } },
       { 0, XF86XK_AudioLowerVolume, spawn, {.v = down_vol } },
       { 0, XF86XK_AudioRaiseVolume, spawn, {.v = up_vol } },
       
       ... 
};

调节亮度

安装 brightnessctl 软件包。现在在 config.h 中,我们可以添加用于调暗和调亮屏幕的命令。

static const char *brighter[] = { "brightnessctl", "set", "10%+", NULL };
static const char *dimmer[]   = { "brightnessctl", "set", "10%-", NULL };
...

static const Key keys[] = {
       ...
       
       { 0, XF86XK_MonBrightnessDown, spawn, {.v = dimmer } },
       { 0, XF86XK_MonBrightnessUp,   spawn, {.v = brighter } },
       
       ...
};

自动启动

有一个可用的补丁。它在进入处理程序循环之前运行 ~/.dwm/autostart_blocking.sh~/.dwm/autostart.sh &。可以省略其中一个或两个文件。

故障排除

修复 Java 应用程序行为异常

请参阅 Java#Gray window, applications not resizing with WM, menus immediately closing

修复终端窗口周围的间隙

如果终端窗口外部存在桌面空间的空白间隙,则很可能是由于终端的字体大小。调整大小直到找到关闭间隙的理想比例,或在 config.h 中将 resizehints 切换为 0

这将导致 dwm 忽略来自所有客户端窗口(而不仅仅是终端)的大小调整请求。这种解决方法的不利之处在于,某些终端可能会出现重绘异常,例如重影线和过早的换行等。

或者,如果您使用 st 终端模拟器,您可以应用 anysize 补丁并重新编译 st。

阿拉伯字母整形

dwm 状态栏不支持字母整形。但是,您可以使用 类似 fribidi 的工具,使用 Unicode 阿拉伯文呈现形式-B 应用字母整形。例如,代替

xsetroot -name "لِخَـوْلَةَ أطْـلالٌ بِبُرْقَةِ ثَهْمَـدِ"

使用

xsetroot -name "$(echo "لِخَـوْلَةَ أطْـلالٌ بِبُرْقَةِ ثَهْمَـدِ" | fribidi --nopad)"

参见