From 36c87d463879f3b772eb7d9f59aa8b9526ac4817 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 19 Mar 2026 23:19:40 -0300 Subject: [PATCH] Use intrinsic (buffer) size when geometry is not set The simplest clients like vkcube do not set geometry, and were left without decorations --- src/client_buffer.rs | 108 +++++++++++++++++++++++++++++++++++++++++++ src/deco.rs | 22 ++++++++- src/main.rs | 13 +++++- src/xdg.rs | 57 ++++++++++++++++++++++- 4 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 src/client_buffer.rs diff --git a/src/client_buffer.rs b/src/client_buffer.rs new file mode 100644 index 0000000..9374c7d --- /dev/null +++ b/src/client_buffer.rs @@ -0,0 +1,108 @@ +use std::{os::unix::prelude::OwnedFd, rc::Rc}; + +use wl_proxy::protocols::{ + linux_dmabuf_v1::{ + zwp_linux_buffer_params_v1::{ + ZwpLinuxBufferParamsV1, ZwpLinuxBufferParamsV1Flags, ZwpLinuxBufferParamsV1Handler, + }, + zwp_linux_dmabuf_v1::{ZwpLinuxDmabufV1, ZwpLinuxDmabufV1Handler}, + }, + wayland::{ + wl_buffer::{WlBuffer, WlBufferHandler}, + wl_shm::{WlShm, WlShmFormat, WlShmHandler}, + wl_shm_pool::{WlShmPool, WlShmPoolHandler}, + }, +}; + +pub struct ClientWlBuffer { + pub width: i32, + pub height: i32, +} + +impl WlBufferHandler for ClientWlBuffer {} + +pub struct ClientWlShm; + +impl WlShmHandler for ClientWlShm { + fn handle_create_pool( + &mut self, + slf: &Rc, + id: &Rc, + fd: &Rc, + size: i32, + ) { + id.set_handler(ClientWlShmPool {}); + slf.send_create_pool(id, fd, size); + } +} + +pub struct ClientWlShmPool {} + +impl WlShmPoolHandler for ClientWlShmPool { + fn handle_create_buffer( + &mut self, + slf: &Rc, + id: &Rc, + offset: i32, + width: i32, + height: i32, + stride: i32, + format: WlShmFormat, + ) { + id.set_handler(ClientWlBuffer { width, height }); + slf.send_create_buffer(id, offset, width, height, stride, format); + } +} + +pub struct ClientZwpLinuxDmabufV1; + +impl ZwpLinuxDmabufV1Handler for ClientZwpLinuxDmabufV1 { + fn handle_create_params( + &mut self, + slf: &Rc, + params_id: &Rc, + ) { + params_id.set_handler(ClientZwpLinuxBufferParamsV1 { size: None }); + slf.send_create_params(params_id); + } +} + +pub struct ClientZwpLinuxBufferParamsV1 { + size: Option<(i32, i32)>, +} + +impl ZwpLinuxBufferParamsV1Handler for ClientZwpLinuxBufferParamsV1 { + fn handle_create( + &mut self, + slf: &Rc, + width: i32, + height: i32, + format: u32, + flags: ZwpLinuxBufferParamsV1Flags, + ) { + self.size = Some((width, height)); + slf.send_create(width, height, format, flags); + } + + fn handle_created(&mut self, slf: &Rc, buffer: &Rc) { + if let Some((width, height)) = self.size { + buffer.set_handler(ClientWlBuffer { width, height }); + } else { + log::warn!("dma-buf created without size {slf:?} {buffer:?}"); + } + slf.send_created(buffer); + } + + fn handle_create_immed( + &mut self, + slf: &Rc, + buffer_id: &Rc, + width: i32, + height: i32, + format: u32, + flags: ZwpLinuxBufferParamsV1Flags, + ) { + buffer_id.set_handler(ClientWlBuffer { width, height }); + slf.send_create_immed(buffer_id, width, height, format, flags); + } +} diff --git a/src/deco.rs b/src/deco.rs index f3d087b..c813d06 100644 --- a/src/deco.rs +++ b/src/deco.rs @@ -21,6 +21,7 @@ use crate::{buffer::SimpleBufferPool, globals::Globals, util::Bounds}; #[derive(Default, Debug, Clone, PartialEq)] struct DecoParams { + has_geometry: bool, bounds: Bounds, } @@ -156,6 +157,23 @@ impl Deco { deco } + pub fn handle_intrinsic_size(&self, width: i32, height: i32) { + let mut params = self.next_params.borrow_mut(); + if params.has_geometry { + return; + } + log::debug!( + "decoration {:?} handling buffer size {width}x{height}", + self.wl_surface + ); + params.bounds = Bounds { + x: 0, + y: 0, + width, + height, + }; + } + pub fn handle_window_geometry( &self, x: i32, @@ -167,7 +185,9 @@ impl Deco { "decoration {:?} handling geometry {width}x{height} @ {x},{y}", self.wl_surface ); - self.next_params.borrow_mut().bounds = Bounds { + let mut params = self.next_params.borrow_mut(); + params.has_geometry = true; + params.bounds = Bounds { x, y, width, diff --git a/src/main.rs b/src/main.rs index 8742017..609dbb6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,11 @@ use wl_proxy::{ baseline::Baseline, object::{ConcreteObject, Object, ObjectCoreApi, ObjectRcUtils}, protocols::{ - wayland::wl_registry::{WlRegistry, WlRegistryHandler}, + linux_dmabuf_v1::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1, + wayland::{ + wl_registry::{WlRegistry, WlRegistryHandler}, + wl_shm::WlShm, + }, xdg_shell::xdg_wm_base::XdgWmBase, }, simple::{SimpleCommandExt, SimpleProxy}, @@ -14,6 +18,7 @@ use wl_proxy::{ use crate::globals::Globals; mod buffer; +mod client_buffer; mod deco; mod globals; mod seat; @@ -40,6 +45,12 @@ impl WlRegistryHandler for ClientWlRegistry { .set_handler(xdg::ClientXdgWmBase { globals: self.globals.clone(), }), + WlShm::INTERFACE => id + .downcast::() + .set_handler(client_buffer::ClientWlShm), + ZwpLinuxDmabufV1::INTERFACE => id + .downcast::() + .set_handler(client_buffer::ClientZwpLinuxDmabufV1), _ => {} } slf.send_bind(name, id); diff --git a/src/xdg.rs b/src/xdg.rs index 236c5c1..2060bfe 100644 --- a/src/xdg.rs +++ b/src/xdg.rs @@ -4,7 +4,8 @@ use wl_proxy::{ object::ObjectUtils, protocols::{ wayland::{ - wl_output::WlOutput, + wl_buffer::WlBuffer, + wl_output::{WlOutput, WlOutputTransform}, wl_surface::{WlSurface, WlSurfaceHandler}, }, xdg_shell::{ @@ -17,13 +18,63 @@ use wl_proxy::{ }, }; -use crate::{deco::Deco, globals::Globals, util::Bounds}; +use crate::{client_buffer, deco::Deco, globals::Globals, util::Bounds}; pub struct ClientWlSurface { pub xdg_surface: Rc, + pub transform: Option, + pub scale: Option, } impl WlSurfaceHandler for ClientWlSurface { + fn handle_set_buffer_transform(&mut self, slf: &Rc, transform: WlOutputTransform) { + self.transform = Some(transform); + slf.send_set_buffer_transform(transform); + } + + fn handle_set_buffer_scale(&mut self, slf: &Rc, scale: i32) { + self.scale = Some(scale); + slf.send_set_buffer_scale(scale); + } + + fn handle_attach( + &mut self, + slf: &Rc, + buffer: Option<&Rc>, + x: i32, + y: i32, + ) { + let surf_handler = self.xdg_surface.get_handler_ref::(); + if let Some(buffer) = buffer { + if let Ok(buf_handler) = buffer.try_get_handler_ref::() { + if let Some(deco) = surf_handler.deco.as_ref() { + let mut width = buf_handler.width; + let mut height = buf_handler.height; + if let Some(scale) = self.scale { + width /= scale; + height /= scale; + } + if let Some(transform) = self.transform + && (transform == WlOutputTransform::_90 + || transform == WlOutputTransform::_270 + || transform == WlOutputTransform::FLIPPED_270 + || transform == WlOutputTransform::FLIPPED_270) + { + std::mem::swap(&mut width, &mut height); + } + deco.handle_intrinsic_size(width, height); + } else { + log::debug!("surface {slf:?} buffer attach before deco"); + } + } else { + log::warn!("surface {slf:?} buffer with unknown size {buffer:?}"); + } + } else { + log::debug!("surface {slf:?} buffer cleared"); + } + slf.send_attach(buffer, x, y); + } + fn handle_commit(&mut self, slf: &Rc) { log::debug!("commit {slf:?}"); let surf_handler = self.xdg_surface.get_handler_ref::(); @@ -47,6 +98,8 @@ impl XdgWmBaseHandler for ClientXdgWmBase { ) { surface.set_handler(ClientWlSurface { xdg_surface: id.clone(), + scale: None, + transform: None, }); id.set_handler(ClientXdgSurface { deco: None,