Get input working
This commit is contained in:
parent
c7682e77de
commit
96bb3570ba
|
@ -19,7 +19,7 @@ winit = { version = "0.8.2", optional = true }
|
|||
drm = { version = "^0.3.0", optional = true }
|
||||
gbm = { version = "^0.3.0", optional = true }
|
||||
glium = { version = "0.17.1", optional = true, default-features = false }
|
||||
input = { version = "0.3.0", optional = true }
|
||||
input = { version = "0.4.0", git = "https://github.com/Smithay/input.rs.git", branch = "feature/udev", optional = true }
|
||||
libudev = { git = "https://github.com/Drakulix/libudev-rs.git", branch = "feature/raw_ffi_access", optional = true }
|
||||
rental = "0.4.11"
|
||||
wayland-protocols = { version = "0.12.0", features = ["unstable_protocols", "server"] }
|
||||
|
|
Binary file not shown.
Binary file not shown.
227
examples/udev.rs
227
examples/udev.rs
|
@ -2,6 +2,8 @@ extern crate drm;
|
|||
#[macro_use]
|
||||
extern crate glium;
|
||||
extern crate rand;
|
||||
extern crate input as libinput;
|
||||
extern crate image;
|
||||
extern crate libudev;
|
||||
#[macro_use(define_roles)]
|
||||
extern crate smithay;
|
||||
|
@ -22,15 +24,24 @@ use drm::control::encoder::Info as EncoderInfo;
|
|||
use drm::control::crtc;
|
||||
use drm::result::Error as DrmError;
|
||||
use glium::Surface;
|
||||
use image::{ImageBuffer, Rgba};
|
||||
use libinput::{Libinput, Device as LibinputDevice, event};
|
||||
use libinput::event::keyboard::KeyboardEventTrait;
|
||||
use helpers::{init_shell, GliumDrawer, MyWindowMap, Roles, SurfaceData};
|
||||
use slog::{Drain, Logger};
|
||||
use smithay::backend::drm::{DrmBackend, DrmDevice, DrmHandler};
|
||||
use smithay::backend::graphics::GraphicsBackend;
|
||||
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||
use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyboardKeyEvent, KeyState, PointerButtonEvent,
|
||||
PointerAxisEvent};
|
||||
use smithay::backend::libinput::{LibinputInputBackend, libinput_bind, PointerAxisEvent as LibinputPointerAxisEvent, LibinputSessionInterface};
|
||||
use smithay::backend::udev::{UdevBackend, UdevHandler, udev_backend_bind};
|
||||
use smithay::backend::session::SessionNotifier;
|
||||
use smithay::backend::session::{Session, SessionNotifier};
|
||||
use smithay::backend::session::direct::{direct_session_bind, DirectSession};
|
||||
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};
|
||||
use smithay::wayland::shell::ShellState;
|
||||
use smithay::wayland::shm::init_shm_global;
|
||||
use std::cell::RefCell;
|
||||
|
@ -38,9 +49,121 @@ use std::collections::HashSet;
|
|||
use std::io::Error as IoError;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use wayland_server::{StateToken, StateProxy};
|
||||
use wayland_server::protocol::{wl_output, wl_pointer};
|
||||
|
||||
struct LibinputInputHandler {
|
||||
log: Logger,
|
||||
pointer: PointerHandle,
|
||||
keyboard: KeyboardHandle,
|
||||
window_map: Rc<RefCell<MyWindowMap>>,
|
||||
pointer_location: Arc<Mutex<(f64, f64)>>,
|
||||
screen_size: (u32, u32),
|
||||
serial: u32,
|
||||
running: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl LibinputInputHandler {
|
||||
fn next_serial(&mut self) -> u32 {
|
||||
self.serial += 1;
|
||||
self.serial
|
||||
}
|
||||
}
|
||||
|
||||
impl InputHandler<LibinputInputBackend> 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));
|
||||
|
||||
match (keycode, state) {
|
||||
(1 /*ESC*/, KeyState::Pressed) => {
|
||||
self.running.store(false, Ordering::SeqCst);
|
||||
},
|
||||
(keycode, state) => {
|
||||
let serial = self.next_serial();
|
||||
self.keyboard.input(keycode, state, serial, |_, _| 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.lock().unwrap();
|
||||
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.lock().unwrap() = (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.lock().unwrap());
|
||||
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: LibinputPointerAxisEvent) {
|
||||
let axis = match evt.axis() {
|
||||
input::Axis::Vertical => wayland_server::protocol::wl_pointer::Axis::VerticalScroll,
|
||||
input::Axis::Horizontal => wayland_server::protocol::wl_pointer::Axis::HorizontalScroll,
|
||||
};
|
||||
self.pointer.axis(axis, evt.amount(), evt.time());
|
||||
}
|
||||
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 */
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// A logger facility, here we use the terminal for this example
|
||||
|
@ -63,7 +186,7 @@ fn main() {
|
|||
* Initialize session on the current tty
|
||||
*/
|
||||
let (session, mut notifier) = DirectSession::new(None, log.clone()).unwrap();
|
||||
let session_token = event_loop.state().insert(session);
|
||||
let session = Arc::new(Mutex::new(session));
|
||||
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
let r = running.clone();
|
||||
|
@ -71,48 +194,124 @@ fn main() {
|
|||
r.store(false, Ordering::SeqCst);
|
||||
}).expect("Error setting Ctrl-C handler");
|
||||
|
||||
let pointer_location = Arc::new(Mutex::new((0.0, 0.0)));
|
||||
|
||||
/*
|
||||
* Initialize the udev backend
|
||||
*/
|
||||
let context = libudev::Context::new().unwrap();
|
||||
let bytes = include_bytes!("resources/cursor2.rgba");
|
||||
let udev
|
||||
= UdevBackend::new(&mut event_loop, &context, &session_token, UdevHandlerImpl {
|
||||
= UdevBackend::new(&mut event_loop, &context, session.clone(), UdevHandlerImpl {
|
||||
shell_state_token,
|
||||
compositor_token,
|
||||
window_map: window_map.clone(),
|
||||
pointer_location: pointer_location.clone(),
|
||||
pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(),
|
||||
logger: log.clone(),
|
||||
}, log.clone()).unwrap();
|
||||
|
||||
let udev_token = event_loop.state().insert(udev);
|
||||
let udev_session_id = notifier.register(udev_token.clone());
|
||||
|
||||
let (seat_token, _) = Seat::new(&mut event_loop, session.seat().into(), log.clone());
|
||||
|
||||
let pointer = event_loop.state().get_mut(&seat_token).add_pointer();
|
||||
let keyboard = event_loop
|
||||
.state()
|
||||
.get_mut(&seat_token)
|
||||
.add_keyboard("", "", "", None, 1000, 500)
|
||||
.expect("Failed to initialize the keyboard");
|
||||
|
||||
let (output_token, _output_global) = Output::new(
|
||||
&mut event_loop,
|
||||
"Drm".into(),
|
||||
PhysicalProperties {
|
||||
width: 0,
|
||||
height: 0,
|
||||
subpixel: wl_output::Subpixel::Unknown,
|
||||
maker: "Smithay".into(),
|
||||
model: "Generic DRM".into(),
|
||||
},
|
||||
log.clone(),
|
||||
);
|
||||
|
||||
let (w, h) = (1920, 1080); // Hardcode full-hd res
|
||||
event_loop
|
||||
.state()
|
||||
.get_mut(&output_token)
|
||||
.change_current_state(
|
||||
Some(Mode {
|
||||
width: w as i32,
|
||||
height: h as i32,
|
||||
refresh: 60_000,
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
event_loop
|
||||
.state()
|
||||
.get_mut(&output_token)
|
||||
.set_preferred(Mode {
|
||||
width: w as i32,
|
||||
height: h as i32,
|
||||
refresh: 60_000,
|
||||
});
|
||||
|
||||
/*
|
||||
* Initialize libinput backend
|
||||
*/
|
||||
let seat = session.seat();
|
||||
let mut libinput_context = Libinput::new_from_udev::<LibinputSessionInterface<Arc<Mutex<DirectSession>>>>(session.into(), &context);
|
||||
let libinput_session_id = notifier.register(libinput_context.clone());
|
||||
libinput_context.udev_assign_seat(&seat);
|
||||
let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
|
||||
libinput_backend.set_handler(LibinputInputHandler {
|
||||
log: log.clone(),
|
||||
pointer,
|
||||
keyboard,
|
||||
window_map: window_map.clone(),
|
||||
pointer_location,
|
||||
screen_size: (w, h),
|
||||
serial: 0,
|
||||
running: running.clone(),
|
||||
});
|
||||
let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop).unwrap();
|
||||
|
||||
let session_event_source = direct_session_bind(notifier, &mut event_loop, log.clone()).unwrap();
|
||||
let udev_event_source = udev_backend_bind(&mut event_loop, udev_token).unwrap();
|
||||
|
||||
/*
|
||||
* Add a listening socket:
|
||||
* Add a listening socket
|
||||
*/
|
||||
let name = display.add_socket_auto().unwrap().into_string().unwrap();
|
||||
println!("Listening on socket: {}", name);
|
||||
|
||||
while running.load(Ordering::SeqCst) {
|
||||
event_loop.dispatch(Some(16)).unwrap();
|
||||
event_loop.dispatch(Some(16));
|
||||
display.flush_clients();
|
||||
window_map.borrow_mut().refresh();
|
||||
}
|
||||
|
||||
println!("Bye Bye");
|
||||
|
||||
let mut notifier = session_event_source.remove();
|
||||
notifier.unregister(udev_session_id);
|
||||
notifier.unregister(libinput_session_id);
|
||||
|
||||
libinput_event_source.remove();
|
||||
|
||||
let udev_token = udev_event_source.remove();
|
||||
let udev = event_loop.state().remove(udev_token);
|
||||
udev.close(event_loop.state());
|
||||
|
||||
event_loop.state().remove(session_token);
|
||||
}
|
||||
|
||||
struct UdevHandlerImpl {
|
||||
shell_state_token: StateToken<ShellState<SurfaceData, Roles, (), ()>>,
|
||||
compositor_token: CompositorToken<SurfaceData, Roles, ()>,
|
||||
window_map: Rc<RefCell<MyWindowMap>>,
|
||||
pointer_location: Arc<Mutex<(f64, f64)>>,
|
||||
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
||||
logger: ::slog::Logger,
|
||||
}
|
||||
|
||||
|
@ -146,6 +345,12 @@ impl UdevHandlerImpl {
|
|||
// create a backend
|
||||
let renderer_token = device.create_backend(&mut state, crtc, mode, vec![connector_info.handle()]).unwrap();
|
||||
|
||||
// create cursor
|
||||
{
|
||||
let renderer = state.get_mut(renderer_token);
|
||||
renderer.set_cursor_representation(&self.pointer_image, (2, 2)).unwrap();
|
||||
}
|
||||
|
||||
// render first frame
|
||||
{
|
||||
let renderer = state.get_mut(renderer_token);
|
||||
|
@ -172,6 +377,7 @@ impl UdevHandler<GliumDrawer<DrmBackend>, DrmHandlerImpl> for UdevHandlerImpl {
|
|||
shell_state_token: self.shell_state_token.clone(),
|
||||
compositor_token: self.compositor_token.clone(),
|
||||
window_map: self.window_map.clone(),
|
||||
pointer_location: self.pointer_location.clone(),
|
||||
logger: self.logger.clone(),
|
||||
})
|
||||
}
|
||||
|
@ -202,6 +408,7 @@ pub struct DrmHandlerImpl {
|
|||
shell_state_token: StateToken<ShellState<SurfaceData, Roles, (), ()>>,
|
||||
compositor_token: CompositorToken<SurfaceData, Roles, ()>,
|
||||
window_map: Rc<RefCell<MyWindowMap>>,
|
||||
pointer_location: Arc<Mutex<(f64, f64)>>,
|
||||
logger: ::slog::Logger,
|
||||
}
|
||||
|
||||
|
@ -210,6 +417,10 @@ impl DrmHandler<GliumDrawer<DrmBackend>> for DrmHandlerImpl {
|
|||
backend: &StateToken<GliumDrawer<DrmBackend>>, _crtc: crtc::Handle, _frame: u32, _duration: Duration) {
|
||||
let state = state.into();
|
||||
let drawer = state.get(backend);
|
||||
{
|
||||
let (x, y) = *self.pointer_location.lock().unwrap();
|
||||
let _ = (**drawer).set_cursor_position(x.trunc().abs() as u32, y.trunc().abs() as u32);
|
||||
}
|
||||
let mut frame = drawer.draw();
|
||||
frame.clear_color(0.8, 0.8, 0.9, 1.0);
|
||||
// redraw the frame, in a simple but inneficient way
|
||||
|
|
|
@ -424,7 +424,7 @@ impl GraphicsBackend for DrmBackend {
|
|||
})
|
||||
}
|
||||
|
||||
fn set_cursor_representation(&self, buffer: ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32))
|
||||
fn set_cursor_representation(&self, buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32))
|
||||
-> Result<()> {
|
||||
let (w, h) = buffer.dimensions();
|
||||
|
||||
|
@ -445,7 +445,7 @@ impl GraphicsBackend for DrmBackend {
|
|||
)
|
||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||
cursor
|
||||
.write(&*buffer.into_raw())
|
||||
.write(&**buffer)
|
||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||
|
||||
trace!(self.logger, "Set the new imported cursor");
|
||||
|
|
|
@ -29,7 +29,7 @@ pub trait GraphicsBackend {
|
|||
/// The format is entirely dictated by the concrete implementation and might range
|
||||
/// from raw image buffers over a fixed list of possible cursor types to simply the
|
||||
/// void type () to represent no possible customization of the cursor itself.
|
||||
fn set_cursor_representation(&self, cursor: Self::CursorFormat, hotspot: (u32, u32))
|
||||
fn set_cursor_representation(&self, cursor: &Self::CursorFormat, hotspot: (u32, u32))
|
||||
-> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
//! Implementation of input backend trait for types provided by `libinput`
|
||||
|
||||
#[cfg(feature = "backend_session")]
|
||||
use backend::session::{AsErrno, Session, SessionObserver};
|
||||
use backend::input as backend;
|
||||
use input as libinput;
|
||||
use input::event;
|
||||
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::Error as IoError;
|
||||
use std::io::{Error as IoError, Result as IoResult};
|
||||
use std::rc::Rc;
|
||||
use std::path::Path;
|
||||
use std::os::unix::io::RawFd;
|
||||
use wayland_server::{EventLoopHandle, StateProxy};
|
||||
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
|
||||
|
||||
/// Libinput based `InputBackend`.
|
||||
///
|
||||
|
@ -260,7 +266,7 @@ impl backend::InputBackend for LibinputInputBackend {
|
|||
if self.handler.is_some() {
|
||||
self.clear_handler();
|
||||
}
|
||||
info!(self.logger, "New input handler set.");
|
||||
info!(self.logger, "New input handler set");
|
||||
for seat in self.seats.values() {
|
||||
trace!(self.logger, "Calling on_seat_created with {:?}", seat);
|
||||
handler.on_seat_created(seat);
|
||||
|
@ -548,3 +554,59 @@ impl From<event::pointer::ButtonState> for backend::MouseButtonState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SessionObserver for libinput::Libinput {
|
||||
fn pause<'a>(&mut self, _state: &mut StateProxy<'a>) {
|
||||
self.suspend()
|
||||
}
|
||||
|
||||
fn activate<'a>(&mut self, _state: &mut StateProxy<'a>) {
|
||||
// TODO Is this the best way to handle this failure?
|
||||
self.resume().expect("Unable to resume libinput context");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LibinputSessionInterface<S: Session>(S);
|
||||
|
||||
impl<S: Session> From<S> for LibinputSessionInterface<S> {
|
||||
fn from(session: S) -> LibinputSessionInterface<S> {
|
||||
LibinputSessionInterface(session)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Session> libinput::LibinputInterface for LibinputSessionInterface<S> {
|
||||
fn open_restricted(&mut self, path: &Path, flags: i32) -> Result<RawFd, i32> {
|
||||
use nix::fcntl::OFlag;
|
||||
self.0.open(path, OFlag::from_bits_truncate(flags)).map_err(|err| err.as_errno().unwrap_or(1 /*Use EPERM by default*/))
|
||||
}
|
||||
|
||||
fn close_restricted(&mut self, fd: RawFd) {
|
||||
let _ = self.0.close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn libinput_bind(backend: LibinputInputBackend, evlh: &mut EventLoopHandle)
|
||||
-> IoResult<FdEventSource<LibinputInputBackend>>
|
||||
{
|
||||
let fd = unsafe { backend.context.fd() };
|
||||
evlh.add_fd_event_source(
|
||||
fd,
|
||||
fd_event_source_implementation(),
|
||||
backend,
|
||||
FdInterest::READ,
|
||||
)
|
||||
}
|
||||
|
||||
fn fd_event_source_implementation() -> FdEventSourceImpl<LibinputInputBackend> {
|
||||
FdEventSourceImpl {
|
||||
ready: |_evlh, ref mut backend, _, _| {
|
||||
use ::backend::input::InputBackend;
|
||||
if let Err(error) = backend.dispatch_new_events() {
|
||||
warn!(backend.logger, "Libinput errored: {}", error);
|
||||
}
|
||||
},
|
||||
error: |_evlh, ref backend, _, error| {
|
||||
warn!(backend.logger, "Libinput fd errored: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::os::unix::io::RawFd;
|
|||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use nix::{Error as NixError, Result as NixResult};
|
||||
use nix::fcntl::{self, open};
|
||||
use nix::fcntl::{self, open, OFlag};
|
||||
use nix::libc::c_int;
|
||||
use nix::sys::signal::{self, Signal};
|
||||
use nix::sys::stat::{dev_t, major, minor, Mode, fstat};
|
||||
|
@ -15,7 +15,7 @@ use wayland_server::sources::SignalEventSource;
|
|||
#[cfg(feature = "backend_session_udev")]
|
||||
use libudev::Context;
|
||||
|
||||
use super::{Session, SessionNotifier, SessionObserver};
|
||||
use super::{AsErrno, Session, SessionNotifier, SessionObserver};
|
||||
|
||||
mod tty {
|
||||
ioctl!(bad read kd_get_mode with 0x4B3B; i16);
|
||||
|
@ -34,6 +34,7 @@ mod tty {
|
|||
ioctl!(bad write_int vt_activate with 0x5606);
|
||||
ioctl!(bad write_int vt_wait_active with 0x5607);
|
||||
ioctl!(bad write_ptr vt_set_mode with 0x5602; VtMode);
|
||||
ioctl!(bad write_int vt_rel_disp with 0x5605);
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub struct VtMode {
|
||||
|
@ -50,7 +51,7 @@ mod tty {
|
|||
}
|
||||
pub const VT_AUTO: i8 = 0x00;
|
||||
pub const VT_PROCESS: i8 = 0x01;
|
||||
pub const VT_ACKACQ: i8 = 0x02;
|
||||
pub const VT_ACKACQ: i32 = 0x02;
|
||||
|
||||
extern {
|
||||
pub fn __libc_current_sigrtmin() -> i8;
|
||||
|
@ -146,6 +147,7 @@ pub struct DirectSession {
|
|||
}
|
||||
|
||||
pub struct DirectSessionNotifier {
|
||||
tty: RawFd,
|
||||
active: Arc<AtomicBool>,
|
||||
signals: Vec<Option<Box<SessionObserver>>>,
|
||||
signal: Signal,
|
||||
|
@ -175,6 +177,7 @@ impl DirectSession {
|
|||
old_keyboard_mode,
|
||||
logger: logger.new(o!("vt" => format!("{}", vt), "component" => "session")),
|
||||
}, DirectSessionNotifier {
|
||||
tty: fd,
|
||||
active,
|
||||
signals: Vec::new(),
|
||||
signal,
|
||||
|
@ -194,7 +197,7 @@ impl DirectSession {
|
|||
bail!(ErrorKind::NotRunningFromTTY);
|
||||
}
|
||||
|
||||
let vt_num = minor(stat.st_dev) as i32 - 1;
|
||||
let vt_num = minor(stat.st_rdev) as i32;
|
||||
info!(logger, "Running from tty: {}", vt_num);
|
||||
|
||||
let mut mode = 0;
|
||||
|
@ -246,8 +249,9 @@ impl DirectSession {
|
|||
impl Session for DirectSession {
|
||||
type Error = NixError;
|
||||
|
||||
fn open(&mut self, path: &Path) -> NixResult<RawFd> {
|
||||
open(path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK, Mode::empty())
|
||||
fn open(&mut self, path: &Path, flags: OFlag) -> NixResult<RawFd> {
|
||||
info!(self.logger, "Opening device: {:?}", path);
|
||||
open(path, flags, Mode::empty())
|
||||
}
|
||||
|
||||
fn close(&mut self, fd: RawFd) -> NixResult<()> {
|
||||
|
@ -258,9 +262,9 @@ impl Session for DirectSession {
|
|||
self.active.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn seat(&self) -> &str {
|
||||
fn seat(&self) -> String {
|
||||
// The VT api can only be used on seat0
|
||||
return "seat0"
|
||||
String::from("seat0")
|
||||
}
|
||||
|
||||
fn change_vt(&mut self, vt_num: i32) -> NixResult<()> {
|
||||
|
@ -268,8 +272,19 @@ impl Session for DirectSession {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsErrno for NixError {
|
||||
fn as_errno(&self) -> Option<i32> {
|
||||
match *self {
|
||||
NixError::Sys(errno) => Some(errno as i32),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DirectSession {
|
||||
fn drop(&mut self) {
|
||||
info!(self.logger, "Deallocating tty {}", self.tty);
|
||||
|
||||
if let Err(err) = unsafe { tty::kd_set_kb_mode(self.tty, self.old_keyboard_mode) } {
|
||||
warn!(self.logger, "Unable to restore vt keyboard mode. Error: {}", err);
|
||||
}
|
||||
|
@ -318,7 +333,13 @@ where
|
|||
if let &mut Some(ref mut signal) = signal {signal.pause(&mut evlh.state().as_proxy()); }
|
||||
}
|
||||
notifier.active.store(false, Ordering::SeqCst);
|
||||
unsafe {
|
||||
tty::vt_rel_disp(notifier.tty, 1).expect("Unable to release tty lock");
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
tty::vt_rel_disp(notifier.tty, tty::VT_ACKACQ).expect("Unable to acquire tty lock");
|
||||
}
|
||||
for signal in &mut notifier.signals {
|
||||
if let &mut Some(ref mut signal) = signal { signal.activate(&mut evlh.state().as_proxy()); }
|
||||
}
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::os::unix::io::RawFd;
|
||||
use nix::fcntl::OFlag;
|
||||
use wayland_server::StateProxy;
|
||||
|
||||
pub trait Session {
|
||||
type Error: ::std::fmt::Debug;
|
||||
type Error: AsErrno;
|
||||
|
||||
fn open(&mut self, path: &Path) -> Result<RawFd, Self::Error>;
|
||||
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Self::Error>;
|
||||
fn close(&mut self, fd: RawFd) -> Result<(), Self::Error>;
|
||||
|
||||
fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error>;
|
||||
|
||||
fn is_active(&self) -> bool;
|
||||
fn seat(&self) -> &str;
|
||||
fn seat(&self) -> String;
|
||||
}
|
||||
|
||||
pub trait SessionNotifier {
|
||||
|
@ -30,13 +32,47 @@ pub trait SessionObserver {
|
|||
impl Session for () {
|
||||
type Error = ();
|
||||
|
||||
fn open(&mut self, _path: &Path) -> Result<RawFd, Self::Error> { Err(()) }
|
||||
fn open(&mut self, _path: &Path, _flags: OFlag) -> Result<RawFd, Self::Error> { Err(()) }
|
||||
fn close(&mut self, _fd: RawFd) -> Result<(), Self::Error> { Err(()) }
|
||||
|
||||
fn change_vt(&mut self, _vt: i32) -> Result<(), Self::Error> { Err(()) }
|
||||
|
||||
fn is_active(&self) -> bool { false }
|
||||
fn seat(&self) -> &str { "seat0" }
|
||||
fn seat(&self) -> String { String::from("seat0") }
|
||||
}
|
||||
|
||||
impl<S: Session> Session for Arc<Mutex<S>> {
|
||||
type Error = S::Error;
|
||||
|
||||
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Self::Error> {
|
||||
self.lock().unwrap().open(path, flags)
|
||||
}
|
||||
|
||||
fn close(&mut self, fd: RawFd) -> Result<(), Self::Error> {
|
||||
self.lock().unwrap().close(fd)
|
||||
}
|
||||
|
||||
fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error> {
|
||||
self.lock().unwrap().change_vt(vt)
|
||||
}
|
||||
|
||||
fn is_active(&self) -> bool {
|
||||
self.lock().unwrap().is_active()
|
||||
}
|
||||
|
||||
fn seat(&self) -> String {
|
||||
self.lock().unwrap().seat()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsErrno: ::std::fmt::Debug {
|
||||
fn as_errno(&self) -> Option<i32>;
|
||||
}
|
||||
|
||||
impl AsErrno for () {
|
||||
fn as_errno(&self) -> Option<i32> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub mod direct;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use libudev::{Context, MonitorBuilder, MonitorSocket, Event, EventType, Enumerator, Result as UdevResult};
|
||||
use nix::fcntl;
|
||||
use nix::sys::stat::{dev_t, fstat};
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
|
@ -16,7 +17,7 @@ use ::backend::session::{Session, SessionObserver};
|
|||
pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> {
|
||||
devices: HashMap<dev_t, (StateToken<DrmDevice<B>>, FdEventSource<(StateToken<DrmDevice<B>>, H)>)>,
|
||||
monitor: MonitorSocket,
|
||||
session: StateToken<S>,
|
||||
session: S,
|
||||
handler: T,
|
||||
logger: ::slog::Logger,
|
||||
}
|
||||
|
@ -24,7 +25,7 @@ pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'stat
|
|||
impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> UdevBackend<B, H, S, T> {
|
||||
pub fn new<'a, L>(mut evlh: &mut EventLoopHandle,
|
||||
context: &Context,
|
||||
session_token: &StateToken<S>,
|
||||
mut session: S,
|
||||
mut handler: T,
|
||||
logger: L)
|
||||
-> Result<UdevBackend<B, H, S, T>>
|
||||
|
@ -32,7 +33,7 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
|
|||
L: Into<Option<::slog::Logger>>
|
||||
{
|
||||
let logger = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_udev"));
|
||||
let seat = String::from(evlh.state().get(&session_token).seat());
|
||||
let seat = session.seat();
|
||||
let devices = all_gpus(context, seat)
|
||||
.chain_err(|| ErrorKind::FailedToScan)?
|
||||
.into_iter()
|
||||
|
@ -40,8 +41,7 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
|
|||
.flat_map(|path| {
|
||||
match unsafe { DrmDevice::new_from_fd(
|
||||
{
|
||||
let session = evlh.state().get_mut(session_token);
|
||||
match session.open(&path) {
|
||||
match session.open(&path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => {
|
||||
warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
|
||||
|
@ -63,7 +63,6 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
|
|||
let device = evlh.state().remove(token);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
let session = evlh.state().get_mut(session_token);
|
||||
if let Err(err) = session.close(fd) {
|
||||
warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
|
||||
};
|
||||
|
@ -78,7 +77,6 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
|
|||
let device = evlh.state().remove(token);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
let session = evlh.state().get_mut(session_token);
|
||||
if let Err(err) = session.close(fd) {
|
||||
warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
|
||||
};
|
||||
|
@ -88,7 +86,6 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
|
|||
None => {
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device); //drops master
|
||||
let session = evlh.state().get_mut(session_token);
|
||||
if let Err(err) = session.close(fd) {
|
||||
warn!(logger, "Failed to close device. Error: {:?}. Ignoring", err);
|
||||
}
|
||||
|
@ -110,7 +107,7 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
|
|||
Ok(UdevBackend {
|
||||
devices,
|
||||
monitor,
|
||||
session: session_token.clone(),
|
||||
session,
|
||||
handler,
|
||||
logger,
|
||||
})
|
||||
|
@ -124,11 +121,11 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
|
|||
let device = state.remove(device);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
let session = state.get_mut(&self.session);
|
||||
if let Err(err) = session.close(fd) {
|
||||
if let Err(err) = self.session.close(fd) {
|
||||
warn!(self.logger, "Failed to close device. Error: {:?}. Ignoring", err);
|
||||
};
|
||||
}
|
||||
info!(self.logger, "All devices closed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,10 +184,8 @@ where
|
|||
let mut device = {
|
||||
match unsafe { DrmDevice::new_from_fd(
|
||||
{
|
||||
let session_token = evlh.state().get(token).session.clone();
|
||||
let logger = evlh.state().get(token).logger.clone();
|
||||
let session = evlh.state().get_mut(&session_token);
|
||||
match session.open(path) {
|
||||
match evlh.state().get_mut(token).session.open(path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => {
|
||||
warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
|
||||
|
@ -213,30 +208,25 @@ where
|
|||
evlh.state().get_mut(token).devices.insert(devnum, (dev_token, fd_event_source));
|
||||
} else {
|
||||
evlh.state().with_value(token, |state, udev| {
|
||||
let session_token = udev.session.clone();
|
||||
state.with_value(&session_token, |state, session| {
|
||||
let mut state: StateProxy = state.into();
|
||||
udev.handler.device_removed(&mut state, &dev_token);
|
||||
let device = state.remove(dev_token);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
if let Err(err) = session.close(fd) {
|
||||
if let Err(err) = udev.session.close(fd) {
|
||||
warn!(udev.logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
|
||||
};
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
evlh.state().with_value(token, |state, udev| {
|
||||
state.with_value(&udev.session, |_, session| {
|
||||
if let Err(err) = session.close(fd) {
|
||||
evlh.state().with_value(token, |_state, udev| {
|
||||
if let Err(err) = udev.session.close(fd) {
|
||||
warn!(udev.logger, "Failed to close unused device. Error: {:?}", err);
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -244,8 +234,6 @@ where
|
|||
// Device removed
|
||||
EventType::Remove => {
|
||||
evlh.state().with_value(token, |state, udev| {
|
||||
let session_token = udev.session.clone();
|
||||
state.with_value(&session_token, |state, session| {
|
||||
info!(udev.logger, "Device Remove");
|
||||
if let Some(devnum) = event.devnum() {
|
||||
if let Some((device, fd_event_source)) = udev.devices.remove(&devnum) {
|
||||
|
@ -255,13 +243,12 @@ where
|
|||
let device = state.remove(device);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
if let Err(err) = session.close(fd) {
|
||||
if let Err(err) = udev.session.close(fd) {
|
||||
warn!(udev.logger, "Failed to close device {:?}. Error: {:?}. Ignoring", event.sysname(), err);
|
||||
};
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
// New connector
|
||||
EventType::Change => evlh.state().with_value(token, |state, udev| {
|
||||
|
|
|
@ -190,11 +190,11 @@ impl GraphicsBackend for WinitGraphicsBackend {
|
|||
self.window.head().set_cursor_position(x as i32, y as i32)
|
||||
}
|
||||
|
||||
fn set_cursor_representation(&self, cursor: Self::CursorFormat, _hotspot: (u32, u32))
|
||||
fn set_cursor_representation(&self, cursor: &Self::CursorFormat, _hotspot: (u32, u32))
|
||||
-> ::std::result::Result<(), ()> {
|
||||
// Cannot log this one, as `CursorFormat` is not `Debug` and should not be
|
||||
debug!(self.logger, "Changing cursor representation");
|
||||
self.window.head().set_cursor(cursor);
|
||||
self.window.head().set_cursor(*cursor);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue