From 49274fb1c6e1c2d0895a3312548df44d7d4713ae Mon Sep 17 00:00:00 2001 From: khyperia <953151+khyperia@users.noreply.github.com> Date: Tue, 17 Feb 2026 10:18:20 +0100 Subject: [PATCH] config: add XWayland enabled option --- jay-config/src/_private/client.rs | 4 ++++ jay-config/src/_private/ipc.rs | 3 +++ jay-config/src/xwayland.rs | 7 +++++++ src/compositor.rs | 1 + src/config/handler.rs | 8 ++++++++ src/state.rs | 19 +++++++++++++++++++ src/xwayland.rs | 8 +++++++- toml-config/src/config.rs | 1 + toml-config/src/config/parsers/xwayland.rs | 12 ++++++++---- toml-config/src/lib.rs | 13 ++++++++----- toml-spec/spec/spec.generated.json | 4 ++++ toml-spec/spec/spec.generated.md | 8 ++++++++ toml-spec/spec/spec.yaml | 7 +++++++ 13 files changed, 85 insertions(+), 10 deletions(-) diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index a9196cf8..e4cfbd0d 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -1182,6 +1182,10 @@ impl ConfigClient { self.send(&ClientMessage::SetXScalingMode { mode }) } + pub fn set_x_wayland_enabled(&self, enabled: bool) { + self.send(&ClientMessage::SetXWaylandEnabled { enabled }) + } + pub fn set_vrr_mode(&self, connector: Option, mode: VrrMode) { self.send(&ClientMessage::SetVrrMode { connector, mode }) } diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 91d53955..41a672d1 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -831,6 +831,9 @@ pub enum ClientMessage<'a> { seat: Seat, mode: FallbackOutputMode, }, + SetXWaylandEnabled { + enabled: bool, + }, } #[derive(Serialize, Deserialize, Debug)] diff --git a/jay-config/src/xwayland.rs b/jay-config/src/xwayland.rs index bcfbed99..36016697 100644 --- a/jay-config/src/xwayland.rs +++ b/jay-config/src/xwayland.rs @@ -2,6 +2,13 @@ use serde::{Deserialize, Serialize}; +/// Sets whether Xwayland is enabled +/// +/// The default is `true`. +pub fn set_x_wayland_enabled(enabled: bool) { + get!().set_x_wayland_enabled(enabled) +} + /// The scaling mode of X windows. #[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)] pub struct XScalingMode(pub u32); diff --git a/src/compositor.rs b/src/compositor.rs index d5805b32..eedb883f 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -269,6 +269,7 @@ fn start_compositor2( run_args, xwayland: XWaylandState { enabled: Cell::new(true), + running: Cell::new(false), pidfd: Default::default(), handler: Default::default(), queue: Default::default(), diff --git a/src/config/handler.rs b/src/config/handler.rs index a7290d80..76eb6e74 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -979,6 +979,11 @@ impl ConfigProxyHandler { Ok(()) } + fn handle_set_x_wayland_enabled(&self, enabled: bool) -> Result<(), CphError> { + self.state.set_xwayland_enabled(enabled); + Ok(()) + } + fn handle_set_ui_drag_enabled(&self, enabled: bool) { self.state.ui_drag_enabled.set(enabled); } @@ -3369,6 +3374,9 @@ impl ConfigProxyHandler { ClientMessage::SetFallbackOutputMode { seat, mode } => self .handle_set_fallback_output_mode(seat, mode) .wrn("set_fallback_output_mode")?, + ClientMessage::SetXWaylandEnabled { enabled } => self + .handle_set_x_wayland_enabled(enabled) + .wrn("set_x_wayland_enabled")?, } Ok(()) } diff --git a/src/state.rs b/src/state.rs index 3708e935..c9556c15 100644 --- a/src/state.rs +++ b/src/state.rs @@ -313,6 +313,7 @@ pub struct ScreenlockState { pub struct XWaylandState { pub enabled: Cell, + pub running: Cell, pub pidfd: CloneCell>>, pub handler: RefCell>>, pub queue: Rc>, @@ -968,6 +969,24 @@ impl State { } } + pub fn stop_xwayland(&self) { + if self.xwayland.running.get() { + return; + } + self.xwayland.handler.take(); + } + + pub fn set_xwayland_enabled(self: &Rc, enabled: bool) { + if self.xwayland.enabled.replace(enabled) == enabled { + return; + } + if enabled { + self.start_xwayland(); + } else { + self.stop_xwayland(); + } + } + pub fn next_serial(&self, client: Option<&Client>) -> u64 { let serial = self.serial.fetch_add(1); if let Some(client) = client { diff --git a/src/xwayland.rs b/src/xwayland.rs index acd935b4..f994b7b3 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -110,6 +110,7 @@ pub async fn manage(state: Rc) { } let display = format!(":{}", xsocket.id); forker.setenv(DISPLAY.as_bytes(), display.as_bytes()); + let _unsetenv = on_drop(|| forker.unsetenv(DISPLAY.as_bytes())); log::info!("Allocated display :{} for Xwayland", xsocket.id); log::info!("Waiting for connection attempt"); if state.backend.get().import_environment() { @@ -120,12 +121,17 @@ pub async fn manage(state: Rc) { return; } log::info!("Starting Xwayland"); + state.xwayland.running.set(true); if let Err(e) = run(&state, &forker, socket).await { log::error!("Xwayland failed: {}", ErrorFmt(e)); } else { log::warn!("Xwayland exited unexpectedly"); } - forker.unsetenv(DISPLAY.as_bytes()); + state.xwayland.running.set(false); + if !state.xwayland.enabled.get() { + state.stop_xwayland(); + return; + } } } diff --git a/toml-config/src/config.rs b/toml-config/src/config.rs index 9dc6daa0..4b1b29c6 100644 --- a/toml-config/src/config.rs +++ b/toml-config/src/config.rs @@ -463,6 +463,7 @@ pub struct SimpleIm { #[derive(Debug, Clone)] pub struct Xwayland { + pub enabled: Option, pub scaling_mode: Option, } diff --git a/toml-config/src/config/parsers/xwayland.rs b/toml-config/src/config/parsers/xwayland.rs index 6fc9b9f0..c6420334 100644 --- a/toml-config/src/config/parsers/xwayland.rs +++ b/toml-config/src/config/parsers/xwayland.rs @@ -3,11 +3,11 @@ use { config::{ Xwayland, context::Context, - extractor::{Extractor, ExtractorError, opt, val}, + extractor::{Extractor, ExtractorError, bol, opt, recover, val}, parser::{DataType, ParseResult, Parser, UnexpectedDataType}, }, toml::{ - toml_span::{Span, Spanned, SpannedExt}, + toml_span::{DespanExt, Span, Spanned, SpannedExt}, toml_value::Value, }, }, @@ -37,7 +37,8 @@ impl Parser for XwaylandParser<'_> { table: &IndexMap, Spanned>, ) -> ParseResult { let mut ext = Extractor::new(self.0, span, table); - let scaling_mode = ext.extract(opt(val("scaling-mode")))?; + let (enabled, scaling_mode) = + ext.extract((recover(opt(bol("enabled"))), opt(val("scaling-mode"))))?; let scaling_mode = scaling_mode.and_then(|m| match m.parse(&mut XScalingModeParser) { Ok(m) => Some(m), Err(e) => { @@ -45,7 +46,10 @@ impl Parser for XwaylandParser<'_> { None } }); - Ok(Xwayland { scaling_mode }) + Ok(Xwayland { + enabled: enabled.despan(), + scaling_mode, + }) } } diff --git a/toml-config/src/lib.rs b/toml-config/src/lib.rs index 77420126..d3e4f1f6 100644 --- a/toml-config/src/lib.rs +++ b/toml-config/src/lib.rs @@ -56,7 +56,7 @@ use { }, window::Window, workspace::set_workspace_display_order, - xwayland::set_x_scaling_mode, + xwayland::{set_x_scaling_mode, set_x_wayland_enabled}, }, run_on_drop::on_drop, std::{ @@ -1578,10 +1578,13 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc