- Vala 72.5%
- Python 19.6%
- SCSS 5%
- Meson 2.1%
- Shell 0.6%
- Other 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Попап шире самой кнопки, а виджет сидит у правого края панели — без явного halign=END GTK центрировал попап на кнопке и обрезал правый верхний угол за пределами монитора. Добавлены переключатели LAVD и ananicy-cpp прямо в попап (видны только если доступен sched_ext) — те же юниты и то же полиси без пароля, что и в Tuner → Питание. Массив юнитов для EnableUnitFiles/DisableUnitFiles собирается через VariantBuilder, а не string[]-литералом в Variant(...) — последнее валит процесс сегфолтом (тот же баг, что и в Tuner-плагине сегодня). |
||
| .forgejo/workflows | ||
| api | ||
| assets | ||
| build-aux/altlinux | ||
| core | ||
| data | ||
| docs | ||
| fuzz | ||
| modules | ||
| scripts | ||
| services | ||
| tests | ||
| widgets | ||
| .gitignore | ||
| build-native.sh | ||
| build.sh | ||
| CHANGELOG.md | ||
| Containerfile | ||
| CONTRIBUTING.md | ||
| DANKMATERIALSHELL_PLAN.md | ||
| DESIGN.md | ||
| dev-run.sh | ||
| index.md | ||
| pytest.ini | ||
| README.md | ||
| SECURITY.md | ||
| Vala.md | ||
| Vala_Develop.md | ||
NitiVala
Wayland-панель для тайлового скроллинг-композитора Niri. Написана на Vala (компилируется в нативный C/GObject-код) с использованием GTK4 и gtk4-layer-shell. Быстрая работа, мгновенный отклик и минимальное потребление ресурсов. Создана специально для ALT Atomic Niri и выступает там в качестве нативного псевдо-шелла по аналогии с gnome-shell.
NitiVala — официальное продолжение проекта Niti (Go-версия больше не разрабатывается). Полный переписанный с нуля порт на Vala с плагинной архитектурой, стандартизированной структурой виджетов и модульным ядром.
![]() |
![]() |
Что это
NitiVala — это панель плюс набор окон-компаньонов для Niri: лаунчер приложений, быстрое меню (Quick Center), уведомления, OSD-индикаторы, меню выключения, календарь, сетка приложений. Всё рисуется как нативные Wayland-слои (layer-shell) и управляется через IPC Niri. Сам композитор и сессию Niri не заменяет — работает рядом с ними.
Почему Vala
Переход с Go на Vala — не смена языка ради языка, а переход на технологию, для которой GObject/GTK — родная экосистема, а не набор биндингов поверх C API.
| Преимущество | Что это даёт |
|---|---|
| Нулевые накладные расходы биндингов | Vala компилируется напрямую в тот же C/GObject код, который использует сам GTK — нет прослойки маршалинга типов, как в Go-биндингах (gotk4) |
| Плагинная архитектура (libpeas) | каждый виджет — независимый .so-модуль, загружаемый динамически. Можно пересобрать и заменить один виджет, не трогая и не перезапуская остальную панель |
| Единый статический нативный бинарник ядра | как и раньше — мгновенный запуск, минимальный RAM/CPU в простое |
| GObject Introspection из коробки | у каждого сервиса есть .vapi/.gir/.typelib — сторонние плагины (в том числе не на Vala — Python, C, JS) видят типы друг друга автоматически, без ручного описания API |
| Нативный синтаксис для GObject-паттернов | свойства и сигналы объявляются как public string foo { get; set; }, без генерируемого boilerplate |
| Кросс-языковая тестируемость | чистая логика сервисов (парсеры, форматтеры, вычисления) покрыта pytest-тестами через ту же интроспекцию — тесты гоняют реальный скомпилированный код, не пересказ логики на другом языке |
Итог: та же нативная скорость и низкий расход памяти, что и раньше, плюс возможность расширять панель третьими сторонами без пересборки всего проекта.
Плагинная система — свой виджет без правки ядра
Каждый виджет панели — самостоятельный плагин libpeas, реализующий один простой контракт:
namespace Niti {
public abstract class Widget : Peas.ExtensionBase {
public abstract Gtk.Widget get_root ();
}
}
Панель ничего не знает о конкретных виджетах заранее — она сканирует каталог плагинов, инстанцирует всё, что реализует Niti.Widget, и расставляет по зонам (left/center/right) согласно config.json. Стандартная структура плагина-виджета:
widgets/<name>/
meson.build
data/
<name>.plugin.in — манифест libpeas (имя, модуль, описание)
default_settings.json — настройки виджета по умолчанию
icons/ — опционально: кастомные symbolic-иконки через GResource
src/
plugin.vala — реализация Niti.Widget
meson.build
Виджету доступны все системные сервисы через тот же механизм интроспекции (Niti.Upower.Service.get_default(), Niti.Network.Service.get_default() и т.д.) — не нужно ничего регистрировать в ядре вручную. Модули-оверлеи (Launcher, QuickCenter, Calendar...) устроены по тому же принципу — прозрачная граница между "ядром" и "обвесом" вокруг него.
Возможности
Панель (Bar)
Панель с виджетами в трёх зонах — левая, центр, правая. Состав по умолчанию:
| Зона | Виджеты |
|---|---|
| Левая | Рабочие столы (workspaces), Таскбар (tasks) |
| Центр | Часы (clock), Медиа (media) |
| Правая | Горячие клавиши (hotkeys), Обновления (systeminfo), Диски (disks), Системный монитор (vitals, CPU/RAM/temp), Питание (power), Caffeine (caffeine), Раскладка клавиатуры (keyboard), Трей (tray), Быстрое меню (quickbutton) |
Дополнительные виджеты, не включённые по умолчанию — подключаются добавлением в config.json: запись экрана (recording, PipeWire), заряд периферии (peripheria, клавиатура/мышь/геймпад), планировщик LAVD (lavd).
Состав зон, порядок и параметры каждого виджета — в ~/.config/niti-vala/config.json.
Профили потребления
В корне ~/.config/niti-vala/panel.json можно выбрать профиль:
{ "profile": "minimal" }
minimal оставляет часы, рабочие столы, таскбар и Launcher; balanced
сохраняет обычный состав панели и оверлеев; full включает дополнительные
виджеты, включая lavd и recording. Индивидуальная настройка модуля
{"enabled": false} или {"enabled": true} имеет приоритет над профилем.
Окна и оверлеи
| Модуль | Что делает |
|---|---|
| Launcher | запуск приложений (Mod+D): парсинг .desktop, поиск, закреплённые и недавние приложения |
| AppGrid | сетка установленных приложений (Mod+G), кастомный порядок значков |
| QuickCenter | быстрое меню: заряд периферии, ползунки громкости/яркости, WiFi/Bluetooth/DND/Ночной свет/Тёмный режим, медиаплеер, список уведомлений |
| OSD | всплывающие индикаторы громкости и яркости |
| Notifications | встроенный демон уведомлений (org.freedesktop.Notifications), поддержка DND |
| Calendar | календарь-попап (клик по часам), интеграция с Evolution Data Server |
| Corners | скруглённые углы экрана |
| Hotkeys | оверлей со списком горячих клавиш из config.kdl Niri |
Тема и внешний вид
Цветовая схема — Material You (Material 3), генерируется matugen из текущих обоев и переключается вместе с системным светлым/тёмным режимом (org.gnome.desktop.interface color-scheme) — панель, Quick Center и все всплывающие окна следуют за темой целиком, включая иконки. Автоматически синхронизируется акцентный цвет GTK-приложений (accent-color).
Стили написаны на SCSS и компилируются в рантайме, поэтому оформление можно менять «на лету» через ~/.config/niti-vala/styles/ и ~/.config/niti-vala/colors.scss, без пересборки панели.
Каноничность GTK4/GNOME
NitiVala старается не изобретать свои решения там, где платформа уже даёт правильный, ожидаемый способ — и следовать духу GNOME HIG даже в мелочах:
- Кастомные иконки — только через GResource, никаких
Gtk.Image.set_from_file()по абсолютному пути. SVG встраивается в бинарник плагина черезgnome.compile_resources()и регистрируется вGtk.IconThemeтем же способом, каким это делает любое нативное GNOME-приложение —icon-name, а не путь к файлу. - Symbolic-recoloring вместо хардкода цвета. Иконки поставляются как обычные
-symbolic.svgс единственным заполняющим цветом — реальный цвет всегда берётся GTK4 из CSScolor(текущего токена темы), поэтому светлая/тёмная схема подхватывается автоматически, без единой строчки «если тёмная тема — цвет такой-то». UPower.Device.IconName, а не самодельные пороги. Индикатор заряда (ноутбук и периферия) использует готовое имя иконки по freedesktop icon naming spec (battery-level-N[-charging]-symbolic) прямо из системного сервиса, вместо таблицы захардкоженных Material-глифов на пороги процентов.Gtk.Widget.overflow, а не самодельная обрезка. Скруглённые составные контейнеры (плитки Quick Center, попап уведомлений) клипают содержимое через нативное свойство виджета, а не вручную вычисленными масками поверх.- Слои Wayland по спецификации, не «лишь бы сверху».
topдля панели и большинства оверлеев — по протоколуwlr-layer-shellон корректно скрывается за полноэкранными окнами;overlayиспользуется точечно и осознанно там, где окно обязано быть видно всегда (например, поверх видео/игр), а не как обходной путь для z-order. - Тема и акцент — через системные ключи GNOME, не свою настройку.
org.gnome.desktop.interface(color-scheme,accent-color) — те же ключи, которыми пользуются Параметры GNOME и любое libadwaita-приложение; переключение темы в NitiVala остаётся синхронным с остальной системой, а не живёт своей отдельной жизнью.
Архитектура
core/ — ядро: GTK Application, окно панели, менеджер плагинов, тема
api/ — публичный API ядра для плагинов: Niti.Widget, Settings, Config, WindowRegistry
widgets/ — виджеты панели, каждый — независимый libpeas-плагин (см. выше)
modules/ — окна-оверлеи: launcher, appgrid (в составе launcher), quickcenter, calendar,
notifications, corners, hotkeys
services/ — интеграции с системой, каждая — отдельная библиотека с .vapi/.gir
assets/ — SCSS-стили, шрифты, шаблоны
tests/ — pytest через GObject Introspection: чистая логика сервисов и виджетов
Сервисы — интеграции с системой
Каждый источник данных — отдельная библиотека (niti-<name>-1.0) с собственным .vapi/.gir, общающаяся через D-Bus или IPC:
niri (IPC Niri), audio (PipeWire), mpris (медиаплееры), network (NetworkManager), bluetooth (BlueZ), backlight (яркость), upower (питание/батарея, в т.ч. периферии), systemtray (SNI + DBusMenu), notifications (демон уведомлений), applications (парсинг .desktop), matugen (обои → цветовая схема), udisks (диски), pwrec (запись экрана), abooster (интеграция с Atomic Booster), eds (Evolution Data Server, календарь), layout (настраиваемые списки QC — плитки/слайдеры/шапка через JSON).
Системные интеграции: systemd и D-Bus
systemd
Панель работает как пользовательский сервис (niti-vala.service), сессия запускает её вместе с графическим окружением. Других сервисов панель при старте не поднимает; через systemctl выполняются только явные действия пользователя (меню выключения, управление планировщиком scx_lavd).
D-Bus
| Шина | Сервис | Для чего |
|---|---|---|
| System | org.freedesktop.NetworkManager |
Wi-Fi/сети |
| System | org.bluez |
Bluetooth |
| System | org.freedesktop.UPower |
питание/батарея, в т.ч. периферии |
| System | org.freedesktop.UDisks2 |
диски |
| Session | org.mpris.MediaPlayer2 |
медиаплееры (бар + Quick Center) |
| Session | org.freedesktop.Notifications |
NitiVala регистрирует это имя — является демоном уведомлений |
| Session | org.kde.StatusNotifierItem + com.canonical.dbusmenu |
системный трей (иконки + меню) |
| Session | org.plafonlinux.AtomicBooster |
интеграция с Atomic Booster |
| Session | org.gnome.evolution.dataserver.Calendar (через libecal) |
события календаря (EDS) |
Прочие IPC
- Niri — собственный IPC через unix-сокет: окна, воркспейсы, события, действия.
- NitiVala ↔ NitiVala — единый unix-сокет для внешних команд (
--open-window,--toggle-window,--set-textи т.д.) — так с панелью общаются биндинги Niri (Mod+D→ Launcher и т.д.).
Сборка и разработка
Сборка происходит в контейнере (нужны valac/meson, которых нет на неизменяемом ALT Atomic хосте), а готовый бинарник устанавливается напрямую на хост и запускается нативно — версии libglib2/libgtk4/libpeas2 у контейнера сборки и хоста ALT Atomic совпадают, ABI-конфликтов нет.
git clone https://altlinux.space/plafonlinux/NitiVala.git
cd NitiVala
bash build-native.sh # сборка в контейнере, установка в ~/.local
systemctl --user restart niti-vala.service
Зависимости для сборки (уже включены в образ сборки, см. Containerfile):
vala,meson,ninja-build,gcc,pkgconfiglibgtk4-devel,libgtk4-layer-shell-devel(+-vala,-girпакеты)libpeas2-devel,gobject-introspection-devellibjson-glib-develevolution-data-server-devel(+-vala)dart-sass(компиляция тем в рантайме)
Тесты
podman run --rm -v $PWD:/src:Z -w /src niti-vala-dev bash -c \
"bash build.sh && python3 -m pytest tests/ -q"
Тесты гоняют реальную скомпилированную логику сервисов через GObject Introspection (Python ↔ Vala), не пересказ на другом языке.
Конфигурация
| Файл | Назначение |
|---|---|
~/.config/niti-vala/config.json |
зоны панели, состав и включённость виджетов, режим/цвет/слой панели |
~/.config/niti-vala/quickcenter-layout.json |
состав и порядок плиток/слайдеров/шапки Quick Center |
~/.config/niti-vala/accent.json |
ручной оверрайд акцентного цвета и режима темы (авто/принудительно светлая/тёмная) |
~/.config/niti-vala/appgrid.json |
сортировка и порядок иконок в сетке приложений |
~/.config/niti-vala/colors.scss |
цветовая палитра (Material 3), генерируется matugen |
~/.config/niti-vala/styles/ |
SCSS-стили, компилируются в рантайме |
Подавляющее большинство параметров панели описано JSON-файлами — включение/выключение виджетов, их порядок, пороги, показывать ли периферию, режим слоя окна и т.д. Настройка не требует пересборки, только systemctl --user restart niti-vala.service (или живой hot-reload для стилей).
Агент секретов NetworkManager
Niti регистрирует org.altlinux.niti.SecretAgent на системной шине и
org.altlinux.Niti.SecretAgent на сессионной. Пароли Wi-Fi, 802.1x и VPN
сохраняются через libsecret в связке ключей пользователя; при необходимости
панель показывает русское окно запроса пароля.
Санитайзеры и valgrind
В CI по dev и ежедневно выполняются сборка ASan/UBSan, тест API без дисплея
и отдельный make memcheck. Локально используйте meson setup build --wipe -Db_sanitize=address,undefined, затем meson test -C build atomicbooster-api;
подавления внешних библиотек находятся в tests/sanitizers/.

