use super::{GliumDrawer, WindowMap}; use smithay::backend::graphics::egl::wayland::{Format, BufferAccessError}; use glium::texture::Texture2d; use rand; use smithay::backend::graphics::egl::{EGLGraphicsBackend, EGLImages}; use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceUserImplementation}; use smithay::wayland::shell::{shell_init, PopupConfigure, ShellState, ShellSurfaceRole, ShellSurfaceUserImplementation, ToplevelConfigure}; use smithay::wayland::shm::with_buffer_contents as shm_buffer_contents; use std::cell::RefCell; use std::rc::Rc; use std::borrow::Borrow; use wayland_server::{EventLoop, StateToken}; define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] ); #[derive(Default)] pub struct SurfaceData { pub buffer: Option, pub texture: Option, } pub enum Buffer { Egl { images: EGLImages }, Shm { data: Vec, size: (u32, u32) }, } unsafe impl Send for Buffer {} pub fn surface_implementation() -> SurfaceUserImplementation>> { SurfaceUserImplementation { commit: |_, drawer, surface, token| { // we retrieve the contents of the associated buffer and copy it token.with_surface_data(surface, |attributes| { match attributes.buffer.take() { Some(Some((buffer, (_x, _y)))) => { // we ignore hotspot coordinates in this simple example match as Borrow>::borrow(&**drawer).egl_buffer_contents(buffer) { Ok(images) => { let format = match images.format { Format::RGB => {}, Format::RGBA => {}, _ => { // we don't handle the more complex formats here. attributes.user_data.buffer = None; attributes.user_data.texture = None; return; }, }; attributes.user_data.texture = drawer.texture_from_egl(&images); attributes.user_data.buffer = Some(Buffer::Egl { images }); }, Err(BufferAccessError::NotManaged(buffer)) => { shm_buffer_contents(&buffer, |slice, data| { let offset = data.offset as usize; let stride = data.stride as usize; let width = data.width as usize; let height = data.height as usize; let mut new_vec = Vec::with_capacity(width * height * 4); for i in 0..height { new_vec .extend(&slice[(offset + i * stride)..(offset + i * stride + width * 4)]); } attributes.user_data.texture = Some(drawer.texture_from_mem(&new_vec, (data.width as u32, data.height as u32))); attributes.user_data.buffer = Some(Buffer::Shm { data: new_vec, size: (data.width as u32, data.height as u32) }); }).unwrap(); buffer.release(); }, Err(err) => panic!("EGL error: {}", err), } } Some(None) => { // erase the contents attributes.user_data.buffer = None; attributes.user_data.texture = None; } None => {} } }); }, frame: |_, _, _, callback, _| { callback.done(0); }, } } pub struct ShellIData { pub token: CompositorToken>>, pub window_map: Rc>, (), F>>>, } pub fn shell_implementation() -> ShellSurfaceUserImplementation>, ShellIData, ()> where F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>, G: EGLGraphicsBackend + 'static, { ShellSurfaceUserImplementation { new_client: |_, _, _| {}, client_pong: |_, _, _| {}, new_toplevel: |_, idata, toplevel| { // place the window at a random location in the [0;300]x[0;300] square use rand::distributions::{IndependentSample, Range}; let range = Range::new(0, 300); let mut rng = rand::thread_rng(); let x = range.ind_sample(&mut rng); let y = range.ind_sample(&mut rng); idata.window_map.borrow_mut().insert(toplevel, (x, y)); ToplevelConfigure { size: None, states: vec![], serial: 42, } }, new_popup: |_, _, _| { PopupConfigure { size: (10, 10), position: (10, 10), serial: 42, } }, move_: |_, _, _, _, _| {}, resize: |_, _, _, _, _, _| {}, grab: |_, _, _, _, _| {}, change_display_state: |_, _, _, _, _, _, _| { ToplevelConfigure { size: None, states: vec![], serial: 42, } }, show_window_menu: |_, _, _, _, _, _, _| {}, } } fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> { attrs .user_data .buffer .as_ref() .map(|ref buffer| match **buffer { Buffer::Shm { ref size, .. } => *size, Buffer::Egl { ref images } => (images.width, images.height), }) .map(|(x, y)| (x as i32, y as i32)) } pub type MyWindowMap = WindowMap< SurfaceData, Roles, Rc>, (), fn(&SurfaceAttributes) -> Option<(i32, i32)>, >; pub fn init_shell( evl: &mut EventLoop, log: ::slog::Logger, data: Rc>) -> ( CompositorToken>>, StateToken>, ()>>, Rc>>, ) { let (compositor_token, _, _) = compositor_init(evl, surface_implementation(), data, log.clone()); let window_map = Rc::new(RefCell::new(WindowMap::<_, _, _, (), _>::new( compositor_token, get_size as _, ))); let (shell_state_token, _, _) = shell_init( evl, compositor_token, shell_implementation(), ShellIData { token: compositor_token, window_map: window_map.clone(), }, log.clone(), ); (compositor_token, shell_state_token, window_map) }