-
Notifications
You must be signed in to change notification settings - Fork 144
Description
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();
}