Draw decorations on commit, skip drawing if params unchanged

This commit is contained in:
Val Packett 2026-03-19 21:35:36 -03:00
parent 35d4419c04
commit 186584398c
4 changed files with 63 additions and 21 deletions

View file

@ -8,7 +8,6 @@ use wl_proxy::{
WpCursorShapeDeviceV1, WpCursorShapeDeviceV1Shape,
},
wayland::{
wl_buffer::WlBuffer,
wl_pointer::WlPointerButtonState,
wl_seat::WlSeat,
wl_subsurface::WlSubsurface,
@ -20,8 +19,14 @@ use wl_proxy::{
use crate::{buffer::SimpleBufferPool, globals::Globals, util::Bounds};
#[derive(Default, Debug, Clone, PartialEq)]
struct DecoParams {
bounds: Bounds,
}
pub struct Deco {
bounds: RefCell<Bounds>,
last_params: RefCell<DecoParams>,
next_params: RefCell<DecoParams>,
top_size: i32,
border_size: i32,
@ -34,10 +39,11 @@ pub struct Deco {
impl Deco {
fn resize_anchor(&self, x: i32, y: i32) -> XdgToplevelResizeEdge {
let bounds = &self.last_params.borrow().bounds;
let n = y < self.border_size;
let e = x >= self.bounds.borrow().width + self.border_size;
let e = x >= bounds.width + self.border_size;
let w = x < self.border_size;
let s = y >= self.bounds.borrow().height + self.border_size;
let s = y >= bounds.height + self.border_size;
if n && e {
XdgToplevelResizeEdge::TOP_RIGHT
} else if n && w {
@ -126,6 +132,7 @@ impl Deco {
globals: &Rc<Globals>,
) -> Rc<Deco> {
let wl_surface = globals.wl_compositor.new_send_create_surface();
log::debug!("creating deco for surface {host_surface:?} -> {wl_surface:?}");
wl_surface.set_forward_to_client(false);
let subsurface = globals
.wl_subcompositor
@ -135,12 +142,8 @@ impl Deco {
let pool = SimpleBufferPool::new(globals, 1, 1).unwrap();
let args = crate::ARGS.get().unwrap();
let deco = Rc::new(Deco {
bounds: RefCell::new(Bounds {
x: 0,
y: 0,
width: 10,
height: 10,
}),
last_params: RefCell::new(Default::default()),
next_params: RefCell::new(Default::default()),
top_size: args.thickness as i32, // TODO: title
border_size: args.thickness as i32,
wl_surface: wl_surface.clone(),
@ -159,17 +162,24 @@ impl Deco {
y: i32,
width: i32,
height: i32,
) -> eyre::Result<(i32, i32, i32, i32)> {
self.bounds.replace(Bounds {
) -> (i32, i32, i32, i32) {
log::debug!(
"decoration {:?} handling geometry {width}x{height} @ {x},{y}",
self.wl_surface
);
self.next_params.borrow_mut().bounds = Bounds {
x,
y,
width,
height,
});
self.draw()?;
};
let width = width + self.border_size * 2;
let height = height + self.top_size + self.border_size;
Ok((x - self.border_size, y - self.top_size, width, height))
(x - self.border_size, y - self.top_size, width, height)
}
pub fn handle_commit(&self) -> eyre::Result<()> {
self.draw()
}
pub fn transform_configure(&self, width: i32, height: i32) -> (i32, i32) {
@ -190,8 +200,18 @@ impl Deco {
(x + self.border_size, y + self.top_size)
}
fn draw(&self) -> eyre::Result<Rc<WlBuffer>> {
let bounds = self.bounds.borrow();
fn draw(&self) -> eyre::Result<()> {
let params = self.next_params.borrow();
if *params == *self.last_params.borrow() {
log::debug!("decoration {:?} unchanged", self.wl_surface);
return Ok(());
}
log::debug!(
"decoration {:?} changed to {params:?}, drawing",
self.wl_surface
);
self.last_params.replace(params.clone());
let bounds = &params.bounds;
let (width, height) = self.transform_size(bounds.width, bounds.height);
let mut pool = self.pool.borrow_mut();
@ -224,6 +244,6 @@ impl Deco {
.send_set_position(bounds.x - self.border_size, bounds.y - self.top_size);
self.wl_surface.send_commit();
// let _ = self.globals.wl_display.new_send_sync();
Ok(buf)
Ok(())
}
}

View file

@ -130,6 +130,7 @@ impl WlPointerHandler for ProxyWlPointer {
let Some((surface_x, surface_y)) = self.last_xy else {
return;
};
log::debug!("pointer button at {surface_x},{surface_y} on {surface:?}");
if let Ok(deco) = surface.try_get_handler_mut::<DecoSurface>() {
deco.pointer_button(&self.seat, serial, surface_x, surface_y, button, state);
}

View file

@ -1,4 +1,4 @@
#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Bounds {
pub x: i32,
pub y: i32,

View file

@ -3,7 +3,10 @@ use std::rc::Rc;
use wl_proxy::{
object::ObjectUtils,
protocols::{
wayland::{wl_output::WlOutput, wl_surface::WlSurface},
wayland::{
wl_output::WlOutput,
wl_surface::{WlSurface, WlSurfaceHandler},
},
xdg_shell::{
xdg_popup::XdgPopup,
xdg_positioner::{XdgPositioner, XdgPositionerHandler},
@ -16,6 +19,21 @@ use wl_proxy::{
use crate::{deco::Deco, globals::Globals, util::Bounds};
pub struct ClientWlSurface {
pub xdg_surface: Rc<XdgSurface>,
}
impl WlSurfaceHandler for ClientWlSurface {
fn handle_commit(&mut self, slf: &Rc<WlSurface>) {
log::debug!("commit {slf:?}");
let surf_handler = self.xdg_surface.get_handler_ref::<ClientXdgSurface>();
if let Some(deco) = surf_handler.deco.as_ref() {
deco.handle_commit().unwrap();
}
slf.send_commit();
}
}
pub struct ClientXdgWmBase {
pub globals: Rc<Globals>,
}
@ -27,6 +45,9 @@ impl XdgWmBaseHandler for ClientXdgWmBase {
id: &Rc<XdgSurface>,
surface: &Rc<WlSurface>,
) {
surface.set_handler(ClientWlSurface {
xdg_surface: id.clone(),
});
id.set_handler(ClientXdgSurface {
deco: None,
globals: self.globals.clone(),
@ -86,7 +107,7 @@ impl XdgSurfaceHandler for ClientXdgSurface {
mut height: i32,
) {
if let Some(deco) = self.deco.as_ref() {
(x, y, width, height) = deco.handle_window_geometry(x, y, width, height).unwrap();
(x, y, width, height) = deco.handle_window_geometry(x, y, width, height);
}
slf.send_set_window_geometry(x, y, width, height);
}