Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions backends/qtfb-clients/c/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions backends/qtfb-clients/c/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "qtfb-client-c"
version = "0.1.0"
edition = "2021"
[features]
capi = []

[dependencies]
qtfb-client = { path = "../rust" }
libc = "0.2.186"
5 changes: 5 additions & 0 deletions backends/qtfb-clients/c/cbindgen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language = "C"

# An optional name to use as an include guard
# default: doesn't emit an include guard
include_guard = "appload_bindings"
108 changes: 108 additions & 0 deletions backends/qtfb-clients/c/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
mod dumbstupidhack {
pub(crate) use qtfb_client::ClientConnection as QTFB_ClientConnection;
pub(crate) use qtfb_client::InputMessage as QTFB_InputMessage;
}
mod capi {
use std::ffi::c_void;
use std::ptr::null;
use libc::c_int;
use qtfb_client;
use qtfb_client::RefreshMode;
use qtfb_client::user_input::InputEvent;
use crate::dumbstupidhack;


pub const QTFB_DEFAULT_SCENE: u32 = 245209899;
#[no_mangle]
pub static QTFB_SOCKET_PATH: &[u8] = b"/tmp/qtfb.sock\0";
pub const QTFB_MESSAGE_INITIALIZE: u8 = 0;
pub const QTFB_MESSAGE_UPDATE: u8 = 1;
pub const QTFB_MESSAGE_CUSTOM_INITIALIZE: u8 = 2;
pub const QTFB_UPDATE_ALL: i32 = 0;
pub const QTFB_UPDATE_PARTIAL: i32 = 1;
pub const QTFB_FBFMT_RM2FB: u8 = 0;
pub const QTFB_FBFMT_RMPP_RGB888: u8 = 1;
pub const QTFB_FBFMT_RMPP_RGBA8888: u8 = 2;

pub type QTFB_FBKey = u32;

pub type QTFB_ClientConnection = c_void;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct QTFB_InputMessage {
input_type: u32,
dev_id: u32,
x: u32, y: u32, d: u32
}


#[repr(C)]
struct QTFB_CustomResolution {
width: u16,
height: u16,
}

#[no_mangle]
unsafe extern "C" fn qtfb_create_connection<'a>(framebuffer_id: QTFB_FBKey,
shm_type: u8,
custom_resolution: *const QTFB_CustomResolution,
) -> *mut dumbstupidhack::QTFB_ClientConnection<'a> {
match dumbstupidhack::QTFB_ClientConnection::new(framebuffer_id, shm_type, custom_resolution.as_ref().and_then(|t| Some((t.width, t.height)))) {
Ok(val) => Box::into_raw(Box::new(val)),
Err(err) => {
eprintln!("Couldnt open connection: {}", err);
null::<*mut dumbstupidhack::QTFB_ClientConnection>() as *mut dumbstupidhack::QTFB_ClientConnection
}
}
}
#[no_mangle]
unsafe extern "C" fn qtfb_send_complete_update(connection: *mut dumbstupidhack::QTFB_ClientConnection) -> c_int {
connection.as_ref().unwrap().send_complete_update().map_or_else(|e| e.raw_os_error().unwrap_or(-1), |_| 0)
}
#[no_mangle]
unsafe extern "C" fn qtfb_send_partial_update(connection: *mut dumbstupidhack::QTFB_ClientConnection, x: i32, y: i32, w: i32, h: i32) -> c_int {
connection.as_ref().unwrap().send_partial_update(x, y, w, h).map_or_else(|e| e.raw_os_error().unwrap_or(-1), |_| 0)
}
#[no_mangle]
unsafe extern "C" fn qtfb_destroy_connection(connection: *mut dumbstupidhack::QTFB_ClientConnection) {
if connection.is_null() {
return;
}
let _ = Box::from_raw(connection);
}
#[no_mangle]
extern "C" fn qtfb_get_socket_path() -> *const libc::c_char {
QTFB_SOCKET_PATH.as_ptr() as *const libc::c_char
}

#[no_mangle]
unsafe extern "C" fn qtfb_get_buffer(connection: *mut dumbstupidhack::QTFB_ClientConnection) -> *const u8 {
return connection.as_ref().unwrap().shm.as_ptr()
}

#[no_mangle]
unsafe extern "C" fn qtfb_set_refresh_mode(connection: *mut dumbstupidhack::QTFB_ClientConnection, mode: u32) -> c_int {
let mode_enum = match mode {
0 => RefreshMode::UltraFast,
1 => RefreshMode::Fast,
2 => RefreshMode::Animate,
3 => RefreshMode::Content,
4 => RefreshMode::UI,
_ => return -1,
};
return connection.as_mut().unwrap().set_refresh_mode(mode_enum).map_or_else(|e| e.raw_os_error().unwrap_or(-1), |_| 0);
}

#[no_mangle]
unsafe extern "C" fn qtfb_poll_input(connection: *mut dumbstupidhack::QTFB_ClientConnection, message: *const dumbstupidhack::QTFB_InputMessage) -> bool {
match (connection.as_ref().unwrap().poll_input()) {
Ok(val) => {
let dst_ptr = message as *mut qtfb_client::InputMessage;
std::ptr::write(dst_ptr, val);
true
},
Err(_) => false
}
}
}
8 changes: 8 additions & 0 deletions backends/qtfb-clients/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "qtfb-client"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1.0.94"
libc = "0.2.169"
108 changes: 100 additions & 8 deletions backends/qtfb-clients/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub mod user_input;

use std::cmp::PartialEq;
use anyhow::{Error, Result};
use libc::{
c_void, mmap, munmap, sockaddr_un, socket, AF_UNIX, MAP_FAILED, MAP_SHARED, PROT_READ,
Expand All @@ -11,13 +14,16 @@ use std::mem::transmute;
use std::os::unix::io::{AsRawFd, RawFd};
use std::ptr;
use std::slice;
use crate::user_input::InputEvent;

pub mod constants {
pub const DEFAULT_SCENE: u32 = 245209899;
pub const SOCKET_PATH: &str = "/tmp/qtfb.sock";
pub const MESSAGE_INITIALIZE: u8 = 0;
pub const MESSAGE_INPUT: u8 = 4;
pub const MESSAGE_UPDATE: u8 = 1;
pub const MESSAGE_CUSTOM_INITIALIZE: u8 = 2;
pub const MESSAGE_SET_REFRESH_MODE: u8 = 5;
pub const UPDATE_ALL: i32 = 0;
pub const UPDATE_PARTIAL: i32 = 1;
pub const FBFMT_RM2FB: u8 = 0;
Expand All @@ -27,6 +33,15 @@ pub mod constants {
pub type FBKey = u32;
}


#[repr(C)]
#[derive(Clone, Copy)]
pub struct InputMessage {
input_type: InputEvent,
dev_id: u32,
x: u32, y: u32, d: u32
}

pub type FBKey = u32;

#[repr(C)]
Expand Down Expand Up @@ -67,6 +82,7 @@ union ClientMessageContents {
init: InitMessageContents,
update: UpdateRegionMessageContents,
custom_init: CustomInitMessageContents,
refresh_mode: i32
}

#[repr(C)]
Expand All @@ -75,16 +91,39 @@ struct ClientMessage {
contents: ClientMessageContents,
}

#[repr(C)]
union ServerMessageContents {
init: InitMessageResponseContents,
input: InputMessage,
}

#[repr(C)]
struct ServerMessage {
msg_type: u8,
init: InitMessageResponseContents,
contents: ServerMessageContents,
}

pub struct ClientConnection<'a> {
fd: RawFd,
current_refresh_mode: RefreshMode,
pub shm: &'a mut [u8],
}
#[repr(u32)]
#[derive(Clone, Copy, PartialEq)]
pub enum RefreshMode {
UltraFast=0,
Fast=1,
Animate=2,
Content=3,
UI=4
}



#[derive(Debug, Clone)]
struct InvalidMessage;



impl<'a> ClientConnection<'a> {
pub fn new(
Expand Down Expand Up @@ -158,10 +197,10 @@ impl<'a> ClientConnection<'a> {

let mut server_message = ServerMessage {
msg_type: 0,
init: InitMessageResponseContents {
contents: ServerMessageContents { init: InitMessageResponseContents {
shm_key_defined: 0,
shm_size: 0,
},
}},
};

let recv_res = unsafe {
Expand All @@ -176,14 +215,17 @@ impl<'a> ClientConnection<'a> {
if recv_res < 1 {
return Err(Error::new(io::Error::last_os_error()));
}

let shm_name = format!("/dev/shm/qtfb_{}", server_message.init.shm_key_defined);
if (server_message.msg_type != constants::MESSAGE_INITIALIZE) {
return Err(Error::from(io::Error::other("your message here")));
}
let init_message = unsafe{ server_message.contents.init};
let shm_name = format!("/dev/shm/qtfb_{}", init_message.shm_key_defined);
let shm_fd = OpenOptions::new().read(true).write(true).open(&shm_name)?;

let shm_ptr = unsafe {
mmap(
ptr::null_mut(),
server_message.init.shm_size,
init_message.shm_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
shm_fd.as_raw_fd(),
Expand All @@ -196,9 +238,9 @@ impl<'a> ClientConnection<'a> {
}

let shm =
unsafe { slice::from_raw_parts_mut(shm_ptr as *mut u8, server_message.init.shm_size) };
unsafe { slice::from_raw_parts_mut(shm_ptr as *mut u8, init_message.shm_size) };

Ok(Self { fd, shm })
Ok(Self { fd, current_refresh_mode: RefreshMode::UI, shm })
}

pub fn send_complete_update(&self) -> io::Result<()> {
Expand Down Expand Up @@ -250,6 +292,56 @@ impl<'a> ClientConnection<'a> {
}
Ok(())
}

pub fn poll_input(&self) -> Result<InputMessage> {

let mut server_message = ServerMessage {
msg_type: 0,
contents: ServerMessageContents { input: InputMessage {
input_type: InputEvent::BtnXLeft,
dev_id: 0,
x: 0,
y: 0,
d: 0,
}},
};

let recv_res = unsafe {
libc::recv(
self.fd,
&mut server_message as *mut _ as *mut c_void,
mem::size_of::<ServerMessage>(),
libc::MSG_DONTWAIT,
)
};

if recv_res < 1 {
return Err(Error::new(io::Error::last_os_error()));
}
if (server_message.msg_type != constants::MESSAGE_INPUT) {
return Err(Error::from(io::Error::other("your message here")));
}
return Ok(unsafe{ server_message.contents.input});

}

pub fn set_refresh_mode(&mut self, refresh_mode: RefreshMode) -> io::Result<()> {
if (self.current_refresh_mode == refresh_mode) {return Ok(())}
let message = ClientMessage {
msg_type: constants::MESSAGE_SET_REFRESH_MODE,
contents: ClientMessageContents {
refresh_mode: refresh_mode as i32,
},
};

match self.send_message(&message) {
Ok(_) => {
self.current_refresh_mode = refresh_mode;
Ok(())
},
Err(e) => Err(e),
}
}
}

impl<'a> Drop for ClientConnection<'a> {
Expand Down
Loading