Files
wayland_client/src/registry.rs
T

126 lines
3.6 KiB
Rust

// SPDX-License-Identifier: GPL-2.0-only
use std::ffi::CStr;
use std::{ffi::{c_char,c_void}, ptr::NonNull};
use crate::registry::ffi::{wl_proxy, wl_proxy_add_listener, wl_registry, wl_registry_listener};
mod ffi {
use std::ffi::{c_char, c_void};
#[repr(C)]
#[allow(non_camel_case_types)]
pub(super) struct wl_registry;
#[repr(C)]
#[allow(non_camel_case_types)]
pub(super) struct wl_proxy;
// function types
#[allow(non_camel_case_types)]
pub(super) type registry_global_callback = unsafe extern "C" fn(*mut c_void, *mut wl_registry, u32, *const c_char, u32);
#[allow(non_camel_case_types)]
pub(super) type registry_global_remove_callback = unsafe extern "C" fn(*mut c_void, *mut wl_registry, u32);
#[allow(non_camel_case_types)]
pub(super) type cb_implementation = unsafe extern "C" fn();
#[repr(C)]
pub(super) struct wl_registry_listener {
pub global: Option<registry_global_callback>,
pub global_remove: Option<registry_global_remove_callback>
}
#[link(name = "wayland-client")]
unsafe extern "C" {
pub(super) unsafe fn wl_proxy_add_listener(proxy: *mut wl_proxy, implementation: *const cb_implementation, data: *mut c_void);
}
}
// C->Rust trampoline functions
unsafe extern "C" fn registry_handle_global(
data: *mut c_void,
_registry: *mut wl_registry,
name: u32,
interface: *const c_char,
version: u32,
) {
let registry = unsafe {
&mut *(data as *mut RegistryListener)
};
let interface = unsafe {
CStr::from_ptr(interface)
.to_string_lossy()
.into_owned()
};
if let Some(callback) = registry.global.as_mut() {
callback(interface, name, version)
}
}
unsafe extern "C" fn registry_handle_global_remove(
data: *mut c_void,
_registry: *mut wl_registry,
name: u32,
) {
let registry = unsafe {
&mut *(data as *mut RegistryListener)
};
if let Some(callback) = registry.global_remove.as_mut() {
callback(name)
}
}
// callback holder cell
pub struct RegistryListener {
global: Option<Box<dyn FnMut(String, u32, u32) + 'static>>,
global_remove: Option<Box<dyn FnMut(u32) + 'static>>,
}
// the main registry cell
pub struct Registry {
raw: NonNull<wl_registry>,
callbacks: Box<RegistryListener>,
listener: Box<wl_registry_listener>,
}
impl Registry {
pub fn on_global<F>(&mut self, global: F)
where
F: FnMut(String, u32, u32) + 'static
{
self.callbacks.global = Some(Box::new(global));
}
pub fn on_global_remove<F>(&mut self, global_remove: F)
where
F: FnMut(u32) + 'static
{
self.callbacks.global_remove = Some(Box::new(global_remove));
}
pub fn registry_listener(&mut self) {
unsafe {
wl_proxy_add_listener(
self.raw.as_ptr() as *mut wl_proxy,
&*self.listener as *const _ as *const ffi::cb_implementation,
self.callbacks.as_mut() as *mut _ as *mut c_void)
};
}
}
impl From<*mut c_void> for Registry {
fn from(value: *mut c_void) -> Self {
let raw = NonNull::new(value as *mut wl_registry)
.expect("unable to get display registry");
Self {
raw,
callbacks: Box::new(
RegistryListener { global: None, global_remove: None }
),
listener: Box::new(ffi::wl_registry_listener {
global: Some(registry_handle_global),
global_remove: Some(registry_handle_global_remove),
}),
}
}
}