smithay/wlcs_anvil/src/ffi_wrappers.rs

262 lines
8.8 KiB
Rust

use std::{
os::{
raw::{c_char, c_int},
unix::{
net::UnixStream,
prelude::{AsRawFd, IntoRawFd},
},
},
thread::JoinHandle,
};
use smithay::reexports::calloop::channel::{channel, Sender};
use wayland_sys::{
client::*,
common::{wl_fixed_t, wl_fixed_to_double},
ffi_dispatch,
};
use crate::{ffi_api::*, WlcsEvent};
macro_rules! container_of(
($ptr: expr, $container: ident, $field: ident) => {
($ptr as *mut u8).offset(-(memoffset::offset_of!($container, $field) as isize)) as *mut $container
}
);
#[no_mangle]
pub static wlcs_server_integration: WlcsServerIntegration = WlcsServerIntegration {
version: 1,
create_server,
destroy_server,
};
unsafe extern "C" fn create_server(_argc: c_int, _argv: *mut *const c_char) -> *mut WlcsDisplayServer {
// block the SIGPIPE signal here, we are a cdylib so Rust does not do it for us
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
sigaction(
Signal::SIGPIPE,
&SigAction::new(SigHandler::SigIgn, SaFlags::empty(), SigSet::empty()),
)
.unwrap();
let handle = Box::into_raw(Box::new(DisplayServerHandle::new()));
&mut (*handle).wlcs_display_server
}
unsafe extern "C" fn destroy_server(ptr: *mut WlcsDisplayServer) {
let _server = Box::from_raw(container_of!(ptr, DisplayServerHandle, wlcs_display_server));
}
struct DisplayServerHandle {
wlcs_display_server: WlcsDisplayServer,
server: Option<(Sender<WlcsEvent>, JoinHandle<()>)>,
next_device_id: u32,
}
impl DisplayServerHandle {
fn new() -> DisplayServerHandle {
DisplayServerHandle {
wlcs_display_server: WlcsDisplayServer {
version: 3,
start: Self::start,
stop: Self::stop,
create_client_socket: Self::create_client_socket,
position_window_absolute: Self::position_window_absolute,
create_pointer: Self::create_pointer,
create_touch: Self::create_touch,
get_descriptor: Self::get_descriptor,
start_on_this_thread: None,
},
server: None,
next_device_id: 1,
}
}
unsafe extern "C" fn start(ptr: *mut WlcsDisplayServer) {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
let (tx, rx) = channel();
let join = crate::start_anvil(rx);
me.server = Some((tx, join));
}
unsafe extern "C" fn stop(ptr: *mut WlcsDisplayServer) {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((sender, join)) = me.server.take() {
let _ = sender.send(WlcsEvent::Exit);
let _ = join.join();
}
}
unsafe extern "C" fn create_client_socket(ptr: *mut WlcsDisplayServer) -> c_int {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((ref sender, _)) = me.server {
if let Ok((client_side, server_side)) = UnixStream::pair() {
if sender
.send(WlcsEvent::NewClient {
stream: server_side,
client_id: client_side.as_raw_fd(),
})
.is_err()
{
return -1;
}
return client_side.into_raw_fd();
}
}
-1
}
unsafe extern "C" fn position_window_absolute(
ptr: *mut WlcsDisplayServer,
display: *mut wl_display,
surface: *mut wl_proxy,
x: c_int,
y: c_int,
) {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
let client_id = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_get_fd, display);
let surface_id = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, surface);
if let Some((ref sender, _)) = me.server {
let _ = sender.send(WlcsEvent::PositionWindow {
client_id,
surface_id,
location: (x, y).into(),
});
}
}
unsafe extern "C" fn create_pointer(ptr: *mut WlcsDisplayServer) -> *mut WlcsPointer {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((ref sender, _)) = me.server {
let pointer = Box::into_raw(Box::new(PointerHandle::new(me.next_device_id, sender.clone())));
me.next_device_id += 1;
&mut (*pointer).wlcs_pointer
} else {
std::ptr::null_mut()
}
}
unsafe extern "C" fn create_touch(ptr: *mut WlcsDisplayServer) -> *mut WlcsTouch {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((ref sender, _)) = me.server {
let pointer = Box::into_raw(Box::new(TouchHandle::new(me.next_device_id, sender.clone())));
me.next_device_id += 1;
&mut (*pointer).wlcs_touch
} else {
std::ptr::null_mut()
}
}
unsafe extern "C" fn get_descriptor(_: *const WlcsDisplayServer) -> *const WlcsIntegrationDescriptor {
&crate::DESCRIPTOR
}
}
struct PointerHandle {
wlcs_pointer: WlcsPointer,
device_id: u32,
sender: Sender<WlcsEvent>,
}
impl PointerHandle {
fn new(device_id: u32, sender: Sender<WlcsEvent>) -> PointerHandle {
PointerHandle {
wlcs_pointer: WlcsPointer {
version: 1,
move_absolute: Self::move_absolute,
move_relative: Self::move_relative,
button_down: Self::button_down,
button_up: Self::button_up,
destroy: Self::destroy,
},
device_id,
sender,
}
}
unsafe extern "C" fn move_absolute(ptr: *mut WlcsPointer, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerMoveAbsolute {
device_id: me.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
});
}
unsafe extern "C" fn move_relative(ptr: *mut WlcsPointer, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerMoveRelative {
device_id: me.device_id,
delta: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
});
}
unsafe extern "C" fn button_up(ptr: *mut WlcsPointer, button_id: i32) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerButtonUp {
device_id: me.device_id,
button_id,
});
}
unsafe extern "C" fn button_down(ptr: *mut WlcsPointer, button_id: i32) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerButtonDown {
device_id: me.device_id,
button_id,
});
}
unsafe extern "C" fn destroy(ptr: *mut WlcsPointer) {
let _me = Box::from_raw(container_of!(ptr, PointerHandle, wlcs_pointer));
}
}
struct TouchHandle {
wlcs_touch: WlcsTouch,
device_id: u32,
sender: Sender<WlcsEvent>,
}
impl TouchHandle {
fn new(device_id: u32, sender: Sender<WlcsEvent>) -> TouchHandle {
TouchHandle {
wlcs_touch: WlcsTouch {
version: 1,
touch_down: Self::touch_down,
touch_move: Self::touch_move,
touch_up: Self::touch_up,
destroy: Self::destroy,
},
device_id,
sender,
}
}
unsafe extern "C" fn touch_down(ptr: *mut WlcsTouch, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, TouchHandle, wlcs_touch);
let _ = me.sender.send(WlcsEvent::TouchDown {
device_id: me.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
});
}
unsafe extern "C" fn touch_move(ptr: *mut WlcsTouch, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, TouchHandle, wlcs_touch);
let _ = me.sender.send(WlcsEvent::TouchMove {
device_id: me.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
});
}
unsafe extern "C" fn touch_up(ptr: *mut WlcsTouch) {
let me = &mut *container_of!(ptr, TouchHandle, wlcs_touch);
let _ = me.sender.send(WlcsEvent::TouchUp {
device_id: me.device_id,
});
}
unsafe extern "C" fn destroy(ptr: *mut WlcsTouch) {
let _me = Box::from_raw(container_of!(ptr, TouchHandle, wlcs_touch));
}
}