From 06a5ec35b363effc9ccdfeb451b8a724d8716561 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 25 May 2017 02:29:51 +1000 Subject: [PATCH 01/20] [WIP] Remove Sync and Clone from EventsLoop. Add EventsLoopProxy. This commit only updates the top-level API to get some early feedback. None of the platform-specific code has been updated yet. I'm hoping to get around to this over the next couple days however if someone more familiar with the windows backend would like to do a PR against this fork that would be a great help. Closes #187. --- examples/proxy.rs | 29 +++++++++++++++++++++++++++++ src/lib.rs | 29 +++++++++++++++++++++++++---- tests/events_loop.rs | 10 ---------- 3 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 examples/proxy.rs delete mode 100644 tests/events_loop.rs diff --git a/examples/proxy.rs b/examples/proxy.rs new file mode 100644 index 00000000..7f82788b --- /dev/null +++ b/examples/proxy.rs @@ -0,0 +1,29 @@ +extern crate winit; + +fn main() { + let 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(); + } + }); + + events_loop.run_forever(|event| { + println!("{:?}", event); + match event { + winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => + events_loop.interrupt(), + _ => () + } + }); +} diff --git a/src/lib.rs b/src/lib.rs index 623f03c3..abaaddb9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,10 +186,15 @@ 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, + events_loop: platform::EventsLoop, +} + +/// Used to wake up the `EventsLoop` from another thread. +pub struct EventsLoopProxy { + events_loop_proxy: platform::EventsLoopProxy, } impl EventsLoop { @@ -218,11 +223,27 @@ impl EventsLoop { } /// 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: platform::EventsLoopProxy::new(&self.events_loop), + } + } +} + +impl EventsLoopProxy { + /// Wake up the `EventsLoop` from which this proxy was created. + /// + /// This causes the `EventsLoop` to emit an `Awakened` event. + pub fn wakeup(&self) { + self.events_loop_proxy.wakeup(); + } } /// Object that allows you to build windows. diff --git a/tests/events_loop.rs b/tests/events_loop.rs deleted file mode 100644 index 85b3bb6b..00000000 --- a/tests/events_loop.rs +++ /dev/null @@ -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() {} - check_send_sync::(); -} From c8e791b402391020e21a64b4be29943850bee293 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 25 May 2017 23:18:56 +1000 Subject: [PATCH 02/20] Add a test that checks that EventsLoopProxy impls Send --- tests/events_loop_proxy_send.rs | 8 ++++++++ tests/window_proxy_send.rs | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) create mode 100644 tests/events_loop_proxy_send.rs delete mode 100644 tests/window_proxy_send.rs diff --git a/tests/events_loop_proxy_send.rs b/tests/events_loop_proxy_send.rs new file mode 100644 index 00000000..5c44aa13 --- /dev/null +++ b/tests/events_loop_proxy_send.rs @@ -0,0 +1,8 @@ +extern crate winit; + +#[test] +fn events_loop_proxy_send() { + // ensures that `winit::EventsLoopProxy` implements `Send` + fn needs_send() {} + needs_send::(); +} diff --git a/tests/window_proxy_send.rs b/tests/window_proxy_send.rs deleted file mode 100644 index 7ad62641..00000000 --- a/tests/window_proxy_send.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern crate winit; - -#[cfg(feature = "window")] -#[test] -fn window_proxy_send() { - // ensures that `winit::WindowProxy` implements `Send` - fn needs_send() {} - needs_send::(); -} From f6587aed39bdad2e4f4e4ce0b0281e8ecc3b20f1 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 25 May 2017 23:19:13 +1000 Subject: [PATCH 03/20] [WIP] Have EventsLoopProxy::wakeup return a Result. Begin linux impl. X11 and Wayland implementations are now half implemented, however both still do not correctly break from the inner blocking event dispatch functions when `wakeup` is called, which they should do. --- examples/proxy.rs | 2 +- src/events.rs | 3 +- src/lib.rs | 37 ++++++++++--- src/platform/linux/mod.rs | 25 ++++++++- src/platform/linux/wayland/event_loop.rs | 70 +++++++++++++++++++++--- src/platform/linux/wayland/mod.rs | 2 +- src/platform/linux/x11/mod.rs | 44 ++++++++++++--- 7 files changed, 149 insertions(+), 34 deletions(-) diff --git a/examples/proxy.rs b/examples/proxy.rs index 7f82788b..c3d615a2 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -14,7 +14,7 @@ fn main() { // Wake up the `events_loop` once every second. loop { std::thread::sleep(std::time::Duration::from_secs(1)); - proxy.wakeup(); + proxy.wakeup().unwrap(); } }); diff --git a/src/events.rs b/src/events.rs index ac5e345c..a508b589 100644 --- a/src/events.rs +++ b/src/events.rs @@ -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), diff --git a/src/lib.rs b/src/lib.rs index abaaddb9..d583b267 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,12 +189,7 @@ pub struct ButtonId(u32); /// /// To wake up an `EventsLoop` from a another thread, see the `EventsLoopProxy` docs. pub struct EventsLoop { - events_loop: platform::EventsLoop, -} - -/// Used to wake up the `EventsLoop` from another thread. -pub struct EventsLoopProxy { - events_loop_proxy: platform::EventsLoopProxy, + events_loop: Arc, } impl EventsLoop { @@ -232,17 +227,41 @@ impl EventsLoop { /// thread. pub fn create_proxy(&self) -> EventsLoopProxy { EventsLoopProxy { - events_loop_proxy: platform::EventsLoopProxy::new(&self.events_loop), + 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. - pub fn wakeup(&self) { - self.events_loop_proxy.wakeup(); + /// + /// 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`" } } diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 18924b87..fdc45d46 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -3,9 +3,7 @@ use std::collections::VecDeque; use std::sync::Arc; -use CreationError; -use CursorState; -use MouseCursor; +use {CreationError, CursorState, EventsLoopClosed, MouseCursor}; use libc; use self::x11::XConnection; @@ -309,6 +307,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,6 +329,13 @@ impl EventsLoop { } } + pub fn create_proxy(&self) -> EventsLoopProxy { + match *self { + EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()), + EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()), + } + } + pub fn interrupt(&self) { match *self { EventsLoop::Wayland(ref evlp) => evlp.interrupt(), @@ -351,3 +361,12 @@ impl EventsLoop { } } } + +impl EventsLoopProxy { + pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { + match *self { + EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(), + EventsLoopProxy::X(ref proxy) => proxy.wakeup(), + } + } +} diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index b86e4635..8f6f066b 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -1,7 +1,7 @@ -use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState, KeyboardInput}; +use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState, KeyboardInput, EventsLoopClosed}; -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}; @@ -71,7 +71,38 @@ pub struct EventsLoop { interrupted: AtomicBool, // trigger cleanup of the dead surfaces cleanup_needed: Arc, - hid: usize + // Whether or not there is a pending `Awakened` event to be emitted. + pending_wakeup: Arc, + 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, + pending_wakeup: Weak, +} + +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); + // TODO: + // Cause the `EventsLoop` to break from `dispatch` if it is currently blocked. + ctxt.display.sync(); + Ok(()) + }, + _ => Err(EventsLoopClosed), + } + } } impl EventsLoop { @@ -85,11 +116,19 @@ impl EventsLoop { 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>, Arc) { (self.evq.clone(), self.cleanup_needed.clone()) @@ -120,7 +159,7 @@ impl EventsLoop { } pub fn interrupt(&self) { - self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed); + self.interrupted.store(true, atomic::Ordering::Relaxed); } fn prune_dead_windows(&self) { @@ -160,6 +199,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,7 +214,7 @@ 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() } } @@ -181,7 +222,7 @@ impl EventsLoop { pub fn run_forever(&self, callback: F) where F: FnMut(::Event) { - self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed); + self.interrupted.store(false, atomic::Ordering::Relaxed); // send pending requests to the server... self.ctxt.flush(); @@ -195,16 +236,19 @@ impl EventsLoop { let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box) }; let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) }; - while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) { + while !self.interrupted.load(atomic::Ordering::Relaxed) { 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.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() } } @@ -212,6 +256,14 @@ impl EventsLoop { // 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 { diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index f267669b..46665ee3 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -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}; diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index 7535e42e..c69ce029 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -7,10 +7,11 @@ 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}; 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,15 +30,20 @@ mod xdisplay; // the one generated by the macro. pub struct EventsLoop { - interrupted: ::std::sync::atomic::AtomicBool, + interrupted: AtomicBool, display: Arc, wm_delete_window: ffi::Atom, windows: Mutex>, devices: Mutex>, xi2ext: XExtension, + pending_wakeup: Arc, root: ffi::Window, } +pub struct EventsLoopProxy { + pending_wakeup: Weak, +} + impl EventsLoop { pub fn new(display: Arc) -> EventsLoop { let wm_delete_window = unsafe { (display.xlib.XInternAtom)(display.display, b"WM_DELETE_WINDOW\0".as_ptr() as *const c_char, 0) }; @@ -73,7 +79,8 @@ impl EventsLoop { let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) }; let result = EventsLoop { - interrupted: ::std::sync::atomic::AtomicBool::new(false), + interrupted: AtomicBool::new(false), + pending_wakeup: Arc::new(AtomicBool::new(false)), display: display, wm_delete_window: wm_delete_window, windows: Mutex::new(HashMap::new()), @@ -101,8 +108,14 @@ impl EventsLoop { result } + pub fn create_proxy(&self) -> EventsLoopProxy { + EventsLoopProxy { + pending_wakeup: Arc::downgrade(&self.pending_wakeup), + } + } + pub fn interrupt(&self) { - self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed); + self.interrupted.store(true, atomic::Ordering::Relaxed); // Push an event on the X event queue so that methods like run_forever will advance. let mut xev = ffi::XClientMessageEvent { @@ -126,7 +139,7 @@ impl EventsLoop { pub fn poll_events(&self, mut callback: F) where F: FnMut(Event) { - self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed); + self.interrupted.store(false, atomic::Ordering::Relaxed); let xlib = &self.display.xlib; let mut xev = unsafe { mem::uninitialized() }; @@ -142,7 +155,7 @@ 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) { + if self.interrupted.load(atomic::Ordering::Relaxed) { break; } } @@ -151,7 +164,7 @@ impl EventsLoop { pub fn run_forever(&self, mut callback: F) where F: FnMut(Event) { - self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed); + self.interrupted.store(false, atomic::Ordering::Relaxed); let xlib = &self.display.xlib; @@ -160,7 +173,7 @@ 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) { + if self.interrupted.load(atomic::Ordering::Relaxed) { break; } } @@ -197,7 +210,7 @@ impl EventsLoop { callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Closed }) } else { // FIXME: Prone to spurious wakeups - callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Awakened }) + callback(Event::Awakened) } } @@ -523,6 +536,19 @@ impl EventsLoop { } } +impl EventsLoopProxy { + pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { + // Update the `EventsLoop`'s `pending_wakeup` flag. + match self.pending_wakeup.upgrade() { + Some(wakeup) => Ok(wakeup.store(true, atomic::Ordering::Relaxed)), + None => Err(EventsLoopClosed), + } + + // TODO: + // Cause the `EventsLoop` to break if it is currently blocked. + } +} + struct DeviceInfo<'a> { display: &'a XConnection, info: *const ffi::XIDeviceInfo, From 9ca2f8378401b14e06aee908900b317fd0951659 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Sat, 27 May 2017 22:51:59 +1000 Subject: [PATCH 04/20] Call flush so that the wayland eventsloop correctly breaks from dispatch when wakeup is called --- src/platform/linux/wayland/event_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index 8f6f066b..17b136a3 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -95,9 +95,9 @@ impl EventsLoopProxy { (Some(ctxt), Some(wakeup)) => { // Update the `EventsLoop`'s `pending_wakeup` flag. wakeup.store(true, atomic::Ordering::Relaxed); - // TODO: // Cause the `EventsLoop` to break from `dispatch` if it is currently blocked. ctxt.display.sync(); + ctxt.display.flush().ok(); Ok(()) }, _ => Err(EventsLoopClosed), From 339318f295c7884097caf57279809cbd78456772 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Wed, 31 May 2017 15:00:49 +1000 Subject: [PATCH 05/20] Update macOS backend to removal of Send+Sync and addition of EventsLoopProxy --- src/platform/macos/events_loop.rs | 55 ++++++++++++++++++------------- src/platform/macos/mod.rs | 2 +- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index 5b075a69..12fe2c0e 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -1,3 +1,4 @@ +use EventsLoopClosed; use cocoa::{self, appkit, foundation}; use cocoa::appkit::{NSApplication, NSEvent, NSView, NSWindow}; use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent, ModifiersState, KeyboardInput}; @@ -23,6 +24,8 @@ pub struct EventsLoop { user_callback: UserCallback, } +pub struct Proxy {} + struct Modifiers { shift_pressed: bool, ctrl_pressed: bool, @@ -40,9 +43,6 @@ pub struct UserCallback { } -unsafe impl Send for UserCallback {} -unsafe impl Sync for UserCallback {} - impl UserCallback { // Here we store user's `callback` behind the mutex so that they may be safely shared between @@ -197,25 +197,6 @@ impl EventsLoop { 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. @@ -505,7 +486,7 @@ impl EventsLoop { appkit::NSApplicationDefined => match ns_event.subtype() { appkit::NSEventSubtype::NSApplicationActivatedEventType => { - Some(into_event(WindowEvent::Awakened)) + Some(Event::Awakened) }, _ => None, }, @@ -514,6 +495,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(()) + } } diff --git a/src/platform/macos/mod.rs b/src/platform/macos/mod.rs index 5b207bb2..0e1451b6 100644 --- a/src/platform/macos/mod.rs +++ b/src/platform/macos/mod.rs @@ -1,6 +1,6 @@ #![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}; From 647a1727d0aacedcda8e46348cfc7527fb03e4c6 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Wed, 31 May 2017 15:35:08 +1000 Subject: [PATCH 06/20] Attempt to update api_transition to addition of EventsLoopProxy --- src/api_transition.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/api_transition.rs b/src/api_transition.rs index 56a25934..7cd14a1b 100644 --- a/src/api_transition.rs +++ b/src/api_transition.rs @@ -10,6 +10,11 @@ macro_rules! gen_api_transition { pub struct EventsLoop { windows: ::std::sync::Mutex>>, interrupted: ::std::sync::atomic::AtomicBool, + awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>, + } + + pub struct EventsLoopProxy { + awakened: ::std::sync::Weak<::std::sync::atomic::AtomicBool>, } impl EventsLoop { @@ -17,6 +22,7 @@ macro_rules! gen_api_transition { EventsLoop { windows: ::std::sync::Mutex::new(vec![]), interrupted: ::std::sync::atomic::AtomicBool::new(false), + awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)), } } @@ -27,6 +33,11 @@ macro_rules! gen_api_transition { pub fn poll_events(&self, mut callback: F) where F: FnMut(::Event) { + if self.awakened.load(::std::sync::atomic::Ordering::Relaxed) { + self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed); + callback(::Event::Awakened); + } + let mut windows = self.windows.lock().unwrap(); for window in windows.iter() { for event in window.poll_events() { @@ -42,6 +53,7 @@ macro_rules! gen_api_transition { where F: FnMut(::Event) { 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 { @@ -52,6 +64,24 @@ macro_rules! gen_api_transition { } } } + + 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(()) + }, + } + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] From 8f0ef514b13d38398c5ecfd9ff0e4ab65ed43941 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Wed, 31 May 2017 15:52:15 +1000 Subject: [PATCH 07/20] Fix incorred Awakened import in windows backend --- src/platform/windows/callback.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/platform/windows/callback.rs b/src/platform/windows/callback.rs index 864cf9c9..015ecec9 100644 --- a/src/platform/windows/callback.rs +++ b/src/platform/windows/callback.rs @@ -410,8 +410,7 @@ 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); + send_event(window, ::Event::Awakened); 0 }, From 2b55b2e0efb977a7e02fb5b3accc117c795cc688 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Wed, 31 May 2017 16:11:06 +1000 Subject: [PATCH 08/20] Temporarily remove windows window-specific awakened event. Needs to be updated to non-window-specific Event. --- src/platform/windows/callback.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platform/windows/callback.rs b/src/platform/windows/callback.rs index 015ecec9..c11aac13 100644 --- a/src/platform/windows/callback.rs +++ b/src/platform/windows/callback.rs @@ -410,7 +410,9 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, }, x if x == *super::WAKEUP_MSG_ID => { - send_event(window, ::Event::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 }, From 38856b1c608bc9cbc89c01c2fdb5fba9c2823e44 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Wed, 31 May 2017 18:07:51 +1000 Subject: [PATCH 09/20] X11 - Move event insertion from interrupt to proxy wakeup. --- src/platform/linux/x11/mod.rs | 59 +++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index c69ce029..eb98fb97 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -42,6 +42,8 @@ pub struct EventsLoop { pub struct EventsLoopProxy { pending_wakeup: Weak, + display: Weak, + root: ffi::Window, } impl EventsLoop { @@ -111,29 +113,13 @@ impl EventsLoop { pub fn create_proxy(&self) -> EventsLoopProxy { EventsLoopProxy { pending_wakeup: Arc::downgrade(&self.pending_wakeup), + display: Arc::downgrade(&self.display), + root: self.root, } } pub fn interrupt(&self) { self.interrupted.store(true, 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 poll_events(&self, mut callback: F) @@ -165,6 +151,7 @@ impl EventsLoop { where F: FnMut(Event) { self.interrupted.store(false, atomic::Ordering::Relaxed); + self.pending_wakeup.store(false, atomic::Ordering::Relaxed); let xlib = &self.display.xlib; @@ -172,6 +159,12 @@ impl EventsLoop { loop { unsafe { (xlib.XNextEvent)(self.display.display, &mut xev) }; // Blocks as necessary + + if self.pending_wakeup.load(atomic::Ordering::Relaxed) { + self.pending_wakeup.store(false, atomic::Ordering::Relaxed); + callback(Event::Awakened); + } + self.process_event(&mut xev, &mut callback); if self.interrupted.load(atomic::Ordering::Relaxed) { break; @@ -539,13 +532,33 @@ impl EventsLoop { impl EventsLoopProxy { pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { // Update the `EventsLoop`'s `pending_wakeup` flag. - match self.pending_wakeup.upgrade() { - Some(wakeup) => Ok(wakeup.store(true, atomic::Ordering::Relaxed)), - None => Err(EventsLoopClosed), + 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 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: display.display, + data: unsafe { mem::zeroed() }, + }; + + unsafe { + (display.xlib.XSendEvent)(display.display, self.root, 0, 0, mem::transmute(&mut xev)); + (display.xlib.XFlush)(display.display); + display.check_errors().expect("Failed to call XSendEvent after wakeup"); } - // TODO: - // Cause the `EventsLoop` to break if it is currently blocked. + Ok(()) } } From f2dd2f07524564ab42398a8fb6ee5d878548e1cb Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 2 Jun 2017 21:19:45 +1000 Subject: [PATCH 10/20] WIP - Make poll_events and run_forever take &mut self This removes the need for the EventsLoop::interrupt method by inroducing a ControlFlow type. This new type is to be returned by the user's callback and indicates whether the `EventsLoop` should continue waiting for events or break from the loop. Only the wayland, x11 and api_transition backends have been updated so far, and only the wayland backend has actually been tested. --- examples/window.rs | 6 +- src/api_transition.rs | 15 ++--- src/lib.rs | 29 +++++---- src/platform/linux/mod.rs | 28 ++++----- src/platform/linux/wayland/event_loop.rs | 39 ++++++------ src/platform/linux/x11/mod.rs | 79 +++++++++++++----------- src/window.rs | 2 +- 7 files changed, 103 insertions(+), 95 deletions(-) diff --git a/examples/window.rs b/examples/window.rs index c6d9327a..921b7ea6 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -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::Complete + }, + _ => winit::ControlFlow::Continue, } }); } diff --git a/src/api_transition.rs b/src/api_transition.rs index 7cd14a1b..db2c617d 100644 --- a/src/api_transition.rs +++ b/src/api_transition.rs @@ -8,7 +8,7 @@ macro_rules! gen_api_transition { () => { pub struct EventsLoop { - windows: ::std::sync::Mutex>>, + windows: ::std::sync::Arc<::std::sync::Mutex>>>, interrupted: ::std::sync::atomic::AtomicBool, awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>, } @@ -20,7 +20,7 @@ macro_rules! gen_api_transition { impl EventsLoop { pub fn new() -> EventsLoop { EventsLoop { - windows: ::std::sync::Mutex::new(vec![]), + windows: ::std::sync::Arc::new(::std::sync::Mutex::new(vec![])), interrupted: ::std::sync::atomic::AtomicBool::new(false), awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)), } @@ -92,7 +92,7 @@ macro_rules! gen_api_transition { pub struct Window2 { pub window: ::std::sync::Arc, - events_loop: ::std::sync::Weak, + windows: ::std::sync::Weak<::std::sync::Mutex>>> } impl ::std::ops::Deref for Window2 { @@ -104,7 +104,8 @@ macro_rules! gen_api_transition { } impl Window2 { - pub fn new(events_loop: ::std::sync::Arc, window: &::WindowAttributes, + pub fn new(events_loop: &EventsLoop, + window: &::WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result { @@ -112,7 +113,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), + events_loop: ::std::sync::Arc::downgrade(&events_loop.windows), }) } @@ -124,8 +125,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 _); } } diff --git a/src/lib.rs b/src/lib.rs index d583b267..4097b83a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,8 +119,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; @@ -189,21 +187,32 @@ pub struct ButtonId(u32); /// /// To wake up an `EventsLoop` from a another thread, see the `EventsLoopProxy` docs. pub struct EventsLoop { - events_loop: Arc, + 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, + /// Exit from the event loop. + Complete, } 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(&self, callback: F) + pub fn poll_events(&mut self, callback: F) where F: FnMut(Event) { self.events_loop.poll_events(callback) @@ -211,18 +220,12 @@ impl EventsLoop { /// Runs forever until `interrupt()` is called. Whenever an event happens, calls the callback. #[inline] - pub fn run_forever(&self, callback: F) - where F: FnMut(Event) + pub fn run_forever(&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. - #[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 { diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index fdc45d46..6bc4719d 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -3,7 +3,7 @@ use std::collections::VecDeque; use std::sync::Arc; -use {CreationError, CursorState, EventsLoopClosed, MouseCursor}; +use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow}; use libc; use self::x11::XConnection; @@ -129,9 +129,10 @@ impl MonitorId { impl Window2 { #[inline] - pub fn new(events_loop: ::std::sync::Arc, window: &::WindowAttributes, + pub fn new(events_loop: &EventsLoop, + window: &::WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes) - -> Result + -> Result { match *UNIX_BACKEND { UnixBackend::Wayland(ref ctxt) => { @@ -336,28 +337,21 @@ impl EventsLoop { } } - pub fn interrupt(&self) { - match *self { - EventsLoop::Wayland(ref evlp) => evlp.interrupt(), - EventsLoop::X(ref evlp) => evlp.interrupt() - } - } - - pub fn poll_events(&self, callback: F) + pub fn poll_events(&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(&self, callback: F) - where F: FnMut(::Event) + pub fn run_forever(&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) } } } diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index 17b136a3..f2b1325e 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -1,4 +1,5 @@ -use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState, KeyboardInput, EventsLoopClosed}; +use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState, + KeyboardInput, EventsLoopClosed, ControlFlow}; use std::sync::{Arc, Mutex, Weak}; use std::sync::atomic::{self, AtomicBool}; @@ -53,7 +54,9 @@ impl EventsLoopSink { ::std::mem::replace(&mut self.callback, cb) } - fn with_callback(&mut self, f: F) { + fn with_callback(&mut self, f: F) + where F: FnOnce(&mut FnMut(::Event)), + { f(&mut *self.callback) } } @@ -67,8 +70,6 @@ pub struct EventsLoop { decorated_ids: Mutex)>>, // our sink, receiver of callbacks, shared with some handlers sink: Arc>, - // trigger interruption of the run - interrupted: AtomicBool, // trigger cleanup of the dead surfaces cleanup_needed: Arc, // Whether or not there is a pending `Awakened` event to be emitted. @@ -115,7 +116,6 @@ 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 @@ -158,10 +158,6 @@ impl EventsLoop { } } - pub fn interrupt(&self) { - self.interrupted.store(true, 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(); @@ -175,7 +171,7 @@ impl EventsLoop { } } - pub fn poll_events(&self, callback: F) + pub fn poll_events(&mut self, callback: F) where F: FnMut(::Event) { // send pending requests to the server... @@ -219,38 +215,45 @@ impl EventsLoop { } } - pub fn run_forever(&self, callback: F) - where F: FnMut(::Event) + pub fn run_forever(&mut self, mut callback: F) + where F: FnMut(::Event) -> ControlFlow, { - self.interrupted.store(false, 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::Complete = callback(event) { + control_flow.set(ControlFlow::Complete); + }; + // 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) }; let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) }; - while !self.interrupted.load(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, atomic::Ordering::Relaxed) { self.prune_dead_windows() } + + if let ControlFlow::Complete = control_flow.get() { + break; + } } // replace the old noop callback diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index eb98fb97..f18b986c 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -7,7 +7,8 @@ pub use self::xdisplay::{XConnection, XNotSupported, XError}; pub mod ffi; use platform::PlatformSpecificWindowBuilderAttributes; -use {CreationError, Event, EventsLoopClosed, 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}; @@ -30,10 +31,9 @@ mod xdisplay; // the one generated by the macro. pub struct EventsLoop { - interrupted: AtomicBool, display: Arc, wm_delete_window: ffi::Atom, - windows: Mutex>, + windows: Arc>>, devices: Mutex>, xi2ext: XExtension, pending_wakeup: Arc, @@ -81,11 +81,10 @@ impl EventsLoop { let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) }; let result = EventsLoop { - interrupted: 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, @@ -118,14 +117,9 @@ impl EventsLoop { } } - pub fn interrupt(&self) { - self.interrupted.store(true, atomic::Ordering::Relaxed); - } - pub fn poll_events(&self, mut callback: F) where F: FnMut(Event) { - self.interrupted.store(false, atomic::Ordering::Relaxed); let xlib = &self.display.xlib; let mut xev = unsafe { mem::uninitialized() }; @@ -141,16 +135,12 @@ impl EventsLoop { (xlib.XNextEvent)(self.display.display, &mut xev); } self.process_event(&mut xev, &mut callback); - if self.interrupted.load(atomic::Ordering::Relaxed) { - break; - } } } - pub fn run_forever(&self, mut callback: F) - where F: FnMut(Event) + pub fn run_forever(&mut self, mut callback: F) + where F: FnMut(Event) -> ControlFlow { - self.interrupted.store(false, atomic::Ordering::Relaxed); self.pending_wakeup.store(false, atomic::Ordering::Relaxed); let xlib = &self.display.xlib; @@ -160,13 +150,25 @@ impl EventsLoop { loop { unsafe { (xlib.XNextEvent)(self.display.display, &mut xev) }; // Blocks as necessary + let mut control_flow = ControlFlow::Continue; + if self.pending_wakeup.load(atomic::Ordering::Relaxed) { self.pending_wakeup.store(false, atomic::Ordering::Relaxed); - callback(Event::Awakened); + control_flow = callback(Event::Awakened); } - self.process_event(&mut xev, &mut callback); - if self.interrupted.load(atomic::Ordering::Relaxed) { + // Track whether or not `Complete` was returned when processing the event. + { + let mut cb = |event| { + if let ControlFlow::Complete = callback(event) { + control_flow = ControlFlow::Complete; + } + }; + + self.process_event(&mut xev, &mut cb); + } + + if let ControlFlow::Complete = control_flow { break; } } @@ -178,7 +180,7 @@ impl EventsLoop { device.name.clone() } - fn process_event(&self, xev: &mut ffi::XEvent, callback: &mut F) + fn process_event(&self, xev: &mut ffi::XEvent, mut callback: F) where F: FnMut(Event) { let xlib = &self.display.xlib; @@ -312,7 +314,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); } } } @@ -603,7 +609,8 @@ pub struct DeviceId(c_int); pub struct Window2 { pub window: Arc, - events_loop: Weak<::platform::EventsLoop>, + display: Weak, + windows: Weak>>, } impl ::std::ops::Deref for Window2 { @@ -620,9 +627,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 + pub fn new(events_loop: &::platform::EventsLoop, + window: &::WindowAttributes, + pl_attribs: &PlatformSpecificWindowBuilderAttributes) + -> Result { 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))); @@ -662,7 +670,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), }) } @@ -674,17 +683,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); } } } diff --git a/src/window.rs b/src/window.rs index 349c31b1..94c677b0 100644 --- a/src/window.rs +++ b/src/window.rs @@ -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 }) } From db9e80bdb6eeacd30c5944ce9b6aa6571a1fb446 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 8 Jun 2017 00:12:41 +1000 Subject: [PATCH 11/20] Update examples and tests to addition of ControlFlow --- examples/cursor.rs | 7 ++++--- examples/fullscreen.rs | 13 ++++++++----- examples/grabbing.rs | 8 +++++--- examples/min_max_size.rs | 6 +++--- examples/multiwindow.rs | 5 +++-- examples/proxy.rs | 8 ++++---- examples/transparent.rs | 6 +++--- examples/window.rs | 4 ++-- src/lib.rs | 27 +++++++++++---------------- 9 files changed, 43 insertions(+), 41 deletions(-) diff --git a/examples/cursor.rs b/examples/cursor.rs index dcb37971..cd979b99 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -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::Complete; }, _ => () } + ControlFlow::Continue }); } diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 1c1d8bdb..921caa61 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -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::Complete, + WindowEvent::KeyboardInput { input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, .. - } => events_loop.interrupt(), + } => return ControlFlow::Complete, _ => () } }, _ => {} } + + ControlFlow::Continue }); } diff --git a/examples/grabbing.rs b/examples/grabbing.rs index 2ba327f4..fc6b7d7c 100644 --- a/examples/grabbing.rs +++ b/examples/grabbing.rs @@ -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::Complete, a @ WindowEvent::MouseMoved { .. } => { println!("{:?}", a); @@ -39,5 +39,7 @@ fn main() { } _ => {} } + + ControlFlow::Continue }); } diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index fe22f3e9..54f03da7 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -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::Complete, + _ => winit::ControlFlow::Continue, } }); } diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 6c92b69e..28f9955f 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -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::Complete; } }, _ => (), } + winit::ControlFlow::Continue }) } diff --git a/examples/proxy.rs b/examples/proxy.rs index c3d615a2..8741d775 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -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(); @@ -22,8 +22,8 @@ fn main() { println!("{:?}", event); match event { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => - events_loop.interrupt(), - _ => () + winit::ControlFlow::Complete, + _ => winit::ControlFlow::Continue, } }); } diff --git a/examples/transparent.rs b/examples/transparent.rs index 9e476dee..da9a80e7 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -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::Complete, + _ => winit::ControlFlow::Continue, } }); } diff --git a/examples/window.rs b/examples/window.rs index 921b7ea6..fd5ef6e9 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -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(); diff --git a/src/lib.rs b/src/lib.rs index 4097b83a..74d3c5a8 100644 --- a/src/lib.rs +++ b/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::Complete`. //! //! ```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::Complete //! }, -//! _ => () +//! _ => ControlFlow::Continue, //! } //! }); //! ``` @@ -137,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::Complete /// }, -/// _ => () +/// _ => ControlFlow::Continue, /// } /// }); /// ``` From c5b9bd361227e3df2fe58b80c87044e8507a7942 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 9 Jun 2017 19:40:22 +1000 Subject: [PATCH 12/20] Update macos backend to addition of ControlFlow (untested) --- src/platform/macos/events_loop.rs | 36 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index 12fe2c0e..bed3df56 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -1,4 +1,4 @@ -use EventsLoopClosed; +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}; @@ -11,7 +11,6 @@ pub struct EventsLoop { pub windows: std::sync::Mutex>>, pub pending_events: std::sync::Mutex>, modifiers: std::sync::Mutex, - interrupted: std::sync::atomic::AtomicBool, // The user event callback given via either of the `poll_events` or `run_forever` methods. // @@ -102,12 +101,11 @@ impl 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) }, } } - pub fn poll_events(&self, mut callback: F) + pub fn poll_events(&mut self, mut callback: F) where F: FnMut(Event), { unsafe { @@ -148,23 +146,33 @@ impl EventsLoop { self.user_callback.drop(); } - pub fn run_forever(&self, mut callback: F) - where F: FnMut(Event) + pub fn run_forever(&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"); } } + // Track whether or not control flow has changed. + let mut control_flow = std::cell::Cell::new(ControlFlow::Continue); + + let mut callback = |event| { + if let ControlFlow::Complete = callback(event) { + control_flow.set(ControlFlow::Complete); + } + }; + self.user_callback.store(&mut callback); loop { unsafe { // First, yield all pending events. self.call_user_callback_with_pending_events(); + if let ControlFlow::Complete = control_flow.get() { + break; + } let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil); @@ -183,22 +191,16 @@ impl EventsLoop { if let Some(event) = maybe_event { self.user_callback.call_with_event(event); + if let ControlFlow::Complete = 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); - } - // Removes the window with the given `Id` from the `windows` list. // // This is called when a window is either `Closed` or `Drop`ped. From 02375269999f7ea10a85d5a683f9425e9ea3e3dd Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 9 Jun 2017 22:13:30 +1000 Subject: [PATCH 13/20] Complete macos backend update to addition of ControlFlow --- src/platform/macos/events_loop.rs | 181 +++++++++++++++++------------- src/platform/macos/mod.rs | 13 ++- src/platform/macos/window.rs | 24 ++-- 3 files changed, 121 insertions(+), 97 deletions(-) diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index bed3df56..c11321cd 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -2,16 +2,22 @@ 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>>, - pub pending_events: std::sync::Mutex>, - modifiers: std::sync::Mutex, + modifiers: Modifiers, + pub shared: Arc, +} +// State shared between the `EventsLoop` and its registered windows. +pub struct Shared { + pub windows: Mutex>>, + pub pending_events: Mutex>, // 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 @@ -36,9 +42,74 @@ 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>, + mutex: Mutex>, +} + + +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, + } + } } @@ -91,17 +162,9 @@ 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), - user_callback: UserCallback { mutex: std::sync::Mutex::new(None) }, + shared: Arc::new(Shared::new()), + modifiers: Modifiers::new(), } } @@ -114,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); @@ -137,13 +200,13 @@ 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(&mut self, mut callback: F) @@ -156,7 +219,7 @@ impl EventsLoop { } // Track whether or not control flow has changed. - let mut control_flow = std::cell::Cell::new(ControlFlow::Continue); + let control_flow = std::cell::Cell::new(ControlFlow::Continue); let mut callback = |event| { if let ControlFlow::Complete = callback(event) { @@ -164,12 +227,12 @@ impl EventsLoop { } }; - self.user_callback.store(&mut callback); + 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::Complete = control_flow.get() { break; } @@ -190,7 +253,7 @@ 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::Complete = control_flow.get() { break; } @@ -198,51 +261,11 @@ impl EventsLoop { } } - self.user_callback.drop(); - } - - // 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 { + unsafe fn ns_event_to_event(&mut self, ns_event: cocoa::base::id) -> Option { if ns_event == cocoa::base::nil { return None; } @@ -268,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 { @@ -280,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 @@ -309,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)) }, @@ -331,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, @@ -375,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 }, diff --git a/src/platform/macos/mod.rs b/src/platform/macos/mod.rs index 0e1451b6..dbde5ee9 100644 --- a/src/platform/macos/mod.rs +++ b/src/platform/macos/mod.rs @@ -3,6 +3,7 @@ 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, + pub window: Arc, } 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, + pub fn new(events_loop: &EventsLoop, attributes: &::WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result { - 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 }) } diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index e4b1f1f4..8ea04a76 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -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, + shared: Weak, } 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, + pub fn new(shared: Weak, win_attribs: &WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result @@ -266,7 +268,7 @@ impl Window { let ds = DelegateState { view: view.clone(), window: window.clone(), - events_loop: events_loop, + shared: shared, }; let window = Window { From 0af3c04900e1fd3c252d94084f4897020fbe9cfb Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 9 Jun 2017 22:55:32 +1000 Subject: [PATCH 14/20] Update api transition to use ControlFlow --- src/api_transition.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/api_transition.rs b/src/api_transition.rs index db2c617d..645dc59e 100644 --- a/src/api_transition.rs +++ b/src/api_transition.rs @@ -9,7 +9,6 @@ macro_rules! gen_api_transition { () => { pub struct EventsLoop { windows: ::std::sync::Arc<::std::sync::Mutex>>>, - interrupted: ::std::sync::atomic::AtomicBool, awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>, } @@ -21,16 +20,11 @@ macro_rules! gen_api_transition { pub fn new() -> EventsLoop { EventsLoop { windows: ::std::sync::Arc::new(::std::sync::Mutex::new(vec![])), - interrupted: ::std::sync::atomic::AtomicBool::new(false), awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)), } } - pub fn interrupt(&self) { - self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed); - } - - pub fn poll_events(&self, mut callback: F) + pub fn poll_events(&mut self, mut callback: F) where F: FnMut(::Event) { if self.awakened.load(::std::sync::atomic::Ordering::Relaxed) { @@ -49,19 +43,23 @@ macro_rules! gen_api_transition { } } - pub fn run_forever(&self, mut callback: F) - where F: FnMut(::Event) + pub fn run_forever(&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::Complete = callback(e) { + control_flow = ::ControlFlow::Complete; + } + }); + if let ::ControlFlow::Complete = control_flow { break; } + ::std::thread::sleep_ms(5); } } From 4b42af910bad15e4d6e662311653b69b0c947f67 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 9 Jun 2017 22:55:48 +1000 Subject: [PATCH 15/20] Make x11 backend take &mut self in poll_events method --- src/platform/linux/x11/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index f18b986c..35472957 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -117,7 +117,7 @@ impl EventsLoop { } } - pub fn poll_events(&self, mut callback: F) + pub fn poll_events(&mut self, mut callback: F) where F: FnMut(Event) { let xlib = &self.display.xlib; From cd71271f0d990e016dc15207411e01ed4614f8af Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 9 Jun 2017 07:33:22 -0700 Subject: [PATCH 16/20] Fix api_transition ControlFlow update compile errors --- src/api_transition.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api_transition.rs b/src/api_transition.rs index 645dc59e..34448801 100644 --- a/src/api_transition.rs +++ b/src/api_transition.rs @@ -32,7 +32,7 @@ macro_rules! gen_api_transition { callback(::Event::Awakened); } - let mut windows = self.windows.lock().unwrap(); + let windows = self.windows.lock().unwrap(); for window in windows.iter() { for event in window.poll_events() { callback(::Event::WindowEvent { @@ -44,7 +44,7 @@ macro_rules! gen_api_transition { } pub fn run_forever(&mut self, mut callback: F) - where F: FnMut(::Event) -> ControlFlow, + where F: FnMut(::Event) -> ::ControlFlow, { self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed); @@ -59,7 +59,7 @@ macro_rules! gen_api_transition { if let ::ControlFlow::Complete = control_flow { break; } - ::std::thread::sleep_ms(5); + ::std::thread::sleep(::std::time::Duration::from_millis(5)); } } @@ -111,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), + windows: ::std::sync::Arc::downgrade(&events_loop.windows), }) } From 24d6f8da49ddf1dc645c7931e34c860c58c09dff Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Sat, 10 Jun 2017 13:43:15 +1000 Subject: [PATCH 17/20] Update README to addition of ControlFlow --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7979037a..a7bd9f4f 100644 --- a/README.md +++ b/README.md @@ -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::Complete }, - _ => () + _ => winit::ControlFlow::Continue, } }); } From df1276d72a2a08c7ec2a4193eead5d9ad111ebd5 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Sat, 17 Jun 2017 22:59:56 +1000 Subject: [PATCH 18/20] Fix x11 EventsLoopProxy::wakeup implementation using a dummy, InputOnly window --- src/platform/linux/x11/mod.rs | 39 ++++++++++++++++++++++---------- src/platform/linux/x11/window.rs | 3 +-- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index 35472957..151c9e0c 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -38,12 +38,15 @@ pub struct EventsLoop { xi2ext: XExtension, pending_wakeup: Arc, 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, display: Weak, - root: ffi::Window, + wakeup_dummy_window: ffi::Window, } impl EventsLoop { @@ -80,6 +83,13 @@ 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 { pending_wakeup: Arc::new(AtomicBool::new(false)), display: display, @@ -88,6 +98,7 @@ impl EventsLoop { devices: Mutex::new(HashMap::new()), xi2ext: xi2ext, root: root, + wakeup_dummy_window: wakeup_dummy_window, }; { @@ -113,7 +124,7 @@ impl EventsLoop { EventsLoopProxy { pending_wakeup: Arc::downgrade(&self.pending_wakeup), display: Arc::downgrade(&self.display), - root: self.root, + wakeup_dummy_window: self.wakeup_dummy_window, } } @@ -152,11 +163,6 @@ impl EventsLoop { let mut control_flow = ControlFlow::Continue; - if self.pending_wakeup.load(atomic::Ordering::Relaxed) { - self.pending_wakeup.store(false, atomic::Ordering::Relaxed); - control_flow = callback(Event::Awakened); - } - // Track whether or not `Complete` was returned when processing the event. { let mut cb = |event| { @@ -204,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::Awakened) + if self.pending_wakeup.load(atomic::Ordering::Relaxed) { + self.pending_wakeup.store(false, atomic::Ordering::Relaxed); + callback(Event::Awakened); + } } } @@ -546,10 +554,14 @@ impl EventsLoopProxy { _ => return Err(EventsLoopClosed), }; - // Push an event on the X event queue so that methods like run_forever will advance. + // 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.root, + window: self.wakeup_dummy_window, format: 32, message_type: 0, serial: 0, @@ -559,7 +571,10 @@ impl EventsLoopProxy { }; unsafe { - (display.xlib.XSendEvent)(display.display, self.root, 0, 0, mem::transmute(&mut xev)); + 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"); } diff --git a/src/platform/linux/x11/window.rs b/src/platform/linux/x11/window.rs index 475cab8a..f5fa6794 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform/linux/x11/window.rs @@ -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 = { From 04ccad1dbcca13cad951dc966d84bd221d61308e Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Tue, 20 Jun 2017 21:25:53 +1000 Subject: [PATCH 19/20] Rename ControlFlow variant from Complete to Break --- examples/cursor.rs | 2 +- examples/fullscreen.rs | 4 ++-- examples/grabbing.rs | 2 +- examples/min_max_size.rs | 2 +- examples/multiwindow.rs | 2 +- examples/proxy.rs | 2 +- examples/transparent.rs | 2 +- examples/window.rs | 2 +- src/api_transition.rs | 6 +++--- src/lib.rs | 10 +++++----- src/platform/linux/wayland/event_loop.rs | 6 +++--- src/platform/linux/x11/mod.rs | 8 ++++---- src/platform/macos/events_loop.rs | 8 ++++---- 13 files changed, 28 insertions(+), 28 deletions(-) diff --git a/examples/cursor.rs b/examples/cursor.rs index cd979b99..bc7deea6 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -23,7 +23,7 @@ fn main() { } }, Event::WindowEvent { event: WindowEvent::Closed, .. } => { - return ControlFlow::Complete; + return ControlFlow::Break; }, _ => () } diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 921caa61..6f2f118a 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -37,10 +37,10 @@ fn main() { match event { Event::WindowEvent { event, .. } => { match event { - WindowEvent::Closed => return ControlFlow::Complete, + WindowEvent::Closed => return ControlFlow::Break, WindowEvent::KeyboardInput { input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, .. - } => return ControlFlow::Complete, + } => return ControlFlow::Break, _ => () } }, diff --git a/examples/grabbing.rs b/examples/grabbing.rs index fc6b7d7c..f7e7c9b3 100644 --- a/examples/grabbing.rs +++ b/examples/grabbing.rs @@ -28,7 +28,7 @@ fn main() { } }, - WindowEvent::Closed => return ControlFlow::Complete, + WindowEvent::Closed => return ControlFlow::Break, a @ WindowEvent::MouseMoved { .. } => { println!("{:?}", a); diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 54f03da7..7500e893 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -13,7 +13,7 @@ fn main() { println!("{:?}", event); match event { - winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => winit::ControlFlow::Complete, + winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => winit::ControlFlow::Break, _ => winit::ControlFlow::Continue, } }); diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 28f9955f..9c5b93b8 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -24,7 +24,7 @@ fn main() { num_windows -= 1; if num_windows == 0 { - return winit::ControlFlow::Complete; + return winit::ControlFlow::Break; } }, _ => (), diff --git a/examples/proxy.rs b/examples/proxy.rs index 8741d775..338c4675 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -22,7 +22,7 @@ fn main() { println!("{:?}", event); match event { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => - winit::ControlFlow::Complete, + winit::ControlFlow::Break, _ => winit::ControlFlow::Continue, } }); diff --git a/examples/transparent.rs b/examples/transparent.rs index da9a80e7..de633175 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -13,7 +13,7 @@ fn main() { println!("{:?}", event); match event { - winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => winit::ControlFlow::Complete, + winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => winit::ControlFlow::Break, _ => winit::ControlFlow::Continue, } }); diff --git a/examples/window.rs b/examples/window.rs index fd5ef6e9..65f0ade2 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -13,7 +13,7 @@ fn main() { match event { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => { - winit::ControlFlow::Complete + winit::ControlFlow::Break }, _ => winit::ControlFlow::Continue, } diff --git a/src/api_transition.rs b/src/api_transition.rs index 34448801..158c6d44 100644 --- a/src/api_transition.rs +++ b/src/api_transition.rs @@ -52,11 +52,11 @@ macro_rules! gen_api_transition { loop { let mut control_flow = ::ControlFlow::Continue; self.poll_events(|e| { - if let ::ControlFlow::Complete = callback(e) { - control_flow = ::ControlFlow::Complete; + if let ::ControlFlow::Break = callback(e) { + control_flow = ::ControlFlow::Break; } }); - if let ::ControlFlow::Complete = control_flow { + if let ::ControlFlow::Break = control_flow { break; } ::std::thread::sleep(::std::time::Duration::from_millis(5)); diff --git a/src/lib.rs b/src/lib.rs index 74d3c5a8..d4b91c40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,7 +51,7 @@ //! ``` //! //! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run -//! forever unless it is stopped by returning `ControlFlow::Complete`. +//! forever unless it is stopped by returning `ControlFlow::Break`. //! //! ```no_run //! use winit::{ControlFlow, Event, WindowEvent}; @@ -62,7 +62,7 @@ //! match event { //! Event::WindowEvent { event: WindowEvent::Closed, .. } => { //! println!("The window was closed ; stopping"); -//! ControlFlow::Complete +//! ControlFlow::Break //! }, //! _ => ControlFlow::Continue, //! } @@ -143,7 +143,7 @@ pub mod os; /// events_loop.run_forever(|event| { /// match event { /// Event::WindowEvent { event: WindowEvent::Closed, .. } => { -/// ControlFlow::Complete +/// ControlFlow::Break /// }, /// _ => ControlFlow::Continue, /// } @@ -192,8 +192,8 @@ pub struct EventsLoop { pub enum ControlFlow { /// Continue looping and waiting for events. Continue, - /// Exit from the event loop. - Complete, + /// Break from the event loop. + Break, } impl EventsLoop { diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index f2b1325e..703562b6 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -226,8 +226,8 @@ impl EventsLoop { // Check for control flow by wrapping the callback. let control_flow = ::std::cell::Cell::new(ControlFlow::Continue); - let callback = |event| if let ControlFlow::Complete = callback(event) { - control_flow.set(ControlFlow::Complete); + let callback = |event| if let ControlFlow::Break = callback(event) { + control_flow.set(ControlFlow::Break); }; // set the callback into the sink @@ -251,7 +251,7 @@ impl EventsLoop { self.prune_dead_windows() } - if let ControlFlow::Complete = control_flow.get() { + if let ControlFlow::Break = control_flow.get() { break; } } diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index 151c9e0c..7b8f6bd7 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -163,18 +163,18 @@ impl EventsLoop { let mut control_flow = ControlFlow::Continue; - // Track whether or not `Complete` was returned when processing the event. + // Track whether or not `Break` was returned when processing the event. { let mut cb = |event| { - if let ControlFlow::Complete = callback(event) { - control_flow = ControlFlow::Complete; + if let ControlFlow::Break = callback(event) { + control_flow = ControlFlow::Break; } }; self.process_event(&mut xev, &mut cb); } - if let ControlFlow::Complete = control_flow { + if let ControlFlow::Break = control_flow { break; } } diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index c11321cd..52130bbe 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -222,8 +222,8 @@ impl EventsLoop { let control_flow = std::cell::Cell::new(ControlFlow::Continue); let mut callback = |event| { - if let ControlFlow::Complete = callback(event) { - control_flow.set(ControlFlow::Complete); + if let ControlFlow::Break = callback(event) { + control_flow.set(ControlFlow::Break); } }; @@ -233,7 +233,7 @@ impl EventsLoop { unsafe { // First, yield all pending events. self.shared.call_user_callback_with_pending_events(); - if let ControlFlow::Complete = control_flow.get() { + if let ControlFlow::Break = control_flow.get() { break; } @@ -254,7 +254,7 @@ impl EventsLoop { if let Some(event) = maybe_event { self.shared.user_callback.call_with_event(event); - if let ControlFlow::Complete = control_flow.get() { + if let ControlFlow::Break = control_flow.get() { break; } } From fe61d81d4109f38f6563165eab962ad14ea4d250 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Tue, 20 Jun 2017 21:34:00 +1000 Subject: [PATCH 20/20] Change Complete to Break in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a7bd9f4f..868486de 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ fn main() { events_loop.run_forever(|event| { match event { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => { - winit::ControlFlow::Complete + winit::ControlFlow::Break }, _ => winit::ControlFlow::Continue, }