wayland: migrate to smithay-client-toolkit (#490)

* wayland: migrate to smithay-client-toolkit

* Update smithay-client-toolkit

* Add changelog entry for wayland rework
This commit is contained in:
Victor Berger 2018-05-05 19:36:34 +02:00 committed by Francesca Frangipane
parent cc8907b956
commit 1e97103094
11 changed files with 764 additions and 902 deletions

View file

@ -15,6 +15,7 @@
- Fixed memory leak on X11 every time the mouse entered the window. - Fixed memory leak on X11 every time the mouse entered the window.
- On X11, drag and drop now works reliably in release mode. - On X11, drag and drop now works reliably in release mode.
- Added `WindowBuilderExt::with_resize_increments` and `WindowBuilderExt::with_base_size` to X11, allowing for more optional hints to be set. - Added `WindowBuilderExt::with_resize_increments` and `WindowBuilderExt::with_base_size` to X11, allowing for more optional hints to be set.
- Rework of the wayland backend, migrating it to use [Smithay's Client Toolkit](https://github.com/Smithay/client-toolkit).
# Version 0.13.1 (2018-04-26) # Version 0.13.1 (2018-04-26)

View file

@ -44,10 +44,8 @@ features = [
] ]
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies]
wayland-client = { version = "0.12.0", features = ["dlopen"] } wayland-client = { version = "0.20.2", features = [ "dlopen", "egl", "cursor"] }
wayland-protocols = { version = "0.12.0", features = ["unstable_protocols"] } smithay-client-toolkit = "0.2.1"
wayland-kbd = "0.13.0"
wayland-window = "0.13.0"
x11-dl = "2.17.5" x11-dl = "2.17.5"
parking_lot = "0.5" parking_lot = "0.5"
percent-encoding = "1.0" percent-encoding = "1.0"

View file

@ -105,8 +105,7 @@ extern crate parking_lot;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
extern crate percent_encoding; extern crate percent_encoding;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
#[macro_use] extern crate smithay_client_toolkit as sctk;
extern crate wayland_client;
pub use events::*; pub use events::*;
pub use window::{AvailableMonitorsIter, MonitorId}; pub use window::{AvailableMonitorsIter, MonitorId};

View file

@ -173,18 +173,16 @@ impl WindowExt for Window {
#[inline] #[inline]
fn get_wayland_surface(&self) -> Option<*mut raw::c_void> { fn get_wayland_surface(&self) -> Option<*mut raw::c_void> {
use wayland_client::Proxy;
match self.window { match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_surface().ptr() as *mut _), LinuxWindow::Wayland(ref w) => Some(w.get_surface().c_ptr() as *mut _),
_ => None _ => None
} }
} }
#[inline] #[inline]
fn get_wayland_display(&self) -> Option<*mut raw::c_void> { fn get_wayland_display(&self) -> Option<*mut raw::c_void> {
use wayland_client::Proxy;
match self.window { match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_display().ptr() as *mut _), LinuxWindow::Wayland(ref w) => Some(w.get_display().c_ptr() as *mut _),
_ => None _ => None
} }
} }

View file

@ -255,19 +255,17 @@ impl Window {
#[inline] #[inline]
pub fn platform_display(&self) -> *mut libc::c_void { pub fn platform_display(&self) -> *mut libc::c_void {
use wayland_client::Proxy;
match self { match self {
&Window::X(ref w) => w.platform_display(), &Window::X(ref w) => w.platform_display(),
&Window::Wayland(ref w) => w.get_display().ptr() as *mut _ &Window::Wayland(ref w) => w.get_display().c_ptr() as *mut _
} }
} }
#[inline] #[inline]
pub fn platform_window(&self) -> *mut libc::c_void { pub fn platform_window(&self) -> *mut libc::c_void {
use wayland_client::Proxy;
match self { match self {
&Window::X(ref w) => w.platform_window(), &Window::X(ref w) => w.platform_window(),
&Window::Wayland(ref w) => w.get_surface().ptr() as *mut _ &Window::Wayland(ref w) => w.get_surface().c_ptr() as *mut _
} }
} }

View file

@ -3,37 +3,35 @@ use std::collections::VecDeque;
use std::sync::{Arc, Mutex, Weak}; use std::sync::{Arc, Mutex, Weak};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use {EventsLoopClosed, ControlFlow}; use {ControlFlow, EventsLoopClosed};
use super::WindowId; use super::WindowId;
use super::window::WindowStore; use super::window::WindowStore;
use super::keyboard::init_keyboard;
use wayland_client::{EnvHandler, EnvNotify, default_connect, EventQueue, EventQueueHandle, Proxy, StateToken}; use sctk::Environment;
use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor, use sctk::output::OutputMgr;
wl_display, wl_registry, wl_output, wl_surface, use sctk::reexports::client::{Display, EventQueue, GlobalEvent, Proxy};
wl_pointer, wl_keyboard, wl_touch}; use sctk::reexports::client::commons::Implementation;
use sctk::reexports::client::protocol::{wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat,
wl_touch};
use super::wayland_window::{Frame, Shell, create_frame, FrameImplementation}; use sctk::reexports::client::protocol::wl_display::RequestsTrait as DisplayRequests;
use super::wayland_protocols::unstable::xdg_shell::v6::client::zxdg_shell_v6;
pub struct EventsLoopSink { pub struct EventsLoopSink {
buffer: VecDeque<::Event> buffer: VecDeque<::Event>,
} }
unsafe impl Send for EventsLoopSink { }
impl EventsLoopSink { impl EventsLoopSink {
pub fn new() -> EventsLoopSink{ pub fn new() -> EventsLoopSink {
EventsLoopSink { EventsLoopSink {
buffer: VecDeque::new() buffer: VecDeque::new(),
} }
} }
pub fn send_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)),
}; };
self.buffer.push_back(evt); self.buffer.push_back(evt);
} }
@ -42,7 +40,10 @@ impl EventsLoopSink {
self.buffer.push_back(evt); self.buffer.push_back(evt);
} }
fn empty_with<F>(&mut self, callback: &mut F) where F: FnMut(::Event) { fn empty_with<F>(&mut self, callback: &mut F)
where
F: FnMut(::Event),
{
for evt in self.buffer.drain(..) { for evt in self.buffer.drain(..) {
callback(evt) callback(evt)
} }
@ -57,15 +58,15 @@ pub struct EventsLoop {
// Whether or not there is a pending `Awakened` event to be emitted. // Whether or not there is a pending `Awakened` event to be emitted.
pending_wakeup: Arc<AtomicBool>, pending_wakeup: Arc<AtomicBool>,
// The window store // The window store
pub store: StateToken<WindowStore>, pub store: Arc<Mutex<WindowStore>>,
// the env // the env
env_token: StateToken<EnvHandler<InnerEnv>>, pub env: Environment,
// the ctxt
pub ctxt_token: StateToken<StateContext>,
// a cleanup switch to prune dead windows // a cleanup switch to prune dead windows
pub cleanup_needed: Arc<Mutex<bool>>, pub cleanup_needed: Arc<Mutex<bool>>,
// The wayland display // The wayland display
pub display: Arc<wl_display::WlDisplay>, pub display: Arc<Display>,
// The list of seats
pub seats: Arc<Mutex<Vec<(u32, Proxy<wl_seat::WlSeat>)>>>,
} }
// A handle that can be sent across threads and used to wake up the `EventsLoop`. // A handle that can be sent across threads and used to wake up the `EventsLoop`.
@ -73,7 +74,7 @@ pub struct EventsLoop {
// We should only try and wake up the `EventsLoop` if it still exists, so we hold Weak ptrs. // We should only try and wake up the `EventsLoop` if it still exists, so we hold Weak ptrs.
#[derive(Clone)] #[derive(Clone)]
pub struct EventsLoopProxy { pub struct EventsLoopProxy {
display: Weak<wl_display::WlDisplay>, display: Weak<Display>,
pending_wakeup: Weak<AtomicBool>, pending_wakeup: Weak<AtomicBool>,
} }
@ -89,10 +90,10 @@ impl EventsLoopProxy {
// Update the `EventsLoop`'s `pending_wakeup` flag. // Update the `EventsLoop`'s `pending_wakeup` flag.
wakeup.store(true, Ordering::Relaxed); wakeup.store(true, Ordering::Relaxed);
// Cause the `EventsLoop` to break from `dispatch` if it is currently blocked. // Cause the `EventsLoop` to break from `dispatch` if it is currently blocked.
display.sync(); let _ = display.sync();
display.flush().map_err(|_| EventsLoopClosed)?; display.flush().map_err(|_| EventsLoopClosed)?;
Ok(()) Ok(())
}, }
_ => Err(EventsLoopClosed), _ => Err(EventsLoopClosed),
} }
} }
@ -100,58 +101,35 @@ impl EventsLoopProxy {
impl EventsLoop { impl EventsLoop {
pub fn new() -> Option<EventsLoop> { pub fn new() -> Option<EventsLoop> {
let (display, mut event_queue) = match default_connect() { let (display, mut event_queue) = match Display::connect_to_env() {
Ok(ret) => ret, Ok(ret) => ret,
Err(_) => return None Err(_) => return None,
}; };
let registry = display.get_registry();
let ctxt_token = event_queue.state().insert(
StateContext::new(registry.clone().unwrap())
);
let env_token = EnvHandler::init_with_notify(
&mut event_queue,
&registry,
env_notify(),
ctxt_token.clone()
);
// two round trips to fully initialize
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
event_queue.state().with_value(&ctxt_token, |proxy, ctxt| {
ctxt.ensure_shell(proxy.get_mut(&env_token))
});
let sink = Arc::new(Mutex::new(EventsLoopSink::new())); let sink = Arc::new(Mutex::new(EventsLoopSink::new()));
let store = Arc::new(Mutex::new(WindowStore::new()));
let seats = Arc::new(Mutex::new(Vec::new()));
let store = event_queue.state().insert(WindowStore::new()); let env = Environment::from_registry_with_cb(
display.get_registry().unwrap(),
&mut event_queue,
SeatManager {
sink: sink.clone(),
store: store.clone(),
seats: seats.clone(),
},
).unwrap();
let seat_idata = SeatIData { Some(EventsLoop {
sink: sink.clone(),
keyboard: None,
pointer: None,
touch: None,
windows_token: store.clone()
};
let mut me = EventsLoop {
display: Arc::new(display), display: Arc::new(display),
evq: RefCell::new(event_queue), evq: RefCell::new(event_queue),
sink: sink, sink: sink,
pending_wakeup: Arc::new(AtomicBool::new(false)), pending_wakeup: Arc::new(AtomicBool::new(false)),
store: store, store: store,
ctxt_token: ctxt_token, env: env,
env_token: env_token, cleanup_needed: Arc::new(Mutex::new(false)),
cleanup_needed: Arc::new(Mutex::new(false)) seats: seats,
}; })
me.init_seat(|evqh, seat| {
evqh.register(seat, seat_implementation(), seat_idata);
});
Some(me)
} }
pub fn create_proxy(&self) -> EventsLoopProxy { pub fn create_proxy(&self) -> EventsLoopProxy {
@ -162,7 +140,8 @@ impl EventsLoop {
} }
pub fn poll_events<F>(&mut self, mut callback: F) pub fn poll_events<F>(&mut self, mut callback: F)
where F: FnMut(::Event) where
F: FnMut(::Event),
{ {
// send pending events to the server // send pending events to the server
self.display.flush().expect("Wayland connection lost."); self.display.flush().expect("Wayland connection lost.");
@ -175,7 +154,10 @@ impl EventsLoop {
h.read_events().expect("Wayland connection lost."); h.read_events().expect("Wayland connection lost.");
} }
// dispatch wayland events // dispatch wayland events
self.evq.get_mut().dispatch_pending().expect("Wayland connection lost."); self.evq
.get_mut()
.dispatch_pending()
.expect("Wayland connection lost.");
self.post_dispatch_triggers(); self.post_dispatch_triggers();
// dispatch buffered events to client // dispatch buffered events to client
@ -183,15 +165,18 @@ impl EventsLoop {
} }
pub fn run_forever<F>(&mut self, mut callback: F) pub fn run_forever<F>(&mut self, mut callback: F)
where F: FnMut(::Event) -> ControlFlow, where
F: FnMut(::Event) -> ControlFlow,
{ {
// send pending events to the server // send pending events to the server
self.display.flush().expect("Wayland connection lost."); self.display.flush().expect("Wayland connection lost.");
// Check for control flow by wrapping the callback. // Check for control flow by wrapping the callback.
let control_flow = ::std::cell::Cell::new(ControlFlow::Continue); let control_flow = ::std::cell::Cell::new(ControlFlow::Continue);
let mut callback = |event| if let ControlFlow::Break = callback(event) { let mut callback = |event| {
control_flow.set(ControlFlow::Break); if let ControlFlow::Break = callback(event) {
control_flow.set(ControlFlow::Break);
}
}; };
// dispatch any pre-buffered events // dispatch any pre-buffered events
@ -200,7 +185,10 @@ impl EventsLoop {
loop { loop {
// dispatch events blocking if needed // dispatch events blocking if needed
self.evq.get_mut().dispatch().expect("Wayland connection lost."); self.evq
.get_mut()
.dispatch()
.expect("Wayland connection lost.");
self.post_dispatch_triggers(); self.post_dispatch_triggers();
// empty buffer of events // empty buffer of events
@ -213,25 +201,27 @@ impl EventsLoop {
} }
pub fn get_primary_monitor(&self) -> MonitorId { pub fn get_primary_monitor(&self) -> MonitorId {
let mut guard = self.evq.borrow_mut(); self.env.outputs.with_all(|list| {
let state = guard.state(); if let Some(&(_, ref proxy, _)) = list.first() {
let state_ctxt = state.get(&self.ctxt_token); MonitorId {
if let Some(info) = state_ctxt.monitors.iter().next() { proxy: proxy.clone(),
MonitorId { mgr: self.env.outputs.clone(),
info: info.clone() }
} else {
panic!("No monitor is available.")
} }
} else { })
panic!("No monitor is available.")
}
} }
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> { pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
let mut guard = self.evq.borrow_mut(); self.env.outputs.with_all(|list| {
let state = guard.state(); list.iter()
let state_ctxt = state.get(&self.ctxt_token); .map(|&(_, ref proxy, _)| MonitorId {
state_ctxt.monitors.iter() proxy: proxy.clone(),
.map(|m| MonitorId { info: m.clone() }) mgr: self.env.outputs.clone(),
.collect() })
.collect()
})
} }
} }
@ -239,93 +229,9 @@ impl EventsLoop {
* Private EventsLoop Internals * Private EventsLoop Internals
*/ */
wayland_env!(InnerEnv,
compositor: wl_compositor::WlCompositor,
shm: wl_shm::WlShm,
subcompositor: wl_subcompositor::WlSubcompositor
);
pub struct StateContext {
registry: wl_registry::WlRegistry,
seat: Option<wl_seat::WlSeat>,
shell: Option<Shell>,
monitors: Vec<Arc<Mutex<OutputInfo>>>
}
impl StateContext {
fn new(registry: wl_registry::WlRegistry) -> StateContext {
StateContext {
registry: registry,
seat: None,
shell: None,
monitors: Vec::new()
}
}
/// Ensures a shell is available
///
/// If a shell is already bound, do nothing. Otherwise,
/// try to bind wl_shell as a fallback. If this fails,
/// panic, as this is a bug from the compositor.
fn ensure_shell(&mut self, env: &mut EnvHandler<InnerEnv>) {
if self.shell.is_some() {
return;
}
// xdg_shell is not available, so initialize wl_shell
for &(name, ref interface, _) in env.globals() {
if interface == "wl_shell" {
self.shell = Some(Shell::Wl(self.registry.bind::<wl_shell::WlShell>(1, name)));
return;
}
}
// This is a compositor bug, it _must_ at least support wl_shell
panic!("Compositor didi not advertize xdg_shell not wl_shell.");
}
pub fn monitor_id_for(&self, output: &wl_output::WlOutput) -> MonitorId {
for info in &self.monitors {
let guard = info.lock().unwrap();
if guard.output.equals(output) {
return MonitorId {
info: info.clone()
};
}
}
panic!("Received an inexistent wl_output?!");
}
}
impl EventsLoop { impl EventsLoop {
pub fn init_seat<F>(&mut self, f: F)
where F: FnOnce(&mut EventQueueHandle, &wl_seat::WlSeat)
{
let mut guard = self.evq.borrow_mut();
if guard.state().get(&self.ctxt_token).seat.is_some() {
// seat has already been init
return;
}
// clone the token to make borrow checker happy
let ctxt_token = self.ctxt_token.clone();
let seat = guard.state().with_value(&self.env_token, |proxy, env| {
let ctxt = proxy.get(&ctxt_token);
for &(name, ref interface, _) in env.globals() {
if interface == wl_seat::WlSeat::interface_name() {
return Some(ctxt.registry.bind::<wl_seat::WlSeat>(5, name));
}
}
None
});
if let Some(seat) = seat {
f(&mut *guard, &seat);
guard.state().get_mut(&self.ctxt_token).seat = Some(seat)
}
}
fn post_dispatch_triggers(&mut self) { fn post_dispatch_triggers(&mut self) {
let mut sink = self.sink.lock().unwrap(); let mut sink = self.sink.lock().unwrap();
let evq = self.evq.get_mut();
// process a possible pending wakeup call // process a possible pending wakeup call
if self.pending_wakeup.load(Ordering::Relaxed) { if self.pending_wakeup.load(Ordering::Relaxed) {
sink.send_raw_event(::Event::Awakened); sink.send_raw_event(::Event::Awakened);
@ -335,7 +241,7 @@ impl EventsLoop {
{ {
let mut cleanup_needed = self.cleanup_needed.lock().unwrap(); let mut cleanup_needed = self.cleanup_needed.lock().unwrap();
if *cleanup_needed { if *cleanup_needed {
let pruned = evq.state().get_mut(&self.store).cleanup(); let pruned = self.store.lock().unwrap().cleanup();
*cleanup_needed = false; *cleanup_needed = false;
for wid in pruned { for wid in pruned {
sink.send_event(::WindowEvent::Destroyed, wid); sink.send_event(::WindowEvent::Destroyed, wid);
@ -343,11 +249,11 @@ impl EventsLoop {
} }
} }
// process pending resize/refresh // process pending resize/refresh
evq.state().get_mut(&self.store).for_each( self.store.lock().unwrap().for_each(
|newsize, refresh, frame_refresh, closed, wid, frame| { |newsize, refresh, frame_refresh, closed, wid, frame| {
if let Some(frame) = frame { if let Some(frame) = frame {
if let Some((w, h)) = newsize { if let Some((w, h)) = newsize {
frame.resize(w as i32, h as i32); frame.resize(w as u32, h as u32);
frame.refresh(); frame.refresh();
sink.send_event(::WindowEvent::Resized(w as u32, h as u32), wid); sink.send_event(::WindowEvent::Resized(w as u32, h as u32), wid);
} else if frame_refresh { } else if frame_refresh {
@ -360,140 +266,147 @@ impl EventsLoop {
if closed { if closed {
sink.send_event(::WindowEvent::CloseRequested, wid); sink.send_event(::WindowEvent::CloseRequested, wid);
} }
} },
) )
} }
/// Create a new window with given dimensions
///
/// Grabs a lock on the event queue in the process
pub fn create_window<ID: 'static, F>(&self, width: u32, height: u32, implem: FrameImplementation<ID>, idata: F)
-> (wl_surface::WlSurface, Frame)
where F: FnOnce(&wl_surface::WlSurface) -> ID
{
let (surface, frame) = {
let mut guard = self.evq.borrow_mut();
let env = guard.state().get(&self.env_token).clone_inner().unwrap();
let shell = match guard.state().get(&self.ctxt_token).shell {
Some(Shell::Wl(ref wl_shell)) => Shell::Wl(wl_shell.clone().unwrap()),
Some(Shell::Xdg(ref xdg_shell)) => Shell::Xdg(xdg_shell.clone().unwrap()),
None => unreachable!()
};
let seat = guard.state().get(&self.ctxt_token).seat.as_ref().and_then(|s| s.clone());
let surface = env.compositor.create_surface();
let frame = create_frame(
&mut guard,
implem,
idata(&surface),
&surface, width as i32, height as i32,
&env.compositor,
&env.subcompositor,
&env.shm,
&shell,
seat
).expect("Failed to create a tmpfile buffer.");
(surface, frame)
};
(surface, frame)
}
} }
/* /*
* Wayland protocol implementations * Wayland protocol implementations
*/ */
fn env_notify() -> EnvNotify<StateToken<StateContext>> { struct SeatManager {
EnvNotify { sink: Arc<Mutex<EventsLoopSink>>,
new_global: |evqh, token, registry, id, interface, version| { store: Arc<Mutex<WindowStore>>,
use std::cmp::min; seats: Arc<Mutex<Vec<(u32, Proxy<wl_seat::WlSeat>)>>>,
if interface == wl_output::WlOutput::interface_name() {
// a new output is available
let output = registry.bind::<wl_output::WlOutput>(min(version, 3), id);
evqh.register(&output, output_impl(), token.clone());
evqh.state().get_mut(&token).monitors.push(
Arc::new(Mutex::new(OutputInfo::new(output, id)))
);
} else if interface == zxdg_shell_v6::ZxdgShellV6::interface_name() {
// We have an xdg_shell, bind it
let xdg_shell = registry.bind::<zxdg_shell_v6::ZxdgShellV6>(1, id);
evqh.register(&xdg_shell, xdg_ping_implementation(), ());
evqh.state().get_mut(&token).shell = Some(Shell::Xdg(xdg_shell));
}
},
del_global: |evqh, token, _, id| {
// maybe this was a monitor, cleanup
evqh.state().get_mut(&token).monitors.retain(
|m| m.lock().unwrap().id != id
);
},
ready: |_, _, _| {}
}
} }
fn xdg_ping_implementation() -> zxdg_shell_v6::Implementation<()> { impl Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> for SeatManager {
zxdg_shell_v6::Implementation { fn receive(&mut self, evt: GlobalEvent, registry: Proxy<wl_registry::WlRegistry>) {
ping: |_, _, shell, serial| { use self::wl_registry::RequestsTrait as RegistryRequests;
shell.pong(serial); use self::wl_seat::RequestsTrait as SeatRequests;
match evt {
GlobalEvent::New {
id,
ref interface,
version,
} if interface == "wl_seat" =>
{
use std::cmp::min;
let seat = registry
.bind::<wl_seat::WlSeat>(min(version, 5), id)
.unwrap()
.implement(SeatData {
sink: self.sink.clone(),
store: self.store.clone(),
pointer: None,
keyboard: None,
touch: None,
});
self.store.lock().unwrap().new_seat(&seat);
self.seats.lock().unwrap().push((id, seat));
}
GlobalEvent::Removed { id, ref interface } if interface == "wl_seat" => {
let mut seats = self.seats.lock().unwrap();
if let Some(idx) = seats.iter().position(|&(i, _)| i == id) {
let (_, seat) = seats.swap_remove(idx);
if seat.version() >= 5 {
seat.release();
}
}
}
_ => (),
} }
} }
} }
struct SeatIData { struct SeatData {
sink: Arc<Mutex<EventsLoopSink>>, sink: Arc<Mutex<EventsLoopSink>>,
pointer: Option<wl_pointer::WlPointer>, store: Arc<Mutex<WindowStore>>,
keyboard: Option<wl_keyboard::WlKeyboard>, pointer: Option<Proxy<wl_pointer::WlPointer>>,
touch: Option<wl_touch::WlTouch>, keyboard: Option<Proxy<wl_keyboard::WlKeyboard>>,
windows_token: StateToken<WindowStore> touch: Option<Proxy<wl_touch::WlTouch>>,
} }
fn seat_implementation() -> wl_seat::Implementation<SeatIData> { impl Implementation<Proxy<wl_seat::WlSeat>, wl_seat::Event> for SeatData {
wl_seat::Implementation { fn receive(&mut self, evt: wl_seat::Event, seat: Proxy<wl_seat::WlSeat>) {
name: |_, _, _, _| {}, use self::wl_seat::RequestsTrait as SeatRequests;
capabilities: |evqh, idata, seat, capabilities| { match evt {
// create pointer if applicable wl_seat::Event::Name { .. } => (),
if capabilities.contains(wl_seat::Capability::Pointer) && idata.pointer.is_none() { wl_seat::Event::Capabilities { capabilities } => {
let pointer = seat.get_pointer().expect("Seat is not dead"); // create pointer if applicable
let p_idata = super::pointer::PointerIData::new( if capabilities.contains(wl_seat::Capability::Pointer) && self.pointer.is_none() {
&idata.sink, self.pointer = Some(super::pointer::implement_pointer(
idata.windows_token.clone() seat.get_pointer().unwrap(),
); self.sink.clone(),
evqh.register(&pointer, super::pointer::pointer_implementation(), p_idata); self.store.clone(),
idata.pointer = Some(pointer); ))
} }
// destroy pointer if applicable // destroy pointer if applicable
if !capabilities.contains(wl_seat::Capability::Pointer) { if !capabilities.contains(wl_seat::Capability::Pointer) {
if let Some(pointer) = idata.pointer.take() { if let Some(pointer) = self.pointer.take() {
pointer.release(); if pointer.version() >= 3 {
use self::wl_pointer::RequestsTrait;
pointer.release();
}
}
}
// create keyboard if applicable
if capabilities.contains(wl_seat::Capability::Keyboard) && self.keyboard.is_none() {
self.keyboard = Some(super::keyboard::init_keyboard(
seat.get_keyboard().unwrap(),
self.sink.clone(),
))
}
// destroy keyboard if applicable
if !capabilities.contains(wl_seat::Capability::Keyboard) {
if let Some(kbd) = self.keyboard.take() {
if kbd.version() >= 3 {
use self::wl_keyboard::RequestsTrait;
kbd.release();
}
}
}
// create touch if applicable
if capabilities.contains(wl_seat::Capability::Touch) && self.touch.is_none() {
self.touch = Some(super::touch::implement_touch(
seat.get_touch().unwrap(),
self.sink.clone(),
self.store.clone(),
))
}
// destroy touch if applicable
if !capabilities.contains(wl_seat::Capability::Touch) {
if let Some(touch) = self.touch.take() {
if touch.version() >= 3 {
use self::wl_touch::RequestsTrait;
touch.release();
}
}
} }
} }
// create keyboard if applicable }
if capabilities.contains(wl_seat::Capability::Keyboard) && idata.keyboard.is_none() { }
let kbd = seat.get_keyboard().expect("Seat is not dead"); }
init_keyboard(evqh, &kbd, &idata.sink);
idata.keyboard = Some(kbd); impl Drop for SeatData {
fn drop(&mut self) {
if let Some(pointer) = self.pointer.take() {
if pointer.version() >= 3 {
use self::wl_pointer::RequestsTrait;
pointer.release();
} }
// destroy keyboard if applicable }
if !capabilities.contains(wl_seat::Capability::Keyboard) { if let Some(kbd) = self.keyboard.take() {
if let Some(kbd) = idata.keyboard.take() { if kbd.version() >= 3 {
kbd.release(); use self::wl_keyboard::RequestsTrait;
} kbd.release();
} }
// create touch if applicable }
if capabilities.contains(wl_seat::Capability::Touch) && idata.touch.is_none() { if let Some(touch) = self.touch.take() {
let touch = seat.get_touch().expect("Seat is not dead"); if touch.version() >= 3 {
let t_idata = super::touch::TouchIData::new( use self::wl_touch::RequestsTrait;
&idata.sink, touch.release();
idata.windows_token.clone()
);
evqh.register(&touch, super::touch::touch_implementation(), t_idata);
idata.touch = Some(touch);
}
// destroy touch if applicable
if !capabilities.contains(wl_seat::Capability::Touch) {
if let Some(touch) = idata.touch.take() {
touch.release();
}
} }
} }
} }
@ -503,92 +416,54 @@ fn seat_implementation() -> wl_seat::Implementation<SeatIData> {
* Monitor stuff * Monitor stuff
*/ */
fn output_impl() -> wl_output::Implementation<StateToken<StateContext>> {
wl_output::Implementation {
geometry: |evqh, token, output, x, y, _, _, _, make, model, _| {
let ctxt = evqh.state().get_mut(token);
for info in &ctxt.monitors {
let mut guard = info.lock().unwrap();
if guard.output.equals(output) {
guard.pix_pos = (x, y);
guard.name = format!("{} - {}", make, model);
return;
}
}
},
mode: |evqh, token, output, flags, w, h, _refresh| {
if flags.contains(wl_output::Mode::Current) {
let ctxt = evqh.state().get_mut(token);
for info in &ctxt.monitors {
let mut guard = info.lock().unwrap();
if guard.output.equals(output) {
guard.pix_size = (w as u32, h as u32);
return;
}
}
}
},
done: |_, _, _| {},
scale: |evqh, token, output, scale| {
let ctxt = evqh.state().get_mut(token);
for info in &ctxt.monitors {
let mut guard = info.lock().unwrap();
if guard.output.equals(output) {
guard.scale = scale as f32;
return;
}
}
}
}
}
pub struct OutputInfo {
pub output: wl_output::WlOutput,
pub id: u32,
pub scale: f32,
pub pix_size: (u32, u32),
pub pix_pos: (i32, i32),
pub name: String
}
impl OutputInfo {
fn new(output: wl_output::WlOutput, id: u32) -> OutputInfo {
OutputInfo {
output: output,
id: id,
scale: 1.0,
pix_size: (0, 0),
pix_pos: (0, 0),
name: "".into()
}
}
}
#[derive(Clone)]
pub struct MonitorId { pub struct MonitorId {
pub info: Arc<Mutex<OutputInfo>> pub(crate) proxy: Proxy<wl_output::WlOutput>,
pub(crate) mgr: OutputMgr,
}
impl Clone for MonitorId {
fn clone(&self) -> MonitorId {
MonitorId {
proxy: self.proxy.clone(),
mgr: self.mgr.clone(),
}
}
} }
impl MonitorId { impl MonitorId {
pub fn get_name(&self) -> Option<String> { pub fn get_name(&self) -> Option<String> {
Some(self.info.lock().unwrap().name.clone()) self.mgr.with_info(&self.proxy, |_, info| {
format!("{} ({})", info.model, info.make)
})
} }
#[inline] #[inline]
pub fn get_native_identifier(&self) -> u32 { pub fn get_native_identifier(&self) -> u32 {
self.info.lock().unwrap().id self.mgr.with_info(&self.proxy, |id, _| id).unwrap_or(0)
} }
pub fn get_dimensions(&self) -> (u32, u32) { pub fn get_dimensions(&self) -> (u32, u32) {
self.info.lock().unwrap().pix_size match self.mgr.with_info(&self.proxy, |_, info| {
info.modes
.iter()
.find(|m| m.is_current)
.map(|m| m.dimensions)
}) {
Some(Some((w, h))) => (w as u32, h as u32),
_ => (0, 0),
}
} }
pub fn get_position(&self) -> (i32, i32) { pub fn get_position(&self) -> (i32, i32) {
self.info.lock().unwrap().pix_pos self.mgr
.with_info(&self.proxy, |_, info| info.location)
.unwrap_or((0, 0))
} }
#[inline] #[inline]
pub fn get_hidpi_factor(&self) -> f32 { pub fn get_hidpi_factor(&self) -> f32 {
self.info.lock().unwrap().scale self.mgr
.with_info(&self.proxy, |_, info| info.scale_factor as f32)
.unwrap_or(1.0)
} }
} }

View file

@ -1,150 +1,154 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use {VirtualKeyCode, ElementState, WindowEvent as Event, KeyboardInput, ModifiersState}; use {ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
use super::{EventsLoopSink, WindowId, make_wid, DeviceId}; use super::{make_wid, DeviceId, EventsLoopSink};
use super::wayland_kbd::{MappedKeyboardImplementation, register_kbd}; use sctk::keyboard::{self, map_keyboard_auto, Event as KbEvent};
use wayland_client::protocol::wl_keyboard; use sctk::reexports::client::{NewProxy, Proxy};
use wayland_client::EventQueueHandle; use sctk::reexports::client::protocol::wl_keyboard;
pub fn init_keyboard(evq: &mut EventQueueHandle, keyboard: &wl_keyboard::WlKeyboard, sink: &Arc<Mutex<EventsLoopSink>>) { pub fn init_keyboard(
let idata = KeyboardIData { keyboard: NewProxy<wl_keyboard::WlKeyboard>,
sink: sink.clone(),
target: None
};
if register_kbd(evq, keyboard, mapped_keyboard_impl(), idata).is_err() {
// initializing libxkbcommon failed :(
// fallback implementation
let idata = KeyboardIData {
sink: sink.clone(),
target: None
};
evq.register(keyboard, raw_keyboard_impl(), idata);
}
}
struct KeyboardIData {
sink: Arc<Mutex<EventsLoopSink>>, sink: Arc<Mutex<EventsLoopSink>>,
target: Option<WindowId> ) -> Proxy<wl_keyboard::WlKeyboard> {
} // { variables to be captured by the closure
let mut target = None;
fn mapped_keyboard_impl() -> MappedKeyboardImplementation<KeyboardIData> { let my_sink = sink.clone();
MappedKeyboardImplementation { // }
enter: |_, idata, _, _, surface, _, _, _| { let ret = map_keyboard_auto(keyboard, move |evt: KbEvent, _| match evt {
let wid = make_wid(surface); KbEvent::Enter { surface, .. } => {
idata.sink.lock().unwrap().send_event(Event::Focused(true), wid); let wid = make_wid(&surface);
idata.target = Some(wid); my_sink
}, .lock()
leave: |_, idata, _, _, surface| { .unwrap()
let wid = make_wid(surface); .send_event(WindowEvent::Focused(true), wid);
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid); target = Some(wid);
idata.target = None; }
}, KbEvent::Leave { surface, .. } => {
key: |_, idata, _, _, _, mods, rawkey, keysym, state, utf8| { let wid = make_wid(&surface);
if let Some(wid) = idata.target { my_sink
.lock()
.unwrap()
.send_event(WindowEvent::Focused(false), wid);
target = None;
}
KbEvent::Key {
modifiers,
rawkey,
keysym,
state,
utf8,
..
} => {
if let Some(wid) = 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 = idata.sink.lock().unwrap(); let mut guard = my_sink.lock().unwrap();
guard.send_event( guard.send_event(
Event::KeyboardInput { WindowEvent::KeyboardInput {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
input: KeyboardInput { input: KeyboardInput {
state: state, state: state,
scancode: rawkey, scancode: rawkey,
virtual_keycode: vkcode, virtual_keycode: vkcode,
modifiers: ModifiersState { modifiers: modifiers.into(),
shift: mods.shift,
ctrl: mods.ctrl,
alt: mods.alt,
logo: mods.logo
},
}, },
}, },
wid 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.send_event(Event::ReceivedCharacter(chr), wid); guard.send_event(WindowEvent::ReceivedCharacter(chr), wid);
} }
} }
} }
},
repeat_info: |_, _idata, _, _rate, _delay| {
// TODO: handle repeat info
} }
} KbEvent::RepeatInfo { .. } => { /* TODO: handle repeat info */ }
} });
match ret {
Ok(keyboard) => keyboard,
Err((_, keyboard)) => {
// This is a 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 keymap information (it is
// supposed to be serialized by the compositor using libxkbcommon)
// This is fallback impl if libxkbcommon was not available // { variables to be captured by the closure
// This case should probably never happen, as most wayland let mut target = None;
// compositors _need_ libxkbcommon anyway... let my_sink = sink;
// // }
// In this case, we don't have the keymap information (it is keyboard.implement(move |evt, _| match evt {
// supposed to be serialized by the compositor using libxkbcommon) wl_keyboard::Event::Enter { surface, .. } => {
fn raw_keyboard_impl() -> wl_keyboard::Implementation<KeyboardIData> { let wid = make_wid(&surface);
wl_keyboard::Implementation { my_sink
enter: |_, idata, _, _, surface, _| { .lock()
let wid = make_wid(surface); .unwrap()
idata.sink.lock().unwrap().send_event(Event::Focused(true), wid); .send_event(WindowEvent::Focused(true), wid);
idata.target = Some(wid); target = Some(wid);
}, }
leave: |_, idata, _, _, surface| { wl_keyboard::Event::Leave { surface, .. } => {
let wid = make_wid(surface); let wid = make_wid(&surface);
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid); my_sink
idata.target = None; .lock()
}, .unwrap()
key: |_, idata, _, _, _, key, state| { .send_event(WindowEvent::Focused(false), wid);
if let Some(wid) = idata.target { target = None;
let state = match state { }
wl_keyboard::KeyState::Pressed => ElementState::Pressed, wl_keyboard::Event::Key { key, state, .. } => {
wl_keyboard::KeyState::Released => ElementState::Released, if let Some(wid) = target {
}; let state = match state {
idata.sink.lock().unwrap().send_event( wl_keyboard::KeyState::Pressed => ElementState::Pressed,
Event::KeyboardInput { wl_keyboard::KeyState::Released => ElementState::Released,
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), };
input: KeyboardInput { my_sink.lock().unwrap().send_event(
state: state, WindowEvent::KeyboardInput {
scancode: key, device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
virtual_keycode: None, input: KeyboardInput {
modifiers: ModifiersState::default(), state: state,
}, scancode: key,
}, virtual_keycode: None,
wid modifiers: ModifiersState::default(),
); },
} },
}, wid,
repeat_info: |_, _idata, _, _rate, _delay| {}, );
keymap: |_, _, _, _, _, _| {}, }
modifiers: |_, _, _, _, _, _, _, _| {} }
_ => (),
})
}
} }
} }
fn key_to_vkey(rawkey: u32, keysym: u32) -> Option<VirtualKeyCode> { fn key_to_vkey(rawkey: u32, keysym: u32) -> Option<VirtualKeyCode> {
match rawkey { match rawkey {
1 => Some(VirtualKeyCode::Escape), 1 => Some(VirtualKeyCode::Escape),
2 => Some(VirtualKeyCode::Key1), 2 => Some(VirtualKeyCode::Key1),
3 => Some(VirtualKeyCode::Key2), 3 => Some(VirtualKeyCode::Key2),
4 => Some(VirtualKeyCode::Key3), 4 => Some(VirtualKeyCode::Key3),
5 => Some(VirtualKeyCode::Key4), 5 => Some(VirtualKeyCode::Key4),
6 => Some(VirtualKeyCode::Key5), 6 => Some(VirtualKeyCode::Key5),
7 => Some(VirtualKeyCode::Key6), 7 => Some(VirtualKeyCode::Key6),
8 => Some(VirtualKeyCode::Key7), 8 => Some(VirtualKeyCode::Key7),
9 => Some(VirtualKeyCode::Key8), 9 => Some(VirtualKeyCode::Key8),
10 => Some(VirtualKeyCode::Key9), 10 => Some(VirtualKeyCode::Key9),
11 => Some(VirtualKeyCode::Key0), 11 => Some(VirtualKeyCode::Key0),
_ => keysym_to_vkey(keysym) _ => keysym_to_vkey(keysym),
} }
} }
fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> { fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
use super::wayland_kbd::keysyms; use sctk::keyboard::keysyms;
match keysym { match keysym {
// letters // letters
keysyms::XKB_KEY_A | keysyms::XKB_KEY_a => Some(VirtualKeyCode::A), keysyms::XKB_KEY_A | keysyms::XKB_KEY_a => Some(VirtualKeyCode::A),
@ -174,15 +178,15 @@ fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
keysyms::XKB_KEY_Y | keysyms::XKB_KEY_y => Some(VirtualKeyCode::Y), keysyms::XKB_KEY_Y | keysyms::XKB_KEY_y => Some(VirtualKeyCode::Y),
keysyms::XKB_KEY_Z | keysyms::XKB_KEY_z => Some(VirtualKeyCode::Z), keysyms::XKB_KEY_Z | keysyms::XKB_KEY_z => Some(VirtualKeyCode::Z),
// F-- // F--
keysyms::XKB_KEY_F1 => Some(VirtualKeyCode::F1), keysyms::XKB_KEY_F1 => Some(VirtualKeyCode::F1),
keysyms::XKB_KEY_F2 => Some(VirtualKeyCode::F2), keysyms::XKB_KEY_F2 => Some(VirtualKeyCode::F2),
keysyms::XKB_KEY_F3 => Some(VirtualKeyCode::F3), keysyms::XKB_KEY_F3 => Some(VirtualKeyCode::F3),
keysyms::XKB_KEY_F4 => Some(VirtualKeyCode::F4), keysyms::XKB_KEY_F4 => Some(VirtualKeyCode::F4),
keysyms::XKB_KEY_F5 => Some(VirtualKeyCode::F5), keysyms::XKB_KEY_F5 => Some(VirtualKeyCode::F5),
keysyms::XKB_KEY_F6 => Some(VirtualKeyCode::F6), keysyms::XKB_KEY_F6 => Some(VirtualKeyCode::F6),
keysyms::XKB_KEY_F7 => Some(VirtualKeyCode::F7), keysyms::XKB_KEY_F7 => Some(VirtualKeyCode::F7),
keysyms::XKB_KEY_F8 => Some(VirtualKeyCode::F8), keysyms::XKB_KEY_F8 => Some(VirtualKeyCode::F8),
keysyms::XKB_KEY_F9 => Some(VirtualKeyCode::F9), keysyms::XKB_KEY_F9 => Some(VirtualKeyCode::F9),
keysyms::XKB_KEY_F10 => Some(VirtualKeyCode::F10), keysyms::XKB_KEY_F10 => Some(VirtualKeyCode::F10),
keysyms::XKB_KEY_F11 => Some(VirtualKeyCode::F11), keysyms::XKB_KEY_F11 => Some(VirtualKeyCode::F11),
keysyms::XKB_KEY_F12 => Some(VirtualKeyCode::F12), keysyms::XKB_KEY_F12 => Some(VirtualKeyCode::F12),
@ -294,6 +298,17 @@ fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
keysyms::XKB_KEY_XF86Paste => Some(VirtualKeyCode::Paste), keysyms::XKB_KEY_XF86Paste => Some(VirtualKeyCode::Paste),
keysyms::XKB_KEY_XF86Cut => Some(VirtualKeyCode::Cut), keysyms::XKB_KEY_XF86Cut => Some(VirtualKeyCode::Cut),
// fallback // fallback
_ => None _ => None,
}
}
impl From<keyboard::ModifiersState> for ModifiersState {
fn from(mods: keyboard::ModifiersState) -> ModifiersState {
ModifiersState {
shift: mods.shift,
ctrl: mods.ctrl,
alt: mods.alt,
logo: mods.logo,
}
} }
} }

View file

@ -1,14 +1,11 @@
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd"))]
pub use self::window::Window; pub use self::window::Window;
pub use self::event_loop::{EventsLoop, EventsLoopProxy, EventsLoopSink, MonitorId}; pub use self::event_loop::{EventsLoop, EventsLoopProxy, EventsLoopSink, MonitorId};
extern crate wayland_kbd; use sctk::reexports::client::protocol::wl_surface;
extern crate wayland_window; use sctk::reexports::client::Proxy;
extern crate wayland_protocols;
use wayland_client::protocol::wl_surface;
use wayland_client::Proxy;
mod event_loop; mod event_loop;
mod pointer; mod pointer;
@ -23,6 +20,6 @@ pub struct DeviceId;
pub struct WindowId(usize); pub struct WindowId(usize);
#[inline] #[inline]
fn make_wid(s: &wl_surface::WlSurface) -> WindowId { fn make_wid(s: &Proxy<wl_surface::WlSurface>) -> WindowId {
WindowId(s.ptr() as usize) WindowId(s.c_ptr() as usize)
} }

View file

@ -1,194 +1,190 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase}; use {ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent};
use events::ModifiersState; use events::ModifiersState;
use super::{WindowId, DeviceId}; use super::DeviceId;
use super::event_loop::EventsLoopSink; use super::event_loop::EventsLoopSink;
use super::window::WindowStore; use super::window::WindowStore;
use wayland_client::{Proxy, StateToken}; use sctk::reexports::client::{NewProxy, Proxy};
use wayland_client::protocol::wl_pointer; use sctk::reexports::client::protocol::wl_pointer::{self, Event as PtrEvent, WlPointer};
pub struct PointerIData { pub fn implement_pointer(
pointer: NewProxy<WlPointer>,
sink: Arc<Mutex<EventsLoopSink>>, sink: Arc<Mutex<EventsLoopSink>>,
windows_token: StateToken<WindowStore>, store: Arc<Mutex<WindowStore>>,
mouse_focus: Option<WindowId>, ) -> Proxy<WlPointer> {
axis_buffer: Option<(f32, f32)>, let mut mouse_focus = None;
axis_discrete_buffer: Option<(i32, i32)>, let mut axis_buffer = None;
axis_state: TouchPhase, let mut axis_discrete_buffer = None;
} let mut axis_state = TouchPhase::Ended;
impl PointerIData { pointer.implement(move |evt, pointer: Proxy<_>| {
pub fn new(sink: &Arc<Mutex<EventsLoopSink>>, token: StateToken<WindowStore>) let mut sink = sink.lock().unwrap();
-> PointerIData let store = store.lock().unwrap();
{ match evt {
PointerIData { PtrEvent::Enter {
sink: sink.clone(), surface,
windows_token: token, surface_x,
mouse_focus: None, surface_y,
axis_buffer: None, ..
axis_discrete_buffer: None, } => {
axis_state: TouchPhase::Cancelled let wid = store.find_wid(&surface);
if let Some(wid) = wid {
mouse_focus = Some(wid);
sink.send_event(
WindowEvent::CursorEntered {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
},
wid,
);
sink.send_event(
WindowEvent::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (surface_x, surface_y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
}
}
PtrEvent::Leave { surface, .. } => {
mouse_focus = None;
let wid = store.find_wid(&surface);
if let Some(wid) = wid {
sink.send_event(
WindowEvent::CursorLeft {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
},
wid,
);
}
}
PtrEvent::Motion {
surface_x,
surface_y,
..
} => {
if let Some(wid) = mouse_focus {
sink.send_event(
WindowEvent::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (surface_x, surface_y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
}
}
PtrEvent::Button { button, state, .. } => {
if let Some(wid) = 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.send_event(
WindowEvent::MouseInput {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
state: state,
button: button,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
}
}
PtrEvent::Axis { axis, value, .. } => {
if let Some(wid) = mouse_focus {
if pointer.version() < 5 {
let (mut x, mut y) = (0.0, 0.0);
// old seat compatibility
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32,
}
sink.send_event(
WindowEvent::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: TouchPhase::Moved,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
} else {
let (mut x, mut y) = axis_buffer.unwrap_or((0.0, 0.0));
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32,
}
axis_buffer = Some((x, y));
axis_state = match axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started,
}
}
}
}
PtrEvent::Frame => {
let axis_buffer = axis_buffer.take();
let axis_discrete_buffer = axis_discrete_buffer.take();
if let Some(wid) = mouse_focus {
if let Some((x, y)) = axis_discrete_buffer {
sink.send_event(
WindowEvent::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
phase: axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
} else if let Some((x, y)) = axis_buffer {
sink.send_event(
WindowEvent::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
}
}
}
PtrEvent::AxisSource { .. } => (),
PtrEvent::AxisStop { .. } => {
axis_state = TouchPhase::Ended;
}
PtrEvent::AxisDiscrete { axis, discrete } => {
let (mut x, mut y) = axis_discrete_buffer.unwrap_or((0, 0));
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= discrete,
wl_pointer::Axis::HorizontalScroll => x += discrete,
}
axis_discrete_buffer = Some((x, y));
axis_state = match axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started,
}
}
} }
} })
}
pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
wl_pointer::Implementation {
enter: |evqh, idata, _, _, surface, x, y| {
let wid = evqh.state().get(&idata.windows_token).find_wid(surface);
if let Some(wid) = wid {
idata.mouse_focus = Some(wid);
let mut guard = idata.sink.lock().unwrap();
guard.send_event(
Event::CursorEntered {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
},
wid,
);
guard.send_event(
Event::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (x, y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
}
},
leave: |evqh, idata, _, _, surface| {
idata.mouse_focus = None;
let wid = evqh.state().get(&idata.windows_token).find_wid(surface);
if let Some(wid) = wid {
let mut guard = idata.sink.lock().unwrap();
guard.send_event(
Event::CursorLeft {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
},
wid,
);
}
},
motion: |_, idata, _, _, x, y| {
if let Some(wid) = idata.mouse_focus {
idata.sink.lock().unwrap().send_event(
Event::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (x, y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
}
},
button: |_, idata, _, _, _, button, state| {
if let Some(wid) = idata.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
};
idata.sink.lock().unwrap().send_event(
Event::MouseInput {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
state: state,
button: button,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
}
},
axis: |_, idata, pointer, _, axis, value| {
if let Some(wid) = idata.mouse_focus {
if pointer.version() < 5 {
let (mut x, mut y) = (0.0, 0.0);
// old seat compatibility
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32
}
idata.sink.lock().unwrap().send_event(
Event::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: TouchPhase::Moved,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
} else {
let (mut x, mut y) = idata.axis_buffer.unwrap_or((0.0, 0.0));
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32
}
idata.axis_buffer = Some((x,y));
idata.axis_state = match idata.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
}
}
},
frame: |_, idata, _| {
let axis_buffer = idata.axis_buffer.take();
let axis_discrete_buffer = idata.axis_discrete_buffer.take();
if let Some(wid) = idata.mouse_focus {
if let Some((x, y)) = axis_discrete_buffer {
idata.sink.lock().unwrap().send_event(
Event::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
phase: idata.axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
} else if let Some((x, y)) = axis_buffer {
idata.sink.lock().unwrap().send_event(
Event::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: idata.axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
}
}
},
axis_source: |_, _, _, _| {},
axis_stop: |_, idata, _, _, _| {
idata.axis_state = TouchPhase::Ended;
},
axis_discrete: |_, idata, _, axis, discrete| {
let (mut x, mut y) = idata.axis_discrete_buffer.unwrap_or((0,0));
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= discrete,
wl_pointer::Axis::HorizontalScroll => x += discrete
}
idata.axis_discrete_buffer = Some((x,y));
idata.axis_state = match idata.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
},
}
} }

View file

@ -1,106 +1,93 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use {WindowEvent as Event, TouchPhase}; use {TouchPhase, WindowEvent};
use super::{WindowId, DeviceId}; use super::{DeviceId, WindowId};
use super::event_loop::EventsLoopSink; use super::event_loop::EventsLoopSink;
use super::window::WindowStore; use super::window::WindowStore;
use wayland_client::StateToken; use sctk::reexports::client::{NewProxy, Proxy};
use wayland_client::protocol::wl_touch; use sctk::reexports::client::protocol::wl_touch::{Event as TouchEvent, WlTouch};
pub struct TouchIData {
sink: Arc<Mutex<EventsLoopSink>>,
windows_token: StateToken<WindowStore>,
pending_ids: Vec<TouchPoint>,
}
struct TouchPoint { struct TouchPoint {
wid: WindowId, wid: WindowId,
location: (f64, f64), location: (f64, f64),
id: i32 id: i32,
} }
impl TouchIData { pub(crate) fn implement_touch(
pub fn new(sink: &Arc<Mutex<EventsLoopSink>>, token: StateToken<WindowStore>) touch: NewProxy<WlTouch>,
-> TouchIData sink: Arc<Mutex<EventsLoopSink>>,
{ store: Arc<Mutex<WindowStore>>,
TouchIData { ) -> Proxy<WlTouch> {
sink: sink.clone(), let mut pending_ids = Vec::new();
windows_token: token, touch.implement(move |evt, _| {
pending_ids: Vec::new(), let mut sink = sink.lock().unwrap();
} let store = store.lock().unwrap();
} match evt {
} TouchEvent::Down {
surface, id, x, y, ..
pub fn touch_implementation() -> wl_touch::Implementation<TouchIData> { } => {
wl_touch::Implementation { let wid = store.find_wid(&surface);
down: |evqh, idata, _, _serial, _time, surface, touch_id, x, y| { if let Some(wid) = wid {
let wid = evqh.state().get(&idata.windows_token).find_wid(surface); sink.send_event(
if let Some(wid) = wid { WindowEvent::Touch(::Touch {
let mut guard = idata.sink.lock().unwrap(); device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
guard.send_event( phase: TouchPhase::Started,
Event::Touch(::Touch { location: (x, y),
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), id: id as u64,
phase: TouchPhase::Started, }),
wid,
);
pending_ids.push(TouchPoint {
wid: wid,
location: (x, y), location: (x, y),
id: touch_id as u64 id: id,
}), });
wid, }
);
idata.pending_ids.push(TouchPoint {
wid: wid,
location: (x, y),
id: touch_id
});
} }
}, TouchEvent::Up { id, .. } => {
up: |_, idata, _, _serial, _time, touch_id| { let idx = pending_ids.iter().position(|p| p.id == id);
let idx = idata.pending_ids.iter().position(|p| p.id == touch_id); if let Some(idx) = idx {
if let Some(idx) = idx { let pt = pending_ids.remove(idx);
let pt = idata.pending_ids.remove(idx); sink.send_event(
let mut guard = idata.sink.lock().unwrap(); WindowEvent::Touch(::Touch {
guard.send_event( device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
Event::Touch(::Touch { phase: TouchPhase::Ended,
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), location: pt.location,
phase: TouchPhase::Ended, id: id as u64,
location: pt.location, }),
id: touch_id as u64 pt.wid,
}), );
pt.wid, }
);
} }
}, TouchEvent::Motion { id, x, y, .. } => {
motion: |_, idata, _, _time, touch_id, x, y| { let pt = pending_ids.iter_mut().find(|p| p.id == id);
let pt = idata.pending_ids.iter_mut().find(|p| p.id == touch_id); if let Some(pt) = pt {
if let Some(pt) = pt { pt.location = (x, y);
let mut guard = idata.sink.lock().unwrap(); sink.send_event(
pt.location = (x, y); WindowEvent::Touch(::Touch {
guard.send_event( device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
Event::Touch(::Touch { phase: TouchPhase::Moved,
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), location: (x, y),
phase: TouchPhase::Moved, id: id as u64,
location: (x, y), }),
id: touch_id as u64 pt.wid,
}), );
pt.wid, }
);
} }
}, TouchEvent::Frame => (),
frame: |_, _, _| {}, TouchEvent::Cancel => for pt in pending_ids.drain(..) {
cancel: |_, idata, _| { sink.send_event(
let mut guard = idata.sink.lock().unwrap(); WindowEvent::Touch(::Touch {
for pt in idata.pending_ids.drain(..) {
guard.send_event(
Event::Touch(::Touch {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
phase: TouchPhase::Cancelled, phase: TouchPhase::Cancelled,
location: pt.location, location: pt.location,
id: pt.id as u64 id: pt.id as u64,
}), }),
pt.wid, pt.wid,
); );
} },
} }
} })
} }

View file

@ -1,81 +1,128 @@
use std::sync::{Arc, Mutex, Weak}; use std::sync::{Arc, Mutex, Weak};
use wayland_client::protocol::{wl_display,wl_surface}; use {CreationError, CursorState, MouseCursor, WindowAttributes};
use wayland_client::{Proxy, StateToken};
use {CreationError, MouseCursor, CursorState, WindowAttributes};
use platform::MonitorId as PlatformMonitorId; use platform::MonitorId as PlatformMonitorId;
use window::MonitorId as RootMonitorId; use window::MonitorId as RootMonitorId;
use super::{EventsLoop, WindowId, make_wid, MonitorId}; use sctk::window::{BasicFrame, Event as WEvent, Window as SWindow};
use super::wayland_window::{Frame, FrameImplementation, State as FrameState}; use sctk::reexports::client::{Display, Proxy};
use super::event_loop::StateContext; use sctk::reexports::client::protocol::{wl_seat, wl_surface};
use sctk::reexports::client::protocol::wl_compositor::RequestsTrait as CompositorRequests;
use sctk::reexports::client::protocol::wl_surface::RequestsTrait as SurfaceRequests;
use super::{make_wid, EventsLoop, MonitorId, WindowId};
pub struct Window { pub struct Window {
surface: wl_surface::WlSurface, surface: Proxy<wl_surface::WlSurface>,
frame: Arc<Mutex<Frame>>, frame: Arc<Mutex<SWindow<BasicFrame>>>,
monitors: Arc<Mutex<MonitorList>>, monitors: Arc<Mutex<Vec<MonitorId>>>,
size: Arc<Mutex<(u32, u32)>>, size: Arc<Mutex<(u32, u32)>>,
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>), kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
display: Arc<wl_display::WlDisplay>, display: Arc<Display>,
need_frame_refresh: Arc<Mutex<bool>> need_frame_refresh: Arc<Mutex<bool>>,
} }
impl Window { impl Window {
pub fn new(evlp: &EventsLoop, attributes: &WindowAttributes) -> Result<Window, CreationError> pub fn new(evlp: &EventsLoop, attributes: &WindowAttributes) -> Result<Window, CreationError> {
{ let (width, height) = attributes.dimensions.unwrap_or((800, 600));
let (width, height) = attributes.dimensions.unwrap_or((800,600));
// Create the decorated surface // Create the window
let size = Arc::new(Mutex::new((width, height))); let size = Arc::new(Mutex::new((width, height)));
let store_token = evlp.store.clone();
let (surface, mut frame) = evlp.create_window( // monitor tracking
width, height, decorated_impl(), let monitor_list = Arc::new(Mutex::new(Vec::new()));
|surface| FrameIData {
surface: surface.clone().unwrap(), let surface = evlp.env.compositor.create_surface().unwrap().implement({
store_token: store_token.clone() let list = monitor_list.clone();
let omgr = evlp.env.outputs.clone();
move |event, _| match event {
wl_surface::Event::Enter { output } => list.lock().unwrap().push(MonitorId {
proxy: output,
mgr: omgr.clone(),
}),
wl_surface::Event::Leave { output } => {
list.lock().unwrap().retain(|m| !m.proxy.equals(&output));
}
} }
); });
let window_store = evlp.store.clone();
let my_surface = surface.clone();
let mut frame = SWindow::<BasicFrame>::init(
surface.clone(),
(width, height),
&evlp.env.compositor,
&evlp.env.subcompositor,
&evlp.env.shm,
&evlp.env.shell,
move |event, ()| match event {
WEvent::Configure { new_size, .. } => {
let mut store = window_store.lock().unwrap();
for window in &mut store.windows {
if window.surface.equals(&my_surface) {
window.newsize = new_size.map(|(w, h)| (w as i32, h as i32));
window.need_refresh = true;
*(window.need_frame_refresh.lock().unwrap()) = true;
return;
}
}
}
WEvent::Refresh => {
let store = window_store.lock().unwrap();
for window in &store.windows {
if window.surface.equals(&my_surface) {
*(window.need_frame_refresh.lock().unwrap()) = true;
return;
}
}
}
WEvent::Close => {
let mut store = window_store.lock().unwrap();
for window in &mut store.windows {
if window.surface.equals(&my_surface) {
window.closed = true;
return;
}
}
}
},
).unwrap();
for &(_, ref seat) in evlp.seats.lock().unwrap().iter() {
frame.new_seat(seat);
}
// Check for fullscreen requirements // Check for fullscreen requirements
if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = attributes.fullscreen { if let Some(RootMonitorId {
let info = monitor_id.info.lock().unwrap(); inner: PlatformMonitorId::Wayland(ref monitor_id),
frame.set_state(FrameState::Fullscreen(Some(&info.output))); }) = attributes.fullscreen
{
frame.set_fullscreen(Some(&monitor_id.proxy));
} else if attributes.maximized { } else if attributes.maximized {
frame.set_state(FrameState::Maximized); frame.set_maximized();
} }
// set decorations // set decorations
frame.set_decorate(attributes.decorations); frame.set_decorate(attributes.decorations);
// min-max dimensions // min-max dimensions
frame.set_min_size(attributes.min_dimensions.map(|(w, h)| (w as i32, h as i32))); frame.set_min_size(attributes.min_dimensions);
frame.set_max_size(attributes.max_dimensions.map(|(w, h)| (w as i32, h as i32))); frame.set_max_size(attributes.max_dimensions);
// setup the monitor tracking
let monitor_list = Arc::new(Mutex::new(MonitorList::default()));
{
let mut evq = evlp.evq.borrow_mut();
let idata = (evlp.ctxt_token.clone(), monitor_list.clone());
evq.register(&surface, surface_impl(), idata);
}
let kill_switch = Arc::new(Mutex::new(false)); let kill_switch = Arc::new(Mutex::new(false));
let need_frame_refresh = Arc::new(Mutex::new(true)); let need_frame_refresh = Arc::new(Mutex::new(true));
let frame = Arc::new(Mutex::new(frame)); let frame = Arc::new(Mutex::new(frame));
{ evlp.store.lock().unwrap().windows.push(InternalWindow {
let mut evq = evlp.evq.borrow_mut(); closed: false,
evq.state().get_mut(&store_token).windows.push(InternalWindow { newsize: None,
closed: false, need_refresh: false,
newsize: None, need_frame_refresh: need_frame_refresh.clone(),
need_refresh: false, surface: surface.clone(),
need_frame_refresh: need_frame_refresh.clone(), kill_switch: kill_switch.clone(),
surface: surface.clone().unwrap(), frame: Arc::downgrade(&frame),
kill_switch: kill_switch.clone(), });
frame: Arc::downgrade(&frame) evlp.evq.borrow_mut().sync_roundtrip().unwrap();
});
evq.sync_roundtrip().unwrap();
}
Ok(Window { Ok(Window {
display: evlp.display.clone(), display: evlp.display.clone(),
@ -84,7 +131,7 @@ impl Window {
monitors: monitor_list, monitors: monitor_list,
size: size, size: size,
kill_switch: (kill_switch, evlp.cleanup_needed.clone()), kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
need_frame_refresh: need_frame_refresh need_frame_refresh: need_frame_refresh,
}) })
} }
@ -131,25 +178,25 @@ impl Window {
#[inline] #[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> { pub fn get_outer_size(&self) -> Option<(u32, u32)> {
let (w, h) = self.size.lock().unwrap().clone(); let (w, h) = self.size.lock().unwrap().clone();
let (w, h) = super::wayland_window::add_borders(w as i32, h as i32); // let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
Some((w as u32, h as u32)) Some((w as u32, h as u32))
} }
#[inline] #[inline]
// NOTE: This will only resize the borders, the contents must be updated by the user // NOTE: This will only resize the borders, the contents must be updated by the user
pub fn set_inner_size(&self, x: u32, y: u32) { pub fn set_inner_size(&self, x: u32, y: u32) {
self.frame.lock().unwrap().resize(x as i32, y as i32); self.frame.lock().unwrap().resize(x, y);
*(self.size.lock().unwrap()) = (x, y); *(self.size.lock().unwrap()) = (x, y);
} }
#[inline] #[inline]
pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) { pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
self.frame.lock().unwrap().set_min_size(dimensions.map(|(w, h)| (w as i32, h as i32))); self.frame.lock().unwrap().set_min_size(dimensions);
} }
#[inline] #[inline]
pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) { pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
self.frame.lock().unwrap().set_max_size(dimensions.map(|(w, h)| (w as i32, h as i32))); self.frame.lock().unwrap().set_max_size(dimensions);
} }
#[inline] #[inline]
@ -159,22 +206,22 @@ impl Window {
#[inline] #[inline]
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
use CursorState::{Grab, Normal, Hide}; use CursorState::{Grab, Hide, Normal};
// TODO : not yet possible on wayland to grab cursor // TODO : not yet possible on wayland to grab cursor
match state { match state {
Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()), Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()), Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
Normal => Ok(()) Normal => Ok(()),
} }
} }
#[inline] #[inline]
pub fn hidpi_factor(&self) -> f32 { pub fn hidpi_factor(&self) -> f32 {
let mut factor = 1.0; let mut factor: f32 = 1.0;
let guard = self.monitors.lock().unwrap(); let guard = self.monitors.lock().unwrap();
for monitor_id in &guard.monitors { for monitor_id in guard.iter() {
let info = monitor_id.info.lock().unwrap(); let hidpif = monitor_id.get_hidpi_factor();
if info.scale > factor { factor = info.scale; } factor = factor.max(hidpif);
} }
factor factor
} }
@ -186,18 +233,23 @@ impl Window {
pub fn set_maximized(&self, maximized: bool) { pub fn set_maximized(&self, maximized: bool) {
if maximized { if maximized {
self.frame.lock().unwrap().set_state(FrameState::Maximized); self.frame.lock().unwrap().set_maximized();
} else { } else {
self.frame.lock().unwrap().set_state(FrameState::Regular); self.frame.lock().unwrap().unset_maximized();
} }
} }
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) { pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = monitor { if let Some(RootMonitorId {
let info = monitor_id.info.lock().unwrap(); inner: PlatformMonitorId::Wayland(ref monitor_id),
self.frame.lock().unwrap().set_state(FrameState::Fullscreen(Some(&info.output))); }) = monitor
{
self.frame
.lock()
.unwrap()
.set_fullscreen(Some(&monitor_id.proxy));
} else { } else {
self.frame.lock().unwrap().set_state(FrameState::Regular); self.frame.lock().unwrap().unset_fullscreen();
} }
} }
@ -207,11 +259,11 @@ impl Window {
Err(()) Err(())
} }
pub fn get_display(&self) -> &wl_display::WlDisplay { pub fn get_display(&self) -> &Display {
&*self.display &*self.display
} }
pub fn get_surface(&self) -> &wl_surface::WlSurface { pub fn get_surface(&self) -> &Proxy<wl_surface::WlSurface> {
&self.surface &self.surface
} }
@ -219,7 +271,7 @@ impl Window {
// we don't know how much each monitor sees us so... // we don't know how much each monitor sees us so...
// just return the most recent one ? // just return the most recent one ?
let guard = self.monitors.lock().unwrap(); let guard = self.monitors.lock().unwrap();
guard.monitors.last().unwrap().clone() guard.last().unwrap().clone()
} }
} }
@ -235,25 +287,27 @@ impl Drop for Window {
*/ */
struct InternalWindow { struct InternalWindow {
surface: wl_surface::WlSurface, surface: Proxy<wl_surface::WlSurface>,
newsize: Option<(i32, i32)>, newsize: Option<(i32, i32)>,
need_refresh: bool, need_refresh: bool,
need_frame_refresh: Arc<Mutex<bool>>, need_frame_refresh: Arc<Mutex<bool>>,
closed: bool, closed: bool,
kill_switch: Arc<Mutex<bool>>, kill_switch: Arc<Mutex<bool>>,
frame: Weak<Mutex<Frame>> frame: Weak<Mutex<SWindow<BasicFrame>>>,
} }
pub struct WindowStore { pub struct WindowStore {
windows: Vec<InternalWindow> windows: Vec<InternalWindow>,
} }
impl WindowStore { impl WindowStore {
pub fn new() -> WindowStore { pub fn new() -> WindowStore {
WindowStore { windows: Vec::new() } WindowStore {
windows: Vec::new(),
}
} }
pub fn find_wid(&self, surface: &wl_surface::WlSurface) -> Option<WindowId> { pub fn find_wid(&self, surface: &Proxy<wl_surface::WlSurface>) -> Option<WindowId> {
for window in &self.windows { for window in &self.windows {
if surface.equals(&window.surface) { if surface.equals(&window.surface) {
return Some(make_wid(surface)); return Some(make_wid(surface));
@ -277,8 +331,17 @@ impl WindowStore {
pruned pruned
} }
pub fn new_seat(&self, seat: &Proxy<wl_seat::WlSeat>) {
for window in &self.windows {
if let Some(w) = window.frame.upgrade() {
w.lock().unwrap().new_seat(seat);
}
}
}
pub fn for_each<F>(&mut self, mut f: F) pub fn for_each<F>(&mut self, mut f: F)
where F: FnMut(Option<(i32, i32)>, bool, bool, bool, WindowId, Option<&mut Frame>) where
F: FnMut(Option<(i32, i32)>, bool, bool, bool, WindowId, Option<&mut SWindow<BasicFrame>>),
{ {
for window in &mut self.windows { for window in &mut self.windows {
let opt_arc = window.frame.upgrade(); let opt_arc = window.frame.upgrade();
@ -289,7 +352,7 @@ impl WindowStore {
::std::mem::replace(&mut *window.need_frame_refresh.lock().unwrap(), false), ::std::mem::replace(&mut *window.need_frame_refresh.lock().unwrap(), false),
window.closed, window.closed,
make_wid(&window.surface), make_wid(&window.surface),
opt_mutex_lock.as_mut().map(|m| &mut **m) opt_mutex_lock.as_mut().map(|m| &mut **m),
); );
window.need_refresh = false; window.need_refresh = false;
// avoid re-spamming the event // avoid re-spamming the event
@ -297,68 +360,3 @@ impl WindowStore {
} }
} }
} }
/*
* Protocol implementation
*/
struct FrameIData {
store_token: StateToken<WindowStore>,
surface: wl_surface::WlSurface
}
fn decorated_impl() -> FrameImplementation<FrameIData> {
FrameImplementation {
configure: |evqh, idata, _, newsize| {
let store = evqh.state().get_mut(&idata.store_token);
for window in &mut store.windows {
if window.surface.equals(&idata.surface) {
window.newsize = newsize;
window.need_refresh = true;
*(window.need_frame_refresh.lock().unwrap()) = true;
return;
}
}
},
close: |evqh, idata| {
let store = evqh.state().get_mut(&idata.store_token);
for window in &mut store.windows {
if window.surface.equals(&idata.surface) {
window.closed = true;
return;
}
}
},
refresh: |evqh, idata| {
let store = evqh.state().get_mut(&idata.store_token);
for window in &mut store.windows {
if window.surface.equals(&idata.surface) {
*(window.need_frame_refresh.lock().unwrap()) = true;
return;
}
}
}
}
}
#[derive(Default)]
struct MonitorList {
monitors: Vec<MonitorId>
}
fn surface_impl() -> wl_surface::Implementation<(StateToken<StateContext>, Arc<Mutex<MonitorList>>)> {
wl_surface::Implementation {
enter: |evqh, &mut (ref token, ref list), _, output| {
let mut guard = list.lock().unwrap();
let ctxt = evqh.state().get(token);
let monitor = ctxt.monitor_id_for(output);
guard.monitors.push(monitor);
},
leave: |evqh, &mut (ref token, ref list), _, output| {
let mut guard = list.lock().unwrap();
let ctxt = evqh.state().get(token);
let monitor = ctxt.monitor_id_for(output);
guard.monitors.retain(|m| !Arc::ptr_eq(&m.info, &monitor.info));
}
}
}