fix(client): start reliably on Wayland; degrade PTT without X11

On Wayland sessions (notably GNOME + NVIDIA), WebKitGTK's DMABUF renderer
can crash or render a blank window, so the client failed to start. Set
WEBKIT_DISABLE_DMABUF_RENDERER=1 on Wayland unless the user has already set
it themselves.

device_query's global key state needs an X11/XWayland display and panicked
per poll on pure-Wayland setups. Use DeviceState::checked_new() so push-to-
talk degrades to inactive with a single warning instead.

Fixes #96

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwtnpHAoSFr1ZibQgQkNQK
This commit is contained in:
Claude
2026-07-19 10:50:10 +00:00
parent 14e41f38b7
commit da628aa1a7
3 changed files with 31 additions and 3 deletions
+11
View File
@@ -2,5 +2,16 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
// WebKitGTK's DMABUF renderer is known to crash or produce a blank window
// under Wayland (notably on NVIDIA). Disable it on Wayland sessions unless
// the user has already set the variable themselves (any value wins).
#[cfg(target_os = "linux")]
{
let is_wayland = std::env::var_os("WAYLAND_DISPLAY").is_some()
|| std::env::var("XDG_SESSION_TYPE").is_ok_and(|v| v.eq_ignore_ascii_case("wayland"));
if is_wayland && std::env::var_os("WEBKIT_DISABLE_DMABUF_RENDERER").is_none() {
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
}
}
owncord_client_lib::run()
}
+17 -3
View File
@@ -82,13 +82,24 @@ fn is_key_down(vk: i32) -> bool {
use device_query::{DeviceQuery, DeviceState};
// Cache DeviceState per thread — creating it on every call would open/close
// /dev/input/ file descriptors every 20ms in the polling loop.
// checked_new() returns None when no X11 display is reachable (e.g. a
// pure-Wayland session without XWayland), so PTT degrades to "key never
// pressed" instead of panicking on every poll.
thread_local! {
static DEVICE_STATE: DeviceState = DeviceState::new();
static DEVICE_STATE: Option<DeviceState> = {
let ds = DeviceState::checked_new();
if ds.is_none() {
log::warn!(
"PTT unavailable: no X11/XWayland display for global key state"
);
}
ds
};
}
let Some(keycode) = linux::vk_to_keycode(vk) else {
return false;
};
DEVICE_STATE.with(|ds| ds.get_keys().contains(&keycode))
DEVICE_STATE.with(|ds| ds.as_ref().is_some_and(|ds| ds.get_keys().contains(&keycode)))
}
#[cfg(not(any(windows, target_os = "linux")))]
@@ -400,7 +411,10 @@ pub async fn ptt_listen_for_key() -> i32 {
#[cfg(target_os = "linux")]
{
use device_query::{DeviceQuery, DeviceState};
let device_state = DeviceState::new();
let Some(device_state) = DeviceState::checked_new() else {
log::warn!("PTT key capture unavailable: no X11/XWayland display");
return 0;
};
let deadline = std::time::Instant::now() + Duration::from_secs(10);
while std::time::Instant::now() < deadline {
+3
View File
@@ -78,6 +78,9 @@ npm run tauri build
- The desktop client uses TOFU certificate pinning:
- First connection prompts for trust.
- Future connections require the same cert fingerprint.
- Linux/Wayland: the client automatically sets `WEBKIT_DISABLE_DMABUF_RENDERER=1`
on Wayland sessions to work around WebKitGTK rendering crashes. Export the
variable yourself (any value) before launching to override this.
## If Remote Users Cannot Connect