refactor: Linux environment detection logic (#5108)
* fix: wayland framebuffer * refactor(utils): move linux env heuristics into platform helper * refactor(linux): let DMABUF override helper use resolved decision * fix: clippy * fix: clippy * feat: NVIDIA detection * fix: clippy
This commit is contained in:
@@ -59,6 +59,7 @@
|
||||
- 修复删除订阅时未能实际删除相关文件
|
||||
- 修复 macOS 连接界面显示异常
|
||||
- 修复规则配置项在不同配置文件间全局共享导致切换被重置的问题
|
||||
- 修复 Linux Wayland 下部分 GPU 可能出现的 UI 渲染问题
|
||||
|
||||
## v2.4.2
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ mod feat;
|
||||
mod module;
|
||||
mod process;
|
||||
pub mod utils;
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::utils::linux;
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::utils::window_manager::WindowManager;
|
||||
use crate::{
|
||||
@@ -234,89 +236,7 @@ pub fn run() {
|
||||
|
||||
// Set Linux environment variable
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let desktop_env = std::env::var("XDG_CURRENT_DESKTOP")
|
||||
.unwrap_or_default()
|
||||
.to_uppercase();
|
||||
let session_desktop = std::env::var("XDG_SESSION_DESKTOP")
|
||||
.unwrap_or_default()
|
||||
.to_uppercase();
|
||||
let desktop_session = std::env::var("DESKTOP_SESSION")
|
||||
.unwrap_or_default()
|
||||
.to_uppercase();
|
||||
let is_kde_desktop = desktop_env.contains("KDE");
|
||||
let is_plasma_desktop = desktop_env.contains("PLASMA");
|
||||
let is_hyprland_desktop = desktop_env.contains("HYPR")
|
||||
|| session_desktop.contains("HYPR")
|
||||
|| desktop_session.contains("HYPR");
|
||||
|
||||
let is_wayland_session = std::env::var("XDG_SESSION_TYPE")
|
||||
.map(|value| value.eq_ignore_ascii_case("wayland"))
|
||||
.unwrap_or(false)
|
||||
|| std::env::var("WAYLAND_DISPLAY").is_ok();
|
||||
let prefer_native_wayland =
|
||||
is_wayland_session && (is_kde_desktop || is_plasma_desktop || is_hyprland_desktop);
|
||||
let dmabuf_override = std::env::var("WEBKIT_DISABLE_DMABUF_RENDERER");
|
||||
|
||||
if prefer_native_wayland {
|
||||
let compositor_label = if is_hyprland_desktop {
|
||||
"Hyprland"
|
||||
} else if is_plasma_desktop {
|
||||
"KDE Plasma"
|
||||
} else {
|
||||
"KDE"
|
||||
};
|
||||
|
||||
if matches!(dmabuf_override.as_deref(), Ok("1")) {
|
||||
unsafe {
|
||||
std::env::remove_var("WEBKIT_DISABLE_DMABUF_RENDERER");
|
||||
}
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"Wayland + {} detected: Re-enabled WebKit DMABUF renderer to avoid Cairo surface failures.",
|
||||
compositor_label
|
||||
);
|
||||
} else {
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"Wayland + {} detected: Using native Wayland backend for reliable rendering.",
|
||||
compositor_label
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if dmabuf_override.is_err() {
|
||||
unsafe {
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
}
|
||||
}
|
||||
|
||||
// Force X11 backend for tray icon compatibility on Wayland
|
||||
if is_wayland_session {
|
||||
unsafe {
|
||||
std::env::set_var("GDK_BACKEND", "x11");
|
||||
std::env::remove_var("WAYLAND_DISPLAY");
|
||||
}
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"Wayland detected: Forcing X11 backend for tray icon compatibility"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if is_kde_desktop || is_plasma_desktop {
|
||||
unsafe {
|
||||
std::env::set_var("GTK_CSD", "0");
|
||||
}
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"KDE detected: Disabled GTK CSD for better titlebar stability."
|
||||
);
|
||||
}
|
||||
}
|
||||
linux::configure_environment();
|
||||
|
||||
// Create and configure the Tauri builder
|
||||
let builder = app_init::setup_plugins(tauri::Builder::default())
|
||||
|
||||
522
src-tauri/src/utils/linux.rs
Normal file
522
src-tauri/src/utils/linux.rs
Normal file
@@ -0,0 +1,522 @@
|
||||
use crate::logging;
|
||||
use crate::utils::logging::Type;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const DRM_PATH: &str = "/sys/class/drm";
|
||||
const INTEL_VENDOR_ID: &str = "0x8086";
|
||||
const NVIDIA_VENDOR_ID: &str = "0x10de";
|
||||
const NVIDIA_VERSION_PATH: &str = "/proc/driver/nvidia/version";
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
struct IntelGpuDetection {
|
||||
has_intel: bool,
|
||||
intel_is_primary: bool,
|
||||
inconclusive: bool,
|
||||
}
|
||||
|
||||
impl IntelGpuDetection {
|
||||
fn should_disable_dmabuf(&self) -> bool {
|
||||
self.intel_is_primary || self.inconclusive
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct NvidiaGpuDetection {
|
||||
has_nvidia: bool,
|
||||
nvidia_is_primary: bool,
|
||||
missing_boot_vga: bool,
|
||||
open_kernel_module: bool,
|
||||
driver_summary: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum NvidiaDmabufDisableReason {
|
||||
PrimaryOpenKernelModule,
|
||||
MissingBootVga,
|
||||
PreferNativeWayland,
|
||||
}
|
||||
|
||||
impl NvidiaGpuDetection {
|
||||
fn disable_reason(&self, session: &SessionEnv) -> Option<NvidiaDmabufDisableReason> {
|
||||
if !session.is_wayland {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !self.has_nvidia {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !self.open_kernel_module {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.nvidia_is_primary {
|
||||
return Some(NvidiaDmabufDisableReason::PrimaryOpenKernelModule);
|
||||
}
|
||||
|
||||
if self.missing_boot_vga {
|
||||
return Some(NvidiaDmabufDisableReason::MissingBootVga);
|
||||
}
|
||||
|
||||
if session.prefer_native_wayland {
|
||||
return Some(NvidiaDmabufDisableReason::PreferNativeWayland);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SessionEnv {
|
||||
is_kde_plasma: bool,
|
||||
is_wayland: bool,
|
||||
prefer_native_wayland: bool,
|
||||
compositor_label: String,
|
||||
}
|
||||
|
||||
impl SessionEnv {
|
||||
fn gather() -> Self {
|
||||
let desktop_env = env::var("XDG_CURRENT_DESKTOP")
|
||||
.unwrap_or_default()
|
||||
.to_uppercase();
|
||||
let session_desktop = env::var("XDG_SESSION_DESKTOP")
|
||||
.unwrap_or_default()
|
||||
.to_uppercase();
|
||||
let desktop_session = env::var("DESKTOP_SESSION")
|
||||
.unwrap_or_default()
|
||||
.to_uppercase();
|
||||
|
||||
let is_kde_plasma = desktop_env.contains("KDE")
|
||||
|| session_desktop.contains("KDE")
|
||||
|| desktop_session.contains("KDE")
|
||||
|| desktop_env.contains("PLASMA")
|
||||
|| session_desktop.contains("PLASMA")
|
||||
|| desktop_session.contains("PLASMA");
|
||||
let is_hyprland = desktop_env.contains("HYPR")
|
||||
|| session_desktop.contains("HYPR")
|
||||
|| desktop_session.contains("HYPR");
|
||||
let is_wayland = env::var("XDG_SESSION_TYPE")
|
||||
.map(|value| value.eq_ignore_ascii_case("wayland"))
|
||||
.unwrap_or(false)
|
||||
|| env::var("WAYLAND_DISPLAY").is_ok();
|
||||
let prefer_native_wayland = is_wayland && (is_kde_plasma || is_hyprland);
|
||||
let compositor_label = if is_hyprland {
|
||||
String::from("Hyprland")
|
||||
} else if is_kde_plasma {
|
||||
String::from("KDE Plasma")
|
||||
} else {
|
||||
String::from("Wayland compositor")
|
||||
};
|
||||
|
||||
Self {
|
||||
is_kde_plasma,
|
||||
is_wayland,
|
||||
prefer_native_wayland,
|
||||
compositor_label,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DmabufOverrides {
|
||||
user_preference: Option<bool>,
|
||||
dmabuf_override: Option<String>,
|
||||
}
|
||||
|
||||
impl DmabufOverrides {
|
||||
fn gather() -> Self {
|
||||
let user_preference = env::var("CLASH_VERGE_DMABUF").ok().and_then(|value| {
|
||||
match value.trim().to_ascii_lowercase().as_str() {
|
||||
"1" | "true" | "enable" | "on" => Some(true),
|
||||
"0" | "false" | "disable" | "off" => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
let dmabuf_override = env::var("WEBKIT_DISABLE_DMABUF_RENDERER").ok();
|
||||
|
||||
Self {
|
||||
user_preference,
|
||||
dmabuf_override,
|
||||
}
|
||||
}
|
||||
|
||||
fn has_env_override(&self) -> bool {
|
||||
self.dmabuf_override.is_some()
|
||||
}
|
||||
|
||||
fn should_override_env(&self, decision: &DmabufDecision) -> bool {
|
||||
if self.user_preference.is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if decision.enable_dmabuf {
|
||||
return true;
|
||||
}
|
||||
|
||||
!self.has_env_override()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DmabufDecision {
|
||||
enable_dmabuf: bool,
|
||||
force_x11_backend: bool,
|
||||
warn: bool,
|
||||
message: Option<String>,
|
||||
}
|
||||
|
||||
impl DmabufDecision {
|
||||
fn resolve(
|
||||
session: &SessionEnv,
|
||||
overrides: &DmabufOverrides,
|
||||
intel_gpu: IntelGpuDetection,
|
||||
nvidia_gpu: &NvidiaGpuDetection,
|
||||
) -> Self {
|
||||
let mut decision = Self {
|
||||
enable_dmabuf: true,
|
||||
force_x11_backend: false,
|
||||
warn: false,
|
||||
message: None,
|
||||
};
|
||||
|
||||
match overrides.user_preference {
|
||||
Some(true) => {
|
||||
decision.enable_dmabuf = true;
|
||||
decision.message =
|
||||
Some("CLASH_VERGE_DMABUF=1: 强制启用 WebKit DMABUF 渲染。".into());
|
||||
}
|
||||
Some(false) => {
|
||||
decision.enable_dmabuf = false;
|
||||
decision.message =
|
||||
Some("CLASH_VERGE_DMABUF=0: 强制禁用 WebKit DMABUF 渲染。".into());
|
||||
if session.is_wayland && !session.prefer_native_wayland {
|
||||
decision.force_x11_backend = true;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if overrides.has_env_override() {
|
||||
if overrides.dmabuf_override.as_deref() == Some("1") {
|
||||
decision.enable_dmabuf = false;
|
||||
decision.message = Some(
|
||||
"检测到 WEBKIT_DISABLE_DMABUF_RENDERER=1,沿用用户的软件渲染配置。"
|
||||
.into(),
|
||||
);
|
||||
if session.is_wayland && !session.prefer_native_wayland {
|
||||
decision.force_x11_backend = true;
|
||||
}
|
||||
} else {
|
||||
decision.enable_dmabuf = true;
|
||||
let value = overrides.dmabuf_override.clone().unwrap_or_default();
|
||||
decision.message = Some(format!(
|
||||
"检测到 WEBKIT_DISABLE_DMABUF_RENDERER={},沿用用户配置。",
|
||||
value
|
||||
));
|
||||
}
|
||||
} else if let Some(reason) = nvidia_gpu.disable_reason(session) {
|
||||
decision.enable_dmabuf = false;
|
||||
decision.warn = true;
|
||||
if session.is_wayland && !session.prefer_native_wayland {
|
||||
decision.force_x11_backend = true;
|
||||
}
|
||||
let summary = nvidia_gpu
|
||||
.driver_summary
|
||||
.as_deref()
|
||||
.and_then(|line| {
|
||||
extract_nvidia_driver_version(line)
|
||||
.map(|version| format!("NVIDIA Open Kernel Module {}", version))
|
||||
})
|
||||
.unwrap_or_else(|| String::from("NVIDIA Open Kernel Module"));
|
||||
let message = match reason {
|
||||
NvidiaDmabufDisableReason::PrimaryOpenKernelModule => format!(
|
||||
"Wayland 会话检测到 {}:禁用 WebKit DMABUF 渲染以规避协议错误。",
|
||||
summary
|
||||
),
|
||||
NvidiaDmabufDisableReason::MissingBootVga => format!(
|
||||
"Wayland 会话检测到 {},但缺少 boot_vga 信息:预防性禁用 WebKit DMABUF。",
|
||||
summary
|
||||
),
|
||||
NvidiaDmabufDisableReason::PreferNativeWayland => format!(
|
||||
"Wayland ({}) + {}:检测到 NVIDIA Open Kernel Module 在辅 GPU 上运行,预防性禁用 WebKit DMABUF。",
|
||||
session.compositor_label, summary
|
||||
),
|
||||
};
|
||||
decision.message = Some(message);
|
||||
} else if session.prefer_native_wayland && !intel_gpu.should_disable_dmabuf() {
|
||||
decision.enable_dmabuf = true;
|
||||
decision.message = Some(format!(
|
||||
"Wayland + {} detected: 使用原生 DMABUF 渲染。",
|
||||
session.compositor_label
|
||||
));
|
||||
} else {
|
||||
decision.enable_dmabuf = false;
|
||||
if session.is_wayland && !session.prefer_native_wayland {
|
||||
decision.force_x11_backend = true;
|
||||
}
|
||||
|
||||
if intel_gpu.should_disable_dmabuf() && session.is_wayland {
|
||||
decision.warn = true;
|
||||
if intel_gpu.inconclusive {
|
||||
decision.message = Some("Wayland 上检测到 Intel GPU,但缺少 boot_vga 信息:预防性禁用 WebKit DMABUF,若确认非主 GPU 可通过 CLASH_VERGE_DMABUF=1 覆盖。".into());
|
||||
} else {
|
||||
decision.message = Some("Wayland 上检测到 Intel 主 GPU (0x8086):禁用 WebKit DMABUF 以避免帧缓冲失败。".into());
|
||||
}
|
||||
} else if session.is_wayland {
|
||||
decision.message = Some(
|
||||
"Wayland 会话未匹配受支持的合成器:禁用 WebKit DMABUF 渲染。".into(),
|
||||
);
|
||||
} else {
|
||||
decision.message =
|
||||
Some("禁用 WebKit DMABUF 渲染以获得更稳定的输出。".into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decision
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_intel_gpu() -> IntelGpuDetection {
|
||||
let Ok(entries) = fs::read_dir(DRM_PATH) else {
|
||||
return IntelGpuDetection::default();
|
||||
};
|
||||
|
||||
let mut detection = IntelGpuDetection::default();
|
||||
let mut seen_devices: HashSet<PathBuf> = HashSet::new();
|
||||
let mut missing_boot_vga = false;
|
||||
|
||||
for entry in entries.flatten() {
|
||||
let name = entry.file_name();
|
||||
let name = name.to_string_lossy();
|
||||
|
||||
if !(name.starts_with("renderD") || name.starts_with("card")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let device_path = entry.path().join("device");
|
||||
let device_key = fs::canonicalize(&device_path).unwrap_or(device_path);
|
||||
|
||||
if !seen_devices.insert(device_key.clone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let vendor_path = device_key.join("vendor");
|
||||
let Ok(vendor) = fs::read_to_string(&vendor_path) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if !vendor.trim().eq_ignore_ascii_case(INTEL_VENDOR_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
detection.has_intel = true;
|
||||
|
||||
let boot_vga_path = device_key.join("boot_vga");
|
||||
match fs::read_to_string(&boot_vga_path) {
|
||||
Ok(flag) => {
|
||||
if flag.trim() == "1" {
|
||||
detection.intel_is_primary = true;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
missing_boot_vga = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if detection.has_intel && !detection.intel_is_primary && missing_boot_vga {
|
||||
detection.inconclusive = true;
|
||||
}
|
||||
|
||||
detection
|
||||
}
|
||||
|
||||
fn detect_nvidia_gpu() -> NvidiaGpuDetection {
|
||||
let mut detection = NvidiaGpuDetection::default();
|
||||
let entries = match fs::read_dir(DRM_PATH) {
|
||||
Ok(entries) => entries,
|
||||
Err(err) => {
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"无法读取 DRM 设备目录 {}({}),尝试通过 NVIDIA 驱动摘要进行降级检测。",
|
||||
DRM_PATH,
|
||||
err
|
||||
);
|
||||
detection.driver_summary = read_nvidia_driver_summary();
|
||||
if let Some(summary) = detection.driver_summary.as_ref() {
|
||||
detection.open_kernel_module = summary_indicates_open_kernel_module(summary);
|
||||
detection.has_nvidia = true;
|
||||
detection.missing_boot_vga = true;
|
||||
} else {
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"降级检测失败:未能读取 NVIDIA 驱动摘要,保留 WebKit DMABUF。"
|
||||
);
|
||||
}
|
||||
return detection;
|
||||
}
|
||||
};
|
||||
|
||||
let mut seen_devices: HashSet<PathBuf> = HashSet::new();
|
||||
|
||||
for entry in entries.flatten() {
|
||||
let name = entry.file_name();
|
||||
let name = name.to_string_lossy();
|
||||
|
||||
if !(name.starts_with("renderD") || name.starts_with("card")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let device_path = entry.path().join("device");
|
||||
let device_key = fs::canonicalize(&device_path).unwrap_or(device_path);
|
||||
|
||||
if !seen_devices.insert(device_key.clone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let vendor_path = device_key.join("vendor");
|
||||
let Ok(vendor) = fs::read_to_string(&vendor_path) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if !vendor.trim().eq_ignore_ascii_case(NVIDIA_VENDOR_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
detection.has_nvidia = true;
|
||||
|
||||
let boot_vga_path = device_key.join("boot_vga");
|
||||
match fs::read_to_string(&boot_vga_path) {
|
||||
Ok(flag) => {
|
||||
if flag.trim() == "1" {
|
||||
detection.nvidia_is_primary = true;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
detection.missing_boot_vga = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if detection.has_nvidia {
|
||||
detection.driver_summary = read_nvidia_driver_summary();
|
||||
match detection.driver_summary.as_ref() {
|
||||
Some(summary) => {
|
||||
detection.open_kernel_module = summary_indicates_open_kernel_module(summary);
|
||||
}
|
||||
None => {
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"检测到 NVIDIA 设备,但无法读取 {},默认视为未启用开源内核模块。",
|
||||
NVIDIA_VERSION_PATH
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detection
|
||||
}
|
||||
|
||||
fn read_nvidia_driver_summary() -> Option<String> {
|
||||
match fs::read_to_string(NVIDIA_VERSION_PATH) {
|
||||
Ok(content) => content
|
||||
.lines()
|
||||
.next()
|
||||
.map(|line| line.trim().to_string())
|
||||
.filter(|line| !line.is_empty()),
|
||||
Err(err) => {
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"读取 {} 失败:{}",
|
||||
NVIDIA_VERSION_PATH,
|
||||
err
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn summary_indicates_open_kernel_module(summary: &str) -> bool {
|
||||
let normalized = summary.to_ascii_lowercase();
|
||||
const PATTERNS: [&str; 4] = [
|
||||
"open kernel module",
|
||||
"open kernel modules",
|
||||
"open gpu kernel module",
|
||||
"open gpu kernel modules",
|
||||
];
|
||||
|
||||
let is_open = PATTERNS.iter().any(|pattern| normalized.contains(pattern));
|
||||
|
||||
if !is_open && normalized.contains("open") {
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"检测到 NVIDIA 驱动摘要包含 open 关键字但未匹配已知开源模块格式:{}",
|
||||
summary
|
||||
);
|
||||
}
|
||||
|
||||
is_open
|
||||
}
|
||||
|
||||
fn extract_nvidia_driver_version(summary: &str) -> Option<&str> {
|
||||
summary
|
||||
.split_whitespace()
|
||||
.find(|token| token.chars().all(|c| c.is_ascii_digit() || c == '.'))
|
||||
}
|
||||
|
||||
pub fn configure_environment() {
|
||||
let session = SessionEnv::gather();
|
||||
let overrides = DmabufOverrides::gather();
|
||||
let intel_gpu = detect_intel_gpu();
|
||||
let nvidia_gpu = detect_nvidia_gpu();
|
||||
let decision = DmabufDecision::resolve(&session, &overrides, intel_gpu, &nvidia_gpu);
|
||||
|
||||
if overrides.should_override_env(&decision) {
|
||||
unsafe {
|
||||
if decision.enable_dmabuf {
|
||||
env::remove_var("WEBKIT_DISABLE_DMABUF_RENDERER");
|
||||
} else {
|
||||
env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(message) = decision.message {
|
||||
if decision.warn {
|
||||
logging!(warn, Type::Setup, "{}", message);
|
||||
} else {
|
||||
logging!(info, Type::Setup, "{}", message);
|
||||
}
|
||||
}
|
||||
|
||||
if decision.force_x11_backend {
|
||||
unsafe {
|
||||
env::set_var("GDK_BACKEND", "x11");
|
||||
env::remove_var("WAYLAND_DISPLAY");
|
||||
}
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"Wayland detected: Forcing X11 backend for WebKit stability."
|
||||
);
|
||||
}
|
||||
|
||||
if session.is_kde_plasma {
|
||||
unsafe {
|
||||
env::set_var("GTK_CSD", "0");
|
||||
}
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
"KDE/Plasma detected: Disabled GTK CSD for better titlebar stability."
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ pub mod format;
|
||||
pub mod help;
|
||||
pub mod i18n;
|
||||
pub mod init;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod linux;
|
||||
pub mod logging;
|
||||
pub mod network;
|
||||
pub mod notification;
|
||||
|
||||
Reference in New Issue
Block a user