DWM: Suckless переход с GNOME. Часть 1

от
Linux    dwm, xorg, archlinux

В этой статье речь пойдет о настройке DWM (Dynamic Window Manager). Это простой тайловый оконный менеджер от сообщества suckless.org, который отличается от своих аналогов простотой и легковесностью. И пусть вас не пугает факт того, что настройка DWM происходит путем редактирования исходного кода - для этого не требуется никаких навыков программирования (но потребуется немножко усидчивости и желание вникнуть).

Статья будет разбита на две части. В первой (этой) речь пойдет о базовой установке и настройке DWM и Xorg до состояния "юзабельно", во второй пойдет речь о цветной строке статуса, хоткеях, скриптах, а так же решении частых проблем. В процессе чтения статьи вы углубите свои знания про Xorg и про внутренности Linux. Однако, эта статья может не подойти пользователям, "которые только что поставили Ubuntu".

Because dwm is customized through editing its source code, it's pointless to make binary packages of it. This keeps its userbase small and elitist. No novices asking stupid questions. Кстати, в данной статье настройка будет происходить на дистрибутиве Archlinux, поэтому пользователям apt/rpm-based дистров нужно будет поискать упомянутные в статье пакеты под свои дистры.

Установка
DWM распространяется в виде исходников, поэтому просто клонируем репозиторий https://git.suckless.org/dwm. Убедитесь, что у вас установлена группа пакетов base-devel.
Собираем пакет
  1. make
и устанавливаем с помощью
  1. sudo make install

Запуск
Есть два способа запуска DWM: с помощью startx и с помощью Display Manager. Мы будем использовать первый способ, т.к. это позволит нам запустить дополнительные скрипты и определить переменные окружения
Создадим файл ~/.xinitrc
  1. #!/usr/bin/bash
  2. exec dwm
теперь запустим startx из tty. По умолчанию, DWM имеет только статусбар вверху, с 9 рабочими столами (они называются "теги", и их отличие от рабочих столов в том, что одно окно может быть помечено сразу несколькими тегами), а так же надписью dwm-%версия% справа. Позднее, мы заменим эту надпись на красивый статусбар с цветными иконками-эмодзи.
Основная идея тайлового оконного менеджера в том, что в нем окна расположены в стеке, и окно на вершине стека является основным, master окном, и оно занимает наибольшее пространство. На самом деле, это зависит от раскладки (оконного менеджера, не клавиатуры :кек2: ), но в дефолтной раскладке DWM все именно так. И полезное сочетание клавиш, которое вам сейчас понадобится - alt+Shift+q, чтобы выйти из dwm и открыть терминал в tty (по дефолту, DWM использует st в качестве терминала, и если у вас его нет, то вы не сможете перейти к настройке)

Настройка
Настрока производится путем редактирования файла config.h. Откройте его в вашем любимом редакторе vim.

Первое что мы сделаем - увеличим размер рамки окна, чтобы было видно какое окно сейчас активно. за это отвечает переменная borderpx, по умолчанию равна 1. Я использую 4 (здесь и далее я буду приводить значения, которые использую сам, вы можете использовать подходящие вам).

Массив colors[] отвечает за цвета рамок окон. Сейчас нам это не так важно, разбор пойдет во второй части

Массив tags[] отвечает за названия тегов. По-умолчанию, теги называются цифрами от 1 до 9, и их можно тут переименовать. Например, { "web", "media", "dev", "term", ... };

Массив rules[] отвечает за правила, на каком теге какое окно должно появляться. Примеры для Gimp и Firefox уже есть в коде. Обратите внимание на столбец tags mask. Чтобы окно запускалось на i-ом теге, туда нужно вписать 1 << i-1, то есть для того чтобы Telegram запускался на 2 теге, нужно вписать
  1. { "Telegram", NULL, NULL, 1 << 1, 0 },
Чтобы получить значение столбца class, запустите команду
  1. xprop | grep WM_CLASS
и нажмите мышкой на нужное окно. У меня, например, Firefox называется firefox, поэтому пример в исходном коде не работает, нужно переименовать

Прокрутите до строчки /* key definitions */. Замените в строчке
  1. #define MODKEY Mod1Mask
1 на 4, чтобы в качестве клавиши-модификатора для комбинаций использовать super (win) вместо alt.

Далее, под комментарием /* commands */ указаны команды, на которые позже мы повесим хоткеи. Команды - это массив char (массив строк), в которой последний аргумент должен быть всегда NULL. Массив представляет собой саму программу (первым элементом), и аргументы, передаваемые программе. Обратите внимание: аргументы передаются не в bash, поэтому вот такая конструкция
  1. static const char *show_waifu[] = { "eog", "~/Pics/megumin.png", NULL };
работать не будет, т.к. в bash это будет эквивалентно вводу в терминале
  1. eog "~/Pics/megumin.png"
то есть, ~ на $HOME не будет заменено. Если вам нужна эта фича - вы можете закинуть в $PATH скрипты и указать их уже в config.h.
Замените в переменной termcmd st на ваш терминал (кстати, во второй части я буду использовать xterm).
Кроме того, вы можете объявить тут свои команды, просто добавив свои переменные. Например:
  1. static const char *connect_wifi[] = { "nmcli", "con", "up", "wifi-home", NULL };

Далее идет самое интересное - массив keys[], в котором можно назначить хоткеи на указанные выше команды.
Первым аргументом идет модификатор. Например, MODKEY (super), 0 (без модификатора), MODKEY|ShiftMask (super+shift)
вторым аргументом идет кнопка. С буквами понятно - XK_b, XK_j, XK_e. Для более сложных кнопок (регулировка громкости, яркости и т.д) вам перед массивом keys нужно подключить библиотеку из пакета xorgproto:
  1. #include <X11/XF86keysym.h>
Чтобы узнать названия кнопок, посмотрите содержимое /usr/include/X11/XF86keysym.h. Либо запустите xev (пакет xorg-xev) и нажмите нужную вам кнопку, и посмотрите вывод.
кроме функции spawn, которая запускает команду, есть и другие (как они работают, можно узнать, понажимав соответствующие хоткеи).
togglebar - скрывает/показывает верхнюю панель
focusstack - i=+1 делает активным следующее окно, i=-1 - предыдущее
setmfact - увеличивает/уменьшает размер активного окна
zoom - ставит текущее окно на вершину стека
view - переключает между 2 последними тегами
killclient - отправляет текущему окну SIGTERM
quit - закрывает DWM и все окошки без предупреждения
еще тут же описаны хоткеи для переключения между тегами. Опишу их тут понятным языком
mod+[1-9] - переключение на соответствующий тег
mod+0 - просмотр всех тегов (показать все окна)
mod+shift+[1-9] - отправить текущее окно на тег
mod+ctrl+[1-9] - просмотр текущего тега и еще нескольких. Например, mod+ctrl+2, mod+ctrl+3 покажет текущий тег, а еще второй и третий.
mod+shift+0 - поставить все теги на текущее окно. То есть, это окно будет отображаться на всех тегах!
mod+shift+ctrl+[1-9] - пометить окно несколькими тегами (частный случай предыдущего пункта
Таким образом, в отличие от рабочих столов, вы можете как отображать окна на нескольких тегах, так и просматривать все окна, принадлежащие отмеченным тегам!.
mod+, и mod+. - переключение между мониторами
mod+shift+, и mod+shift+. - перекинуть текущее окно на следующий/предыдущий монитор
Кстати, каждый монитор имеет свое пространство тегов, и переключение тегов происходит только на активном мониторе!
Не спешите захламлять config.h хоткеями на все подряд!. Во второй части статьи мы настроим sxhkd для этой цели. Однако, пару вещей мы все же поменяем.

Rofi (рофи, а не рофл, если у кого-то шрифт кривой :кек2: )
rofi - хороший аналог dmenu (панельки для запуска команд). В отличие от dmenu, rofi имеет больше возможностей для кастомизации, имеет темы, и умеет сканнировать .dekstop файлы из /usr/share/applications и .local/share/applications. dmenu же умеет исполнять файлы только из $PATH. А еще оно умеет переключать окна. Не очень полезная фича, но вдруг нужно.
Установим пакет rofi, создадим конфиг
  1. rofi -dump-config > .config/rofi/config.rasi
Отредактируйте этот файлик на свое усмотрение. Я изменил только строчки modi (список режимов и их порядок), и width (25 хватит всем), а еще включил иконки приложений. Не забудьте раскомментировать.
  1. modi: "drun,run,window";
  2. width: 25;
  3. show-icons: true;
drun - режим выбора .desktop приложений. run - аналог dmenu, запуск приложений из $PATH. window - переключение между окнами. Запустите rofi-theme-selector и выберите тему, которая вам нравится. Я использую тему dmenu, в этом случае rofi отображается поверх статусбара DWM

Xterm
Это стандартный терминал для Xorg. Однако, по-умолчанию у него белый фон и черный шрифт, все очень мелкое, и не работает копирование через ctrl+insert. Исправим:
Открываем/создаем файл ~/.Xresources. Мой конфиг выглядит так:
  1. XTerm.vt100.foreground: white
  2. XTerm.vt100.background: black
  3. XTerm.vt100.faceName: Droid Sans Mono:size=12:antialias=true
  4. XTerm.vt100.font: 7x13
  5.  
  6. xterm*selectToClipboard: true
  7. xterm*VT100.Translations: #override \
  8.                 Shift <Key>Insert:    insert-selection(SELECT) \n\
  9.                  Ctrl <Key>Insert:     copy-selection(SELECT) \n\
Чтобы узнать, как "в этом файле" называется шрифт, который вы хотите использовать, используйте fc-list. Например,
  1. fc-list | grep Droid
в ~/.xinitrc (до запуска DWM) впишите строчку
  1. xrdb ~/.Xresources
Кроме того, настроим дополнительные параметры отображения шрифтов в .Xresources:
  1. Xft.autohint: 0
  2. Xft.lcdfilter:  lcddefault
  3. Xft.hintstyle:  hintfull
  4. Xft.hinting: 1
  5. Xft.antialias: 1
  6. Xft.rgba: rgb
Если у вас HiDPI, допишите так же строчку
  1. Xft.dpi: 120
и измените этот параметр согласно вашим предпочтениям. 120 подходит для 1920x1080. Для применения изменений, перезапустите Xorg (выйдите из DWM и запустите startx)

Возвращаемся в config.h
Добавим 2 переменные там, где у вас указаны команды
  1. static const char *rofi[] = { "rofi", "-show", "drun", NULL };
  2. static const char *termcmd[] = { "xterm", NULL };

termcmd в массиве keys[] уже есть, добавим rofi на super+r:
  1. { MODKEY, XK_r, spawn, {.v=rofi } },
Пересоберем и установим dwm снова (это нужно делать при любом изменении config.h):
  1. sudo make clean install
нажмем Win+Shift+Q (или что там у вас), запустим startx и, если вы все сделали правильно, то при нажатии Win+Shift+Enter запустится xterm, а при win+r - rofi, откуда вы сможете запустить любое приложение.

Скриншоты
А вот не покажу! :blabla: Скриншоты вы будете делать сами! А чтобы их делать, нужен flameshot. Конечно, вы можете использовать любую другую программу, и не читать эту секцию. А вот те кто будут использовать, читаем!
устанавливаем пакет flameshot. в DWM flameshot будет работать если
а) он запущен до DWM в фоне
б) DWM запущен с dbus

Вариант а (для тех кто будет вторую часть статьи читать):
~/.xinitrc:
  1. flameshot &
Вариант б (даже если вы используете вариант а, все равно сделайте, не только flameshot это требует):
~/.xinitrc:
  1. exec dbus-launch --exit-with-session dwm

а затем, в обоих случаях, config.h:
  1. static const char *flameshot[] = { "flameshot", "gui", NULL };
  2.  
  3. static Key keys[] = {
  4.     0, XK_Print, spawn, {.v=flameshot } },
  5. ...

Pereklyuchenie raskladki, или я уже в панике нафлудил во все чаты транслитом:
~/.xinitrc:
  1. setxkbmap -layout us,ru -option "grp:win_space_toggle"
посмотреть доступные комбинации - man xkeyboard-config

Обои
Устанавливаем feh, в .xinitrc пишем:
  1. feh --bg-scale ~/Wallpapers/megumin.png

java.lang.НифигаНеВидноError
При попытке запуска окон приложений java AWT (Idea, TLauncher, да что угодно) они будут либо серые, либо ничего не отображать. Эта проблема касается всех non-reparenting WM. Установите пакет wmname и пропишите в .xinitrc:
  1. export _JAVA_AWT_WM_NONREPARENTING=1
  2. export AWT_TOOLKIT=MToolkit
  3. wmname LG3D

На этом все! В следующей статье:
1) Выставим тему и шрифты
2) Заюзаем sxhkd для хоткеев, чтобы не перекомпиливать DWM каждый раз
3) Сделаем очень красивый статусбар с иконками
dwm_bar.png
4) Научимся применять патчи к dwm
5) Для желающих, поставим трей