fix(gui): просить программный рендер, чтобы окно создавалось без 3D (#28)

Интерфейс построен на системном WebView, а тот без 3D-ускорения окно не
создаёт. Отсюда весь класс жалоб: не стартует в виртуалке, не стартует с
дефолтным драйвером Microsoft, не стартует без монитора. Диагноз в #17 дал
@de4me: в VirtualBox приложение запускается только после включения галочки
«Включить ускорение 3D».

Перед стартом Tauri TGLock теперь сам запрашивает программный рендер:
- Windows: WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS с --disable-gpu
  и --disable-gpu-compositing;
- Linux: WEBKIT_DISABLE_COMPOSITING_MODE и WEBKIT_DISABLE_DMABUF_RENDERER;
- macOS: не требуется, WebKit сам уходит в программный рендер.

Для панели со статусом программный рендер не стоит ничего заметного, поэтому
он выбран значением по умолчанию, а не аварийным режимом. Уже заданные
оператором переменные не перезаписываются, TGLOCK_FORCE_GPU=1 отключает
механизм целиком.

Логика вынесена в чистую функцию software_rendering_vars и покрыта четырьмя
тестами: значение по умолчанию, отключение через TGLOCK_FORCE_GPU, уважение
чужой переменной и правильный набор ключей на каждой платформе.

Версия поднята до 2.0.0-beta.2 в Cargo.toml, package.json и tauri.conf.json:
нужен тег, чтобы в релиз попали и tglock-cli, и этот фикс.

README получил отдельный вопрос в FAQ про «окно не появляется»,
ARCHITECTURE_V2.md — обновлённый пункт в Current limitations.

Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>
This commit is contained in:
Никита Sonic
2026-07-30 13:40:04 +03:00
committed by GitHub
parent 9bacc488a5
commit b06272437c
7 changed files with 122 additions and 12 deletions
Generated
+1 -1
View File
@@ -3553,7 +3553,7 @@ dependencies = [
[[package]] [[package]]
name = "tglock" name = "tglock"
version = "2.0.0-beta.1" version = "2.0.0-beta.2"
dependencies = [ dependencies = [
"aes", "aes",
"cipher", "cipher",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tglock" name = "tglock"
version = "2.0.0-beta.1" version = "2.0.0-beta.2"
edition = "2021" edition = "2021"
rust-version = "1.88" rust-version = "1.88"
description = "Telegram unblock via local WebSocket tunnel" description = "Telegram unblock via local WebSocket tunnel"
+10
View File
@@ -323,6 +323,16 @@ xattr -cr /Applications/TGLock.app
- На macOS — убедись что снят Gatekeeper (`xattr -cr ...`). - На macOS — убедись что снят Gatekeeper (`xattr -cr ...`).
</details> </details>
<details>
<summary><b>Приложение вообще не запускается — окно не появляется</b></summary>
Так проявляется отсутствие 3D-ускорения: интерфейс построен на системном WebView, а тот без ускорения окно не создаёт. Отсюда же случаи «не работает в виртуалке», «не стартует с дефолтным драйвером Microsoft» и «нет монитора».
Начиная с **2.0.0-beta.2** TGLock сам просит у WebView программный рендер, так что на таких машинах должен запускаться. Если хочется вернуть аппаратное ускорение — запусти с переменной `TGLOCK_FORCE_GPU=1`.
Если окно всё равно не появилось, интерфейс тебе и не нужен: возьми [`tglock-cli`](#-без-графического-интерфейса-tglock-cli), которому WebView не требуется вообще. И напиши в [#10](https://github.com/by-sonic/tglock/issues/10) или [#17](https://github.com/by-sonic/tglock/issues/17), что именно за система — это как раз те ишью.
</details>
<details> <details>
<summary><b>Порт 1080 уже занят другим приложением</b></summary> <summary><b>Порт 1080 уже занят другим приложением</b></summary>
+12 -8
View File
@@ -12,9 +12,11 @@
Фича `gui` включена по умолчанию и подтягивает `tauri`, `tauri-build` и `open`. Фича `gui` включена по умолчанию и подтягивает `tauri`, `tauri-build` и `open`.
При `--no-default-features` ни Tauri, ни системный WebView, ни фронтенд в сборку При `--no-default-features` ни Tauri, ни системный WebView, ни фронтенд в сборку
не попадают, и `build.rs` не вызывает `tauri_build`. Это единственный способ не попадают, и `build.rs` не вызывает `tauri_build`. Так TGLock собирается и
собрать и запустить TGLock там, где WebView не создаёт окно: сервер, контейнер, работает там, где WebView недоступен в принципе: сервер без графического
виртуалка, машина без монитора или без 3D-ускорения. окружения, контейнер, машина без монитора. Для случаев, где WebView есть, но нет
3D-ускорения, GUI дополнительно просит программный рендер — см. Current
limitations.
## Local protocols ## Local protocols
@@ -109,11 +111,13 @@ Worker должен принимать WebSocket на:
- SNI camouflage не включена: небезопасное отключение hostname verification - SNI camouflage не включена: небезопасное отключение hostname verification
из референсной реализации не переносится. из референсной реализации не переносится.
- Голосовые звонки по UDP не поддерживаются. - Голосовые звонки по UDP не поддерживаются.
- **GUI не запускается там, где WebView не может создать окно** — нет - **GUI зависит от WebView, а тот — от 3D-ускорения.** Начиная с
3D-ускорения, дефолтный видеодрайвер, отсутствует монитор, виртуальная 2.0.0-beta.2 приложение перед стартом Tauri само просит программный рендер:
машина. Это ограничение Tauri, а не транспорта; программный рендер как на Windows через `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS`, на Linux через
обходной путь не проверен. Рабочий вариант для таких машин — `tglock-cli` `WEBKIT_DISABLE_COMPOSITING_MODE` и `WEBKIT_DISABLE_DMABUF_RENDERER`. Уже
(issues #10, #17). заданные оператором значения не перезаписываются, а `TGLOCK_FORCE_GPU=1`
возвращает аппаратное ускорение. Для машин без монитора остаётся
`tglock-cli`, которому WebView не нужен вовсе (issues #10, #17).
- Windows-инсталлятор не подписан, macOS-сборка не нотарифицирована. Часть - Windows-инсталлятор не подписан, macOS-сборка не нотарифицирована. Часть
антивирусов реагирует на неподписанный установщик, открывающий локальный антивирусов реагирует на неподписанный установщик, открывающий локальный
сокет; проверяемый ответ — сборка из исходников либо публичные логи сокет; проверяемый ответ — сборка из исходников либо публичные логи
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "tglock-ui", "name": "tglock-ui",
"private": true, "private": true,
"version": "2.0.0-beta.1", "version": "2.0.0-beta.2",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --port 1420", "dev": "vite --port 1420",
+96
View File
@@ -222,7 +222,56 @@ fn push_log(logs: &Arc<Mutex<Vec<LogLine>>>, message: String, error: bool) {
}); });
} }
/// Environment variables that make the WebView render without a GPU.
///
/// The window is never created when 3D acceleration is unavailable: no
/// monitor, the default Microsoft display driver, a virtual machine without
/// 3D enabled (by-sonic/tglock#10, by-sonic/tglock#17). For a small status
/// panel software rendering costs nothing noticeable, so preferring it is the
/// safer default.
///
/// Values already present in the environment are never overwritten, and
/// `TGLOCK_FORCE_GPU` disables the whole mechanism.
fn software_rendering_vars(
force_gpu: bool,
is_set: impl Fn(&str) -> bool,
) -> Vec<(&'static str, &'static str)> {
if force_gpu {
return Vec::new();
}
let candidates: &[(&str, &str)] = if cfg!(target_os = "windows") {
&[(
"WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS",
"--disable-gpu --disable-gpu-compositing",
)]
} else if cfg!(target_os = "macos") {
// WebKit on macOS falls back to software rendering on its own.
&[]
} else {
&[
("WEBKIT_DISABLE_COMPOSITING_MODE", "1"),
("WEBKIT_DISABLE_DMABUF_RENDERER", "1"),
]
};
candidates
.iter()
.filter(|(key, _)| !is_set(key))
.copied()
.collect()
}
fn prefer_software_rendering() {
let force_gpu = std::env::var_os("TGLOCK_FORCE_GPU").is_some();
for (key, value) in software_rendering_vars(force_gpu, |key| std::env::var_os(key).is_some()) {
std::env::set_var(key, value);
}
}
fn main() { fn main() {
prefer_software_rendering();
tauri::Builder::default() tauri::Builder::default()
.setup(|app| { .setup(|app| {
let settings_path = app let settings_path = app
@@ -243,3 +292,50 @@ fn main() {
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("failed to run TGLock"); .expect("failed to run TGLock");
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn software_rendering_is_requested_by_default() {
let vars = software_rendering_vars(false, |_| false);
if cfg!(target_os = "macos") {
assert!(vars.is_empty(), "macOS needs no override");
} else {
assert!(
!vars.is_empty(),
"a machine without 3D acceleration must still get a window"
);
}
}
#[test]
fn force_gpu_disables_the_override() {
assert!(software_rendering_vars(true, |_| false).is_empty());
}
#[test]
fn an_operators_own_value_is_never_overwritten() {
assert!(software_rendering_vars(false, |_| true).is_empty());
}
#[test]
fn windows_uses_webview2_arguments_and_linux_uses_webkit_ones() {
let keys: Vec<_> = software_rendering_vars(false, |_| false)
.into_iter()
.map(|(key, _)| key)
.collect();
if cfg!(target_os = "windows") {
assert_eq!(keys, ["WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS"]);
} else if cfg!(target_os = "linux") {
assert_eq!(
keys,
[
"WEBKIT_DISABLE_COMPOSITING_MODE",
"WEBKIT_DISABLE_DMABUF_RENDERER"
]
);
}
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "TGLock", "productName": "TGLock",
"version": "2.0.0-beta.1", "version": "2.0.0-beta.2",
"identifier": "com.bysonic.tglock", "identifier": "com.bysonic.tglock",
"build": { "build": {
"beforeDevCommand": "npm run dev", "beforeDevCommand": "npm run dev",