diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs new file mode 100644 index 0000000..e52cafe --- /dev/null +++ b/anvil/src/input_handler.rs @@ -0,0 +1,321 @@ +use std::cell::RefCell; +use std::process::Command; +use std::rc::Rc; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; + +use slog::Logger; + +#[cfg(feature = "tty_launch")] +use smithay::backend::session::auto::AutoSession; +use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, + PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, + PointerMotionEvent}; +use smithay::wayland::seat::{keysyms as xkb, KeyboardHandle, Keysym, ModifiersState, PointerHandle}; +use smithay::wayland_server::protocol::wl_pointer; + +use shell::MyWindowMap; + +pub struct AnvilInputHandler { + log: Logger, + pointer: PointerHandle, + keyboard: KeyboardHandle, + window_map: Rc>, + pointer_location: Rc>, + screen_size: (u32, u32), + serial: u32, + #[cfg(feature = "tty_launch")] + session: Option, + running: Arc, +} + +impl AnvilInputHandler { + pub fn new( + log: Logger, + pointer: PointerHandle, + keyboard: KeyboardHandle, + window_map: Rc>, + screen_size: (u32, u32), + running: Arc, + pointer_location: Rc>, + ) -> AnvilInputHandler { + AnvilInputHandler { + log, + pointer, + keyboard, + window_map, + screen_size, + running, + pointer_location, + serial: 1, + #[cfg(feature = "tty_launch")] + session: None, + } + } + + #[cfg(feature = "tty_launch")] + pub fn new_with_session( + log: Logger, + pointer: PointerHandle, + keyboard: KeyboardHandle, + window_map: Rc>, + screen_size: (u32, u32), + running: Arc, + pointer_location: Rc>, + session: AutoSession, + ) -> AnvilInputHandler { + AnvilInputHandler { + log, + pointer, + keyboard, + window_map, + screen_size, + running, + pointer_location, + serial: 1, + session: Some(session), + } + } + + fn next_serial(&mut self) -> u32 { + self.serial += 1; + self.serial + } +} + +impl InputHandler for AnvilInputHandler { + fn on_seat_created(&mut self, _: &input::Seat) { + /* currently we just create a single static one */ + } + + fn on_seat_destroyed(&mut self, _: &input::Seat) { + /* currently we just create a single static one */ + } + + fn on_seat_changed(&mut self, _: &input::Seat) { + /* currently we just create a single static one */ + } + + fn on_keyboard_key(&mut self, _: &input::Seat, evt: B::KeyboardKeyEvent) { + let keycode = evt.key_code(); + let state = evt.state(); + debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state)); + let serial = self.next_serial(); + let log = &self.log; + let time = Event::time(&evt); + let mut action = KeyAction::None; + self.keyboard + .input(keycode, state, serial, time, |modifiers, keysym| { + debug!(log, "keysym"; + "state" => format!("{:?}", state), + "mods" => format!("{:?}", modifiers), + "keysym" => ::xkbcommon::xkb::keysym_get_name(keysym) + ); + action = process_keyboard_shortcut(modifiers, keysym); + // forward to client only if action == KeyAction::Forward + // both for pressed and released, to avoid inconsistencies + if let KeyAction::Forward = action { + true + } else { + false + } + }); + if let KeyState::Released = state { + // only process special actions on key press, not release + return; + } + match action { + KeyAction::Quit => { + info!(self.log, "Quitting."); + self.running.store(false, Ordering::SeqCst); + } + #[cfg(feature = "tty_lauch")] + KeyAction::VtSwitch(vt) => if let Some(ref mut session) = self.session { + info!(log, "Trying to switch to vt {}", vt); + if let Err(err) = session.change_vt(vt) { + error!(log, "Error switching to vt {}: {}", vt, err); + } + }, + KeyAction::Run(cmd) => { + info!(self.log, "Starting program"; "cmd" => cmd.clone()); + if let Err(e) = Command::new(&cmd).spawn() { + error!(log, + "Failed to start program"; + "cmd" => cmd, + "err" => format!("{:?}", e) + ); + } + } + _ => (), + } + } + + fn on_pointer_move(&mut self, _: &input::Seat, evt: B::PointerMotionEvent) { + let (x, y) = (evt.delta_x(), evt.delta_y()); + let serial = self.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 so self.screen_size is relevant + location.0 = (location.0).max(0.0).min(self.screen_size.0 as f64); + location.1 = (location.1).max(0.0).min(self.screen_size.1 as f64); + let under = self.window_map + .borrow() + .get_surface_under((location.0, location.1)); + self.pointer.motion( + under.as_ref().map(|&(ref s, (x, y))| (s, x, y)), + serial, + evt.time(), + ); + } + + fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: B::PointerMotionAbsoluteEvent) { + // different cases depending on the context: + let (x, y) = { + #[cfg(feature = "tty_launch")] + { + if self.session.is_some() { + // we are started on a tty + let (ux, uy) = evt.position_transformed(self.screen_size); + (ux as f64, uy as f64) + } else { + // we are started in winit + evt.position() + } + } + #[cfg(not(feature = "tty_launch"))] + { + evt.position() + } + }; + *self.pointer_location.borrow_mut() = (x, y); + let serial = self.next_serial(); + let under = self.window_map + .borrow() + .get_surface_under((x as f64, y as f64)); + self.pointer.motion( + under.as_ref().map(|&(ref s, (x, y))| (s, x, y)), + serial, + evt.time(), + ); + } + + fn on_pointer_button(&mut self, _: &input::Seat, evt: B::PointerButtonEvent) { + let serial = self.next_serial(); + let button = match evt.button() { + input::MouseButton::Left => 0x110, + input::MouseButton::Right => 0x111, + input::MouseButton::Middle => 0x112, + input::MouseButton::Other(b) => b as u32, + }; + let state = match evt.state() { + input::MouseButtonState::Pressed => { + // change the keyboard focus + let under = self.window_map + .borrow_mut() + .get_surface_and_bring_to_top(*self.pointer_location.borrow()); + self.keyboard + .set_focus(under.as_ref().map(|&(ref s, _)| s), serial); + wl_pointer::ButtonState::Pressed + } + input::MouseButtonState::Released => wl_pointer::ButtonState::Released, + }; + self.pointer.button(button, state, serial, evt.time()); + } + + fn on_pointer_axis(&mut self, _: &input::Seat, evt: B::PointerAxisEvent) { + let source = match evt.source() { + input::AxisSource::Continuous => wl_pointer::AxisSource::Continuous, + input::AxisSource::Finger => wl_pointer::AxisSource::Finger, + input::AxisSource::Wheel | input::AxisSource::WheelTilt => wl_pointer::AxisSource::Wheel, + }; + let horizontal_amount = evt.amount(&input::Axis::Horizontal) + .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0); + let vertical_amount = evt.amount(&input::Axis::Vertical) + .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0); + let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal); + let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical); + + { + let mut event = self.pointer.axis(); + event.source(source); + if horizontal_amount != 0.0 { + event.value( + wl_pointer::Axis::HorizontalScroll, + horizontal_amount, + evt.time(), + ); + if let Some(discrete) = horizontal_amount_discrete { + event.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32); + } + } else if source == wl_pointer::AxisSource::Finger { + event.stop(wl_pointer::Axis::HorizontalScroll, evt.time()); + } + if vertical_amount != 0.0 { + event.value( + wl_pointer::Axis::VerticalScroll, + vertical_amount, + evt.time(), + ); + if let Some(discrete) = vertical_amount_discrete { + event.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32); + } + } else if source == wl_pointer::AxisSource::Finger { + event.stop(wl_pointer::Axis::VerticalScroll, evt.time()); + } + event.done(); + } + } + + fn on_touch_down(&mut self, _: &input::Seat, _: B::TouchDownEvent) { + /* not done in this example */ + } + fn on_touch_motion(&mut self, _: &input::Seat, _: B::TouchMotionEvent) { + /* not done in this example */ + } + fn on_touch_up(&mut self, _: &input::Seat, _: B::TouchUpEvent) { + /* not done in this example */ + } + fn on_touch_cancel(&mut self, _: &input::Seat, _: B::TouchCancelEvent) { + /* not done in this example */ + } + fn on_touch_frame(&mut self, _: &input::Seat, _: B::TouchFrameEvent) { + /* not done in this example */ + } + fn on_input_config_changed(&mut self, _: &mut B::InputConfig) { + /* not done in this example */ + } +} + +/// Possible results of a keyboard action +enum KeyAction { + /// Quit the compositor + Quit, + /// Trigger a vt-switch + VtSwitch(i32), + /// run a command + Run(String), + /// Forward the key to the client + Forward, + /// Do nothing more + None, +} + +fn process_keyboard_shortcut(modifiers: &ModifiersState, keysym: Keysym) -> KeyAction { + if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace { + // ctrl+alt+backspace = quit + KeyAction::Quit + } else if modifiers.logo && keysym == xkb::KEY_q { + // logo + q = quit + KeyAction::Quit + } else if keysym >= xkb::KEY_XF86Switch_VT_1 && keysym <= xkb::KEY_XF86Switch_VT_12 { + // VTSwicth + KeyAction::VtSwitch((keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32) + } else if modifiers.logo && keysym == xkb::KEY_Return { + // run terminal + KeyAction::Run("weston-terminal".into()) + } else { + KeyAction::Forward + } +} diff --git a/anvil/src/main.rs b/anvil/src/main.rs index 6bfddfb..1cf5f91 100644 --- a/anvil/src/main.rs +++ b/anvil/src/main.rs @@ -9,7 +9,6 @@ extern crate slog_term; extern crate smithay; extern crate xkbcommon; - use slog::Drain; use smithay::wayland_server::Display; @@ -20,6 +19,14 @@ mod udev; mod window_map; #[cfg(feature = "winit")] mod winit; +mod input_handler; + +static POSSIBLE_BACKENDS: &'static [&'static str] = &[ + #[cfg(feature = "winit")] + "--winit", + #[cfg(feature = "tty_launch")] + "--tty", +]; fn main() { // A logger facility, here we use the terminal here @@ -30,21 +37,29 @@ fn main() { let (mut display, mut event_loop) = Display::new(); - #[cfg(feature = "winit")] - { - if let Ok(()) = winit::run_winit(&mut display, &mut event_loop, log.clone()) { - return; + let arg = ::std::env::args().skip(1).next(); + 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(&mut display, &mut event_loop, log.clone()) { + crit!(log, "Failed to initialize winit backend."); + } } - warn!(log, "Failed to initialize winit backend, skipping."); - } - - #[cfg(feature = "tty_launch")] - { - if let Ok(()) = udev::run_udev(display, event_loop, log.clone()) { - return; + #[cfg(feature = "tty_launch")] + Some("--tty") => { + info!(log, "Starting anvil on a tty"); + if let Err(()) = udev::run_udev(display, event_loop, log.clone()) { + crit!(log, "Failed to initialize tty backend."); + } + } + _ => { + println!("USAGE: anvil --backend"); + println!(""); + println!("Possible backends are:"); + for b in POSSIBLE_BACKENDS { + println!("\t{}", b); + } } - warn!(log, "Failed to initialize udev backend, skipping."); } - - error!(log, "Failed to initialize any backend."); } diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 3a8cdef..7122e5e 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::collections::HashMap; use std::io::Error as IoError; use std::path::PathBuf; -use std::process::Command; use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; @@ -23,8 +22,7 @@ use smithay::backend::drm::{DevPath, DrmBackend, DrmDevice, DrmHandler}; use smithay::backend::graphics::GraphicsBackend; use smithay::backend::graphics::egl::EGLGraphicsBackend; use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions, Format}; -use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, - PointerAxisEvent, PointerButtonEvent}; +use smithay::backend::input::InputBackend; use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}; use smithay::backend::session::{Session, SessionNotifier}; use smithay::backend::session::auto::{auto_session_bind, AutoSession}; @@ -32,219 +30,18 @@ use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, TraversalAction}; use smithay::wayland::compositor::roles::Role; use smithay::wayland::output::{Mode, Output, PhysicalProperties}; -use smithay::wayland::seat::{KeyboardHandle, PointerHandle, Seat, keysyms as xkb}; +use smithay::wayland::seat::Seat; use smithay::wayland::shm::init_shm_global; use smithay::wayland_server::{Display, EventLoop}; use smithay::wayland_server::commons::downcast_impl; -use smithay::wayland_server::protocol::{wl_output, wl_pointer}; -use smithay::input::{event, Device as LibinputDevice, Libinput}; -use smithay::input::event::keyboard::KeyboardEventTrait; +use smithay::wayland_server::protocol::wl_output; +use smithay::input::Libinput; use glium_drawer::GliumDrawer; -use shell::{init_shell, MyWindowMap, Buffer, Roles, SurfaceData}; - -struct LibinputInputHandler { - log: Logger, - pointer: PointerHandle, - keyboard: KeyboardHandle, - window_map: Rc>, - pointer_location: Rc>, - screen_size: (u32, u32), - serial: u32, - session: AutoSession, - running: Arc, -} - -impl LibinputInputHandler { - fn next_serial(&mut self) -> u32 { - self.serial += 1; - self.serial - } -} - -impl InputHandler for LibinputInputHandler { - fn on_seat_created(&mut self, _: &input::Seat) { - /* we just create a single static one */ - } - fn on_seat_destroyed(&mut self, _: &input::Seat) { - /* we just create a single static one */ - } - fn on_seat_changed(&mut self, _: &input::Seat) { - /* we just create a single static one */ - } - fn on_keyboard_key(&mut self, _: &input::Seat, evt: event::keyboard::KeyboardKeyEvent) { - let keycode = evt.key(); - let state = evt.state(); - debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state)); - let serial = self.next_serial(); - - // we cannot borrow `self` into the closure, because we need self.keyboard. - // but rust does not borrow all fields separately, so we need to do that manually... - let running = &self.running; - let mut session = &mut self.session; - let log = &self.log; - let time = Event::time(&evt); - self.keyboard - .input(keycode, state, serial, time, move |modifiers, keysym| { - debug!(log, "keysym"; - "state" => format!("{:?}", state), - "mods" => format!("{:?}", modifiers), - "keysym" => ::xkbcommon::xkb::keysym_get_name(keysym) - ); - if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace - && state == KeyState::Pressed - { - info!(log, "Stopping example using Ctrl+Alt+Backspace"); - running.store(false, Ordering::SeqCst); - false - } else if modifiers.logo && keysym == xkb::KEY_q { - info!(log, "Stopping example using Logo+Q"); - running.store(false, Ordering::SeqCst); - false - } else if modifiers.ctrl && modifiers.alt && keysym >= xkb::KEY_XF86Switch_VT_1 - && keysym <= xkb::KEY_XF86Switch_VT_12 - && state == KeyState::Pressed - { - let vt = (keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32; - info!(log, "Trying to switch to vt {}", vt); - if let Err(err) = session.change_vt(vt) { - error!(log, "Error switching to vt {}: {}", vt, err); - } - false - } else if modifiers.logo && keysym == xkb::KEY_Return && state == KeyState::Pressed { - info!(log, "Launching terminal"); - let _ = Command::new("weston-terminal").spawn(); - false - } else { - true - } - }); - } - fn on_pointer_move(&mut self, _: &input::Seat, evt: event::pointer::PointerMotionEvent) { - let (x, y) = (evt.dx(), evt.dy()); - let serial = self.next_serial(); - let mut location = self.pointer_location.borrow_mut(); - location.0 += x; - location.1 += y; - let under = self.window_map - .borrow() - .get_surface_under((location.0, location.1)); - self.pointer.motion( - under.as_ref().map(|&(ref s, (x, y))| (s, x, y)), - serial, - evt.time(), - ); - } - fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: event::pointer::PointerMotionAbsoluteEvent) { - let (x, y) = ( - evt.absolute_x_transformed(self.screen_size.0), - evt.absolute_y_transformed(self.screen_size.1), - ); - *self.pointer_location.borrow_mut() = (x, y); - let serial = self.next_serial(); - let under = self.window_map.borrow().get_surface_under((x, y)); - self.pointer.motion( - under.as_ref().map(|&(ref s, (x, y))| (s, x, y)), - serial, - evt.time(), - ); - } - fn on_pointer_button(&mut self, _: &input::Seat, evt: event::pointer::PointerButtonEvent) { - let serial = self.next_serial(); - let button = evt.button(); - let state = match evt.state() { - input::MouseButtonState::Pressed => { - // change the keyboard focus - let under = self.window_map - .borrow_mut() - .get_surface_and_bring_to_top(*self.pointer_location.borrow()); - self.keyboard - .set_focus(under.as_ref().map(|&(ref s, _)| s), serial); - wl_pointer::ButtonState::Pressed - } - input::MouseButtonState::Released => wl_pointer::ButtonState::Released, - }; - self.pointer.button(button, state, serial, evt.time()); - } - fn on_pointer_axis(&mut self, _: &input::Seat, evt: event::pointer::PointerAxisEvent) { - let source = match evt.source() { - input::AxisSource::Continuous => wl_pointer::AxisSource::Continuous, - input::AxisSource::Finger => wl_pointer::AxisSource::Finger, - input::AxisSource::Wheel | input::AxisSource::WheelTilt => { - wl_pointer::AxisSource::Wheel - } - }; - let horizontal_amount = evt.amount(&input::Axis::Horizontal) - .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0); - let vertical_amount = evt.amount(&input::Axis::Vertical) - .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0); - let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal); - let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical); - - { - let mut event = self.pointer.axis(); - event.source(source); - if horizontal_amount != 0.0 { - event.value( - wl_pointer::Axis::HorizontalScroll, - horizontal_amount, - evt.time(), - ); - if let Some(discrete) = horizontal_amount_discrete { - event.discrete( - wl_pointer::Axis::HorizontalScroll, - discrete as i32, - ); - } - } else if source == wl_pointer::AxisSource::Finger { - event.stop( - wl_pointer::Axis::HorizontalScroll, - evt.time(), - ); - } - if vertical_amount != 0.0 { - event.value( - wl_pointer::Axis::VerticalScroll, - vertical_amount, - evt.time(), - ); - if let Some(discrete) = vertical_amount_discrete { - event.discrete( - wl_pointer::Axis::VerticalScroll, - discrete as i32, - ); - } - } else if source == wl_pointer::AxisSource::Finger { - event.stop( - wl_pointer::Axis::VerticalScroll, - evt.time(), - ); - } - event.done(); - } - } - fn on_touch_down(&mut self, _: &input::Seat, _: event::touch::TouchDownEvent) { - /* not done in this example */ - } - fn on_touch_motion(&mut self, _: &input::Seat, _: event::touch::TouchMotionEvent) { - /* not done in this example */ - } - fn on_touch_up(&mut self, _: &input::Seat, _: event::touch::TouchUpEvent) { - /* not done in this example */ - } - fn on_touch_cancel(&mut self, _: &input::Seat, _: event::touch::TouchCancelEvent) { - /* not done in this example */ - } - fn on_touch_frame(&mut self, _: &input::Seat, _: event::touch::TouchFrameEvent) { - /* not done in this example */ - } - fn on_input_config_changed(&mut self, _: &mut [LibinputDevice]) { - /* not done in this example */ - } -} - -pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> Result<(),()> { +use shell::{init_shell, Buffer, MyWindowMap, Roles, SurfaceData}; +use input_handler::AnvilInputHandler; +pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> Result<(), ()> { let name = display.add_socket_auto().unwrap().into_string().unwrap(); info!(log, "Listening on wayland socket"; "name" => name.clone()); ::std::env::set_var("WAYLAND_DISPLAY", name); @@ -358,17 +155,16 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> let libinput_session_id = notifier.register(&mut libinput_context); libinput_context.udev_assign_seat(&seat).unwrap(); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); - libinput_backend.set_handler(LibinputInputHandler { - log: log.clone(), + libinput_backend.set_handler(AnvilInputHandler::new_with_session( + log.clone(), pointer, keyboard, - window_map: window_map.clone(), + window_map.clone(), + (w, h), + running.clone(), pointer_location, - screen_size: (w, h), - serial: 0, - session: session, - running: running.clone(), - }); + session, + )); let libinput_event_source = libinput_bind(libinput_backend, event_loop.token()) .map_err(|(err, _)| err) .unwrap(); diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 73fd298..2c7540e 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -1,161 +1,27 @@ use std::cell::RefCell; use std::rc::Rc; +use std::sync::Arc; +use std::sync::atomic::AtomicBool; use smithay::wayland::shm::init_shm_global; -use smithay::wayland::seat::{KeyboardHandle, PointerHandle, Seat}; +use smithay::wayland::seat::Seat; use smithay::wayland::compositor::{SubsurfaceRole, TraversalAction}; use smithay::wayland::compositor::roles::Role; use smithay::wayland::output::{Mode, Output, PhysicalProperties}; -use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyboardKeyEvent, PointerAxisEvent, - PointerButtonEvent, PointerMotionAbsoluteEvent}; +use smithay::backend::input::InputBackend; use smithay::backend::winit; use smithay::backend::graphics::egl::EGLGraphicsBackend; use smithay::backend::graphics::egl::wayland::{EGLWaylandExtensions, Format}; use smithay::wayland_server::{Display, EventLoop}; -use smithay::wayland_server::protocol::{wl_pointer, wl_output}; +use smithay::wayland_server::protocol::wl_output; use glium::Surface; use slog::Logger; use glium_drawer::GliumDrawer; -use shell::{init_shell, MyWindowMap, Buffer}; - -struct WinitInputHandler { - log: Logger, - pointer: PointerHandle, - keyboard: KeyboardHandle, - window_map: Rc>, - pointer_location: (f64, f64), - serial: u32, -} - -impl WinitInputHandler { - fn next_serial(&mut self) -> u32 { - self.serial += 1; - self.serial - } -} - -impl InputHandler for WinitInputHandler { - fn on_seat_created(&mut self, _: &input::Seat) { - /* never happens with winit */ - } - fn on_seat_destroyed(&mut self, _: &input::Seat) { - /* never happens with winit */ - } - fn on_seat_changed(&mut self, _: &input::Seat) { - /* never happens with winit */ - } - fn on_keyboard_key(&mut self, _: &input::Seat, evt: winit::WinitKeyboardInputEvent) { - let keycode = evt.key_code(); - let state = evt.state(); - debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state)); - let serial = self.next_serial(); - self.keyboard - .input(keycode, state, serial, evt.time(), |_, _| true); - } - fn on_pointer_move(&mut self, _: &input::Seat, _: input::UnusedEvent) { - /* never happens with winit */ - } - fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: winit::WinitMouseMovedEvent) { - // on winit, mouse events are already in pixel coordinates - let (x, y) = evt.position(); - self.pointer_location = (x, y); - let serial = self.next_serial(); - let under = self.window_map.borrow().get_surface_under((x, y)); - self.pointer.motion( - under.as_ref().map(|&(ref s, (x, y))| (s, x, y)), - serial, - evt.time(), - ); - } - fn on_pointer_button(&mut self, _: &input::Seat, evt: winit::WinitMouseInputEvent) { - let serial = self.next_serial(); - let button = match evt.button() { - input::MouseButton::Left => 0x110, - input::MouseButton::Right => 0x111, - input::MouseButton::Middle => 0x112, - input::MouseButton::Other(b) => b as u32, - }; - let state = match evt.state() { - input::MouseButtonState::Pressed => { - // change the keyboard focus - let under = self.window_map - .borrow_mut() - .get_surface_and_bring_to_top(self.pointer_location); - self.keyboard - .set_focus(under.as_ref().map(|&(ref s, _)| s), serial); - wl_pointer::ButtonState::Pressed - } - input::MouseButtonState::Released => wl_pointer::ButtonState::Released, - }; - self.pointer.button(button, state, serial, evt.time()); - } - fn on_pointer_axis(&mut self, _: &input::Seat, evt: winit::WinitMouseWheelEvent) { - let source = match evt.source() { - input::AxisSource::Continuous => wl_pointer::AxisSource::Continuous, - input::AxisSource::Wheel => wl_pointer::AxisSource::Wheel, - _ => unreachable!(), //winit does not have more specific sources - }; - let horizontal_amount = evt.amount(&input::Axis::Horizontal) - .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0); - let vertical_amount = evt.amount(&input::Axis::Vertical) - .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0); - let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal); - let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical); - - { - let mut event = self.pointer.axis(); - event.source(source); - if horizontal_amount != 0.0 { - event.value( - wl_pointer::Axis::HorizontalScroll, - horizontal_amount, - evt.time(), - ); - if let Some(discrete) = horizontal_amount_discrete { - event.discrete( - wl_pointer::Axis::HorizontalScroll, - discrete as i32, - ); - } - } - if vertical_amount != 0.0 { - event.value( - wl_pointer::Axis::VerticalScroll, - vertical_amount, - evt.time(), - ); - if let Some(discrete) = vertical_amount_discrete { - event.discrete( - wl_pointer::Axis::VerticalScroll, - discrete as i32, - ); - } - } - event.done(); - } - } - fn on_touch_down(&mut self, _: &input::Seat, _: winit::WinitTouchStartedEvent) { - /* not done in this example */ - } - fn on_touch_motion(&mut self, _: &input::Seat, _: winit::WinitTouchMovedEvent) { - /* not done in this example */ - } - fn on_touch_up(&mut self, _: &input::Seat, _: winit::WinitTouchEndedEvent) { - /* not done in this example */ - } - fn on_touch_cancel(&mut self, _: &input::Seat, _: winit::WinitTouchCancelledEvent) { - /* not done in this example */ - } - fn on_touch_frame(&mut self, _: &input::Seat, _: input::UnusedEvent) { - /* never happens with winit */ - } - fn on_input_config_changed(&mut self, _: &mut ()) { - /* never happens with winit */ - } -} +use shell::{init_shell, Buffer}; +use input_handler::AnvilInputHandler; pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) -> Result<(), ()> { let (renderer, mut input) = winit::init(log.clone()).map_err(|_| ())?; @@ -176,6 +42,8 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) info!(log, "Listening on wayland socket"; "name" => name.clone()); ::std::env::set_var("WAYLAND_DISPLAY", name); + let running = Arc::new(AtomicBool::new(true)); + /* * Initialize the globals */ @@ -185,12 +53,7 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) let (compositor_token, _, _, window_map) = init_shell(display, event_loop.token(), log.clone(), egl_display); - let (mut seat, _) = Seat::new( - display, - event_loop.token(), - "winit".into(), - log.clone(), - ); + let (mut seat, _) = Seat::new(display, event_loop.token(), "winit".into(), log.clone()); let pointer = seat.add_pointer(); let keyboard = seat.add_keyboard("", "fr", "oss", None, 1000, 500) @@ -225,14 +88,15 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) refresh: 60_000, }); - input.set_handler(WinitInputHandler { - log: log.clone(), + input.set_handler(AnvilInputHandler::new( + log.clone(), pointer, keyboard, - window_map: window_map.clone(), - pointer_location: (0.0, 0.0), - serial: 0, - }); + window_map.clone(), + (0, 0), + running.clone(), + Rc::new(RefCell::new((0.0, 0.0))), + )); info!(log, "Initialization completed, starting the main loop."); @@ -332,4 +196,4 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) window_map.borrow_mut().refresh(); } -} \ No newline at end of file +} diff --git a/src/wayland/seat/mod.rs b/src/wayland/seat/mod.rs index 35ceb58..d45d229 100644 --- a/src/wayland/seat/mod.rs +++ b/src/wayland/seat/mod.rs @@ -59,7 +59,7 @@ use std::sync::{Arc, Mutex}; mod keyboard; mod pointer; -pub use self::keyboard::{Error as KeyboardError, KeyboardHandle, ModifiersState, Keysym, keysyms}; +pub use self::keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState}; pub use self::pointer::{PointerAxisHandle, PointerHandle}; use wayland_server::{Display, Global, LoopToken, NewResource, Resource}; use wayland_server::protocol::wl_seat;