anvil: reorganize platform-specific values
This commit is contained in:
parent
3f01f978f8
commit
4bf6bfa08d
|
@ -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"
|
||||
|
|
|
@ -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<Backend> AnvilState<Backend> {
|
||||
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
|
||||
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) {
|
||||
fn keyboard_key_to_action<B: InputBackend>(&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<Backend> AnvilState<Backend> {
|
|||
});
|
||||
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<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) {
|
||||
|
@ -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
|
||||
#[derive(Debug)]
|
||||
enum KeyAction {
|
||||
/// Quit the compositor
|
||||
Quit,
|
||||
|
|
|
@ -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<Backend> {
|
||||
pub backend: Backend,
|
||||
pub struct AnvilState<BackendData> {
|
||||
pub backend_data: BackendData,
|
||||
pub socket_name: String,
|
||||
pub running: Arc<AtomicBool>,
|
||||
pub display: Rc<RefCell<Display>>,
|
||||
pub handle: LoopHandle<'static, AnvilState<Backend>>,
|
||||
pub handle: LoopHandle<'static, AnvilState<BackendData>>,
|
||||
pub ctoken: CompositorToken<crate::shell::Roles>,
|
||||
pub window_map: Rc<RefCell<crate::window_map::WindowMap<crate::shell::Roles>>>,
|
||||
pub dnd_icon: Arc<Mutex<Option<WlSurface>>>,
|
||||
|
@ -48,56 +44,48 @@ pub struct AnvilState<Backend> {
|
|||
pub keyboard: KeyboardHandle,
|
||||
pub pointer_location: Rc<RefCell<(f64, f64)>>,
|
||||
pub cursor_status: Arc<Mutex<CursorImageStatus>>,
|
||||
#[cfg(feature = "udev")]
|
||||
pub output_map: Option<Rc<RefCell<Vec<MyOutput>>>>,
|
||||
pub seat_name: String,
|
||||
#[cfg(feature = "udev")]
|
||||
pub session: Option<AutoSession>,
|
||||
#[cfg(feature = "egl")]
|
||||
pub egl_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
||||
// things we must keep alive
|
||||
_wayland_event_source: RegistrationToken,
|
||||
#[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(
|
||||
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 = "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,
|
||||
) -> AnvilState<Backend> {
|
||||
) -> AnvilState<BackendData> {
|
||||
// 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<Backend>| {
|
||||
move |_, _, state: &mut AnvilState<BackendData>| {
|
||||
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!(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);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.expect("Failed to init the wayland event source.");
|
||||
|
||||
// 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::<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"))]
|
||||
let shell_handles = init_shell(&mut display.borrow_mut(), log.clone());
|
||||
|
||||
|
@ -132,14 +120,7 @@ impl<Backend: Default + 'static> AnvilState<Backend> {
|
|||
);
|
||||
|
||||
// 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<Backend: Default + 'static> AnvilState<Backend> {
|
|||
};
|
||||
|
||||
AnvilState {
|
||||
backend: Default::default(),
|
||||
backend_data,
|
||||
running: Arc::new(AtomicBool::new(true)),
|
||||
display,
|
||||
handle,
|
||||
|
@ -187,14 +168,14 @@ impl<Backend: Default + 'static> AnvilState<Backend> {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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<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 {
|
||||
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::<LibinputSessionInterface<AutoSession>>(
|
||||
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,28 +279,7 @@ struct BackendData {
|
|||
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>,
|
||||
gbm: &GbmDevice<SessionFd>,
|
||||
egl: &EGLDisplay,
|
||||
|
@ -313,7 +288,7 @@ impl UdevHandlerImpl {
|
|||
output_map: &mut Vec<MyOutput>,
|
||||
signaler: &Signaler<SessionSignal>,
|
||||
logger: &::slog::Logger,
|
||||
) -> HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>> {
|
||||
) -> HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>> {
|
||||
// Get a set of all modesetting resource handles (excluding planes):
|
||||
let res_handles = device.resource_handles().unwrap();
|
||||
|
||||
|
@ -372,8 +347,8 @@ impl UdevHandlerImpl {
|
|||
}
|
||||
};
|
||||
surface.link(signaler.clone());
|
||||
let renderer =
|
||||
match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.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);
|
||||
|
@ -397,13 +372,13 @@ impl UdevHandlerImpl {
|
|||
}
|
||||
|
||||
backends
|
||||
}
|
||||
}
|
||||
|
||||
impl UdevHandlerImpl {
|
||||
impl AnvilState<UdevData> {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue