diff --git a/Cargo.toml b/Cargo.toml index da14c56..9687e9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ members = [ "anvil" ] [dependencies] bitflags = "1" -calloop = {version = "0.8.0" } +calloop = "0.8.0" cgmath = "0.18.0" dbus = { version = "0.9.0", optional = true } drm-fourcc = "^2.1.1" diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index e05fcb6..a62e235 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -1,9 +1,7 @@ use std::{process::Command, sync::atomic::Ordering}; -use crate::AnvilState; +use crate::{udev::UdevData, winit::WinitData, AnvilState}; -#[cfg(feature = "udev")] -use smithay::backend::session::Session; use smithay::{ backend::input::{ self, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, @@ -17,20 +15,7 @@ use smithay::{ }; impl AnvilState { - pub fn process_input_event(&mut self, event: InputEvent) { - match event { - InputEvent::Keyboard { event, .. } => self.on_keyboard_key::(event), - InputEvent::PointerMotion { event, .. } => self.on_pointer_move::(event), - InputEvent::PointerMotionAbsolute { event, .. } => self.on_pointer_move_absolute::(event), - InputEvent::PointerButton { event, .. } => self.on_pointer_button::(event), - InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::(event), - _ => { - // other events are not handled in anvil (yet) - } - } - } - - fn on_keyboard_key(&mut self, evt: B::KeyboardKeyEvent) { + fn keyboard_key_to_action(&mut self, evt: B::KeyboardKeyEvent) -> KeyAction { let keycode = evt.key_code(); let state = evt.state(); debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state)); @@ -52,8 +37,10 @@ impl AnvilState { }); if let KeyState::Released = state { // only process special actions on key press, not release - return; + return KeyAction::None; } + return action; + /* match action { KeyAction::Quit => { info!(self.log, "Quitting."); @@ -94,113 +81,7 @@ impl AnvilState { } _ => (), } - } - - fn on_pointer_move(&mut self, evt: B::PointerMotionEvent) { - let (x, y) = (evt.delta_x(), evt.delta_y()); - let serial = SCOUNTER.next_serial(); - let mut location = self.pointer_location.borrow_mut(); - location.0 += x as f64; - location.1 += y as f64; - - #[cfg(feature = "udev")] - { - // clamp to screen limits - // this event is never generated by winit - *location = self.clamp_coords(*location); - } - - let under = self - .window_map - .borrow() - .get_surface_under((location.0, location.1)); - self.pointer.motion(*location, under, serial, evt.time()); - } - - fn on_pointer_move_absolute(&mut self, evt: B::PointerMotionAbsoluteEvent) { - // different cases depending on the context: - let (x, y) = { - #[cfg(feature = "udev")] - { - if self.session.is_some() { - // we are started on a tty - let x = self.pointer_location.borrow().0; - let screen_size = self.current_output_size(x); - // monitor coordinates - let (ux, uy) = evt.position_transformed(screen_size); - (ux + self.current_output_offset(x) as f64, uy as f64) - } else { - // we are started in winit - evt.position() - } - } - #[cfg(not(feature = "udev"))] - { - evt.position() - } - }; - *self.pointer_location.borrow_mut() = (x, y); - let serial = SCOUNTER.next_serial(); - let under = self.window_map.borrow().get_surface_under((x as f64, y as f64)); - self.pointer.motion((x, y), under, serial, evt.time()); - } - - #[cfg(feature = "udev")] - fn clamp_coords(&self, pos: (f64, f64)) -> (f64, f64) { - let output_map = self.output_map.as_ref().unwrap(); - let outputs = output_map.borrow(); - - if outputs.len() == 0 { - return pos; - } - - let (mut x, mut y) = pos; - // max_x is the sum of the width of all outputs - let max_x = outputs.iter().fold(0u32, |acc, output| acc + output.size.0); - x = x.max(0.0).min(max_x as f64); - - // max y depends on the current output - let max_y = self.current_output_size(x).1; - y = y.max(0.0).min(max_y as f64); - - (x, y) - } - - #[cfg(feature = "udev")] - fn current_output_idx(&self, x: f64) -> usize { - let output_map = self.output_map.as_ref().unwrap(); - let outputs = output_map.borrow(); - - outputs - .iter() - // map each output to their x position - .scan(0u32, |acc, output| { - let curr_x = *acc; - *acc += output.size.0; - Some(curr_x) - }) - // get an index - .enumerate() - // find the first one with a greater x - .find(|(_idx, x_pos)| *x_pos as f64 > x) - // the previous output is the one we are on - .map(|(idx, _)| idx - 1) - .unwrap_or(outputs.len() - 1) - } - #[cfg(feature = "udev")] - fn current_output_size(&self, x: f64) -> (u32, u32) { - let output_map = self.output_map.as_ref().unwrap(); - let outputs = output_map.borrow(); - outputs[self.current_output_idx(x)].size - } - #[cfg(feature = "udev")] - fn current_output_offset(&self, x: f64) -> u32 { - let output_map = self.output_map.as_ref().unwrap(); - let outputs = output_map.borrow(); - outputs - .iter() - .take(self.current_output_idx(x)) - .fold(0u32, |acc, output| acc + output.size.0) + */ } fn on_pointer_button(&mut self, evt: B::PointerButtonEvent) { @@ -267,7 +148,147 @@ impl AnvilState { } } +#[cfg(feature = "winit")] +impl AnvilState { + pub fn process_input_event(&mut self, event: InputEvent) { + match event { + InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::(event) { + KeyAction::None => {} + KeyAction::Quit => { + info!(self.log, "Quitting."); + self.running.store(false, Ordering::SeqCst); + } + KeyAction::Run(cmd) => { + info!(self.log, "Starting program"; "cmd" => cmd.clone()); + if let Err(e) = Command::new(&cmd).spawn() { + error!(self.log, + "Failed to start program"; + "cmd" => cmd, + "err" => format!("{:?}", e) + ); + } + } + action => { + warn!(self.log, "Key action {:?} unsupported on winit backend.", action); + } + }, + InputEvent::PointerMotionAbsolute { event, .. } => self.on_pointer_move_absolute::(event), + InputEvent::PointerButton { event, .. } => self.on_pointer_button::(event), + InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::(event), + _ => { + // other events are not handled in anvil (yet) + } + } + } + + fn on_pointer_move_absolute(&mut self, evt: B::PointerMotionAbsoluteEvent) { + // different cases depending on the context: + let (x, y) = evt.position(); + *self.pointer_location.borrow_mut() = (x, y); + let serial = SCOUNTER.next_serial(); + let under = self.window_map.borrow().get_surface_under((x as f64, y as f64)); + self.pointer.motion((x, y), under, serial, evt.time()); + } +} + +#[cfg(feature = "udev")] +impl AnvilState { + pub fn process_input_event(&mut self, event: InputEvent) { + match event { + InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::(event) { + KeyAction::None => {} + KeyAction::Quit => { + info!(self.log, "Quitting."); + self.running.store(false, Ordering::SeqCst); + } + KeyAction::Run(cmd) => { + info!(self.log, "Starting program"; "cmd" => cmd.clone()); + if let Err(e) = Command::new(&cmd).spawn() { + error!(self.log, + "Failed to start program"; + "cmd" => cmd, + "err" => format!("{:?}", e) + ); + } + } + action => { + warn!(self.log, "Key action {:?} unsupported on winit backend.", action); + } + }, + InputEvent::PointerMotion { event, .. } => self.on_pointer_move::(event), + InputEvent::PointerButton { event, .. } => self.on_pointer_button::(event), + InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::(event), + _ => { + // other events are not handled in anvil (yet) + } + } + } + + fn on_pointer_move(&mut self, evt: B::PointerMotionEvent) { + let (x, y) = (evt.delta_x(), evt.delta_y()); + let serial = SCOUNTER.next_serial(); + let mut location = self.pointer_location.borrow_mut(); + location.0 += x as f64; + location.1 += y as f64; + + // clamp to screen limits + // this event is never generated by winit + *location = self.clamp_coords(*location); + + let under = self + .window_map + .borrow() + .get_surface_under((location.0, location.1)); + self.pointer.motion(*location, under, serial, evt.time()); + } + + fn clamp_coords(&self, pos: (f64, f64)) -> (f64, f64) { + let outputs = self.backend_data.output_map.borrow(); + + if outputs.len() == 0 { + return pos; + } + + let (mut x, mut y) = pos; + // max_x is the sum of the width of all outputs + let max_x = outputs.iter().fold(0u32, |acc, output| acc + output.size.0); + x = x.max(0.0).min(max_x as f64); + + // max y depends on the current output + let max_y = self.current_output_size(x).1; + y = y.max(0.0).min(max_y as f64); + + (x, y) + } + + fn current_output_idx(&self, x: f64) -> usize { + let outputs = self.backend_data.output_map.borrow(); + + outputs + .iter() + // map each output to their x position + .scan(0u32, |acc, output| { + let curr_x = *acc; + *acc += output.size.0; + Some(curr_x) + }) + // get an index + .enumerate() + // find the first one with a greater x + .find(|(_idx, x_pos)| *x_pos as f64 > x) + // the previous output is the one we are on + .map(|(idx, _)| idx - 1) + .unwrap_or(outputs.len() - 1) + } + + fn current_output_size(&self, x: f64) -> (u32, u32) { + let outputs = self.backend_data.output_map.borrow(); + outputs[self.current_output_idx(x)].size + } +} + /// Possible results of a keyboard action +#[derive(Debug)] enum KeyAction { /// Quit the compositor Quit, diff --git a/anvil/src/state.rs b/anvil/src/state.rs index 06d088d..c3823dc 100644 --- a/anvil/src/state.rs +++ b/anvil/src/state.rs @@ -9,7 +9,7 @@ use std::{ use smithay::{ reexports::{ - calloop::{generic::Generic, Interest, LoopHandle, Mode, RegistrationToken}, + calloop::{generic::Generic, Interest, LoopHandle, Mode}, wayland_server::{protocol::wl_surface::WlSurface, Display}, }, wayland::{ @@ -22,23 +22,19 @@ use smithay::{ #[cfg(feature = "egl")] use smithay::backend::egl::display::EGLBufferReader; -#[cfg(feature = "udev")] -use smithay::backend::session::{auto::AutoSession, Session}; #[cfg(feature = "xwayland")] use smithay::xwayland::XWayland; use crate::shell::init_shell; -#[cfg(feature = "udev")] -use crate::udev::MyOutput; #[cfg(feature = "xwayland")] use crate::xwayland::XWm; -pub struct AnvilState { - pub backend: Backend, +pub struct AnvilState { + pub backend_data: BackendData, pub socket_name: String, pub running: Arc, pub display: Rc>, - pub handle: LoopHandle<'static, AnvilState>, + pub handle: LoopHandle<'static, AnvilState>, pub ctoken: CompositorToken, pub window_map: Rc>>, pub dnd_icon: Arc>>, @@ -48,44 +44,35 @@ pub struct AnvilState { pub keyboard: KeyboardHandle, pub pointer_location: Rc>, pub cursor_status: Arc>, - #[cfg(feature = "udev")] - pub output_map: Option>>>, pub seat_name: String, - #[cfg(feature = "udev")] - pub session: Option, + #[cfg(feature = "egl")] + pub egl_reader: Rc>>, // things we must keep alive - _wayland_event_source: RegistrationToken, #[cfg(feature = "xwayland")] - _xwayland: XWayland>, + _xwayland: XWayland>, } -impl AnvilState { +impl AnvilState { pub fn init( display: Rc>, - handle: LoopHandle<'static, AnvilState>, + handle: LoopHandle<'static, AnvilState>, + backend_data: BackendData, #[cfg(feature = "egl")] egl_reader: Rc>>, - #[cfg(feature = "udev")] session: Option, - #[cfg(not(feature = "udev"))] _session: Option<()>, - #[cfg(feature = "udev")] output_map: Option>>>, - #[cfg(not(feature = "udev"))] _output_map: Option<()>, log: slog::Logger, - ) -> AnvilState { + ) -> AnvilState { // init the wayland connection - let _wayland_event_source = handle + handle .insert_source( Generic::from_fd(display.borrow().get_poll_fd(), Interest::READ, Mode::Level), - { - let display = display.clone(); - let log = log.clone(); - move |_, _, state: &mut AnvilState| { - let mut display = display.borrow_mut(); - match display.dispatch(std::time::Duration::from_millis(0), state) { - Ok(_) => Ok(()), - Err(e) => { - error!(log, "I/O error on the Wayland display: {}", e); - state.running.store(false, Ordering::SeqCst); - Err(e) - } + move |_, _, state: &mut AnvilState| { + let display = state.display.clone(); + let mut display = display.borrow_mut(); + match display.dispatch(std::time::Duration::from_millis(0), state) { + Ok(_) => Ok(()), + Err(e) => { + error!(state.log, "I/O error on the Wayland display: {}", e); + state.running.store(false, Ordering::SeqCst); + Err(e) } } }, @@ -94,10 +81,11 @@ impl AnvilState { // Init the basic compositor globals - init_shm_global(&mut display.borrow_mut(), vec![], log.clone()); + init_shm_global(&mut (*display).borrow_mut(), vec![], log.clone()); #[cfg(feature = "egl")] - let shell_handles = init_shell::(&mut display.borrow_mut(), egl_reader, log.clone()); + let shell_handles = + init_shell::(&mut display.borrow_mut(), egl_reader.clone(), log.clone()); #[cfg(not(feature = "egl"))] let shell_handles = init_shell(&mut display.borrow_mut(), log.clone()); @@ -132,14 +120,7 @@ impl AnvilState { ); // init input - #[cfg(feature = "udev")] - let seat_name = if let Some(ref session) = session { - session.seat() - } else { - "anvil".into() - }; - #[cfg(not(feature = "udev"))] - let seat_name: String = "anvil".into(); + let seat_name = backend_data.seat_name(); let (mut seat, _) = Seat::new( &mut display.borrow_mut(), @@ -174,7 +155,7 @@ impl AnvilState { }; AnvilState { - backend: Default::default(), + backend_data, running: Arc::new(AtomicBool::new(true)), display, handle, @@ -187,14 +168,14 @@ impl AnvilState { keyboard, cursor_status, pointer_location: Rc::new(RefCell::new((0.0, 0.0))), - #[cfg(feature = "udev")] - output_map, seat_name, - #[cfg(feature = "udev")] - session, - _wayland_event_source, + egl_reader, #[cfg(feature = "xwayland")] _xwayland, } } } + +pub trait Backend { + fn seat_name(&self) -> String; +} diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 34cfcdf..685431c 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -60,7 +60,7 @@ use smithay::{ use crate::drawing::*; use crate::shell::{MyWindowMap, Roles}; -use crate::state::AnvilState; +use crate::state::{AnvilState, Backend}; #[derive(Clone)] pub struct SessionFd(RawFd); @@ -70,11 +70,19 @@ impl AsRawFd for SessionFd { } } -pub struct UdevData {} +pub struct UdevData { + pub output_map: Rc>>, + pub session: AutoSession, + #[cfg(feature = "egl")] + primary_gpu: Option, + backends: HashMap, + signaler: Signaler, + pointer_image: ImageBuffer, Vec>, +} -impl Default for UdevData { - fn default() -> UdevData { - UdevData {} +impl Backend for UdevData { + fn seat_name(&self) -> String { + self.session.seat() } } @@ -106,42 +114,30 @@ pub fn run_udev( /* * Initialize the compositor */ + let pointer_bytes = include_bytes!("../resources/cursor2.rgba"); + let primary_gpu = primary_gpu(&session.seat()).unwrap_or_default(); + let data = UdevData { + session, + output_map: output_map.clone(), + primary_gpu, + backends: HashMap::new(), + signaler: session_signal.clone(), + pointer_image: ImageBuffer::from_raw(64, 64, pointer_bytes.to_vec()).unwrap(), + }; let mut state = AnvilState::init( display.clone(), event_loop.handle(), + data, #[cfg(feature = "egl")] egl_buffer_reader.clone(), - Some(session), - Some(output_map.clone()), log.clone(), ); /* * Initialize the udev backend */ - let bytes = include_bytes!("../resources/cursor2.rgba"); let udev_backend = UdevBackend::new(state.seat_name.clone(), log.clone()).map_err(|_| ())?; - let mut udev_handler = UdevHandlerImpl { - compositor_token: state.ctoken, - #[cfg(feature = "egl")] - egl_buffer_reader, - session: state.session.clone().unwrap(), - backends: HashMap::new(), - output_map, - display: display.clone(), - #[cfg(feature = "egl")] - primary_gpu: primary_gpu(&state.seat_name).unwrap_or_default(), - window_map: state.window_map.clone(), - pointer_location: state.pointer_location.clone(), - pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(), - cursor_status: state.cursor_status.clone(), - dnd_icon: state.dnd_icon.clone(), - loop_handle: event_loop.handle(), - signaler: session_signal.clone(), - logger: log.clone(), - }; - /* * Initialize a fake output (we render one screen to every device in this example) */ @@ -150,7 +146,7 @@ pub fn run_udev( * Initialize libinput backend */ let mut libinput_context = Libinput::new_with_udev::>( - state.session.clone().unwrap().into(), + state.backend_data.session.clone().into(), ); libinput_context.udev_assign_seat(&state.seat_name).unwrap(); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); @@ -170,15 +166,15 @@ pub fn run_udev( .insert_source(notifier, |(), &mut (), _anvil_state| {}) .unwrap(); for (dev, path) in udev_backend.device_list() { - udev_handler.device_added(dev, path.into()) + state.device_added(dev, path.into()) } let udev_event_source = event_loop .handle() - .insert_source(udev_backend, move |event, _, _state| match event { - UdevEvent::Added { device_id, path } => udev_handler.device_added(device_id, path), - UdevEvent::Changed { device_id } => udev_handler.device_changed(device_id), - UdevEvent::Removed { device_id } => udev_handler.device_removed(device_id), + .insert_source(udev_backend, move |event, _, state| match event { + UdevEvent::Added { device_id, path } => state.device_added(device_id, path), + UdevEvent::Changed { device_id } => state.device_changed(device_id), + UdevEvent::Removed { device_id } => state.device_removed(device_id), }) .map_err(|e| -> IoError { e.into() }) .unwrap(); @@ -283,127 +279,106 @@ struct BackendData { event_dispatcher: Dispatcher<'static, DrmDevice, AnvilState>, } -struct UdevHandlerImpl { - compositor_token: CompositorToken, - #[cfg(feature = "egl")] - egl_buffer_reader: Rc>>, - session: AutoSession, - backends: HashMap, - display: Rc>, - #[cfg(feature = "egl")] - primary_gpu: Option, - window_map: Rc>, - output_map: Rc>>, - pointer_location: Rc>, - pointer_image: ImageBuffer, Vec>, - cursor_status: Arc>, - dnd_icon: Arc>>, - loop_handle: LoopHandle<'static, AnvilState>, - signaler: Signaler, - logger: ::slog::Logger, -} +pub fn scan_connectors( + device: &mut DrmDevice, + gbm: &GbmDevice, + egl: &EGLDisplay, + context: &EGLContext, + display: &mut Display, + output_map: &mut Vec, + signaler: &Signaler, + logger: &::slog::Logger, +) -> HashMap>> { + // Get a set of all modesetting resource handles (excluding planes): + let res_handles = device.resource_handles().unwrap(); -impl UdevHandlerImpl { - pub fn scan_connectors( - device: &mut DrmDevice, - gbm: &GbmDevice, - egl: &EGLDisplay, - context: &EGLContext, - display: &mut Display, - output_map: &mut Vec, - signaler: &Signaler, - logger: &::slog::Logger, - ) -> HashMap>> { - // Get a set of all modesetting resource handles (excluding planes): - let res_handles = device.resource_handles().unwrap(); + // Use first connected connector + let connector_infos: Vec = res_handles + .connectors() + .iter() + .map(|conn| device.get_connector(*conn).unwrap()) + .filter(|conn| conn.state() == ConnectorState::Connected) + .inspect(|conn| info!(logger, "Connected: {:?}", conn.interface())) + .collect(); - // Use first connected connector - let connector_infos: Vec = res_handles - .connectors() + let mut backends = HashMap::new(); + + // very naive way of finding good crtc/encoder/connector combinations. This problem is np-complete + for connector_info in connector_infos { + let encoder_infos = connector_info + .encoders() .iter() - .map(|conn| device.get_connector(*conn).unwrap()) - .filter(|conn| conn.state() == ConnectorState::Connected) - .inspect(|conn| info!(logger, "Connected: {:?}", conn.interface())) - .collect(); + .filter_map(|e| *e) + .flat_map(|encoder_handle| device.get_encoder(encoder_handle)) + .collect::>(); + 'outer: for encoder_info in encoder_infos { + for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { + if let Entry::Vacant(entry) = backends.entry(crtc) { + info!( + logger, + "Trying to setup connector {:?}-{} with crtc {:?}", + connector_info.interface(), + connector_info.interface_id(), + crtc, + ); + let context = match EGLContext::new_shared(egl, context, logger.clone()) { + Ok(context) => context, + Err(err) => { + warn!(logger, "Failed to create EGLContext: {}", err); + continue; + } + }; + let renderer = match unsafe { Gles2Renderer::new(context, logger.clone()) } { + Ok(renderer) => renderer, + Err(err) => { + warn!(logger, "Failed to create Gles2 Renderer: {}", err); + continue; + } + }; + let mut surface = match device.create_surface( + crtc, + connector_info.modes()[0], + &[connector_info.handle()], + ) { + Ok(surface) => surface, + Err(err) => { + warn!(logger, "Failed to create drm surface: {}", err); + continue; + } + }; + surface.link(signaler.clone()); + let renderer = match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone()) + { + Ok(renderer) => renderer, + Err(err) => { + warn!(logger, "Failed to create rendering surface: {}", err); + continue; + } + }; - let mut backends = HashMap::new(); + output_map.push(MyOutput::new( + display, + device.device_id(), + crtc, + connector_info, + logger.clone(), + )); - // very naive way of finding good crtc/encoder/connector combinations. This problem is np-complete - for connector_info in connector_infos { - let encoder_infos = connector_info - .encoders() - .iter() - .filter_map(|e| *e) - .flat_map(|encoder_handle| device.get_encoder(encoder_handle)) - .collect::>(); - 'outer: for encoder_info in encoder_infos { - for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { - if let Entry::Vacant(entry) = backends.entry(crtc) { - info!( - logger, - "Trying to setup connector {:?}-{} with crtc {:?}", - connector_info.interface(), - connector_info.interface_id(), - crtc, - ); - let context = match EGLContext::new_shared(egl, context, logger.clone()) { - Ok(context) => context, - Err(err) => { - warn!(logger, "Failed to create EGLContext: {}", err); - continue; - } - }; - let renderer = match unsafe { Gles2Renderer::new(context, logger.clone()) } { - Ok(renderer) => renderer, - Err(err) => { - warn!(logger, "Failed to create Gles2 Renderer: {}", err); - continue; - } - }; - let mut surface = match device.create_surface( - crtc, - connector_info.modes()[0], - &[connector_info.handle()], - ) { - Ok(surface) => surface, - Err(err) => { - warn!(logger, "Failed to create drm surface: {}", err); - continue; - } - }; - surface.link(signaler.clone()); - let renderer = - match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone()) { - Ok(renderer) => renderer, - Err(err) => { - warn!(logger, "Failed to create rendering surface: {}", err); - continue; - } - }; - - output_map.push(MyOutput::new( - display, - device.device_id(), - crtc, - connector_info, - logger.clone(), - )); - - entry.insert(Rc::new(RefCell::new(renderer))); - break 'outer; - } + entry.insert(Rc::new(RefCell::new(renderer))); + break 'outer; } } } - - backends } + + backends } -impl UdevHandlerImpl { +impl AnvilState { fn device_added(&mut self, device_id: dev_t, path: PathBuf) { // Try to open the device if let Some((mut device, gbm)) = self + .backend_data .session .open( &path, @@ -414,14 +389,14 @@ impl UdevHandlerImpl { match { let fd = SessionFd(fd); ( - DrmDevice::new(fd.clone(), true, self.logger.clone()), + DrmDevice::new(fd.clone(), true, self.log.clone()), GbmDevice::new(fd), ) } { (Ok(drm), Ok(gbm)) => Some((drm, gbm)), (Err(err), _) => { warn!( - self.logger, + self.log, "Skipping device {:?}, because of drm error: {}", device_id, err ); None @@ -429,7 +404,7 @@ impl UdevHandlerImpl { (_, Err(err)) => { // TODO try DumbBuffer allocator in this case warn!( - self.logger, + self.log, "Skipping device {:?}, because of gbm error: {}", device_id, err ); None @@ -437,11 +412,11 @@ impl UdevHandlerImpl { } }) { - let egl = match EGLDisplay::new(&gbm, self.logger.clone()) { + let egl = match EGLDisplay::new(&gbm, self.log.clone()) { Ok(display) => display, Err(err) => { warn!( - self.logger, + self.log, "Skipping device {:?}, because of egl display error: {}", device_id, err ); return; @@ -449,48 +424,45 @@ impl UdevHandlerImpl { }; #[cfg(feature = "egl")] - let is_primary = path.canonicalize().ok() == self.primary_gpu; + let is_primary = path.canonicalize().ok() == self.backend_data.primary_gpu; // init hardware acceleration on the primary gpu. #[cfg(feature = "egl")] { if is_primary { - info!( - self.logger, - "Initializing EGL Hardware Acceleration via {:?}", path - ); - *self.egl_buffer_reader.borrow_mut() = egl.bind_wl_display(&*self.display.borrow()).ok(); + info!(self.log, "Initializing EGL Hardware Acceleration via {:?}", path); + *self.egl_reader.borrow_mut() = egl.bind_wl_display(&*self.display.borrow()).ok(); } } - let context = match EGLContext::new(&egl, self.logger.clone()) { + let context = match EGLContext::new(&egl, self.log.clone()) { Ok(context) => context, Err(err) => { warn!( - self.logger, + self.log, "Skipping device {:?}, because of egl context error: {}", device_id, err ); return; } }; - let backends = Rc::new(RefCell::new(UdevHandlerImpl::scan_connectors( + let backends = Rc::new(RefCell::new(scan_connectors( &mut device, &gbm, &egl, &context, &mut *self.display.borrow_mut(), - &mut *self.output_map.borrow_mut(), - &self.signaler, - &self.logger, + &mut *self.backend_data.output_map.borrow_mut(), + &self.backend_data.signaler, + &self.log, ))); // we leak this texture (we would need to call `destroy_texture` on Drop of DrmRenderer), // but only on shutdown anyway, because we do not support hot-pluggin, so it does not really matter. let pointer_image = { - let context = EGLContext::new_shared(&egl, &context, self.logger.clone()).unwrap(); - let mut renderer = unsafe { Gles2Renderer::new(context, self.logger.clone()).unwrap() }; + let context = EGLContext::new_shared(&egl, &context, self.log.clone()).unwrap(); + let mut renderer = unsafe { Gles2Renderer::new(context, self.log.clone()).unwrap() }; renderer - .import_bitmap(&self.pointer_image) + .import_bitmap(&self.backend_data.pointer_image) .expect("Failed to load pointer") }; @@ -501,35 +473,35 @@ impl UdevHandlerImpl { device_id, #[cfg(feature = "egl")] egl_buffer_reader: if is_primary { - self.egl_buffer_reader.borrow().clone() + self.egl_reader.borrow().clone() } else { None }, - compositor_token: self.compositor_token, + compositor_token: self.ctoken, backends: backends.clone(), window_map: self.window_map.clone(), - output_map: self.output_map.clone(), + output_map: self.backend_data.output_map.clone(), pointer_location: self.pointer_location.clone(), pointer_image, cursor_status: self.cursor_status.clone(), dnd_icon: self.dnd_icon.clone(), - logger: self.logger.clone(), + logger: self.log.clone(), start_time: std::time::Instant::now(), }); let mut listener = DrmRendererSessionListener { renderer: renderer.clone(), - loop_handle: self.loop_handle.clone(), + loop_handle: self.handle.clone(), }; - let restart_token = self.signaler.register(move |signal| match signal { + let restart_token = self.backend_data.signaler.register(move |signal| match signal { SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => listener.activate(), _ => {} }); let mut drm_handler = DrmHandlerImpl { renderer, - loop_handle: self.loop_handle.clone(), + loop_handle: self.handle.clone(), }; - device.link(self.signaler.clone()); + device.link(self.backend_data.signaler.clone()); let dev_id = device.device_id(); let event_dispatcher = Dispatcher::new(device, move |event, _, _| match event { DrmEvent::VBlank(crtc) => drm_handler.vblank(crtc), @@ -537,19 +509,16 @@ impl UdevHandlerImpl { error!(drm_handler.renderer.logger, "{:?}", error); } }); - let registration_token = self - .loop_handle - .register_dispatcher(event_dispatcher.clone()) - .unwrap(); + let registration_token = self.handle.register_dispatcher(event_dispatcher.clone()).unwrap(); - trace!(self.logger, "Backends: {:?}", backends.borrow().keys()); + trace!(self.log, "Backends: {:?}", backends.borrow().keys()); for backend in backends.borrow_mut().values() { // render first frame - trace!(self.logger, "Scheduling frame"); - schedule_initial_render(backend.clone(), &self.loop_handle, self.logger.clone()); + trace!(self.log, "Scheduling frame"); + schedule_initial_render(backend.clone(), &self.handle, self.log.clone()); } - self.backends.insert( + self.backend_data.backends.insert( dev_id, BackendData { _restart_token: restart_token, @@ -566,17 +535,17 @@ impl UdevHandlerImpl { fn device_changed(&mut self, device: dev_t) { //quick and dirty, just re-init all backends - if let Some(ref mut backend_data) = self.backends.get_mut(&device) { - let logger = self.logger.clone(); - let loop_handle = self.loop_handle.clone(); + if let Some(ref mut backend_data) = self.backend_data.backends.get_mut(&device) { + let logger = self.log.clone(); + let loop_handle = self.handle.clone(); let mut display = self.display.borrow_mut(); - let mut output_map = self.output_map.borrow_mut(); - let signaler = self.signaler.clone(); + let mut output_map = self.backend_data.output_map.borrow_mut(); + let signaler = self.backend_data.signaler.clone(); output_map.retain(|output| output.device_id != device); let mut source = backend_data.event_dispatcher.as_source_mut(); let mut backends = backend_data.surfaces.borrow_mut(); - *backends = UdevHandlerImpl::scan_connectors( + *backends = scan_connectors( &mut *source, &backend_data.gbm, &backend_data.egl, @@ -597,26 +566,29 @@ impl UdevHandlerImpl { fn device_removed(&mut self, device: dev_t) { // drop the backends on this side - if let Some(backend_data) = self.backends.remove(&device) { + if let Some(backend_data) = self.backend_data.backends.remove(&device) { // drop surfaces backend_data.surfaces.borrow_mut().clear(); - debug!(self.logger, "Surfaces dropped"); + debug!(self.log, "Surfaces dropped"); // clear outputs - self.output_map + self.backend_data + .output_map .borrow_mut() .retain(|output| output.device_id != device); - let _device = self.loop_handle.remove(backend_data.registration_token); + let _device = self.handle.remove(backend_data.registration_token); let _device = backend_data.event_dispatcher.into_source_inner(); // don't use hardware acceleration anymore, if this was the primary gpu #[cfg(feature = "egl")] { - if _device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { - *self.egl_buffer_reader.borrow_mut() = None; + if _device.dev_path().and_then(|path| path.canonicalize().ok()) + == self.backend_data.primary_gpu + { + *self.egl_reader.borrow_mut() = None; } } - debug!(self.logger, "Dropping device"); + debug!(self.log, "Dropping device"); } } } diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index c795a72..599a3d5 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -15,13 +15,13 @@ use smithay::{ use slog::Logger; use crate::drawing::*; -use crate::state::AnvilState; +use crate::state::{AnvilState, Backend}; pub struct WinitData; -impl Default for WinitData { - fn default() -> WinitData { - WinitData +impl Backend for WinitData { + fn seat_name(&self) -> String { + String::from("winit") } } @@ -54,10 +54,9 @@ pub fn run_winit( let mut state = AnvilState::init( display.clone(), event_loop.handle(), + WinitData, #[cfg(feature = "egl")] Rc::new(RefCell::new(reader.clone())), - None, - None, log.clone(), );