# Сборка и запуск Lark DE ## Требования ### Системные зависимости ```bash # Debian/Ubuntu sudo apt install \ libwayland-dev \ libxkbcommon-dev \ libdrm-dev \ libgbm-dev \ libpipewire-0.3-dev \ libseat-dev \ libdbus-1-dev \ libudev-dev \ libinput-dev # Fedora sudo dnf install \ wayland-devel \ libxkbcommon-devel \ libdrm-devel \ mesa-libgbm-devel \ pipewire-devel \ libseat-devel \ dbus-devel \ libudev-devel \ libinput-devel ``` ### Rust ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` ## Сборка ```bash cargo build --release ``` ### Сборка на удалённой машине в Docker Слабому устройству не обязательно собирать проект самому: это можно сделать на другой машине, а готовый бинарник вернуть. На удалённой машине нужны `ssh`, `rsync` и Docker. Скрипт копирует исходники, собирает образ по `Dockerfile` и забирает бинарник: ```bash ./scripts/build-remote.sh niko@n1ko.dev 2241 # target/release/lark ./scripts/build-remote.sh niko@n1ko.dev 2241 --check # ещё и проверка без дисплея ``` | Переменная | Назначение | |------------|------------| | `LARK_REMOTE_DIR` | каталог сборки на удалённой машине (`/tmp/lark-build`) | | `LARK_LOCAL_BIN` | куда положить бинарник (`target/release/lark`) | | `LARK_CHECK` | непустое значение равносильно `--check` | Этапы `Dockerfile`: | Этап | Что внутри | |------|------------| | `builder` | Rust и библиотеки разработки, `cargo build --release` | | `runtime` | библиотеки времени выполнения и сам композитор | | `headless` | плюс Xvfb, imagemagick, weston-terminal и xdotool | | `binary` | только исполняемый файл: `docker build --target binary -o dist .` | Реестр Cargo, git-зависимости и `target` подключены кэшем BuildKit: повторная сборка после правки кода занимает секунды, зависимости не пересобираются. ```bash docker build -t lark . # образ для запуска docker build --target binary -o dist . # только бинарник: dist/lark docker build --target headless -t lark:headless . # образ для проверки docker run --rm lark:headless # снимок экрана и журнал ``` Проверка `--check` поднимает Xvfb в контейнере, запускает композитор с `weston-terminal`, снимает экран и складывает снимок и журнал в `target/lark-headless/`. Образ `headless` содержит `xdotool`: им можно «нажать» кнопку «Пуск» перед снимком, чтобы проверить меню. ## Запуск Композитор открывает окно через winit, поэтому запускается **внутри существующей X11/Wayland-сессии** — вложенно, что удобно для разработки. Поверх DRM/KMS он пока не запускается: бэкенд не реализован ([дорожная карта](ROADMAP.md)), поэтому из TTY (без графической сессии) запуск невозможен — композитор скажет об этом и подскажет, что делать. Требуется переменная `XDG_RUNTIME_DIR`: сокет Wayland создаётся в ней. ```bash # Вложенный запуск в текущей сессии ./target/release/lark ``` Композитор сам занимает свободный сокет `wayland-N` и сообщает его при старте. Дочерние процессы (меню «Пуск», терминал) наследуют `WAYLAND_DISPLAY`, поэтому запускать их нужно после инициализации композитора. Завершение: `Ctrl+Esc` в окне композитора либо `SIGINT`/`SIGTERM`. ### Журнал По умолчанию показываются сообщения Lark и предупреждения библиотек: фильтр `lark=info,warn`. Без него smithay печатает на несколько экранов список расширений OpenGL и параметры инициализации — это вытесняет всё, что действительно нужно читать. ```bash RUST_LOG=debug ./target/release/lark # подробно, включая smithay RUST_LOG=lark=trace ./target/release/lark # только свой код, максимум ``` Вывод запущенных приложений в консоль композитора не попадает: иначе приложение вместе со своей шиной D-Bus и запущенными ею службами засыпал бы терминал сообщениями об ошибках, которые к Lark отношения не имеют. ## Горячие клавиши | Сочетание | Действие | |-----------|----------| | `Ctrl+Esc` | Выход из сессии | | `Super` | Свернуть активное окно | | `Super+Shift` | Развернуть окно / вернуть к прежнему размеру | | `Super+Delete` | Закрыть активное окно | | `Super+1` … `Super+4` | Перейти на рабочую область | | `Super+Shift+1` … `Super+Shift+4` | Перенести активное окно на область | | `Ctrl+Super+←` / `Ctrl+Super+→` | Шаг по рабочим областям по кругу | | `Alt+Tab` | Переключение окон (список, пока `Alt` удержан) | | `Alt+Shift+Tab` | Переключение окон в обратную сторону | | `Super+Space` | Следующая раскладка клавиатуры | | `Super+Shift+Space` | Предыдущая раскладка клавиатуры | | `Escape` | Закрыть меню «Пуск», настройки или отменить переключение | Клик по кнопке окна на панели задач переводит на него фокус, повторный клик по активному окну сворачивает его, клик по свёрнутому — возвращает. Ни то, ни другое не двигает окно по экрану. ### Переключение окон `Alt+Tab` показывает список открытых окон текущей рабочей области. `Tab` перебирает их по кругу, `Alt+Shift+Tab` — в обратную сторону. Фокус переводится только при отпускании `Alt`: иначе быстрый пролёт по списку переключал бы окна на каждом шаге и приложения мигали бы. `Escape` отменяет переключение, клик по пункту списка выбирает его сразу. Список строится по z-порядку сверху вниз, поэтому первым идёт текущее окно, а следующее за ним — то, на которое переключится первое нажатие `Tab`. ## Окна Заголовок рисует композитор (`[decoration] server_side = true`). В нём показывается название окна, а справа — кнопки «свернуть», «развернуть» и «закрыть» со значками. Верхние углы заголовка скруглены, кнопка под указателем подсвечивается, а кнопка закрытия — красным. Окно нельзя утащить за пределы рабочей области, поэтому заголовок всегда остаётся на экране. Развёрнутое окно показывает в кнопке значок возврата. Окно меняет размер мышью за край рамки и за углы. Верх заголовка тянет размер по вертикали, середина — перетаскивает окно. ## Панель задач Раскладка повторяет Windows 10, оформление — Material 3 Expressive. Слева идут: - **«Пуск»** — плитка с логотипом; открывает меню «Пуск» - **Поиск** — строка с лупой; клик открывает меню, запрос набирается сразу - **Рабочие области** — четыре скруглённые кнопки; текущая залита акцентом - **Окна** — значок приложения и подпись, у активного окна акцентная полоска снизу, у свёрнутого — приглушённые значок и подпись Справа идут индикаторы состояния, раскладка клавиатуры, часы (время над датой) и полоска «показать рабочий стол» у самого края. Индикаторы показывают настоящее состояние системы, а не заглушки: заряд и статус батареи читаются из `/sys/class/power_supply`, уровень сигнала Wi-Fi — из `/proc/net/wireless`, наличие адаптера Bluetooth — из `/sys/class/bluetooth`, громкость — через `wpctl` (PipeWire) или `pactl`. Значок батареи меняется по заряду (разряжена, половина, заряжена, идёт зарядка), звук перечёркивается при выключенном, у Wi-Fi без соединения появляется перечёркнутый значок. Индикатор, о котором нет данных (например, батарея на стационарной машине), не показывается вовсе: пустой значок был бы выдумкой. Опрос идёт раз в две секунды. Кнопки окон подстраиваются под длину названия. Если подписи перестают помещаться, они отбрасываются и остаются значки; если не помещаются сами кнопки, лишние окна сворачиваются в счётчик `+N`. Место под счётчик резервируется заранее, поэтому он не наезжает на часы. Панель задач показывает только окна текущей рабочей области. ## Меню «Пуск» Раскладка — «1 в 1» из Windows 10, оформление — Material 3 Expressive. Открывается кликом по «Пуску» или по строке поиска, закрывается по `Esc` или клику мимо меню. Слева — полоса: кнопка «Все приложения» (раскрывает список на всю ширину), учётная запись, настройки и завершение работы. Правее — строка поиска, список приложений по алфавиту с заголовками букв и колонка закреплённых плиток. | Действие | Результат | |----------|-----------| | Ввод символов | поиск по названию, без учёта регистра | | `Backspace` | удалить символ; на пустой строке уходит в окно | | `↑` / `↓` | перемещение выделения | | `Enter` | запустить выделенное приложение | | `Esc` | закрыть меню | | Прокрутка | листает список | | Клик по плитке | запустить приложение | | Клик по шестерне | открыть настройки | | Клик по питанию | завершить сессию | Список приложений читается из системы: просматриваются каталоги `.desktop`-файлов (`/usr/share/applications`, `/usr/local/share/applications`, `~/.local/share/applications`) и берутся записи `Type=Application` без `NoDisplay` и `Hidden`. Локализованное имя (`Name[ru]`) важнее английского, команда разбирается с учётом кавычек и кодов полей, а значок подбирается по категории: терминал получает терминал, файловый менеджер — папку. Приложения с `Terminal=true` запускаются внутри первого найденного терминала. Кроме установленных программ в меню есть встроенные пункты: | Пункт | Что запускается | |-------|-----------------| | `Файлы` | `nautilus`, `thunar`, `pcmanfm`, `dolphin` — первый найденный; иначе `xdg-open ~/` | | `Терминал` | `foot`, `alacritty`, `kitty`, `gnome-terminal`, `konsole`, `xfce4-terminal`, `xterm` — первый найденный | | `Настройки` | встроенное окно настроек | | `Завершение сессии` | завершает Lark | ### Поиск в интернете Когда в строке меню набран запрос, под списком приложений появляется строка поиска в интернете. Поиск выполняет пакет `ddgs` (DuckDuckGo), запускаемый через `uv run --with ddgs`; если `uv` в системе нет, берётся системный `python3` с уже установленным пакетом. Результаты показываются строками меню — клик открывает страницу браузером по умолчанию. Поиск идёт в отдельном потоке: сеть отвечает секундами, и главный цикл событий не должен её ждать. Пока меню закрыто, поиск не выполняется. Пункт, у которого нет ни одной программы в системе, не запускается: перебор кандидатов идёт до первого найденного. ## Рабочий стол Обои рисуются градиентом с двумя мягкими пятнами. Варианты — по акценту темы («По акценту»), синие, фиолетовые, зелёные, графит и однотонные по цвету `[desktop] background`; выбор — в настройках, там же есть анимации интерфейса. Значки собраны в столбец у левого края: встроенные приложения и, если включено `[desktop] show_home`, содержимое каталога `~/Desktop`. Ярлыки `.desktop` на рабочем столе читаются как программы, каталоги и файлы открываются через `xdg-open`. Одиночный клик выделяет значок, двойной — запускает приложение или открывает файл; клик по пустому месту снимает выделение. При панели задач сверху значки начинаются под ней, а не под краем экрана. ## Настройки Встроенное окно в стиле Windows 11: полоса разделов слева, карточки параметров справа. Открывается из меню «Пуск» (шестерня или пункт «Настройки»), закрывается по `Esc`, кнопке закрытия или клику мимо окна. | Раздел | Что настраивается | |--------|-------------------| | Оформление | тёмная или светлая тема, акцентный цвет из восьми, варианты обоев, анимации интерфейса | | Панель задач | положение (внизу или сверху), высота, центрирование значков, прозрачность | | Рабочий стол | число рабочих областей, значки из `~/Desktop` | | Клавиатура | список раскладок (переключаются `Super+Space`), вариант, чем переключать (Alt+Shift, Super+Space, Caps Lock), задержка и частота автоповтора | | Ввод | тачпад, скорость прокрутки | | Окна | заголовки рисует композитор, высота заголовка, ширина кнопок | | О системе | версия, шрифт, разрешение, файл настроек, сброс настроек | У каждой настройки есть кнопка сброса: она возвращает только эту настройку к значению по умолчанию, не трогая остальные. Значения по умолчанию берутся из `Config::default()`, поэтому они не могут разойтись с файлом конфигурации. Изменения применяются сразу и сохраняются в `~/.config/lark/config.toml`. Панель, рабочие области, декорации, раскладка клавиатуры и скорость прокрутки принадлежат композитору: после изменения настроек он заново читает конфигурацию, поэтому сброс настроек не оставляет после себя старых значений. Развёрнутые окна раскладываются заново, если панель изменила размер или положение. ### Почему приложения запускаются через `dbus-run-session` Lark часто запускают вложенно — внутри другой сессии (niri, GNOME). Окружение композитора наследуется правильно, но этого мало: однопользовательские программы (`thunar`, `gedo`, файловые менеджеры) через GApplication ищут уже запущенный экземпляр и передают ему свои аргументы. Найденный экземпляр принадлежит внешней сессии, и окно открывается **не в Lark**, а в ней. Поэтому каждое приложение запускается в отдельной сессии D-Bus: ``` dbus-run-session -- thunar ``` Собственная шина отрезает приложение от внешней: запущенного там экземпляра оно не находит и поднимает своё — уже в Lark. Если `dbus-run-session` в системе нет, приложение запускается напрямую (тогда возможен возврат к поведению выше). ## Рабочие области Количество задаётся `[desktop] workspaces` (по умолчанию 4) и меняется в настройках. Окно открывается в текущей области; перенесённое окно остаётся открытым, но не показывается на панели и не попадает на экран до возврата на его область. Если число областей уменьшают, окна исчезнувших областей переезжают в последнюю. ## Текст и шрифты Подписи рисует собственный растровщик на `fontdb` + `fontdue`. Шрифт выбирается автоматически: перебираются системные гарнитуры и выбирается первая, умеющая нарисовать кириллицу — иначе русский интерфейс превратился бы в пустые прямоугольники. Моноширинные и знаковые шрифты пропускаются. Кегль округляется до целых пикселей, а базовая линия — до целого пикселя строки: дробный размер размывает сразу все штрихи, и текст выглядит «потекшим». Дополнительно покрытие глифа проходит через кривую контраста: она отодвигает полутона от середины, поэтому штрих собирается в один плотный столбик вместо двух бледных. Концы шкалы кривая не трогает — мягкие края остаются мягкими. Ширины строк кэшируются отдельно от растров: раскладка меряет текст каждый кадр, и полная растеризация на каждое измерение была бы напрасной работой. ## Поддерживаемые протоколы Помимо `wl_compositor`, `wl_subcompositor`, `wl_shm`, `xdg_wm_base`, `wl_seat`, `wl_output` и `xdg-output`, регистрируются: - `wp_viewporter` — рисование в поверхности меньше окна - `wp_presentation` — обратная связь о времени показа кадра - `xdg-decoration` — согласование декораций с клиентом Не реализовано: XWayland и DRM/KMS, см. `docs/ROADMAP.md`. ### Проверка без дисплея Скрипт поднимает Xvfb, запускает композитор с тестовым клиентом и делает снимок экрана: ```bash sudo apt install xvfb x11-apps imagemagick mesa-utils # eglgears_wayland ./scripts/dev-run.sh ``` Снимок сохраняется в `/tmp/lark-shot.png`. Скрипт сообщает, работает ли клиент: если клиент завершился (например, не смог инициализировать графику), окна на снимке не будет, и это не ошибка композитора. Полезные переменные окружения: | Переменная | Назначение | |------------|------------| | `LARK_BIN` | собранный композитор (по умолчанию `target/debug/lark`) | | `LARK_TEST_DISPLAY` | дисплей Xvfb (по умолчанию `:78`) | | `LARK_TEST_CLIENT` | тестовый клиент (по умолчанию `eglgears_wayland`) | | `LARK_TEST_WAIT` | секунд до снимка (по умолчанию `6`) | | `LARK_TEST_SHOT` | путь к снимку | | `RUST_LOG` | уровень журналирования | При проверке ввода с клавиатуры под Xvfb окно нужно сфокусировать: без оконного менеджера фокус не ставится автоматически. ```bash DISPLAY=:78 xdotool search --name "" | while read w; do xdotool windowfocus $w; done ``` ### На реальном железе Пока только вложенно — из графической сессии: ```bash ./target/release/lark ``` Запуск поверх DRM/KMS (из TTY, без графической сессии) появится вместе с бэкендом DRM/KMS: см. [дорожную карту](ROADMAP.md). ## Тесты ```bash cargo test ``` Тесты покрывают обработку ввода и трейты `KeyboardKeyEvent`, `PointerButtonEvent`, распознавание сочетаний клавиш, геометрию декораций и зон изменения размера, раскладку панели задач и меню «Пуск», переключатель рабочих областей, растровщик текста и раскладку клавиатуры. ## Конфигурация Файл конфигурации: `~/.config/lark/config.toml`. Создаётся автоматически при первом запуске с значениями по умолчанию. ```toml [compositor] backend = "auto" # auto, vulkan, gl, cpu socket = "wayland-1" # запасное имя сокета, если auto не подошёл animations = true # анимации появления меню и настроек [desktop] workspaces = 4 # число рабочих областей background = "#0F0F17" # цвет однотонных обоев wallpaper = "auto" # auto, blue, violet, green, graphite, solid show_home = true # значки из ~/Desktop на рабочем столе [panel] position = "bottom" # bottom, top centered = false # false — значки от левого края, как в Windows 10 height = 48 transparent = true [theme] name = "dark" # light, dark accent = "#0078D4" [decoration] server_side = true # заголовок рисует композитор titlebar_height = 32 button_width = 46 [language] code = "ru-RU" # ru-RU, en-US [keyboard] xkb_layout = "us" # запасная раскладка, если список пуст layouts = ["us", "ru"] # раскладки по порядку переключения (Super+Space) xkb_variant = "" xkb_model = "pc105" xkb_rules = "evdev" xkb_options = "" # например "grp:alt_shift_toggle" repeat_delay = 25 # мс до автоповтора repeat_rate = 600 # символов в секунду [input] touchpad = true scroll_speed = 1.0 [seat] name = "seat0" ```