Skip to content

[Question] How can i impliment multi-threading? #779

@Zai-Kun

Description

@Zai-Kun

What I want to do is listen to commands/events from another place (in my case, it's going to be sway-ipc), change the 'state' struct accordingly, and update the overlay content. How can I achieve this? Do you think I even need to use multi-threading here? Also, I'm going to be creating an overlay on top of the whole screen using the wlr-layer-shell protocol and setting the input region to an empty input region so I won't be receiving any mouse events or keyboard events from the overlay. I'm probably not going to receive any events from the wayland server (probably). How should I approach this?

Any help is appreciated. Thanks in advance!
Here is what I currently have (it's pretty much the same as the example in the examples folder, but instead of using xdg-shell, I'm using wlr layer shell):

use std::os::unix::io::AsFd;
use std::{error::Error, fs::File};
use wayland_client::{
    delegate_noop,
    protocol::{wl_buffer, wl_compositor, wl_region, wl_registry, wl_shm, wl_shm_pool, wl_surface},
    Connection, Dispatch, QueueHandle
};

use wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::Anchor;
use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};

use std::io::Write;

struct State {
    running: bool,
    wl_compositor: Option<wl_compositor::WlCompositor>,
    base_surface: Option<wl_surface::WlSurface>,
    wl_shm: Option<wl_shm::WlShm>,
    buffer: Option<wl_buffer::WlBuffer>,
    configured: bool,
    wm_base: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
    zwlr_surface: Option<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
}

delegate_noop!(State: ignore wl_compositor::WlCompositor);
delegate_noop!(State: ignore wl_surface::WlSurface);
delegate_noop!(State: ignore wl_region::WlRegion);
delegate_noop!(State: ignore wl_shm::WlShm);
delegate_noop!(State: ignore wl_shm_pool::WlShmPool);
delegate_noop!(State: ignore wl_buffer::WlBuffer);

impl State {
    fn init_zwlr_surface(&mut self, qh: &QueueHandle<State>) {
        let wm_base = self.wm_base.as_ref().unwrap();
        let base_surface = self.base_surface.as_ref().unwrap();
        let wl_compositor = self.wl_compositor.as_ref().unwrap();

        let zwlr_surface = wm_base.get_layer_surface(
            base_surface,
            None,
            zwlr_layer_shell_v1::Layer::Overlay,
            "kitty".into(),
            qh,
            (),
        );
        zwlr_surface.set_size(0, 0);
        zwlr_surface.set_anchor(Anchor::all());
        
        let r = wl_compositor.create_region(qh, ());
        base_surface.set_input_region(Some(&r));
        r.destroy();
        base_surface.commit();

        self.zwlr_surface = Some(zwlr_surface);
    }
}

impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
    fn event(
        state: &mut Self,
        wm_base: &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
        event: zwlr_layer_surface_v1::Event,
        _: &(),
        _: &Connection,
        qh: &QueueHandle<Self>,
    ) {
        println!("{:?}", event);
        if let zwlr_layer_surface_v1::Event::Configure {
            serial,
            width,
            height,
        } = event
        {
            wm_base.ack_configure(serial);
            if state.configured {
                return;
            }
            let mut file = tempfile::tempfile().unwrap();
            draw(&mut file, (width, height));
            let pool = state.wl_shm.as_ref().unwrap().create_pool(
                file.as_fd(),
                (width * height  * 4) as i32,
                qh,
                (),
            );
            let buffer = pool.create_buffer(
                0,
                width as i32,
                height as i32,
                (width * 4) as i32,
                wl_shm::Format::Argb8888,
                qh,
                (),
            );
            state.buffer = Some(buffer.clone());
            
            let surface = state.base_surface.as_ref().unwrap();
            surface.attach(Some(&buffer), 0, 0);
            surface.commit();
            state.configured = true;

        } else if let zwlr_layer_surface_v1::Event::Closed = event {
            state.running = false;
        }
    }
}

impl Dispatch<zwlr_layer_shell_v1::ZwlrLayerShellV1, ()> for State {
    fn event(
        _: &mut Self,
        _: &zwlr_layer_shell_v1::ZwlrLayerShellV1,
        event: zwlr_layer_shell_v1::Event,
        _: &(),
        _: &Connection,
        _: &QueueHandle<Self>,
    ) {
        println!("{:?}", event);
    }
}

impl Dispatch<wl_registry::WlRegistry, ()> for State {
    fn event(
        state: &mut Self,
        registry: &wl_registry::WlRegistry,
        event: wl_registry::Event,
        _: &(),
        _: &Connection,
        qh: &QueueHandle<Self>,
    ) {
        if let wl_registry::Event::Global {
            name, interface, ..
        } = event
        {
            match &interface[..] {
                "wl_compositor" => {
                    let compositor =
                        registry.bind::<wl_compositor::WlCompositor, _, _>(name, 1, qh, ());
                    let surface = compositor.create_surface(qh, ());
                    state.base_surface = Some(surface);
                    state.wl_compositor = Some(compositor);
                    if state.wm_base.is_some() && state.zwlr_surface.is_none() {
                        state.init_zwlr_surface(qh);
                    }
                }
                "wl_shm" => {
                    state.wl_shm = Some(registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ()));
                }
                "zwlr_layer_shell_v1" => {
                    let wm_base = registry.bind::<zwlr_layer_shell_v1::ZwlrLayerShellV1, _, _>(
                        name,
                        1,
                        qh,
                        (),
                    );
                    state.wm_base = Some(wm_base);

                    if state.base_surface.is_some() && state.zwlr_surface.is_none() {
                        state.init_zwlr_surface(qh);
                    }
                }
                _ => {}
            }
        }
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let conn = Connection::connect_to_env()?;
    let mut event_queue = conn.new_event_queue::<State>();
    let qhandle = event_queue.handle();
    let display = conn.display();
    display.get_registry(&qhandle, ());
    let mut state = State {
        running: true,
        wl_compositor: None,
        wl_shm: None,
        base_surface: None,
        buffer: None,
        configured: false,
        wm_base: None,
        zwlr_surface: None,
    };

    while state.running {
        event_queue.blocking_dispatch(&mut state).unwrap();
    }

    Ok(())
}

fn draw(tmp: &mut File, (buf_x, buf_y): (u32, u32)) {
    use std::cmp::min;
    let mut buf = std::io::BufWriter::new(tmp);
    for y in 0..buf_y {
        for x in 0..buf_x {
            let a = 0x0;
            let r = min(((buf_x - x) * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
            let g = min((x * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
            let b = min(((buf_x - x) * 0xFF) / buf_x, (y * 0xFF) / buf_y);
            buf.write_all(&[b as u8, g as u8, r as u8, a as u8]).unwrap();
        }
    }
    buf.flush().unwrap();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions