hyprwm / Hyprland

Hyprland is a highly customizable dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
https://hyprland.org
BSD 3-Clause "New" or "Revised" License
17.88k stars 752 forks source link

ZwlrLayerSurfaceV1 Configuration event is not being send on attaching Null buffer. #6651

Closed laycookie closed 58 minutes ago

laycookie commented 5 days ago

Regression?

No

System Info and Version

hyprctl systeminfo -c does not work I build of nixpkgs around a little less then a week ago.

Description

From what I have read from the docs of wayland protocol, it sounds like there should be a layer_surface configuration event emitted when you unmap the buffer from the surface, but hyprland doesn't seem to be doing it.

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.

https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1

How to reproduce

I had written this little app in rust to test it out.

[dependencies]
wayland-client = "0.31.2"
wayland-protocols = "0.31.2"
wayland-protocols-wlr = { version =  "0.2.0", features = ["client"]}
tempfile = "3.10.1"
bytemuck = "1.16.0"
use std::{
    fs::File,
    io::{Seek, SeekFrom, Write},
    os::fd::AsFd,
    thread,
    time::Duration,
};

use wayland_client::{
    delegate_noop,
    globals::{registry_queue_init, GlobalListContents},
    protocol::{
        wl_buffer::WlBuffer,
        wl_compositor::WlCompositor,
        wl_output::WlOutput,
        wl_registry::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,
        _: <WlRegistry as wayland_client::Proxy>::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!("{:#?}", event);
        if let zwlr_layer_surface_v1::Event::Configure { serial, .. } = event {
            layer_surface.ack_configure(serial);
        }
    }
}

delegate_noop!(Delegate: ignore WlSurface);
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 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 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,
        None,
        Layer::Overlay,
        "ScreenshotUtil".to_string(),
        &qh,
        (),
    );

    draw_background([100, 44, 44, 44], &mut overlay);

    // ===
    config(&layer_surface, &surface);
    event_queue.blocking_dispatch(&mut Delegate).unwrap();

    surface.attach(Some(&buffer), 0, 0);
    surface.commit();
    event_queue.blocking_dispatch(&mut Delegate).unwrap();

    thread::sleep(Duration::from_secs(1));
    println!("test1");

    surface.attach(None, 0, 0);
    surface.commit();
    event_queue.blocking_dispatch(&mut Delegate).unwrap();

    thread::sleep(Duration::from_secs(2));
    println!("test2");

    config(&layer_surface, &surface);
    surface.attach(Some(&buffer), 0, 0);
    surface.commit();
    // ===

    println!("finish");
    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();
}

fn config(layer_surface: &ZwlrLayerSurfaceV1, surface: &WlSurface) {
    layer_surface.set_size(1920, 1080);
    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);
    surface.commit();
}

Crash reports, logs, images, videos

No response

vaxerski commented 4 days ago

I suck at rust and hate the language, but: image

Committing a null buffer once unmaps it. You have to attach(null) and then commit() again to signal you want to map

laycookie commented 4 days ago

@vaxerski Ya we dont have Null we use None instead for ressons, so I would assume that surface.attach(None, 0, 0); is analogies to surface.attach(null, 0, 0) in C

vaxerski commented 3 days ago

you need to commit a null buffer again to get a map event

laycookie commented 3 days ago

@vaxerski Ohh alright a bit strange, I assumed that I would be able to commit a buffer and it will also provide me with a map event but alright.

I have attempted to commit an empty buffer twice in both of those ways, but this also didn't result in any events being emitted.

    surface.attach(None, 0, 0);
    surface.commit();
    surface.commit();
    surface.attach(None, 0, 0);
    surface.commit();
    surface.attach(None, 0, 0);
    surface.commit();

My apologies if that is just me miss understanding the docs.

vaxerski commented 2 days ago

honestly dunno, but try reading i3bar-river's source, it does that and works just fine AFAIK https://github.com/MaxVerevkin/i3bar-river

laycookie commented 58 minutes ago

@vaxerski Not sure if something got changed in hyprland but I updated everything on my computer once again switched my NVIDIA drivers to beta and it now appears to work correctly, so I will be closing the issue now.

For anyone who has stumbled on this issue with a similar problem my finial code that worked looks like this.

use std::{
    fs::File,
    io::{Seek, SeekFrom, Write},
    os::fd::AsFd,
    thread,
    time::Duration,
};

use wayland_client::{
    delegate_noop,
    globals::{registry_queue_init, GlobalListContents},
    protocol::{
        wl_buffer::WlBuffer,
        wl_compositor::WlCompositor,
        wl_output::WlOutput,
        wl_registry::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,
        _: <WlRegistry as wayland_client::Proxy>::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!("{:#?}", event);
        if let zwlr_layer_surface_v1::Event::Configure { serial, .. } = event {
            layer_surface.ack_configure(serial);
        }
    }
}

delegate_noop!(Delegate: ignore WlSurface);
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 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 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,
        None,
        Layer::Overlay,
        "ScreenshotUtil".to_string(),
        &qh,
        (),
    );

    draw_background([100, 44, 44, 44], &mut overlay);

    // ===
    config(&layer_surface, &surface);
    event_queue.blocking_dispatch(&mut Delegate).unwrap();

    surface.attach(Some(&buffer), 0, 0);
    surface.commit();
    event_queue.blocking_dispatch(&mut Delegate).unwrap();

    thread::sleep(Duration::from_secs(1));
    println!("test1");

    surface.attach(None, 0, 0);
    surface.commit();

    config(&layer_surface, &surface);
    event_queue.blocking_dispatch(&mut Delegate).unwrap();

    thread::sleep(Duration::from_secs(1));
    println!("test2");

    surface.attach(Some(&buffer), 0, 0);
    surface.commit();
    event_queue.blocking_dispatch(&mut Delegate).unwrap();

    thread::sleep(Duration::from_secs(1));
    // ===

    println!("finish");
    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();
}

fn config(layer_surface: &ZwlrLayerSurfaceV1, surface: &WlSurface) {
    layer_surface.set_size(1920, 1080);
    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);
    surface.commit();
}