From 64efed2f86a2bb758994912a2d053edbdd0677c7 Mon Sep 17 00:00:00 2001 From: KosmX Date: Fri, 30 May 2025 17:53:28 +0000 Subject: [PATCH 01/10] Expose libWayland wl_display_set_default_max_buffer_size function. This is necessary to increase on higher-end systems (high polling rate hardware/high refresh-rate) to avoid crashing some apps that cannot keep up with the event loop momentarily --- wayland-backend/src/rs/server_impl/common_poll.rs | 2 ++ wayland-backend/src/server_api.rs | 8 ++++++++ wayland-backend/src/sys/server_impl/mod.rs | 11 +++++++++++ wayland-sys/src/server.rs | 1 + 4 files changed, 22 insertions(+) diff --git a/wayland-backend/src/rs/server_impl/common_poll.rs b/wayland-backend/src/rs/server_impl/common_poll.rs index 83b279a9df7..bb353eddbda 100644 --- a/wayland-backend/src/rs/server_impl/common_poll.rs +++ b/wayland-backend/src/rs/server_impl/common_poll.rs @@ -326,6 +326,8 @@ impl InnerBackend { } Ok(dispatched) } + + pub fn set_max_buffer_size(&self, _: usize) {} } enum DispatchAction { diff --git a/wayland-backend/src/server_api.rs b/wayland-backend/src/server_api.rs index b7b60b65796..e526f6e8037 100644 --- a/wayland-backend/src/server_api.rs +++ b/wayland-backend/src/server_api.rs @@ -603,6 +603,14 @@ impl Backend { pub fn dispatch_all_clients(&mut self, data: &mut D) -> std::io::Result { self.backend.dispatch_all_clients(data) } + + /// Set wl_client max buffer size. + /// + /// This method will only affect connections created after the method call. + /// only for libwayland backend + pub fn set_max_buffer_size(&mut self, max_buffer_size: usize) { + self.backend.set_max_buffer_size(max_buffer_size); + } } // Workaround: Some versions of rustc throw a `struct is never constructed`-warning here, diff --git a/wayland-backend/src/sys/server_impl/mod.rs b/wayland-backend/src/sys/server_impl/mod.rs index b8240af5147..b4ed8d378f9 100644 --- a/wayland-backend/src/sys/server_impl/mod.rs +++ b/wayland-backend/src/sys/server_impl/mod.rs @@ -424,6 +424,17 @@ impl InnerBackend { Ok(ret as usize) } } + + pub fn set_max_buffer_size(&mut self, max_buffer_size: usize) { + unsafe { + ffi_dispatch!( + wayland_server_handle(), + wl_display_set_default_max_buffer_size, + self.display_ptr, + max_buffer_size + ); + } + } } impl Drop for State { diff --git a/wayland-sys/src/server.rs b/wayland-sys/src/server.rs index 03ded560e0c..64e9f32eb60 100644 --- a/wayland-sys/src/server.rs +++ b/wayland-sys/src/server.rs @@ -82,6 +82,7 @@ external_library!(WaylandServer, "wayland-server", fn wl_display_add_client_created_listener(*mut wl_display, *mut wl_listener) -> (), fn wl_display_set_global_filter(*mut wl_display, wl_display_global_filter_func_t, *mut c_void) -> (), fn wl_display_get_client_list(*mut wl_display) -> *mut wl_list, + fn wl_display_set_default_max_buffer_size(*mut wl_display, usize) -> (), // wl_event_loop fn wl_event_loop_create() -> *mut wl_event_loop, fn wl_event_loop_destroy(*mut wl_event_loop) -> (), From aa7e2687efb9bc29ecdc16155c978e03da942fc2 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 2 Mar 2026 19:09:26 -0800 Subject: [PATCH 02/10] backend: Use `set_default_max_buffer_size()` as method name Matches `libwayland`. The name may otherwise be confusing since it only applies to newly connected clients. --- wayland-backend/src/rs/server_impl/common_poll.rs | 2 +- wayland-backend/src/server_api.rs | 4 ++-- wayland-backend/src/sys/server_impl/mod.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wayland-backend/src/rs/server_impl/common_poll.rs b/wayland-backend/src/rs/server_impl/common_poll.rs index bb353eddbda..2785f0e3909 100644 --- a/wayland-backend/src/rs/server_impl/common_poll.rs +++ b/wayland-backend/src/rs/server_impl/common_poll.rs @@ -327,7 +327,7 @@ impl InnerBackend { Ok(dispatched) } - pub fn set_max_buffer_size(&self, _: usize) {} + pub fn set_default_max_buffer_size(&self, _: usize) {} } enum DispatchAction { diff --git a/wayland-backend/src/server_api.rs b/wayland-backend/src/server_api.rs index e526f6e8037..90636e77348 100644 --- a/wayland-backend/src/server_api.rs +++ b/wayland-backend/src/server_api.rs @@ -608,8 +608,8 @@ impl Backend { /// /// This method will only affect connections created after the method call. /// only for libwayland backend - pub fn set_max_buffer_size(&mut self, max_buffer_size: usize) { - self.backend.set_max_buffer_size(max_buffer_size); + pub fn set_default_max_buffer_size(&mut self, max_buffer_size: usize) { + self.backend.set_default_max_buffer_size(max_buffer_size); } } diff --git a/wayland-backend/src/sys/server_impl/mod.rs b/wayland-backend/src/sys/server_impl/mod.rs index b4ed8d378f9..1503300901e 100644 --- a/wayland-backend/src/sys/server_impl/mod.rs +++ b/wayland-backend/src/sys/server_impl/mod.rs @@ -425,7 +425,7 @@ impl InnerBackend { } } - pub fn set_max_buffer_size(&mut self, max_buffer_size: usize) { + pub fn set_default_max_buffer_size(&mut self, max_buffer_size: usize) { unsafe { ffi_dispatch!( wayland_server_handle(), From 88791e44683605f97a3a357038d367d6b5aac24e Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 10 Dec 2025 15:52:16 -0800 Subject: [PATCH 03/10] tests: Add test for `set_default_max_buffer_size()` This test fails without the call to this method. --- wayland-tests/tests/buffer_size.rs | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/wayland-tests/tests/buffer_size.rs b/wayland-tests/tests/buffer_size.rs index b2f2160c8a8..9c34afe17b9 100644 --- a/wayland-tests/tests/buffer_size.rs +++ b/wayland-tests/tests/buffer_size.rs @@ -101,6 +101,48 @@ fn buffer_size_client() { // roundtrip(&mut client, &mut server, &mut client_ddata, &mut server_handler).unwrap(); } +#[test] +fn buffer_size_increase() { + let mut server = TestServer::new(); + server + .display + .handle() + .create_global::(1, ()); + + server.display.backend().set_default_max_buffer_size(1024 * 32); + + let (_, mut client) = server.add_client(); + let mut client_ddata = ClientHandler { globals: globals::GlobalList::new() }; + + let registry = client.display.get_registry(&client.event_queue.handle(), ()); + + let mut server_handler = ServerHandler::default(); + + roundtrip(&mut client, &mut server, &mut client_ddata, &mut server_handler).unwrap(); + + let seat = client_ddata + .globals + .bind::( + &client.event_queue.handle(), + ®istry, + 1..2, + (), + ) + .unwrap(); + + let _pointer = seat.get_pointer(&client.event_queue.handle(), ()); + + roundtrip(&mut client, &mut server, &mut client_ddata, &mut server_handler).unwrap(); + + // Send too many Wayland events to buffer + let server_pointer = server_handler.pointer.as_ref().unwrap().clone(); + for _ in 0..10_000 { + server_pointer.motion(0, 0., 0.); + } + + roundtrip(&mut client, &mut server, &mut client_ddata, &mut server_handler).unwrap(); +} + /* * Client handler */ From 8f69e8e0d1dc8a58a9316c48bf9faa272b6fd1d3 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 26 Feb 2026 13:12:46 -0800 Subject: [PATCH 04/10] sys,backend: Put `set_default_max_buffer_size()` behind feature Allows wayland-rs to continue to work with `server_system` and an older libwayland version. --- wayland-backend/Cargo.toml | 1 + wayland-backend/src/rs/server_impl/common_poll.rs | 1 + wayland-backend/src/server_api.rs | 1 + wayland-backend/src/sys/server_impl/mod.rs | 1 + wayland-server/Cargo.toml | 1 + wayland-sys/Cargo.toml | 1 + wayland-sys/src/server.rs | 1 + wayland-tests/Cargo.toml | 1 + wayland-tests/tests/buffer_size.rs | 1 + 9 files changed, 9 insertions(+) diff --git a/wayland-backend/Cargo.toml b/wayland-backend/Cargo.toml index ae004b01fdb..bc792a229e7 100644 --- a/wayland-backend/Cargo.toml +++ b/wayland-backend/Cargo.toml @@ -54,6 +54,7 @@ client_system = ["wayland-sys/client", "dep:scoped-tls"] server_system = ["wayland-sys/server", "dep:scoped-tls"] dlopen = ["wayland-sys/dlopen"] libwayland_server_1_22 = ["wayland-sys/libwayland_server_1_22"] +libwayland_server_1_23 = ["wayland-sys/libwayland_server_1_23", "libwayland_server_1_22"] [package.metadata.docs.rs] all-features = true diff --git a/wayland-backend/src/rs/server_impl/common_poll.rs b/wayland-backend/src/rs/server_impl/common_poll.rs index 2785f0e3909..45fbd2bc1ce 100644 --- a/wayland-backend/src/rs/server_impl/common_poll.rs +++ b/wayland-backend/src/rs/server_impl/common_poll.rs @@ -327,6 +327,7 @@ impl InnerBackend { Ok(dispatched) } + #[allow(dead_code)] pub fn set_default_max_buffer_size(&self, _: usize) {} } diff --git a/wayland-backend/src/server_api.rs b/wayland-backend/src/server_api.rs index 90636e77348..7c7ab5bf012 100644 --- a/wayland-backend/src/server_api.rs +++ b/wayland-backend/src/server_api.rs @@ -608,6 +608,7 @@ impl Backend { /// /// This method will only affect connections created after the method call. /// only for libwayland backend + #[cfg(feature = "libwayland_server_1_23")] pub fn set_default_max_buffer_size(&mut self, max_buffer_size: usize) { self.backend.set_default_max_buffer_size(max_buffer_size); } diff --git a/wayland-backend/src/sys/server_impl/mod.rs b/wayland-backend/src/sys/server_impl/mod.rs index 1503300901e..56e1d15820e 100644 --- a/wayland-backend/src/sys/server_impl/mod.rs +++ b/wayland-backend/src/sys/server_impl/mod.rs @@ -425,6 +425,7 @@ impl InnerBackend { } } + #[cfg(feature = "libwayland_server_1_23")] pub fn set_default_max_buffer_size(&mut self, max_buffer_size: usize) { unsafe { ffi_dispatch!( diff --git a/wayland-server/Cargo.toml b/wayland-server/Cargo.toml index cc2e0e4c1b7..b31b09c517f 100644 --- a/wayland-server/Cargo.toml +++ b/wayland-server/Cargo.toml @@ -24,6 +24,7 @@ rustix = { version = "1.0.2", features = ["fs"] } system = ["wayland-backend/server_system"] dlopen = ["wayland-backend/dlopen"] libwayland_1_22 = ["wayland-backend/libwayland_server_1_22"] +libwayland_1_23 = ["libwayland_1_22", "wayland-backend/libwayland_server_1_23"] [package.metadata.docs.rs] all-features = true diff --git a/wayland-sys/Cargo.toml b/wayland-sys/Cargo.toml index 88933066216..d5bef773c31 100644 --- a/wayland-sys/Cargo.toml +++ b/wayland-sys/Cargo.toml @@ -28,6 +28,7 @@ cursor = ["client"] egl = ["client"] server = ["libc", "memoffset", "dep:dlib", "dep:log"] libwayland_server_1_22 = [] +libwayland_server_1_23 = ["libwayland_server_1_22"] [package.metadata.docs.rs] all-features = true diff --git a/wayland-sys/src/server.rs b/wayland-sys/src/server.rs index 64e9f32eb60..5b707777e87 100644 --- a/wayland-sys/src/server.rs +++ b/wayland-sys/src/server.rs @@ -82,6 +82,7 @@ external_library!(WaylandServer, "wayland-server", fn wl_display_add_client_created_listener(*mut wl_display, *mut wl_listener) -> (), fn wl_display_set_global_filter(*mut wl_display, wl_display_global_filter_func_t, *mut c_void) -> (), fn wl_display_get_client_list(*mut wl_display) -> *mut wl_list, + #[cfg(feature = "libwayland_server_1_23")] fn wl_display_set_default_max_buffer_size(*mut wl_display, usize) -> (), // wl_event_loop fn wl_event_loop_create() -> *mut wl_event_loop, diff --git a/wayland-tests/Cargo.toml b/wayland-tests/Cargo.toml index bcd07e8a97a..9a36325e5ae 100644 --- a/wayland-tests/Cargo.toml +++ b/wayland-tests/Cargo.toml @@ -19,6 +19,7 @@ server_system = ["wayland-server/system"] client_system = ["wayland-client/system"] libwayland_client_1_23 = [] libwayland_server_1_22 = ["wayland-server/libwayland_1_22"] +libwayland_server_1_23 = ["libwayland_server_1_22", "wayland-server/libwayland_1_23"] [[test]] name = "attach_to_surface" diff --git a/wayland-tests/tests/buffer_size.rs b/wayland-tests/tests/buffer_size.rs index 9c34afe17b9..304aed02347 100644 --- a/wayland-tests/tests/buffer_size.rs +++ b/wayland-tests/tests/buffer_size.rs @@ -101,6 +101,7 @@ fn buffer_size_client() { // roundtrip(&mut client, &mut server, &mut client_ddata, &mut server_handler).unwrap(); } +#[cfg(feature = "libwayland_server_1_23")] #[test] fn buffer_size_increase() { let mut server = TestServer::new(); From 1af69a3b76d3578691319ea3ca971800523f1c10 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 2 Mar 2026 19:29:38 -0800 Subject: [PATCH 05/10] ci: Test with `libwayland_client_1_23` feature --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 889e6fad1fc..e71ae1080db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -224,7 +224,7 @@ jobs: env: PKG_CONFIG_PATH: "${{ github.workspace }}/wayland-install/lib/x86_64-linux-gnu/pkgconfig" LD_LIBRARY_PATH: "${{ github.workspace }}/wayland-install/lib/x86_64-linux-gnu" - run: cargo test -p wayland-tests --features client_system,libwayland_client_1_23 + run: cargo test -p wayland-tests --features client_system,libwayland_client_1_23,libwayland_server_1_23 check-redox: needs: @@ -338,7 +338,7 @@ jobs: fail-fast: false matrix: client_feature: ["libwayland_client_1_23", "client_system"] - server_feature: ["libwayland_server_1_22", "server_system", "server_system,libwayland_server_1_22"] + server_feature: ["libwayland_server_1_23", "server_system", "server_system,libwayland_server_1_22"] steps: - name: Checkout sources From feaf15a7570a29a71cfdf3490ec59d1feae734dc Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 3 Mar 2026 18:50:36 -0800 Subject: [PATCH 06/10] backend: Use `MAX_BYTES_OUT` for `in_data`, not `2 * MAX_BYTES_OUT` This should match `libwayland`, and there should be no need to have a larger buffer here. Once the buffer is full, it will have at least one complete message. --- wayland-backend/src/rs/socket.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wayland-backend/src/rs/socket.rs b/wayland-backend/src/rs/socket.rs index 3b19a312bae..9e06d295266 100644 --- a/wayland-backend/src/rs/socket.rs +++ b/wayland-backend/src/rs/socket.rs @@ -142,8 +142,8 @@ impl BufferedSocket { pub fn new(socket: Socket, unbounded: bool) -> Self { Self { socket, - in_data: Buffer::new(2 * MAX_BYTES_OUT), // Incoming buffers are twice as big in order to be - in_fds: VecDeque::new(), // able to store leftover data if needed + in_data: Buffer::new(MAX_BYTES_OUT), + in_fds: VecDeque::new(), out_data: Buffer::new(MAX_BYTES_OUT), out_fds: Vec::new(), unbounded, From f383e15490ed6614d911ce37b420318e698dedba Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 11 Dec 2025 14:27:01 -0800 Subject: [PATCH 07/10] backend(rs): Support default max buffer size --- wayland-backend/src/rs/client_impl/mod.rs | 2 +- wayland-backend/src/rs/mod.rs | 3 ++ wayland-backend/src/rs/server_impl/client.rs | 6 ++-- .../src/rs/server_impl/common_poll.rs | 8 +++-- wayland-backend/src/rs/server_impl/handle.rs | 5 +++- wayland-backend/src/rs/socket.rs | 29 ++++++++++--------- wayland-backend/src/test/protocol_error.rs | 13 +++++---- 7 files changed, 41 insertions(+), 25 deletions(-) diff --git a/wayland-backend/src/rs/client_impl/mod.rs b/wayland-backend/src/rs/client_impl/mod.rs index 0bed8ebbf9d..129652f6bae 100644 --- a/wayland-backend/src/rs/client_impl/mod.rs +++ b/wayland-backend/src/rs/client_impl/mod.rs @@ -150,7 +150,7 @@ impl InnerBackend { } pub fn connect(stream: UnixStream) -> Result { - let socket = BufferedSocket::new(Socket::from(stream), true); + let socket = BufferedSocket::new(Socket::from(stream), None); let mut map = ObjectMap::new(); map.insert_at( 1, diff --git a/wayland-backend/src/rs/mod.rs b/wayland-backend/src/rs/mod.rs index da6d0b68953..77ca03035df 100644 --- a/wayland-backend/src/rs/mod.rs +++ b/wayland-backend/src/rs/mod.rs @@ -7,6 +7,9 @@ mod map; pub(crate) mod socket; mod wire; +// Matches `WL_BUFFER_DEFAULT_MAX_SIZE` in `libwayland` +pub(crate) const DEFAULT_MAX_BUFFER_SIZE: usize = 4096; + /// Client-side rust implementation of a Wayland protocol backend /// /// The main entrypoint is the [`Backend::connect()`][client::Backend::connect()] method. diff --git a/wayland-backend/src/rs/server_impl/client.rs b/wayland-backend/src/rs/server_impl/client.rs index 9f6b232bb29..16061e9aa6a 100644 --- a/wayland-backend/src/rs/server_impl/client.rs +++ b/wayland-backend/src/rs/server_impl/client.rs @@ -68,8 +68,9 @@ impl Client { id: InnerClientId, debug: bool, data: Arc, + buffer_size: usize, ) -> Self { - let socket = BufferedSocket::new(Socket::from(stream), false); + let socket = BufferedSocket::new(Socket::from(stream), Some(buffer_size)); let mut map = ObjectMap::new(); map.insert_at( 1, @@ -709,6 +710,7 @@ impl ClientStore { &mut self, stream: UnixStream, data: Arc, + buffer_size: usize, ) -> InnerClientId { let serial = self.next_serial(); // Find the next free place @@ -722,7 +724,7 @@ impl ClientStore { let id = InnerClientId { id: id as u32, serial }; - *place = Some(Client::new(stream, id.clone(), self.debug, data)); + *place = Some(Client::new(stream, id.clone(), self.debug, data, buffer_size)); id } diff --git a/wayland-backend/src/rs/server_impl/common_poll.rs b/wayland-backend/src/rs/server_impl/common_poll.rs index 45fbd2bc1ce..c234b67f053 100644 --- a/wayland-backend/src/rs/server_impl/common_poll.rs +++ b/wayland-backend/src/rs/server_impl/common_poll.rs @@ -10,7 +10,7 @@ use super::{ use crate::{ core_interfaces::{WL_DISPLAY_INTERFACE, WL_REGISTRY_INTERFACE}, protocol::{same_interface, Argument, Message}, - rs::map::Object, + rs::{map::Object, DEFAULT_MAX_BUFFER_SIZE}, types::server::InitError, }; @@ -328,7 +328,11 @@ impl InnerBackend { } #[allow(dead_code)] - pub fn set_default_max_buffer_size(&self, _: usize) {} + pub fn set_default_max_buffer_size(&self, size: usize) { + let size = + size.checked_next_power_of_two().unwrap_or(usize::MAX).max(DEFAULT_MAX_BUFFER_SIZE); + self.state.lock().unwrap().default_max_buffer_size = size; + } } enum DispatchAction { diff --git a/wayland-backend/src/rs/server_impl/handle.rs b/wayland-backend/src/rs/server_impl/handle.rs index 73c05ed68a7..2aafcefa1a5 100644 --- a/wayland-backend/src/rs/server_impl/handle.rs +++ b/wayland-backend/src/rs/server_impl/handle.rs @@ -9,6 +9,7 @@ use std::{ use crate::{ protocol::{same_interface, Interface, Message, ObjectInfo, ANONYMOUS_INTERFACE}, + rs::DEFAULT_MAX_BUFFER_SIZE, types::server::{DisconnectReason, GlobalInfo, InvalidId}, }; @@ -25,6 +26,7 @@ pub struct State { pub(crate) registry: Registry, pub(crate) pending_destructors: Vec>, pub(crate) poll_fd: OwnedFd, + pub(crate) default_max_buffer_size: usize, } impl State { @@ -36,6 +38,7 @@ impl State { registry: Registry::new(), pending_destructors: Vec::new(), poll_fd, + default_max_buffer_size: DEFAULT_MAX_BUFFER_SIZE, } } @@ -329,7 +332,7 @@ impl ErasedState for State { stream: UnixStream, data: Arc, ) -> std::io::Result { - let id = self.clients.create_client(stream, data); + let id = self.clients.create_client(stream, data, self.default_max_buffer_size); let client = self.clients.get_client(id.clone()).unwrap(); // register the client to the internal epoll diff --git a/wayland-backend/src/rs/socket.rs b/wayland-backend/src/rs/socket.rs index 9e06d295266..cfc6efc4a67 100644 --- a/wayland-backend/src/rs/socket.rs +++ b/wayland-backend/src/rs/socket.rs @@ -14,6 +14,7 @@ use rustix::net::{ }; use crate::protocol::{ArgumentType, Message}; +use crate::rs::DEFAULT_MAX_BUFFER_SIZE; use super::wire::{parse_message, write_to_buffers, MessageParseError, MessageWriteError}; @@ -134,19 +135,19 @@ pub struct BufferedSocket { in_fds: VecDeque, out_data: Buffer, out_fds: Vec, - unbounded: bool, + max_buffer_size: Option, } impl BufferedSocket { /// Wrap a Socket into a Buffered Socket - pub fn new(socket: Socket, unbounded: bool) -> Self { + pub fn new(socket: Socket, max_buffer_size: Option) -> Self { Self { socket, - in_data: Buffer::new(MAX_BYTES_OUT), + in_data: Buffer::new(DEFAULT_MAX_BUFFER_SIZE), in_fds: VecDeque::new(), - out_data: Buffer::new(MAX_BYTES_OUT), + out_data: Buffer::new(DEFAULT_MAX_BUFFER_SIZE), out_fds: Vec::new(), - unbounded, + max_buffer_size, } } @@ -217,7 +218,7 @@ impl BufferedSocket { } Err(MessageWriteError::BufferTooSmall) => { self.out_fds.truncate(fds_len); - if !self.unbounded { + if self.max_buffer_size.is_some_and(|s| s <= self.out_data.storage.len()) { return Ok(false); } self.out_data.increase_capacity(); @@ -437,8 +438,8 @@ mod tests { }; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); - let mut client = BufferedSocket::new(Socket::from(client), false); - let mut server = BufferedSocket::new(Socket::from(server), false); + let mut client = BufferedSocket::new(Socket::from(client), Some(DEFAULT_MAX_BUFFER_SIZE)); + let mut server = BufferedSocket::new(Socket::from(server), Some(DEFAULT_MAX_BUFFER_SIZE)); client.write_message(&msg).unwrap(); client.flush().unwrap(); @@ -481,8 +482,8 @@ mod tests { }; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); - let mut client = BufferedSocket::new(Socket::from(client), false); - let mut server = BufferedSocket::new(Socket::from(server), false); + let mut client = BufferedSocket::new(Socket::from(client), Some(DEFAULT_MAX_BUFFER_SIZE)); + let mut server = BufferedSocket::new(Socket::from(server), Some(DEFAULT_MAX_BUFFER_SIZE)); client.write_message(&msg).unwrap(); client.flush().unwrap(); @@ -540,8 +541,8 @@ mod tests { ]; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); - let mut client = BufferedSocket::new(Socket::from(client), false); - let mut server = BufferedSocket::new(Socket::from(server), false); + let mut client = BufferedSocket::new(Socket::from(client), Some(DEFAULT_MAX_BUFFER_SIZE)); + let mut server = BufferedSocket::new(Socket::from(server), Some(DEFAULT_MAX_BUFFER_SIZE)); for msg in &messages { client.write_message(msg).unwrap(); @@ -579,8 +580,8 @@ mod tests { }; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); - let mut client = BufferedSocket::new(Socket::from(client), false); - let mut server = BufferedSocket::new(Socket::from(server), false); + let mut client = BufferedSocket::new(Socket::from(client), Some(DEFAULT_MAX_BUFFER_SIZE)); + let mut server = BufferedSocket::new(Socket::from(server), Some(DEFAULT_MAX_BUFFER_SIZE)); client.write_message(&msg).unwrap(); client.flush().unwrap(); diff --git a/wayland-backend/src/test/protocol_error.rs b/wayland-backend/src/test/protocol_error.rs index af0a5859753..992e975248a 100644 --- a/wayland-backend/src/test/protocol_error.rs +++ b/wayland-backend/src/test/protocol_error.rs @@ -3,7 +3,10 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::rs::socket::{BufferedSocket, Socket}; +use crate::rs::{ + socket::{BufferedSocket, Socket}, + DEFAULT_MAX_BUFFER_SIZE, +}; use super::*; @@ -114,7 +117,7 @@ expand_test!(client_wrong_id, { let mut server = server_backend::Backend::<()>::new().unwrap(); let _client_id = server.handle().insert_client(rx, Arc::new(())).unwrap(); - let mut socket = BufferedSocket::new(Socket::from(tx), false); + let mut socket = BufferedSocket::new(Socket::from(tx), Some(DEFAULT_MAX_BUFFER_SIZE)); socket .write_message(&Message { @@ -140,7 +143,7 @@ expand_test!(client_wrong_opcode, { let mut server = server_backend::Backend::<()>::new().unwrap(); let _client_id = server.handle().insert_client(rx, Arc::new(())).unwrap(); - let mut socket = BufferedSocket::new(Socket::from(tx), false); + let mut socket = BufferedSocket::new(Socket::from(tx), Some(DEFAULT_MAX_BUFFER_SIZE)); socket .write_message(&Message { @@ -164,7 +167,7 @@ expand_test!(client_wrong_sender, { let mut server = server_backend::Backend::<()>::new().unwrap(); let _client_id = server.handle().insert_client(rx, Arc::new(())).unwrap(); - let mut socket = BufferedSocket::new(Socket::from(tx), false); + let mut socket = BufferedSocket::new(Socket::from(tx), Some(DEFAULT_MAX_BUFFER_SIZE)); socket .write_message(&Message { @@ -332,7 +335,7 @@ expand_test!(protocol_version_check, { Arc::new(ServerData(object_id.clone())), ); - let mut socket = BufferedSocket::new(Socket::from(tx), false); + let mut socket = BufferedSocket::new(Socket::from(tx), Some(DEFAULT_MAX_BUFFER_SIZE)); socket .write_message(&Message { From 44bb78f390097db614a42e0b8595ee69f002258a Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 15 Dec 2025 14:13:12 -0800 Subject: [PATCH 08/10] sys: Add bindings for `*_set_max_buffer_size()` --- wayland-sys/Cargo.toml | 1 + wayland-sys/src/client.rs | 2 ++ wayland-sys/src/server.rs | 2 ++ 3 files changed, 5 insertions(+) diff --git a/wayland-sys/Cargo.toml b/wayland-sys/Cargo.toml index d5bef773c31..52c859e0600 100644 --- a/wayland-sys/Cargo.toml +++ b/wayland-sys/Cargo.toml @@ -27,6 +27,7 @@ client = ["dep:dlib", "dep:log"] cursor = ["client"] egl = ["client"] server = ["libc", "memoffset", "dep:dlib", "dep:log"] +libwayland_client_1_23 = [] libwayland_server_1_22 = [] libwayland_server_1_23 = ["libwayland_server_1_22"] diff --git a/wayland-sys/src/client.rs b/wayland-sys/src/client.rs index f2796399875..c14bdf3054f 100644 --- a/wayland-sys/src/client.rs +++ b/wayland-sys/src/client.rs @@ -30,6 +30,8 @@ external_library!(WaylandClient, "wayland-client", fn wl_display_cancel_read(*mut wl_display) -> (), fn wl_display_dispatch(*mut wl_display) -> c_int, fn wl_display_dispatch_pending(*mut wl_display) -> c_int, + #[cfg(feature = "libwayland_client_1_23")] + fn wl_display_set_max_buffer_size(*mut wl_display, usize) -> (), // error handling fn wl_display_get_error(*mut wl_display) -> c_int, fn wl_display_get_protocol_error(*mut wl_display, *mut *const wl_interface, *mut u32) -> u32, diff --git a/wayland-sys/src/server.rs b/wayland-sys/src/server.rs index 5b707777e87..16f7f04518a 100644 --- a/wayland-sys/src/server.rs +++ b/wayland-sys/src/server.rs @@ -56,6 +56,8 @@ external_library!(WaylandServer, "wayland-server", fn wl_client_add_destroy_listener(*mut wl_client, *mut wl_listener) -> (), fn wl_client_get_destroy_listener(*mut wl_client, wl_notify_func_t) -> *mut wl_listener, fn wl_client_post_no_memory(*mut wl_client) -> (), + #[cfg(feature = "libwayland_server_1_23")] + fn wl_client_set_max_buffer_size(*mut wl_client, usize) -> (), fn wl_resource_create(*mut wl_client, *const wl_interface, c_int, u32) -> *mut wl_resource, fn wl_client_get_link(*mut wl_client) -> *mut wl_list, fn wl_client_from_link(*mut wl_list) -> *mut wl_client, From d968d06f6393f94a5d4ece691116e274d34851f7 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 4 Mar 2026 12:31:00 -0800 Subject: [PATCH 09/10] backend: Add `set_max_buffer_size()` for server and client API This is in addition to the `set_default_max_buffer_size()` previously added to the server API. --- wayland-backend/Cargo.toml | 1 + wayland-backend/src/client_api.rs | 6 ++++++ wayland-backend/src/rs/client_impl/mod.rs | 6 ++++++ wayland-backend/src/rs/server_impl/client.rs | 2 +- wayland-backend/src/rs/server_impl/handle.rs | 16 +++++++++++++++ wayland-backend/src/rs/socket.rs | 5 +++++ wayland-backend/src/server_api.rs | 9 +++++++-- wayland-backend/src/sys/client_impl/mod.rs | 13 ++++++++++++ wayland-backend/src/sys/server_impl/mod.rs | 21 ++++++++++++++++++++ wayland-client/Cargo.toml | 1 + wayland-tests/Cargo.toml | 2 +- 11 files changed, 78 insertions(+), 4 deletions(-) diff --git a/wayland-backend/Cargo.toml b/wayland-backend/Cargo.toml index bc792a229e7..d1a4c74b3c1 100644 --- a/wayland-backend/Cargo.toml +++ b/wayland-backend/Cargo.toml @@ -53,6 +53,7 @@ scoped-tls = "1.0" client_system = ["wayland-sys/client", "dep:scoped-tls"] server_system = ["wayland-sys/server", "dep:scoped-tls"] dlopen = ["wayland-sys/dlopen"] +libwayland_client_1_23 = ["wayland-sys/libwayland_client_1_23"] libwayland_server_1_22 = ["wayland-sys/libwayland_server_1_22"] libwayland_server_1_23 = ["wayland-sys/libwayland_server_1_23", "libwayland_server_1_22"] diff --git a/wayland-backend/src/client_api.rs b/wayland-backend/src/client_api.rs index 5c817595e04..52167d413da 100644 --- a/wayland-backend/src/client_api.rs +++ b/wayland-backend/src/client_api.rs @@ -297,6 +297,12 @@ impl Backend { pub fn dispatch_inner_queue(&self) -> Result { self.backend.dispatch_inner_queue() } + + /// Set maximum buffer size for connection + #[cfg(feature = "libwayland_client_1_23")] + pub fn set_max_buffer_size(&self, max_buffer_size: Option) { + self.backend.set_max_buffer_size(max_buffer_size); + } } /// Guard for synchronizing event reading across multiple threads diff --git a/wayland-backend/src/rs/client_impl/mod.rs b/wayland-backend/src/rs/client_impl/mod.rs index 129652f6bae..90f3f964662 100644 --- a/wayland-backend/src/rs/client_impl/mod.rs +++ b/wayland-backend/src/rs/client_impl/mod.rs @@ -527,6 +527,12 @@ impl InnerBackend { pub fn dispatch_inner_queue(&self) -> Result { Ok(0) } + + #[allow(dead_code)] + pub fn set_max_buffer_size(&self, max_buffer_size: Option) { + let mut guard = self.state.lock_protocol(); + guard.socket.set_max_buffer_size(max_buffer_size); + } } impl ProtocolState { diff --git a/wayland-backend/src/rs/server_impl/client.rs b/wayland-backend/src/rs/server_impl/client.rs index 16061e9aa6a..d3ec7b00321 100644 --- a/wayland-backend/src/rs/server_impl/client.rs +++ b/wayland-backend/src/rs/server_impl/client.rs @@ -46,7 +46,7 @@ pub(crate) enum DisplayError { #[derive(Debug)] pub(crate) struct Client { - socket: BufferedSocket, + pub(crate) socket: BufferedSocket, pub(crate) map: ObjectMap>, debug: bool, last_serial: u32, diff --git a/wayland-backend/src/rs/server_impl/handle.rs b/wayland-backend/src/rs/server_impl/handle.rs index 2aafcefa1a5..6b0566c8a02 100644 --- a/wayland-backend/src/rs/server_impl/handle.rs +++ b/wayland-backend/src/rs/server_impl/handle.rs @@ -73,6 +73,12 @@ impl State { Ok(()) } } + + fn set_max_buffer_size(&mut self, client: InnerClientId, max_buffer_size: usize) { + if let Ok(client) = self.clients.get_client_mut(client) { + client.socket.set_max_buffer_size(Some(max_buffer_size)); + } + } } #[derive(Clone)] @@ -284,6 +290,11 @@ impl InnerHandle { pub fn flush(&mut self, client: Option) -> std::io::Result<()> { self.state.lock().unwrap().flush(client) } + + #[allow(dead_code)] + pub fn set_max_buffer_size(&mut self, client: InnerClientId, max_buffer_size: usize) { + self.state.lock().unwrap().set_max_buffer_size(client, max_buffer_size) + } } pub(crate) trait ErasedState: downcast_rs::Downcast { @@ -318,6 +329,7 @@ pub(crate) trait ErasedState: downcast_rs::Downcast { fn global_info(&self, id: InnerGlobalId) -> Result; fn global_name(&self, global: InnerGlobalId, client: InnerClientId) -> Option; fn flush(&mut self, client: Option) -> std::io::Result<()>; + fn set_max_buffer_size(&mut self, client: InnerClientId, max_buffer_size: usize); } downcast_rs::impl_downcast!(ErasedState); @@ -477,4 +489,8 @@ impl ErasedState for State { fn flush(&mut self, client: Option) -> std::io::Result<()> { self.flush(client) } + + fn set_max_buffer_size(&mut self, client: InnerClientId, max_buffer_size: usize) { + self.set_max_buffer_size(client, max_buffer_size) + } } diff --git a/wayland-backend/src/rs/socket.rs b/wayland-backend/src/rs/socket.rs index cfc6efc4a67..65d84ee780e 100644 --- a/wayland-backend/src/rs/socket.rs +++ b/wayland-backend/src/rs/socket.rs @@ -308,6 +308,11 @@ impl BufferedSocket { Ok(msg) } + + pub fn set_max_buffer_size(&mut self, max_buffer_size: Option) { + // TODO: what if it decreases? + self.max_buffer_size = max_buffer_size; + } } impl AsRawFd for BufferedSocket { diff --git a/wayland-backend/src/server_api.rs b/wayland-backend/src/server_api.rs index 7c7ab5bf012..97734dc9192 100644 --- a/wayland-backend/src/server_api.rs +++ b/wayland-backend/src/server_api.rs @@ -521,6 +521,12 @@ impl Handle { pub fn flush(&mut self, client: Option) -> std::io::Result<()> { self.handle.flush(client) } + + /// Set maximum buffer size for client. + #[cfg(feature = "libwayland_server_1_23")] + pub fn set_max_buffer_size(&mut self, client: ClientId, max_buffer_size: usize) { + self.handle.set_max_buffer_size(client.id, max_buffer_size); + } } /// A backend object that represents the state of a wayland server. @@ -604,10 +610,9 @@ impl Backend { self.backend.dispatch_all_clients(data) } - /// Set wl_client max buffer size. + /// Set default client max buffer size. /// /// This method will only affect connections created after the method call. - /// only for libwayland backend #[cfg(feature = "libwayland_server_1_23")] pub fn set_default_max_buffer_size(&mut self, max_buffer_size: usize) { self.backend.set_default_max_buffer_size(max_buffer_size); diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index afeb77b052a..72f70b8cd77 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -319,6 +319,19 @@ impl InnerBackend { pub fn dispatch_inner_queue(&self) -> Result { self.inner.dispatch_lock.lock().unwrap().dispatch_pending(self.inner.clone()) } + + #[cfg(feature = "libwayland_client_1_23")] + pub fn set_max_buffer_size(&self, max_buffer_size: Option) { + let guard = self.lock_state(); + unsafe { + ffi_dispatch!( + wayland_client_handle(), + wl_display_set_max_buffer_size, + guard.display, + max_buffer_size.unwrap_or(0) + ) + } + } } impl ConnectionState { diff --git a/wayland-backend/src/sys/server_impl/mod.rs b/wayland-backend/src/sys/server_impl/mod.rs index 56e1d15820e..0187164ac68 100644 --- a/wayland-backend/src/sys/server_impl/mod.rs +++ b/wayland-backend/src/sys/server_impl/mod.rs @@ -853,6 +853,11 @@ impl InnerHandle { self.state.lock().unwrap().flush(client) } + #[cfg(feature = "libwayland_server_1_23")] + pub fn set_max_buffer_size(&mut self, client: InnerClientId, max_buffer_size: usize) { + self.state.lock().unwrap().set_max_buffer_size(client, max_buffer_size) + } + pub fn display_ptr(&self) -> *mut wl_display { self.state.lock().unwrap().display_ptr() } @@ -892,6 +897,8 @@ pub(crate) trait ErasedState: downcast_rs::Downcast { fn global_name(&self, global: InnerGlobalId, client: InnerClientId) -> Option; fn is_known_global(&self, global_ptr: *const wl_global) -> bool; fn flush(&mut self, client: Option) -> std::io::Result<()>; + #[cfg(feature = "libwayland_server_1_23")] + fn set_max_buffer_size(&mut self, client: InnerClientId, max_buffer_size: usize); fn display_ptr(&self) -> *mut wl_display; } @@ -1317,6 +1324,20 @@ impl ErasedState for State { Ok(()) } + #[cfg(feature = "libwayland_server_1_23")] + fn set_max_buffer_size(&mut self, client: InnerClientId, max_buffer_size: usize) { + if client.alive.load(Ordering::Acquire) { + unsafe { + ffi_dispatch!( + wayland_server_handle(), + wl_client_set_max_buffer_size, + client.ptr, + max_buffer_size + ) + } + } + } + fn display_ptr(&self) -> *mut wl_display { self.display } diff --git a/wayland-client/Cargo.toml b/wayland-client/Cargo.toml index 8811e3a865b..3086acc4008 100644 --- a/wayland-client/Cargo.toml +++ b/wayland-client/Cargo.toml @@ -28,6 +28,7 @@ tempfile = "3.2" [features] system = ["wayland-backend/client_system"] dlopen = ["wayland-backend/dlopen"] +libwayland_1_23 = ["wayland-backend/libwayland_client_1_23"] [package.metadata.docs.rs] all-features = true diff --git a/wayland-tests/Cargo.toml b/wayland-tests/Cargo.toml index 9a36325e5ae..c7a92901c2d 100644 --- a/wayland-tests/Cargo.toml +++ b/wayland-tests/Cargo.toml @@ -17,7 +17,7 @@ tempfile = "3" [features] server_system = ["wayland-server/system"] client_system = ["wayland-client/system"] -libwayland_client_1_23 = [] +libwayland_client_1_23 = ["wayland-client/libwayland_1_23"] libwayland_server_1_22 = ["wayland-server/libwayland_1_22"] libwayland_server_1_23 = ["libwayland_server_1_22", "wayland-server/libwayland_1_23"] From 56785f843b122e6419cd30fc73af4cba1975f90c Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 4 Mar 2026 16:17:01 -0800 Subject: [PATCH 10/10] backend: Add changelog entries for buffer size APIs --- wayland-backend/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wayland-backend/CHANGELOG.md b/wayland-backend/CHANGELOG.md index fcafe37a9b4..6de0ebbff5e 100644 --- a/wayland-backend/CHANGELOG.md +++ b/wayland-backend/CHANGELOG.md @@ -6,6 +6,8 @@ - client: Added `display_ptr` method to `ObjectId` - server: Addded `Handle::global_name` * Requires `libwayland_server_1_22` feature +- client: Added `set_max_buffer_size` method +- server: Added `set_default_max_buffer_size` and `set_max_buffer_size` methods ## 0.3.12 -- 2025-12-30