DigitableCourses
Настройки портала
Показать возможности портала

Локально и без аккаунта. Аккаунта нет, регистрация не нужна: введённое в инструменты остаётся в localStorage браузера и на сервер не уходит.

Свой счётчик считает открытия страниц и дочитывания: уезжает адрес и десятая доля текста. Без cookies и чужих счётчиков, IP не хранится, Do Not Track уважается. Как это проверить

Репозиторий портала не выложен, «открытым кодом» мы его не зовём. Открыто это:

Живёт портал на донатах, платных консультациях и разборах по запросу и покупке Workbench.

Планов делать курсы платными нет.

X11 · BSD-2-Clause · ранний

digitwm — окна на ленте, а не в сетке.

Окна живут на бесконечной горизонтальной ленте колонок, в колонке — стопка окон; вместе они полотно, а экран — окно просмотра по нему. Полотно едет по обеим осям и за свои края не уходит. Модель как у niri, но на X11: Linux, FreeBSD и NetBSD одинаково. Маковская цель есть в дереве и ни разу не запущена — мака в проекте нет.

Как это выглядит

Двадцать три кадра записанного сеанса, по которым можно пройти теми же клавишами, что стоят в конфиге, и четырнадцать кадров с работающего менеджера — включая пару «с Workbench и без него».

Пройти тот же сеанс клавишами

Это запись, а не менеджер. В вашем браузере не работает ни одного окна digitwm — там листаются картинки. Двадцать три кадра сняты с двоичного файла из f3e63de под Xvfb 1280×800, каждый после ровно одного нажатия, числа под ним промерены xwininfo. Обход один: три шага 4-l вдоль ленты и девятнадцать 4-j вниз по стопке из двадцати окон; шага, которого в записи нет, проигрыватель не подрисует.
Чего в записи нет Скорости (кадр сменяется мгновенно, а сколько стоит вставка окна, отсюда не узнать), мыши, меню, смены ширины колонки, закрытия окна, второго монитора и вашего конфига — сцена собрана шестью строками cwmrc.
Кадр 1 из 23, экран digitwm 1280×800. В фокусе колонка 1 из 4: она стоит на 0,0 и занимает 634×798 точек. Вьюпорт сдвинут поперёк на 0 из 1288, полотно вниз — на 0.

Рабочее место целиком

Как лента едет вбок

Один сеанс, четыре кадра: едет вьюпорт, а не колонки

Экран digitwm 1920×1080. Слева колонка шириной 1281 точка с исходником ribbon.c в Vim — она в фокусе и стоит во вьюпорте целиком. Через зазор 8 точек справа начинается колонка с doc/ribbon.ru.md, правым краем экрана она обрезана: видны 631 точка из 1281. Остальные четыре колонки за правым краем.
1 Смещение 0, фокус на первой колонке. Второй колонки видно 631 точку из 1281.
Тот же экран после перевода фокуса вправо. Слева колонка с ribbon.c обрезана левым краем экрана: видны 623 точки из 1281. Справа целиком стоит колонка с doc/ribbon.ru.md — теперь в фокусе она. У правого края экрана чёрная полоса зазора шириной 8 точек.
2 Фокус на соседе — вьюпорт уехал. Первая колонка ушла за левый край, её ширина та же.
Ещё шаг вправо. Слева колонка с doc/ribbon.ru.md обрезана левым краем экрана, видны 623 точки из 1281. Справа целиком колонка с файлом fts/scroll-offset.fts, она в фокусе. У правого края снова чёрная полоса зазора 8 точек.
3 Третья колонка — спецификация той самой политики смещения. Ширины опять не изменились.
Правый конец ленты. Слева колонка с doc/commands.ru.md обрезана левым краем экрана, видны 631 точка из 1281. Справа целиком колонка с calmwm.h в фокусе, её правый край совпадает с правым краем экрана, справа от неё ничего нет.
4 Правый конец: дальше вьюпорт не идёт. Зазор справа исчез — колонка стоит на 8 точек правее, чем на кадрах 2 и 3 (639 против 631). Это и есть зажим смещения.

Один сеанс с двоичного файла из 83fc87b, Xvfb 1920×1080: шесть окон Alacritty с vim -R, пресет 67 %, ribbongap 8, палитра Digitable Focus. Рамки у колонки с фокусом здесь нет: Alacritty просит нулевую своим ConfigureRequest, а менеджер выполняет просьбу клиента как есть (xevents.c:209-210).

Как полотно едет вниз

Тот же сеанс: одна колонка стала стопкой из двух окон, разделённых по вертикали. Справа колонка шириной 1281 точка: сверху doc/commands.ru.md высотой 536 точек, снизу calmwm.h высотой 536 точек, между ними зазор 8 точек. Слева колонка с session/config/cwmrc.in обрезана левым краем экрана, видны 631 точка из 1281.
Сначала деление: колонка делится на стопку — 536 + 8 + 536 = 1080, ровно высота экрана. Вьюпорт не двинулся ни на точку: пока стопка помещается в экран, прокручивать нечего. Полный размер

Один сеанс, два кадра: двадцать окон в одной колонке, полотно 1352 при экране 800

Экран digitwm 1280×800: одна колонка на всю ширину, в ней стопка из двадцати окон Alacritty по 60 точек высотой. В кадре окна с первого по двенадцатое, в каждом две строки — номер с путём файла (01/20 ribbon.c, 06/20 fts/stack-offset.fts) и первая строка этого файла. Двенадцатое окно обрезано нижней кромкой экрана, окна с тринадцатого по двадцатое в кадр не попали вовсе.
1 Полотно на 0, фокус на первом окне. Видно двенадцать окон из двадцати, двенадцатое обрезано кромкой; ниже экрана осталось 552 точки.
Тот же экран после девятнадцати нажатий 4-j: полотно уехало вниз на 552 точки. Сверху обрезано девятое окно, дальше идут окна с десятого по двадцатое. Двадцатое, 20/20 tools/measure-insert.sh, стоит на 740 точках и занимает нижние 60 точек экрана целиком, у него подсвечена рамка фокуса. Первых восьми окон в кадре нет — они ушли за верхнюю кромку.
2 Фокус на двадцатом окне — полотно на 552. Двадцатое занимает 740…800 и видно целиком, первые восемь ушли за верхнюю кромку.

Те самые 552 точки, которых до второй оси было не достать. Один сеанс с двоичного файла из f3e63de, Xvfb 1280×800: двадцать окон Alacritty в одной колонке пресетом 100 %, ribbongap 8, ribbonminheight 60 — те же числа, что в таблице вкладки «Как едет лента». Пространства имён у этих двух кадров нет: оболочки в кадре не запущено ни одной, каждое окно печатает одну строку и засыпает.

Колонка держит ширину, лента длиннее экрана

Одно и то же с Workbench и без него

Как сняты кадры: коммиты, дисплей, пространство имён

Менеджер собран из 83fc87b, кроме полосы «Как полотно едет вниз» — её два кадра сняты с f3e63de, до которого второй оси не было. Конфигурация — session/config/cwmrc.in с палитрой Digitable Focus Carbon; дисплей Xvfb 1920×1080, у полосы «вниз» 1280×800. Конфигурации приложений взяты из архива Workbench и разложены кодом галереи тем. Сеанс двенадцати кадров идёт в отдельном пространстве имён: /home/dev вместо домашнего каталога, в /etc/passwd только dev, имя машины workbench, свой список процессов.

Лента вместо сетки

Тайловый менеджер делит экран между всеми окнами: открыли пятое — четыре предыдущих стали уже. На ленте колонки стоят в ряд и держат свою ширину, а экран ездит по ним.

01

Колонка держит ширину

Новая колонка встаёт в ленту, соседи разъезжаются вдоль неё, но не сжимаются: геометрия открытого окна при вставке не меняется — проверено и арифметикой, и экраном.

02

Экран — окно просмотра

Фокус двигает вьюпорт, а не перестраивает ленту. Колонка с фокусом всегда целиком внутри экрана: после фокуса, вставки, закрытия, смены ширины и смены конфигурации мониторов.

03

За краем — не значит закрыто

Уехавшие за край окна остаются отображёнными по координате вне экрана. Гасить их можно настройкой ribbonhide.

04

Это не композитор

Анимация требует процесса, который владеет кадром, а оконный менеджер X11 им не владеет: окна переезжают за один шаг. Нужны плавные переходы — рядом запускается композитор.

Те же четыре утверждения — в кадрах витрины.

Полотно едет по обеим осям

Смещений два — offset вдоль ленты и voffset вниз по полотну (calmwm.h:339-340), — и оба вычитаются из координат окна на экране (ribbon.c:746-747). Вторая ось появилась в f3e63de; сколько точек терялось до неё — в таблице ниже.

Горизонталь Вьюпорт ездит вдоль ленты за колонкой с фокусом: ribbon_policy_offset() (ribbon.c:80-104), модель — fts/scroll-offset.fts.
Вертикаль Сначала деление: стопка делит высоту вьюпорта между своими окнами, и пересчёт не выходит за пределы колонки (doc/ribbon.ru.md:28-30). Делит, пока делится: когда равная доля упирается в минимальную высоту, побеждает минимум, и полотно становится выше экрана (ribbon.c:192-212). Дальше вторая ось: ribbon_policy_voffset() (ribbon.c:124-127) везёт вьюпорт за окном с фокусом. Единица другая, чем поперёк: стопка бывает выше любого экрана, поэтому вниз вьюпорт держит окно, а не колонку. Модель — fts/stack-offset.fts.
Края Зажим у осей общий (ribbon.c:95-101): вдоль ленты смещение сидит в [0, длина − ширина экрана], вниз — в [0, высота полотна − высота экрана]. «Бесконечная» — про ленту, не про прокрутку.

Где были потерянные точки. Там, где стояла потеря, теперь стоит предел прокрутки, и это одно число. Снято пробой раскладки — тем самым кодом, который исполняет менеджер: cwm -C 'layout-probe layout viewport=1280x800 gap=8 min-height=60 columns=N presets=3 focus=0'.

Окон в стопкеВысота полотнаБыло до второй осиСтало
11 800 Стопка совпадала с экраном точка в точку — терять было нечего. Предел прокрутки 0. Прокручивать нечего, и модель говорит это отдельным правилом, а не молчанием.
12 811 11 точек последнего окна навсегда под нижней кромкой. Предел прокрутки 11 — ровно те же 11 точек, и теперь они доезжают до экрана.
20 1 352 552 точки под кромкой: восемь окон с тринадцатого по двадцатое целиком за экраном. Они стояли на 0, 68, … 1292 всегда — ribbon-focus-down двигал фокус, не двигая вьюпорт (83fc87b, ribbon.c:826-850). Предел прокрутки 552. На двадцатом окне полотно стоит на 552, окно занимает 740…800 и видно целиком; подъём по стопке возвращает полотно к 0.

То же в движении: четыре кадра вдоль ленты и два кадра стопки из двадцати окон на вкладке «В деле».

Зачем это ставить — и когда не стоит

Ставить стоит, если

  • Окон больше трёх, и тайлинг делает их узкими. На ленте колонка держит ширину: при вставке окна геометрия соседей не меняется, и это замерено — ноль перерисовок за 11 вставок.
  • Нужен X11, а не Wayland. Модель niri на системе, где Wayland-композитора может не быть вовсе: Linux, FreeBSD, NetBSD одинаково, три библиотеки в сборке.
  • Хочется читать и править сам менеджер. 10 380 строк своего кода под BSD-2-Clause поверх cwm под ISC — патч можно нести и обратно в апстрим.
  • Уже стоит cwm. Конфигурация читается прежняя: сначала ~/.digitable/digitwm/digitwmrc, если его нет — ~/.cwmrc, и менеджер говорит вслух, который взял.

Не стоит, если

  • Нужен бар из коробки. Своей панели нет: место для чужой есть и полоса читается, но polybar — отдельная программа со своей настройкой, и за пределами Linux она не проверена.
  • Нужны плавные переходы. Окна переезжают одним шагом: это не композитор.
  • Нужен пакет. Ни тега, ни порта — сборка из исходников.
  • Нужна уверенность на третьи сутки. Ни одного дня непрерывной работы за ним не отсчитано, и сказать об этом нечего.

Workbench для этого не нужен, и наоборот. Две программы разговаривают только по X11. digitwm бесплатен и работает сам по себе; Workbench работает в любом оконном менеджере, и что в его поставку не попали ни исходники менеджера, ни линковка с ним, проверяет гейт архива.

Основа — cwm, и выбрана она не по вкусу

cwm — оконный менеджер из базовой системы OpenBSD, взятый через переносимую сборку. Маленький, три библиотеки, два десятка лет в базе. Но решило не это.

7 883 строки C в апстриме на базовом коммите a343cc9: 7 242 в .c и .h плюс 641 в parse.y.
3 библиотеки в сборке — x11, xft, xrandr. Ни одной добавленной сверх этого.
10 380 строк добавила Digitable в тридцати трёх файлах: ribbon.c — 1 542, probe.c — 1 172, маковская цель — 4 443, остальное — обработка событий, конфигурация и измерительные инструменты.

Главная причина в другом: у cwm нет тайлинга, который пришлось бы выдирать. Лента добавляется на чистое место, а не прививается поверх чужого дерева фреймов. Форк сохраняет историю апстрима целиком — 1 146 коммитов.

Правила раскладки — исполняемые спецификации

Числа, которыми живёт лента, не закопаны в C. Десять скалярных решений — смещение вдоль ленты и вниз по полотну, ширина колонки, высота окна в ней, место для нового окна, фокус после закрытия, смещение при смене монитора, длина полосы под чужую панель, её доля и спор двух панелей — записаны моделями FTS на двух поверхностях, русской и английской.

Внутри оконного менеджера FTS не исполняется никогда. Модели работают только в CI; рантайм остаётся на C, yacc и трёх библиотеках X — иначе NetBSD стал бы недостижим.

  • surfaces.mjs 10 моделей Русская и английская поверхности дают один канонический документ. Это не перевод: один парсер, одно представление, сверка поле за полем. Моделей ровно столько, сколько политик в ribbon.c: имена ribbon_policy_* сверяются с именами файлов моделей.
  • conformance.mjs 448 проверок Векторы идут двумя путями — через сгенерированный TypeScript и через cwm -C "layout-probe …", то есть через тот самый код, что исполняет менеджер. Совпали все.
  • selftest.mjs 11 мутаций Харнессу ломают по одной константе в копии моделей и требуют, чтобы он это заметил. Одна из мутаций — поле у верхней кромки полотна — сначала НЕ ловилась: дыра была настоящая, и вектор к ней дописан.
  • invariants.mjs 320 сценариев 612 вставок, 5 771 окно в конечных состояниях, зерно 20260804. Снято с двоичного файла, а не с модели: ribbon_insert() зовут ту же, что зовёт обработчик MapRequest.
  • invariants --selfcheck 7 поломок Смена пресета у существующей колонки, потеря пикселя высоты у существующего окна, колонка с фокусом за краем вьюпорта, колонка мимо сетки, полотно мимо окна с фокусом, полотно ниже своей самой высокой колонки и колонка, совравшая о высоте своей стопки, — каждая замечена.

Три числа, снятые с экрана

Харнессы выше отвечают об арифметике; эти три числа — о картинке. Замер: Xvfb 1280×800, двенадцать окон по одному, sh tools/measure-insert.sh -n 12 -w 500, шестнадцать прогонов — 192 вставки, перерисовки нулевые.

Что мерилиРезультатЧто это значит
Мерцание 0 за 11 вставок Ни одно уже открытое окно не перерисовалось, пока открывалось следующее.
Задержка вставки 1–10 мс от XMapWindow Собственная доля менеджера — принять MapRequest, выбрать колонку, выдать геометрию, отобразить. Время до появления окна на экране — другое число: от запуска процесса медиана 108 мс, и меряет она fork, exec, подключение к серверу и занятость машины, а не менеджер.
Окна за краем 0 событий UnmapNotify Двенадцать окон на вьюпорте в 1 280 точек: большинство за краем, и ни одно не свёрнуто — ровно это и означает ribbonhide no.

Почему чисел два. На перезамере загрузка машины выросла вдвое (34–49 и 57–94 на восьми ядрах): медиана «от запуска» выросла вдесятеро, с 10 мс до 108, а медиана собственной доли не сдвинулась — 4 мс против 5.

Ноль был не всегда. До 5c4ba49 замер давал полную перерисовку на вставку: новое окно отображалось раньше, чем лента уезжала вьюпортом, и накрывало соседа целиком, а содержимое закрытого окна X выбрасывает. Починка — перенесённый вызов ribbon_sync(); харнесс инвариантов этого увидеть не мог, он смотрит на числа, а не на экран.

Чего в этих числах нет

Контрольного образца. DGT-WM-01 просила замерить papersway поверх i3 теми же тремя числами; он не снят — ни i3, ни papersway на машине нет. Значит, ни одно число выше ни с чем не сравнено, и «digitwm быстрее» здесь не написано.

Где это стоит в цикле разработки

Пять продуктов Digitable — не пять инструментов рядом, а один цикл. digitwm занимает в нём последнюю станцию и сам по этому циклу сделан.

  1. УвиделКадры на вкладке «В деле»: пятое окно не сжимает четыре предыдущих.
  2. Узнал свою больТайлинг делит экран между всеми. Лента — не делит.
  3. ПоставилЧетыре команды, --plan сначала печатает, что произойдёт.
  4. Результат в первый деньЗакрыть нечем: дня непрерывной работы за менеджером не отсчитано.
  1. 01 Правило записывается спецификацией · FTS Не комментарием и не тикетом, а исполняемой моделью на языке предметной области. В digitwm так записаны 10 скалярных решений раскладки — от смещения вьюпорта до полосы под чужую панель; они перечислены на вкладке «Чем доказано».
  2. 02 Спецификация доказывается, а не согласуется · flang Модель исполняется, гоняется на своих примерах и печатается в код. 448 векторов идут через сгенерированный код и через живой двоичный файл; расхождение валит сборку, а сам харнесс проверен 11 мутациями.
  3. 03 Правит агент, а решает программа · Digit Локальный агент пишет и проверяет .fts детерминированными инструментами; данные остаются в ~/.digit. 320 сценариев, 612 вставок, 5 771 окно в конечных состояниях — и семь нарочных поломок, которые харнесс обязан заметить.
  4. 04 Работа идёт в собранной среде · Workbench Единые темы, Compendium и бланки решений: редактор, терминал и просмотрщик не настраиваются заново на каждой машине. Связь только по X11, и её стережёт гейт архива; что даёт Workbench, видно на 2 кадрах витрины — с ним и без него.
  5. 05 Среда стоит в окне · digitwm Колонки на ленте: спецификация, код по ней и задачник — три окна, между которыми ходишь, а не переключаешься. Замер, который закрывает цикл на первую станцию: ноль перерисовок соседей за 11 вставок — то, чего арифметика увидеть не могла.

Чего в этом цикле нет. Он замкнут на одном продукте — на этом: модели раскладки, сверка с живым двоичным файлом и мутации харнесса сняты здесь, а не в остальных четырёх.

Состояние: рано, и вот чего именно нет

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

  • Своей панели нет — и не будет. Бар чужой: сессия ставит polybar, а менеджер читает заявленную полосу _NET_WM_STRUT_PARTIAL (calmwm.h:548-549, xutil.c:221-222) и снимает её с рабочей области. На живом баре колонки 798 точек становятся 770 при панели в 28. Не проверено: два монитора, панель снизу и по бокам, батарея и сам polybar на FreeBSD и NetBSD — систем обещано три, проверена одна.
  • В нём никто не жил неделю. Как он ведёт себя на третьи сутки, сказать нечем.
  • Доставка проверена не везде. bootstrap.sh и порт для pkgsrc прогнаны на Debian, остальное вычитано глазами. Маковская цель (macos/, три способа установки, формула brew) не запускалась ни разу: мака в проекте нет.
  • Релиза нет. Ни тега, ни пакета в pkgsrc, ни порта FreeBSD. Сборка — из исходников.

Почему панель чужая — решено числом. Своя стоила бы около 1 550 строк (bar.c у sdorfehs — 1 093, drw.c у dwm — 471) на каждой из трёх систем; место для чужой обошлось в 310 строк, из них 178 не комментарии. Размеры, лицензии и отвергнутые кандидаты — в doc/panel.md.

Как взять

С голой системы — одной командой; --plan сначала печатает, что произойдёт, и ничего не делает. На маке тот же скрипт собирает маковскую цель, а не X11-сборку.

git clone https://github.com/digitable-lol/digitwm
cd digitwm
sh bootstrap.sh --plan
sh bootstrap.sh
session/verify.sh
Открыть репозиторий

Документация двуязычная — 13 пар, и каждая называет, что в ней замерено, а что нет: doc/ribbon.md (модель ленты), doc/baseline.md (три числа) и doc/macos-install.md (мак).

Лицензия: BSD-2-Clause на наше, ISC на унаследованное

Граница проведена по коммиту, которым файл добавлен: 137 наших файлов под BSD-2-Clause, 25 из 26 унаследованных от cwm — под ISC, и queue.h под BSD-3-Clause. ISC досталась дереву по наследству, а не была выбрана; смена действует вперёд и ничего ни у кого не отзывает (NOTICE).

Ни строки из GPL-соседей

papersway (GPL-3.0-or-later), sdorfehs и ratpoison (GPL-2.0-or-later) дают похожий скроллируемый тайлинг. Заимствование оттуда сдвинуло бы digitwm на копилефт и закрыло бы путь патчей обратно в cwm. Идеи наблюдать можно, код — нельзя.

В платный архив не входит

И не потому, что лицензия запрещает: продавать разрешают обе — ISC говорит «with or without fee» прямым текстом, BSD-2-Clause не запрещает и подавно. Запрет — записанное решение: разрешительная лицензия заведена ради pkgsrc и портов, а деньги берутся с архива Workbench.

Забор стережёт сборка

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

Сессия ничего не вендорит

Каталог session/ настраивает окружение вокруг менеджера, но ни один из инструментов в репозиторий не кладётся: они ставятся пакетным менеджером системы под своими лицензиями. Своё здесь — конфигурация и скрипты установки.