Колонка держит ширину
Новая колонка встаёт в ленту, соседи разъезжаются вдоль неё, но не сжимаются. Геометрия уже открытого окна при вставке не меняется — это проверяется и арифметически, и на экране.
X11 · ISC · ранний
Окна живут на бесконечной горизонтальной ленте колонок, экран — окно просмотра по этой ленте. Открытие окна двигает ленту, а не сжимает соседей в нечитаемые полоски. Модель как у niri, но на X11 — то есть на Linux, FreeBSD и NetBSD одинаково.
Тайловый менеджер обычно делит экран между всеми окнами: открыли пятое — четыре предыдущих стали уже. Лента устроена иначе. Колонки стоят в ряд и держат свою ширину, а экран ездит по ним.
Новая колонка встаёт в ленту, соседи разъезжаются вдоль неё, но не сжимаются. Геометрия уже открытого окна при вставке не меняется — это проверяется и арифметически, и на экране.
Фокус двигает вьюпорт, а не перестраивает ленту. Колонка с фокусом всегда целиком внутри экрана: после фокуса, вставки, закрытия, смены ширины и смены конфигурации мониторов.
Уехавшие за край окна остаются отображёнными по координате вне экрана. Гасить их можно настройкой ribbonhide, и цена решения замерена, а не выбрана на глаз.
Анимации нет и не будет: анимация требует процесса, который владеет кадром, а оконный менеджер X11 им не владеет. Окна переезжают за один шаг. Нужны плавные переходы — рядом запускается композитор.
editors/vim-fts. Полный размер
cwm — оконный менеджер из базовой системы OpenBSD, взятый через переносимую сборку. Он маленький, зависит от трёх библиотек и живёт в базе два десятка лет. Но решило не это.
a343cc9: 7 242 в .c и .h плюс 641 в parse.y.
x11, xft, xrandr. Ни одной добавленной сверх этого.
ribbon.c — 968, probe.c — 1 002, остальное — правки в обработке событий и конфигурации.
Главная причина в другом: у cwm нет тайлинга, который пришлось бы выдирать. Это плавающий менеджер, поэтому лента добавляется на чистое место, а не прививается поверх чужого дерева фреймов. Форк сохраняет историю апстрима целиком — 1 146 коммитов, — чтобы авторство читалось из git log, а не только из NOTICE.
Числа, которыми живёт лента, не закопаны в C. Шесть скалярных решений — на сколько уехать после смены фокуса, какой ширины колонка, какой высоты окно в ней, куда вставить новое, что получает фокус после закрытия, что делать со смещением при смене монитора — записаны моделями FTS на двух поверхностях, русской и английской.
Внутри оконного менеджера FTS не исполняется никогда. Модели работают в CI: одни и те же векторы проходят через сгенерированный код и через живой двоичный файл, расхождение валит сборку. Рантайм остаётся на C, yacc и трёх библиотеках X — иначе NetBSD стал бы недостижим.
surfaces.mjs
6 моделей
Русская и английская поверхности дают один и тот же канонический документ. Это не перевод: один парсер, одно каноническое представление, сверка поле за полем.
conformance.mjs
248 проверок
Векторы идут двумя путями — через сгенерированный TypeScript и через cwm -C "layout-probe …", то есть через тот самый код, что исполняет менеджер. Совпали все.
selftest.mjs
7 мутаций
Харнессу ломают по одной константе в копии моделей и требуют, чтобы он это заметил. Зелёный харнесс, который не умеет краснеть, не доказывает ничего.
invariants.mjs
320 сценариев
612 вставок, 5 771 окно в конечных состояниях, зерно 20260804. Оба обещания ленты сняты с двоичного файла, а не с модели: ribbon_insert() зовут ту же, что зовёт обработчик MapRequest.
invariants --selfcheck
4 поломки
Смена пресета у существующей колонки, потеря пикселя высоты у существующего окна, колонка с фокусом за краем вьюпорта и колонка мимо сетки — каждая замечена.
Харнесс инвариантов отвечает на вопрос об арифметике. Эти три числа отвечают на вопрос о картинке, и одно из них поймало то, чего арифметика увидеть не могла. Замер: Xvfb 1280×800, программный сервер, двенадцать окон по одному, sh tools/measure-insert.sh -d :91 -n 12 -w 500.
| Что мерили | Результат | Что это значит |
|---|---|---|
| Мерцание | 0 за 11 вставок | Ни одно уже открытое окно не перерисовалось, пока открывалось следующее. |
| Задержка вставки | 2–6 мс от XMapWindow |
Собственная доля менеджера — принять запрос, выбрать колонку, выдать геометрию. От запуска процесса выходит 5–15 мс, и почти всё это fork, exec и подключение к серверу. |
| Окна за краем | 0 событий UnmapNotify |
Двенадцать окон на вьюпорте в 1 280 точек: большинство за краем, и ни одно не свёрнуто — ровно это и означает ribbonhide no. |
Ноль был не всегда. До коммита 5c4ba49 замер давал одну полную перерисовку на вставку, и ценность замера в том, что он показал причину. Лента ставила новую колонку туда, где стояла старая, и уезжала вьюпортом; новое окно отображалось первым и на несколько миллисекунд накрывало соседа целиком, а содержимое полностью закрытого окна X выбрасывает. Починка — один перенесённый вызов: ribbon_sync() идёт до отображения новичка. Геометрия соседа не менялась ни до, ни после — двигался только x, — поэтому харнесс инвариантов эту беду увидеть не мог: он смотрит на числа, а не на экран.
Контрольного образца. Задача DGT-WM-01 просила замерить papersway поверх i3 теми же тремя числами. Он не снят: ни i3, ни papersway на машине нет и в репозиториях дистрибутива их нет, а ставить чужой системный софт ради замера — решение владельца, и задача остаётся открытой ровно на этом. Значит, ни одно число выше ни с чем не сравнено. «digitwm быстрее» здесь не написано и написано не будет, пока сравнивать не с чем.
digitwm под ISC — дословно тем текстом, что стоит в базовой системе OpenBSD, с девятью строками правообладателей апстрима и одной нашей. Единственное исключение — queue.h под BSD-3-Clause: это sys/queue.h, и он не меняется, чтобы оставаться синхронным с апстримом.
papersway (GPL-3.0-or-later), sdorfehs и ratpoison (GPL-2.0-or-later) дают похожий скроллируемый тайлинг. Заимствование оттуда автоматически сдвинуло бы digitwm на копилефт и закрыло бы и путь патчей обратно в cwm, и разрешительную лицензию как таковую. Идеи наблюдать можно, код — нельзя.
И не потому, что лицензия запрещает: ISC разрешает распространение «with or without fee» прямым текстом. Запрет — записанное решение. Разрешительная лицензия заведена ради pkgsrc и портов FreeBSD и NetBSD, а деньги берутся с архива Workbench, оболочки и работы, а не с оконного менеджера.
Решение не осталось словами в спецификации. Гейт архива падает, если в поставку попадают исходники, бинарь или узнаваемый код менеджера, и отдельно проверяется, что в дереве оболочки нет ни исходников digitwm, ни линковки с ним: это две программы, которые разговаривают по X11 и по управляющему сокету.
Каталог session/ настраивает окружение вокруг менеджера — редактор, терминал, мультиплексор, оболочку. Ни один из этих инструментов в репозиторий не кладётся: они ставятся пакетным менеджером системы под своими лицензиями. Своё здесь — только конфигурация и скрипты установки.
Лента есть и проверена — колонки, стопки, вьюпорт, вставка, фокус, пресеты ширины, отдельная лента на каждый выход. Всё остальное честнее перечислить, чем обойти.
_NET_WM_STRUT и _NET_WM_STRUT_PARTIAL не встречаются в исходниках вовсе — полосу менеджер резервирует своей настройкой gap, а не по просьбе клиента. Это найдено замером, а не чтением.bootstrap.sh и порт для pkgsrc прогнаны на Debian и вычитаны глазами, а не запущены на каждой системе, которую они называют.С голой системы — одной командой; --plan сначала печатает, что произойдёт, и ничего не делает.
git clone https://github.com/digitable-lol/digitwm
cd digitwm
sh bootstrap.sh --plan
sh bootstrap.sh
session/verify.sh
Открыть репозиторий
Документация в репозитории двуязычная: шесть пар документов, русская и английская, и каждый называет, что в нём замерено, а что нет. Начинать стоит с doc/ribbon.md — модель ленты на одной странице — и с doc/baseline.md, где лежат три числа выше вместе с отсутствующим образцом.
Ступени, треки и материалы портала. Кликните ступень, чтобы раскрыть треки, трек — чтобы увидеть статьи, статью — чтобы увидеть, с чем она связана по общим темам.
Колесо — масштаб, перетаскивание — панорама. Стрелки и Tab — переход между узлами, Enter — раскрыть или выбрать. Повторный клик по материалу показывает его соседей по общим темам.