wayland: move input logic to the event loop

This commit is contained in:
Victor Berger 2017-03-10 23:22:59 +01:00
parent 7336cacf07
commit 17fde48ed7
4 changed files with 450 additions and 467 deletions

View file

@ -1,18 +1,11 @@
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase};
use events::ModifiersState;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use wayland_client::{EnvHandler, default_connect, EventQueue, EventQueueHandle, Init, Proxy}; use wayland_client::{EnvHandler, default_connect, EventQueue, EventQueueHandle, Init, Proxy};
use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor, use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor,
wl_display, wl_registry, wl_output, wl_surface, wl_pointer, wl_display, wl_registry, wl_output, wl_surface};
wl_keyboard};
use super::{wayland_window, EventsLoopSink, make_wid}; use super::wayland_window;
use super::wayland_kbd::MappedKeyboard;
use super::keyboard::KbdHandler;
/* /*
* Registry and globals handling * Registry and globals handling
@ -25,26 +18,11 @@ wayland_env!(InnerEnv,
subcompositor: wl_subcompositor::WlSubcompositor subcompositor: wl_subcompositor::WlSubcompositor
); );
enum KbdType {
Mapped(MappedKeyboard<KbdHandler>),
Plain(Option<(Arc<wl_surface::WlSurface>,Arc<Mutex<EventsLoopSink>>)>)
}
struct WaylandEnv { struct WaylandEnv {
registry: wl_registry::WlRegistry, registry: wl_registry::WlRegistry,
inner: EnvHandler<InnerEnv>, inner: EnvHandler<InnerEnv>,
monitors: Vec<OutputInfo>, monitors: Vec<OutputInfo>,
my_id: usize, my_id: usize,
windows: Vec<(Arc<wl_surface::WlSurface>,Arc<Mutex<EventsLoopSink>>)>,
seat: Option<wl_seat::WlSeat>,
mouse: Option<wl_pointer::WlPointer>,
mouse_focus: Option<(Arc<wl_surface::WlSurface>,Arc<Mutex<EventsLoopSink>>)>,
mouse_location: (i32, i32),
axis_buffer: Option<(f32, f32)>,
axis_discrete_buffer: Option<(i32, i32)>,
axis_state: TouchPhase,
kbd: Option<wl_keyboard::WlKeyboard>,
kbd_handler: KbdType
} }
struct OutputInfo { struct OutputInfo {
@ -69,25 +47,11 @@ impl OutputInfo {
impl WaylandEnv { impl WaylandEnv {
fn new(registry: wl_registry::WlRegistry) -> WaylandEnv { fn new(registry: wl_registry::WlRegistry) -> WaylandEnv {
let kbd_handler = match MappedKeyboard::new(KbdHandler::new()) {
Ok(h) => KbdType::Mapped(h),
Err(_) => KbdType::Plain(None)
};
WaylandEnv { WaylandEnv {
registry: registry, registry: registry,
inner: EnvHandler::new(), inner: EnvHandler::new(),
monitors: Vec::new(), monitors: Vec::new(),
my_id: 0, my_id: 0,
windows: Vec::new(),
seat: None,
mouse: None,
mouse_focus: None,
mouse_location: (0,0),
axis_buffer: None,
axis_discrete_buffer: None,
axis_state: TouchPhase::Started,
kbd: None,
kbd_handler: kbd_handler
} }
} }
@ -127,14 +91,6 @@ impl wl_registry::Handler for WaylandEnv {
.expect("Registry cannot be dead"); .expect("Registry cannot be dead");
evqh.register::<_, WaylandEnv>(&output, self.my_id); evqh.register::<_, WaylandEnv>(&output, self.my_id);
self.monitors.push(OutputInfo::new(output, name)); self.monitors.push(OutputInfo::new(output, name));
} else if interface == "wl_seat" && self.seat.is_none() {
// Only grab the first seat
// TODO: Handle multi-seat-setup?
assert!(version >= 5, "Version 5 of seat interface is needed by glutin.");
let seat = self.registry.bind::<wl_seat::WlSeat>(5, name)
.expect("Registry cannot be dead");
evqh.register::<_, WaylandEnv>(&seat, self.my_id);
self.seat = Some(seat);
} }
self.inner.global(evqh, registry, name, interface, version); self.inner.global(evqh, registry, name, interface, version);
} }
@ -242,6 +198,12 @@ impl WaylandContext {
let _ = self.display.flush(); let _ = self.display.flush();
} }
pub fn get_seat(&self) -> Option<wl_seat::WlSeat> {
let mut guard = self.evq.lock().unwrap();
let state = guard.state();
state.get_handler::<WaylandEnv>(self.env_id).get_seat()
}
pub fn with_output<F>(&self, id: MonitorId, f: F) where F: FnOnce(&wl_output::WlOutput) { pub fn with_output<F>(&self, id: MonitorId, f: F) where F: FnOnce(&wl_output::WlOutput) {
let mut guard = self.evq.lock().unwrap(); let mut guard = self.evq.lock().unwrap();
let state = guard.state(); let state = guard.state();
@ -252,7 +214,7 @@ impl WaylandContext {
} }
} }
pub fn create_window<H: wayland_window::Handler>(&self, sink: Arc<Mutex<EventsLoopSink>>) pub fn create_window<H: wayland_window::Handler>(&self)
-> (Arc<wl_surface::WlSurface>, wayland_window::DecoratedSurface<H>) -> (Arc<wl_surface::WlSurface>, wayland_window::DecoratedSurface<H>)
{ {
let mut guard = self.evq.lock().unwrap(); let mut guard = self.evq.lock().unwrap();
@ -260,7 +222,6 @@ impl WaylandContext {
let env = state.get_mut_handler::<WaylandEnv>(self.env_id); let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
// this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69)
let surface = Arc::new(env.inner.compositor.create_surface().expect("Compositor cannot be dead")); let surface = Arc::new(env.inner.compositor.create_surface().expect("Compositor cannot be dead"));
env.windows.push((surface.clone(), sink));
let decorated = wayland_window::DecoratedSurface::new( let decorated = wayland_window::DecoratedSurface::new(
&*surface, 800, 600, &*surface, 800, 600,
&env.inner.compositor, &env.inner.compositor,
@ -272,13 +233,6 @@ impl WaylandContext {
).expect("Failed to create a tmpfile buffer."); ).expect("Failed to create a tmpfile buffer.");
(surface, decorated) (surface, decorated)
} }
pub fn prune_dead_windows(&self) {
let mut guard = self.evq.lock().unwrap();
let mut state = guard.state();
let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
env.windows.retain(|w| w.0.is_alive());
}
} }
/* /*
@ -342,346 +296,3 @@ impl MonitorId {
(0,0) (0,0)
} }
} }
/*
* Input Handling
*/
impl wl_seat::Handler for WaylandEnv {
fn capabilities(&mut self,
evqh: &mut EventQueueHandle,
seat: &wl_seat::WlSeat,
capabilities: wl_seat::Capability)
{
// create pointer if applicable
if capabilities.contains(wl_seat::Pointer) && self.mouse.is_none() {
let pointer = seat.get_pointer().expect("Seat is not dead");
evqh.register::<_, WaylandEnv>(&pointer, self.my_id);
self.mouse = Some(pointer);
}
// destroy pointer if applicable
if !capabilities.contains(wl_seat::Pointer) {
if let Some(pointer) = self.mouse.take() {
pointer.release();
}
}
// create keyboard if applicable
if capabilities.contains(wl_seat::Keyboard) && self.kbd.is_none() {
let kbd = seat.get_keyboard().expect("Seat is not dead");
evqh.register::<_, WaylandEnv>(&kbd, self.my_id);
self.kbd = Some(kbd);
}
// destroy keyboard if applicable
if !capabilities.contains(wl_seat::Keyboard) {
if let Some(kbd) = self.kbd.take() {
kbd.release();
}
}
}
}
declare_handler!(WaylandEnv, wl_seat::Handler, wl_seat::WlSeat);
/*
* Pointer Handling
*/
impl wl_pointer::Handler for WaylandEnv {
fn enter(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_serial: u32,
surface: &wl_surface::WlSurface,
surface_x: f64,
surface_y: f64)
{
self.mouse_location = (surface_x as i32, surface_y as i32);
for &(ref window, ref sink) in &self.windows {
if window.equals(surface) {
self.mouse_focus = Some((window.clone(), sink.clone()));
let (w, h) = self.mouse_location;
let mut event_queue = sink.lock().unwrap();
event_queue.push_event(Event::MouseEntered, make_wid(window));
event_queue.push_event(Event::MouseMoved(w, h), make_wid(window));
break;
}
}
}
fn leave(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_serial: u32,
surface: &wl_surface::WlSurface)
{
self.mouse_focus = None;
for &(ref window, ref sink) in &self.windows {
if window.equals(surface) {
let mut event_queue = sink.lock().unwrap();
event_queue.push_event(Event::MouseLeft, make_wid(window));
break;
}
}
}
fn motion(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_time: u32,
surface_x: f64,
surface_y: f64)
{
self.mouse_location = (surface_x as i32, surface_y as i32);
if let Some((ref window, ref sink)) = self.mouse_focus {
let (w,h) = self.mouse_location;
sink.lock().unwrap().push_event(
Event::MouseMoved(w, h),
make_wid(window)
);
}
}
fn button(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_serial: u32,
_time: u32,
button: u32,
state: wl_pointer::ButtonState)
{
if let Some((ref window, ref sink)) = self.mouse_focus {
let state = match state {
wl_pointer::ButtonState::Pressed => ElementState::Pressed,
wl_pointer::ButtonState::Released => ElementState::Released
};
let button = match button {
0x110 => MouseButton::Left,
0x111 => MouseButton::Right,
0x112 => MouseButton::Middle,
// TODO figure out the translation ?
_ => return
};
sink.lock().unwrap().push_event(
Event::MouseInput(state, button),
make_wid(window)
);
}
}
fn axis(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_time: u32,
axis: wl_pointer::Axis,
value: f64)
{
let (mut x, mut y) = self.axis_buffer.unwrap_or((0.0, 0.0));
match axis {
wl_pointer::Axis::VerticalScroll => y += value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32
}
self.axis_buffer = Some((x,y));
self.axis_state = match self.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
}
fn frame(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer)
{
let axis_buffer = self.axis_buffer.take();
let axis_discrete_buffer = self.axis_discrete_buffer.take();
if let Some((ref window, ref sink)) = self.mouse_focus {
if let Some((x, y)) = axis_discrete_buffer {
sink.lock().unwrap().push_event(
Event::MouseWheel(
MouseScrollDelta::LineDelta(x as f32, y as f32),
self.axis_state
),
make_wid(window)
);
} else if let Some((x, y)) = axis_buffer {
sink.lock().unwrap().push_event(
Event::MouseWheel(
MouseScrollDelta::PixelDelta(x as f32, y as f32),
self.axis_state
),
make_wid(window)
);
}
}
}
fn axis_source(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_axis_source: wl_pointer::AxisSource)
{
}
fn axis_stop(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_time: u32,
_axis: wl_pointer::Axis)
{
self.axis_state = TouchPhase::Ended;
}
fn axis_discrete(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
axis: wl_pointer::Axis,
discrete: i32)
{
let (mut x, mut y) = self.axis_discrete_buffer.unwrap_or((0,0));
match axis {
wl_pointer::Axis::VerticalScroll => y += discrete,
wl_pointer::Axis::HorizontalScroll => x += discrete
}
self.axis_discrete_buffer = Some((x,y));
self.axis_state = match self.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
}
}
declare_handler!(WaylandEnv, wl_pointer::Handler, wl_pointer::WlPointer);
/*
* Keyboard Handling
*/
impl wl_keyboard::Handler for WaylandEnv {
// mostly pass-through
fn keymap(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
format: wl_keyboard::KeymapFormat,
fd: ::std::os::unix::io::RawFd,
size: u32)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.keymap(evqh, proxy, format, fd, size),
_ => ()
}
}
fn enter(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
surface: &wl_surface::WlSurface,
keys: Vec<u8>)
{
let mut opt_sink = None;
for &(ref window, ref sink) in &self.windows {
if window.equals(surface) {
opt_sink = Some((window.clone(), sink.clone()));
break;
}
}
if let Some((ref window, ref sink)) = opt_sink {
// send focused event
let mut guard = sink.lock().unwrap();
guard.push_event(Event::Focused(true), make_wid(window));
}
match self.kbd_handler {
KbdType::Mapped(ref mut h) => {
h.handler().target = opt_sink;
h.enter(evqh, proxy, serial, surface, keys);
},
KbdType::Plain(ref mut opt) => { *opt = opt_sink; }
}
}
fn leave(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
surface: &wl_surface::WlSurface)
{
let opt_sink = match self.kbd_handler {
KbdType::Mapped(ref mut h) => {
let sink = h.handler().target.take();
h.leave(evqh, proxy, serial, surface);
sink
},
KbdType::Plain(ref mut opt) => opt.take()
};
if let Some((ref window, ref sink)) = opt_sink {
let mut guard = sink.lock().unwrap();
guard.push_event(Event::Focused(false), make_wid(window));
}
}
fn key(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
time: u32,
key: u32,
state: wl_keyboard::KeyState)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.key(evqh, proxy, serial, time, key, state),
KbdType::Plain(Some((ref window, ref sink))) => {
let state = match state {
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
wl_keyboard::KeyState::Released => ElementState::Released,
};
let mut guard = sink.lock().unwrap();
// This is fallback impl if libxkbcommon was not available
// This case should probably never happen, as most wayland
// compositors _need_ libxkbcommon anyway...
//
// In this case, we don't have the modifiers state information
// anyway, as we need libxkbcommon to interpret it (it is
// supposed to be serialized by the compositor using libxkbcommon)
guard.push_event(
Event::KeyboardInput(
state,
key as u8,
None,
ModifiersState::default()
),
make_wid(window)
);
},
KbdType::Plain(None) => ()
}
}
fn modifiers(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
mods_depressed: u32,
mods_latched: u32,
mods_locked: u32,
group: u32)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.modifiers(evqh, proxy, serial, mods_depressed,
mods_latched, mods_locked, group),
_ => ()
}
}
fn repeat_info(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
rate: i32,
delay: i32)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.repeat_info(evqh, proxy, rate, delay),
_ => ()
}
}
}
declare_handler!(WaylandEnv, wl_keyboard::Handler, wl_keyboard::WlKeyboard);

View file

@ -1,15 +1,23 @@
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState};
use std::cell::UnsafeCell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use super::{DecoratedHandler, WindowId, WaylandContext}; use super::{DecoratedHandler, WindowId, WaylandContext};
use wayland_client::EventQueue;
use wayland_client::{EventQueue, EventQueueHandle, Init, Proxy};
use wayland_client::protocol::{wl_seat, wl_surface, wl_pointer, wl_keyboard};
use super::make_wid;
use super::wayland_window::DecoratedSurface; use super::wayland_window::DecoratedSurface;
use super::wayland_kbd::MappedKeyboard;
use super::keyboard::KbdHandler;
pub struct EventsLoopSink { pub struct EventsLoopSink {
callback: Option<*mut FnMut(::Event)>, callback: Box<FnMut(::Event)>
queue: VecDeque<::Event>
} }
unsafe impl Send for EventsLoopSink { } unsafe impl Send for EventsLoopSink { }
@ -17,21 +25,16 @@ unsafe impl Send for EventsLoopSink { }
impl EventsLoopSink { impl EventsLoopSink {
pub fn new() -> EventsLoopSink { pub fn new() -> EventsLoopSink {
EventsLoopSink { EventsLoopSink {
callback: None, callback: Box::new(|_| {}),
queue: VecDeque::new()
} }
} }
pub fn push_event(&mut self, evt: ::WindowEvent, wid: WindowId) { pub fn send_event(&mut self, evt: ::WindowEvent, wid: WindowId) {
let evt = ::Event::WindowEvent { let evt = ::Event::WindowEvent {
event: evt, event: evt,
window_id: ::WindowId(::platform::WindowId::Wayland(wid)) window_id: ::WindowId(::platform::WindowId::Wayland(wid))
}; };
if let Some(cb) = self.callback { (self.callback)(evt)
unsafe { (&mut *cb)(evt) }
} else {
self.queue.push_back(evt)
}
} }
// This function is only safe of the set callback is unset before exclusive // This function is only safe of the set callback is unset before exclusive
@ -39,25 +42,12 @@ impl EventsLoopSink {
// //
// The callback also cannot be used any longer as long as it has not been // The callback also cannot be used any longer as long as it has not been
// cleared from the Sink. // cleared from the Sink.
unsafe fn set_callback(&mut self, cb: &mut FnMut(::Event)) { unsafe fn set_callback(&mut self, cb: Box<FnMut(::Event)>) -> Box<FnMut(::Event)> {
let cb: &mut FnMut(::Event) = ::std::mem::transmute(cb); ::std::mem::replace(&mut self.callback, cb)
self.callback = Some(cb as *mut _);
} }
fn with_callback<F: FnOnce(&mut FnMut(::Event))>(&mut self, f: F) { fn with_callback<F: FnOnce(&mut FnMut(::Event))>(&mut self, f: F) {
if let Some(cb) = self.callback { f(&mut *self.callback)
f(unsafe {&mut *cb})
}
}
fn clear_callback(&mut self) {
self.callback = None
}
fn drain_queue<F: FnMut(::Event)>(&mut self, cb: &mut F) {
for evt in self.queue.drain(..) {
cb(evt)
}
} }
} }
@ -67,30 +57,33 @@ pub struct EventsLoop {
decorated_ids: Mutex<Vec<(usize, WindowId)>>, decorated_ids: Mutex<Vec<(usize, WindowId)>>,
sink: Arc<Mutex<EventsLoopSink>>, sink: Arc<Mutex<EventsLoopSink>>,
interrupted: AtomicBool, interrupted: AtomicBool,
hid: usize
} }
impl EventsLoop { impl EventsLoop {
pub fn new(ctxt: Arc<WaylandContext>) -> EventsLoop { pub fn new(ctxt: Arc<WaylandContext>) -> EventsLoop {
let evq = ctxt.display.create_event_queue(); let mut evq = ctxt.display.create_event_queue();
let sink = Arc::new(Mutex::new(EventsLoopSink::new()));
let hid = evq.add_handler_with_init(InputHandler::new(&ctxt, sink.clone()));
EventsLoop { EventsLoop {
ctxt: ctxt, ctxt: ctxt,
evq: Arc::new(Mutex::new(evq)), evq: Arc::new(Mutex::new(evq)),
decorated_ids: Mutex::new(Vec::new()), decorated_ids: Mutex::new(Vec::new()),
sink: Arc::new(Mutex::new(EventsLoopSink::new())), sink: sink,
interrupted: AtomicBool::new(false) interrupted: AtomicBool::new(false),
hid: hid
} }
} }
pub fn get_sink(&self) -> Arc<Mutex<EventsLoopSink>> {
self.sink.clone()
}
pub fn get_event_queue(&self) -> Arc<Mutex<EventQueue>> { pub fn get_event_queue(&self) -> Arc<Mutex<EventQueue>> {
self.evq.clone() self.evq.clone()
} }
pub fn register_window(&self, decorated_id: usize, wid: WindowId) { pub fn register_window(&self, decorated_id: usize, surface: Arc<wl_surface::WlSurface>) {
self.decorated_ids.lock().unwrap().push((decorated_id, wid)); self.decorated_ids.lock().unwrap().push((decorated_id, make_wid(&surface)));
let mut guard = self.evq.lock().unwrap();
let mut state = guard.state();
state.get_mut_handler::<InputHandler>(self.hid).windows.push(surface);
} }
fn process_resize(evq: &mut EventQueue, ids: &[(usize, WindowId)], callback: &mut FnMut(::Event)) fn process_resize(evq: &mut EventQueue, ids: &[(usize, WindowId)], callback: &mut FnMut(::Event))
@ -123,16 +116,16 @@ impl EventsLoop {
// first of all, get exclusive access to this event queue // first of all, get exclusive access to this event queue
let mut evq_guard = self.evq.lock().unwrap(); let mut evq_guard = self.evq.lock().unwrap();
// dispatch stored events:
self.sink.lock().unwrap().drain_queue(&mut callback);
// read some events from the socket if some are waiting & queue is empty // read some events from the socket if some are waiting & queue is empty
if let Some(guard) = evq_guard.prepare_read() { if let Some(guard) = evq_guard.prepare_read() {
guard.read_events().expect("Wayland connection unexpectedly lost"); guard.read_events().expect("Wayland connection unexpectedly lost");
} }
// set the callback into the sink // set the callback into the sink
unsafe { self.sink.lock().unwrap().set_callback(&mut callback) }; // we extend the lifetime of the closure to 'static to be able to put it in
// the sink, but we'll explicitly drop it at the end of this function, so it's fine
let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box<FnMut(_)>) };
let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) };
// then do the actual dispatching // then do the actual dispatching
self.ctxt.dispatch_pending(); self.ctxt.dispatch_pending();
@ -146,9 +139,8 @@ impl EventsLoop {
|cb| Self::process_resize(&mut evq_guard, &ids_guard, cb) |cb| Self::process_resize(&mut evq_guard, &ids_guard, cb)
); );
sink_guard.clear_callback(); // replace the old noop callback
// we must keep callback alive up to this point! unsafe { self.sink.lock().unwrap().set_callback(old_cb) };
drop(callback);
} }
@ -161,11 +153,11 @@ impl EventsLoop {
// first of all, get exclusive access to this event queue // first of all, get exclusive access to this event queue
let mut evq_guard = self.evq.lock().unwrap(); let mut evq_guard = self.evq.lock().unwrap();
// dispatch stored events:
self.sink.lock().unwrap().drain_queue(&mut callback);
// set the callback into the sink // set the callback into the sink
unsafe { self.sink.lock().unwrap().set_callback(&mut callback) }; // we extend the lifetime of the closure to 'static to be able to put it in
// the sink, but we'll explicitly drop it at the end of this function, so it's fine
let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box<FnMut(_)>) };
let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) };
while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) { while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
self.ctxt.dispatch(); self.ctxt.dispatch();
@ -177,8 +169,388 @@ impl EventsLoop {
self.ctxt.flush(); self.ctxt.flush();
} }
self.sink.lock().unwrap().clear_callback(); // replace the old noop callback
// we must keep callback alive up to this point! unsafe { self.sink.lock().unwrap().set_callback(old_cb) };
drop(callback)
} }
} }
enum KbdType {
Mapped(MappedKeyboard<KbdHandler>),
Plain(Option<WindowId>)
}
struct InputHandler {
my_id: usize,
windows: Vec<Arc<wl_surface::WlSurface>>,
seat: Option<wl_seat::WlSeat>,
mouse: Option<wl_pointer::WlPointer>,
mouse_focus: Option<Arc<wl_surface::WlSurface>>,
mouse_location: (i32, i32),
axis_buffer: Option<(f32, f32)>,
axis_discrete_buffer: Option<(i32, i32)>,
axis_state: TouchPhase,
kbd: Option<wl_keyboard::WlKeyboard>,
kbd_handler: KbdType,
callback: Arc<Mutex<EventsLoopSink>>
}
impl InputHandler {
fn new(ctxt: &WaylandContext, sink: Arc<Mutex<EventsLoopSink>>) -> InputHandler {
let kbd_handler = match MappedKeyboard::new(KbdHandler::new(sink.clone())) {
Ok(h) => KbdType::Mapped(h),
Err(_) => KbdType::Plain(None)
};
InputHandler {
my_id: 0,
windows: Vec::new(),
seat: ctxt.get_seat(),
mouse: None,
mouse_focus: None,
mouse_location: (0,0),
axis_buffer: None,
axis_discrete_buffer: None,
axis_state: TouchPhase::Started,
kbd: None,
kbd_handler: kbd_handler,
callback: sink
}
}
}
impl Init for InputHandler {
fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) {
if let Some(ref seat) = self.seat {
evqh.register::<_, InputHandler>(seat, index);
}
self.my_id = index;
}
}
impl wl_seat::Handler for InputHandler {
fn capabilities(&mut self,
evqh: &mut EventQueueHandle,
seat: &wl_seat::WlSeat,
capabilities: wl_seat::Capability)
{
// create pointer if applicable
if capabilities.contains(wl_seat::Pointer) && self.mouse.is_none() {
let pointer = seat.get_pointer().expect("Seat is not dead");
evqh.register::<_, InputHandler>(&pointer, self.my_id);
self.mouse = Some(pointer);
}
// destroy pointer if applicable
if !capabilities.contains(wl_seat::Pointer) {
if let Some(pointer) = self.mouse.take() {
pointer.release();
}
}
// create keyboard if applicable
if capabilities.contains(wl_seat::Keyboard) && self.kbd.is_none() {
let kbd = seat.get_keyboard().expect("Seat is not dead");
evqh.register::<_, InputHandler>(&kbd, self.my_id);
self.kbd = Some(kbd);
}
// destroy keyboard if applicable
if !capabilities.contains(wl_seat::Keyboard) {
if let Some(kbd) = self.kbd.take() {
kbd.release();
}
}
}
}
declare_handler!(InputHandler, wl_seat::Handler, wl_seat::WlSeat);
/*
* Pointer Handling
*/
impl wl_pointer::Handler for InputHandler {
fn enter(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_serial: u32,
surface: &wl_surface::WlSurface,
surface_x: f64,
surface_y: f64)
{
self.mouse_location = (surface_x as i32, surface_y as i32);
for window in &self.windows {
if window.equals(surface) {
self.mouse_focus = Some(window.clone());
let (w, h) = self.mouse_location;
let mut guard = self.callback.lock().unwrap();
guard.send_event(Event::MouseEntered, make_wid(window));
guard.send_event(Event::MouseMoved(w, h), make_wid(window));
break;
}
}
}
fn leave(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_serial: u32,
surface: &wl_surface::WlSurface)
{
self.mouse_focus = None;
for window in &self.windows {
if window.equals(surface) {
self.callback.lock().unwrap().send_event(Event::MouseLeft, make_wid(window));
}
}
}
fn motion(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_time: u32,
surface_x: f64,
surface_y: f64)
{
self.mouse_location = (surface_x as i32, surface_y as i32);
if let Some(ref window) = self.mouse_focus {
let (w,h) = self.mouse_location;
self.callback.lock().unwrap().send_event(Event::MouseMoved(w, h), make_wid(window));
}
}
fn button(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_serial: u32,
_time: u32,
button: u32,
state: wl_pointer::ButtonState)
{
if let Some(ref window) = self.mouse_focus {
let state = match state {
wl_pointer::ButtonState::Pressed => ElementState::Pressed,
wl_pointer::ButtonState::Released => ElementState::Released
};
let button = match button {
0x110 => MouseButton::Left,
0x111 => MouseButton::Right,
0x112 => MouseButton::Middle,
// TODO figure out the translation ?
_ => return
};
self.callback.lock().unwrap().send_event(Event::MouseInput(state, button), make_wid(window));
}
}
fn axis(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_time: u32,
axis: wl_pointer::Axis,
value: f64)
{
let (mut x, mut y) = self.axis_buffer.unwrap_or((0.0, 0.0));
match axis {
wl_pointer::Axis::VerticalScroll => y += value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32
}
self.axis_buffer = Some((x,y));
self.axis_state = match self.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
}
fn frame(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer)
{
let axis_buffer = self.axis_buffer.take();
let axis_discrete_buffer = self.axis_discrete_buffer.take();
if let Some(ref window) = self.mouse_focus {
if let Some((x, y)) = axis_discrete_buffer {
self.callback.lock().unwrap().send_event(
Event::MouseWheel(
MouseScrollDelta::LineDelta(x as f32, y as f32),
self.axis_state
),
make_wid(window)
);
} else if let Some((x, y)) = axis_buffer {
self.callback.lock().unwrap().send_event(
Event::MouseWheel(
MouseScrollDelta::PixelDelta(x as f32, y as f32),
self.axis_state
),
make_wid(window)
);
}
}
}
fn axis_source(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_axis_source: wl_pointer::AxisSource)
{
}
fn axis_stop(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_time: u32,
_axis: wl_pointer::Axis)
{
self.axis_state = TouchPhase::Ended;
}
fn axis_discrete(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
axis: wl_pointer::Axis,
discrete: i32)
{
let (mut x, mut y) = self.axis_discrete_buffer.unwrap_or((0,0));
match axis {
wl_pointer::Axis::VerticalScroll => y += discrete,
wl_pointer::Axis::HorizontalScroll => x += discrete
}
self.axis_discrete_buffer = Some((x,y));
self.axis_state = match self.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
}
}
declare_handler!(InputHandler, wl_pointer::Handler, wl_pointer::WlPointer);
/*
* Keyboard Handling
*/
impl wl_keyboard::Handler for InputHandler {
// mostly pass-through
fn keymap(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
format: wl_keyboard::KeymapFormat,
fd: ::std::os::unix::io::RawFd,
size: u32)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.keymap(evqh, proxy, format, fd, size),
_ => ()
}
}
fn enter(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
surface: &wl_surface::WlSurface,
keys: Vec<u8>)
{
for window in &self.windows {
if window.equals(surface) {
self.callback.lock().unwrap().send_event(Event::Focused(true), make_wid(window));
match self.kbd_handler {
KbdType::Mapped(ref mut h) => {
h.handler().target = Some(make_wid(window));
h.enter(evqh, proxy, serial, surface, keys);
},
KbdType::Plain(ref mut target) => {
*target = Some(make_wid(window))
}
}
break;
}
}
}
fn leave(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
surface: &wl_surface::WlSurface)
{
for window in &self.windows {
if window.equals(surface) {
self.callback.lock().unwrap().send_event(Event::Focused(false), make_wid(window));
match self.kbd_handler {
KbdType::Mapped(ref mut h) => {
h.handler().target = None;
h.leave(evqh, proxy, serial, surface);
},
KbdType::Plain(ref mut target) => {
*target = None
}
}
break;
}
}
}
fn key(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
time: u32,
key: u32,
state: wl_keyboard::KeyState)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.key(evqh, proxy, serial, time, key, state),
KbdType::Plain(Some(wid)) => {
let state = match state {
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
wl_keyboard::KeyState::Released => ElementState::Released,
};
// This is fallback impl if libxkbcommon was not available
// This case should probably never happen, as most wayland
// compositors _need_ libxkbcommon anyway...
//
// In this case, we don't have the modifiers state information
// anyway, as we need libxkbcommon to interpret it (it is
// supposed to be serialized by the compositor using libxkbcommon)
self.callback.lock().unwrap().send_event(
Event::KeyboardInput(
state,
key as u8,
None,
ModifiersState::default()
),
wid
);
},
KbdType::Plain(None) => ()
}
}
fn modifiers(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
mods_depressed: u32,
mods_latched: u32,
mods_locked: u32,
group: u32)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.modifiers(evqh, proxy, serial, mods_depressed,
mods_latched, mods_locked, group),
_ => ()
}
}
fn repeat_info(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
rate: i32,
delay: i32)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.repeat_info(evqh, proxy, rate, delay),
_ => ()
}
}
}
declare_handler!(InputHandler, wl_keyboard::Handler, wl_keyboard::WlKeyboard);

View file

@ -4,17 +4,18 @@ use {VirtualKeyCode, ElementState, WindowEvent as Event};
use events::ModifiersState; use events::ModifiersState;
use super::{wayland_kbd, make_wid, EventsLoopSink}; use super::{wayland_kbd, EventsLoopSink, WindowId};
use wayland_client::EventQueueHandle; use wayland_client::EventQueueHandle;
use wayland_client::protocol::{wl_keyboard, wl_surface}; use wayland_client::protocol::wl_keyboard;
pub struct KbdHandler { pub struct KbdHandler {
pub target: Option<(Arc<wl_surface::WlSurface>,Arc<Mutex<EventsLoopSink>>)> sink: Arc<Mutex<EventsLoopSink>>,
pub target: Option<WindowId>
} }
impl KbdHandler { impl KbdHandler {
pub fn new() -> KbdHandler { pub fn new(sink: Arc<Mutex<EventsLoopSink>>) -> KbdHandler {
KbdHandler { target: None } KbdHandler { sink: sink, target: None }
} }
} }
@ -30,14 +31,14 @@ impl wayland_kbd::Handler for KbdHandler {
state: wl_keyboard::KeyState, state: wl_keyboard::KeyState,
utf8: Option<String>) utf8: Option<String>)
{ {
if let Some((ref window, ref sink)) = self.target { if let Some(wid) = self.target {
let state = match state { let state = match state {
wl_keyboard::KeyState::Pressed => ElementState::Pressed, wl_keyboard::KeyState::Pressed => ElementState::Pressed,
wl_keyboard::KeyState::Released => ElementState::Released, wl_keyboard::KeyState::Released => ElementState::Released,
}; };
let vkcode = key_to_vkey(rawkey, keysym); let vkcode = key_to_vkey(rawkey, keysym);
let mut guard = sink.lock().unwrap(); let mut guard = self.sink.lock().unwrap();
guard.push_event( guard.send_event(
Event::KeyboardInput( Event::KeyboardInput(
state, state,
rawkey as u8, rawkey as u8,
@ -49,13 +50,13 @@ impl wayland_kbd::Handler for KbdHandler {
logo: mods.logo logo: mods.logo
} }
), ),
make_wid(window) wid
); );
// send char event only on key press, not release // send char event only on key press, not release
if let ElementState::Released = state { return } if let ElementState::Released = state { return }
if let Some(txt) = utf8 { if let Some(txt) = utf8 {
for chr in txt.chars() { for chr in txt.chars() {
guard.push_event(Event::ReceivedCharacter(chr), make_wid(window)); guard.send_event(Event::ReceivedCharacter(chr), wid);
} }
} }
} }

View file

@ -1,6 +1,6 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use wayland_client::{EventQueue, EventQueueHandle, Init, Proxy}; use wayland_client::{EventQueue, EventQueueHandle, Proxy};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface}; use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};
use {CreationError, MouseCursor, CursorState, WindowAttributes}; use {CreationError, MouseCursor, CursorState, WindowAttributes};
@ -31,7 +31,7 @@ impl Window {
{ {
let (width, height) = attributes.dimensions.unwrap_or((800,600)); let (width, height) = attributes.dimensions.unwrap_or((800,600));
let (surface, decorated) = ctxt.create_window::<DecoratedHandler>(evlp.get_sink()); let (surface, decorated) = ctxt.create_window::<DecoratedHandler>();
// init DecoratedSurface // init DecoratedSurface
let evq = evlp.get_event_queue(); let evq = evlp.get_event_queue();
@ -67,7 +67,7 @@ impl Window {
decorated_id: decorated_id decorated_id: decorated_id
}; };
evlp.register_window(me.decorated_id, me.id()); evlp.register_window(me.decorated_id, me.surface.clone());
Ok(me) Ok(me)
} }
@ -165,7 +165,6 @@ impl Window {
impl Drop for Window { impl Drop for Window {
fn drop(&mut self) { fn drop(&mut self) {
self.surface.destroy(); self.surface.destroy();
self.ctxt.prune_dead_windows();
} }
} }