use sctk::reexports::calloop::LoopHandle;
pub use waycrate_xkbkeycode::keyboard;
pub use waycrate_xkbkeycode::xkb_keyboard;
pub use sctk::reexports::calloop;
mod events;
mod strtoshape;
use std::fmt::Debug;
use events::DispatchMessageInner;
pub mod id;
pub use events::{AxisScroll, DispatchMessage, LayerEvent, ReturnData, XdgInfoChangedType};
use strtoshape::str_to_shape;
use wayland_client::{
delegate_noop,
globals::{registry_queue_init, BindError, GlobalError, GlobalList, GlobalListContents},
protocol::{
wl_buffer::WlBuffer,
wl_compositor::WlCompositor,
wl_display::WlDisplay,
wl_keyboard::{self, KeyState, KeymapFormat, WlKeyboard},
wl_output::{self, WlOutput},
wl_pointer::{self, WlPointer},
wl_registry,
wl_seat::{self, WlSeat},
wl_shm::WlShm,
wl_shm_pool::WlShmPool,
wl_surface::WlSurface,
wl_touch::{self, WlTouch},
},
ConnectError, Connection, Dispatch, DispatchError, EventQueue, Proxy, QueueHandle, WEnum,
};
use sctk::reexports::{calloop::EventLoop, calloop_wayland_source::WaylandSource};
use std::time::Duration;
use wayland_cursor::{CursorImageBuffer, CursorTheme};
use wayland_protocols_wlr::layer_shell::v1::client::{
zwlr_layer_shell_v1::{Layer, ZwlrLayerShellV1},
zwlr_layer_surface_v1::{self, Anchor, ZwlrLayerSurfaceV1},
};
use wayland_protocols::{
wp::fractional_scale::v1::client::{
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
wp_fractional_scale_v1::{self, WpFractionalScaleV1},
},
xdg::xdg_output::zv1::client::{
zxdg_output_manager_v1::ZxdgOutputManagerV1,
zxdg_output_v1::{self, ZxdgOutputV1},
},
};
use wayland_protocols::wp::cursor_shape::v1::client::{
wp_cursor_shape_device_v1::WpCursorShapeDeviceV1,
wp_cursor_shape_manager_v1::WpCursorShapeManagerV1,
};
use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{
zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1,
zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
};
use sctk::reexports::calloop::Error as CallLoopError;
#[derive(Debug, thiserror::Error)]
pub enum LayerEventError {
#[error("connect error")]
ConnectError(#[from] ConnectError),
#[error("Global Error")]
GlobalError(#[from] GlobalError),
#[error("Bind Error")]
BindError(#[from] BindError),
#[error("Error during queue")]
DispatchError(#[from] DispatchError),
#[error("create file failed")]
TempFileCreateFailed(#[from] std::io::Error),
#[error("Event Loop Error")]
EventLoopInitError(#[from] CallLoopError),
}
pub mod reexport {
pub use wayland_protocols_wlr::layer_shell::v1::client::{
zwlr_layer_shell_v1::{Layer, ZwlrLayerShellV1},
zwlr_layer_surface_v1::{Anchor, KeyboardInteractivity},
};
pub mod wl_shm {
pub use wayland_client::protocol::wl_shm::Format;
pub use wayland_client::protocol::wl_shm::WlShm;
}
pub mod zwp_virtual_keyboard_v1 {
pub use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{
zwp_virtual_keyboard_manager_v1::{self, ZwpVirtualKeyboardManagerV1},
zwp_virtual_keyboard_v1::{self, ZwpVirtualKeyboardV1},
};
}
pub mod wp_fractional_scale_v1 {
pub use wayland_protocols::wp::fractional_scale::v1::client::{
wp_fractional_scale_manager_v1::{self, WpFractionalScaleManagerV1},
wp_fractional_scale_v1::{self, WpFractionalScaleV1},
};
}
pub mod wayland_client {
pub use wayland_client::{
globals::GlobalList,
protocol::{
wl_keyboard::{self, KeyState},
wl_pointer::{self, ButtonState},
wl_seat::WlSeat,
},
QueueHandle, WEnum,
};
}
}
#[derive(Debug)]
struct BaseState;
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for BaseState {
fn event(
_state: &mut Self,
_proxy: &wl_registry::WlRegistry,
_event: <wl_registry::WlRegistry as wayland_client::Proxy>::Event,
_data: &GlobalListContents,
_conn: &Connection,
_qh: &wayland_client::QueueHandle<Self>,
) {
}
}
#[derive(Debug)]
pub struct ZxdgOutputInfo {
zxdgoutput: ZxdgOutputV1,
logical_size: (i32, i32),
position: (i32, i32),
}
impl ZxdgOutputInfo {
fn new(zxdgoutput: ZxdgOutputV1) -> Self {
Self {
zxdgoutput,
logical_size: (0, 0),
position: (0, 0),
}
}
pub fn get_position(&self) -> (i32, i32) {
self.position
}
pub fn get_logical_size(&self) -> (i32, i32) {
self.logical_size
}
}
#[derive(Debug)]
pub struct WindowStateUnit<T: Debug> {
id: id::Id,
display: WlDisplay,
wl_surface: WlSurface,
size: (u32, u32),
buffer: Option<WlBuffer>,
layer_shell: ZwlrLayerSurfaceV1,
zxdgoutput: Option<ZxdgOutputInfo>,
fractional_scale: Option<WpFractionalScaleV1>,
binding: Option<T>,
}
impl<T: Debug> WindowStateUnit<T> {
pub fn id(&self) -> id::Id {
self.id
}
pub fn gen_wrapper(&self) -> WindowWrapper {
WindowWrapper {
id: self.id,
display: self.display.clone(),
wl_surface: self.wl_surface.clone(),
}
}
}
impl<T: Debug> WindowStateUnit<T> {
#[inline]
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
Ok(rwh_06::WaylandWindowHandle::new({
let ptr = self.wl_surface.id().as_ptr();
std::ptr::NonNull::new(ptr as *mut _).expect("wl_surface will never be null")
})
.into())
}
#[inline]
pub fn raw_display_handle_rwh_06(
&self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::WaylandDisplayHandle::new({
let ptr = self.display.id().as_ptr();
std::ptr::NonNull::new(ptr as *mut _).expect("wl_proxy should never be null")
})
.into())
}
}
impl<T: Debug> rwh_06::HasWindowHandle for WindowStateUnit<T> {
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
let raw = self.raw_window_handle_rwh_06()?;
Ok(unsafe { rwh_06::WindowHandle::borrow_raw(raw) })
}
}
impl<T: Debug> rwh_06::HasDisplayHandle for WindowStateUnit<T> {
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
let raw = self.raw_display_handle_rwh_06()?;
Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) })
}
}
impl<T: Debug> rwh_06::HasWindowHandle for WindowState<T> {
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
let raw = self.main_window().raw_window_handle_rwh_06()?;
Ok(unsafe { rwh_06::WindowHandle::borrow_raw(raw) })
}
}
impl<T: Debug> rwh_06::HasDisplayHandle for WindowState<T> {
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
let raw = self.main_window().raw_display_handle_rwh_06()?;
Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) })
}
}
impl<T: Debug> WindowStateUnit<T> {
pub fn get_wlsurface(&self) -> &WlSurface {
&self.wl_surface
}
pub fn get_xdgoutput_info(&self) -> Option<&ZxdgOutputInfo> {
self.zxdgoutput.as_ref()
}
pub fn set_anchor(&self, anchor: Anchor) {
self.layer_shell.set_anchor(anchor);
self.wl_surface.commit();
}
pub fn set_margin(&self, (top, right, bottom, left): (i32, i32, i32, i32)) {
self.layer_shell.set_margin(top, right, bottom, left);
self.wl_surface.commit();
}
pub fn set_layer(&self, layer: Layer) {
self.layer_shell.set_layer(layer);
self.wl_surface.commit();
}
pub fn set_size(&self, (width, height): (u32, u32)) {
self.layer_shell.set_size(width, height);
self.wl_surface.commit();
}
pub fn set_exclusive_zone(&self, zone: i32) {
self.layer_shell.set_exclusive_zone(zone);
self.wl_surface.commit();
}
pub fn set_binding(&mut self, binding: T) {
self.binding = Some(binding);
}
pub fn get_binding_mut(&mut self) -> Option<&mut T> {
self.binding.as_mut()
}
pub fn get_size(&self) -> (u32, u32) {
self.size
}
pub fn request_refresh(&self, (width, height): (i32, i32)) {
self.wl_surface.attach(self.buffer.as_ref(), 0, 0);
self.wl_surface.damage(0, 0, width, height);
self.wl_surface.commit();
}
}
#[derive(Debug)]
pub struct WindowState<T: Debug> {
outputs: Vec<(u32, wl_output::WlOutput)>,
current_surface: Option<WlSurface>,
is_single: bool,
units: Vec<WindowStateUnit<T>>,
message: Vec<(Option<usize>, DispatchMessageInner)>,
connection: Option<Connection>,
event_queue: Option<EventQueue<WindowState<T>>>,
wl_compositor: Option<WlCompositor>,
xdg_output_manager: Option<ZxdgOutputManagerV1>,
shm: Option<WlShm>,
cursor_manager: Option<WpCursorShapeManagerV1>,
fractional_scale_manager: Option<WpFractionalScaleManagerV1>,
globals: Option<GlobalList>,
seat: Option<WlSeat>,
keyboard_state: Option<xkb_keyboard::KeyboardState>,
pointer: Option<WlPointer>,
touch: Option<WlTouch>,
virtual_keyboard: Option<ZwpVirtualKeyboardV1>,
namespace: String,
keyboard_interactivity: zwlr_layer_surface_v1::KeyboardInteractivity,
anchor: Anchor,
layer: Layer,
size: Option<(u32, u32)>,
exclusive_zone: Option<i32>,
margin: Option<(i32, i32, i32, i32)>,
use_display_handle: bool,
loop_handler: Option<LoopHandle<'static, Self>>,
}
impl<T: Debug> WindowState<T> {
pub fn main_window(&self) -> &WindowStateUnit<T> {
&self.units[0]
}
pub fn get_window_with_id(&self, id: id::Id) -> Option<&WindowStateUnit<T>> {
self.units.iter().find(|w| w.id() == id)
}
pub fn windows(&self) -> &Vec<WindowStateUnit<T>> {
&self.units
}
}
#[derive(Debug)]
pub struct WindowWrapper {
pub id: id::Id,
display: WlDisplay,
wl_surface: WlSurface,
}
impl WindowWrapper {
pub fn id(&self) -> id::Id {
self.id
}
}
impl<T: Debug> WindowState<T> {
pub fn get_seat(&self) -> &WlSeat {
self.seat.as_ref().unwrap()
}
pub fn get_keyboard(&self) -> Option<&WlKeyboard> {
Some(&self.keyboard_state.as_ref()?.keyboard)
}
pub fn get_pointer(&self) -> Option<&WlPointer> {
self.pointer.as_ref()
}
pub fn get_touch(&self) -> Option<&WlTouch> {
self.touch.as_ref()
}
}
impl<T: Debug> WindowState<T> {
pub fn gen_main_wrapper(&self) -> WindowWrapper {
self.main_window().gen_wrapper()
}
}
impl WindowWrapper {
#[inline]
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
Ok(rwh_06::WaylandWindowHandle::new({
let ptr = self.wl_surface.id().as_ptr();
std::ptr::NonNull::new(ptr as *mut _).expect("wl_surface will never be null")
})
.into())
}
#[inline]
pub fn raw_display_handle_rwh_06(
&self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::WaylandDisplayHandle::new({
let ptr = self.display.id().as_ptr();
std::ptr::NonNull::new(ptr as *mut _).expect("wl_proxy should never be null")
})
.into())
}
}
impl rwh_06::HasWindowHandle for WindowWrapper {
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
let raw = self.raw_window_handle_rwh_06()?;
Ok(unsafe { rwh_06::WindowHandle::borrow_raw(raw) })
}
}
impl rwh_06::HasDisplayHandle for WindowWrapper {
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
let raw = self.raw_display_handle_rwh_06()?;
Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) })
}
}
impl<T: Debug> WindowState<T> {
pub fn new(namespace: &str) -> Self {
assert_ne!(namespace, "");
Self {
namespace: namespace.to_owned(),
..Default::default()
}
}
pub fn with_single(mut self, single: bool) -> Self {
self.is_single = single;
self
}
pub fn with_keyboard_interacivity(
mut self,
keyboard_interacivity: zwlr_layer_surface_v1::KeyboardInteractivity,
) -> Self {
self.keyboard_interactivity = keyboard_interacivity;
self
}
pub fn with_anchor(mut self, anchor: Anchor) -> Self {
self.anchor = anchor;
self
}
pub fn with_layer(mut self, layer: Layer) -> Self {
self.layer = layer;
self
}
pub fn with_margin(mut self, (top, right, bottom, left): (i32, i32, i32, i32)) -> Self {
self.margin = Some((top, right, bottom, left));
self
}
pub fn with_size(mut self, size: (u32, u32)) -> Self {
self.size = Some(size);
self
}
pub fn with_option_size(mut self, size: Option<(u32, u32)>) -> Self {
self.size = size;
self
}
pub fn with_exclusize_zone(mut self, exclusive_zone: i32) -> Self {
self.exclusive_zone = Some(exclusive_zone);
self
}
pub fn with_use_display_handle(mut self, use_display_handle: bool) -> Self {
self.use_display_handle = use_display_handle;
self
}
}
impl<T: Debug> Default for WindowState<T> {
fn default() -> Self {
Self {
outputs: Vec::new(),
current_surface: None,
is_single: true,
units: Vec::new(),
message: Vec::new(),
connection: None,
event_queue: None,
wl_compositor: None,
shm: None,
cursor_manager: None,
xdg_output_manager: None,
globals: None,
fractional_scale_manager: None,
virtual_keyboard: None,
seat: None,
keyboard_state: None,
pointer: None,
touch: None,
namespace: "".to_owned(),
keyboard_interactivity: zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand,
layer: Layer::Overlay,
anchor: Anchor::Top | Anchor::Left | Anchor::Right | Anchor::Bottom,
size: None,
exclusive_zone: None,
margin: None,
use_display_handle: false,
loop_handler: None,
}
}
}
impl<T: Debug> WindowState<T> {
pub fn set_virtual_keyboard(&mut self, keyboard: ZwpVirtualKeyboardV1) {
self.virtual_keyboard = Some(keyboard);
}
pub fn get_virtual_keyboard(&self) -> Option<&ZwpVirtualKeyboardV1> {
self.virtual_keyboard.as_ref()
}
pub fn get_loop_handler(&self) -> Option<&LoopHandle<'static, Self>> {
self.loop_handler.as_ref()
}
pub fn get_unit(&mut self, index: usize) -> &mut WindowStateUnit<T> {
&mut self.units[index]
}
pub fn get_unit_iter(&self) -> impl Iterator<Item = &WindowStateUnit<T>> {
self.units.iter()
}
pub fn get_unit_iter_mut(&mut self) -> impl Iterator<Item = &mut WindowStateUnit<T>> {
self.units.iter_mut()
}
fn surface_pos(&self) -> Option<usize> {
self.units
.iter()
.position(|unit| Some(&unit.wl_surface) == self.current_surface.as_ref())
}
fn get_pos_from_surface(&self, surface: &WlSurface) -> Option<usize> {
self.units
.iter()
.position(|unit| &unit.wl_surface == surface)
}
}
impl<T: Debug + 'static> Dispatch<wl_registry::WlRegistry, ()> for WindowState<T> {
fn event(
state: &mut Self,
proxy: &wl_registry::WlRegistry,
event: <wl_registry::WlRegistry as wayland_client::Proxy>::Event,
_data: &(),
_conn: &Connection,
qh: &wayland_client::QueueHandle<Self>,
) {
match event {
wl_registry::Event::Global {
name,
interface,
version,
} => {
if interface == wl_output::WlOutput::interface().name {
let output = proxy.bind::<wl_output::WlOutput, _, _>(name, version, qh, ());
state.outputs.push((name, output.clone()));
state
.message
.push((None, DispatchMessageInner::NewDisplay(output)));
}
}
wl_registry::Event::GlobalRemove { name } => {
state.outputs.retain(|x| x.0 != name);
state.units.retain(|unit| unit.wl_surface.is_alive());
}
_ => {}
}
}
}
impl<T: Debug + 'static> Dispatch<wl_seat::WlSeat, ()> for WindowState<T> {
fn event(
state: &mut Self,
seat: &wl_seat::WlSeat,
event: <wl_seat::WlSeat as Proxy>::Event,
_data: &(),
_conn: &Connection,
qh: &wayland_client::QueueHandle<Self>,
) {
use xkb_keyboard::KeyboardState;
if let wl_seat::Event::Capabilities {
capabilities: WEnum::Value(capabilities),
} = event
{
if capabilities.contains(wl_seat::Capability::Keyboard) {
state.keyboard_state = Some(KeyboardState::new(seat.get_keyboard(qh, ())));
}
if capabilities.contains(wl_seat::Capability::Pointer) {
state.pointer = Some(seat.get_pointer(qh, ()));
}
if capabilities.contains(wl_seat::Capability::Touch) {
state.touch = Some(seat.get_touch(qh, ()));
}
}
}
}
impl<T: Debug> Dispatch<wl_keyboard::WlKeyboard, ()> for WindowState<T> {
fn event(
state: &mut Self,
_proxy: &wl_keyboard::WlKeyboard,
event: <wl_keyboard::WlKeyboard as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
use keyboard::*;
use xkb_keyboard::ElementState;
let keyboard_state = state.keyboard_state.as_mut().unwrap();
match event {
wl_keyboard::Event::Keymap { format, fd, size } => match format {
WEnum::Value(KeymapFormat::XkbV1) => {
let context = &mut keyboard_state.xkb_context;
context.set_keymap_from_fd(fd, size as usize)
}
WEnum::Value(KeymapFormat::NoKeymap) => {
log::warn!("non-xkb compatible keymap")
}
_ => unreachable!(),
},
wl_keyboard::Event::Leave { .. } => {
state.message.push((
state.surface_pos(),
DispatchMessageInner::ModifiersChanged(ModifiersState::empty()),
));
}
wl_keyboard::Event::Key {
state: keystate,
key,
..
} => {
let pressed_state = match keystate {
WEnum::Value(KeyState::Pressed) => ElementState::Pressed,
WEnum::Value(KeyState::Released) => ElementState::Released,
_ => {
return;
}
};
let key = key + 8;
if let Some(mut key_context) = keyboard_state.xkb_context.key_context() {
let event = key_context.process_key_event(key, pressed_state, false);
let event = DispatchMessageInner::KeyboardInput {
event,
is_synthetic: false,
};
state.message.push((state.surface_pos(), event));
}
}
wl_keyboard::Event::Modifiers {
mods_depressed,
mods_locked,
mods_latched,
group,
..
} => {
let xkb_context = &mut keyboard_state.xkb_context;
let xkb_state = match xkb_context.state_mut() {
Some(state) => state,
None => return,
};
xkb_state.update_modifiers(mods_depressed, mods_latched, mods_locked, 0, 0, group);
let modifiers = xkb_state.modifiers();
state.message.push((
state.surface_pos(),
DispatchMessageInner::ModifiersChanged(modifiers.into()),
))
}
_ => {}
}
}
}
impl<T: Debug> Dispatch<wl_touch::WlTouch, ()> for WindowState<T> {
fn event(
state: &mut Self,
_proxy: &wl_touch::WlTouch,
event: <wl_touch::WlTouch as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
match event {
wl_touch::Event::Down {
serial,
time,
surface,
id,
x,
y,
} => state.message.push((
state.get_pos_from_surface(&surface),
DispatchMessageInner::TouchDown {
serial,
time,
id,
x,
y,
},
)),
wl_touch::Event::Up { serial, time, id } => state
.message
.push((None, DispatchMessageInner::TouchUp { serial, time, id })),
wl_touch::Event::Motion { time, id, x, y } => state
.message
.push((None, DispatchMessageInner::TouchMotion { time, id, x, y })),
_ => {}
}
}
}
impl<T: Debug> Dispatch<wl_pointer::WlPointer, ()> for WindowState<T> {
fn event(
state: &mut Self,
pointer: &wl_pointer::WlPointer,
event: <wl_pointer::WlPointer as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &wayland_client::QueueHandle<Self>,
) {
match event {
wl_pointer::Event::Axis { time, axis, value } => match axis {
WEnum::Value(axis) => {
let (mut horizontal, mut vertical) = <(AxisScroll, AxisScroll)>::default();
match axis {
wl_pointer::Axis::VerticalScroll => {
vertical.absolute = value;
}
wl_pointer::Axis::HorizontalScroll => {
horizontal.absolute = value;
}
_ => unreachable!(),
};
state.message.push((
state.surface_pos(),
DispatchMessageInner::Axis {
time,
horizontal,
vertical,
source: None,
},
))
}
WEnum::Unknown(unknown) => {
log::warn!(target: "layershellev", "{}: invalid pointer axis: {:x}", pointer.id(), unknown);
}
},
wl_pointer::Event::AxisStop { time, axis } => match axis {
WEnum::Value(axis) => {
let (mut horizontal, mut vertical) = <(AxisScroll, AxisScroll)>::default();
match axis {
wl_pointer::Axis::VerticalScroll => vertical.stop = true,
wl_pointer::Axis::HorizontalScroll => horizontal.stop = true,
_ => unreachable!(),
}
state.message.push((
state.surface_pos(),
DispatchMessageInner::Axis {
time,
horizontal,
vertical,
source: None,
},
));
}
WEnum::Unknown(unknown) => {
log::warn!(target: "layershellev", "{}: invalid pointer axis: {:x}", pointer.id(), unknown);
}
},
wl_pointer::Event::AxisSource { axis_source } => match axis_source {
WEnum::Value(source) => state.message.push((
state.surface_pos(),
DispatchMessageInner::Axis {
horizontal: AxisScroll::default(),
vertical: AxisScroll::default(),
source: Some(source),
time: 0,
},
)),
WEnum::Unknown(unknown) => {
log::warn!(target: "layershellev", "unknown pointer axis source: {:x}", unknown);
}
},
wl_pointer::Event::AxisDiscrete { axis, discrete } => match axis {
WEnum::Value(axis) => {
let (mut horizontal, mut vertical) = <(AxisScroll, AxisScroll)>::default();
match axis {
wl_pointer::Axis::VerticalScroll => {
vertical.discrete = discrete;
}
wl_pointer::Axis::HorizontalScroll => {
horizontal.discrete = discrete;
}
_ => unreachable!(),
};
state.message.push((
state.surface_pos(),
DispatchMessageInner::Axis {
time: 0,
horizontal,
vertical,
source: None,
},
));
}
WEnum::Unknown(unknown) => {
log::warn!(target: "layershellev", "{}: invalid pointer axis: {:x}", pointer.id(), unknown);
}
},
wl_pointer::Event::Button {
state: btnstate,
serial,
button,
time,
} => {
state.message.push((
state.surface_pos(),
DispatchMessageInner::MouseButton {
state: btnstate,
serial,
button,
time,
},
));
}
wl_pointer::Event::Leave { .. } => {
state.current_surface = None;
state
.message
.push((state.surface_pos(), DispatchMessageInner::MouseLeave));
}
wl_pointer::Event::Enter {
serial,
surface,
surface_x,
surface_y,
} => {
state.current_surface = Some(surface.clone());
state.message.push((
state.surface_pos(),
DispatchMessageInner::MouseEnter {
pointer: pointer.clone(),
serial,
surface_x,
surface_y,
},
));
}
wl_pointer::Event::Motion {
time,
surface_x,
surface_y,
} => {
state.message.push((
state.surface_pos(),
DispatchMessageInner::MouseMotion {
time,
surface_x,
surface_y,
},
));
}
_ => {
}
}
}
}
impl<T: Debug> Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for WindowState<T> {
fn event(
state: &mut Self,
surface: &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
event: <zwlr_layer_surface_v1::ZwlrLayerSurfaceV1 as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &wayland_client::QueueHandle<Self>,
) {
if let zwlr_layer_surface_v1::Event::Configure {
serial,
width,
height,
} = event
{
surface.ack_configure(serial);
let Some(unit_index) = state
.units
.iter()
.position(|unit| unit.layer_shell == *surface)
else {
return;
};
state.units[unit_index].size = (width, height);
state.message.push((
Some(unit_index),
DispatchMessageInner::RefreshSurface { width, height },
));
}
}
}
impl<T: Debug> Dispatch<zxdg_output_v1::ZxdgOutputV1, ()> for WindowState<T> {
fn event(
state: &mut Self,
proxy: &zxdg_output_v1::ZxdgOutputV1,
event: <zxdg_output_v1::ZxdgOutputV1 as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
let Some(index) = state.units.iter().position(|info| {
info.zxdgoutput
.as_ref()
.is_some_and(|zxdgoutput| zxdgoutput.zxdgoutput == *proxy)
}) else {
return;
};
let info = &mut state.units[index];
let xdg_info = info.zxdgoutput.as_mut().unwrap();
let change_type = match event {
zxdg_output_v1::Event::LogicalSize { width, height } => {
xdg_info.logical_size = (width, height);
XdgInfoChangedType::Size
}
zxdg_output_v1::Event::LogicalPosition { x, y } => {
xdg_info.position = (x, y);
XdgInfoChangedType::Position
}
_ => {
return;
}
};
state.message.push((
Some(index),
DispatchMessageInner::XdgInfoChanged(change_type),
));
}
}
impl<T: Debug> Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ()> for WindowState<T> {
fn event(
state: &mut Self,
proxy: &wp_fractional_scale_v1::WpFractionalScaleV1,
event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
if let wp_fractional_scale_v1::Event::PreferredScale { scale } = event {
let Some(index) = state.units.iter().position(|info| {
info.fractional_scale
.as_ref()
.is_some_and(|fractional_scale| fractional_scale == proxy)
}) else {
return;
};
state
.message
.push((Some(index), DispatchMessageInner::PrefredScale(scale)));
}
}
}
delegate_noop!(@<T: Debug>WindowState<T>: ignore WlCompositor); delegate_noop!(@<T: Debug>WindowState<T>: ignore WlSurface); delegate_noop!(@<T: Debug>WindowState<T>: ignore WlOutput); delegate_noop!(@<T: Debug>WindowState<T>: ignore WlShm); delegate_noop!(@<T: Debug>WindowState<T>: ignore WlShmPool); delegate_noop!(@<T: Debug>WindowState<T>: ignore WlBuffer); delegate_noop!(@<T: Debug>WindowState<T>: ignore ZwlrLayerShellV1);
delegate_noop!(@<T: Debug>WindowState<T>: ignore WpCursorShapeManagerV1);
delegate_noop!(@<T: Debug>WindowState<T>: ignore WpCursorShapeDeviceV1);
delegate_noop!(@<T: Debug>WindowState<T>: ignore ZwpVirtualKeyboardV1);
delegate_noop!(@<T: Debug>WindowState<T>: ignore ZwpVirtualKeyboardManagerV1);
delegate_noop!(@<T: Debug>WindowState<T>: ignore ZxdgOutputManagerV1);
delegate_noop!(@<T: Debug>WindowState<T>: ignore WpFractionalScaleManagerV1);
impl<T: Debug + 'static> WindowState<T> {
pub fn build(mut self) -> Result<Self, LayerEventError> {
let connection = Connection::connect_to_env()?;
let (globals, _) = registry_queue_init::<BaseState>(&connection)?;
let mut event_queue = connection.new_event_queue::<WindowState<T>>();
let qh = event_queue.handle();
let wmcompositer = globals.bind::<WlCompositor, _, _>(&qh, 1..=5, ())?;
let shm = globals.bind::<WlShm, _, _>(&qh, 1..=1, ())?;
self.shm = Some(shm);
self.seat = Some(globals.bind::<WlSeat, _, _>(&qh, 1..=1, ())?);
let cursor_manager = globals
.bind::<WpCursorShapeManagerV1, _, _>(&qh, 1..=1, ())
.ok();
let _ = connection.display().get_registry(&qh, ());
let xdg_output_manager = globals.bind::<ZxdgOutputManagerV1, _, _>(&qh, 1..=3, ())?;
let fractional_scale_manager = globals
.bind::<WpFractionalScaleManagerV1, _, _>(&qh, 1..=1, ())
.ok();
event_queue.blocking_dispatch(&mut self)?;
if self.is_single {
let wl_surface = wmcompositer.create_surface(&qh, ()); let layer_shell = globals
.bind::<ZwlrLayerShellV1, _, _>(&qh, 3..=4, ())
.unwrap();
let layer = layer_shell.get_layer_surface(
&wl_surface,
None,
self.layer,
self.namespace.clone(),
&qh,
(),
);
layer.set_anchor(self.anchor);
layer.set_keyboard_interactivity(self.keyboard_interactivity);
if let Some((init_w, init_h)) = self.size {
layer.set_size(init_w, init_h);
}
if let Some(zone) = self.exclusive_zone {
layer.set_exclusive_zone(zone);
}
if let Some((top, right, bottom, left)) = self.margin {
layer.set_margin(top, right, bottom, left);
}
wl_surface.commit();
let mut fractional_scale = None;
if let Some(ref fractional_scale_manager) = fractional_scale_manager {
fractional_scale =
Some(fractional_scale_manager.get_fractional_scale(&wl_surface, &qh, ()));
}
self.units.push(WindowStateUnit {
id: id::Id::unique(),
display: connection.display(),
wl_surface,
size: (0, 0),
buffer: None,
layer_shell: layer,
zxdgoutput: None,
fractional_scale,
binding: None,
});
} else {
let displays = self.outputs.clone();
for (_, display) in displays.iter() {
let wl_surface = wmcompositer.create_surface(&qh, ()); let layer_shell = globals
.bind::<ZwlrLayerShellV1, _, _>(&qh, 3..=4, ())
.unwrap();
let layer = layer_shell.get_layer_surface(
&wl_surface,
Some(display),
self.layer,
self.namespace.clone(),
&qh,
(),
);
layer.set_anchor(self.anchor);
layer.set_keyboard_interactivity(self.keyboard_interactivity);
if let Some((init_w, init_h)) = self.size {
layer.set_size(init_w, init_h);
}
if let Some(zone) = self.exclusive_zone {
layer.set_exclusive_zone(zone);
}
if let Some((top, right, bottom, left)) = self.margin {
layer.set_margin(top, right, bottom, left);
}
wl_surface.commit();
let zxdgoutput = xdg_output_manager.get_xdg_output(display, &qh, ());
let mut fractional_scale = None;
if let Some(ref fractional_scale_manager) = fractional_scale_manager {
fractional_scale =
Some(fractional_scale_manager.get_fractional_scale(&wl_surface, &qh, ()));
}
self.units.push(WindowStateUnit {
id: id::Id::unique(),
display: connection.display(),
wl_surface,
size: (0, 0),
buffer: None,
layer_shell: layer,
zxdgoutput: Some(ZxdgOutputInfo::new(zxdgoutput)),
fractional_scale,
binding: None,
});
}
self.message.clear();
}
self.event_queue = Some(event_queue);
self.globals = Some(globals);
self.wl_compositor = Some(wmcompositer);
self.fractional_scale_manager = fractional_scale_manager;
self.cursor_manager = cursor_manager;
self.xdg_output_manager = Some(xdg_output_manager);
self.connection = Some(connection);
Ok(self)
}
pub fn running_with_proxy<F, Message>(
mut self,
message_receiver: std::sync::mpsc::Receiver<Message>,
mut event_handler: F,
) -> Result<(), LayerEventError>
where
F: FnMut(LayerEvent<T, Message>, &mut WindowState<T>, Option<usize>) -> ReturnData,
{
let globals = self.globals.take().unwrap();
let event_queue = self.event_queue.take().unwrap();
let qh = event_queue.handle();
let wmcompositer = self.wl_compositor.take().unwrap();
let shm = self.shm.take().unwrap();
let fractional_scale_manager = self.fractional_scale_manager.take();
let cursor_manager: Option<WpCursorShapeManagerV1> = self.cursor_manager.take();
let xdg_output_manager = self.xdg_output_manager.take().unwrap();
let connection = self.connection.take().unwrap();
let mut init_event = None;
while !matches!(init_event, Some(ReturnData::None)) {
match init_event {
None => {
init_event = Some(event_handler(LayerEvent::InitRequest, &mut self, None));
}
Some(ReturnData::RequestBind) => {
init_event = Some(event_handler(
LayerEvent::BindProvide(&globals, &qh),
&mut self,
None,
));
}
_ => panic!("Not provide server here"),
}
}
let mut event_loop: EventLoop<Self> =
EventLoop::try_new().expect("Failed to initialize the event loop");
WaylandSource::new(connection.clone(), event_queue)
.insert(event_loop.handle())
.expect("Failed to init wayland source");
self.loop_handler = Some(event_loop.handle());
'out: loop {
event_loop.dispatch(Duration::from_millis(1), &mut self)?;
let mut messages = Vec::new();
std::mem::swap(&mut messages, &mut self.message);
for msg in messages.iter() {
match msg {
(Some(unit_index), DispatchMessageInner::RefreshSurface { width, height }) => {
let index = *unit_index;
if self.units[index].buffer.is_none() && !self.use_display_handle {
let mut file = tempfile::tempfile()?;
let ReturnData::WlBuffer(buffer) = event_handler(
LayerEvent::RequestBuffer(&mut file, &shm, &qh, *width, *height),
&mut self,
Some(index),
) else {
panic!("You cannot return this one");
};
let surface = &self.units[index].wl_surface;
surface.attach(Some(&buffer), 0, 0);
self.units[index].buffer = Some(buffer);
} else {
event_handler(
LayerEvent::RequestMessages(&DispatchMessage::RequestRefresh {
width: *width,
height: *height,
}),
&mut self,
Some(index),
);
}
let surface = &self.units[index].wl_surface;
surface.commit();
}
(index_info, DispatchMessageInner::XdgInfoChanged(change_type)) => {
event_handler(
LayerEvent::XdgInfoChanged(*change_type),
&mut self,
*index_info,
);
}
(_, DispatchMessageInner::NewDisplay(display)) => {
if self.is_single {
continue;
}
let wl_surface = wmcompositer.create_surface(&qh, ()); let layer_shell = globals
.bind::<ZwlrLayerShellV1, _, _>(&qh, 3..=4, ())
.unwrap();
let layer = layer_shell.get_layer_surface(
&wl_surface,
Some(display),
self.layer,
self.namespace.clone(),
&qh,
(),
);
layer.set_anchor(self.anchor);
layer.set_keyboard_interactivity(self.keyboard_interactivity);
if let Some((init_w, init_h)) = self.size {
layer.set_size(init_w, init_h);
}
if let Some(zone) = self.exclusive_zone {
layer.set_exclusive_zone(zone);
}
if let Some((top, right, bottom, left)) = self.margin {
layer.set_margin(top, right, bottom, left);
}
wl_surface.commit();
let zxdgoutput = xdg_output_manager.get_xdg_output(display, &qh, ());
let mut fractional_scale = None;
if let Some(ref fractional_scale_manager) = fractional_scale_manager {
fractional_scale = Some(fractional_scale_manager.get_fractional_scale(
&wl_surface,
&qh,
(),
));
}
self.units.push(WindowStateUnit {
id: id::Id::unique(),
display: connection.display(),
wl_surface,
size: (0, 0),
buffer: None,
layer_shell: layer,
zxdgoutput: Some(ZxdgOutputInfo::new(zxdgoutput)),
fractional_scale,
binding: None,
});
}
_ => {
let (index_message, msg) = msg;
let msg: DispatchMessage = msg.clone().into();
match event_handler(
LayerEvent::RequestMessages(&msg),
&mut self,
*index_message,
) {
ReturnData::RedrawAllRequest => {
for index in 0..self.units.len() {
let unit = &self.units[index];
event_handler(
LayerEvent::RequestMessages(
&DispatchMessage::RequestRefresh {
width: unit.size.0,
height: unit.size.1,
},
),
&mut self,
None,
);
}
}
ReturnData::RedrawIndexRequest(id) => {
if let Some((index, unit)) = &self
.units
.iter()
.enumerate()
.find(|(_, unit)| unit.id == id)
{
event_handler(
LayerEvent::RequestMessages(
&DispatchMessage::RequestRefresh {
width: unit.size.0,
height: unit.size.1,
},
),
&mut self,
Some(*index),
);
}
}
ReturnData::RequestExist => {
break 'out;
}
ReturnData::RequestSetCursorShape((shape_name, pointer, serial)) => {
if let Some(ref cursor_manager) = cursor_manager {
let Some(shape) = str_to_shape(&shape_name) else {
eprintln!("Not supported shape");
continue;
};
let device = cursor_manager.get_pointer(&pointer, &qh, ());
device.set_shape(serial, shape);
device.destroy();
} else {
let Some(cursor_buffer) =
get_cursor_buffer(&shape_name, &connection, &shm)
else {
eprintln!("Cannot find cursor {shape_name}");
continue;
};
let cursor_surface = wmcompositer.create_surface(&qh, ());
cursor_surface.attach(Some(&cursor_buffer), 0, 0);
let (hotspot_x, hotspot_y) = cursor_buffer.hotspot();
pointer.set_cursor(
serial,
Some(&cursor_surface),
hotspot_x as i32,
hotspot_y as i32,
);
cursor_surface.commit();
}
}
_ => {}
}
}
}
}
if let Ok(event) = message_receiver.try_recv() {
match event_handler(LayerEvent::UserEvent(event), &mut self, None) {
ReturnData::RequestExist => {
break 'out;
}
ReturnData::RequestSetCursorShape((shape_name, pointer, serial)) => {
if let Some(ref cursor_manager) = cursor_manager {
let Some(shape) = str_to_shape(&shape_name) else {
eprintln!("Not supported shape");
continue;
};
let device = cursor_manager.get_pointer(&pointer, &qh, ());
device.set_shape(serial, shape);
device.destroy();
} else {
let Some(cursor_buffer) =
get_cursor_buffer(&shape_name, &connection, &shm)
else {
eprintln!("Cannot find cursor {shape_name}");
continue;
};
let cursor_surface = wmcompositer.create_surface(&qh, ());
cursor_surface.attach(Some(&cursor_buffer), 0, 0);
let (hotspot_x, hotspot_y) = cursor_buffer.hotspot();
pointer.set_cursor(
serial,
Some(&cursor_surface),
hotspot_x as i32,
hotspot_y as i32,
);
cursor_surface.commit();
}
}
_ => {}
}
}
let mut return_data = vec![event_handler(LayerEvent::NormalDispatch, &mut self, None)];
loop {
let mut replace_data = Vec::new();
for data in return_data {
match data {
ReturnData::RedrawAllRequest => {
for index in 0..self.units.len() {
let unit = &self.units[index];
replace_data.push(event_handler(
LayerEvent::RequestMessages(&DispatchMessage::RequestRefresh {
width: unit.size.0,
height: unit.size.1,
}),
&mut self,
Some(index),
));
}
}
ReturnData::RedrawIndexRequest(id) => {
if let Some((index, unit)) = &self
.units
.iter()
.enumerate()
.find(|(_, unit)| unit.id == id)
{
replace_data.push(event_handler(
LayerEvent::RequestMessages(&DispatchMessage::RequestRefresh {
width: unit.size.0,
height: unit.size.1,
}),
&mut self,
Some(*index),
));
}
}
ReturnData::RequestExist => {
break 'out;
}
ReturnData::RequestSetCursorShape((shape_name, pointer, serial)) => {
if let Some(ref cursor_manager) = cursor_manager {
let Some(shape) = str_to_shape(&shape_name) else {
eprintln!("Not supported shape");
continue;
};
let device = cursor_manager.get_pointer(&pointer, &qh, ());
device.set_shape(serial, shape);
device.destroy();
} else {
let Some(cursor_buffer) =
get_cursor_buffer(&shape_name, &connection, &shm)
else {
eprintln!("Cannot find cursor {shape_name}");
continue;
};
let cursor_surface = wmcompositer.create_surface(&qh, ());
cursor_surface.attach(Some(&cursor_buffer), 0, 0);
let (hotspot_x, hotspot_y) = cursor_buffer.hotspot();
pointer.set_cursor(
serial,
Some(&cursor_surface),
hotspot_x as i32,
hotspot_y as i32,
);
cursor_surface.commit();
}
}
_ => {}
}
}
replace_data.retain(|x| *x != ReturnData::None);
if replace_data.is_empty() {
break;
}
return_data = replace_data;
}
continue;
}
Ok(())
}
pub fn running<F>(mut self, mut event_handler: F) -> Result<(), LayerEventError>
where
F: FnMut(LayerEvent<T, ()>, &mut WindowState<T>, Option<usize>) -> ReturnData,
{
let globals = self.globals.take().unwrap();
let event_queue = self.event_queue.take().unwrap();
let qh = event_queue.handle();
let wmcompositer = self.wl_compositor.take().unwrap();
let shm = self.shm.take().unwrap();
let fractional_scale_manager = self.fractional_scale_manager.take();
let cursor_manager: Option<WpCursorShapeManagerV1> = self.cursor_manager.take();
let xdg_output_manager = self.xdg_output_manager.take().unwrap();
let connection = self.connection.take().unwrap();
let mut init_event = None;
while !matches!(init_event, Some(ReturnData::None)) {
match init_event {
None => {
init_event = Some(event_handler(LayerEvent::InitRequest, &mut self, None));
}
Some(ReturnData::RequestBind) => {
init_event = Some(event_handler(
LayerEvent::BindProvide(&globals, &qh),
&mut self,
None,
));
}
_ => panic!("Not provide server here"),
}
}
let mut event_loop: EventLoop<Self> =
EventLoop::try_new().expect("Failed to initialize the event loop");
WaylandSource::new(connection.clone(), event_queue)
.insert(event_loop.handle())
.expect("Failed to init wayland source");
'out: loop {
event_loop.dispatch(Duration::from_millis(1), &mut self)?;
let mut messages = Vec::new();
std::mem::swap(&mut messages, &mut self.message);
for msg in messages.iter() {
match msg {
(Some(unit_index), DispatchMessageInner::RefreshSurface { width, height }) => {
let index = *unit_index;
if self.units[index].buffer.is_none() && !self.use_display_handle {
let mut file = tempfile::tempfile()?;
let ReturnData::WlBuffer(buffer) = event_handler(
LayerEvent::RequestBuffer(&mut file, &shm, &qh, *width, *height),
&mut self,
Some(index),
) else {
panic!("You cannot return this one");
};
let surface = &self.units[index].wl_surface;
surface.attach(Some(&buffer), 0, 0);
self.units[index].buffer = Some(buffer);
} else {
event_handler(
LayerEvent::RequestMessages(&DispatchMessage::RequestRefresh {
width: *width,
height: *height,
}),
&mut self,
Some(index),
);
}
let surface = &self.units[index].wl_surface;
surface.commit();
}
(index_info, DispatchMessageInner::XdgInfoChanged(change_type)) => {
event_handler(
LayerEvent::XdgInfoChanged(*change_type),
&mut self,
*index_info,
);
}
(_, DispatchMessageInner::NewDisplay(display)) => {
if self.is_single {
continue;
}
let wl_surface = wmcompositer.create_surface(&qh, ()); let layer_shell = globals
.bind::<ZwlrLayerShellV1, _, _>(&qh, 3..=4, ())
.unwrap();
let layer = layer_shell.get_layer_surface(
&wl_surface,
Some(display),
self.layer,
self.namespace.clone(),
&qh,
(),
);
layer.set_anchor(self.anchor);
layer.set_keyboard_interactivity(self.keyboard_interactivity);
if let Some((init_w, init_h)) = self.size {
layer.set_size(init_w, init_h);
}
if let Some(zone) = self.exclusive_zone {
layer.set_exclusive_zone(zone);
}
if let Some((top, right, bottom, left)) = self.margin {
layer.set_margin(top, right, bottom, left);
}
wl_surface.commit();
let zxdgoutput = xdg_output_manager.get_xdg_output(display, &qh, ());
let mut fractional_scale = None;
if let Some(ref fractional_scale_manager) = fractional_scale_manager {
fractional_scale = Some(fractional_scale_manager.get_fractional_scale(
&wl_surface,
&qh,
(),
));
}
self.units.push(WindowStateUnit {
id: id::Id::unique(),
display: connection.display(),
wl_surface,
size: (0, 0),
buffer: None,
layer_shell: layer,
zxdgoutput: Some(ZxdgOutputInfo::new(zxdgoutput)),
fractional_scale,
binding: None,
});
}
_ => {
let (index_message, msg) = msg;
let msg: DispatchMessage = msg.clone().into();
match event_handler(
LayerEvent::RequestMessages(&msg),
&mut self,
*index_message,
) {
ReturnData::RequestExist => {
break 'out;
}
ReturnData::RequestSetCursorShape((shape_name, pointer, serial)) => {
if let Some(ref cursor_manager) = cursor_manager {
let Some(shape) = str_to_shape(&shape_name) else {
eprintln!("Not supported shape");
continue;
};
let device = cursor_manager.get_pointer(&pointer, &qh, ());
device.set_shape(serial, shape);
device.destroy();
} else {
let Some(cursor_buffer) =
get_cursor_buffer(&shape_name, &connection, &shm)
else {
eprintln!("Cannot find cursor {shape_name}");
continue;
};
let cursor_surface = wmcompositer.create_surface(&qh, ());
cursor_surface.attach(Some(&cursor_buffer), 0, 0);
let (hotspot_x, hotspot_y) = cursor_buffer.hotspot();
pointer.set_cursor(
serial,
Some(&cursor_surface),
hotspot_x as i32,
hotspot_y as i32,
);
cursor_surface.commit();
}
}
_ => {}
}
}
}
}
match event_handler(LayerEvent::NormalDispatch, &mut self, None) {
ReturnData::RequestExist => {
break 'out;
}
ReturnData::RequestSetCursorShape((shape_name, pointer, serial)) => {
if let Some(ref cursor_manager) = cursor_manager {
let Some(shape) = str_to_shape(&shape_name) else {
eprintln!("Not supported shape");
continue;
};
let device = cursor_manager.get_pointer(&pointer, &qh, ());
device.set_shape(serial, shape);
device.destroy();
} else {
let Some(cursor_buffer) = get_cursor_buffer(&shape_name, &connection, &shm)
else {
eprintln!("Cannot find cursor {shape_name}");
continue;
};
let cursor_surface = wmcompositer.create_surface(&qh, ());
cursor_surface.attach(Some(&cursor_buffer), 0, 0);
let (hotspot_x, hotspot_y) = cursor_buffer.hotspot();
pointer.set_cursor(
serial,
Some(&cursor_surface),
hotspot_x as i32,
hotspot_y as i32,
);
cursor_surface.commit();
}
}
_ => {}
}
continue;
}
Ok(())
}
}
fn get_cursor_buffer(
shape: &str,
connection: &Connection,
shm: &WlShm,
) -> Option<CursorImageBuffer> {
let mut cursor_theme = CursorTheme::load(connection, shm.clone(), 23).ok()?;
let cursor = cursor_theme.get_cursor(shape);
Some(cursor?[0].clone())
}