mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
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
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
|
||||||
®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 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(),
|
||||||
let seat_idata = SeatIData {
|
&mut event_queue,
|
||||||
|
SeatManager {
|
||||||
sink: sink.clone(),
|
sink: sink.clone(),
|
||||||
keyboard: None,
|
store: store.clone(),
|
||||||
pointer: None,
|
seats: seats.clone(),
|
||||||
touch: None,
|
},
|
||||||
windows_token: store.clone()
|
).unwrap();
|
||||||
};
|
|
||||||
|
|
||||||
let mut me = EventsLoop {
|
Some(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| {
|
||||||
|
if let ControlFlow::Break = callback(event) {
|
||||||
control_flow.set(ControlFlow::Break);
|
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);
|
|
||||||
if let Some(info) = state_ctxt.monitors.iter().next() {
|
|
||||||
MonitorId {
|
MonitorId {
|
||||||
info: info.clone()
|
proxy: proxy.clone(),
|
||||||
|
mgr: self.env.outputs.clone(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("No monitor is available.")
|
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,235 +266,204 @@ 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 {
|
|
||||||
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: |_, _, _| {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn xdg_ping_implementation() -> zxdg_shell_v6::Implementation<()> {
|
|
||||||
zxdg_shell_v6::Implementation {
|
|
||||||
ping: |_, _, shell, serial| {
|
|
||||||
shell.pong(serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SeatIData {
|
|
||||||
sink: Arc<Mutex<EventsLoopSink>>,
|
sink: Arc<Mutex<EventsLoopSink>>,
|
||||||
pointer: Option<wl_pointer::WlPointer>,
|
store: Arc<Mutex<WindowStore>>,
|
||||||
keyboard: Option<wl_keyboard::WlKeyboard>,
|
seats: Arc<Mutex<Vec<(u32, Proxy<wl_seat::WlSeat>)>>>,
|
||||||
touch: Option<wl_touch::WlTouch>,
|
|
||||||
windows_token: StateToken<WindowStore>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seat_implementation() -> wl_seat::Implementation<SeatIData> {
|
impl Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> for SeatManager {
|
||||||
wl_seat::Implementation {
|
fn receive(&mut self, evt: GlobalEvent, registry: Proxy<wl_registry::WlRegistry>) {
|
||||||
name: |_, _, _, _| {},
|
use self::wl_registry::RequestsTrait as RegistryRequests;
|
||||||
capabilities: |evqh, idata, seat, capabilities| {
|
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 SeatData {
|
||||||
|
sink: Arc<Mutex<EventsLoopSink>>,
|
||||||
|
store: Arc<Mutex<WindowStore>>,
|
||||||
|
pointer: Option<Proxy<wl_pointer::WlPointer>>,
|
||||||
|
keyboard: Option<Proxy<wl_keyboard::WlKeyboard>>,
|
||||||
|
touch: Option<Proxy<wl_touch::WlTouch>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// create pointer if applicable
|
||||||
if capabilities.contains(wl_seat::Capability::Pointer) && idata.pointer.is_none() {
|
if capabilities.contains(wl_seat::Capability::Pointer) && self.pointer.is_none() {
|
||||||
let pointer = seat.get_pointer().expect("Seat is not dead");
|
self.pointer = Some(super::pointer::implement_pointer(
|
||||||
let p_idata = super::pointer::PointerIData::new(
|
seat.get_pointer().unwrap(),
|
||||||
&idata.sink,
|
self.sink.clone(),
|
||||||
idata.windows_token.clone()
|
self.store.clone(),
|
||||||
);
|
))
|
||||||
evqh.register(&pointer, super::pointer::pointer_implementation(), p_idata);
|
|
||||||
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() {
|
||||||
|
if pointer.version() >= 3 {
|
||||||
|
use self::wl_pointer::RequestsTrait;
|
||||||
pointer.release();
|
pointer.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// create keyboard if applicable
|
// create keyboard if applicable
|
||||||
if capabilities.contains(wl_seat::Capability::Keyboard) && idata.keyboard.is_none() {
|
if capabilities.contains(wl_seat::Capability::Keyboard) && self.keyboard.is_none() {
|
||||||
let kbd = seat.get_keyboard().expect("Seat is not dead");
|
self.keyboard = Some(super::keyboard::init_keyboard(
|
||||||
init_keyboard(evqh, &kbd, &idata.sink);
|
seat.get_keyboard().unwrap(),
|
||||||
idata.keyboard = Some(kbd);
|
self.sink.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
// destroy keyboard if applicable
|
// destroy keyboard if applicable
|
||||||
if !capabilities.contains(wl_seat::Capability::Keyboard) {
|
if !capabilities.contains(wl_seat::Capability::Keyboard) {
|
||||||
if let Some(kbd) = idata.keyboard.take() {
|
if let Some(kbd) = self.keyboard.take() {
|
||||||
|
if kbd.version() >= 3 {
|
||||||
|
use self::wl_keyboard::RequestsTrait;
|
||||||
kbd.release();
|
kbd.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// create touch if applicable
|
// create touch if applicable
|
||||||
if capabilities.contains(wl_seat::Capability::Touch) && idata.touch.is_none() {
|
if capabilities.contains(wl_seat::Capability::Touch) && self.touch.is_none() {
|
||||||
let touch = seat.get_touch().expect("Seat is not dead");
|
self.touch = Some(super::touch::implement_touch(
|
||||||
let t_idata = super::touch::TouchIData::new(
|
seat.get_touch().unwrap(),
|
||||||
&idata.sink,
|
self.sink.clone(),
|
||||||
idata.windows_token.clone()
|
self.store.clone(),
|
||||||
);
|
))
|
||||||
evqh.register(&touch, super::touch::touch_implementation(), t_idata);
|
|
||||||
idata.touch = Some(touch);
|
|
||||||
}
|
}
|
||||||
// destroy touch if applicable
|
// destroy touch if applicable
|
||||||
if !capabilities.contains(wl_seat::Capability::Touch) {
|
if !capabilities.contains(wl_seat::Capability::Touch) {
|
||||||
if let Some(touch) = idata.touch.take() {
|
if let Some(touch) = self.touch.take() {
|
||||||
|
if touch.version() >= 3 {
|
||||||
|
use self::wl_touch::RequestsTrait;
|
||||||
touch.release();
|
touch.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(kbd) = self.keyboard.take() {
|
||||||
|
if kbd.version() >= 3 {
|
||||||
|
use self::wl_keyboard::RequestsTrait;
|
||||||
|
kbd.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(touch) = self.touch.take() {
|
||||||
|
if touch.version() >= 3 {
|
||||||
|
use self::wl_touch::RequestsTrait;
|
||||||
|
touch.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,113 +1,117 @@
|
||||||
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;
|
||||||
|
let my_sink = sink.clone();
|
||||||
|
// }
|
||||||
|
let ret = map_keyboard_auto(keyboard, move |evt: KbEvent, _| match evt {
|
||||||
|
KbEvent::Enter { surface, .. } => {
|
||||||
|
let wid = make_wid(&surface);
|
||||||
|
my_sink
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send_event(WindowEvent::Focused(true), wid);
|
||||||
|
target = Some(wid);
|
||||||
}
|
}
|
||||||
|
KbEvent::Leave { surface, .. } => {
|
||||||
fn mapped_keyboard_impl() -> MappedKeyboardImplementation<KeyboardIData> {
|
let wid = make_wid(&surface);
|
||||||
MappedKeyboardImplementation {
|
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(false), wid);
|
||||||
idata.target = Some(wid);
|
target = None;
|
||||||
},
|
}
|
||||||
leave: |_, idata, _, _, surface| {
|
KbEvent::Key {
|
||||||
let wid = make_wid(surface);
|
modifiers,
|
||||||
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid);
|
rawkey,
|
||||||
idata.target = None;
|
keysym,
|
||||||
},
|
state,
|
||||||
key: |_, idata, _, _, _, mods, rawkey, keysym, state, utf8| {
|
utf8,
|
||||||
if let Some(wid) = idata.target {
|
..
|
||||||
|
} => {
|
||||||
|
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 {
|
||||||
// This is fallback impl if libxkbcommon was not available
|
Ok(keyboard) => keyboard,
|
||||||
|
Err((_, keyboard)) => {
|
||||||
|
// This is a fallback impl if libxkbcommon was not available
|
||||||
// This case should probably never happen, as most wayland
|
// This case should probably never happen, as most wayland
|
||||||
// compositors _need_ libxkbcommon anyway...
|
// compositors _need_ libxkbcommon anyway...
|
||||||
//
|
//
|
||||||
// In this case, we don't have the keymap information (it is
|
// In this case, we don't have the keymap information (it is
|
||||||
// supposed to be serialized by the compositor using libxkbcommon)
|
// supposed to be serialized by the compositor using libxkbcommon)
|
||||||
fn raw_keyboard_impl() -> wl_keyboard::Implementation<KeyboardIData> {
|
|
||||||
wl_keyboard::Implementation {
|
// { variables to be captured by the closure
|
||||||
enter: |_, idata, _, _, surface, _| {
|
let mut target = None;
|
||||||
let wid = make_wid(surface);
|
let my_sink = sink;
|
||||||
idata.sink.lock().unwrap().send_event(Event::Focused(true), wid);
|
// }
|
||||||
idata.target = Some(wid);
|
keyboard.implement(move |evt, _| match evt {
|
||||||
},
|
wl_keyboard::Event::Enter { surface, .. } => {
|
||||||
leave: |_, idata, _, _, surface| {
|
let wid = make_wid(&surface);
|
||||||
let wid = make_wid(surface);
|
my_sink
|
||||||
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid);
|
.lock()
|
||||||
idata.target = None;
|
.unwrap()
|
||||||
},
|
.send_event(WindowEvent::Focused(true), wid);
|
||||||
key: |_, idata, _, _, _, key, state| {
|
target = Some(wid);
|
||||||
if let Some(wid) = idata.target {
|
}
|
||||||
|
wl_keyboard::Event::Leave { surface, .. } => {
|
||||||
|
let wid = make_wid(&surface);
|
||||||
|
my_sink
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send_event(WindowEvent::Focused(false), wid);
|
||||||
|
target = None;
|
||||||
|
}
|
||||||
|
wl_keyboard::Event::Key { key, state, .. } => {
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
idata.sink.lock().unwrap().send_event(
|
my_sink.lock().unwrap().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,
|
||||||
|
@ -116,13 +120,13 @@ fn raw_keyboard_impl() -> wl_keyboard::Implementation<KeyboardIData> {
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wid
|
wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
repeat_info: |_, _idata, _, _rate, _delay| {},
|
_ => (),
|
||||||
keymap: |_, _, _, _, _, _| {},
|
})
|
||||||
modifiers: |_, _, _, _, _, _, _, _| {}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,12 +143,12 @@ fn key_to_vkey(rawkey: u32, keysym: u32) -> Option<VirtualKeyCode> {
|
||||||
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),
|
||||||
|
@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if let Some(wid) = wid {
|
||||||
idata.mouse_focus = Some(wid);
|
mouse_focus = Some(wid);
|
||||||
let mut guard = idata.sink.lock().unwrap();
|
sink.send_event(
|
||||||
guard.send_event(
|
WindowEvent::CursorEntered {
|
||||||
Event::CursorEntered {
|
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
},
|
},
|
||||||
wid,
|
wid,
|
||||||
);
|
);
|
||||||
guard.send_event(
|
sink.send_event(
|
||||||
Event::CursorMoved {
|
WindowEvent::CursorMoved {
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
position: (x, y),
|
position: (surface_x, surface_y),
|
||||||
// TODO: replace dummy value with actual modifier state
|
// TODO: replace dummy value with actual modifier state
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
},
|
||||||
wid,
|
wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
leave: |evqh, idata, _, _, surface| {
|
PtrEvent::Leave { surface, .. } => {
|
||||||
idata.mouse_focus = None;
|
mouse_focus = None;
|
||||||
let wid = evqh.state().get(&idata.windows_token).find_wid(surface);
|
let wid = store.find_wid(&surface);
|
||||||
if let Some(wid) = wid {
|
if let Some(wid) = wid {
|
||||||
let mut guard = idata.sink.lock().unwrap();
|
sink.send_event(
|
||||||
guard.send_event(
|
WindowEvent::CursorLeft {
|
||||||
Event::CursorLeft {
|
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
},
|
},
|
||||||
wid,
|
wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
motion: |_, idata, _, _, x, y| {
|
PtrEvent::Motion {
|
||||||
if let Some(wid) = idata.mouse_focus {
|
surface_x,
|
||||||
idata.sink.lock().unwrap().send_event(
|
surface_y,
|
||||||
Event::CursorMoved {
|
..
|
||||||
|
} => {
|
||||||
|
if let Some(wid) = mouse_focus {
|
||||||
|
sink.send_event(
|
||||||
|
WindowEvent::CursorMoved {
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
position: (x, y),
|
position: (surface_x, surface_y),
|
||||||
// TODO: replace dummy value with actual modifier state
|
// TODO: replace dummy value with actual modifier state
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
},
|
||||||
wid
|
wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
button: |_, idata, _, _, _, button, state| {
|
PtrEvent::Button { button, state, .. } => {
|
||||||
if let Some(wid) = idata.mouse_focus {
|
if let Some(wid) = mouse_focus {
|
||||||
let state = match state {
|
let state = match state {
|
||||||
wl_pointer::ButtonState::Pressed => ElementState::Pressed,
|
wl_pointer::ButtonState::Pressed => ElementState::Pressed,
|
||||||
wl_pointer::ButtonState::Released => ElementState::Released
|
wl_pointer::ButtonState::Released => ElementState::Released,
|
||||||
};
|
};
|
||||||
let button = match button {
|
let button = match button {
|
||||||
0x110 => MouseButton::Left,
|
0x110 => MouseButton::Left,
|
||||||
0x111 => MouseButton::Right,
|
0x111 => MouseButton::Right,
|
||||||
0x112 => MouseButton::Middle,
|
0x112 => MouseButton::Middle,
|
||||||
// TODO figure out the translation ?
|
// TODO figure out the translation ?
|
||||||
_ => return
|
_ => return,
|
||||||
};
|
};
|
||||||
idata.sink.lock().unwrap().send_event(
|
sink.send_event(
|
||||||
Event::MouseInput {
|
WindowEvent::MouseInput {
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
state: state,
|
state: state,
|
||||||
button: button,
|
button: button,
|
||||||
// TODO: replace dummy value with actual modifier state
|
// TODO: replace dummy value with actual modifier state
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
},
|
||||||
wid
|
wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
axis: |_, idata, pointer, _, axis, value| {
|
PtrEvent::Axis { axis, value, .. } => {
|
||||||
if let Some(wid) = idata.mouse_focus {
|
if let Some(wid) = mouse_focus {
|
||||||
if pointer.version() < 5 {
|
if pointer.version() < 5 {
|
||||||
let (mut x, mut y) = (0.0, 0.0);
|
let (mut x, mut y) = (0.0, 0.0);
|
||||||
// old seat compatibility
|
// old seat compatibility
|
||||||
match axis {
|
match axis {
|
||||||
// wayland vertical sign convention is the inverse of winit
|
// wayland vertical sign convention is the inverse of winit
|
||||||
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
||||||
wl_pointer::Axis::HorizontalScroll => x += value as f32
|
wl_pointer::Axis::HorizontalScroll => x += value as f32,
|
||||||
}
|
}
|
||||||
idata.sink.lock().unwrap().send_event(
|
sink.send_event(
|
||||||
Event::MouseWheel {
|
WindowEvent::MouseWheel {
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
|
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
|
||||||
phase: TouchPhase::Moved,
|
phase: TouchPhase::Moved,
|
||||||
// TODO: replace dummy value with actual modifier state
|
// TODO: replace dummy value with actual modifier state
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
},
|
||||||
wid
|
wid,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let (mut x, mut y) = idata.axis_buffer.unwrap_or((0.0, 0.0));
|
let (mut x, mut y) = axis_buffer.unwrap_or((0.0, 0.0));
|
||||||
match axis {
|
match axis {
|
||||||
// wayland vertical sign convention is the inverse of winit
|
// wayland vertical sign convention is the inverse of winit
|
||||||
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
||||||
wl_pointer::Axis::HorizontalScroll => x += value as f32
|
wl_pointer::Axis::HorizontalScroll => x += value as f32,
|
||||||
}
|
}
|
||||||
idata.axis_buffer = Some((x,y));
|
axis_buffer = Some((x, y));
|
||||||
idata.axis_state = match idata.axis_state {
|
axis_state = match axis_state {
|
||||||
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
||||||
_ => TouchPhase::Started
|
_ => TouchPhase::Started,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
frame: |_, idata, _| {
|
PtrEvent::Frame => {
|
||||||
let axis_buffer = idata.axis_buffer.take();
|
let axis_buffer = axis_buffer.take();
|
||||||
let axis_discrete_buffer = idata.axis_discrete_buffer.take();
|
let axis_discrete_buffer = axis_discrete_buffer.take();
|
||||||
if let Some(wid) = idata.mouse_focus {
|
if let Some(wid) = mouse_focus {
|
||||||
if let Some((x, y)) = axis_discrete_buffer {
|
if let Some((x, y)) = axis_discrete_buffer {
|
||||||
idata.sink.lock().unwrap().send_event(
|
sink.send_event(
|
||||||
Event::MouseWheel {
|
WindowEvent::MouseWheel {
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
|
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
|
||||||
phase: idata.axis_state,
|
phase: axis_state,
|
||||||
// TODO: replace dummy value with actual modifier state
|
// TODO: replace dummy value with actual modifier state
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
},
|
||||||
wid
|
wid,
|
||||||
);
|
);
|
||||||
} else if let Some((x, y)) = axis_buffer {
|
} else if let Some((x, y)) = axis_buffer {
|
||||||
idata.sink.lock().unwrap().send_event(
|
sink.send_event(
|
||||||
Event::MouseWheel {
|
WindowEvent::MouseWheel {
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
|
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
|
||||||
phase: idata.axis_state,
|
phase: axis_state,
|
||||||
// TODO: replace dummy value with actual modifier state
|
// TODO: replace dummy value with actual modifier state
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
},
|
||||||
wid
|
wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
axis_source: |_, _, _, _| {},
|
PtrEvent::AxisSource { .. } => (),
|
||||||
axis_stop: |_, idata, _, _, _| {
|
PtrEvent::AxisStop { .. } => {
|
||||||
idata.axis_state = TouchPhase::Ended;
|
axis_state = TouchPhase::Ended;
|
||||||
},
|
}
|
||||||
axis_discrete: |_, idata, _, axis, discrete| {
|
PtrEvent::AxisDiscrete { axis, discrete } => {
|
||||||
let (mut x, mut y) = idata.axis_discrete_buffer.unwrap_or((0,0));
|
let (mut x, mut y) = axis_discrete_buffer.unwrap_or((0, 0));
|
||||||
match axis {
|
match axis {
|
||||||
// wayland vertical sign convention is the inverse of winit
|
// wayland vertical sign convention is the inverse of winit
|
||||||
wl_pointer::Axis::VerticalScroll => y -= discrete,
|
wl_pointer::Axis::VerticalScroll => y -= discrete,
|
||||||
wl_pointer::Axis::HorizontalScroll => x += discrete
|
wl_pointer::Axis::HorizontalScroll => x += discrete,
|
||||||
}
|
}
|
||||||
idata.axis_discrete_buffer = Some((x,y));
|
axis_discrete_buffer = Some((x, y));
|
||||||
idata.axis_state = match idata.axis_state {
|
axis_state = match axis_state {
|
||||||
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
||||||
_ => TouchPhase::Started
|
_ => TouchPhase::Started,
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -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| {
|
|
||||||
let wid = evqh.state().get(&idata.windows_token).find_wid(surface);
|
|
||||||
if let Some(wid) = wid {
|
if let Some(wid) = wid {
|
||||||
let mut guard = idata.sink.lock().unwrap();
|
sink.send_event(
|
||||||
guard.send_event(
|
WindowEvent::Touch(::Touch {
|
||||||
Event::Touch(::Touch {
|
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
phase: TouchPhase::Started,
|
phase: TouchPhase::Started,
|
||||||
location: (x, y),
|
location: (x, y),
|
||||||
id: touch_id as u64
|
id: id as u64,
|
||||||
}),
|
}),
|
||||||
wid,
|
wid,
|
||||||
);
|
);
|
||||||
idata.pending_ids.push(TouchPoint {
|
pending_ids.push(TouchPoint {
|
||||||
wid: wid,
|
wid: wid,
|
||||||
location: (x, y),
|
location: (x, y),
|
||||||
id: touch_id
|
id: id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
up: |_, idata, _, _serial, _time, touch_id| {
|
TouchEvent::Up { id, .. } => {
|
||||||
let idx = idata.pending_ids.iter().position(|p| p.id == touch_id);
|
let idx = pending_ids.iter().position(|p| p.id == id);
|
||||||
if let Some(idx) = idx {
|
if let Some(idx) = idx {
|
||||||
let pt = idata.pending_ids.remove(idx);
|
let pt = pending_ids.remove(idx);
|
||||||
let mut guard = idata.sink.lock().unwrap();
|
sink.send_event(
|
||||||
guard.send_event(
|
WindowEvent::Touch(::Touch {
|
||||||
Event::Touch(::Touch {
|
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
phase: TouchPhase::Ended,
|
phase: TouchPhase::Ended,
|
||||||
location: pt.location,
|
location: pt.location,
|
||||||
id: touch_id as u64
|
id: id as u64,
|
||||||
}),
|
}),
|
||||||
pt.wid,
|
pt.wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
motion: |_, idata, _, _time, touch_id, x, y| {
|
TouchEvent::Motion { id, x, y, .. } => {
|
||||||
let pt = idata.pending_ids.iter_mut().find(|p| p.id == touch_id);
|
let pt = pending_ids.iter_mut().find(|p| p.id == id);
|
||||||
if let Some(pt) = pt {
|
if let Some(pt) = pt {
|
||||||
let mut guard = idata.sink.lock().unwrap();
|
|
||||||
pt.location = (x, y);
|
pt.location = (x, y);
|
||||||
guard.send_event(
|
sink.send_event(
|
||||||
Event::Touch(::Touch {
|
WindowEvent::Touch(::Touch {
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
phase: TouchPhase::Moved,
|
phase: TouchPhase::Moved,
|
||||||
location: (x, y),
|
location: (x, y),
|
||||||
id: touch_id as u64
|
id: id as u64,
|
||||||
}),
|
}),
|
||||||
pt.wid,
|
pt.wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
frame: |_, _, _| {},
|
TouchEvent::Frame => (),
|
||||||
cancel: |_, idata, _| {
|
TouchEvent::Cancel => for pt in pending_ids.drain(..) {
|
||||||
let mut guard = idata.sink.lock().unwrap();
|
sink.send_event(
|
||||||
for pt in idata.pending_ids.drain(..) {
|
WindowEvent::Touch(::Touch {
|
||||||
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,
|
||||||
);
|
);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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();
|
|
||||||
evq.state().get_mut(&store_token).windows.push(InternalWindow {
|
|
||||||
closed: false,
|
closed: false,
|
||||||
newsize: None,
|
newsize: None,
|
||||||
need_refresh: false,
|
need_refresh: false,
|
||||||
need_frame_refresh: need_frame_refresh.clone(),
|
need_frame_refresh: need_frame_refresh.clone(),
|
||||||
surface: surface.clone().unwrap(),
|
surface: surface.clone(),
|
||||||
kill_switch: kill_switch.clone(),
|
kill_switch: kill_switch.clone(),
|
||||||
frame: Arc::downgrade(&frame)
|
frame: Arc::downgrade(&frame),
|
||||||
});
|
});
|
||||||
evq.sync_roundtrip().unwrap();
|
evlp.evq.borrow_mut().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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue