diff --git a/anvil/src/main.rs b/anvil/src/main.rs index 7ba7dcf..f6d28cc 100644 --- a/anvil/src/main.rs +++ b/anvil/src/main.rs @@ -7,20 +7,10 @@ extern crate slog; #[macro_use(define_roles)] extern crate smithay; -use std::{ - cell::RefCell, - rc::Rc, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, -}; +use std::{cell::RefCell, rc::Rc}; use slog::Drain; -use smithay::reexports::{ - calloop::{generic::Generic, mio::Interest, EventLoop}, - wayland_server::Display, -}; +use smithay::reexports::{calloop::EventLoop, wayland_server::Display}; #[macro_use] mod shaders; @@ -29,12 +19,15 @@ mod glium_drawer; mod input_handler; mod shell; mod shm_load; +mod state; #[cfg(feature = "udev")] mod udev; mod window_map; #[cfg(feature = "winit")] mod winit; +use state::AnvilState; + static POSSIBLE_BACKENDS: &[&str] = &[ #[cfg(feature = "winit")] "--winit : Run anvil as a X11 or Wayland client using winit.", @@ -42,18 +35,6 @@ static POSSIBLE_BACKENDS: &[&str] = &[ "--tty-udev : Run anvil as a tty udev client (requires root if without logind).", ]; -pub struct AnvilState { - pub running: Arc, -} - -impl Default for AnvilState { - fn default() -> AnvilState { - AnvilState { - running: Arc::new(AtomicBool::new(true)), - } - } -} - fn main() { // A logger facility, here we use the terminal here let log = slog::Logger::root( @@ -61,40 +42,22 @@ fn main() { o!(), ); - let event_loop = EventLoop::::new().unwrap(); + let mut event_loop = EventLoop::::new().unwrap(); let display = Rc::new(RefCell::new(Display::new())); - // Glue for event dispatching - let mut wayland_event_source = Generic::from_raw_fd(display.borrow().get_poll_fd()); - wayland_event_source.set_interest(Interest::READABLE); - let _wayland_source = event_loop.handle().insert_source(wayland_event_source, { - 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(_) => {} - Err(e) => { - error!(log, "I/O error on the Wayland display: {}", e); - state.running.store(false, Ordering::SeqCst); - } - } - } - }); - let arg = ::std::env::args().nth(1); match arg.as_ref().map(|s| &s[..]) { #[cfg(feature = "winit")] Some("--winit") => { info!(log, "Starting anvil with winit backend"); - if let Err(()) = winit::run_winit(display, event_loop, log.clone()) { + if let Err(()) = winit::run_winit(display, &mut event_loop, log.clone()) { crit!(log, "Failed to initialize winit backend."); } } #[cfg(feature = "udev")] Some("--tty-udev") => { info!(log, "Starting anvil on a tty using udev"); - if let Err(()) = udev::run_udev(display, event_loop, log.clone()) { + if let Err(()) = udev::run_udev(display, &mut event_loop, log.clone()) { crit!(log, "Failed to initialize tty backend."); } } diff --git a/anvil/src/state.rs b/anvil/src/state.rs new file mode 100644 index 0000000..5248500 --- /dev/null +++ b/anvil/src/state.rs @@ -0,0 +1,117 @@ +use std::{ + cell::RefCell, + rc::Rc, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, Mutex, + }, +}; + +use smithay::{ + reexports::{ + calloop::{ + generic::{Generic, SourceRawFd}, + mio::Interest, + LoopHandle, Source, + }, + wayland_server::{protocol::wl_surface::WlSurface, Display}, + }, + wayland::{ + compositor::CompositorToken, + data_device::{default_action_chooser, init_data_device, DataDeviceEvent}, + shm::init_shm_global, + }, +}; + +use crate::{buffer_utils::BufferUtils, shell::init_shell}; + +pub struct AnvilState { + pub socket_name: String, + pub running: Arc, + pub display: Rc>, + pub handle: LoopHandle, + pub ctoken: CompositorToken, + pub window_map: Rc>>, + pub dnd_icon: Arc>>, + pub log: slog::Logger, + // things we must keep alive + _wayland_event_source: Source>, +} + +impl AnvilState { + pub fn init( + display: Rc>, + handle: LoopHandle, + buffer_utils: BufferUtils, + log: slog::Logger, + ) -> AnvilState { + // init the wayland connection + let _wayland_event_source = handle + .insert_source( + { + let mut source = Generic::from_raw_fd(display.borrow().get_poll_fd()); + source.set_interest(Interest::READABLE); + source + }, + { + 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(_) => {} + Err(e) => { + error!(log, "I/O error on the Wayland display: {}", e); + state.running.store(false, Ordering::SeqCst); + } + } + } + }, + ) + .expect("Failed to init the wayland event source."); + + init_shm_global(&mut display.borrow_mut(), vec![], log.clone()); + + let (ctoken, _, _, window_map) = init_shell(&mut display.borrow_mut(), buffer_utils, log.clone()); + + let socket_name = display + .borrow_mut() + .add_socket_auto() + .unwrap() + .into_string() + .unwrap(); + info!(log, "Listening on wayland socket"; "name" => socket_name.clone()); + ::std::env::set_var("WAYLAND_DISPLAY", &socket_name); + + let dnd_icon = Arc::new(Mutex::new(None)); + + let dnd_icon2 = dnd_icon.clone(); + init_data_device( + &mut display.borrow_mut(), + move |event| match event { + DataDeviceEvent::DnDStarted { icon, .. } => { + *dnd_icon2.lock().unwrap() = icon; + } + DataDeviceEvent::DnDDropped => { + *dnd_icon2.lock().unwrap() = None; + } + _ => {} + }, + default_action_chooser, + ctoken, + log.clone(), + ); + + AnvilState { + running: Arc::new(AtomicBool::new(true)), + display, + handle, + ctoken, + window_map, + dnd_icon, + log, + socket_name, + _wayland_event_source, + } + } +} diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index b6fd370..345edfd 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -53,17 +53,16 @@ use smithay::{ }, wayland::{ compositor::CompositorToken, - data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent}, + data_device::set_data_device_focus, output::{Mode, Output, PhysicalProperties}, seat::{CursorImageStatus, Seat, XkbConfig}, - shm::init_shm_global, }, }; use crate::buffer_utils::BufferUtils; use crate::glium_drawer::GliumDrawer; use crate::input_handler::AnvilInputHandler; -use crate::shell::{init_shell, MyWindowMap, Roles}; +use crate::shell::{MyWindowMap, Roles}; use crate::AnvilState; use smithay::backend::drm::gbm::GbmSurface; @@ -84,7 +83,7 @@ type RenderSurface = pub fn run_udev( display: Rc>, - mut event_loop: EventLoop, + event_loop: &mut EventLoop, log: Logger, ) -> Result<(), ()> { let name = display @@ -107,10 +106,7 @@ pub fn run_udev( /* * Initialize the compositor */ - init_shm_global(&mut display.borrow_mut(), vec![], log.clone()); - - let (compositor_token, _, _, window_map) = - init_shell(&mut display.borrow_mut(), buffer_utils, log.clone()); + let mut state = AnvilState::init(display.clone(), event_loop.handle(), buffer_utils, log.clone()); /* * Initialize session @@ -119,11 +115,8 @@ pub fn run_udev( let (udev_observer, udev_notifier) = notify_multiplexer(); let udev_session_id = notifier.register(udev_observer); - let mut state = AnvilState::default(); - let pointer_location = Rc::new(RefCell::new((0.0, 0.0))); let cursor_status = Arc::new(Mutex::new(CursorImageStatus::Default)); - let dnd_icon = Arc::new(Mutex::new(None)); /* * Initialize the udev backend @@ -135,18 +128,18 @@ pub fn run_udev( let bytes = include_bytes!("../resources/cursor2.rgba"); let udev_backend = UdevBackend::new( UdevHandlerImpl { - compositor_token, + compositor_token: state.ctoken, #[cfg(feature = "egl")] egl_buffer_reader, session: session.clone(), backends: HashMap::new(), display: display.clone(), primary_gpu, - window_map: window_map.clone(), + window_map: state.window_map.clone(), pointer_location: pointer_location.clone(), pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(), cursor_status: cursor_status.clone(), - dnd_icon: dnd_icon.clone(), + dnd_icon: state.dnd_icon.clone(), loop_handle: event_loop.handle(), notifier: udev_notifier, logger: log.clone(), @@ -156,37 +149,17 @@ pub fn run_udev( ) .map_err(|_| ())?; - /* - * Initialize wayland clipboard - */ - - init_data_device( - &mut display.borrow_mut(), - move |event| match event { - DataDeviceEvent::DnDStarted { icon, .. } => { - *dnd_icon.lock().unwrap() = icon; - } - DataDeviceEvent::DnDDropped => { - *dnd_icon.lock().unwrap() = None; - } - _ => {} - }, - default_action_chooser, - compositor_token, - log.clone(), - ); - /* * Initialize wayland input object */ let (mut w_seat, _) = Seat::new( &mut display.borrow_mut(), session.seat(), - compositor_token, + state.ctoken, log.clone(), ); - let pointer = w_seat.add_pointer(compositor_token.clone(), move |new_status| { + let pointer = w_seat.add_pointer(state.ctoken.clone(), move |new_status| { *cursor_status.lock().unwrap() = new_status; }); let keyboard = w_seat @@ -239,7 +212,7 @@ pub fn run_udev( log.clone(), pointer, keyboard, - window_map.clone(), + state.window_map.clone(), (w, h), state.running.clone(), pointer_location, @@ -271,12 +244,12 @@ pub fn run_udev( state.running.store(false, Ordering::SeqCst); } else { display.borrow_mut().flush_clients(&mut state); - window_map.borrow_mut().refresh(); + state.window_map.borrow_mut().refresh(); } } // Cleanup stuff - window_map.borrow_mut().clear(); + state.window_map.borrow_mut().clear(); let mut notifier = session_event_source.unbind(); notifier.unregister(libinput_session_id); diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 8b48a3f..2bc4789 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -11,10 +11,9 @@ use smithay::{ wayland_server::{protocol::wl_output, Display}, }, wayland::{ - data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent}, + data_device::set_data_device_focus, output::{Mode, Output, PhysicalProperties}, seat::{CursorImageStatus, Seat, XkbConfig}, - shm::init_shm_global, }, }; @@ -23,12 +22,11 @@ use slog::Logger; use crate::buffer_utils::BufferUtils; use crate::glium_drawer::GliumDrawer; use crate::input_handler::AnvilInputHandler; -use crate::shell::init_shell; use crate::AnvilState; pub fn run_winit( display: Rc>, - mut event_loop: EventLoop, + event_loop: &mut EventLoop, log: Logger, ) -> Result<(), ()> { let (renderer, mut input) = winit::init(log.clone()).map_err(|_| ())?; @@ -54,56 +52,23 @@ pub fn run_winit( #[cfg(not(feature = "egl"))] let buffer_utils = BufferUtils::new(log.clone()); - let name = display - .borrow_mut() - .add_socket_auto() - .unwrap() - .into_string() - .unwrap(); - info!(log, "Listening on wayland socket"; "name" => name.clone()); - ::std::env::set_var("WAYLAND_DISPLAY", name); - - let mut state = AnvilState::default(); - /* * Initialize the globals */ - init_shm_global(&mut display.borrow_mut(), vec![], log.clone()); - - let (compositor_token, _, _, window_map) = - init_shell(&mut display.borrow_mut(), buffer_utils, log.clone()); - - let dnd_icon = Arc::new(Mutex::new(None)); - - let dnd_icon2 = dnd_icon.clone(); - init_data_device( - &mut display.borrow_mut(), - move |event| match event { - DataDeviceEvent::DnDStarted { icon, .. } => { - *dnd_icon2.lock().unwrap() = icon; - } - DataDeviceEvent::DnDDropped => { - *dnd_icon2.lock().unwrap() = None; - } - _ => {} - }, - default_action_chooser, - compositor_token, - log.clone(), - ); + let mut state = AnvilState::init(display.clone(), event_loop.handle(), buffer_utils, log.clone()); let (mut seat, _) = Seat::new( &mut display.borrow_mut(), "winit".into(), - compositor_token, + state.ctoken, log.clone(), ); let cursor_status = Arc::new(Mutex::new(CursorImageStatus::Default)); let cursor_status2 = cursor_status.clone(); - let pointer = seat.add_pointer(compositor_token.clone(), move |new_status| { + let pointer = seat.add_pointer(state.ctoken.clone(), move |new_status| { // TODO: hide winit system cursor when relevant *cursor_status2.lock().unwrap() = new_status }); @@ -148,7 +113,7 @@ pub fn run_winit( log.clone(), pointer, keyboard, - window_map.clone(), + state.window_map.clone(), (0, 0), state.running.clone(), pointer_location.clone(), @@ -166,15 +131,15 @@ pub fn run_winit( frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None); // draw the windows - drawer.draw_windows(&mut frame, &*window_map.borrow(), compositor_token); + drawer.draw_windows(&mut frame, &*state.window_map.borrow(), state.ctoken); let (x, y) = *pointer_location.borrow(); // draw the dnd icon if any { - let guard = dnd_icon.lock().unwrap(); + let guard = state.dnd_icon.lock().unwrap(); if let Some(ref surface) = *guard { if surface.as_ref().is_alive() { - drawer.draw_dnd_icon(&mut frame, surface, (x as i32, y as i32), compositor_token); + drawer.draw_dnd_icon(&mut frame, surface, (x as i32, y as i32), state.ctoken); } } } @@ -191,7 +156,7 @@ pub fn run_winit( } // draw as relevant if let CursorImageStatus::Image(ref surface) = *guard { - drawer.draw_cursor(&mut frame, surface, (x as i32, y as i32), compositor_token); + drawer.draw_cursor(&mut frame, surface, (x as i32, y as i32), state.ctoken); } } @@ -207,12 +172,12 @@ pub fn run_winit( state.running.store(false, Ordering::SeqCst); } else { display.borrow_mut().flush_clients(&mut state); - window_map.borrow_mut().refresh(); + state.window_map.borrow_mut().refresh(); } } // Cleanup stuff - window_map.borrow_mut().clear(); + state.window_map.borrow_mut().clear(); Ok(()) }