mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-25 06:41:31 +11:00
Merge pull request #191 from mitchmindtree/remove_sync
Remove Sync and Clone from EventsLoop. Add EventsLoopProxy.
This commit is contained in:
commit
a08347eef0
|
@ -28,15 +28,15 @@ another library.
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
let window = winit::Window::new(&events_loop).unwrap();
|
let window = winit::Window::new(&events_loop).unwrap();
|
||||||
|
|
||||||
events_loop.run_forever(|event| {
|
events_loop.run_forever(|event| {
|
||||||
match event {
|
match event {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
|
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
|
||||||
events_loop.interrupt();
|
winit::ControlFlow::Break
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => winit::ControlFlow::Continue,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput};
|
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
|
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
|
||||||
window.set_title("A fantastic window!");
|
window.set_title("A fantastic window!");
|
||||||
|
@ -23,9 +23,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
||||||
events_loop.interrupt()
|
return ControlFlow::Break;
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
ControlFlow::Continue
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use winit::{ControlFlow, Event, WindowEvent};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// enumerating monitors
|
// enumerating monitors
|
||||||
|
@ -22,7 +23,7 @@ fn main() {
|
||||||
monitor
|
monitor
|
||||||
};
|
};
|
||||||
|
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
let _window = winit::WindowBuilder::new()
|
let _window = winit::WindowBuilder::new()
|
||||||
.with_title("Hello world!")
|
.with_title("Hello world!")
|
||||||
|
@ -34,16 +35,18 @@ fn main() {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
winit::Event::WindowEvent { event, .. } => {
|
Event::WindowEvent { event, .. } => {
|
||||||
match event {
|
match event {
|
||||||
winit::WindowEvent::Closed => events_loop.interrupt(),
|
WindowEvent::Closed => return ControlFlow::Break,
|
||||||
winit::WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, ..
|
input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, ..
|
||||||
} => events_loop.interrupt(),
|
} => return ControlFlow::Break,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ControlFlow::Continue
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
use winit::{WindowEvent, ElementState, KeyboardInput};
|
use winit::{ControlFlow, WindowEvent, ElementState, KeyboardInput};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
|
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
|
||||||
window.set_title("winit - Cursor grabbing test");
|
window.set_title("winit - Cursor grabbing test");
|
||||||
|
@ -28,7 +28,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
WindowEvent::Closed => events_loop.interrupt(),
|
WindowEvent::Closed => return ControlFlow::Break,
|
||||||
|
|
||||||
a @ WindowEvent::MouseMoved { .. } => {
|
a @ WindowEvent::MouseMoved { .. } => {
|
||||||
println!("{:?}", a);
|
println!("{:?}", a);
|
||||||
|
@ -39,5 +39,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ControlFlow::Continue
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
let _window = winit::WindowBuilder::new()
|
let _window = winit::WindowBuilder::new()
|
||||||
.with_min_dimensions(400, 200)
|
.with_min_dimensions(400, 200)
|
||||||
|
@ -13,8 +13,8 @@ fn main() {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => events_loop.interrupt(),
|
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => winit::ControlFlow::Break,
|
||||||
_ => ()
|
_ => winit::ControlFlow::Continue,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
let window1 = winit::Window::new(&events_loop).unwrap();
|
let window1 = winit::Window::new(&events_loop).unwrap();
|
||||||
let window2 = winit::Window::new(&events_loop).unwrap();
|
let window2 = winit::Window::new(&events_loop).unwrap();
|
||||||
|
@ -24,10 +24,11 @@ fn main() {
|
||||||
|
|
||||||
num_windows -= 1;
|
num_windows -= 1;
|
||||||
if num_windows == 0 {
|
if num_windows == 0 {
|
||||||
events_loop.interrupt();
|
return winit::ControlFlow::Break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
winit::ControlFlow::Continue
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
29
examples/proxy.rs
Normal file
29
examples/proxy.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
extern crate winit;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
|
let _window = winit::WindowBuilder::new()
|
||||||
|
.with_title("A fantastic window!")
|
||||||
|
.build(&events_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let proxy = events_loop.create_proxy();
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
// Wake up the `events_loop` once every second.
|
||||||
|
loop {
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||||
|
proxy.wakeup().unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
events_loop.run_forever(|event| {
|
||||||
|
println!("{:?}", event);
|
||||||
|
match event {
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } =>
|
||||||
|
winit::ControlFlow::Break,
|
||||||
|
_ => winit::ControlFlow::Continue,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
let window = winit::WindowBuilder::new().with_decorations(false)
|
let window = winit::WindowBuilder::new().with_decorations(false)
|
||||||
.with_transparency(true)
|
.with_transparency(true)
|
||||||
|
@ -13,8 +13,8 @@ fn main() {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => events_loop.interrupt(),
|
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => winit::ControlFlow::Break,
|
||||||
_ => ()
|
_ => winit::ControlFlow::Continue,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
extern crate winit;
|
extern crate winit;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
let window = winit::WindowBuilder::new()
|
let _window = winit::WindowBuilder::new()
|
||||||
.with_title("A fantastic window!")
|
.with_title("A fantastic window!")
|
||||||
.build(&events_loop)
|
.build(&events_loop)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -12,8 +12,10 @@ fn main() {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => events_loop.interrupt(),
|
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
|
||||||
_ => ()
|
winit::ControlFlow::Break
|
||||||
|
},
|
||||||
|
_ => winit::ControlFlow::Continue,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,26 +8,31 @@
|
||||||
macro_rules! gen_api_transition {
|
macro_rules! gen_api_transition {
|
||||||
() => {
|
() => {
|
||||||
pub struct EventsLoop {
|
pub struct EventsLoop {
|
||||||
windows: ::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>,
|
windows: ::std::sync::Arc<::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>>,
|
||||||
interrupted: ::std::sync::atomic::AtomicBool,
|
awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventsLoopProxy {
|
||||||
|
awakened: ::std::sync::Weak<::std::sync::atomic::AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
pub fn new() -> EventsLoop {
|
pub fn new() -> EventsLoop {
|
||||||
EventsLoop {
|
EventsLoop {
|
||||||
windows: ::std::sync::Mutex::new(vec![]),
|
windows: ::std::sync::Arc::new(::std::sync::Mutex::new(vec![])),
|
||||||
interrupted: ::std::sync::atomic::AtomicBool::new(false),
|
awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt(&self) {
|
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||||
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_events<F>(&self, mut callback: F)
|
|
||||||
where F: FnMut(::Event)
|
where F: FnMut(::Event)
|
||||||
{
|
{
|
||||||
let mut windows = self.windows.lock().unwrap();
|
if self.awakened.load(::std::sync::atomic::Ordering::Relaxed) {
|
||||||
|
self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
||||||
|
callback(::Event::Awakened);
|
||||||
|
}
|
||||||
|
|
||||||
|
let windows = self.windows.lock().unwrap();
|
||||||
for window in windows.iter() {
|
for window in windows.iter() {
|
||||||
for event in window.poll_events() {
|
for event in window.poll_events() {
|
||||||
callback(::Event::WindowEvent {
|
callback(::Event::WindowEvent {
|
||||||
|
@ -38,18 +43,41 @@ macro_rules! gen_api_transition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&self, mut callback: F)
|
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(::Event)
|
where F: FnMut(::Event) -> ::ControlFlow,
|
||||||
{
|
{
|
||||||
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
// Yeah that's a very bad implementation.
|
// Yeah that's a very bad implementation.
|
||||||
loop {
|
loop {
|
||||||
self.poll_events(|e| callback(e));
|
let mut control_flow = ::ControlFlow::Continue;
|
||||||
::std::thread::sleep_ms(5);
|
self.poll_events(|e| {
|
||||||
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
|
if let ::ControlFlow::Break = callback(e) {
|
||||||
|
control_flow = ::ControlFlow::Break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if let ::ControlFlow::Break = control_flow {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
::std::thread::sleep(::std::time::Duration::from_millis(5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||||
|
EventsLoopProxy {
|
||||||
|
awakened: ::std::sync::Arc::downgrade(&self.awakened),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventsLoopProxy {
|
||||||
|
pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
|
||||||
|
match self.awakened.upgrade() {
|
||||||
|
None => Err(::EventsLoopClosed),
|
||||||
|
Some(awakened) => {
|
||||||
|
awakened.store(true, ::std::sync::atomic::Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +90,7 @@ macro_rules! gen_api_transition {
|
||||||
|
|
||||||
pub struct Window2 {
|
pub struct Window2 {
|
||||||
pub window: ::std::sync::Arc<Window>,
|
pub window: ::std::sync::Arc<Window>,
|
||||||
events_loop: ::std::sync::Weak<EventsLoop>,
|
windows: ::std::sync::Weak<::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::Deref for Window2 {
|
impl ::std::ops::Deref for Window2 {
|
||||||
|
@ -74,7 +102,8 @@ macro_rules! gen_api_transition {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window2 {
|
impl Window2 {
|
||||||
pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
|
pub fn new(events_loop: &EventsLoop,
|
||||||
|
window: &::WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||||
-> Result<Window2, CreationError>
|
-> Result<Window2, CreationError>
|
||||||
{
|
{
|
||||||
|
@ -82,7 +111,7 @@ macro_rules! gen_api_transition {
|
||||||
events_loop.windows.lock().unwrap().push(win.clone());
|
events_loop.windows.lock().unwrap().push(win.clone());
|
||||||
Ok(Window2 {
|
Ok(Window2 {
|
||||||
window: win,
|
window: win,
|
||||||
events_loop: ::std::sync::Arc::downgrade(&events_loop),
|
windows: ::std::sync::Arc::downgrade(&events_loop.windows),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +123,8 @@ macro_rules! gen_api_transition {
|
||||||
|
|
||||||
impl Drop for Window2 {
|
impl Drop for Window2 {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(ev) = self.events_loop.upgrade() {
|
if let Some(windows) = self.windows.upgrade() {
|
||||||
let mut windows = ev.windows.lock().unwrap();
|
let mut windows = windows.lock().unwrap();
|
||||||
windows.retain(|w| &**w as *const Window != &*self.window as *const _);
|
windows.retain(|w| &**w as *const Window != &*self.window as *const _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,11 @@ pub enum Event {
|
||||||
device_id: DeviceId,
|
device_id: DeviceId,
|
||||||
event: DeviceEvent,
|
event: DeviceEvent,
|
||||||
},
|
},
|
||||||
|
Awakened,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum WindowEvent {
|
pub enum WindowEvent {
|
||||||
// TODO: remove ; can break the lib internally so be careful
|
|
||||||
Awakened,
|
|
||||||
|
|
||||||
/// The size of the window has changed.
|
/// The size of the window has changed.
|
||||||
Resized(u32, u32),
|
Resized(u32, u32),
|
||||||
|
|
98
src/lib.rs
98
src/lib.rs
|
@ -34,10 +34,9 @@
|
||||||
//! screen, such as video games.
|
//! screen, such as video games.
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use winit::Event;
|
//! use winit::{Event, WindowEvent};
|
||||||
//! use winit::WindowEvent;
|
|
||||||
//! # use winit::EventsLoop;
|
//! # use winit::EventsLoop;
|
||||||
//! # let events_loop = EventsLoop::new();
|
//! # let mut events_loop = EventsLoop::new();
|
||||||
//!
|
//!
|
||||||
//! loop {
|
//! loop {
|
||||||
//! events_loop.poll_events(|event| {
|
//! events_loop.poll_events(|event| {
|
||||||
|
@ -52,21 +51,20 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run
|
//! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run
|
||||||
//! forever unless it is stopped by calling `events_loop.interrupt()`.
|
//! forever unless it is stopped by returning `ControlFlow::Break`.
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use winit::Event;
|
//! use winit::{ControlFlow, Event, WindowEvent};
|
||||||
//! use winit::WindowEvent;
|
|
||||||
//! # use winit::EventsLoop;
|
//! # use winit::EventsLoop;
|
||||||
//! # let events_loop = EventsLoop::new();
|
//! # let mut events_loop = EventsLoop::new();
|
||||||
//!
|
//!
|
||||||
//! events_loop.run_forever(|event| {
|
//! events_loop.run_forever(|event| {
|
||||||
//! match event {
|
//! match event {
|
||||||
//! Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
//! Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
||||||
//! println!("The window was closed ; stopping");
|
//! println!("The window was closed ; stopping");
|
||||||
//! events_loop.interrupt();
|
//! ControlFlow::Break
|
||||||
//! },
|
//! },
|
||||||
//! _ => ()
|
//! _ => ControlFlow::Continue,
|
||||||
//! }
|
//! }
|
||||||
//! });
|
//! });
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -119,8 +117,6 @@ extern crate x11_dl;
|
||||||
#[macro_use(wayland_env,declare_handler)]
|
#[macro_use(wayland_env,declare_handler)]
|
||||||
extern crate wayland_client;
|
extern crate wayland_client;
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub use events::*;
|
pub use events::*;
|
||||||
pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor};
|
pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor};
|
||||||
pub use native_monitor::NativeMonitorId;
|
pub use native_monitor::NativeMonitorId;
|
||||||
|
@ -139,20 +135,17 @@ pub mod os;
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use winit::Event;
|
/// use winit::{Event, EventsLoop, Window, WindowEvent, ControlFlow};
|
||||||
/// use winit::EventsLoop;
|
|
||||||
/// use winit::Window;
|
|
||||||
/// use winit::WindowEvent;
|
|
||||||
///
|
///
|
||||||
/// let events_loop = EventsLoop::new();
|
/// let mut events_loop = EventsLoop::new();
|
||||||
/// let window = Window::new(&events_loop).unwrap();
|
/// let window = Window::new(&events_loop).unwrap();
|
||||||
///
|
///
|
||||||
/// events_loop.run_forever(|event| {
|
/// events_loop.run_forever(|event| {
|
||||||
/// match event {
|
/// match event {
|
||||||
/// Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
/// Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
||||||
/// events_loop.interrupt();
|
/// ControlFlow::Break
|
||||||
/// },
|
/// },
|
||||||
/// _ => ()
|
/// _ => ControlFlow::Continue,
|
||||||
/// }
|
/// }
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -186,24 +179,35 @@ pub struct AxisId(u32);
|
||||||
pub struct ButtonId(u32);
|
pub struct ButtonId(u32);
|
||||||
|
|
||||||
/// Provides a way to retreive events from the windows that were registered to it.
|
/// Provides a way to retreive events from the windows that were registered to it.
|
||||||
// TODO: document usage in multiple threads
|
///
|
||||||
#[derive(Clone)]
|
/// To wake up an `EventsLoop` from a another thread, see the `EventsLoopProxy` docs.
|
||||||
pub struct EventsLoop {
|
pub struct EventsLoop {
|
||||||
events_loop: Arc<platform::EventsLoop>,
|
events_loop: platform::EventsLoop,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returned by the user callback given to the `EventsLoop::run_forever` method.
|
||||||
|
///
|
||||||
|
/// Indicates whether the `run_forever` method should continue or complete.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ControlFlow {
|
||||||
|
/// Continue looping and waiting for events.
|
||||||
|
Continue,
|
||||||
|
/// Break from the event loop.
|
||||||
|
Break,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
/// Builds a new events loop.
|
/// Builds a new events loop.
|
||||||
pub fn new() -> EventsLoop {
|
pub fn new() -> EventsLoop {
|
||||||
EventsLoop {
|
EventsLoop {
|
||||||
events_loop: Arc::new(platform::EventsLoop::new()),
|
events_loop: platform::EventsLoop::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches all the events that are pending, calls the callback function for each of them,
|
/// Fetches all the events that are pending, calls the callback function for each of them,
|
||||||
/// and returns.
|
/// and returns.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn poll_events<F>(&self, callback: F)
|
pub fn poll_events<F>(&mut self, callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event)
|
||||||
{
|
{
|
||||||
self.events_loop.poll_events(callback)
|
self.events_loop.poll_events(callback)
|
||||||
|
@ -211,17 +215,51 @@ impl EventsLoop {
|
||||||
|
|
||||||
/// Runs forever until `interrupt()` is called. Whenever an event happens, calls the callback.
|
/// Runs forever until `interrupt()` is called. Whenever an event happens, calls the callback.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run_forever<F>(&self, callback: F)
|
pub fn run_forever<F>(&mut self, callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event) -> ControlFlow
|
||||||
{
|
{
|
||||||
self.events_loop.run_forever(callback)
|
self.events_loop.run_forever(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If we called `run_forever()`, stops the process of waiting for events.
|
/// Creates an `EventsLoopProxy` that can be used to wake up the `EventsLoop` from another
|
||||||
// TODO: what if we're waiting from multiple threads?
|
/// thread.
|
||||||
#[inline]
|
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||||
pub fn interrupt(&self) {
|
EventsLoopProxy {
|
||||||
self.events_loop.interrupt()
|
events_loop_proxy: self.events_loop.create_proxy(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to wake up the `EventsLoop` from another thread.
|
||||||
|
pub struct EventsLoopProxy {
|
||||||
|
events_loop_proxy: platform::EventsLoopProxy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventsLoopProxy {
|
||||||
|
/// Wake up the `EventsLoop` from which this proxy was created.
|
||||||
|
///
|
||||||
|
/// This causes the `EventsLoop` to emit an `Awakened` event.
|
||||||
|
///
|
||||||
|
/// Returns an `Err` if the associated `EventsLoop` no longer exists.
|
||||||
|
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
||||||
|
self.events_loop_proxy.wakeup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The error that is returned when an `EventsLoopProxy` attempts to wake up an `EventsLoop` that
|
||||||
|
/// no longer exists.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct EventsLoopClosed;
|
||||||
|
|
||||||
|
impl std::fmt::Display for EventsLoopClosed {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", std::error::Error::description(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for EventsLoopClosed {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"Tried to wake up a closed `EventsLoop`"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use CreationError;
|
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
|
||||||
use CursorState;
|
|
||||||
use MouseCursor;
|
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
use self::x11::XConnection;
|
use self::x11::XConnection;
|
||||||
|
@ -131,9 +129,10 @@ impl MonitorId {
|
||||||
|
|
||||||
impl Window2 {
|
impl Window2 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
|
pub fn new(events_loop: &EventsLoop,
|
||||||
|
window: &::WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||||
-> Result<Window2, CreationError>
|
-> Result<Self, CreationError>
|
||||||
{
|
{
|
||||||
match *UNIX_BACKEND {
|
match *UNIX_BACKEND {
|
||||||
UnixBackend::Wayland(ref ctxt) => {
|
UnixBackend::Wayland(ref ctxt) => {
|
||||||
|
@ -309,6 +308,11 @@ pub enum EventsLoop {
|
||||||
X(x11::EventsLoop)
|
X(x11::EventsLoop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum EventsLoopProxy {
|
||||||
|
X(x11::EventsLoopProxy),
|
||||||
|
Wayland(wayland::EventsLoopProxy),
|
||||||
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
pub fn new() -> EventsLoop {
|
pub fn new() -> EventsLoop {
|
||||||
match *UNIX_BACKEND {
|
match *UNIX_BACKEND {
|
||||||
|
@ -326,28 +330,37 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt(&self) {
|
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||||
match *self {
|
match *self {
|
||||||
EventsLoop::Wayland(ref evlp) => evlp.interrupt(),
|
EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()),
|
||||||
EventsLoop::X(ref evlp) => evlp.interrupt()
|
EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events<F>(&self, callback: F)
|
pub fn poll_events<F>(&mut self, callback: F)
|
||||||
where F: FnMut(::Event)
|
where F: FnMut(::Event)
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
EventsLoop::Wayland(ref evlp) => evlp.poll_events(callback),
|
EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback),
|
||||||
EventsLoop::X(ref evlp) => evlp.poll_events(callback)
|
EventsLoop::X(ref mut evlp) => evlp.poll_events(callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&self, callback: F)
|
pub fn run_forever<F>(&mut self, callback: F)
|
||||||
where F: FnMut(::Event)
|
where F: FnMut(::Event) -> ControlFlow
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
EventsLoop::Wayland(ref evlp) => evlp.run_forever(callback),
|
EventsLoop::Wayland(ref mut evlp) => evlp.run_forever(callback),
|
||||||
EventsLoop::X(ref evlp) => evlp.run_forever(callback)
|
EventsLoop::X(ref mut evlp) => evlp.run_forever(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventsLoopProxy {
|
||||||
|
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
||||||
|
match *self {
|
||||||
|
EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(),
|
||||||
|
EventsLoopProxy::X(ref proxy) => proxy.wakeup(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState, KeyboardInput};
|
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState,
|
||||||
|
KeyboardInput, EventsLoopClosed, ControlFlow};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::{self, AtomicBool};
|
||||||
|
|
||||||
use super::{DecoratedHandler, WindowId, DeviceId, WaylandContext};
|
use super::{DecoratedHandler, WindowId, DeviceId, WaylandContext};
|
||||||
|
|
||||||
|
@ -53,7 +54,9 @@ impl EventsLoopSink {
|
||||||
::std::mem::replace(&mut self.callback, cb)
|
::std::mem::replace(&mut self.callback, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_callback<F: FnOnce(&mut FnMut(::Event))>(&mut self, f: F) {
|
fn with_callback<F>(&mut self, f: F)
|
||||||
|
where F: FnOnce(&mut FnMut(::Event)),
|
||||||
|
{
|
||||||
f(&mut *self.callback)
|
f(&mut *self.callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,11 +70,40 @@ pub struct EventsLoop {
|
||||||
decorated_ids: Mutex<Vec<(usize, Arc<wl_surface::WlSurface>)>>,
|
decorated_ids: Mutex<Vec<(usize, Arc<wl_surface::WlSurface>)>>,
|
||||||
// our sink, receiver of callbacks, shared with some handlers
|
// our sink, receiver of callbacks, shared with some handlers
|
||||||
sink: Arc<Mutex<EventsLoopSink>>,
|
sink: Arc<Mutex<EventsLoopSink>>,
|
||||||
// trigger interruption of the run
|
|
||||||
interrupted: AtomicBool,
|
|
||||||
// trigger cleanup of the dead surfaces
|
// trigger cleanup of the dead surfaces
|
||||||
cleanup_needed: Arc<AtomicBool>,
|
cleanup_needed: Arc<AtomicBool>,
|
||||||
hid: usize
|
// Whether or not there is a pending `Awakened` event to be emitted.
|
||||||
|
pending_wakeup: Arc<AtomicBool>,
|
||||||
|
hid: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// A handle that can be sent across threads and used to wake up the `EventsLoop`.
|
||||||
|
//
|
||||||
|
// We should only try and wake up the `EventsLoop` if it still exists, so we hold Weak ptrs.
|
||||||
|
pub struct EventsLoopProxy {
|
||||||
|
ctxt: Weak<WaylandContext>,
|
||||||
|
pending_wakeup: Weak<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventsLoopProxy {
|
||||||
|
// Causes the `EventsLoop` to stop blocking on `run_forever` and emit an `Awakened` event.
|
||||||
|
//
|
||||||
|
// Returns `Err` if the associated `EventsLoop` no longer exists.
|
||||||
|
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
||||||
|
let ctxt = self.ctxt.upgrade();
|
||||||
|
let wakeup = self.pending_wakeup.upgrade();
|
||||||
|
match (ctxt, wakeup) {
|
||||||
|
(Some(ctxt), Some(wakeup)) => {
|
||||||
|
// Update the `EventsLoop`'s `pending_wakeup` flag.
|
||||||
|
wakeup.store(true, atomic::Ordering::Relaxed);
|
||||||
|
// Cause the `EventsLoop` to break from `dispatch` if it is currently blocked.
|
||||||
|
ctxt.display.sync();
|
||||||
|
ctxt.display.flush().ok();
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
_ => Err(EventsLoopClosed),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
|
@ -84,12 +116,19 @@ impl EventsLoop {
|
||||||
evq: Arc::new(Mutex::new(evq)),
|
evq: Arc::new(Mutex::new(evq)),
|
||||||
decorated_ids: Mutex::new(Vec::new()),
|
decorated_ids: Mutex::new(Vec::new()),
|
||||||
sink: sink,
|
sink: sink,
|
||||||
interrupted: AtomicBool::new(false),
|
pending_wakeup: Arc::new(AtomicBool::new(false)),
|
||||||
cleanup_needed: Arc::new(AtomicBool::new(false)),
|
cleanup_needed: Arc::new(AtomicBool::new(false)),
|
||||||
hid: hid
|
hid: hid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||||
|
EventsLoopProxy {
|
||||||
|
ctxt: Arc::downgrade(&self.ctxt),
|
||||||
|
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// some internals that Window needs access to
|
// some internals that Window needs access to
|
||||||
pub fn get_window_init(&self) -> (Arc<Mutex<EventQueue>>, Arc<AtomicBool>) {
|
pub fn get_window_init(&self) -> (Arc<Mutex<EventQueue>>, Arc<AtomicBool>) {
|
||||||
(self.evq.clone(), self.cleanup_needed.clone())
|
(self.evq.clone(), self.cleanup_needed.clone())
|
||||||
|
@ -119,10 +158,6 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt(&self) {
|
|
||||||
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prune_dead_windows(&self) {
|
fn prune_dead_windows(&self) {
|
||||||
self.decorated_ids.lock().unwrap().retain(|&(_, ref w)| w.is_alive());
|
self.decorated_ids.lock().unwrap().retain(|&(_, ref w)| w.is_alive());
|
||||||
let mut evq_guard = self.evq.lock().unwrap();
|
let mut evq_guard = self.evq.lock().unwrap();
|
||||||
|
@ -136,7 +171,7 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events<F>(&self, callback: F)
|
pub fn poll_events<F>(&mut self, callback: F)
|
||||||
where F: FnMut(::Event)
|
where F: FnMut(::Event)
|
||||||
{
|
{
|
||||||
// send pending requests to the server...
|
// send pending requests to the server...
|
||||||
|
@ -160,6 +195,8 @@ impl EventsLoop {
|
||||||
self.ctxt.dispatch_pending();
|
self.ctxt.dispatch_pending();
|
||||||
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
||||||
|
|
||||||
|
self.emit_pending_wakeup();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut sink_guard = self.sink.lock().unwrap();
|
let mut sink_guard = self.sink.lock().unwrap();
|
||||||
|
|
||||||
|
@ -173,45 +210,63 @@ impl EventsLoop {
|
||||||
unsafe { sink_guard.set_callback(old_cb) };
|
unsafe { sink_guard.set_callback(old_cb) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) {
|
if self.cleanup_needed.swap(false, atomic::Ordering::Relaxed) {
|
||||||
self.prune_dead_windows()
|
self.prune_dead_windows()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&self, callback: F)
|
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(::Event)
|
where F: FnMut(::Event) -> ControlFlow,
|
||||||
{
|
{
|
||||||
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
// send pending requests to the server...
|
// send pending requests to the server...
|
||||||
self.ctxt.flush();
|
self.ctxt.flush();
|
||||||
|
|
||||||
// first of all, get exclusive access to this event queue
|
// first of all, get exclusive access to this event queue
|
||||||
let mut evq_guard = self.evq.lock().unwrap();
|
let mut evq_guard = self.evq.lock().unwrap();
|
||||||
|
|
||||||
|
// Check for control flow by wrapping the callback.
|
||||||
|
let control_flow = ::std::cell::Cell::new(ControlFlow::Continue);
|
||||||
|
let callback = |event| if let ControlFlow::Break = callback(event) {
|
||||||
|
control_flow.set(ControlFlow::Break);
|
||||||
|
};
|
||||||
|
|
||||||
// set the callback into the sink
|
// set the callback into the sink
|
||||||
// we extend the lifetime of the closure to 'static to be able to put it in
|
// we extend the lifetime of the closure to 'static to be able to put it in
|
||||||
// the sink, but we'll explicitly drop it at the end of this function, so it's fine
|
// the sink, but we'll explicitly drop it at the end of this function, so it's fine
|
||||||
let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box<FnMut(_)>) };
|
let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box<FnMut(_)>) };
|
||||||
let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) };
|
let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) };
|
||||||
|
|
||||||
while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
|
loop {
|
||||||
self.ctxt.dispatch();
|
self.ctxt.dispatch();
|
||||||
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
||||||
|
|
||||||
|
self.emit_pending_wakeup();
|
||||||
|
|
||||||
let ids_guard = self.decorated_ids.lock().unwrap();
|
let ids_guard = self.decorated_ids.lock().unwrap();
|
||||||
self.sink.lock().unwrap().with_callback(
|
self.sink.lock().unwrap()
|
||||||
|cb| Self::process_resize(&mut evq_guard, &ids_guard, cb)
|
.with_callback(|cb| Self::process_resize(&mut evq_guard, &ids_guard, cb));
|
||||||
);
|
|
||||||
self.ctxt.flush();
|
self.ctxt.flush();
|
||||||
|
|
||||||
if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) {
|
if self.cleanup_needed.swap(false, atomic::Ordering::Relaxed) {
|
||||||
self.prune_dead_windows()
|
self.prune_dead_windows()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let ControlFlow::Break = control_flow.get() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace the old noop callback
|
// replace the old noop callback
|
||||||
unsafe { self.sink.lock().unwrap().set_callback(old_cb) };
|
unsafe { self.sink.lock().unwrap().set_callback(old_cb) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If an `EventsLoopProxy` has signalled a wakeup, emit an event and reset the flag.
|
||||||
|
fn emit_pending_wakeup(&self) {
|
||||||
|
if self.pending_wakeup.load(atomic::Ordering::Relaxed) {
|
||||||
|
self.sink.lock().unwrap().with_callback(|cb| cb(::Event::Awakened));
|
||||||
|
self.pending_wakeup.store(false, atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum KbdType {
|
enum KbdType {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![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, WindowId};
|
pub use self::window::{Window, WindowId};
|
||||||
pub use self::event_loop::EventsLoop;
|
pub use self::event_loop::{EventsLoop, EventsLoopProxy};
|
||||||
pub use self::context::{WaylandContext, MonitorId, get_available_monitors,
|
pub use self::context::{WaylandContext, MonitorId, get_available_monitors,
|
||||||
get_primary_monitor};
|
get_primary_monitor};
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,12 @@ pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
|
|
||||||
use platform::PlatformSpecificWindowBuilderAttributes;
|
use platform::PlatformSpecificWindowBuilderAttributes;
|
||||||
use {CreationError, Event, WindowEvent, DeviceEvent, AxisId, ButtonId, KeyboardInput};
|
use {CreationError, Event, EventsLoopClosed, WindowEvent, DeviceEvent, AxisId, ButtonId,
|
||||||
|
KeyboardInput, ControlFlow};
|
||||||
|
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
|
use std::sync::atomic::{self, AtomicBool};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
|
@ -29,13 +31,22 @@ mod xdisplay;
|
||||||
// the one generated by the macro.
|
// the one generated by the macro.
|
||||||
|
|
||||||
pub struct EventsLoop {
|
pub struct EventsLoop {
|
||||||
interrupted: ::std::sync::atomic::AtomicBool,
|
|
||||||
display: Arc<XConnection>,
|
display: Arc<XConnection>,
|
||||||
wm_delete_window: ffi::Atom,
|
wm_delete_window: ffi::Atom,
|
||||||
windows: Mutex<HashMap<WindowId, WindowData>>,
|
windows: Arc<Mutex<HashMap<WindowId, WindowData>>>,
|
||||||
devices: Mutex<HashMap<DeviceId, Device>>,
|
devices: Mutex<HashMap<DeviceId, Device>>,
|
||||||
xi2ext: XExtension,
|
xi2ext: XExtension,
|
||||||
|
pending_wakeup: Arc<AtomicBool>,
|
||||||
root: ffi::Window,
|
root: ffi::Window,
|
||||||
|
// A dummy, `InputOnly` window that we can use to receive wakeup events and interrupt blocking
|
||||||
|
// `XNextEvent` calls.
|
||||||
|
wakeup_dummy_window: ffi::Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventsLoopProxy {
|
||||||
|
pending_wakeup: Weak<AtomicBool>,
|
||||||
|
display: Weak<XConnection>,
|
||||||
|
wakeup_dummy_window: ffi::Window,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
|
@ -72,14 +83,22 @@ impl EventsLoop {
|
||||||
|
|
||||||
let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
|
let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
|
||||||
|
|
||||||
|
let wakeup_dummy_window = unsafe {
|
||||||
|
let (x, y, w, h) = (10, 10, 10, 10);
|
||||||
|
let (border_w, border_px, background_px) = (0, 0, 0);
|
||||||
|
(display.xlib.XCreateSimpleWindow)(display.display, root, x, y, w, h,
|
||||||
|
border_w, border_px, background_px)
|
||||||
|
};
|
||||||
|
|
||||||
let result = EventsLoop {
|
let result = EventsLoop {
|
||||||
interrupted: ::std::sync::atomic::AtomicBool::new(false),
|
pending_wakeup: Arc::new(AtomicBool::new(false)),
|
||||||
display: display,
|
display: display,
|
||||||
wm_delete_window: wm_delete_window,
|
wm_delete_window: wm_delete_window,
|
||||||
windows: Mutex::new(HashMap::new()),
|
windows: Arc::new(Mutex::new(HashMap::new())),
|
||||||
devices: Mutex::new(HashMap::new()),
|
devices: Mutex::new(HashMap::new()),
|
||||||
xi2ext: xi2ext,
|
xi2ext: xi2ext,
|
||||||
root: root,
|
root: root,
|
||||||
|
wakeup_dummy_window: wakeup_dummy_window,
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -101,32 +120,17 @@ impl EventsLoop {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt(&self) {
|
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||||
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
|
EventsLoopProxy {
|
||||||
|
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
|
||||||
// Push an event on the X event queue so that methods like run_forever will advance.
|
display: Arc::downgrade(&self.display),
|
||||||
let mut xev = ffi::XClientMessageEvent {
|
wakeup_dummy_window: self.wakeup_dummy_window,
|
||||||
type_: ffi::ClientMessage,
|
|
||||||
window: self.root,
|
|
||||||
format: 32,
|
|
||||||
message_type: 0,
|
|
||||||
serial: 0,
|
|
||||||
send_event: 0,
|
|
||||||
display: self.display.display,
|
|
||||||
data: unsafe { mem::zeroed() },
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
(self.display.xlib.XSendEvent)(self.display.display, self.root, 0, 0, mem::transmute(&mut xev));
|
|
||||||
(self.display.xlib.XFlush)(self.display.display);
|
|
||||||
self.display.check_errors().expect("Failed to call XSendEvent after wakeup");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events<F>(&self, mut callback: F)
|
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event)
|
||||||
{
|
{
|
||||||
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
|
||||||
let xlib = &self.display.xlib;
|
let xlib = &self.display.xlib;
|
||||||
|
|
||||||
let mut xev = unsafe { mem::uninitialized() };
|
let mut xev = unsafe { mem::uninitialized() };
|
||||||
|
@ -142,16 +146,13 @@ impl EventsLoop {
|
||||||
(xlib.XNextEvent)(self.display.display, &mut xev);
|
(xlib.XNextEvent)(self.display.display, &mut xev);
|
||||||
}
|
}
|
||||||
self.process_event(&mut xev, &mut callback);
|
self.process_event(&mut xev, &mut callback);
|
||||||
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&self, mut callback: F)
|
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event) -> ControlFlow
|
||||||
{
|
{
|
||||||
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
self.pending_wakeup.store(false, atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
let xlib = &self.display.xlib;
|
let xlib = &self.display.xlib;
|
||||||
|
|
||||||
|
@ -159,8 +160,21 @@ impl EventsLoop {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { (xlib.XNextEvent)(self.display.display, &mut xev) }; // Blocks as necessary
|
unsafe { (xlib.XNextEvent)(self.display.display, &mut xev) }; // Blocks as necessary
|
||||||
self.process_event(&mut xev, &mut callback);
|
|
||||||
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
|
let mut control_flow = ControlFlow::Continue;
|
||||||
|
|
||||||
|
// Track whether or not `Break` was returned when processing the event.
|
||||||
|
{
|
||||||
|
let mut cb = |event| {
|
||||||
|
if let ControlFlow::Break = callback(event) {
|
||||||
|
control_flow = ControlFlow::Break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.process_event(&mut xev, &mut cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ControlFlow::Break = control_flow {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +186,7 @@ impl EventsLoop {
|
||||||
device.name.clone()
|
device.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event<F>(&self, xev: &mut ffi::XEvent, callback: &mut F)
|
fn process_event<F>(&self, xev: &mut ffi::XEvent, mut callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event)
|
||||||
{
|
{
|
||||||
let xlib = &self.display.xlib;
|
let xlib = &self.display.xlib;
|
||||||
|
@ -196,8 +210,10 @@ impl EventsLoop {
|
||||||
if client_msg.data.get_long(0) as ffi::Atom == self.wm_delete_window {
|
if client_msg.data.get_long(0) as ffi::Atom == self.wm_delete_window {
|
||||||
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Closed })
|
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Closed })
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Prone to spurious wakeups
|
if self.pending_wakeup.load(atomic::Ordering::Relaxed) {
|
||||||
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Awakened })
|
self.pending_wakeup.store(false, atomic::Ordering::Relaxed);
|
||||||
|
callback(Event::Awakened);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +322,11 @@ impl EventsLoop {
|
||||||
};
|
};
|
||||||
|
|
||||||
for chr in written.chars() {
|
for chr in written.chars() {
|
||||||
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::ReceivedCharacter(chr) })
|
let event = Event::WindowEvent {
|
||||||
|
window_id: wid,
|
||||||
|
event: WindowEvent::ReceivedCharacter(chr),
|
||||||
|
};
|
||||||
|
callback(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,6 +543,46 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EventsLoopProxy {
|
||||||
|
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
||||||
|
// Update the `EventsLoop`'s `pending_wakeup` flag.
|
||||||
|
let display = match (self.pending_wakeup.upgrade(), self.display.upgrade()) {
|
||||||
|
(Some(wakeup), Some(display)) => {
|
||||||
|
wakeup.store(true, atomic::Ordering::Relaxed);
|
||||||
|
display
|
||||||
|
},
|
||||||
|
_ => return Err(EventsLoopClosed),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Push an event on the X event queue so that methods run_forever will advance.
|
||||||
|
//
|
||||||
|
// NOTE: This code (and the following `XSendEvent` code) is taken from the old
|
||||||
|
// `WindowProxy::wakeup` implementation. The code assumes that X11 is thread safe. Is this
|
||||||
|
// true?
|
||||||
|
let mut xev = ffi::XClientMessageEvent {
|
||||||
|
type_: ffi::ClientMessage,
|
||||||
|
window: self.wakeup_dummy_window,
|
||||||
|
format: 32,
|
||||||
|
message_type: 0,
|
||||||
|
serial: 0,
|
||||||
|
send_event: 0,
|
||||||
|
display: display.display,
|
||||||
|
data: unsafe { mem::zeroed() },
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let propagate = false as i32;
|
||||||
|
let event_mask = 0;
|
||||||
|
let xevent = &mut xev as *mut ffi::XClientMessageEvent as *mut ffi::XEvent;
|
||||||
|
(display.xlib.XSendEvent)(display.display, self.wakeup_dummy_window, propagate, event_mask, xevent);
|
||||||
|
(display.xlib.XFlush)(display.display);
|
||||||
|
display.check_errors().expect("Failed to call XSendEvent after wakeup");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct DeviceInfo<'a> {
|
struct DeviceInfo<'a> {
|
||||||
display: &'a XConnection,
|
display: &'a XConnection,
|
||||||
info: *const ffi::XIDeviceInfo,
|
info: *const ffi::XIDeviceInfo,
|
||||||
|
@ -564,7 +624,8 @@ pub struct DeviceId(c_int);
|
||||||
|
|
||||||
pub struct Window2 {
|
pub struct Window2 {
|
||||||
pub window: Arc<Window>,
|
pub window: Arc<Window>,
|
||||||
events_loop: Weak<::platform::EventsLoop>,
|
display: Weak<XConnection>,
|
||||||
|
windows: Weak<Mutex<HashMap<WindowId, WindowData>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::Deref for Window2 {
|
impl ::std::ops::Deref for Window2 {
|
||||||
|
@ -581,9 +642,10 @@ lazy_static! { // TODO: use a static mutex when that's possible, and put me
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window2 {
|
impl Window2 {
|
||||||
pub fn new(events_loop: Arc<::platform::EventsLoop>,
|
pub fn new(events_loop: &::platform::EventsLoop,
|
||||||
window: &::WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
window: &::WindowAttributes,
|
||||||
-> Result<Window2, CreationError>
|
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||||
|
-> Result<Self, CreationError>
|
||||||
{
|
{
|
||||||
let x_events_loop = if let ::platform::EventsLoop::X(ref e) = *events_loop { e } else { unreachable!() };
|
let x_events_loop = if let ::platform::EventsLoop::X(ref e) = *events_loop { e } else { unreachable!() };
|
||||||
let win = ::std::sync::Arc::new(try!(Window::new(&x_events_loop, window, pl_attribs)));
|
let win = ::std::sync::Arc::new(try!(Window::new(&x_events_loop, window, pl_attribs)));
|
||||||
|
@ -623,7 +685,8 @@ impl Window2 {
|
||||||
|
|
||||||
Ok(Window2 {
|
Ok(Window2 {
|
||||||
window: win,
|
window: win,
|
||||||
events_loop: Arc::downgrade(&events_loop),
|
windows: Arc::downgrade(&x_events_loop.windows),
|
||||||
|
display: Arc::downgrade(&x_events_loop.display),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,17 +698,13 @@ impl Window2 {
|
||||||
|
|
||||||
impl Drop for Window2 {
|
impl Drop for Window2 {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(ev) = self.events_loop.upgrade() {
|
if let (Some(windows), Some(display)) = (self.windows.upgrade(), self.display.upgrade()) {
|
||||||
if let ::platform::EventsLoop::X(ref ev) = *ev {
|
let mut windows = windows.lock().unwrap();
|
||||||
let mut windows = ev.windows.lock().unwrap();
|
let w = windows.remove(&self.window.id()).unwrap();
|
||||||
|
let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap();
|
||||||
|
unsafe {
|
||||||
let w = windows.remove(&self.window.id()).unwrap();
|
(display.xlib.XDestroyIC)(w.ic);
|
||||||
let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap();
|
(display.xlib.XCloseIM)(w.im);
|
||||||
unsafe {
|
|
||||||
(ev.display.xlib.XDestroyIC)(w.ic);
|
|
||||||
(ev.display.xlib.XCloseIM)(w.im);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,8 +166,7 @@ impl Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
// getting the root window
|
// getting the root window
|
||||||
let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
|
let root = ctx.root;
|
||||||
display.check_errors().expect("Failed to get root window");
|
|
||||||
|
|
||||||
// creating
|
// creating
|
||||||
let mut set_win_attr = {
|
let mut set_win_attr = {
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
|
use {ControlFlow, EventsLoopClosed};
|
||||||
use cocoa::{self, appkit, foundation};
|
use cocoa::{self, appkit, foundation};
|
||||||
use cocoa::appkit::{NSApplication, NSEvent, NSView, NSWindow};
|
use cocoa::appkit::{NSApplication, NSEvent, NSView, NSWindow};
|
||||||
use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent, ModifiersState, KeyboardInput};
|
use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent, ModifiersState, KeyboardInput};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
use super::window::Window;
|
use super::window::Window;
|
||||||
use std;
|
use std;
|
||||||
use super::DeviceId;
|
use super::DeviceId;
|
||||||
|
|
||||||
|
|
||||||
pub struct EventsLoop {
|
pub struct EventsLoop {
|
||||||
pub windows: std::sync::Mutex<Vec<std::sync::Weak<Window>>>,
|
modifiers: Modifiers,
|
||||||
pub pending_events: std::sync::Mutex<std::collections::VecDeque<Event>>,
|
pub shared: Arc<Shared>,
|
||||||
modifiers: std::sync::Mutex<Modifiers>,
|
}
|
||||||
interrupted: std::sync::atomic::AtomicBool,
|
|
||||||
|
|
||||||
|
// State shared between the `EventsLoop` and its registered windows.
|
||||||
|
pub struct Shared {
|
||||||
|
pub windows: Mutex<Vec<Weak<Window>>>,
|
||||||
|
pub pending_events: Mutex<VecDeque<Event>>,
|
||||||
// The user event callback given via either of the `poll_events` or `run_forever` methods.
|
// The user event callback given via either of the `poll_events` or `run_forever` methods.
|
||||||
//
|
//
|
||||||
// We store the user's callback here so that it may be accessed by each of the window delegate
|
// We store the user's callback here so that it may be accessed by each of the window delegate
|
||||||
|
@ -23,6 +29,8 @@ pub struct EventsLoop {
|
||||||
user_callback: UserCallback,
|
user_callback: UserCallback,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Proxy {}
|
||||||
|
|
||||||
struct Modifiers {
|
struct Modifiers {
|
||||||
shift_pressed: bool,
|
shift_pressed: bool,
|
||||||
ctrl_pressed: bool,
|
ctrl_pressed: bool,
|
||||||
|
@ -34,14 +42,76 @@ struct Modifiers {
|
||||||
//
|
//
|
||||||
// - ensure the callback pointer is never accidentally cloned
|
// - ensure the callback pointer is never accidentally cloned
|
||||||
// - ensure that only the `EventsLoop` can `store` and `drop` the callback pointer
|
// - ensure that only the `EventsLoop` can `store` and `drop` the callback pointer
|
||||||
// - `unsafe impl Send` and `Sync` so that `Send` and `Sync` can be implemented for `EventsLoop`.
|
// - Share access to the user callback with the NSWindow callbacks.
|
||||||
pub struct UserCallback {
|
pub struct UserCallback {
|
||||||
mutex: std::sync::Mutex<Option<*mut FnMut(Event)>>,
|
mutex: Mutex<Option<*mut FnMut(Event)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsafe impl Send for UserCallback {}
|
impl Shared {
|
||||||
unsafe impl Sync for UserCallback {}
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Shared {
|
||||||
|
windows: Mutex::new(Vec::new()),
|
||||||
|
pending_events: Mutex::new(VecDeque::new()),
|
||||||
|
user_callback: UserCallback { mutex: Mutex::new(None) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_user_callback_with_pending_events(&self) {
|
||||||
|
loop {
|
||||||
|
let event = match self.pending_events.lock().unwrap().pop_front() {
|
||||||
|
Some(event) => event,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
self.user_callback.call_with_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls the user callback if one exists.
|
||||||
|
//
|
||||||
|
// Otherwise, stores the event in the `pending_events` queue.
|
||||||
|
//
|
||||||
|
// This is necessary for the case when `WindowDelegate` callbacks are triggered during a call
|
||||||
|
// to the user's callback.
|
||||||
|
pub fn call_user_callback_with_event_or_store_in_pending(&self, event: Event) {
|
||||||
|
if self.user_callback.mutex.lock().unwrap().is_some() {
|
||||||
|
unsafe {
|
||||||
|
self.user_callback.call_with_event(event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.pending_events.lock().unwrap().push_back(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the window with the given `Id` from the `windows` list.
|
||||||
|
//
|
||||||
|
// This is called when a window is either `Closed` or `Drop`ped.
|
||||||
|
pub fn find_and_remove_window(&self, id: super::window::Id) {
|
||||||
|
if let Ok(mut windows) = self.windows.lock() {
|
||||||
|
windows.retain(|w| match w.upgrade() {
|
||||||
|
Some(w) => w.id() != id,
|
||||||
|
None => true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Modifiers {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Modifiers {
|
||||||
|
shift_pressed: false,
|
||||||
|
ctrl_pressed: false,
|
||||||
|
win_pressed: false,
|
||||||
|
alt_pressed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl UserCallback {
|
impl UserCallback {
|
||||||
|
|
||||||
|
@ -92,22 +162,13 @@ impl UserCallback {
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let modifiers = Modifiers {
|
|
||||||
shift_pressed: false,
|
|
||||||
ctrl_pressed: false,
|
|
||||||
win_pressed: false,
|
|
||||||
alt_pressed: false,
|
|
||||||
};
|
|
||||||
EventsLoop {
|
EventsLoop {
|
||||||
windows: std::sync::Mutex::new(Vec::new()),
|
shared: Arc::new(Shared::new()),
|
||||||
pending_events: std::sync::Mutex::new(std::collections::VecDeque::new()),
|
modifiers: Modifiers::new(),
|
||||||
modifiers: std::sync::Mutex::new(modifiers),
|
|
||||||
interrupted: std::sync::atomic::AtomicBool::new(false),
|
|
||||||
user_callback: UserCallback { mutex: std::sync::Mutex::new(None) },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events<F>(&self, mut callback: F)
|
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(Event),
|
where F: FnMut(Event),
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -116,13 +177,13 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.user_callback.store(&mut callback);
|
self.shared.user_callback.store(&mut callback);
|
||||||
|
|
||||||
// Loop as long as we have pending events to return.
|
// Loop as long as we have pending events to return.
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
unsafe {
|
||||||
// First, yield all pending events.
|
// First, yield all pending events.
|
||||||
self.call_user_callback_with_pending_events();
|
self.shared.call_user_callback_with_pending_events();
|
||||||
|
|
||||||
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
|
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
|
||||||
|
|
||||||
|
@ -139,32 +200,42 @@ impl EventsLoop {
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
// Call the user's callback.
|
// Call the user's callback.
|
||||||
Some(event) => self.user_callback.call_with_event(event),
|
Some(event) => self.shared.user_callback.call_with_event(event),
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.user_callback.drop();
|
self.shared.user_callback.drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&self, mut callback: F)
|
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event) -> ControlFlow
|
||||||
{
|
{
|
||||||
self.interrupted.store(false, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if !msg_send![cocoa::base::class("NSThread"), isMainThread] {
|
if !msg_send![cocoa::base::class("NSThread"), isMainThread] {
|
||||||
panic!("Events can only be polled from the main thread on macOS");
|
panic!("Events can only be polled from the main thread on macOS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.user_callback.store(&mut callback);
|
// Track whether or not control flow has changed.
|
||||||
|
let control_flow = std::cell::Cell::new(ControlFlow::Continue);
|
||||||
|
|
||||||
|
let mut callback = |event| {
|
||||||
|
if let ControlFlow::Break = callback(event) {
|
||||||
|
control_flow.set(ControlFlow::Break);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.shared.user_callback.store(&mut callback);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
unsafe {
|
||||||
// First, yield all pending events.
|
// First, yield all pending events.
|
||||||
self.call_user_callback_with_pending_events();
|
self.shared.call_user_callback_with_pending_events();
|
||||||
|
if let ControlFlow::Break = control_flow.get() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
|
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
|
||||||
|
|
||||||
|
@ -182,84 +253,19 @@ impl EventsLoop {
|
||||||
let _: () = msg_send![pool, release];
|
let _: () = msg_send![pool, release];
|
||||||
|
|
||||||
if let Some(event) = maybe_event {
|
if let Some(event) = maybe_event {
|
||||||
self.user_callback.call_with_event(event);
|
self.shared.user_callback.call_with_event(event);
|
||||||
|
if let ControlFlow::Break = control_flow.get() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.interrupted.load(std::sync::atomic::Ordering::Relaxed) {
|
|
||||||
self.interrupted.store(false, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.user_callback.drop();
|
self.shared.user_callback.drop();
|
||||||
}
|
|
||||||
|
|
||||||
pub fn interrupt(&self) {
|
|
||||||
self.interrupted.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
// Awaken the event loop by triggering `NSApplicationActivatedEventType`.
|
|
||||||
unsafe {
|
|
||||||
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
|
|
||||||
let event =
|
|
||||||
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
|
|
||||||
cocoa::base::nil,
|
|
||||||
appkit::NSApplicationDefined,
|
|
||||||
foundation::NSPoint::new(0.0, 0.0),
|
|
||||||
appkit::NSEventModifierFlags::empty(),
|
|
||||||
0.0,
|
|
||||||
0,
|
|
||||||
cocoa::base::nil,
|
|
||||||
appkit::NSEventSubtype::NSApplicationActivatedEventType,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
appkit::NSApp().postEvent_atStart_(event, cocoa::base::NO);
|
|
||||||
foundation::NSAutoreleasePool::drain(pool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes the window with the given `Id` from the `windows` list.
|
|
||||||
//
|
|
||||||
// This is called when a window is either `Closed` or `Drop`ped.
|
|
||||||
pub fn find_and_remove_window(&self, id: super::window::Id) {
|
|
||||||
if let Ok(mut windows) = self.windows.lock() {
|
|
||||||
windows.retain(|w| match w.upgrade() {
|
|
||||||
Some(w) => w.id() != id,
|
|
||||||
None => true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_user_callback_with_pending_events(&self) {
|
|
||||||
loop {
|
|
||||||
let event = match self.pending_events.lock().unwrap().pop_front() {
|
|
||||||
Some(event) => event,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
unsafe {
|
|
||||||
self.user_callback.call_with_event(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calls the user callback if one exists.
|
|
||||||
//
|
|
||||||
// Otherwise, stores the event in the `pending_events` queue.
|
|
||||||
//
|
|
||||||
// This is necessary for the case when `WindowDelegate` callbacks are triggered during a call
|
|
||||||
// to the user's callback.
|
|
||||||
pub fn call_user_callback_with_event_or_store_in_pending(&self, event: Event) {
|
|
||||||
if self.user_callback.mutex.lock().unwrap().is_some() {
|
|
||||||
unsafe {
|
|
||||||
self.user_callback.call_with_event(event);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.pending_events.lock().unwrap().push_back(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert some given `NSEvent` into a winit `Event`.
|
// Convert some given `NSEvent` into a winit `Event`.
|
||||||
unsafe fn ns_event_to_event(&self, ns_event: cocoa::base::id) -> Option<Event> {
|
unsafe fn ns_event_to_event(&mut self, ns_event: cocoa::base::id) -> Option<Event> {
|
||||||
if ns_event == cocoa::base::nil {
|
if ns_event == cocoa::base::nil {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -285,9 +291,9 @@ impl EventsLoop {
|
||||||
_ => appkit::NSApp().sendEvent_(ns_event),
|
_ => appkit::NSApp().sendEvent_(ns_event),
|
||||||
}
|
}
|
||||||
|
|
||||||
let windows = self.windows.lock().unwrap();
|
let windows = self.shared.windows.lock().unwrap();
|
||||||
let maybe_window = windows.iter()
|
let maybe_window = windows.iter()
|
||||||
.filter_map(std::sync::Weak::upgrade)
|
.filter_map(Weak::upgrade)
|
||||||
.find(|window| window_id == window.id());
|
.find(|window| window_id == window.id());
|
||||||
|
|
||||||
let into_event = |window_event| Event::WindowEvent {
|
let into_event = |window_event| Event::WindowEvent {
|
||||||
|
@ -297,7 +303,7 @@ impl EventsLoop {
|
||||||
|
|
||||||
// Returns `Some` window if one of our windows is the key window.
|
// Returns `Some` window if one of our windows is the key window.
|
||||||
let maybe_key_window = || windows.iter()
|
let maybe_key_window = || windows.iter()
|
||||||
.filter_map(std::sync::Weak::upgrade)
|
.filter_map(Weak::upgrade)
|
||||||
.find(|window| {
|
.find(|window| {
|
||||||
let is_key_window: cocoa::base::BOOL = msg_send![*window.window, isKeyWindow];
|
let is_key_window: cocoa::base::BOOL = msg_send![*window.window, isKeyWindow];
|
||||||
is_key_window == cocoa::base::YES
|
is_key_window == cocoa::base::YES
|
||||||
|
@ -326,7 +332,7 @@ impl EventsLoop {
|
||||||
let window_event = WindowEvent::ReceivedCharacter(received_char);
|
let window_event = WindowEvent::ReceivedCharacter(received_char);
|
||||||
events.push_back(into_event(window_event));
|
events.push_back(into_event(window_event));
|
||||||
}
|
}
|
||||||
self.pending_events.lock().unwrap().extend(events.into_iter());
|
self.shared.pending_events.lock().unwrap().extend(events.into_iter());
|
||||||
Some(into_event(window_event))
|
Some(into_event(window_event))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -348,8 +354,6 @@ impl EventsLoop {
|
||||||
},
|
},
|
||||||
|
|
||||||
appkit::NSFlagsChanged => {
|
appkit::NSFlagsChanged => {
|
||||||
let mut modifiers = self.modifiers.lock().unwrap();
|
|
||||||
|
|
||||||
unsafe fn modifier_event(event: cocoa::base::id,
|
unsafe fn modifier_event(event: cocoa::base::id,
|
||||||
keymask: appkit::NSEventModifierFlags,
|
keymask: appkit::NSEventModifierFlags,
|
||||||
key: events::VirtualKeyCode,
|
key: events::VirtualKeyCode,
|
||||||
|
@ -392,41 +396,41 @@ impl EventsLoop {
|
||||||
if let Some(window_event) = modifier_event(ns_event,
|
if let Some(window_event) = modifier_event(ns_event,
|
||||||
appkit::NSShiftKeyMask,
|
appkit::NSShiftKeyMask,
|
||||||
events::VirtualKeyCode::LShift,
|
events::VirtualKeyCode::LShift,
|
||||||
modifiers.shift_pressed)
|
self.modifiers.shift_pressed)
|
||||||
{
|
{
|
||||||
modifiers.shift_pressed = !modifiers.shift_pressed;
|
self.modifiers.shift_pressed = !self.modifiers.shift_pressed;
|
||||||
events.push_back(into_event(window_event));
|
events.push_back(into_event(window_event));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(window_event) = modifier_event(ns_event,
|
if let Some(window_event) = modifier_event(ns_event,
|
||||||
appkit::NSControlKeyMask,
|
appkit::NSControlKeyMask,
|
||||||
events::VirtualKeyCode::LControl,
|
events::VirtualKeyCode::LControl,
|
||||||
modifiers.ctrl_pressed)
|
self.modifiers.ctrl_pressed)
|
||||||
{
|
{
|
||||||
modifiers.ctrl_pressed = !modifiers.ctrl_pressed;
|
self.modifiers.ctrl_pressed = !self.modifiers.ctrl_pressed;
|
||||||
events.push_back(into_event(window_event));
|
events.push_back(into_event(window_event));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(window_event) = modifier_event(ns_event,
|
if let Some(window_event) = modifier_event(ns_event,
|
||||||
appkit::NSCommandKeyMask,
|
appkit::NSCommandKeyMask,
|
||||||
events::VirtualKeyCode::LWin,
|
events::VirtualKeyCode::LWin,
|
||||||
modifiers.win_pressed)
|
self.modifiers.win_pressed)
|
||||||
{
|
{
|
||||||
modifiers.win_pressed = !modifiers.win_pressed;
|
self.modifiers.win_pressed = !self.modifiers.win_pressed;
|
||||||
events.push_back(into_event(window_event));
|
events.push_back(into_event(window_event));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(window_event) = modifier_event(ns_event,
|
if let Some(window_event) = modifier_event(ns_event,
|
||||||
appkit::NSAlternateKeyMask,
|
appkit::NSAlternateKeyMask,
|
||||||
events::VirtualKeyCode::LAlt,
|
events::VirtualKeyCode::LAlt,
|
||||||
modifiers.alt_pressed)
|
self.modifiers.alt_pressed)
|
||||||
{
|
{
|
||||||
modifiers.alt_pressed = !modifiers.alt_pressed;
|
self.modifiers.alt_pressed = !self.modifiers.alt_pressed;
|
||||||
events.push_back(into_event(window_event));
|
events.push_back(into_event(window_event));
|
||||||
}
|
}
|
||||||
|
|
||||||
let event = events.pop_front();
|
let event = events.pop_front();
|
||||||
self.pending_events.lock().unwrap().extend(events.into_iter());
|
self.shared.pending_events.lock().unwrap().extend(events.into_iter());
|
||||||
event
|
event
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -505,7 +509,7 @@ impl EventsLoop {
|
||||||
|
|
||||||
appkit::NSApplicationDefined => match ns_event.subtype() {
|
appkit::NSApplicationDefined => match ns_event.subtype() {
|
||||||
appkit::NSEventSubtype::NSApplicationActivatedEventType => {
|
appkit::NSEventSubtype::NSApplicationActivatedEventType => {
|
||||||
Some(into_event(WindowEvent::Awakened))
|
Some(Event::Awakened)
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
@ -514,6 +518,34 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_proxy(&self) -> Proxy {
|
||||||
|
Proxy {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Proxy {
|
||||||
|
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
||||||
|
// Awaken the event loop by triggering `NSApplicationActivatedEventType`.
|
||||||
|
unsafe {
|
||||||
|
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
|
||||||
|
let event =
|
||||||
|
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
|
||||||
|
cocoa::base::nil,
|
||||||
|
appkit::NSApplicationDefined,
|
||||||
|
foundation::NSPoint::new(0.0, 0.0),
|
||||||
|
appkit::NSEventModifierFlags::empty(),
|
||||||
|
0.0,
|
||||||
|
0,
|
||||||
|
cocoa::base::nil,
|
||||||
|
appkit::NSEventSubtype::NSApplicationActivatedEventType,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
appkit::NSApp().postEvent_atStart_(event, cocoa::base::NO);
|
||||||
|
foundation::NSAutoreleasePool::drain(pool);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#![cfg(target_os = "macos")]
|
#![cfg(target_os = "macos")]
|
||||||
|
|
||||||
pub use self::events_loop::EventsLoop;
|
pub use self::events_loop::{EventsLoop, Proxy as EventsLoopProxy};
|
||||||
pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor};
|
pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor};
|
||||||
pub use self::window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, Window};
|
pub use self::window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, Window};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct DeviceId;
|
pub struct DeviceId;
|
||||||
|
@ -10,7 +11,7 @@ pub struct DeviceId;
|
||||||
use {CreationError};
|
use {CreationError};
|
||||||
|
|
||||||
pub struct Window2 {
|
pub struct Window2 {
|
||||||
pub window: ::std::sync::Arc<Window>,
|
pub window: Arc<Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::Deref for Window2 {
|
impl ::std::ops::Deref for Window2 {
|
||||||
|
@ -23,14 +24,14 @@ impl ::std::ops::Deref for Window2 {
|
||||||
|
|
||||||
impl Window2 {
|
impl Window2 {
|
||||||
|
|
||||||
pub fn new(events_loop: ::std::sync::Arc<EventsLoop>,
|
pub fn new(events_loop: &EventsLoop,
|
||||||
attributes: &::WindowAttributes,
|
attributes: &::WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError>
|
pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError>
|
||||||
{
|
{
|
||||||
let weak_events_loop = ::std::sync::Arc::downgrade(&events_loop);
|
let weak_shared = Arc::downgrade(&events_loop.shared);
|
||||||
let window = ::std::sync::Arc::new(try!(Window::new(weak_events_loop, attributes, pl_attribs)));
|
let window = Arc::new(try!(Window::new(weak_shared, attributes, pl_attribs)));
|
||||||
let weak_window = ::std::sync::Arc::downgrade(&window);
|
let weak_window = Arc::downgrade(&window);
|
||||||
events_loop.windows.lock().unwrap().push(weak_window);
|
events_loop.shared.windows.lock().unwrap().push(weak_window);
|
||||||
Ok(Window2 { window: window })
|
Ok(Window2 { window: window })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use libc;
|
||||||
use WindowAttributes;
|
use WindowAttributes;
|
||||||
use native_monitor::NativeMonitorId;
|
use native_monitor::NativeMonitorId;
|
||||||
use os::macos::ActivationPolicy;
|
use os::macos::ActivationPolicy;
|
||||||
|
use os::macos::WindowExt;
|
||||||
|
|
||||||
use objc;
|
use objc;
|
||||||
use objc::runtime::{Class, Object, Sel, BOOL, YES, NO};
|
use objc::runtime::{Class, Object, Sel, BOOL, YES, NO};
|
||||||
|
@ -20,8 +21,9 @@ use core_graphics::display::{CGAssociateMouseAndMouseCursorPosition, CGMainDispl
|
||||||
use std;
|
use std;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
use std::sync::Weak;
|
||||||
|
|
||||||
use os::macos::WindowExt;
|
use super::events_loop::Shared;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -30,7 +32,7 @@ pub struct Id(pub usize);
|
||||||
struct DelegateState {
|
struct DelegateState {
|
||||||
view: IdRef,
|
view: IdRef,
|
||||||
window: IdRef,
|
window: IdRef,
|
||||||
events_loop: std::sync::Weak<super::EventsLoop>,
|
shared: Weak<Shared>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WindowDelegate {
|
pub struct WindowDelegate {
|
||||||
|
@ -51,8 +53,8 @@ impl WindowDelegate {
|
||||||
event: window_event,
|
event: window_event,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(events_loop) = state.events_loop.upgrade() {
|
if let Some(shared) = state.shared.upgrade() {
|
||||||
events_loop.call_user_callback_with_event_or_store_in_pending(event);
|
shared.call_user_callback_with_event_or_store_in_pending(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +73,10 @@ impl WindowDelegate {
|
||||||
let state = &mut *(state as *mut DelegateState);
|
let state = &mut *(state as *mut DelegateState);
|
||||||
emit_event(state, WindowEvent::Closed);
|
emit_event(state, WindowEvent::Closed);
|
||||||
|
|
||||||
// Remove the window from the events_loop.
|
// Remove the window from the shared state.
|
||||||
if let Some(events_loop) = state.events_loop.upgrade() {
|
if let Some(shared) = state.shared.upgrade() {
|
||||||
let window_id = get_window_id(*state.window);
|
let window_id = get_window_id(*state.window);
|
||||||
events_loop.find_and_remove_window(window_id);
|
shared.find_and_remove_window(window_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
YES
|
YES
|
||||||
|
@ -188,8 +190,8 @@ impl Drop for Window {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Remove this window from the `EventLoop`s list of windows.
|
// Remove this window from the `EventLoop`s list of windows.
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
if let Some(ev) = self.delegate.state.events_loop.upgrade() {
|
if let Some(shared) = self.delegate.state.shared.upgrade() {
|
||||||
ev.find_and_remove_window(id);
|
shared.find_and_remove_window(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the window if it has not yet been closed.
|
// Close the window if it has not yet been closed.
|
||||||
|
@ -215,7 +217,7 @@ impl WindowExt for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(events_loop: std::sync::Weak<super::EventsLoop>,
|
pub fn new(shared: Weak<Shared>,
|
||||||
win_attribs: &WindowAttributes,
|
win_attribs: &WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||||
-> Result<Window, CreationError>
|
-> Result<Window, CreationError>
|
||||||
|
@ -266,7 +268,7 @@ impl Window {
|
||||||
let ds = DelegateState {
|
let ds = DelegateState {
|
||||||
view: view.clone(),
|
view: view.clone(),
|
||||||
window: window.clone(),
|
window: window.clone(),
|
||||||
events_loop: events_loop,
|
shared: shared,
|
||||||
};
|
};
|
||||||
|
|
||||||
let window = Window {
|
let window = Window {
|
||||||
|
|
|
@ -410,8 +410,9 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
||||||
},
|
},
|
||||||
|
|
||||||
x if x == *super::WAKEUP_MSG_ID => {
|
x if x == *super::WAKEUP_MSG_ID => {
|
||||||
use events::WindowEvent::Awakened;
|
// TODO: `Awakened` has been moved from the `WindowEvent` enum to the `Event` enum.
|
||||||
send_event(window, Awakened);
|
// This code needs to be updated to reflect this change.
|
||||||
|
//send_event(window, ::Event::Awakened);
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl WindowBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// building
|
// building
|
||||||
let w = try!(platform::Window2::new(events_loop.events_loop.clone(), &self.window, &self.platform_specific));
|
let w = try!(platform::Window2::new(&events_loop.events_loop, &self.window, &self.platform_specific));
|
||||||
|
|
||||||
Ok(Window { window: w })
|
Ok(Window { window: w })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
extern crate winit;
|
|
||||||
|
|
||||||
// A part of the API requirement for `EventsLoop` is that it is `Send` + `Sync`.
|
|
||||||
//
|
|
||||||
// This short test will only compile if the `EventsLoop` is `Send` + `Sync`.
|
|
||||||
#[test]
|
|
||||||
fn send_sync() {
|
|
||||||
fn check_send_sync<T: Send + Sync>() {}
|
|
||||||
check_send_sync::<winit::EventsLoop>();
|
|
||||||
}
|
|
8
tests/events_loop_proxy_send.rs
Normal file
8
tests/events_loop_proxy_send.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
extern crate winit;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn events_loop_proxy_send() {
|
||||||
|
// ensures that `winit::EventsLoopProxy` implements `Send`
|
||||||
|
fn needs_send<T:Send>() {}
|
||||||
|
needs_send::<winit::EventsLoopProxy>();
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
extern crate winit;
|
|
||||||
|
|
||||||
#[cfg(feature = "window")]
|
|
||||||
#[test]
|
|
||||||
fn window_proxy_send() {
|
|
||||||
// ensures that `winit::WindowProxy` implements `Send`
|
|
||||||
fn needs_send<T:Send>() {}
|
|
||||||
needs_send::<winit::WindowProxy>();
|
|
||||||
}
|
|
Loading…
Reference in a new issue