My application creates a popup which at some point needs to be closed and then reappear again. I tried to implement it by attaching a buffer to the surface after which I attach a none to the surface and then finally attach the same buffer as before. The issue is that when I reattach the buffer I get this error: layer_surface has never been configured
.
I scrolled through the docs a little but did not find anything which describes this behavior. Did I misunderstand something or is this a possible bug?
Example:
use std::{
fs::File,
io::{Seek, SeekFrom, Write},
os::fd::AsFd,
};
use wayland_client::{
delegate_noop,
globals::{registry_queue_init, GlobalListContents},
protocol::{
wl_buffer::WlBuffer,
wl_compositor::WlCompositor,
wl_output::WlOutput,
wl_registry::{self, WlRegistry},
wl_shm::{Format, WlShm},
wl_shm_pool::WlShmPool,
wl_surface::WlSurface,
},
Connection, Dispatch, QueueHandle,
};
use wayland_protocols_wlr::layer_shell::v1::client::{
zwlr_layer_shell_v1::{Layer, ZwlrLayerShellV1},
zwlr_layer_surface_v1::{self, Anchor, KeyboardInteractivity, ZwlrLayerSurfaceV1},
};
struct Delegate;
impl Dispatch<WlRegistry, GlobalListContents> for Delegate {
fn event(
_: &mut Self,
_: &WlRegistry,
_event: wl_registry::Event,
_: &GlobalListContents,
_: &Connection,
_: &QueueHandle<Self>,
) {
}
}
impl Dispatch<ZwlrLayerSurfaceV1, ()> for Delegate {
fn event(
_: &mut Self,
layer_surface: &ZwlrLayerSurfaceV1,
event: <ZwlrLayerSurfaceV1 as wayland_client::Proxy>::Event,
_: &(),
_: &Connection,
_: &QueueHandle<Self>,
) {
println!("test");
if let zwlr_layer_surface_v1::Event::Configure { serial, .. } = event {
layer_surface.ack_configure(serial);
}
}
}
delegate_noop!(Delegate: ignore WlOutput);
delegate_noop!(Delegate: ignore WlShm);
delegate_noop!(Delegate: ignore WlShmPool);
delegate_noop!(Delegate: ignore WlBuffer);
delegate_noop!(Delegate: ignore WlCompositor);
delegate_noop!(Delegate: ignore WlSurface);
delegate_noop!(Delegate: ignore ZwlrLayerShellV1);
fn main() {
let conn = Connection::connect_to_env().unwrap();
let (globals, mut event_queue) = registry_queue_init::<Delegate>(&conn).unwrap();
let qh = event_queue.handle();
let mut outputs = vec![];
for global in globals.contents().clone_list() {
if let "wl_output" = &global.interface[..] {
let output: WlOutput = globals
.registry()
.bind(global.name, global.version, &qh, ());
outputs.push(output);
}
}
let output = &outputs[0];
let mut overlay = tempfile::tempfile().unwrap();
let shm: WlShm = globals.bind(&qh, 1..=1, ()).unwrap();
let compositor: WlCompositor = globals.bind(&qh, 1..=4, ()).unwrap();
let layer_shell: ZwlrLayerShellV1 = globals.bind(&qh, 1..=1, ()).unwrap();
let (width, height) = (1920, 1080);
let shm_pool = shm.create_pool(overlay.as_fd(), width * height * 4, &qh, ());
let buffer = shm_pool.create_buffer(0, width, height, width * 4, Format::Abgr8888, &qh, ());
let surface = compositor.create_surface(&qh, ());
let layer_surface = layer_shell.get_layer_surface(
&surface,
Some(output),
Layer::Overlay,
"ScreenshotUtil".to_string(),
&qh,
(),
);
layer_surface.set_size(width as u32, height as u32);
layer_surface.set_anchor(Anchor::Bottom);
layer_surface.set_margin(0, 0, 0, 0);
layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
layer_surface.set_exclusive_zone(-1);
draw_background([100, 44, 44, 44], &mut overlay);
surface.commit();
event_queue.blocking_dispatch(&mut Delegate).unwrap();
surface.attach(Some(&buffer), 0, 0);
surface.commit();
surface.attach(None, 0, 0);
surface.commit();
surface.attach(Some(&buffer), 0, 0);
surface.commit();
loop {
event_queue.blocking_dispatch(&mut Delegate).unwrap();
}
}
fn draw_background(background: [u8; 4], file: &mut File) {
file.seek(SeekFrom::Start(0)).unwrap();
let cashed = u32::from_ne_bytes(background);
let compressed_buf = vec![cashed; 1920 * 1080];
let uncompressed_buf = bytemuck::cast_slice::<u32, u8>(&compressed_buf[..]);
file.write_all(uncompressed_buf).unwrap();
}
The answer is no it is not a bug, and yes it is described in the docs. https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1
Unmapping a layer_surface means that the surface cannot be shown by the compositor until it is explicitly mapped again. The layer_surface returns to the state it had right after layer_shell.get_layer_surface. The client can re-map the surface by performing a commit without any buffer attached, waiting for a configure event and handling it as usual.