mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +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;
|
||||
|
||||
fn main() {
|
||||
let events_loop = winit::EventsLoop::new();
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
let window = winit::Window::new(&events_loop).unwrap();
|
||||
|
||||
events_loop.run_forever(|event| {
|
||||
match event {
|
||||
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
|
||||
events_loop.interrupt();
|
||||
winit::ControlFlow::Break
|
||||
},
|
||||
_ => ()
|
||||
_ => winit::ControlFlow::Continue,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
extern crate winit;
|
||||
|
||||
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput};
|
||||
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow};
|
||||
|
||||
fn main() {
|
||||
let events_loop = winit::EventsLoop::new();
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
|
||||
window.set_title("A fantastic window!");
|
||||
|
@ -23,9 +23,10 @@ fn main() {
|
|||
}
|
||||
},
|
||||
Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
||||
events_loop.interrupt()
|
||||
return ControlFlow::Break;
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
extern crate winit;
|
||||
|
||||
use std::io::{self, Write};
|
||||
use winit::{ControlFlow, Event, WindowEvent};
|
||||
|
||||
fn main() {
|
||||
// enumerating monitors
|
||||
|
@ -22,7 +23,7 @@ fn main() {
|
|||
monitor
|
||||
};
|
||||
|
||||
let events_loop = winit::EventsLoop::new();
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
|
||||
let _window = winit::WindowBuilder::new()
|
||||
.with_title("Hello world!")
|
||||
|
@ -34,16 +35,18 @@ fn main() {
|
|||
println!("{:?}", event);
|
||||
|
||||
match event {
|
||||
winit::Event::WindowEvent { event, .. } => {
|
||||
Event::WindowEvent { event, .. } => {
|
||||
match event {
|
||||
winit::WindowEvent::Closed => events_loop.interrupt(),
|
||||
winit::WindowEvent::KeyboardInput {
|
||||
WindowEvent::Closed => return ControlFlow::Break,
|
||||
WindowEvent::KeyboardInput {
|
||||
input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, ..
|
||||
} => events_loop.interrupt(),
|
||||
} => return ControlFlow::Break,
|
||||
_ => ()
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
extern crate winit;
|
||||
|
||||
use winit::{WindowEvent, ElementState, KeyboardInput};
|
||||
use winit::{ControlFlow, WindowEvent, ElementState, KeyboardInput};
|
||||
|
||||
fn main() {
|
||||
let events_loop = winit::EventsLoop::new();
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
|
||||
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 { .. } => {
|
||||
println!("{:?}", a);
|
||||
|
@ -39,5 +39,7 @@ fn main() {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extern crate winit;
|
||||
|
||||
fn main() {
|
||||
let events_loop = winit::EventsLoop::new();
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
|
||||
let _window = winit::WindowBuilder::new()
|
||||
.with_min_dimensions(400, 200)
|
||||
|
@ -13,8 +13,8 @@ fn main() {
|
|||
println!("{:?}", 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;
|
||||
|
||||
fn main() {
|
||||
let events_loop = winit::EventsLoop::new();
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
|
||||
let window1 = winit::Window::new(&events_loop).unwrap();
|
||||
let window2 = winit::Window::new(&events_loop).unwrap();
|
||||
|
@ -24,10 +24,11 @@ fn main() {
|
|||
|
||||
num_windows -= 1;
|
||||
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;
|
||||
|
||||
fn main() {
|
||||
let events_loop = winit::EventsLoop::new();
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new().with_decorations(false)
|
||||
.with_transparency(true)
|
||||
|
@ -13,8 +13,8 @@ fn main() {
|
|||
println!("{:?}", 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;
|
||||
|
||||
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!")
|
||||
.build(&events_loop)
|
||||
.unwrap();
|
||||
|
@ -12,8 +12,10 @@ fn main() {
|
|||
println!("{:?}", 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 {
|
||||
() => {
|
||||
pub struct EventsLoop {
|
||||
windows: ::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>,
|
||||
interrupted: ::std::sync::atomic::AtomicBool,
|
||||
windows: ::std::sync::Arc<::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>>,
|
||||
awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>,
|
||||
}
|
||||
|
||||
pub struct EventsLoopProxy {
|
||||
awakened: ::std::sync::Weak<::std::sync::atomic::AtomicBool>,
|
||||
}
|
||||
|
||||
impl EventsLoop {
|
||||
pub fn new() -> EventsLoop {
|
||||
EventsLoop {
|
||||
windows: ::std::sync::Mutex::new(vec![]),
|
||||
interrupted: ::std::sync::atomic::AtomicBool::new(false),
|
||||
windows: ::std::sync::Arc::new(::std::sync::Mutex::new(vec![])),
|
||||
awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interrupt(&self) {
|
||||
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn poll_events<F>(&self, mut callback: F)
|
||||
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||
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 event in window.poll_events() {
|
||||
callback(::Event::WindowEvent {
|
||||
|
@ -38,18 +43,41 @@ macro_rules! gen_api_transition {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run_forever<F>(&self, mut callback: F)
|
||||
where F: FnMut(::Event)
|
||||
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||
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.
|
||||
loop {
|
||||
self.poll_events(|e| callback(e));
|
||||
::std::thread::sleep_ms(5);
|
||||
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
|
||||
let mut control_flow = ::ControlFlow::Continue;
|
||||
self.poll_events(|e| {
|
||||
if let ::ControlFlow::Break = callback(e) {
|
||||
control_flow = ::ControlFlow::Break;
|
||||
}
|
||||
});
|
||||
if let ::ControlFlow::Break = control_flow {
|
||||
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 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 {
|
||||
|
@ -74,7 +102,8 @@ macro_rules! gen_api_transition {
|
|||
}
|
||||
|
||||
impl Window2 {
|
||||
pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
|
||||
pub fn new(events_loop: &EventsLoop,
|
||||
window: &::WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||
-> Result<Window2, CreationError>
|
||||
{
|
||||
|
@ -82,7 +111,7 @@ macro_rules! gen_api_transition {
|
|||
events_loop.windows.lock().unwrap().push(win.clone());
|
||||
Ok(Window2 {
|
||||
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 {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ev) = self.events_loop.upgrade() {
|
||||
let mut windows = ev.windows.lock().unwrap();
|
||||
if let Some(windows) = self.windows.upgrade() {
|
||||
let mut windows = windows.lock().unwrap();
|
||||
windows.retain(|w| &**w as *const Window != &*self.window as *const _);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,11 @@ pub enum Event {
|
|||
device_id: DeviceId,
|
||||
event: DeviceEvent,
|
||||
},
|
||||
Awakened,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum WindowEvent {
|
||||
// TODO: remove ; can break the lib internally so be careful
|
||||
Awakened,
|
||||
|
||||
/// The size of the window has changed.
|
||||
Resized(u32, u32),
|
||||
|
|
98
src/lib.rs
98
src/lib.rs
|
@ -34,10 +34,9 @@
|
|||
//! screen, such as video games.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use winit::Event;
|
||||
//! use winit::WindowEvent;
|
||||
//! use winit::{Event, WindowEvent};
|
||||
//! # use winit::EventsLoop;
|
||||
//! # let events_loop = EventsLoop::new();
|
||||
//! # let mut events_loop = EventsLoop::new();
|
||||
//!
|
||||
//! loop {
|
||||
//! 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
|
||||
//! forever unless it is stopped by calling `events_loop.interrupt()`.
|
||||
//! forever unless it is stopped by returning `ControlFlow::Break`.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use winit::Event;
|
||||
//! use winit::WindowEvent;
|
||||
//! use winit::{ControlFlow, Event, WindowEvent};
|
||||
//! # use winit::EventsLoop;
|
||||
//! # let events_loop = EventsLoop::new();
|
||||
//! # let mut events_loop = EventsLoop::new();
|
||||
//!
|
||||
//! events_loop.run_forever(|event| {
|
||||
//! match event {
|
||||
//! Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
||||
//! 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)]
|
||||
extern crate wayland_client;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use events::*;
|
||||
pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor};
|
||||
pub use native_monitor::NativeMonitorId;
|
||||
|
@ -139,20 +135,17 @@ pub mod os;
|
|||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use winit::Event;
|
||||
/// use winit::EventsLoop;
|
||||
/// use winit::Window;
|
||||
/// use winit::WindowEvent;
|
||||
/// use winit::{Event, EventsLoop, Window, WindowEvent, ControlFlow};
|
||||
///
|
||||
/// let events_loop = EventsLoop::new();
|
||||
/// let mut events_loop = EventsLoop::new();
|
||||
/// let window = Window::new(&events_loop).unwrap();
|
||||
///
|
||||
/// events_loop.run_forever(|event| {
|
||||
/// match event {
|
||||
/// Event::WindowEvent { event: WindowEvent::Closed, .. } => {
|
||||
/// events_loop.interrupt();
|
||||
/// ControlFlow::Break
|
||||
/// },
|
||||
/// _ => ()
|
||||
/// _ => ControlFlow::Continue,
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
|
@ -186,24 +179,35 @@ pub struct AxisId(u32);
|
|||
pub struct ButtonId(u32);
|
||||
|
||||
/// 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 {
|
||||
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 {
|
||||
/// Builds a new events loop.
|
||||
pub fn new() -> 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,
|
||||
/// and returns.
|
||||
#[inline]
|
||||
pub fn poll_events<F>(&self, callback: F)
|
||||
pub fn poll_events<F>(&mut self, callback: F)
|
||||
where F: FnMut(Event)
|
||||
{
|
||||
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.
|
||||
#[inline]
|
||||
pub fn run_forever<F>(&self, callback: F)
|
||||
where F: FnMut(Event)
|
||||
pub fn run_forever<F>(&mut self, callback: F)
|
||||
where F: FnMut(Event) -> ControlFlow
|
||||
{
|
||||
self.events_loop.run_forever(callback)
|
||||
}
|
||||
|
||||
/// If we called `run_forever()`, stops the process of waiting for events.
|
||||
// TODO: what if we're waiting from multiple threads?
|
||||
#[inline]
|
||||
pub fn interrupt(&self) {
|
||||
self.events_loop.interrupt()
|
||||
/// Creates an `EventsLoopProxy` that can be used to wake up the `EventsLoop` from another
|
||||
/// thread.
|
||||
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||
EventsLoopProxy {
|
||||
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::sync::Arc;
|
||||
|
||||
use CreationError;
|
||||
use CursorState;
|
||||
use MouseCursor;
|
||||
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
|
||||
use libc;
|
||||
|
||||
use self::x11::XConnection;
|
||||
|
@ -131,9 +129,10 @@ impl MonitorId {
|
|||
|
||||
impl Window2 {
|
||||
#[inline]
|
||||
pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
|
||||
pub fn new(events_loop: &EventsLoop,
|
||||
window: &::WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||
-> Result<Window2, CreationError>
|
||||
-> Result<Self, CreationError>
|
||||
{
|
||||
match *UNIX_BACKEND {
|
||||
UnixBackend::Wayland(ref ctxt) => {
|
||||
|
@ -309,6 +308,11 @@ pub enum EventsLoop {
|
|||
X(x11::EventsLoop)
|
||||
}
|
||||
|
||||
pub enum EventsLoopProxy {
|
||||
X(x11::EventsLoopProxy),
|
||||
Wayland(wayland::EventsLoopProxy),
|
||||
}
|
||||
|
||||
impl EventsLoop {
|
||||
pub fn new() -> EventsLoop {
|
||||
match *UNIX_BACKEND {
|
||||
|
@ -326,28 +330,37 @@ impl EventsLoop {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn interrupt(&self) {
|
||||
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||
match *self {
|
||||
EventsLoop::Wayland(ref evlp) => evlp.interrupt(),
|
||||
EventsLoop::X(ref evlp) => evlp.interrupt()
|
||||
EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()),
|
||||
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)
|
||||
{
|
||||
match *self {
|
||||
EventsLoop::Wayland(ref evlp) => evlp.poll_events(callback),
|
||||
EventsLoop::X(ref evlp) => evlp.poll_events(callback)
|
||||
EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback),
|
||||
EventsLoop::X(ref mut evlp) => evlp.poll_events(callback)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_forever<F>(&self, callback: F)
|
||||
where F: FnMut(::Event)
|
||||
pub fn run_forever<F>(&mut self, callback: F)
|
||||
where F: FnMut(::Event) -> ControlFlow
|
||||
{
|
||||
match *self {
|
||||
EventsLoop::Wayland(ref evlp) => evlp.run_forever(callback),
|
||||
EventsLoop::X(ref evlp) => evlp.run_forever(callback)
|
||||
EventsLoop::Wayland(ref mut 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::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
|
||||
use super::{DecoratedHandler, WindowId, DeviceId, WaylandContext};
|
||||
|
||||
|
@ -53,7 +54,9 @@ impl EventsLoopSink {
|
|||
::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)
|
||||
}
|
||||
}
|
||||
|
@ -67,11 +70,40 @@ pub struct EventsLoop {
|
|||
decorated_ids: Mutex<Vec<(usize, Arc<wl_surface::WlSurface>)>>,
|
||||
// our sink, receiver of callbacks, shared with some handlers
|
||||
sink: Arc<Mutex<EventsLoopSink>>,
|
||||
// trigger interruption of the run
|
||||
interrupted: AtomicBool,
|
||||
// trigger cleanup of the dead surfaces
|
||||
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 {
|
||||
|
@ -84,12 +116,19 @@ impl EventsLoop {
|
|||
evq: Arc::new(Mutex::new(evq)),
|
||||
decorated_ids: Mutex::new(Vec::new()),
|
||||
sink: sink,
|
||||
interrupted: AtomicBool::new(false),
|
||||
pending_wakeup: Arc::new(AtomicBool::new(false)),
|
||||
cleanup_needed: Arc::new(AtomicBool::new(false)),
|
||||
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
|
||||
pub fn get_window_init(&self) -> (Arc<Mutex<EventQueue>>, Arc<AtomicBool>) {
|
||||
(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) {
|
||||
self.decorated_ids.lock().unwrap().retain(|&(_, ref w)| w.is_alive());
|
||||
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)
|
||||
{
|
||||
// send pending requests to the server...
|
||||
|
@ -160,6 +195,8 @@ impl EventsLoop {
|
|||
self.ctxt.dispatch_pending();
|
||||
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
||||
|
||||
self.emit_pending_wakeup();
|
||||
|
||||
{
|
||||
let mut sink_guard = self.sink.lock().unwrap();
|
||||
|
||||
|
@ -173,45 +210,63 @@ impl EventsLoop {
|
|||
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()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_forever<F>(&self, callback: F)
|
||||
where F: FnMut(::Event)
|
||||
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||
where F: FnMut(::Event) -> ControlFlow,
|
||||
{
|
||||
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
// send pending requests to the server...
|
||||
self.ctxt.flush();
|
||||
|
||||
// first of all, get exclusive access to this event queue
|
||||
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
|
||||
// we extend the lifetime of the closure to 'static to be able to put it in
|
||||
// the sink, but we'll explicitly drop it at the end of this function, so it's fine
|
||||
let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box<FnMut(_)>) };
|
||||
let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) };
|
||||
|
||||
while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
|
||||
loop {
|
||||
self.ctxt.dispatch();
|
||||
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
||||
|
||||
self.emit_pending_wakeup();
|
||||
|
||||
let ids_guard = self.decorated_ids.lock().unwrap();
|
||||
self.sink.lock().unwrap().with_callback(
|
||||
|cb| Self::process_resize(&mut evq_guard, &ids_guard, cb)
|
||||
);
|
||||
self.sink.lock().unwrap()
|
||||
.with_callback(|cb| Self::process_resize(&mut evq_guard, &ids_guard, cb));
|
||||
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()
|
||||
}
|
||||
|
||||
if let ControlFlow::Break = control_flow.get() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// replace the old noop callback
|
||||
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 {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
|
||||
|
||||
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,
|
||||
get_primary_monitor};
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@ pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
|||
pub mod ffi;
|
||||
|
||||
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::sync::{Arc, Mutex, Weak};
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CStr;
|
||||
|
||||
|
@ -29,13 +31,22 @@ mod xdisplay;
|
|||
// the one generated by the macro.
|
||||
|
||||
pub struct EventsLoop {
|
||||
interrupted: ::std::sync::atomic::AtomicBool,
|
||||
display: Arc<XConnection>,
|
||||
wm_delete_window: ffi::Atom,
|
||||
windows: Mutex<HashMap<WindowId, WindowData>>,
|
||||
windows: Arc<Mutex<HashMap<WindowId, WindowData>>>,
|
||||
devices: Mutex<HashMap<DeviceId, Device>>,
|
||||
xi2ext: XExtension,
|
||||
pending_wakeup: Arc<AtomicBool>,
|
||||
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 {
|
||||
|
@ -72,14 +83,22 @@ impl EventsLoop {
|
|||
|
||||
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 {
|
||||
interrupted: ::std::sync::atomic::AtomicBool::new(false),
|
||||
pending_wakeup: Arc::new(AtomicBool::new(false)),
|
||||
display: display,
|
||||
wm_delete_window: wm_delete_window,
|
||||
windows: Mutex::new(HashMap::new()),
|
||||
windows: Arc::new(Mutex::new(HashMap::new())),
|
||||
devices: Mutex::new(HashMap::new()),
|
||||
xi2ext: xi2ext,
|
||||
root: root,
|
||||
wakeup_dummy_window: wakeup_dummy_window,
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -101,32 +120,17 @@ impl EventsLoop {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn interrupt(&self) {
|
||||
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
// Push an event on the X event queue so that methods like run_forever will advance.
|
||||
let mut xev = ffi::XClientMessageEvent {
|
||||
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 create_proxy(&self) -> EventsLoopProxy {
|
||||
EventsLoopProxy {
|
||||
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
|
||||
display: Arc::downgrade(&self.display),
|
||||
wakeup_dummy_window: self.wakeup_dummy_window,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poll_events<F>(&self, mut callback: F)
|
||||
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||
where F: FnMut(Event)
|
||||
{
|
||||
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
||||
let xlib = &self.display.xlib;
|
||||
|
||||
let mut xev = unsafe { mem::uninitialized() };
|
||||
|
@ -142,16 +146,13 @@ impl EventsLoop {
|
|||
(xlib.XNextEvent)(self.display.display, &mut xev);
|
||||
}
|
||||
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)
|
||||
where F: FnMut(Event)
|
||||
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||
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;
|
||||
|
||||
|
@ -159,8 +160,21 @@ impl EventsLoop {
|
|||
|
||||
loop {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +186,7 @@ impl EventsLoop {
|
|||
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)
|
||||
{
|
||||
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 {
|
||||
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Closed })
|
||||
} else {
|
||||
// FIXME: Prone to spurious wakeups
|
||||
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Awakened })
|
||||
if self.pending_wakeup.load(atomic::Ordering::Relaxed) {
|
||||
self.pending_wakeup.store(false, atomic::Ordering::Relaxed);
|
||||
callback(Event::Awakened);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,7 +322,11 @@ impl EventsLoop {
|
|||
};
|
||||
|
||||
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> {
|
||||
display: &'a XConnection,
|
||||
info: *const ffi::XIDeviceInfo,
|
||||
|
@ -564,7 +624,8 @@ pub struct DeviceId(c_int);
|
|||
|
||||
pub struct Window2 {
|
||||
pub window: Arc<Window>,
|
||||
events_loop: Weak<::platform::EventsLoop>,
|
||||
display: Weak<XConnection>,
|
||||
windows: Weak<Mutex<HashMap<WindowId, WindowData>>>,
|
||||
}
|
||||
|
||||
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 {
|
||||
pub fn new(events_loop: Arc<::platform::EventsLoop>,
|
||||
window: &::WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||
-> Result<Window2, CreationError>
|
||||
pub fn new(events_loop: &::platform::EventsLoop,
|
||||
window: &::WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||
-> Result<Self, CreationError>
|
||||
{
|
||||
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)));
|
||||
|
@ -623,7 +685,8 @@ impl Window2 {
|
|||
|
||||
Ok(Window2 {
|
||||
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 {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ev) = self.events_loop.upgrade() {
|
||||
if let ::platform::EventsLoop::X(ref ev) = *ev {
|
||||
let mut windows = ev.windows.lock().unwrap();
|
||||
|
||||
|
||||
let w = windows.remove(&self.window.id()).unwrap();
|
||||
let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap();
|
||||
unsafe {
|
||||
(ev.display.xlib.XDestroyIC)(w.ic);
|
||||
(ev.display.xlib.XCloseIM)(w.im);
|
||||
}
|
||||
if let (Some(windows), Some(display)) = (self.windows.upgrade(), self.display.upgrade()) {
|
||||
let mut windows = windows.lock().unwrap();
|
||||
let w = windows.remove(&self.window.id()).unwrap();
|
||||
let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap();
|
||||
unsafe {
|
||||
(display.xlib.XDestroyIC)(w.ic);
|
||||
(display.xlib.XCloseIM)(w.im);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,8 +166,7 @@ impl Window {
|
|||
};
|
||||
|
||||
// getting the root window
|
||||
let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
|
||||
display.check_errors().expect("Failed to get root window");
|
||||
let root = ctx.root;
|
||||
|
||||
// creating
|
||||
let mut set_win_attr = {
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
use {ControlFlow, EventsLoopClosed};
|
||||
use cocoa::{self, appkit, foundation};
|
||||
use cocoa::appkit::{NSApplication, NSEvent, NSView, NSWindow};
|
||||
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 std;
|
||||
use super::DeviceId;
|
||||
|
||||
|
||||
pub struct EventsLoop {
|
||||
pub windows: std::sync::Mutex<Vec<std::sync::Weak<Window>>>,
|
||||
pub pending_events: std::sync::Mutex<std::collections::VecDeque<Event>>,
|
||||
modifiers: std::sync::Mutex<Modifiers>,
|
||||
interrupted: std::sync::atomic::AtomicBool,
|
||||
modifiers: Modifiers,
|
||||
pub shared: Arc<Shared>,
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// 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,
|
||||
}
|
||||
|
||||
pub struct Proxy {}
|
||||
|
||||
struct Modifiers {
|
||||
shift_pressed: bool,
|
||||
ctrl_pressed: bool,
|
||||
|
@ -34,14 +42,76 @@ struct Modifiers {
|
|||
//
|
||||
// - ensure the callback pointer is never accidentally cloned
|
||||
// - 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 {
|
||||
mutex: std::sync::Mutex<Option<*mut FnMut(Event)>>,
|
||||
mutex: Mutex<Option<*mut FnMut(Event)>>,
|
||||
}
|
||||
|
||||
|
||||
unsafe impl Send for UserCallback {}
|
||||
unsafe impl Sync for UserCallback {}
|
||||
impl Shared {
|
||||
|
||||
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 {
|
||||
|
||||
|
@ -92,22 +162,13 @@ impl UserCallback {
|
|||
impl EventsLoop {
|
||||
|
||||
pub fn new() -> Self {
|
||||
let modifiers = Modifiers {
|
||||
shift_pressed: false,
|
||||
ctrl_pressed: false,
|
||||
win_pressed: false,
|
||||
alt_pressed: false,
|
||||
};
|
||||
EventsLoop {
|
||||
windows: std::sync::Mutex::new(Vec::new()),
|
||||
pending_events: std::sync::Mutex::new(std::collections::VecDeque::new()),
|
||||
modifiers: std::sync::Mutex::new(modifiers),
|
||||
interrupted: std::sync::atomic::AtomicBool::new(false),
|
||||
user_callback: UserCallback { mutex: std::sync::Mutex::new(None) },
|
||||
shared: Arc::new(Shared::new()),
|
||||
modifiers: Modifiers::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poll_events<F>(&self, mut callback: F)
|
||||
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||
where F: FnMut(Event),
|
||||
{
|
||||
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 {
|
||||
unsafe {
|
||||
// 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);
|
||||
|
||||
|
@ -139,32 +200,42 @@ impl EventsLoop {
|
|||
|
||||
match event {
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.user_callback.drop();
|
||||
self.shared.user_callback.drop();
|
||||
}
|
||||
|
||||
pub fn run_forever<F>(&self, mut callback: F)
|
||||
where F: FnMut(Event)
|
||||
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||
where F: FnMut(Event) -> ControlFlow
|
||||
{
|
||||
self.interrupted.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
unsafe {
|
||||
if !msg_send![cocoa::base::class("NSThread"), isMainThread] {
|
||||
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 {
|
||||
unsafe {
|
||||
// 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);
|
||||
|
||||
|
@ -182,84 +253,19 @@ impl EventsLoop {
|
|||
let _: () = msg_send![pool, release];
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
self.shared.user_callback.drop();
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return None;
|
||||
}
|
||||
|
@ -285,9 +291,9 @@ impl EventsLoop {
|
|||
_ => appkit::NSApp().sendEvent_(ns_event),
|
||||
}
|
||||
|
||||
let windows = self.windows.lock().unwrap();
|
||||
let windows = self.shared.windows.lock().unwrap();
|
||||
let maybe_window = windows.iter()
|
||||
.filter_map(std::sync::Weak::upgrade)
|
||||
.filter_map(Weak::upgrade)
|
||||
.find(|window| window_id == window.id());
|
||||
|
||||
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.
|
||||
let maybe_key_window = || windows.iter()
|
||||
.filter_map(std::sync::Weak::upgrade)
|
||||
.filter_map(Weak::upgrade)
|
||||
.find(|window| {
|
||||
let is_key_window: cocoa::base::BOOL = msg_send![*window.window, isKeyWindow];
|
||||
is_key_window == cocoa::base::YES
|
||||
|
@ -326,7 +332,7 @@ impl EventsLoop {
|
|||
let window_event = WindowEvent::ReceivedCharacter(received_char);
|
||||
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))
|
||||
},
|
||||
|
||||
|
@ -348,8 +354,6 @@ impl EventsLoop {
|
|||
},
|
||||
|
||||
appkit::NSFlagsChanged => {
|
||||
let mut modifiers = self.modifiers.lock().unwrap();
|
||||
|
||||
unsafe fn modifier_event(event: cocoa::base::id,
|
||||
keymask: appkit::NSEventModifierFlags,
|
||||
key: events::VirtualKeyCode,
|
||||
|
@ -392,41 +396,41 @@ impl EventsLoop {
|
|||
if let Some(window_event) = modifier_event(ns_event,
|
||||
appkit::NSShiftKeyMask,
|
||||
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));
|
||||
}
|
||||
|
||||
if let Some(window_event) = modifier_event(ns_event,
|
||||
appkit::NSControlKeyMask,
|
||||
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));
|
||||
}
|
||||
|
||||
if let Some(window_event) = modifier_event(ns_event,
|
||||
appkit::NSCommandKeyMask,
|
||||
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));
|
||||
}
|
||||
|
||||
if let Some(window_event) = modifier_event(ns_event,
|
||||
appkit::NSAlternateKeyMask,
|
||||
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));
|
||||
}
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
|
@ -505,7 +509,7 @@ impl EventsLoop {
|
|||
|
||||
appkit::NSApplicationDefined => match ns_event.subtype() {
|
||||
appkit::NSEventSubtype::NSApplicationActivatedEventType => {
|
||||
Some(into_event(WindowEvent::Awakened))
|
||||
Some(Event::Awakened)
|
||||
},
|
||||
_ => 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")]
|
||||
|
||||
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::window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, Window};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct DeviceId;
|
||||
|
@ -10,7 +11,7 @@ pub struct DeviceId;
|
|||
use {CreationError};
|
||||
|
||||
pub struct Window2 {
|
||||
pub window: ::std::sync::Arc<Window>,
|
||||
pub window: Arc<Window>,
|
||||
}
|
||||
|
||||
impl ::std::ops::Deref for Window2 {
|
||||
|
@ -23,14 +24,14 @@ impl ::std::ops::Deref for Window2 {
|
|||
|
||||
impl Window2 {
|
||||
|
||||
pub fn new(events_loop: ::std::sync::Arc<EventsLoop>,
|
||||
pub fn new(events_loop: &EventsLoop,
|
||||
attributes: &::WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError>
|
||||
{
|
||||
let weak_events_loop = ::std::sync::Arc::downgrade(&events_loop);
|
||||
let window = ::std::sync::Arc::new(try!(Window::new(weak_events_loop, attributes, pl_attribs)));
|
||||
let weak_window = ::std::sync::Arc::downgrade(&window);
|
||||
events_loop.windows.lock().unwrap().push(weak_window);
|
||||
let weak_shared = Arc::downgrade(&events_loop.shared);
|
||||
let window = Arc::new(try!(Window::new(weak_shared, attributes, pl_attribs)));
|
||||
let weak_window = Arc::downgrade(&window);
|
||||
events_loop.shared.windows.lock().unwrap().push(weak_window);
|
||||
Ok(Window2 { window: window })
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use libc;
|
|||
use WindowAttributes;
|
||||
use native_monitor::NativeMonitorId;
|
||||
use os::macos::ActivationPolicy;
|
||||
use os::macos::WindowExt;
|
||||
|
||||
use objc;
|
||||
use objc::runtime::{Class, Object, Sel, BOOL, YES, NO};
|
||||
|
@ -20,8 +21,9 @@ use core_graphics::display::{CGAssociateMouseAndMouseCursorPosition, CGMainDispl
|
|||
use std;
|
||||
use std::ops::Deref;
|
||||
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)]
|
||||
|
@ -30,7 +32,7 @@ pub struct Id(pub usize);
|
|||
struct DelegateState {
|
||||
view: IdRef,
|
||||
window: IdRef,
|
||||
events_loop: std::sync::Weak<super::EventsLoop>,
|
||||
shared: Weak<Shared>,
|
||||
}
|
||||
|
||||
pub struct WindowDelegate {
|
||||
|
@ -51,8 +53,8 @@ impl WindowDelegate {
|
|||
event: window_event,
|
||||
};
|
||||
|
||||
if let Some(events_loop) = state.events_loop.upgrade() {
|
||||
events_loop.call_user_callback_with_event_or_store_in_pending(event);
|
||||
if let Some(shared) = state.shared.upgrade() {
|
||||
shared.call_user_callback_with_event_or_store_in_pending(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,10 +73,10 @@ impl WindowDelegate {
|
|||
let state = &mut *(state as *mut DelegateState);
|
||||
emit_event(state, WindowEvent::Closed);
|
||||
|
||||
// Remove the window from the events_loop.
|
||||
if let Some(events_loop) = state.events_loop.upgrade() {
|
||||
// Remove the window from the shared state.
|
||||
if let Some(shared) = state.shared.upgrade() {
|
||||
let window_id = get_window_id(*state.window);
|
||||
events_loop.find_and_remove_window(window_id);
|
||||
shared.find_and_remove_window(window_id);
|
||||
}
|
||||
}
|
||||
YES
|
||||
|
@ -188,8 +190,8 @@ impl Drop for Window {
|
|||
fn drop(&mut self) {
|
||||
// Remove this window from the `EventLoop`s list of windows.
|
||||
let id = self.id();
|
||||
if let Some(ev) = self.delegate.state.events_loop.upgrade() {
|
||||
ev.find_and_remove_window(id);
|
||||
if let Some(shared) = self.delegate.state.shared.upgrade() {
|
||||
shared.find_and_remove_window(id);
|
||||
}
|
||||
|
||||
// Close the window if it has not yet been closed.
|
||||
|
@ -215,7 +217,7 @@ impl WindowExt for Window {
|
|||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new(events_loop: std::sync::Weak<super::EventsLoop>,
|
||||
pub fn new(shared: Weak<Shared>,
|
||||
win_attribs: &WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||
-> Result<Window, CreationError>
|
||||
|
@ -266,7 +268,7 @@ impl Window {
|
|||
let ds = DelegateState {
|
||||
view: view.clone(),
|
||||
window: window.clone(),
|
||||
events_loop: events_loop,
|
||||
shared: shared,
|
||||
};
|
||||
|
||||
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 => {
|
||||
use events::WindowEvent::Awakened;
|
||||
send_event(window, Awakened);
|
||||
// TODO: `Awakened` has been moved from the `WindowEvent` enum to the `Event` enum.
|
||||
// This code needs to be updated to reflect this change.
|
||||
//send_event(window, ::Event::Awakened);
|
||||
0
|
||||
},
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ impl WindowBuilder {
|
|||
}
|
||||
|
||||
// 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 })
|
||||
}
|
||||
|
|
|
@ -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