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:
parent
cc8907b956
commit
1e97103094
11 changed files with 764 additions and 902 deletions
|
|
@ -3,37 +3,35 @@ use std::collections::VecDeque;
|
|||
use std::sync::{Arc, Mutex, Weak};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use {EventsLoopClosed, ControlFlow};
|
||||
use {ControlFlow, EventsLoopClosed};
|
||||
|
||||
use super::WindowId;
|
||||
use super::window::WindowStore;
|
||||
use super::keyboard::init_keyboard;
|
||||
|
||||
use wayland_client::{EnvHandler, EnvNotify, default_connect, EventQueue, EventQueueHandle, Proxy, StateToken};
|
||||
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_keyboard, wl_touch};
|
||||
use sctk::Environment;
|
||||
use sctk::output::OutputMgr;
|
||||
use sctk::reexports::client::{Display, EventQueue, GlobalEvent, Proxy};
|
||||
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 super::wayland_protocols::unstable::xdg_shell::v6::client::zxdg_shell_v6;
|
||||
use sctk::reexports::client::protocol::wl_display::RequestsTrait as DisplayRequests;
|
||||
|
||||
pub struct EventsLoopSink {
|
||||
buffer: VecDeque<::Event>
|
||||
buffer: VecDeque<::Event>,
|
||||
}
|
||||
|
||||
unsafe impl Send for EventsLoopSink { }
|
||||
|
||||
impl EventsLoopSink {
|
||||
pub fn new() -> EventsLoopSink{
|
||||
pub fn new() -> EventsLoopSink {
|
||||
EventsLoopSink {
|
||||
buffer: VecDeque::new()
|
||||
buffer: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_event(&mut self, evt: ::WindowEvent, wid: WindowId) {
|
||||
let evt = ::Event::WindowEvent {
|
||||
event: evt,
|
||||
window_id: ::WindowId(::platform::WindowId::Wayland(wid))
|
||||
window_id: ::WindowId(::platform::WindowId::Wayland(wid)),
|
||||
};
|
||||
self.buffer.push_back(evt);
|
||||
}
|
||||
|
|
@ -42,7 +40,10 @@ impl EventsLoopSink {
|
|||
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(..) {
|
||||
callback(evt)
|
||||
}
|
||||
|
|
@ -57,15 +58,15 @@ pub struct EventsLoop {
|
|||
// Whether or not there is a pending `Awakened` event to be emitted.
|
||||
pending_wakeup: Arc<AtomicBool>,
|
||||
// The window store
|
||||
pub store: StateToken<WindowStore>,
|
||||
pub store: Arc<Mutex<WindowStore>>,
|
||||
// the env
|
||||
env_token: StateToken<EnvHandler<InnerEnv>>,
|
||||
// the ctxt
|
||||
pub ctxt_token: StateToken<StateContext>,
|
||||
pub env: Environment,
|
||||
// a cleanup switch to prune dead windows
|
||||
pub cleanup_needed: Arc<Mutex<bool>>,
|
||||
// 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`.
|
||||
|
|
@ -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.
|
||||
#[derive(Clone)]
|
||||
pub struct EventsLoopProxy {
|
||||
display: Weak<wl_display::WlDisplay>,
|
||||
display: Weak<Display>,
|
||||
pending_wakeup: Weak<AtomicBool>,
|
||||
}
|
||||
|
||||
|
|
@ -89,10 +90,10 @@ impl EventsLoopProxy {
|
|||
// Update the `EventsLoop`'s `pending_wakeup` flag.
|
||||
wakeup.store(true, Ordering::Relaxed);
|
||||
// Cause the `EventsLoop` to break from `dispatch` if it is currently blocked.
|
||||
display.sync();
|
||||
let _ = display.sync();
|
||||
display.flush().map_err(|_| EventsLoopClosed)?;
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
_ => Err(EventsLoopClosed),
|
||||
}
|
||||
}
|
||||
|
|
@ -100,58 +101,35 @@ impl EventsLoopProxy {
|
|||
|
||||
impl 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,
|
||||
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,
|
||||
®istry,
|
||||
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 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 {
|
||||
sink: sink.clone(),
|
||||
keyboard: None,
|
||||
pointer: None,
|
||||
touch: None,
|
||||
windows_token: store.clone()
|
||||
};
|
||||
|
||||
let mut me = EventsLoop {
|
||||
Some(EventsLoop {
|
||||
display: Arc::new(display),
|
||||
evq: RefCell::new(event_queue),
|
||||
sink: sink,
|
||||
pending_wakeup: Arc::new(AtomicBool::new(false)),
|
||||
store: store,
|
||||
ctxt_token: ctxt_token,
|
||||
env_token: env_token,
|
||||
cleanup_needed: Arc::new(Mutex::new(false))
|
||||
};
|
||||
|
||||
me.init_seat(|evqh, seat| {
|
||||
evqh.register(seat, seat_implementation(), seat_idata);
|
||||
});
|
||||
|
||||
Some(me)
|
||||
env: env,
|
||||
cleanup_needed: Arc::new(Mutex::new(false)),
|
||||
seats: seats,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||
|
|
@ -162,7 +140,8 @@ impl EventsLoop {
|
|||
}
|
||||
|
||||
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||
where F: FnMut(::Event)
|
||||
where
|
||||
F: FnMut(::Event),
|
||||
{
|
||||
// send pending events to the server
|
||||
self.display.flush().expect("Wayland connection lost.");
|
||||
|
|
@ -175,7 +154,10 @@ impl EventsLoop {
|
|||
h.read_events().expect("Wayland connection lost.");
|
||||
}
|
||||
// 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();
|
||||
|
||||
// dispatch buffered events to client
|
||||
|
|
@ -183,15 +165,18 @@ impl EventsLoop {
|
|||
}
|
||||
|
||||
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
|
||||
self.display.flush().expect("Wayland connection lost.");
|
||||
|
||||
// Check for control flow by wrapping the callback.
|
||||
let control_flow = ::std::cell::Cell::new(ControlFlow::Continue);
|
||||
let mut callback = |event| if let ControlFlow::Break = callback(event) {
|
||||
control_flow.set(ControlFlow::Break);
|
||||
let mut callback = |event| {
|
||||
if let ControlFlow::Break = callback(event) {
|
||||
control_flow.set(ControlFlow::Break);
|
||||
}
|
||||
};
|
||||
|
||||
// dispatch any pre-buffered events
|
||||
|
|
@ -200,7 +185,10 @@ impl EventsLoop {
|
|||
|
||||
loop {
|
||||
// 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();
|
||||
|
||||
// empty buffer of events
|
||||
|
|
@ -213,25 +201,27 @@ impl EventsLoop {
|
|||
}
|
||||
|
||||
pub fn get_primary_monitor(&self) -> MonitorId {
|
||||
let mut guard = self.evq.borrow_mut();
|
||||
let state = guard.state();
|
||||
let state_ctxt = state.get(&self.ctxt_token);
|
||||
if let Some(info) = state_ctxt.monitors.iter().next() {
|
||||
MonitorId {
|
||||
info: info.clone()
|
||||
self.env.outputs.with_all(|list| {
|
||||
if let Some(&(_, ref proxy, _)) = list.first() {
|
||||
MonitorId {
|
||||
proxy: proxy.clone(),
|
||||
mgr: self.env.outputs.clone(),
|
||||
}
|
||||
} else {
|
||||
panic!("No monitor is available.")
|
||||
}
|
||||
} else {
|
||||
panic!("No monitor is available.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
||||
let mut guard = self.evq.borrow_mut();
|
||||
let state = guard.state();
|
||||
let state_ctxt = state.get(&self.ctxt_token);
|
||||
state_ctxt.monitors.iter()
|
||||
.map(|m| MonitorId { info: m.clone() })
|
||||
.collect()
|
||||
self.env.outputs.with_all(|list| {
|
||||
list.iter()
|
||||
.map(|&(_, ref proxy, _)| MonitorId {
|
||||
proxy: proxy.clone(),
|
||||
mgr: self.env.outputs.clone(),
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -239,93 +229,9 @@ impl EventsLoop {
|
|||
* 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 {
|
||||
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) {
|
||||
let mut sink = self.sink.lock().unwrap();
|
||||
let evq = self.evq.get_mut();
|
||||
// process a possible pending wakeup call
|
||||
if self.pending_wakeup.load(Ordering::Relaxed) {
|
||||
sink.send_raw_event(::Event::Awakened);
|
||||
|
|
@ -335,7 +241,7 @@ impl EventsLoop {
|
|||
{
|
||||
let mut cleanup_needed = self.cleanup_needed.lock().unwrap();
|
||||
if *cleanup_needed {
|
||||
let pruned = evq.state().get_mut(&self.store).cleanup();
|
||||
let pruned = self.store.lock().unwrap().cleanup();
|
||||
*cleanup_needed = false;
|
||||
for wid in pruned {
|
||||
sink.send_event(::WindowEvent::Destroyed, wid);
|
||||
|
|
@ -343,11 +249,11 @@ impl EventsLoop {
|
|||
}
|
||||
}
|
||||
// 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| {
|
||||
if let Some(frame) = frame {
|
||||
if let Some((w, h)) = newsize {
|
||||
frame.resize(w as i32, h as i32);
|
||||
frame.resize(w as u32, h as u32);
|
||||
frame.refresh();
|
||||
sink.send_event(::WindowEvent::Resized(w as u32, h as u32), wid);
|
||||
} else if frame_refresh {
|
||||
|
|
@ -360,140 +266,147 @@ impl EventsLoop {
|
|||
if closed {
|
||||
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
|
||||
*/
|
||||
|
||||
fn env_notify() -> EnvNotify<StateToken<StateContext>> {
|
||||
EnvNotify {
|
||||
new_global: |evqh, token, registry, id, interface, version| {
|
||||
use std::cmp::min;
|
||||
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: |_, _, _| {}
|
||||
}
|
||||
struct SeatManager {
|
||||
sink: Arc<Mutex<EventsLoopSink>>,
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
seats: Arc<Mutex<Vec<(u32, Proxy<wl_seat::WlSeat>)>>>,
|
||||
}
|
||||
|
||||
fn xdg_ping_implementation() -> zxdg_shell_v6::Implementation<()> {
|
||||
zxdg_shell_v6::Implementation {
|
||||
ping: |_, _, shell, serial| {
|
||||
shell.pong(serial);
|
||||
impl Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> for SeatManager {
|
||||
fn receive(&mut self, evt: GlobalEvent, registry: Proxy<wl_registry::WlRegistry>) {
|
||||
use self::wl_registry::RequestsTrait as RegistryRequests;
|
||||
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>>,
|
||||
pointer: Option<wl_pointer::WlPointer>,
|
||||
keyboard: Option<wl_keyboard::WlKeyboard>,
|
||||
touch: Option<wl_touch::WlTouch>,
|
||||
windows_token: StateToken<WindowStore>
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
pointer: Option<Proxy<wl_pointer::WlPointer>>,
|
||||
keyboard: Option<Proxy<wl_keyboard::WlKeyboard>>,
|
||||
touch: Option<Proxy<wl_touch::WlTouch>>,
|
||||
}
|
||||
|
||||
fn seat_implementation() -> wl_seat::Implementation<SeatIData> {
|
||||
wl_seat::Implementation {
|
||||
name: |_, _, _, _| {},
|
||||
capabilities: |evqh, idata, seat, capabilities| {
|
||||
// create pointer if applicable
|
||||
if capabilities.contains(wl_seat::Capability::Pointer) && idata.pointer.is_none() {
|
||||
let pointer = seat.get_pointer().expect("Seat is not dead");
|
||||
let p_idata = super::pointer::PointerIData::new(
|
||||
&idata.sink,
|
||||
idata.windows_token.clone()
|
||||
);
|
||||
evqh.register(&pointer, super::pointer::pointer_implementation(), p_idata);
|
||||
idata.pointer = Some(pointer);
|
||||
}
|
||||
// destroy pointer if applicable
|
||||
if !capabilities.contains(wl_seat::Capability::Pointer) {
|
||||
if let Some(pointer) = idata.pointer.take() {
|
||||
pointer.release();
|
||||
impl Implementation<Proxy<wl_seat::WlSeat>, wl_seat::Event> for SeatData {
|
||||
fn receive(&mut self, evt: wl_seat::Event, seat: Proxy<wl_seat::WlSeat>) {
|
||||
use self::wl_seat::RequestsTrait as SeatRequests;
|
||||
match evt {
|
||||
wl_seat::Event::Name { .. } => (),
|
||||
wl_seat::Event::Capabilities { capabilities } => {
|
||||
// create pointer if applicable
|
||||
if capabilities.contains(wl_seat::Capability::Pointer) && self.pointer.is_none() {
|
||||
self.pointer = Some(super::pointer::implement_pointer(
|
||||
seat.get_pointer().unwrap(),
|
||||
self.sink.clone(),
|
||||
self.store.clone(),
|
||||
))
|
||||
}
|
||||
// destroy pointer if applicable
|
||||
if !capabilities.contains(wl_seat::Capability::Pointer) {
|
||||
if let Some(pointer) = self.pointer.take() {
|
||||
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) = idata.keyboard.take() {
|
||||
kbd.release();
|
||||
}
|
||||
}
|
||||
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) && idata.touch.is_none() {
|
||||
let touch = seat.get_touch().expect("Seat is not dead");
|
||||
let t_idata = super::touch::TouchIData::new(
|
||||
&idata.sink,
|
||||
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();
|
||||
}
|
||||
}
|
||||
if let Some(touch) = self.touch.take() {
|
||||
if touch.version() >= 3 {
|
||||
use self::wl_touch::RequestsTrait;
|
||||
touch.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -503,92 +416,54 @@ fn seat_implementation() -> wl_seat::Implementation<SeatIData> {
|
|||
* 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 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 {
|
||||
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]
|
||||
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) {
|
||||
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) {
|
||||
self.info.lock().unwrap().pix_pos
|
||||
self.mgr
|
||||
.with_info(&self.proxy, |_, info| info.location)
|
||||
.unwrap_or((0, 0))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue