Рабочий стол dwm
Это минималистичный рабочий стол, написанный на языке Си и состоящий из 2000 строк кода. В скомпилированном виде это одиночный исполняемый файл размером 49 кбайт. На самом деле это всего лишь оконный менеджер, но его вполне можно считать рабочим столом управляемым с клавиатуры. Для dwm существуют патчи, расширяющие его функционал и находятся они на официальном сайте https://dwm.suckless.org/patches/.
Перезагружать и выключать придется командами:
shutdown -r now
shutdown -p now
Быстрая установка с необходимыми зависимостями:
pkg install drm-kmod xorg dwm alacritty hack-font google-fonts mc librewolf telegram-desktop lite-xl vim transmission-qt keepassxc mpv claws-mail audacious syncthing wget yt-dlp gnupg mixertui flameshot djview qpdfview-qt5 qview zeal xclip xkb-switch fusefs-ntfs pv 7-zip cloc galculator fusefs-sshfs
sysrc mixer_enable="YES"
Скачать порты и пересобрать drm-kmod для отличных от 14.0 релизов:
git clone https://git.FreeBSD.org/ports.git /usr/ports
git -C /usr/ports switch 2025Q1
cd /usr/ports/graphics/drm-61-kmod/
pkg delete drm-61-kmod
make install clean
pkg install drm-kmod
pkg lock drm-61-kmod
Чтобы заработал mc нужно в файл ~/.shrc
дописать одну строчку:
alias mc='mc -u'
Чтобы монтировать удаленные папки по ssh в файл /etc/sysctl.conf добавить строчку:
vfs.usermount=1
Для запуска нужно создать файл ~/.xinitrc
и запускать командой startx
.
# Переключение раскладок по CapsLock
setxkbmap -model pc105 -layout us,ru -variant ,winkeys -option grp:caps_toggle
# Отключить отключение монитора
xset -dpms
# Скринсейвер через час
xset s 3600 3600
syncthing -no-browser > /dev/null &
exec dwm
Если FreeBSD запускается внутри Virtualbox (включите EFI, время в UTC и видео SVGA), то нужно выполнить еще пять команд. В настройках машины выставить адаптер SVGA и не включать 3d ускорение. Так написано в pkg info -D virtualbox-ose-additions
, хотя сам VirtualBox будет ругаться что это неправильная настройка.
pkg install virtualbox-ose-additions
sysrc vboxguest_enable="YES"
sysrc vboxservice_enable="YES"
service vboxguest start
service vboxservice start
А в файл ~/.xinitrc
, в начало, добавить строчек (для Windows 10, VirtualBox-6.1.50 и монитора 1680x1050):
# cvt 1680 945
xrandr --newmode "1680_945_60.00" 130.75 1680 1776 1952 2224 945 948 953 981 -hsync +vsync
xrandr --addmode VGA-0 1680_945_60.00
xrandr --output VGA-0 --mode 1680_945_60.00
# чтобы колесико не работало как кнопка "назад" в браузере
xmodmap -e "pointer = 1 2 3 4 5 6 7 0 0 0 0 0"
Но вот был найден интересный альтернативный способ поиска нужного разрешения (уже после установки VirtualBox-7.1.4). Если окно гостевой системы развернуто в полный экран, то появляется это самое нужное дополнительное разрешение. Достаточно запустить команду xrandr
и оно будет вверху с пометкой +. Тогда вместо трех команд xrandr можно использовать одну:
xrandr --output VGA-0 --mode 1680x944
После запуска системы нужно каждый раз вводить логин/пароль своего пользователя и выполнять команду startx
.
Уже в таком варианте можно пользоваться графическими приложениями. Alt+P запустит dmenu и можно вводить имя приложения для запуска. Alt+Shift+Enter запустит терминал st из пакета sterm. Но терминал st не умеет прокручивать экран вверх чтобы посмотреть вывод команд, поэтому лучше запускать alacritty. Alacritty умеет переходить в режим vim и обратно путем нажатия Ctrl+Shift+Space и осуществлять поиск по нажатию на / в прямом направлении и ? для обратного направления.
Переключаться между рабочими столами можно через Alt+1-9. Выйти из dwm можно нажав Alt+Shift+q. Закрытие приложений обычно выполняется через Ctrl+q, это стандартная комбинация клавиш. Если же у окна нет меню и не реагирует на Ctrl+q, то можно воспользоваться функционалом dwm и нажимать Alt+Shift+c.
Больше информации можно получить на официальном сайте, благо справка там компактная и по существу.
Теперь докрутим dmw до идеала, наложим три патча:
- pertag - позволит иметь на каждом рабочем столе свою раскладку окон
- pwkl - будет запоминать раскладку клавиатуры каждого окна, это нужно для vim
- setstatus - будем выводить время и дату в правом верхнем углу вместо надписи dwm-6.5
cd /root/
mkdir dwm
cd dwm
wget https://dwm.suckless.org/patches/pertag/dwm-pertag-20200914-61bb8b2.diff
wget https://dwm.suckless.org/patches/pwkl/dwm-pwkl-6.2.diff
wget https://dwm.suckless.org/patches/setstatus/dwm-setstatus-6.2.diff
Теперь нам понадобится создать несколько файлов:
- config.h - такой файл имеется в dwm и тут я просто приведу уже немного переделанный, который задает в качестве терминала alacritty, и не растягивает окна калькулятора и торрента.
- config.mk.diff - патч который помогает при первой установке. Возможно и не нужен если более правильно вызывать команды при установке, но пока не ясно какие более правильны.
- install.sh - вызывать при первой установке.
- reinstall.sh - вызывать при изменениях config.h для пересборки.
/* See LICENSE file for copyright and license details. */
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 3; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#eeeeee";
static const char col_cyan[] = "#005577";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
};
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating monitor */
{ "Galculator", NULL, NULL, 0, 1, -1 }, // калькулятор
{ "transmission", NULL, NULL, 0, 1, -1 }, // плавающий transmission
{ "librewolf", "Devtools", NULL, 0, 1, -1 },
//{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
//{ "Gimp", NULL, NULL, 0, 1, -1 },
};
/* Как определить класс окна:
* xprop
* Указатель мыши изменится на перекрестие. Щелкните по окну, класс которого хотите определить.
* Найдите в выводе строку, начинающуюся с WM_CLASS.
* Она будет выглядеть примерно так:
* WM_CLASS(STRING) = "classname", "classname"
* Первое значение — имя экземпляра.
* Второе значение — имя класса окна.
*/
/* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
};
/* key definitions */
/* Mod1Mask = Atl */
/* Mod4Mask = Win */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "alacritty", NULL };
static const char *incrvol[] = { "mixer", "vol.volume=+0.05", NULL };
static const char *decrvol[] = { "mixer", "vol.volume=-0.05", NULL };
static const char *mutevol[] = { "mixer", "vol.mute=^", NULL };
static const char *flameshot[] = { "flameshot", "gui", NULL }; // скриншотер
static const char *calc[] = { "galculator", NULL }; // калькулятор
#define XK_XF86AudioLowerVolume 0x1008ff11
#define XK_XF86AudioMute 0x1008ff12
#define XK_XF86AudioRaiseVolume 0x1008ff13
#define XK_XF86Calculator 0x1008ff1d
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ 0, XK_Print, spawn, {.v = flameshot } }, // скриншотер
{ 0, XK_XF86Calculator, spawn, {.v = calc } }, // калькулятор
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {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|ShiftMask, XK_space, togglefloating, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
TAGKEYS( XK_5, 4)
TAGKEYS( XK_6, 5)
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_q, quit, {0} },
{ 0x0, XK_XF86AudioRaiseVolume, spawn, {.v = incrvol } },
{ 0x0, XK_XF86AudioLowerVolume, spawn, {.v = decrvol } },
{ 0x0, XK_XF86AudioMute, spawn, {.v = mutevol } },
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
};
--- config.mk.orig 2024-08-31 17:56:01.575985000 +0300
+++ config.mk 2024-08-31 17:56:58.462037000 +0300
@@ -7,8 +7,8 @@
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
-X11INC = /usr/X11R6/include
-X11LIB = /usr/X11R6/lib
+X11INC = ${PREFIX}/include
+X11LIB = ${PREFIX}/lib
# Xinerama, comment if you don't want it
XINERAMALIBS = -lXinerama
@@ -16,7 +16,7 @@
# freetype
FREETYPELIBS = -lfontconfig -lXft
-FREETYPEINC = /usr/include/freetype2
+FREETYPEINC = ${PREFIX}/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
#MANPREFIX = ${PREFIX}/man
#!/bin/sh
DST1=/usr/ports/x11-wm/dwm
DST2=$DST1/work/dwm-6.5
SRC=/root/dwm
cd $DST1
make patch
cd $DST2
patch < $SRC/dwm-pertag-20200914-61bb8b2.diff
patch < $SRC/dwm-pwkl-6.2.diff
patch < $SRC/dwm-setstatus-6.2.diff
patch < $SRC/config.mk.diff
cp $SRC/config.h $DST2/
make deinstall
make install
#!/bin/sh
DST1=/usr/ports/x11-wm/dwm
DST2=$DST1/work/dwm-6.5
SRC=/root/dwm
cd $DST1
#make deinstall
cp $SRC/config.h $DST2/
touch $DST2/config.h
make restage reinstall
Теперь выполняем команды чтобы пересобрать dwm
chmod +x install.sh
chmod +x reinstall.sh
И перезагружаемся чтобы запустился новый dwm shutdown -r now
.
Теперь все готово для того чтобы в правом верхнем углу выводить время вместо dwm-6.5. Создаем скрипт и добавляем ему бит исполнимости:
#!/bin/sh
while true; do
sleep 10
dwm -s "$(date "+%e %b %a %H:%M")"
done
А в .xinitrc добавляем строчку перед exec dwm:
dwm_status &
Донастроим alacritty чтобы был получше шрифт в котором нельзя спутать буквы.
Что еще полезного можно дописать в .xinitrc - замедлить движение мыши, но это зависит от модели. Ниже приведен пример для Razer Viper Mini. Добавлять нужно перед `exec dwm`.
# Мышка
array="
Razer Razer Viper Mini Mouse
Razer Razer Viper Mini
Razer product 0x008a Mouse
Razer product 0x008a
vendor 0x1532 product 0x008a Mouse
vendor 0x1532 product 0x008a
vendor 0x1532 Razer Viper Mini Mouse
vendor 0x1532 Razer Viper Mini
"
IFS="
"
for i in $array
do
echo "test $i"
LINE=$(xinput list | grep "$i.*pointer")
if [ ! -z $LINE ]
then
echo $LINE
MOUSE_ID=$(echo $LINE | sed 's/.*id=//' | sed 's/\t.*//')
echo $MOUSE_ID
xinput set-prop $MOUSE_ID 296 -1.0
echo xinput set-prop $MOUSE_ID 296 -1.0
fi
done
Ну а чтобы сбрасывать клавиатуру Axeman, чтобы работали мультимедийные клавиши, нужно создать скрипт:
#!/bin/sh
echo ""
sleep 1
DEV=$(usbconfig | grep SEMICO | sed 's/^\(.......\).*/\1/')
if [ ! -z $DEV ]; then
echo reset keyboard \"$DEV\"
usbconfig -d $DEV reset
fi
# В /boot/loader.conf добавить
# hw.usb.usbhid.enable=1
Чтобы победить тиринг на Nvidia создаем файлик:
Section "Screen"
Identifier "Screen0"
Device "Card0"
SubSection "Display"
Modes "1680x1050"
EndSubSection
Option "metamodes" "nvidia-auto-select +0+0 { ForceFullCompositionPipeline = On }"
EndSection
Чтобы подключать ntfs-диски нужно дописать в /boot/loader.conf
fusefs_load="YES"
Это модуль ядра и нужно либо перезагрузиться, либо набрать kldload fusefs
.
Полезные докрутки
EDITOR=vim; export EDITOR
PAGER='less -i'; export PAGER
alias l='ls -l -a -h'
Чтобы включить полный хинтинг шрифтов нужно создать файл
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
<!-- Включить сглаживание и хинтинг -->
<match target="font">
<edit name="antialias" mode="assign"><bool>true</bool></edit>
<edit name="hinting" mode="assign"><bool>true</bool></edit>
<edit name="hintstyle" mode="assign"><const>hintfull</const></edit>
<!--edit name="hintstyle" mode="assign"><const>hintmedium</const></edit-->
<!--edit name="hintstyle" mode="assign"><const>hintslight</const></edit-->
<edit name="rgba" mode="assign"><const>rgb</const></edit>
<edit name="lcdfilter" mode="assign"><const>lcddefault</const></edit>
</match>
</fontconfig>
Обновить кеш шрифтов командой fc-cache -fv
и перезапустить X-сервер.