Main structure of WLCS integration.
This commit is contained in:
parent
56c3f53575
commit
bdb257474d
|
@ -8,7 +8,7 @@ repository = "https://github.com/Smithay/smithay"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [ "anvil" ]
|
members = [ "anvil", "wlcs_anvil" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
appendlist = "1.4"
|
appendlist = "1.4"
|
||||||
|
|
|
@ -29,7 +29,7 @@ use crate::shell::init_shell;
|
||||||
|
|
||||||
pub struct AnvilState<BackendData> {
|
pub struct AnvilState<BackendData> {
|
||||||
pub backend_data: BackendData,
|
pub backend_data: BackendData,
|
||||||
pub socket_name: String,
|
pub socket_name: Option<String>,
|
||||||
pub running: Arc<AtomicBool>,
|
pub running: Arc<AtomicBool>,
|
||||||
pub display: Rc<RefCell<Display>>,
|
pub display: Rc<RefCell<Display>>,
|
||||||
pub handle: LoopHandle<'static, AnvilState<BackendData>>,
|
pub handle: LoopHandle<'static, AnvilState<BackendData>>,
|
||||||
|
@ -57,6 +57,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
|
||||||
handle: LoopHandle<'static, AnvilState<BackendData>>,
|
handle: LoopHandle<'static, AnvilState<BackendData>>,
|
||||||
backend_data: BackendData,
|
backend_data: BackendData,
|
||||||
log: slog::Logger,
|
log: slog::Logger,
|
||||||
|
listen_on_socket: bool,
|
||||||
) -> AnvilState<BackendData> {
|
) -> AnvilState<BackendData> {
|
||||||
// init the wayland connection
|
// init the wayland connection
|
||||||
handle
|
handle
|
||||||
|
@ -85,6 +86,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
|
||||||
|
|
||||||
init_xdg_output_manager(&mut display.borrow_mut(), log.clone());
|
init_xdg_output_manager(&mut display.borrow_mut(), log.clone());
|
||||||
|
|
||||||
|
let socket_name = if listen_on_socket {
|
||||||
let socket_name = display
|
let socket_name = display
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.add_socket_auto()
|
.add_socket_auto()
|
||||||
|
@ -93,6 +95,10 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
info!(log, "Listening on wayland socket"; "name" => socket_name.clone());
|
info!(log, "Listening on wayland socket"; "name" => socket_name.clone());
|
||||||
::std::env::set_var("WAYLAND_DISPLAY", &socket_name);
|
::std::env::set_var("WAYLAND_DISPLAY", &socket_name);
|
||||||
|
Some(socket_name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// init data device
|
// init data device
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub fn run_udev(log: Logger) {
|
||||||
pointer_image: crate::cursor::Cursor::load(&log),
|
pointer_image: crate::cursor::Cursor::load(&log),
|
||||||
render_timer: timer.handle(),
|
render_timer: timer.handle(),
|
||||||
};
|
};
|
||||||
let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone());
|
let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone(), true);
|
||||||
|
|
||||||
// re-render timer
|
// re-render timer
|
||||||
event_loop
|
event_loop
|
||||||
|
|
|
@ -94,7 +94,7 @@ pub fn run_winit(log: Logger) {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
fps: fps_ticker::Fps::default(),
|
fps: fps_ticker::Fps::default(),
|
||||||
};
|
};
|
||||||
let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone());
|
let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone(), true);
|
||||||
|
|
||||||
let mode = Mode {
|
let mode = Mode {
|
||||||
size,
|
size,
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "wlcs_anvil"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Victor Berger <victor.berger@m4x.org>", "Drakulix (Victor Brekenfeld)"]
|
||||||
|
license = "MIT"
|
||||||
|
publish = false
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
smithay = { path = "..", default-features=false, features=["wayland_frontend"] }
|
||||||
|
anvil = { path = "../anvil", default-features=false }
|
||||||
|
wayland-sys = { version = "0.28.6", features=["client"] }
|
||||||
|
libc = "0.2"
|
||||||
|
memoffset = "0.6"
|
||||||
|
slog = "2.0"
|
||||||
|
cgmath = "0.18"
|
||||||
|
nix = "0.20"
|
|
@ -0,0 +1,71 @@
|
||||||
|
use std::os::raw::{c_char, c_int};
|
||||||
|
|
||||||
|
use smithay::reexports::wayland_server::sys::server as ssys;
|
||||||
|
use wayland_sys::{client::*, common::wl_fixed_t};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WlcsExtensionDescriptor {
|
||||||
|
pub name: *const c_char,
|
||||||
|
pub version: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for WlcsExtensionDescriptor {}
|
||||||
|
unsafe impl Send for WlcsExtensionDescriptor {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WlcsIntegrationDescriptor {
|
||||||
|
pub version: u32,
|
||||||
|
pub num_extensions: usize,
|
||||||
|
pub supported_extensions: *const WlcsExtensionDescriptor,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for WlcsIntegrationDescriptor {}
|
||||||
|
unsafe impl Send for WlcsIntegrationDescriptor {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WlcsDisplayServer {
|
||||||
|
pub version: u32,
|
||||||
|
pub start: unsafe extern "C" fn(*mut WlcsDisplayServer),
|
||||||
|
pub stop: unsafe extern "C" fn(*mut WlcsDisplayServer),
|
||||||
|
pub create_client_socket: unsafe extern "C" fn(*mut WlcsDisplayServer) -> c_int,
|
||||||
|
pub position_window_absolute:
|
||||||
|
unsafe extern "C" fn(*mut WlcsDisplayServer, *mut wl_display, *mut wl_proxy, c_int, c_int),
|
||||||
|
pub create_pointer: unsafe extern "C" fn(*mut WlcsDisplayServer) -> *mut WlcsPointer,
|
||||||
|
pub create_touch: unsafe extern "C" fn(*mut WlcsDisplayServer) -> *mut WlcsTouch,
|
||||||
|
pub get_descriptor: unsafe extern "C" fn(*const WlcsDisplayServer) -> *const WlcsIntegrationDescriptor,
|
||||||
|
pub start_on_this_thread: Option<unsafe extern "C" fn(*mut WlcsDisplayServer, *mut ssys::wl_event_loop)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WlcsServerIntegration {
|
||||||
|
pub version: u32,
|
||||||
|
pub create_server: unsafe extern "C" fn(c_int, *mut *const c_char) -> *mut WlcsDisplayServer,
|
||||||
|
pub destroy_server: unsafe extern "C" fn(*mut WlcsDisplayServer),
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WlcsPointer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WlcsPointer {
|
||||||
|
pub version: u32,
|
||||||
|
pub move_absolute: unsafe extern "C" fn(*mut WlcsPointer, wl_fixed_t, wl_fixed_t),
|
||||||
|
pub move_relative: unsafe extern "C" fn(*mut WlcsPointer, wl_fixed_t, wl_fixed_t),
|
||||||
|
pub button_up: unsafe extern "C" fn(*mut WlcsPointer, c_int),
|
||||||
|
pub button_down: unsafe extern "C" fn(*mut WlcsPointer, c_int),
|
||||||
|
pub destroy: unsafe extern "C" fn(*mut WlcsPointer),
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WlcsTouch
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WlcsTouch {
|
||||||
|
pub version: u32,
|
||||||
|
pub touch_down: unsafe extern "C" fn(*mut WlcsTouch, wl_fixed_t, wl_fixed_t),
|
||||||
|
pub touch_move: unsafe extern "C" fn(*mut WlcsTouch, wl_fixed_t, wl_fixed_t),
|
||||||
|
pub touch_up: unsafe extern "C" fn(*mut WlcsTouch),
|
||||||
|
pub destroy: unsafe extern "C" fn(*mut WlcsTouch),
|
||||||
|
}
|
|
@ -0,0 +1,261 @@
|
||||||
|
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),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
mod ffi_api;
|
||||||
|
mod ffi_wrappers;
|
||||||
|
mod main_loop;
|
||||||
|
mod renderer;
|
||||||
|
|
||||||
|
use std::{os::unix::net::UnixStream, thread::JoinHandle};
|
||||||
|
|
||||||
|
use smithay::reexports::calloop;
|
||||||
|
|
||||||
|
use ffi_api::{WlcsExtensionDescriptor, WlcsIntegrationDescriptor};
|
||||||
|
|
||||||
|
macro_rules! extension_list {
|
||||||
|
($(($name: expr, $version: expr)),* $(,)?) => {
|
||||||
|
&[$(
|
||||||
|
WlcsExtensionDescriptor {
|
||||||
|
name: concat!($name, "\0").as_ptr() as *const std::os::raw::c_char,
|
||||||
|
version: $version
|
||||||
|
}
|
||||||
|
),*]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SUPPORTED_EXTENSIONS: &[WlcsExtensionDescriptor] = extension_list!(
|
||||||
|
("wl_compositor", 4),
|
||||||
|
("wl_subcompositor", 1),
|
||||||
|
("wl_data_device_manager", 3),
|
||||||
|
("wl_shell", 1),
|
||||||
|
("wl_seat", 5),
|
||||||
|
("wl_output", 3),
|
||||||
|
("xdg_wm_base", 1),
|
||||||
|
);
|
||||||
|
|
||||||
|
static DESCRIPTOR: WlcsIntegrationDescriptor = WlcsIntegrationDescriptor {
|
||||||
|
version: 1,
|
||||||
|
num_extensions: SUPPORTED_EXTENSIONS.len(),
|
||||||
|
supported_extensions: SUPPORTED_EXTENSIONS.as_ptr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Event sent by WLCS to control the compositor
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WlcsEvent {
|
||||||
|
/// Stop the running server
|
||||||
|
Exit,
|
||||||
|
/// Create a new client from given RawFd
|
||||||
|
NewClient {
|
||||||
|
stream: UnixStream,
|
||||||
|
client_id: i32,
|
||||||
|
},
|
||||||
|
/// Position this window from the client associated with this Fd on the global space
|
||||||
|
PositionWindow {
|
||||||
|
client_id: i32,
|
||||||
|
surface_id: u32,
|
||||||
|
location: (i32, i32),
|
||||||
|
},
|
||||||
|
/* Pointer related events */
|
||||||
|
/// A new pointer device is available
|
||||||
|
NewPointer {
|
||||||
|
device_id: u32,
|
||||||
|
},
|
||||||
|
/// Move the pointer in absolute coordinate space
|
||||||
|
PointerMoveAbsolute {
|
||||||
|
device_id: u32,
|
||||||
|
location: (f64, f64),
|
||||||
|
},
|
||||||
|
/// Move the pointer in relative coordinate space
|
||||||
|
PointerMoveRelative {
|
||||||
|
device_id: u32,
|
||||||
|
delta: (f64, f64),
|
||||||
|
},
|
||||||
|
/// Press a pointer button
|
||||||
|
PointerButtonDown {
|
||||||
|
device_id: u32,
|
||||||
|
button_id: i32,
|
||||||
|
},
|
||||||
|
/// Release a pointer button
|
||||||
|
PointerButtonUp {
|
||||||
|
device_id: u32,
|
||||||
|
button_id: i32,
|
||||||
|
},
|
||||||
|
/// A pointer device is removed
|
||||||
|
PointerRemoved {
|
||||||
|
device_id: u32,
|
||||||
|
},
|
||||||
|
/* Touch related events */
|
||||||
|
/// A new touch device is available
|
||||||
|
NewTouch {
|
||||||
|
device_id: u32,
|
||||||
|
},
|
||||||
|
/// A touch point is down
|
||||||
|
TouchDown {
|
||||||
|
device_id: u32,
|
||||||
|
location: (f64, f64),
|
||||||
|
},
|
||||||
|
/// A touch point moved
|
||||||
|
TouchMove {
|
||||||
|
device_id: u32,
|
||||||
|
location: (f64, f64),
|
||||||
|
},
|
||||||
|
/// A touch point is up
|
||||||
|
TouchUp {
|
||||||
|
device_id: u32,
|
||||||
|
},
|
||||||
|
TouchRemoved {
|
||||||
|
device_id: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_anvil(channel: calloop::channel::Channel<WlcsEvent>) -> JoinHandle<()> {
|
||||||
|
std::thread::spawn(move || main_loop::run(channel))
|
||||||
|
}
|
|
@ -0,0 +1,195 @@
|
||||||
|
use std::{
|
||||||
|
cell::RefCell, collections::HashMap, os::unix::prelude::IntoRawFd, rc::Rc, sync::atomic::Ordering,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use smithay::{
|
||||||
|
backend::{
|
||||||
|
renderer::{Frame, Renderer, Transform},
|
||||||
|
SwapBuffersError,
|
||||||
|
},
|
||||||
|
reexports::{
|
||||||
|
calloop::{
|
||||||
|
channel::{Channel, Event as ChannelEvent},
|
||||||
|
EventLoop,
|
||||||
|
},
|
||||||
|
wayland_server::{protocol::wl_output, Client, Display},
|
||||||
|
},
|
||||||
|
wayland::{
|
||||||
|
output::{Mode, PhysicalProperties},
|
||||||
|
seat::CursorImageStatus,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anvil::{
|
||||||
|
drawing::{draw_cursor, draw_dnd_icon, draw_windows},
|
||||||
|
state::Backend,
|
||||||
|
AnvilState,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::WlcsEvent;
|
||||||
|
|
||||||
|
pub const OUTPUT_NAME: &str = "anvil";
|
||||||
|
|
||||||
|
struct TestState {
|
||||||
|
clients: HashMap<i32, Client>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backend for TestState {
|
||||||
|
fn seat_name(&self) -> String {
|
||||||
|
"anvil_wlcs".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(channel: Channel<WlcsEvent>) {
|
||||||
|
let mut event_loop =
|
||||||
|
EventLoop::<AnvilState<TestState>>::try_new().expect("Failed to init the event loop.");
|
||||||
|
|
||||||
|
let display = Rc::new(RefCell::new(Display::new()));
|
||||||
|
|
||||||
|
let logger = slog::Logger::root(slog::Discard, slog::o!());
|
||||||
|
|
||||||
|
let test_state = TestState {
|
||||||
|
clients: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut state = AnvilState::init(
|
||||||
|
display.clone(),
|
||||||
|
event_loop.handle(),
|
||||||
|
test_state,
|
||||||
|
logger.clone(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
event_loop
|
||||||
|
.handle()
|
||||||
|
.insert_source(channel, move |event, &mut (), state| match event {
|
||||||
|
ChannelEvent::Msg(evt) => handle_event(evt, state),
|
||||||
|
ChannelEvent::Closed => handle_event(WlcsEvent::Exit, state),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut renderer = crate::renderer::DummyRenderer::new();
|
||||||
|
|
||||||
|
let mode = Mode {
|
||||||
|
size: (800, 600).into(),
|
||||||
|
refresh: 60_000,
|
||||||
|
};
|
||||||
|
|
||||||
|
state.output_map.borrow_mut().add(
|
||||||
|
OUTPUT_NAME,
|
||||||
|
PhysicalProperties {
|
||||||
|
size: (0, 0).into(),
|
||||||
|
subpixel: wl_output::Subpixel::Unknown,
|
||||||
|
make: "Smithay".into(),
|
||||||
|
model: "Winit".into(),
|
||||||
|
},
|
||||||
|
mode,
|
||||||
|
);
|
||||||
|
|
||||||
|
while state.running.load(Ordering::SeqCst) {
|
||||||
|
// pretend to draw something
|
||||||
|
{
|
||||||
|
let output_geometry = state
|
||||||
|
.output_map
|
||||||
|
.borrow()
|
||||||
|
.find_by_name(OUTPUT_NAME)
|
||||||
|
.unwrap()
|
||||||
|
.geometry();
|
||||||
|
|
||||||
|
renderer
|
||||||
|
.render((800, 600).into(), Transform::Normal, |renderer, frame| {
|
||||||
|
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||||
|
|
||||||
|
// draw the windows
|
||||||
|
draw_windows(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
&*state.window_map.borrow(),
|
||||||
|
output_geometry,
|
||||||
|
1.0,
|
||||||
|
&logger,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// draw the dnd icon if any
|
||||||
|
{
|
||||||
|
let guard = state.dnd_icon.lock().unwrap();
|
||||||
|
if let Some(ref surface) = *guard {
|
||||||
|
if surface.as_ref().is_alive() {
|
||||||
|
draw_dnd_icon(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
surface,
|
||||||
|
state.pointer_location.to_i32_floor(),
|
||||||
|
1.0,
|
||||||
|
&logger,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// draw the cursor as relevant
|
||||||
|
{
|
||||||
|
let mut guard = state.cursor_status.lock().unwrap();
|
||||||
|
// reset the cursor if the surface is no longer alive
|
||||||
|
let mut reset = false;
|
||||||
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
|
reset = !surface.as_ref().is_alive();
|
||||||
|
}
|
||||||
|
if reset {
|
||||||
|
*guard = CursorImageStatus::Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw as relevant
|
||||||
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
|
draw_cursor(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
surface,
|
||||||
|
state.pointer_location.to_i32_floor(),
|
||||||
|
1.0,
|
||||||
|
&logger,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
|
.and_then(|x| x)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send frame events so that client start drawing their next frame
|
||||||
|
state
|
||||||
|
.window_map
|
||||||
|
.borrow()
|
||||||
|
.send_frames(state.start_time.elapsed().as_millis() as u32);
|
||||||
|
display.borrow_mut().flush_clients(&mut state);
|
||||||
|
|
||||||
|
if event_loop
|
||||||
|
.dispatch(Some(Duration::from_millis(16)), &mut state)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
state.running.store(false, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
display.borrow_mut().flush_clients(&mut state);
|
||||||
|
state.window_map.borrow_mut().refresh();
|
||||||
|
state.output_map.borrow_mut().refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(event: WlcsEvent, state: &mut AnvilState<TestState>) {
|
||||||
|
match event {
|
||||||
|
WlcsEvent::Exit => state.running.store(false, Ordering::SeqCst),
|
||||||
|
WlcsEvent::NewClient { stream, client_id } => {
|
||||||
|
let display = state.display.clone();
|
||||||
|
let client = unsafe { display.borrow_mut().create_client(stream.into_raw_fd(), state) };
|
||||||
|
state.backend_data.clients.insert(client_id, client);
|
||||||
|
}
|
||||||
|
e => {
|
||||||
|
// TODO: handle the actual events
|
||||||
|
eprintln!("Unhandled event: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
use cgmath::Vector2;
|
||||||
|
use smithay::{
|
||||||
|
backend::{
|
||||||
|
allocator::dmabuf::Dmabuf,
|
||||||
|
renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, Transform},
|
||||||
|
SwapBuffersError,
|
||||||
|
},
|
||||||
|
reexports::wayland_server::protocol::wl_buffer,
|
||||||
|
utils::{Buffer, Physical, Rectangle, Size},
|
||||||
|
wayland::compositor::SurfaceData,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct DummyRenderer {}
|
||||||
|
|
||||||
|
impl DummyRenderer {
|
||||||
|
pub fn new() -> DummyRenderer {
|
||||||
|
DummyRenderer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer for DummyRenderer {
|
||||||
|
type Error = SwapBuffersError;
|
||||||
|
type TextureId = DummyTexture;
|
||||||
|
type Frame = DummyFrame;
|
||||||
|
|
||||||
|
fn render<F, R>(
|
||||||
|
&mut self,
|
||||||
|
_size: Size<i32, Physical>,
|
||||||
|
_transform: Transform,
|
||||||
|
rendering: F,
|
||||||
|
) -> Result<R, Self::Error>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self, &mut Self::Frame) -> R,
|
||||||
|
{
|
||||||
|
let mut frame = DummyFrame {};
|
||||||
|
Ok(rendering(self, &mut frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportShm for DummyRenderer {
|
||||||
|
fn import_shm_buffer(
|
||||||
|
&mut self,
|
||||||
|
buffer: &wl_buffer::WlBuffer,
|
||||||
|
surface: Option<&SurfaceData>,
|
||||||
|
_damage: &[Rectangle<i32, Buffer>],
|
||||||
|
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
|
||||||
|
use smithay::wayland::shm::with_buffer_contents;
|
||||||
|
let ret = with_buffer_contents(&buffer, |slice, data| {
|
||||||
|
let offset = data.offset as u32;
|
||||||
|
let width = data.width as u32;
|
||||||
|
let height = data.height as u32;
|
||||||
|
let stride = data.stride as u32;
|
||||||
|
|
||||||
|
let mut x = 0;
|
||||||
|
for h in 0..height {
|
||||||
|
for w in 0..width {
|
||||||
|
x |= slice[(offset + w + h * stride) as usize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(data) = surface {
|
||||||
|
data.data_map.insert_if_missing(|| Cell::new(0u8));
|
||||||
|
data.data_map.get::<Cell<u8>>().unwrap().set(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
(width, height)
|
||||||
|
});
|
||||||
|
|
||||||
|
match ret {
|
||||||
|
Ok((width, height)) => Ok(DummyTexture { width, height }),
|
||||||
|
Err(e) => Err(SwapBuffersError::TemporaryFailure(Box::new(e))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportDma for DummyRenderer {
|
||||||
|
fn import_dmabuf(
|
||||||
|
&mut self,
|
||||||
|
_dmabuf: &Dmabuf,
|
||||||
|
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DummyFrame {}
|
||||||
|
|
||||||
|
impl Frame for DummyFrame {
|
||||||
|
type Error = SwapBuffersError;
|
||||||
|
type TextureId = DummyTexture;
|
||||||
|
|
||||||
|
fn clear(&mut self, _color: [f32; 4]) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_texture(
|
||||||
|
&mut self,
|
||||||
|
_texture: &Self::TextureId,
|
||||||
|
_matrix: cgmath::Matrix3<f32>,
|
||||||
|
tex_coords: [Vector2<f32>; 4],
|
||||||
|
_alpha: f32,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DummyTexture {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Texture for DummyTexture {
|
||||||
|
fn width(&self) -> u32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> u32 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue