Compare commits

..
3 Commits
Author SHA1 Message Date
neo 0a73abdbc6 resolving merge conflicts 2026-08-25 20:15:19 +02:00
neo 61cfcf283f declared interfaces and more wrappers 2026-08-25 17:55:57 +02:00
neo aeab2375c8 license SPDX line, implementing first global state 2026-08-25 13:48:33 +02:00
11 changed files with 334 additions and 11 deletions
+6
View File
@@ -2,6 +2,12 @@
name = "wayland_server"
version = "0.1.0"
edition = "2024"
license = "GPL-2.0-only"
keywords = ["ffi", "wayland"]
[[example]]
name = "simple_compd"
path = "examples/simple_compd.rs"
[dependencies]
libc = "*"
+29
View File
@@ -1,9 +1,38 @@
// SPDX: GPL-2.0-only
use std::io;
use wayland_server::client::Client;
use wayland_server::display::Display;
use wayland_server::global::{Global, GlobalState};
use wayland_server::interface::{Interface, Output};
use wayland_server::resource::Resource;
struct State {
output_interface: Interface<Output>,
}
impl State {
pub fn new() -> Self {
Self { output_interface: Interface::<Output>::new() }
}
}
impl GlobalState for State {
fn handle_output_bind(&self, client: &Client, _version: u32, id: u32) -> io::Result<()>{
let resource = Resource::new(&client, id, &self.output_interface)?;
Ok(())
}
}
fn main() -> io::Result<()> {
// Creating a compositor State
let state = State::new();
// create a wayland display
let display = Display::new()?;
// get the global registry
let _global = Global::new(&display, state)?;
println!("Running wayland_display on {}", display.get_name());
display.run()?;
+2
View File
@@ -1,3 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::io::{Error, ErrorKind, Result};
use std::ptr::NonNull;
use crate::ffi::wl_array;
+22
View File
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::io;
use std::ptr::NonNull;
use crate::Wrapper;
use crate::ffi::wl_client;
pub struct Client {
raw: NonNull<wl_client>
}
impl Client {
pub(crate) fn from_raw(raw: *mut wl_client) -> Option<Self> {
NonNull::new(raw).map(| raw| Self { raw })
}
}
impl Wrapper for Client {
type T = wl_client;
fn get_raw(&self) -> std::ptr::NonNull<Self::T> {
self.raw
}
}
+9 -1
View File
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::{io::Error, ptr::NonNull};
use std::io::{ErrorKind, Result};
use crate::Wrapper;
// pull in the ffi-bindings
use crate::ffi::{wl_display,
wl_display_create, wl_display_destroy, wl_display_destroy_clients, wl_display_add_client_created_listener,
@@ -37,7 +40,6 @@ impl<'disp> Display<'disp> {
pub fn get_name(&self) -> &str {
self.name
}
pub fn run(&self) -> Result<()> {
unsafe { wl_display_run(self.raw.as_ptr()) };
Ok(())
@@ -51,3 +53,9 @@ impl<'disp> Drop for Display<'disp> {
}
}
}
impl<'disp> Wrapper for Display<'disp> {
type T = wl_display;
fn get_raw(&self) -> std::ptr::NonNull<Self::T> {
self.raw
}
}
+34 -5
View File
@@ -1,3 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::{ffi::CStr, os::fd::RawFd};
use libc::epoll_event;
@@ -28,7 +30,7 @@ pub(crate) type wl_protocol_logger_func_t = unsafe extern "C" fn(user_data: *mut
#[allow(non_camel_case_types)]
pub(crate) type wl_dispatcher_func_t = unsafe extern "C" fn(user_data: *const libc::c_void, target: *mut libc::c_void, opcode: u32, msg: *const wl_message, args: *mut wl_argument) -> i32;
#[allow(non_camel_case_types)]
pub(crate) type wl_log_func_t = unsafe extern "C" fn(fmt: *const libc::c_char, args: std::ffi::VaList);
pub(crate) type wl_log_func_t = unsafe extern "C" fn(fmt: *const libc::c_char, ...);
// ffi data types and struct
const UNIX_PATH_MAX: usize = 108;
@@ -187,7 +189,7 @@ pub(crate) struct wl_message {
#[allow(non_camel_case_types)]
pub(crate) struct wl_interface {
name: *const libc::c_char,
version: i32,
pub version: i32,
method_count: i32,
method: *const wl_message,
event_count: i32,
@@ -338,6 +340,33 @@ pub(crate) struct wl_shm_pool {
sigbus_is_impossible: bool
}
// public static interfaces
unsafe extern "C" {
pub(crate) unsafe static wl_buffer_interface: wl_interface;
pub(crate) unsafe static wl_callback_interface: wl_interface;
pub(crate) unsafe static wl_compositor_interface: wl_interface;
pub(crate) unsafe static wl_data_device_interface: wl_interface;
pub(crate) unsafe static wl_data_device_manager_interface: wl_interface;
pub(crate) unsafe static wl_data_offer_interface: wl_interface;
pub(crate) unsafe static wl_data_source_interface: wl_interface;
pub(crate) unsafe static wl_display_interface: wl_interface;
pub(crate) unsafe static wl_global_interface: wl_interface;
pub(crate) unsafe static wl_keyboard_interface: wl_interface;
pub(crate) unsafe static wl_output_interface: wl_interface;
pub(crate) unsafe static wl_pointer_interface: wl_interface;
pub(crate) unsafe static wl_region_interface: wl_interface;
pub(crate) unsafe static wl_registry_interface: wl_interface;
pub(crate) unsafe static wl_seat_interface: wl_interface;
pub(crate) unsafe static wl_shell_interface: wl_interface;
pub(crate) unsafe static wl_shell_surface_interface: wl_interface;
pub(crate) unsafe static wl_shm_interface: wl_interface;
pub(crate) unsafe static wl_shm_pool_interface: wl_interface;
pub(crate) unsafe static wl_subcompositor_interface: wl_interface;
pub(crate) unsafe static wl_subsurface_interface: wl_interface;
pub(crate) unsafe static wl_surface_interface: wl_interface;
pub(crate) unsafe static wl_touch_interface: wl_interface;
}
#[link(name = "wayland-server")]
unsafe extern "C" {
pub(crate) unsafe fn wl_array_add(array: *mut wl_array, size: usize) -> *mut libc::c_void;
@@ -406,7 +435,7 @@ unsafe extern "C" {
pub(crate) unsafe fn wl_event_source_remove(source: *mut wl_event_source) -> i32;
pub(crate) unsafe fn wl_event_source_timer_update(source: *mut wl_event_source, ms_delay: i32) -> i32;
pub(crate) unsafe fn wl_global_create(disp: *mut wl_display, interface: *const wl_interface) -> *mut wl_global;
pub(crate) unsafe fn wl_global_create(disp: *mut wl_display, interface: *const wl_interface, version: i32, data: *mut libc::c_void, bind: wl_global_bind_func_t) -> *mut wl_global;
pub(crate) unsafe fn wl_global_destroy(global: *mut wl_global);
pub(crate) unsafe fn wl_global_get_display(global: *const wl_global) -> *mut wl_display;
pub(crate) unsafe fn wl_global_get_interface(global: *const wl_global) -> *const wl_interface;
@@ -416,11 +445,11 @@ unsafe extern "C" {
pub(crate) unsafe fn wl_global_remove(global: *mut wl_global);
pub(crate) unsafe fn wl_global_set_user_data(global: *mut wl_global, data: *mut libc::c_void);
pub(crate) unsafe fn wl_list_empty(list: *const wl_list);
pub(crate) unsafe fn wl_list_empty(list: *const wl_list)->bool;
pub(crate) unsafe fn wl_list_init(list: *mut wl_list);
pub(crate) unsafe fn wl_list_insert(list: *mut wl_list, elm: *mut wl_list);
pub(crate) unsafe fn wl_list_insert_list(list: *mut wl_list, other: *mut wl_list);
pub(crate) unsafe fn wl_list_length(list: *const wl_list);
pub(crate) unsafe fn wl_list_length(list: *const wl_list) -> usize;
pub(crate) unsafe fn wl_list_remove(elm: *mut wl_list);
pub(crate) unsafe fn wl_log_set_handler_server(handler: wl_log_func_t);
+61
View File
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::io;
use std::ptr::NonNull;
use crate::Wrapper;
use crate::client::Client;
use crate::display::Display;
use crate::interface::{Interface,Global as GlobalInterface};
use crate::ffi::{wl_client, wl_global,};
use crate::ffi::wl_global_create;
pub trait GlobalState {
fn handle_output_bind(&self, client: &Client, version: u32, id: u32) -> std::io::Result<()>;
}
unsafe extern "C" fn trampoline_handle_output_bind(client: *mut wl_client, data: *mut libc::c_void, version: u32, id: u32) {
let Some(client) = Client::from_raw(client) else {
return;
};
let holder = unsafe { &*(data as *const GlobalStateHolder) };
let _ = holder.state.handle_output_bind(&client, version, id);
}
struct GlobalStateHolder {
state: Box<dyn GlobalState>,
}
pub struct Global {
raw: NonNull<wl_global>,
state: Box<GlobalStateHolder>,
}
impl Global
{
pub fn new<S>(disp: &Display, state: S) -> io::Result<Self>
where
S: GlobalState + 'static,
{
let state = Box::new(GlobalStateHolder { state: Box::new(state) });
let data = state.as_ref() as *const GlobalStateHolder as *mut libc::c_void;
let interface = Interface::<GlobalInterface>::new();
let ptr = unsafe {
wl_global_create(disp.as_raw_ptr(),
interface.get_raw().as_ptr(),
1,
data,
trampoline_handle_output_bind
)
};
let raw = NonNull::new(ptr)
.ok_or_else(||io::Error::last_os_error())?;
Ok(Self{raw,state})
}
}
impl Wrapper for Global {
type T = wl_global;
fn get_raw(&self) -> std::ptr::NonNull<Self::T> {
self.raw
}
}
+64
View File
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::io;
use std::marker::PhantomData;
use std::ptr::{addr_of,NonNull};
use crate::Wrapper;
use crate::ffi::{wl_buffer_interface, wl_callback_interface, wl_compositor_interface, wl_data_device_interface, wl_data_device_manager_interface, wl_data_offer_interface, wl_data_source_interface, wl_display_interface, wl_global_interface, wl_interface, wl_keyboard_interface, wl_output_interface, wl_pointer_interface, wl_region_interface, wl_registry_interface, wl_seat_interface, wl_shell_interface, wl_shell_surface_interface, wl_shm_interface, wl_shm_pool_interface, wl_subcompositor_interface, wl_subsurface_interface, wl_surface_interface, wl_touch_interface};
pub trait WaylandInterface {
fn raw_interface() -> NonNull<wl_interface>;
}
macro_rules! define_interface {
($name:ident, $raw:ident) => {
pub struct $name;
impl WaylandInterface for $name {
#[inline]
fn raw_interface() -> NonNull<wl_interface> {
unsafe { NonNull::from(&$raw) }
}
}
};
}
// defining wayland interfaces
define_interface!(Buffer, wl_buffer_interface);
define_interface!(Calback, wl_callback_interface);
define_interface!(Compositor, wl_compositor_interface);
define_interface!(DataDevice, wl_data_device_interface);
define_interface!(DataDeviceManager, wl_data_device_manager_interface);
define_interface!(DataOffer, wl_data_offer_interface);
define_interface!(DataSource, wl_data_source_interface);
define_interface!(Display, wl_display_interface);
define_interface!(Global, wl_global_interface);
define_interface!(Keyboard, wl_keyboard_interface);
define_interface!(Output, wl_output_interface);
define_interface!(Pointer, wl_pointer_interface);
define_interface!(Region, wl_region_interface);
define_interface!(Registry, wl_registry_interface);
define_interface!(Seat, wl_seat_interface);
define_interface!(Shell, wl_shell_interface);
define_interface!(ShellSurface, wl_shell_surface_interface);
define_interface!(Shm, wl_shm_interface);
define_interface!(ShmPool, wl_shm_pool_interface);
define_interface!(Subcompositor, wl_subcompositor_interface);
define_interface!(Subsurface, wl_subsurface_interface);
define_interface!(Surface, wl_surface_interface);
define_interface!(Touch, wl_touch_interface);
pub struct Interface<T: WaylandInterface> {
_marker: PhantomData<T>
}
impl<T: WaylandInterface> Interface<T> {
pub const fn new() -> Self {
Self {
_marker: PhantomData
}
}
pub(crate) fn get_raw(&self) -> NonNull<wl_interface> {
T::raw_interface()
}
}
+15 -1
View File
@@ -1,7 +1,21 @@
#![feature(c_variadic)]
// SPDX-License-Identifier: GPL-2.0-only
pub(crate) mod ffi;
// public api
pub mod array;
pub mod client;
pub mod display;
pub mod global;
pub mod interface;
pub mod list;
pub mod resource;
pub(crate) trait Wrapper {
type T;
fn get_raw(&self) -> std::ptr::NonNull<Self::T>;
fn as_raw_ptr(&self) -> *mut Self::T {
self.get_raw().as_ptr()
}
}
+49
View File
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::io;
use std::ptr::NonNull;
use crate::Wrapper;
use crate::ffi::wl_list;
use crate::ffi::{
wl_list_init, wl_list_insert, wl_list_insert_list,
wl_list_empty, wl_list_length, wl_list_remove,
};
pub struct List {
raw: NonNull<wl_list>,
}
impl List {
pub fn new() -> io::Result<Self> {
let list = std::ptr::null_mut();
unsafe { wl_list_init(list) };
let Some(raw) = NonNull::new(list) else {
return Err(io::Error::last_os_error());
};
Ok(Self { raw })
}
pub fn insert(&self, elm: &List) {
unsafe { wl_list_insert(self.as_raw_ptr(), elm.as_raw_ptr()) };
}
pub fn insert_list(&self, other: &List) {
unsafe { wl_list_insert_list(self.as_raw_ptr(), other.as_raw_ptr()) };
}
pub fn length(&self) -> usize {
let length = unsafe { wl_list_length(self.as_raw_ptr())};
length
}
pub fn empty(&self) -> bool {
let ret: bool = unsafe { wl_list_empty(self.as_raw_ptr()) };
ret
}
pub fn remove(&self, elm: &List) {
unsafe { wl_list_remove(elm.as_raw_ptr()) };
}
}
impl Wrapper for List {
type T = wl_list;
fn get_raw(&self) -> std::ptr::NonNull<Self::T> {
self.raw
}
}
+39
View File
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-only
use std::io;
use std::ptr::NonNull;
use crate::Wrapper;
use crate::client::Client;
use crate::ffi::{wl_resource, wl_resource_create,wl_interface};
use crate::interface::{WaylandInterface,Interface};
pub struct Resource {
raw: NonNull<wl_resource>,
}
impl Resource {
pub(crate) fn from_raw(raw: *mut wl_resource) -> Option<Self> {
NonNull::new(raw).map(| raw| Self { raw })
}
pub fn new<I: WaylandInterface>(client: &Client, id: u32, interface: &Interface<I>) -> io::Result<Self> {
let ptr = unsafe { wl_resource_create(
client.as_raw_ptr(),
interface.get_raw().as_ptr(),
interface.get_raw().read().version,
id
)};
let Some(raw) = NonNull::new(ptr) else {
return Err(io::Error::last_os_error());
};
Ok(Self { raw })
}
}
impl Wrapper for Resource {
type T = wl_resource;
fn get_raw(&self) -> std::ptr::NonNull<Self::T> {
self.raw
}
}