anvil: reorganize platform-specific values

This commit is contained in:
Victor Berger 2021-05-31 00:56:37 +02:00 committed by Victor Berger
parent 3f01f978f8
commit 4bf6bfa08d
5 changed files with 345 additions and 372 deletions

View File

@ -12,7 +12,7 @@ members = [ "anvil" ]
[dependencies] [dependencies]
bitflags = "1" bitflags = "1"
calloop = {version = "0.8.0" } calloop = "0.8.0"
cgmath = "0.18.0" cgmath = "0.18.0"
dbus = { version = "0.9.0", optional = true } dbus = { version = "0.9.0", optional = true }
drm-fourcc = "^2.1.1" drm-fourcc = "^2.1.1"

View File

@ -1,9 +1,7 @@
use std::{process::Command, sync::atomic::Ordering}; 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::{ use smithay::{
backend::input::{ backend::input::{
self, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, self, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent,
@ -17,20 +15,7 @@ use smithay::{
}; };
impl<Backend> AnvilState<Backend> { impl<Backend> AnvilState<Backend> {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) { fn keyboard_key_to_action<B: InputBackend>(&mut self, evt: B::KeyboardKeyEvent) -> KeyAction {
match event {
InputEvent::Keyboard { event, .. } => self.on_keyboard_key::<B>(event),
InputEvent::PointerMotion { event, .. } => self.on_pointer_move::<B>(event),
InputEvent::PointerMotionAbsolute { event, .. } => self.on_pointer_move_absolute::<B>(event),
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event),
_ => {
// other events are not handled in anvil (yet)
}
}
}
fn on_keyboard_key<B: InputBackend>(&mut self, evt: B::KeyboardKeyEvent) {
let keycode = evt.key_code(); let keycode = evt.key_code();
let state = evt.state(); let state = evt.state();
debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state)); debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state));
@ -52,8 +37,10 @@ impl<Backend> AnvilState<Backend> {
}); });
if let KeyState::Released = state { if let KeyState::Released = state {
// only process special actions on key press, not release // only process special actions on key press, not release
return; return KeyAction::None;
} }
return action;
/*
match action { match action {
KeyAction::Quit => { KeyAction::Quit => {
info!(self.log, "Quitting."); info!(self.log, "Quitting.");
@ -94,113 +81,7 @@ impl<Backend> AnvilState<Backend> {
} }
_ => (), _ => (),
} }
} */
fn on_pointer_move<B: InputBackend>(&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<B: InputBackend>(&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<B: InputBackend>(&mut self, evt: B::PointerButtonEvent) { fn on_pointer_button<B: InputBackend>(&mut self, evt: B::PointerButtonEvent) {
@ -267,7 +148,147 @@ impl<Backend> AnvilState<Backend> {
} }
} }
#[cfg(feature = "winit")]
impl AnvilState<WinitData> {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
match event {
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(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::<B>(event),
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event),
_ => {
// other events are not handled in anvil (yet)
}
}
}
fn on_pointer_move_absolute<B: InputBackend>(&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<UdevData> {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
match event {
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(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::<B>(event),
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event),
_ => {
// other events are not handled in anvil (yet)
}
}
}
fn on_pointer_move<B: InputBackend>(&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 /// Possible results of a keyboard action
#[derive(Debug)]
enum KeyAction { enum KeyAction {
/// Quit the compositor /// Quit the compositor
Quit, Quit,

View File

@ -9,7 +9,7 @@ use std::{
use smithay::{ use smithay::{
reexports::{ reexports::{
calloop::{generic::Generic, Interest, LoopHandle, Mode, RegistrationToken}, calloop::{generic::Generic, Interest, LoopHandle, Mode},
wayland_server::{protocol::wl_surface::WlSurface, Display}, wayland_server::{protocol::wl_surface::WlSurface, Display},
}, },
wayland::{ wayland::{
@ -22,23 +22,19 @@ use smithay::{
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
use smithay::backend::egl::display::EGLBufferReader; use smithay::backend::egl::display::EGLBufferReader;
#[cfg(feature = "udev")]
use smithay::backend::session::{auto::AutoSession, Session};
#[cfg(feature = "xwayland")] #[cfg(feature = "xwayland")]
use smithay::xwayland::XWayland; use smithay::xwayland::XWayland;
use crate::shell::init_shell; use crate::shell::init_shell;
#[cfg(feature = "udev")]
use crate::udev::MyOutput;
#[cfg(feature = "xwayland")] #[cfg(feature = "xwayland")]
use crate::xwayland::XWm; use crate::xwayland::XWm;
pub struct AnvilState<Backend> { pub struct AnvilState<BackendData> {
pub backend: Backend, pub backend_data: BackendData,
pub socket_name: String, pub socket_name: String,
pub running: Arc<AtomicBool>, pub running: Arc<AtomicBool>,
pub display: Rc<RefCell<Display>>, pub display: Rc<RefCell<Display>>,
pub handle: LoopHandle<'static, AnvilState<Backend>>, pub handle: LoopHandle<'static, AnvilState<BackendData>>,
pub ctoken: CompositorToken<crate::shell::Roles>, pub ctoken: CompositorToken<crate::shell::Roles>,
pub window_map: Rc<RefCell<crate::window_map::WindowMap<crate::shell::Roles>>>, pub window_map: Rc<RefCell<crate::window_map::WindowMap<crate::shell::Roles>>>,
pub dnd_icon: Arc<Mutex<Option<WlSurface>>>, pub dnd_icon: Arc<Mutex<Option<WlSurface>>>,
@ -48,56 +44,48 @@ pub struct AnvilState<Backend> {
pub keyboard: KeyboardHandle, pub keyboard: KeyboardHandle,
pub pointer_location: Rc<RefCell<(f64, f64)>>, pub pointer_location: Rc<RefCell<(f64, f64)>>,
pub cursor_status: Arc<Mutex<CursorImageStatus>>, pub cursor_status: Arc<Mutex<CursorImageStatus>>,
#[cfg(feature = "udev")]
pub output_map: Option<Rc<RefCell<Vec<MyOutput>>>>,
pub seat_name: String, pub seat_name: String,
#[cfg(feature = "udev")] #[cfg(feature = "egl")]
pub session: Option<AutoSession>, pub egl_reader: Rc<RefCell<Option<EGLBufferReader>>>,
// things we must keep alive // things we must keep alive
_wayland_event_source: RegistrationToken,
#[cfg(feature = "xwayland")] #[cfg(feature = "xwayland")]
_xwayland: XWayland<XWm<Backend>>, _xwayland: XWayland<XWm<BackendData>>,
} }
impl<Backend: Default + 'static> AnvilState<Backend> { impl<BackendData: Backend + 'static> AnvilState<BackendData> {
pub fn init( pub fn init(
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
handle: LoopHandle<'static, AnvilState<Backend>>, handle: LoopHandle<'static, AnvilState<BackendData>>,
backend_data: BackendData,
#[cfg(feature = "egl")] egl_reader: Rc<RefCell<Option<EGLBufferReader>>>, #[cfg(feature = "egl")] egl_reader: Rc<RefCell<Option<EGLBufferReader>>>,
#[cfg(feature = "udev")] session: Option<AutoSession>,
#[cfg(not(feature = "udev"))] _session: Option<()>,
#[cfg(feature = "udev")] output_map: Option<Rc<RefCell<Vec<MyOutput>>>>,
#[cfg(not(feature = "udev"))] _output_map: Option<()>,
log: slog::Logger, log: slog::Logger,
) -> AnvilState<Backend> { ) -> AnvilState<BackendData> {
// init the wayland connection // init the wayland connection
let _wayland_event_source = handle handle
.insert_source( .insert_source(
Generic::from_fd(display.borrow().get_poll_fd(), Interest::READ, Mode::Level), Generic::from_fd(display.borrow().get_poll_fd(), Interest::READ, Mode::Level),
{ move |_, _, state: &mut AnvilState<BackendData>| {
let display = display.clone(); let display = state.display.clone();
let log = log.clone();
move |_, _, state: &mut AnvilState<Backend>| {
let mut display = display.borrow_mut(); let mut display = display.borrow_mut();
match display.dispatch(std::time::Duration::from_millis(0), state) { match display.dispatch(std::time::Duration::from_millis(0), state) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => { Err(e) => {
error!(log, "I/O error on the Wayland display: {}", e); error!(state.log, "I/O error on the Wayland display: {}", e);
state.running.store(false, Ordering::SeqCst); state.running.store(false, Ordering::SeqCst);
Err(e) Err(e)
} }
} }
}
}, },
) )
.expect("Failed to init the wayland event source."); .expect("Failed to init the wayland event source.");
// Init the basic compositor globals // 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")] #[cfg(feature = "egl")]
let shell_handles = init_shell::<Backend>(&mut display.borrow_mut(), egl_reader, log.clone()); let shell_handles =
init_shell::<BackendData>(&mut display.borrow_mut(), egl_reader.clone(), log.clone());
#[cfg(not(feature = "egl"))] #[cfg(not(feature = "egl"))]
let shell_handles = init_shell(&mut display.borrow_mut(), log.clone()); let shell_handles = init_shell(&mut display.borrow_mut(), log.clone());
@ -132,14 +120,7 @@ impl<Backend: Default + 'static> AnvilState<Backend> {
); );
// init input // init input
#[cfg(feature = "udev")] let seat_name = backend_data.seat_name();
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 (mut seat, _) = Seat::new( let (mut seat, _) = Seat::new(
&mut display.borrow_mut(), &mut display.borrow_mut(),
@ -174,7 +155,7 @@ impl<Backend: Default + 'static> AnvilState<Backend> {
}; };
AnvilState { AnvilState {
backend: Default::default(), backend_data,
running: Arc::new(AtomicBool::new(true)), running: Arc::new(AtomicBool::new(true)),
display, display,
handle, handle,
@ -187,14 +168,14 @@ impl<Backend: Default + 'static> AnvilState<Backend> {
keyboard, keyboard,
cursor_status, cursor_status,
pointer_location: Rc::new(RefCell::new((0.0, 0.0))), pointer_location: Rc::new(RefCell::new((0.0, 0.0))),
#[cfg(feature = "udev")]
output_map,
seat_name, seat_name,
#[cfg(feature = "udev")] egl_reader,
session,
_wayland_event_source,
#[cfg(feature = "xwayland")] #[cfg(feature = "xwayland")]
_xwayland, _xwayland,
} }
} }
} }
pub trait Backend {
fn seat_name(&self) -> String;
}

View File

@ -60,7 +60,7 @@ use smithay::{
use crate::drawing::*; use crate::drawing::*;
use crate::shell::{MyWindowMap, Roles}; use crate::shell::{MyWindowMap, Roles};
use crate::state::AnvilState; use crate::state::{AnvilState, Backend};
#[derive(Clone)] #[derive(Clone)]
pub struct SessionFd(RawFd); pub struct SessionFd(RawFd);
@ -70,11 +70,19 @@ impl AsRawFd for SessionFd {
} }
} }
pub struct UdevData {} pub struct UdevData {
pub output_map: Rc<RefCell<Vec<MyOutput>>>,
pub session: AutoSession,
#[cfg(feature = "egl")]
primary_gpu: Option<PathBuf>,
backends: HashMap<dev_t, BackendData>,
signaler: Signaler<SessionSignal>,
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
}
impl Default for UdevData { impl Backend for UdevData {
fn default() -> UdevData { fn seat_name(&self) -> String {
UdevData {} self.session.seat()
} }
} }
@ -106,42 +114,30 @@ pub fn run_udev(
/* /*
* Initialize the compositor * 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( let mut state = AnvilState::init(
display.clone(), display.clone(),
event_loop.handle(), event_loop.handle(),
data,
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
egl_buffer_reader.clone(), egl_buffer_reader.clone(),
Some(session),
Some(output_map.clone()),
log.clone(), log.clone(),
); );
/* /*
* Initialize the udev backend * 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 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) * 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 * Initialize libinput backend
*/ */
let mut libinput_context = Libinput::new_with_udev::<LibinputSessionInterface<AutoSession>>( let mut libinput_context = Libinput::new_with_udev::<LibinputSessionInterface<AutoSession>>(
state.session.clone().unwrap().into(), state.backend_data.session.clone().into(),
); );
libinput_context.udev_assign_seat(&state.seat_name).unwrap(); libinput_context.udev_assign_seat(&state.seat_name).unwrap();
let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
@ -170,15 +166,15 @@ pub fn run_udev(
.insert_source(notifier, |(), &mut (), _anvil_state| {}) .insert_source(notifier, |(), &mut (), _anvil_state| {})
.unwrap(); .unwrap();
for (dev, path) in udev_backend.device_list() { 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 let udev_event_source = event_loop
.handle() .handle()
.insert_source(udev_backend, move |event, _, _state| match event { .insert_source(udev_backend, move |event, _, state| match event {
UdevEvent::Added { device_id, path } => udev_handler.device_added(device_id, path), UdevEvent::Added { device_id, path } => state.device_added(device_id, path),
UdevEvent::Changed { device_id } => udev_handler.device_changed(device_id), UdevEvent::Changed { device_id } => state.device_changed(device_id),
UdevEvent::Removed { device_id } => udev_handler.device_removed(device_id), UdevEvent::Removed { device_id } => state.device_removed(device_id),
}) })
.map_err(|e| -> IoError { e.into() }) .map_err(|e| -> IoError { e.into() })
.unwrap(); .unwrap();
@ -283,27 +279,6 @@ struct BackendData {
event_dispatcher: Dispatcher<'static, DrmDevice<SessionFd>, AnvilState<UdevData>>, event_dispatcher: Dispatcher<'static, DrmDevice<SessionFd>, AnvilState<UdevData>>,
} }
struct UdevHandlerImpl {
compositor_token: CompositorToken<Roles>,
#[cfg(feature = "egl")]
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
session: AutoSession,
backends: HashMap<dev_t, BackendData>,
display: Rc<RefCell<Display>>,
#[cfg(feature = "egl")]
primary_gpu: Option<PathBuf>,
window_map: Rc<RefCell<MyWindowMap>>,
output_map: Rc<RefCell<Vec<MyOutput>>>,
pointer_location: Rc<RefCell<(f64, f64)>>,
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
cursor_status: Arc<Mutex<CursorImageStatus>>,
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
loop_handle: LoopHandle<'static, AnvilState<UdevData>>,
signaler: Signaler<SessionSignal>,
logger: ::slog::Logger,
}
impl UdevHandlerImpl {
pub fn scan_connectors( pub fn scan_connectors(
device: &mut DrmDevice<SessionFd>, device: &mut DrmDevice<SessionFd>,
gbm: &GbmDevice<SessionFd>, gbm: &GbmDevice<SessionFd>,
@ -372,8 +347,8 @@ impl UdevHandlerImpl {
} }
}; };
surface.link(signaler.clone()); surface.link(signaler.clone());
let renderer = let renderer = match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone())
match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone()) { {
Ok(renderer) => renderer, Ok(renderer) => renderer,
Err(err) => { Err(err) => {
warn!(logger, "Failed to create rendering surface: {}", err); warn!(logger, "Failed to create rendering surface: {}", err);
@ -398,12 +373,12 @@ impl UdevHandlerImpl {
backends backends
} }
}
impl UdevHandlerImpl { impl AnvilState<UdevData> {
fn device_added(&mut self, device_id: dev_t, path: PathBuf) { fn device_added(&mut self, device_id: dev_t, path: PathBuf) {
// Try to open the device // Try to open the device
if let Some((mut device, gbm)) = self if let Some((mut device, gbm)) = self
.backend_data
.session .session
.open( .open(
&path, &path,
@ -414,14 +389,14 @@ impl UdevHandlerImpl {
match { match {
let fd = SessionFd(fd); let fd = SessionFd(fd);
( (
DrmDevice::new(fd.clone(), true, self.logger.clone()), DrmDevice::new(fd.clone(), true, self.log.clone()),
GbmDevice::new(fd), GbmDevice::new(fd),
) )
} { } {
(Ok(drm), Ok(gbm)) => Some((drm, gbm)), (Ok(drm), Ok(gbm)) => Some((drm, gbm)),
(Err(err), _) => { (Err(err), _) => {
warn!( warn!(
self.logger, self.log,
"Skipping device {:?}, because of drm error: {}", device_id, err "Skipping device {:?}, because of drm error: {}", device_id, err
); );
None None
@ -429,7 +404,7 @@ impl UdevHandlerImpl {
(_, Err(err)) => { (_, Err(err)) => {
// TODO try DumbBuffer allocator in this case // TODO try DumbBuffer allocator in this case
warn!( warn!(
self.logger, self.log,
"Skipping device {:?}, because of gbm error: {}", device_id, err "Skipping device {:?}, because of gbm error: {}", device_id, err
); );
None 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, Ok(display) => display,
Err(err) => { Err(err) => {
warn!( warn!(
self.logger, self.log,
"Skipping device {:?}, because of egl display error: {}", device_id, err "Skipping device {:?}, because of egl display error: {}", device_id, err
); );
return; return;
@ -449,48 +424,45 @@ impl UdevHandlerImpl {
}; };
#[cfg(feature = "egl")] #[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. // init hardware acceleration on the primary gpu.
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
{ {
if is_primary { if is_primary {
info!( info!(self.log, "Initializing EGL Hardware Acceleration via {:?}", path);
self.logger, *self.egl_reader.borrow_mut() = egl.bind_wl_display(&*self.display.borrow()).ok();
"Initializing EGL Hardware Acceleration via {:?}", path
);
*self.egl_buffer_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, Ok(context) => context,
Err(err) => { Err(err) => {
warn!( warn!(
self.logger, self.log,
"Skipping device {:?}, because of egl context error: {}", device_id, err "Skipping device {:?}, because of egl context error: {}", device_id, err
); );
return; return;
} }
}; };
let backends = Rc::new(RefCell::new(UdevHandlerImpl::scan_connectors( let backends = Rc::new(RefCell::new(scan_connectors(
&mut device, &mut device,
&gbm, &gbm,
&egl, &egl,
&context, &context,
&mut *self.display.borrow_mut(), &mut *self.display.borrow_mut(),
&mut *self.output_map.borrow_mut(), &mut *self.backend_data.output_map.borrow_mut(),
&self.signaler, &self.backend_data.signaler,
&self.logger, &self.log,
))); )));
// we leak this texture (we would need to call `destroy_texture` on Drop of DrmRenderer), // 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. // but only on shutdown anyway, because we do not support hot-pluggin, so it does not really matter.
let pointer_image = { let pointer_image = {
let context = EGLContext::new_shared(&egl, &context, self.logger.clone()).unwrap(); let context = EGLContext::new_shared(&egl, &context, self.log.clone()).unwrap();
let mut renderer = unsafe { Gles2Renderer::new(context, self.logger.clone()).unwrap() }; let mut renderer = unsafe { Gles2Renderer::new(context, self.log.clone()).unwrap() };
renderer renderer
.import_bitmap(&self.pointer_image) .import_bitmap(&self.backend_data.pointer_image)
.expect("Failed to load pointer") .expect("Failed to load pointer")
}; };
@ -501,35 +473,35 @@ impl UdevHandlerImpl {
device_id, device_id,
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
egl_buffer_reader: if is_primary { egl_buffer_reader: if is_primary {
self.egl_buffer_reader.borrow().clone() self.egl_reader.borrow().clone()
} else { } else {
None None
}, },
compositor_token: self.compositor_token, compositor_token: self.ctoken,
backends: backends.clone(), backends: backends.clone(),
window_map: self.window_map.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_location: self.pointer_location.clone(),
pointer_image, pointer_image,
cursor_status: self.cursor_status.clone(), cursor_status: self.cursor_status.clone(),
dnd_icon: self.dnd_icon.clone(), dnd_icon: self.dnd_icon.clone(),
logger: self.logger.clone(), logger: self.log.clone(),
start_time: std::time::Instant::now(), start_time: std::time::Instant::now(),
}); });
let mut listener = DrmRendererSessionListener { let mut listener = DrmRendererSessionListener {
renderer: renderer.clone(), 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(), SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => listener.activate(),
_ => {} _ => {}
}); });
let mut drm_handler = DrmHandlerImpl { let mut drm_handler = DrmHandlerImpl {
renderer, 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 dev_id = device.device_id();
let event_dispatcher = Dispatcher::new(device, move |event, _, _| match event { let event_dispatcher = Dispatcher::new(device, move |event, _, _| match event {
DrmEvent::VBlank(crtc) => drm_handler.vblank(crtc), DrmEvent::VBlank(crtc) => drm_handler.vblank(crtc),
@ -537,19 +509,16 @@ impl UdevHandlerImpl {
error!(drm_handler.renderer.logger, "{:?}", error); error!(drm_handler.renderer.logger, "{:?}", error);
} }
}); });
let registration_token = self let registration_token = self.handle.register_dispatcher(event_dispatcher.clone()).unwrap();
.loop_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() { for backend in backends.borrow_mut().values() {
// render first frame // render first frame
trace!(self.logger, "Scheduling frame"); trace!(self.log, "Scheduling frame");
schedule_initial_render(backend.clone(), &self.loop_handle, self.logger.clone()); schedule_initial_render(backend.clone(), &self.handle, self.log.clone());
} }
self.backends.insert( self.backend_data.backends.insert(
dev_id, dev_id,
BackendData { BackendData {
_restart_token: restart_token, _restart_token: restart_token,
@ -566,17 +535,17 @@ impl UdevHandlerImpl {
fn device_changed(&mut self, device: dev_t) { fn device_changed(&mut self, device: dev_t) {
//quick and dirty, just re-init all backends //quick and dirty, just re-init all backends
if let Some(ref mut backend_data) = self.backends.get_mut(&device) { if let Some(ref mut backend_data) = self.backend_data.backends.get_mut(&device) {
let logger = self.logger.clone(); let logger = self.log.clone();
let loop_handle = self.loop_handle.clone(); let loop_handle = self.handle.clone();
let mut display = self.display.borrow_mut(); let mut display = self.display.borrow_mut();
let mut output_map = self.output_map.borrow_mut(); let mut output_map = self.backend_data.output_map.borrow_mut();
let signaler = self.signaler.clone(); let signaler = self.backend_data.signaler.clone();
output_map.retain(|output| output.device_id != device); output_map.retain(|output| output.device_id != device);
let mut source = backend_data.event_dispatcher.as_source_mut(); let mut source = backend_data.event_dispatcher.as_source_mut();
let mut backends = backend_data.surfaces.borrow_mut(); let mut backends = backend_data.surfaces.borrow_mut();
*backends = UdevHandlerImpl::scan_connectors( *backends = scan_connectors(
&mut *source, &mut *source,
&backend_data.gbm, &backend_data.gbm,
&backend_data.egl, &backend_data.egl,
@ -597,26 +566,29 @@ impl UdevHandlerImpl {
fn device_removed(&mut self, device: dev_t) { fn device_removed(&mut self, device: dev_t) {
// drop the backends on this side // 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 // drop surfaces
backend_data.surfaces.borrow_mut().clear(); backend_data.surfaces.borrow_mut().clear();
debug!(self.logger, "Surfaces dropped"); debug!(self.log, "Surfaces dropped");
// clear outputs // clear outputs
self.output_map self.backend_data
.output_map
.borrow_mut() .borrow_mut()
.retain(|output| output.device_id != device); .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(); let _device = backend_data.event_dispatcher.into_source_inner();
// don't use hardware acceleration anymore, if this was the primary gpu // don't use hardware acceleration anymore, if this was the primary gpu
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
{ {
if _device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { if _device.dev_path().and_then(|path| path.canonicalize().ok())
*self.egl_buffer_reader.borrow_mut() = None; == self.backend_data.primary_gpu
{
*self.egl_reader.borrow_mut() = None;
} }
} }
debug!(self.logger, "Dropping device"); debug!(self.log, "Dropping device");
} }
} }
} }

View File

@ -15,13 +15,13 @@ use smithay::{
use slog::Logger; use slog::Logger;
use crate::drawing::*; use crate::drawing::*;
use crate::state::AnvilState; use crate::state::{AnvilState, Backend};
pub struct WinitData; pub struct WinitData;
impl Default for WinitData { impl Backend for WinitData {
fn default() -> WinitData { fn seat_name(&self) -> String {
WinitData String::from("winit")
} }
} }
@ -54,10 +54,9 @@ pub fn run_winit(
let mut state = AnvilState::init( let mut state = AnvilState::init(
display.clone(), display.clone(),
event_loop.handle(), event_loop.handle(),
WinitData,
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
Rc::new(RefCell::new(reader.clone())), Rc::new(RefCell::new(reader.clone())),
None,
None,
log.clone(), log.clone(),
); );