diff --git a/Cargo.toml b/Cargo.toml index d14ae5f..126f98d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/Smithay/smithay" edition = "2018" [workspace] -members = [ "anvil" ] +members = [ "anvil", "wlcs_anvil" ] [dependencies] appendlist = "1.4" diff --git a/anvil/src/state.rs b/anvil/src/state.rs index 4e032a9..ee6f9cd 100644 --- a/anvil/src/state.rs +++ b/anvil/src/state.rs @@ -29,7 +29,7 @@ use crate::shell::init_shell; pub struct AnvilState { pub backend_data: BackendData, - pub socket_name: String, + pub socket_name: Option, pub running: Arc, pub display: Rc>, pub handle: LoopHandle<'static, AnvilState>, @@ -57,6 +57,7 @@ impl AnvilState { handle: LoopHandle<'static, AnvilState>, backend_data: BackendData, log: slog::Logger, + listen_on_socket: bool, ) -> AnvilState { // init the wayland connection handle @@ -85,14 +86,19 @@ impl AnvilState { init_xdg_output_manager(&mut display.borrow_mut(), log.clone()); - let socket_name = display - .borrow_mut() - .add_socket_auto() - .unwrap() - .into_string() - .unwrap(); - info!(log, "Listening on wayland socket"; "name" => socket_name.clone()); - ::std::env::set_var("WAYLAND_DISPLAY", &socket_name); + let socket_name = if listen_on_socket { + let socket_name = display + .borrow_mut() + .add_socket_auto() + .unwrap() + .into_string() + .unwrap(); + info!(log, "Listening on wayland socket"; "name" => socket_name.clone()); + ::std::env::set_var("WAYLAND_DISPLAY", &socket_name); + Some(socket_name) + } else { + None + }; // init data device diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 7049661..253f955 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -142,7 +142,7 @@ pub fn run_udev(log: Logger) { pointer_image: crate::cursor::Cursor::load(&log), 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 event_loop diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 72c6a3b..e1b9f09 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -94,7 +94,7 @@ pub fn run_winit(log: Logger) { #[cfg(feature = "debug")] 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 { size, diff --git a/wlcs_anvil/Cargo.toml b/wlcs_anvil/Cargo.toml new file mode 100644 index 0000000..bc7ad65 --- /dev/null +++ b/wlcs_anvil/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "wlcs_anvil" +version = "0.0.1" +authors = ["Victor Berger ", "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" \ No newline at end of file diff --git a/wlcs_anvil/src/ffi_api.rs b/wlcs_anvil/src/ffi_api.rs new file mode 100644 index 0000000..b86d298 --- /dev/null +++ b/wlcs_anvil/src/ffi_api.rs @@ -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, +} + +#[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), +} diff --git a/wlcs_anvil/src/ffi_wrappers.rs b/wlcs_anvil/src/ffi_wrappers.rs new file mode 100644 index 0000000..3dc7efc --- /dev/null +++ b/wlcs_anvil/src/ffi_wrappers.rs @@ -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, 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, +} + +impl PointerHandle { + fn new(device_id: u32, sender: Sender) -> 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, +} + +impl TouchHandle { + fn new(device_id: u32, sender: Sender) -> 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)); + } +} diff --git a/wlcs_anvil/src/lib.rs b/wlcs_anvil/src/lib.rs new file mode 100644 index 0000000..fd89cf0 --- /dev/null +++ b/wlcs_anvil/src/lib.rs @@ -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) -> JoinHandle<()> { + std::thread::spawn(move || main_loop::run(channel)) +} diff --git a/wlcs_anvil/src/main_loop.rs b/wlcs_anvil/src/main_loop.rs new file mode 100644 index 0000000..11c805b --- /dev/null +++ b/wlcs_anvil/src/main_loop.rs @@ -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, +} + +impl Backend for TestState { + fn seat_name(&self) -> String { + "anvil_wlcs".into() + } +} + +pub fn run(channel: Channel) { + let mut event_loop = + EventLoop::>::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::::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) { + 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); + } + } +} diff --git a/wlcs_anvil/src/renderer.rs b/wlcs_anvil/src/renderer.rs new file mode 100644 index 0000000..6901811 --- /dev/null +++ b/wlcs_anvil/src/renderer.rs @@ -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( + &mut self, + _size: Size, + _transform: Transform, + rendering: F, + ) -> Result + 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], + ) -> Result<::TextureId, ::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::>().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<::TextureId, ::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, + tex_coords: [Vector2; 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 + } +}