Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Zai-Kun opened this issue Jan 17, 2025 · 2 comments
Open

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

Zai-Kun opened this issue Jan 17, 2025 · 2 comments

Comments

@Zai-Kun
Copy link

Zai-Kun commented Jan 17, 2025

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();
}
@Zai-Kun
Copy link
Author

Zai-Kun commented Jan 17, 2025

Also, how can i put the overlay on the whole screen? including the exclusive zones like taskbars and stuff. My current implementation doesn't put an overlay on the waybar even tho I used the overlay layer.

@Zai-Kun
Copy link
Author

Zai-Kun commented Jan 18, 2025

Also, how can i put the overlay on the whole screen? including the exclusive zones like taskbars and stuff. My current implementation doesn't put an overlay on the waybar even tho I used the overlay layer.

Found the solution to it. Just had to use 'zwlr_layer_surface_v1_set_exclusive_zone'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant