use gtk::prelude::*;
pub fn force_paint_gl_context(window: >k::ApplicationWindow) {
if !affected() {
eprintln!("kana-trainer: not on Nvidia/Wayland, the workaround is inactive");
return;
}
if window.is_realized() {
create_gl_context(window);
} else {
window.connect_realize(create_gl_context);
}
}
fn create_gl_context(window: >k::ApplicationWindow) {
let Some(gdk_window) = window.window() else {
return;
};
if let Err(error) = gdk_window.create_gl_context() {
eprintln!("kana-trainer: no GL context for the window, the Wayland/Nvidia workaround is inactive: {error}");
}
}
fn affected() -> bool {
std::env::var("WEBKIT_DISABLE_DMABUF_RENDERER").as_deref() != Ok("1") && nvidia_on_wayland()
}
fn nvidia_on_wayland() -> bool {
let on_wayland = (std::env::var_os("WAYLAND_DISPLAY").is_some()
|| std::env::var_os("WAYLAND_SOCKET").is_some()
|| std::env::var("XDG_SESSION_TYPE").as_deref() == Ok("wayland"))
&& prefers_wayland(std::env::var("GDK_BACKEND").ok().as_deref());
on_wayland && std::path::Path::new("/sys/module/nvidia_drm").exists()
}
fn prefers_wayland(backend: Option<&str>) -> bool {
backend
.and_then(|list| list.split(',').next())
.map(str::trim)
.map_or(true, |item| {
item == "wayland" || item == "*" || item.is_empty()
})
}
#[cfg(test)]
mod tests {
use super::prefers_wayland;
#[test]
fn gdk_backend_ordering() {
assert!(prefers_wayland(None));
assert!(prefers_wayland(Some("wayland")));
assert!(prefers_wayland(Some("wayland,x11")));
assert!(prefers_wayland(Some(" wayland , x11")));
assert!(prefers_wayland(Some("*")));
assert!(!prefers_wayland(Some("x11")));
assert!(!prefers_wayland(Some("x11,wayland")));
}
}
#[cfg(test)]
mod probe {
#[test]
#[ignore = "machine-specific probe, not a pass/fail assertion"]
fn nvidia_on_wayland_here() {
println!("nvidia_on_wayland() = {}", super::nvidia_on_wayland());
}
}