Use intrinsic (buffer) size when geometry is not set

The simplest clients like vkcube do not set geometry, and were left
without decorations
This commit is contained in:
Val Packett 2026-03-19 23:19:40 -03:00
parent 186584398c
commit 36c87d4638
4 changed files with 196 additions and 4 deletions

108
src/client_buffer.rs Normal file
View file

@ -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<WlShm>,
id: &Rc<WlShmPool>,
fd: &Rc<OwnedFd>,
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<WlShmPool>,
id: &Rc<WlBuffer>,
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<ZwpLinuxDmabufV1>,
params_id: &Rc<ZwpLinuxBufferParamsV1>,
) {
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<ZwpLinuxBufferParamsV1>,
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<ZwpLinuxBufferParamsV1>, buffer: &Rc<WlBuffer>) {
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<ZwpLinuxBufferParamsV1>,
buffer_id: &Rc<WlBuffer>,
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);
}
}

View file

@ -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,

View file

@ -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::<WlShm>()
.set_handler(client_buffer::ClientWlShm),
ZwpLinuxDmabufV1::INTERFACE => id
.downcast::<ZwpLinuxDmabufV1>()
.set_handler(client_buffer::ClientZwpLinuxDmabufV1),
_ => {}
}
slf.send_bind(name, id);

View file

@ -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<XdgSurface>,
pub transform: Option<WlOutputTransform>,
pub scale: Option<i32>,
}
impl WlSurfaceHandler for ClientWlSurface {
fn handle_set_buffer_transform(&mut self, slf: &Rc<WlSurface>, transform: WlOutputTransform) {
self.transform = Some(transform);
slf.send_set_buffer_transform(transform);
}
fn handle_set_buffer_scale(&mut self, slf: &Rc<WlSurface>, scale: i32) {
self.scale = Some(scale);
slf.send_set_buffer_scale(scale);
}
fn handle_attach(
&mut self,
slf: &Rc<WlSurface>,
buffer: Option<&Rc<WlBuffer>>,
x: i32,
y: i32,
) {
let surf_handler = self.xdg_surface.get_handler_ref::<ClientXdgSurface>();
if let Some(buffer) = buffer {
if let Ok(buf_handler) = buffer.try_get_handler_ref::<client_buffer::ClientWlBuffer>() {
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<WlSurface>) {
log::debug!("commit {slf:?}");
let surf_handler = self.xdg_surface.get_handler_ref::<ClientXdgSurface>();
@ -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,