WUI в браузере (WebAssembly)
Экспериментальный бэкенд использует Emscripten, Canvas 2D и браузерные события. Контролы, темы, локализация и логика примеров остаются на C++17. Каждое физическое окно WUI представлено отдельной областью Canvas внутри страницы; вложенные окна продолжают рисоваться общими контролами.
Сборка и запуск
Установите Emscripten SDK и активируйте его окружение. Порт проверяется с Emscripten 6.0.9.
emcmake cmake -S . -B build-wasm-release -DCMAKE_BUILD_TYPE=Release
cmake --build build-wasm-release --target wui_web_site -j 6
python3 -m http.server 8080 --bind 127.0.0.1 --directory build-wasm-release/site
Откройте http://localhost:8080/. На странице доступны hello_world, simple и demo.
На macOS можно установить Emscripten через Homebrew. Если emcc выбирает системный Python 3.9, поставьте подходящий Python первым в PATH, например для Homebrew Python 3.14:
export PATH="$(brew --prefix python@3.14)/libexec/bin:$PATH"
Требуемая версия Python определяется установленным Emscripten. Системный Python менять не требуется.
Размещение на сайте
Цель wui_web_site собирает самостоятельный каталог build-wasm-release/site. Его можно разместить на статическом хостинге, сохранив структуру подкаталогов и файлы .html, .js, .wasm, .data. Сервер должен отдавать .wasm с типом application/wasm. Для публичного сайта используйте HTTPS; браузерный clipboard зависит от контекста и действий пользователя.
Для встраивания в существующий сайт удобно использовать iframe со страницей выбранного примера. При прямом встраивании задайте Module.wuiContainer до загрузки скрипта или предоставьте элемент #wui с определёнными размерами и position: relative. Стили .wui-* приведены в src/wasm/shell.html.
Подключение своего приложения
Используйте toolchain Emscripten, подключите цель wui и собирайте точку входа int main(). Флаги исключений, Asyncify и браузерный JS-бэкенд распространяются через цель библиотеки. Пример настройки executable и предзагрузки ресурсов находится в cmake/WuiWasm.cmake.
framework::run() сохраняет текущий контракт: возвращается после framework::stop(). Asyncify позволяет браузеру обрабатывать события, пока C++-стек приложения сохранён. Поэтому существующие примеры со стековым объектом MainFrame продолжают работать. Asyncify увеличивает размер и стоимость исполнения; текущий путь предназначен для совместимости с desktop-кодом.
Рисование запрашивается через requestAnimationFrame при изменении интерфейса. Логические координаты измеряются в CSS-пикселях; буферы учитывают devicePixelRatio. Браузерные шрифты и их метрики могут отличаться от desktop.
Ресурсы предзагружаются в виртуальный /res. Изображения декодируются браузером асинхронно и вызывают перерисовку после загрузки. Для PNG размеры читаются из заголовка сразу; размеры других поддерживаемых браузером форматов доступны после декодирования.
Поддержка и ограничения
- Кнопки, поля ввода, списки, меню и другие общие контролы; темы и локализация из ресурсов.
- Перемещение и resize окон в странице, разворачивание в контейнер, сворачивание с кнопкой восстановления, вложенные и отдельные модальные окна, отмена закрытия.
- Unicode-ввод, Tab/Shift+Tab, редактирование, браузерные события copy/cut/paste. IME использует вспомогательный
textarea, показывающий текущую композицию. Автотест проверяет события композиции; работу конкретного системного IME и экранных клавиатур нужно проверять на целевых устройствах. - Синхронный
clipboard_get_text()возвращает последний текст, полученный через событие вставки или записанный приложением. Актуальную вставку из системного clipboard выполняйте браузерной командой Paste или Ctrl/Cmd+V. Встроенный пункт Paste в меню WUI пока работает с этой сохранённой копией. - Таймеры и
emit_event()работают через очередь браузера. Первый бэкенд однопоточный; вызовы UI и таймеров выполняются в основном потоке. Pthreads/Worker-интеграция не реализована. Скрытая вкладка может замедлять таймеры. - Файлы и INI-настройки находятся в памяти и сбрасываются при перезагрузке страницы. Постоянное хранение через IndexedDB, импорт/экспорт пользовательских файлов — следующие задачи.
- Системный tray, taskbar, desktop-уведомления и device hotplug не реализованы. Tray/taskbar-вызовы не создают элементов ОС; включение hotplug возвращает ошибку.
- Полное дерево доступности для контролов Canvas пока отсутствует. Браузерный бэкенд остаётся экспериментальным.
Проверки
emcmake cmake -S . -B build-wasm -DCMAKE_BUILD_TYPE=Debug -DWUI_BUILD_TESTS=ON
cmake --build build-wasm -j 6
npm --prefix tests/wasm ci
npx --prefix tests/wasm playwright install chromium firefox webkit
node tests/wasm/smoke.mjs build-wasm
WUI_BROWSER=firefox node tests/wasm/smoke.mjs build-wasm
WUI_BROWSER=webkit node tests/wasm/smoke.mjs build-wasm
Тест сам поднимает локальный HTTP-сервер и закрывает его после проверки. Проверяются загрузка трёх примеров, ошибки браузера, отрисовка и скриншоты; при WUI_BUILD_TESTS=ON также выполняются проверки кликов, Unicode, clipboard, IME-событий, фокуса, модальности, resize, таймеров и завершения run(). WebKit в Playwright проверяет движок, а не установленное приложение Safari.