# Оконный менеджер bspwm
hugeping(ping,1) — All
2022-05-29 12:27:46


# Эксперименты с оконными менеджерами

Я люблю экспериментировать с рабочей средой в Linux. Редакторы, оконные менеджеры, способы создания документации и т.д. Думаю, меня гнали по этому пути любопытство и жажда эксперимента (в том числе и над собой). Помню как в своём первом Linux (KSI Linux) мне решительно не понравились gnome 2 и kde 2. Тогда же я обнаружил прекрасный WindowMaker и процесс был запущен.

Я перепробовал массу оконных менеджеров. В разные периоды меня кидало от минималистических wm до полновесных рабочих столов. Но фундаментально стиль работы не менялся. "Вынос мозга" случился после ion3. Очень достойный тайловый менеджер (написанный харизматичным автором) дал новые ощущения и я подсел! Стоит ли говорить, что на ion3 я не остановился? Тайловые менеджеры тогда набирали популярность и я пробовал всё, что выглядело интересным: dwm, wmii, musca, xmonad, ratpoison, i3wm... Обычные wm я тоже пробовал, но после выхода gnome 3 интерес к экспериментам угас, так как gnome3 в качестве обычного десктопа мне очень понравился.

# Золотой набор

После выхода gnome3 я постепенно успокоился и у меня сформировался свой "золотой" набор.

- Для работы: i3wm (+dmenu).
- Для дома (компьютер, который использую не только я): gnome3.

i3wm отличный статический тайловый wm, который готов к работе сразу же после установки. i3wm можно назвать идейным наследником ныне почившего wmii, который мне тоже очень нравился.

Интересно что wmii был создан с оглядкой на acme! Только вот про Plan 9 и acme я узнал гораздо позже.

Кстати, раз уж зашёл разговор про Plan 9... В rio ("оконном менеджере" Plan 9) при абсолютной аскетичности сохраняется высокая практичность окружения. Я пытался сделать подобие rio на основе fvwm2 (с частичным успехом), но оставил эту попытку. Слишком уж разный "путь" у Linux и Plan 9. Например, в rio ты заранее создаёшь окна в которых запускаются программы, но программа не создаёт окон сама! Интересно, что небезызвестный Drew DeVault делал эмуляцию такого поведения в своём "клоне" wio: https://drewdevault.com/2019/05/01/Announcing-wio.html Но всё это выглядит как подделка, если честно. Так что я оставил Plan 9 "плановое", а Linux - "линуксовое".

# Новое знакомство: bspwm

Многие годы я использовал i3wm и gnome3 и до сих пор считаю это лучшим "набором", который могу рекомендовать всем. Но время от времени я продолжал экспериментировать. Например, познакомился с cwm. В "наборе" своё место занял tmux. И вот, на днях, решил посмотреть на bspwm. Мне этот оконный менеджер настолько понравился, что я решил написать эту заметку. Говорю сразу -- достойный wm! Для любопытных программистов. :)

# К сути

Обычно упоминают что bspwm работает с окнами как с бинарным деревом. Это первая строчка в man bspwm и, честно говоря, с чисто практической точки зрения для меня это мало что значит. Мне же хочется сделать упор на "практике". А с практической точки зрения "суть такова"(c):

- bspwm конфигурируется и управляется только одним способом: утилитой bspc;
- чтобы управлять bspwm с клавиатуры используется внешний "демон" горячих клавиш (обычно sxhkd) из которого вызывается bspc;
- bspwm не поддерживает никаких панелей и прочих "свистелок". Но с помощью bspc вы можете слушать нужные вам события и делать что хотите;
- bspwm выглядит сбалансированным и отполированным как и i3wm. Многие вещи сделаны "интуитивно-верно".

То-есть, мы видим вполне себе тот самый Unix-way да ещё и в качественном исполнении. Вообще, когда я начинал играться с bspwm меня пугала перспектива писать портянки на shell, как это часто бывает. Но... Обо всём по порядку...

# Конфиг bspwm

Конфигурация bspwm это просто shell скрипт в котором в основном присутствуют вызовы bspc. Я приведу фрагменты своего конфига для иллюстрации. Интересно, что файл получается простым, потому что в нём не заданы горячие клавиши. Только конфигурация самого wm!

#! /bin/sh

pgrep -x sxhkd > /dev/null || sxhkd & # запуск демона горячих клавищ
pgrep -x panel > /dev/null || panel & # запуск панельки (об этом - ниже)

setxkbmap -layout "us,ru" -variant "winkeys" -option "grp:caps_toggle,compose:ralt,grp_led:scroll" # раскладка

xsetroot -cursor_name left_ptr # курсор вместо символа X

bspc monitor -d 1 2 3 4 5 6 7 8 9 0 # рабочие столы

bspc config removal_adjustment false # при удалении окна не ребалансить
bspc config swallow_first_click true # первый клик не идёт в приложение

bspc rule -a librewolf desktop='^4' # пример правила
bspc rule -a Xdialog state=floating # ещё пример правила

bspc config pointer_modifier mod4 # ресайзим и таскаем окна мышкой
bspc config pointer_action1 move
bspc config pointer_action2 resize_side
bspc config pointer_action2 resize_corner
bspc config focused_border_color '#ff0000' # рамка активного окна поярче

На самом деле это практически весь конфиг, кроме каких-то локальных нюансов.

# Конфиг sxhkd

Теперь, sxhkd. На самом деле вам не нужно будет писать этот файл с нуля, можно взять типовой из share/doc/bspwm/examples и начать использовать его. В качестве примера, приведу фрагменты своей конфигурации:

XF86AudioLowerVolume
        amixer -q sset Master 10%-

XF86AudioRaiseVolume
        amixer -q sset Master 10%+

# terminal emulator
super + Return
        st

# focus the node in the given direction
super + {_,shift + }{h,j,k,l}
        bspc node -{f,s} {west,south,north,east}

Тут тоже есть простота. Она состоит в том, что ничего кроме горячих клавиш и реакций на них (в виде запуска утилит) в конфиге нет.

# Панелька

В примерах bspwm есть панелька на основе shell скрипта и lemonbar. Я не люблю портянки на shell (хотя и умею их писать и понимать) поэтому я изучил как она работает и написал свою...

lemonbar рисует саму панель, но содержимое панели приходит в виде stdin. И вот наша задача предоставить информацию для lemonbar в виде текста оформленного определённым образом.

Что за информация? Например: информация о номерах десктопов, активном десктопе, режиме окна и так далее. Эту информацию нам может предоставить bspc. В режиме bspc subscribe report мы получаем события этого оконного менеджера. Но кроме десктопов нам нужны ещё: часы, батарея, раскладка. Ну и так далее, по вкусу.

Панелька из примеров делает fifo и направляет в эту fifo вывод различных утилит, которые запущены в режиме монитора (выводят строчку в stdout при изменении информации). Например, xtitle -s. Далее, скрипт на sh читает из fifo общий поток, парсит его и даёт на вход lemonbar. Я подумал, что это полотно легко переписать на go (go-рутиты идеально здесь подходят). Я приведу фрагмент того, что у меня получилось:

func read(fname string) string {
// читает файл и возвращает строку
// ...
}

// запускает процесс и отправляет его вывод в канал
func cmd_reader(out chan<- string, prog string, args ...string) {
	cmd := exec.Command(prog, args...)
	pipe, _ := cmd.StdoutPipe()
	reader := bufio.NewReader(pipe)
	cmd.Start()
	for {
		output, _, err := reader.ReadLine()
		if err != nil || err == io.EOF {
			break
		}
		out <- string(output)
	}
}
// парсим информацию о десктопе
func bsp_parse(item string) string {
	c := item[0:1]
	var U, F, B string;
	U = "#144b6c"
	nam := item[1:]
	switch c {
	case "f": // free desktop
		F = "#737171"
		B = "#333232"
		// далее F= B= в каждом case (FoOuU) пропущено для краткости
	case "F": // active free desktop
	case "o": // occupied desktop
	case "O": // focused occupied
	case "u": // urgent
	case "U": // focused urgent
	case "L","T","G":
		F = "#ffffff"
		B = "#333232"
		return fmt.Sprintf("%%{F%s}%%{B%s} %s %%{B-}%%{F-}", F, B, nam)
	default:
		return ""
	}
	return fmt.Sprintf("%%{F%s}%%{B%s}%%{U%s}%%{+u}%%{A:bspc desktop -f %s:} %s %%{A}%%{B-}%%{F-}%%{-u}",
		F, B, U, nam, nam)
}

func main() {
	bspc_in := make(chan string)
	xtitle_in := make(chan string)
	mail_in := make(chan string)
	xkb_in := make(chan string)
	go cmd_reader(bspc_in, "bspc", "subscribe", "report") // десктопы
	go cmd_reader(xtitle_in, "xtitle", "-s") // заголовок окна
	go cmd_reader(mail_in, "checkmail", "-s") // новая почта
	go cmd_reader(xkb_in, "xkbmon") // раскладка
	var bspc, bat, clock, mail, xtitle, xkb string;
	for {
		select {
		case bspc = <-bspc_in:
		case xtitle = <-xtitle_in:
		case mail = <-mail_in:
		case xkb = <-xkb_in:
		case <-time.After(time.Second * 30):
		}
		if bspc == "" {
			continue
		}
		bat = read("/sys/class/power_supply/BAT1/status")
		bat += ":" + read("/sys/class/power_supply/BAT1/capacity")
		curt := time.Now()
		clock = curt.Format("02-01-2006 Mon 15:04")
		bsp := strings.Split(bspc, ":")
		desk := ""
		for _, item := range bsp {
			desk += bsp_parse(item)
		}
		fmt.Printf("%%{l}%s%%{c}%s%%{r}%s %s%% %%{F#000000}%%{B#ffffff}%s%%{B-}%%{F-}[%s]\n", desk, xtitle, mail, bat, clock, xkb)
	}
}

Программа совсем простая, написанная под конкретную ситуацию как скрипт. Конечно, можно было взять готовую панель. Можно было взять вместо lemonbar что-то другое. Но мне лично проще, когда я понимаю происходящее полностью и могу это контролировать. Да, монитор раскладки я написал на C. Тоже небольшая программка.

# Особенности использования

В целом, bspwm из коробки вполне себе годен, но мне не хватало некоторых вещей. На этих нюансах остановлюсь подробнее.

Если в запущенном wm просто начать запускать терминал по super + Return, то заполняться пространство будет примерно так (что-то вроде спирали Фибоначчи):

+----------+----------+
|          |          |
|          |          |
|          |          |
+----+-----|          |
|    |     |          |
|    +--+--+          |
|    |  +--+          |
+----+--+--+----------+

При этом, если закрыть какое-то из окон, то оставшиеся окна автоматически "сбалансируются". Это напоминает поведение динамических wm (которое мне не нравится). К счастью, в bspwm есть настройка: bspc config removal_adjustment false.

Кроме того, bspwm позволяет предварительно выбрать следующую позицию для разделения окна. Эта фича висит на хоткеях но я сделал для себя отдельно запуск терминала под текущим терминалом:

super + shift + Return # запуск "вертикально"
        bspc node -p south; \
        st

Таким образом, я могу быстро создавать терминалы в одном столбце:

+----------+----------+
|          |          |
+----------+          |
|          |          |
+----------+     2    |
|    1     |          |
+----------+          |
|          |          |
+----------+----------+

Далее, выбрав определенный терминал хоткеями или мышкой можно максимизировать его на всё пространство (режим монокля, по умолчанию super + m) или поменять его (1) с самым большим окном (2) примерно так, как это сделано в dwm. (Для этого используется хоткей super + g).

# swap the current node and the biggest window
super + g
        bspc node -s biggest.local
# в дефолтном примере было: bspc node -s biggest.window
# в таком режиме большое окно выбиралось со всех десктопов
# что было неудобно
# заменил на .local

Мне ещё не хватало возможности растянуть терминал вертикально:

+----------+----------+
+----------+          |
+----------+     2    |
|          |          |
|    1     |          |
|          |          |
|          |          |
+----------+          |
+----------+----------+

Я смог добиться такого поведения, правда, небольшим хаком:

super + v
	bspc node north#north#north#north#north#north -z top 0 -2000; \
	bspc node north#north#north#north#north -z top 0 -2000; \
	bspc node north#north#north#north -z top 0 -2000; \
	bspc node north#north#north -z top 0 -2000; \
	bspc node north#north -z top 0 -2000; \
	bspc node north -z top 0 -2000; \
	bspc node -z top 0 -2000; \
	bspc node -z bottom 0 2000

Дело в том, что окно не может быть расширено, если над ним есть несколько максимально суженных окон. Возможно, это баг bspwm. Возможно, есть более элегантное решение, но текущее тоже работает!

Всё эти хитрости помогли мне заменить табы и стек окон в i3wm.

Ещё одна штука, которая мне нравилась ещё по Plan9 -- возможность именовать окна по ситуации. В случае bspwm, правда, именуем не окна, а рабочие столы. Я написал скрипт, который вызывает Xdialog (Xdialog --stdout --under-mouse --inputbox "Window name" 0 0) и просит имя для текущего десктопа. Потом делает: bspc desktop focused --rename имя. Повесил на хоткей и всё -- можно именовать!

Ещё один пример гибкости простых решений. Скрипт который делает все окна на 9м десктопе "плавающими". За основу был взят пример с Arch wiki, но немного доработан (отслеживается не только создание, но и перемещение node):

#!/bin/bash

# change the desktop number here
FLOATING_DESKTOP_ID=$(bspc query -D -d '^9')

bspc subscribe node_add node_transfer | while read -a msg ; do
    if [ "${msg[0]}" = "node_transfer" ]; then
        desk_id=${msg[5]}
        wid=${msg[3]}
    else
        desk_id=${msg[2]}
        wid=${msg[4]}
    fi
    [ "$FLOATING_DESKTOP_ID" = "$desk_id" ] && bspc node "$wid" -t floating
done

# Хакерская штучка

bswpm создаёт впечатление добротной и отполированной хакерской "штучки". Например, по умолчанию super + tab работает именно так как нужно! Переключаясь между последними двумя рабочими столами. Работа с окнами просто реактивная. Изменение размера окон мышкой работает тоже отлично. Также мышкой можно перемещать тайловые окна, меняя их местами. Много мелочей, которые незаметны, когда они работают "правильно". По стабильности на данный момент тоже нареканий нет. Кстати, параллельно с bspwm я также посмотрел herbstluftwm (никак не могу выучить название этого wm!). Но ощущения "отполированности" с этим wm у меня не возникло, хотя тоже -- неплохой тайловый менеджер и подход к управлению/конфигурированию очень похож.

# Вместо заключения

Функционально i3wm и bspwm близки. Но i3wm предоставляет большинство функций "из коробки". С другой стороны, в bspwm благодаря простоте устройства многие вещи выглядят менее "захламлёнными" и "раздражающими". То что есть -- работает предсказуемо и отлично. Это для меня уже привычная характеристика для простых инструментов.

И если i3wm я могу рекомендовать всем без исключения программистам, то bspwm уже скорее для любопытных минималистов. Но, как мне кажется, любопытство -- одно из наших основных (программистских) качеств. Ведь правда? :) Ну а на моём рабочем ноутбуке bspwm уже заменил i3wm.

# Re: Оконный менеджер bspwm
vvs(ping,12) — hugeping
2022-05-29 16:06:12


"Каждый заблуждается в меру своих возможностей" (C) х/ф "Чародеи"

Лишний раз убеждаюсь, как сильно вкусы зависят от личных интересов. Настолько по-разному можно относиться к одному и тому же.

Я вообще не люблю оконные системы и до сих пор предпочитал tmux. Gnome 3 использую фактически только ради его терминала. Когда недавно открыл довольно мощный калькулятор в Emacs, то тут же стал всё больше вещей делать там, хотя до сих пор я предпочитал Vim в качестве редактора. А вчера дошёл до того, что заявил, что в каждом настоящем текстовом редакторе должен быть Sokoban :) Даёшь INSTEAD для emacs!

P.S. А ты объектно ориентированное программирование в bash видел? После этого я убедился, что имеет значение даже не столько сам язык, сколько воображение программиста. К слову о пользе теоретической информатики. Вот не могу вспомнить, где я это впервые увидел (https://github.com/kristopolous/TickTick ?), но идея простая: простой препроцессор, сам же написанный на bash и вычисление с помощью eval. И можно писать свой DSL хоть на Brainfuck. Это напоминает deep embedding в типизированных языках :)

# Re: Оконный менеджер bspwm
hugeping(ping,1) — vvs
2022-05-29 17:14:12


Да я тоже люблю: tmux, emacs, acme и vim тоже пользовался. И всё это может сосуществовать с любым wm.

vvs> P.S. А ты объектно ориентированное программирование в bash видел?

Не, не видел. На баше я очень много писал, но я его не люблю. За нечитаемость, за неочевидные нюансы экранирования и подстановок. Особенно после того, как увидел rc из Plan9. Так что сложные вещи я стараюсь на нём не писать.

> сам же написанный на bash и вычисление с помощью eval.

Вот это кошмар с точки зрения безопасности :) Любая малейшая ошибка и твой скрипт начинает выполнять код, поданный извне. Конечно, для быта он годится.

# Re: Оконный менеджер bspwm
vvs(ping,12) — hugeping
2022-05-29 21:13:12


hugeping> Да я тоже люблю: tmux, emacs, acme и vim тоже пользовался. И всё это может сосуществовать с любым wm.

Моя проблема в том, что я так и не нашёл себе никакого полезного применения для оконных систем. А для emacs и tmux нашёл. Потому и говорю о зависимости вкусов от интересов :)

hugeping> Вот это кошмар с точки зрения безопасности :) Любая малейшая ошибка и твой скрипт начинает выполнять код, поданный извне. Конечно, для быта он годится.

Как и для любого самомодифицирующегося кода. Можно, конечно, сначала фильтровать перед выполнением, но это отдельная проблема :) А в принципе надо различать вещи для дома и для промышленного применения. Ну вот ты как-то даже сравнивал Linux с Plan 9 :) А я просто привел пример для стимуляции воображения. Вообще, чем я больше узнаю, тем больше думаю, что теория - это вовсе не модель законов природы, а просто мощное средства для развития воображения: как можно на привычные вещи смотреть по-разному ;)

# Re: Оконный менеджер bspwm
btimofeev(tavern,13) — hugeping
2022-05-30 06:57:48


hugeping> - Для работы: i3wm (+dmenu).
hugeping> - Для дома (компьютер, который использую не только я): gnome3.

А что мешает дома для разных пользователей использовать разные wm?

# Re: Оконный менеджер bspwm
hugeping(ping,1) — btimofeev
2022-05-30 10:40:57


btimofeev> А что мешает дома для разных пользователей использовать разные wm?

Банальная лень. Так просто включил - побраузил - выключил. (Комп всегда в режиме suspend to ram). И таких "заходов" в течении дня -- масса. :)

А так, можно конечно. Но мне gnome3 в целом нравится, так что я не сильно страдаю. :)

# Re: Оконный менеджер bspwm
old.pc(ping,44) — hugeping
2022-05-30 22:21:25


> i3wm отличный статический тайловый wm, который готов к работе сразу же после установки. i3wm можно назвать идейным наследником ныне почившего wmii, который мне тоже очень нравился.

Честно говоря, i3wm не производит впечатления "готового из коробки". По-моему, там даже обоины из коробки нет, и запустив его, видишь "серую рябь" иксов: хотя могу с кем-то ещё путать. Но в любом случае, там ни трея нет из коробки, ни других привычных вещей. Вот awesome за примерно 13 лет довольно частого использования я только неделю назад полез в его конфиг (разве что с выходом 4.0 появились титлбары, мне сказали, как их отключить, и я их всегда отключал, не вникая в конфиг), а так он был действительно "готов из коробки"

Кроме того, i3 почему-то прожорливый. Если на p2 с 64 mb ram awesome, icewm и cwm просто летают, то i3 там ощутимо тормозит.

# Re: Оконный менеджер bspwm
hugeping(ping,1) — old.pc
2022-05-31 08:44:11


old.pc> Честно говоря, i3wm не производит впечатления "готового из коробки".

Ну тут относительно. Его, по крайней мере, можно просто запустить и сразу работать.
Насчёт обоины я не помню, возможно там заливка цветом. Возможно -- нет. Но раскладку клавиатуры вставить или обоину на корневое окно в конфиг -- для любителей экспериментов не проблема.

И трей, кстати, в i3wm из коробки есть. Это значит, что штатная панелька i3bar его поддерживает, и не надо запускать что-то вроде stalonetray (если трей вообще нужен).

По сравнению со всеми остальными тайловыми wm что я пробовал, он был самым дружественным. Да, awesome я обошёл стороной, так как считал его "динамическим" wm, которые мне не очень нравятся.

# Re: Оконный менеджер bspwm
Andrew Lobanov(tavern,1) — old.pc
2022-06-01 11:13:16


old.pc> Честно говоря, i3wm не производит впечатления "готового из коробки". По-моему, там даже обоины из коробки нет, и запустив его, видишь "серую рябь" иксов: хотя могу с кем-то ещё путать. Но в любом случае, там ни трея нет из коробки, ни других привычных вещей. Вот awesome за примерно 13 лет довольно частого использования я только неделю назад полез в его конфиг (разве что с выходом 4.0 появились титлбары, мне сказали, как их отключить, и я их всегда отключал, не вникая в конфиг), а так он был действительно "готов из коробки"

Трей там есть из коробки. Приходится выключать. Серая рябь иксов осталась в очень далёком уже прошлом. Теперь только чёрный фон. Но обои это не задача ВМ. Если ВМ ставит обои, значит он занимается не своим делом и идёт нафиг. В остальном, если не нужны правила (а они нужны) он самый изкоробочный.

# Re: Оконный менеджер bspwm
Andrew Lobanov(tavern,1) — hugeping
2022-06-01 11:13:17


hugeping> По сравнению со всеми остальными тайловыми wm что я пробовал, он был самым дружественным. Да, awesome я обошёл стороной, так как считал его "динамическим" wm, которые мне не очень нравятся.

awesome неповоротлив. Последний раз пробовал его на селероне каком-то (забыл уже, но это мой предыдущий ноут) и там прямо видно как он отрисовывает свои элементы чуть ли не построчно. Моя нежная психика от такого отвыкла :)

i3wm хорош из коробки, bspwm хорош после напильнкиа, если годится динамика, то лучше взять dwm, но он точно не из корбки. Из стековых люблю fvwm и cwm. И ещё очень нежно люблю WindowMaker, но на текущей машине он просто неюзабелен уже. Нужны векторные док-аппы :)