126 lines
3.6 KiB
Rust
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),
|
|
}),
|
|
}
|
|
}
|
|
}
|