Merge pull request #191 from mitchmindtree/remove_sync

Remove Sync and Clone from EventsLoop. Add EventsLoopProxy.
This commit is contained in:
tomaka 2017-06-21 10:18:11 +02:00 committed by GitHub
commit a08347eef0
25 changed files with 586 additions and 331 deletions

View file

@ -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,
}
});
}

View file

@ -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
});
}

View file

@ -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
});
}

View file

@ -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
});
}

View file

@ -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,
}
});
}

View file

@ -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
View 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,
}
});
}

View file

@ -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,
}
});
}

View file

@ -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,
}
});
}

View file

@ -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 _);
}
}

View file

@ -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),

View file

@ -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`"
}
}

View file

@ -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(),
}
}
}

View file

@ -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 {

View file

@ -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};

View file

@ -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);
}
}
}

View file

@ -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 = {

View file

@ -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(())
}
}

View file

@ -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 })
}

View file

@ -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 {

View file

@ -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
},

View file

@ -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 })
}

View file

@ -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>();
}

View 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>();
}

View file

@ -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>();
}